xref: /OK3568_Linux_fs/external/xserver/mi/mieq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun Copyright 1990, 1998  The Open Group
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * Author:  Keith Packard, MIT X Consortium
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun  * mieq.c
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * Machine independent event queue
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #if HAVE_DIX_CONFIG_H
36*4882a593Smuzhiyun #include <dix-config.h>
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include   <X11/X.h>
40*4882a593Smuzhiyun #include   <X11/Xmd.h>
41*4882a593Smuzhiyun #include   <X11/Xproto.h>
42*4882a593Smuzhiyun #include   "misc.h"
43*4882a593Smuzhiyun #include   "windowstr.h"
44*4882a593Smuzhiyun #include   "pixmapstr.h"
45*4882a593Smuzhiyun #include   "inputstr.h"
46*4882a593Smuzhiyun #include   "inpututils.h"
47*4882a593Smuzhiyun #include   "mi.h"
48*4882a593Smuzhiyun #include   "mipointer.h"
49*4882a593Smuzhiyun #include   "scrnintstr.h"
50*4882a593Smuzhiyun #include   <X11/extensions/XI.h>
51*4882a593Smuzhiyun #include   <X11/extensions/XIproto.h>
52*4882a593Smuzhiyun #include   <X11/extensions/geproto.h>
53*4882a593Smuzhiyun #include   "extinit.h"
54*4882a593Smuzhiyun #include   "exglobals.h"
55*4882a593Smuzhiyun #include   "eventstr.h"
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #ifdef DPMSExtension
58*4882a593Smuzhiyun #include "dpmsproc.h"
59*4882a593Smuzhiyun #include <X11/extensions/dpmsconst.h>
60*4882a593Smuzhiyun #endif
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* Maximum size should be initial size multiplied by a power of 2 */
63*4882a593Smuzhiyun #define QUEUE_INITIAL_SIZE                 512
64*4882a593Smuzhiyun #define QUEUE_RESERVED_SIZE                 64
65*4882a593Smuzhiyun #define QUEUE_MAXIMUM_SIZE                4096
66*4882a593Smuzhiyun #define QUEUE_DROP_BACKTRACE_FREQUENCY     100
67*4882a593Smuzhiyun #define QUEUE_DROP_BACKTRACE_MAX            10
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen
70*4882a593Smuzhiyun #define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun typedef struct _Event {
73*4882a593Smuzhiyun     InternalEvent *events;
74*4882a593Smuzhiyun     ScreenPtr pScreen;
75*4882a593Smuzhiyun     DeviceIntPtr pDev;          /* device this event _originated_ from */
76*4882a593Smuzhiyun } EventRec, *EventPtr;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun typedef struct _EventQueue {
79*4882a593Smuzhiyun     HWEventQueueType head, tail;        /* long for SetInputCheck */
80*4882a593Smuzhiyun     CARD32 lastEventTime;       /* to avoid time running backwards */
81*4882a593Smuzhiyun     int lastMotion;             /* device ID if last event motion? */
82*4882a593Smuzhiyun     EventRec *events;           /* our queue as an array */
83*4882a593Smuzhiyun     size_t nevents;             /* the number of buckets in our queue */
84*4882a593Smuzhiyun     size_t dropped;             /* counter for number of consecutive dropped events */
85*4882a593Smuzhiyun     mieqHandler handlers[128];  /* custom event handler */
86*4882a593Smuzhiyun } EventQueueRec, *EventQueuePtr;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static EventQueueRec miEventQueue;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static size_t
mieqNumEnqueued(EventQueuePtr eventQueue)91*4882a593Smuzhiyun mieqNumEnqueued(EventQueuePtr eventQueue)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun     size_t n_enqueued = 0;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun     if (eventQueue->nevents) {
96*4882a593Smuzhiyun         /* % is not well-defined with negative numbers... sigh */
97*4882a593Smuzhiyun         n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
98*4882a593Smuzhiyun         if (n_enqueued >= eventQueue->nevents)
99*4882a593Smuzhiyun             n_enqueued -= eventQueue->nevents;
100*4882a593Smuzhiyun     }
101*4882a593Smuzhiyun     return n_enqueued;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /* Pre-condition: Called with input_lock held */
105*4882a593Smuzhiyun static Bool
mieqGrowQueue(EventQueuePtr eventQueue,size_t new_nevents)106*4882a593Smuzhiyun mieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun     size_t i, n_enqueued, first_hunk;
109*4882a593Smuzhiyun     EventRec *new_events;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun     if (!eventQueue) {
112*4882a593Smuzhiyun         ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
113*4882a593Smuzhiyun         return FALSE;
114*4882a593Smuzhiyun     }
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun     if (new_nevents <= eventQueue->nevents)
117*4882a593Smuzhiyun         return FALSE;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun     new_events = calloc(new_nevents, sizeof(EventRec));
120*4882a593Smuzhiyun     if (new_events == NULL) {
121*4882a593Smuzhiyun         ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
122*4882a593Smuzhiyun         return FALSE;
123*4882a593Smuzhiyun     }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun     n_enqueued = mieqNumEnqueued(eventQueue);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun     /* First copy the existing events */
128*4882a593Smuzhiyun     first_hunk = eventQueue->nevents - eventQueue->head;
129*4882a593Smuzhiyun     memcpy(new_events,
130*4882a593Smuzhiyun            &eventQueue->events[eventQueue->head],
131*4882a593Smuzhiyun            first_hunk * sizeof(EventRec));
132*4882a593Smuzhiyun     memcpy(&new_events[first_hunk],
133*4882a593Smuzhiyun            eventQueue->events, eventQueue->head * sizeof(EventRec));
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun     /* Initialize the new portion */
136*4882a593Smuzhiyun     for (i = eventQueue->nevents; i < new_nevents; i++) {
137*4882a593Smuzhiyun         InternalEvent *evlist = InitEventList(1);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun         if (!evlist) {
140*4882a593Smuzhiyun             size_t j;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun             for (j = 0; j < i; j++)
143*4882a593Smuzhiyun                 FreeEventList(new_events[j].events, 1);
144*4882a593Smuzhiyun             free(new_events);
145*4882a593Smuzhiyun             return FALSE;
146*4882a593Smuzhiyun         }
147*4882a593Smuzhiyun         new_events[i].events = evlist;
148*4882a593Smuzhiyun     }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun     /* And update our record */
151*4882a593Smuzhiyun     eventQueue->tail = n_enqueued;
152*4882a593Smuzhiyun     eventQueue->head = 0;
153*4882a593Smuzhiyun     eventQueue->nevents = new_nevents;
154*4882a593Smuzhiyun     free(eventQueue->events);
155*4882a593Smuzhiyun     eventQueue->events = new_events;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun     return TRUE;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun Bool
mieqInit(void)161*4882a593Smuzhiyun mieqInit(void)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun     memset(&miEventQueue, 0, sizeof(miEventQueue));
164*4882a593Smuzhiyun     miEventQueue.lastEventTime = GetTimeInMillis();
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun     input_lock();
167*4882a593Smuzhiyun     if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
168*4882a593Smuzhiyun         FatalError("Could not allocate event queue.\n");
169*4882a593Smuzhiyun     input_unlock();
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun     SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
172*4882a593Smuzhiyun     return TRUE;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun void
mieqFini(void)176*4882a593Smuzhiyun mieqFini(void)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun     int i;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun     for (i = 0; i < miEventQueue.nevents; i++) {
181*4882a593Smuzhiyun         if (miEventQueue.events[i].events != NULL) {
182*4882a593Smuzhiyun             FreeEventList(miEventQueue.events[i].events, 1);
183*4882a593Smuzhiyun             miEventQueue.events[i].events = NULL;
184*4882a593Smuzhiyun         }
185*4882a593Smuzhiyun     }
186*4882a593Smuzhiyun     free(miEventQueue.events);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /*
190*4882a593Smuzhiyun  * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
191*4882a593Smuzhiyun  * will never be interrupted. Must be called with input_lock held
192*4882a593Smuzhiyun  */
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun void
mieqEnqueue(DeviceIntPtr pDev,InternalEvent * e)195*4882a593Smuzhiyun mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun     unsigned int oldtail = miEventQueue.tail;
198*4882a593Smuzhiyun     InternalEvent *evt;
199*4882a593Smuzhiyun     int isMotion = 0;
200*4882a593Smuzhiyun     int evlen;
201*4882a593Smuzhiyun     Time time;
202*4882a593Smuzhiyun     size_t n_enqueued;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun     verify_internal_event(e);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun     n_enqueued = mieqNumEnqueued(&miEventQueue);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun     /* avoid merging events from different devices */
209*4882a593Smuzhiyun     if (e->any.type == ET_Motion)
210*4882a593Smuzhiyun         isMotion = pDev->id;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun     if (isMotion && isMotion == miEventQueue.lastMotion &&
213*4882a593Smuzhiyun         oldtail != miEventQueue.head) {
214*4882a593Smuzhiyun         oldtail = (oldtail - 1) % miEventQueue.nevents;
215*4882a593Smuzhiyun     }
216*4882a593Smuzhiyun     else if (n_enqueued + 1 == miEventQueue.nevents) {
217*4882a593Smuzhiyun         if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
218*4882a593Smuzhiyun             /* Toss events which come in late.  Usually this means your server's
219*4882a593Smuzhiyun              * stuck in an infinite loop in the main thread.
220*4882a593Smuzhiyun              */
221*4882a593Smuzhiyun             miEventQueue.dropped++;
222*4882a593Smuzhiyun             if (miEventQueue.dropped == 1) {
223*4882a593Smuzhiyun                 ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
224*4882a593Smuzhiyun                               "discarded until existing events are processed.\n");
225*4882a593Smuzhiyun                 xorg_backtrace();
226*4882a593Smuzhiyun                 ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
227*4882a593Smuzhiyun                               "a culprit higher up the stack.\n");
228*4882a593Smuzhiyun                 ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
229*4882a593Smuzhiyun             }
230*4882a593Smuzhiyun             else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
231*4882a593Smuzhiyun                      miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
232*4882a593Smuzhiyun                      QUEUE_DROP_BACKTRACE_MAX) {
233*4882a593Smuzhiyun                 ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
234*4882a593Smuzhiyun                               "dropped.\n", miEventQueue.dropped);
235*4882a593Smuzhiyun                 if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
236*4882a593Smuzhiyun                     QUEUE_DROP_BACKTRACE_MAX) {
237*4882a593Smuzhiyun                     ErrorFSigSafe("[mi] No further overflow reports will be "
238*4882a593Smuzhiyun                                   "reported until the clog is cleared.\n");
239*4882a593Smuzhiyun                 }
240*4882a593Smuzhiyun                 xorg_backtrace();
241*4882a593Smuzhiyun             }
242*4882a593Smuzhiyun             return;
243*4882a593Smuzhiyun         }
244*4882a593Smuzhiyun         oldtail = miEventQueue.tail;
245*4882a593Smuzhiyun     }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun     evlen = e->any.length;
248*4882a593Smuzhiyun     evt = miEventQueue.events[oldtail].events;
249*4882a593Smuzhiyun     memcpy(evt, e, evlen);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun     time = e->any.time;
252*4882a593Smuzhiyun     /* Make sure that event times don't go backwards - this
253*4882a593Smuzhiyun      * is "unnecessary", but very useful. */
254*4882a593Smuzhiyun     if (time < miEventQueue.lastEventTime &&
255*4882a593Smuzhiyun         miEventQueue.lastEventTime - time < 10000)
256*4882a593Smuzhiyun         e->any.time = miEventQueue.lastEventTime;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun     miEventQueue.lastEventTime = evt->any.time;
259*4882a593Smuzhiyun     miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
260*4882a593Smuzhiyun     miEventQueue.events[oldtail].pDev = pDev;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun     miEventQueue.lastMotion = isMotion;
263*4882a593Smuzhiyun     miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun /**
267*4882a593Smuzhiyun  * Changes the screen reference events are being enqueued from.
268*4882a593Smuzhiyun  * Input events are enqueued with a screen reference and dequeued and
269*4882a593Smuzhiyun  * processed with a (potentially different) screen reference.
270*4882a593Smuzhiyun  * This function is called whenever a new event has changed screen but is
271*4882a593Smuzhiyun  * still logically on the previous screen as seen by the client.
272*4882a593Smuzhiyun  * This usually happens whenever the visible cursor moves across screen
273*4882a593Smuzhiyun  * boundaries during event generation, before the same event is processed
274*4882a593Smuzhiyun  * and sent down the wire.
275*4882a593Smuzhiyun  *
276*4882a593Smuzhiyun  * @param pDev The device that triggered a screen change.
277*4882a593Smuzhiyun  * @param pScreen The new screen events are being enqueued for.
278*4882a593Smuzhiyun  * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
279*4882a593Smuzhiyun  * and dequeue screen.
280*4882a593Smuzhiyun  */
281*4882a593Smuzhiyun void
mieqSwitchScreen(DeviceIntPtr pDev,ScreenPtr pScreen,Bool set_dequeue_screen)282*4882a593Smuzhiyun mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun     EnqueueScreen(pDev) = pScreen;
285*4882a593Smuzhiyun     if (set_dequeue_screen)
286*4882a593Smuzhiyun         DequeueScreen(pDev) = pScreen;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun void
mieqSetHandler(int event,mieqHandler handler)290*4882a593Smuzhiyun mieqSetHandler(int event, mieqHandler handler)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun     if (handler && miEventQueue.handlers[event])
293*4882a593Smuzhiyun         ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
294*4882a593Smuzhiyun                "event %d\n", miEventQueue.handlers[event], handler, event);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun     miEventQueue.handlers[event] = handler;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun /**
300*4882a593Smuzhiyun  * Change the device id of the given event to the given device's id.
301*4882a593Smuzhiyun  */
302*4882a593Smuzhiyun static void
ChangeDeviceID(DeviceIntPtr dev,InternalEvent * event)303*4882a593Smuzhiyun ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun     switch (event->any.type) {
306*4882a593Smuzhiyun     case ET_Motion:
307*4882a593Smuzhiyun     case ET_KeyPress:
308*4882a593Smuzhiyun     case ET_KeyRelease:
309*4882a593Smuzhiyun     case ET_ButtonPress:
310*4882a593Smuzhiyun     case ET_ButtonRelease:
311*4882a593Smuzhiyun     case ET_ProximityIn:
312*4882a593Smuzhiyun     case ET_ProximityOut:
313*4882a593Smuzhiyun     case ET_Hierarchy:
314*4882a593Smuzhiyun     case ET_DeviceChanged:
315*4882a593Smuzhiyun     case ET_TouchBegin:
316*4882a593Smuzhiyun     case ET_TouchUpdate:
317*4882a593Smuzhiyun     case ET_TouchEnd:
318*4882a593Smuzhiyun         event->device_event.deviceid = dev->id;
319*4882a593Smuzhiyun         break;
320*4882a593Smuzhiyun     case ET_TouchOwnership:
321*4882a593Smuzhiyun         event->touch_ownership_event.deviceid = dev->id;
322*4882a593Smuzhiyun         break;
323*4882a593Smuzhiyun #ifdef XFreeXDGA
324*4882a593Smuzhiyun     case ET_DGAEvent:
325*4882a593Smuzhiyun         break;
326*4882a593Smuzhiyun #endif
327*4882a593Smuzhiyun     case ET_RawKeyPress:
328*4882a593Smuzhiyun     case ET_RawKeyRelease:
329*4882a593Smuzhiyun     case ET_RawButtonPress:
330*4882a593Smuzhiyun     case ET_RawButtonRelease:
331*4882a593Smuzhiyun     case ET_RawMotion:
332*4882a593Smuzhiyun     case ET_RawTouchBegin:
333*4882a593Smuzhiyun     case ET_RawTouchEnd:
334*4882a593Smuzhiyun     case ET_RawTouchUpdate:
335*4882a593Smuzhiyun         event->raw_event.deviceid = dev->id;
336*4882a593Smuzhiyun         break;
337*4882a593Smuzhiyun     case ET_BarrierHit:
338*4882a593Smuzhiyun     case ET_BarrierLeave:
339*4882a593Smuzhiyun         event->barrier_event.deviceid = dev->id;
340*4882a593Smuzhiyun         break;
341*4882a593Smuzhiyun     default:
342*4882a593Smuzhiyun         ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
343*4882a593Smuzhiyun                event->any.type);
344*4882a593Smuzhiyun     }
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun static void
FixUpEventForMaster(DeviceIntPtr mdev,DeviceIntPtr sdev,InternalEvent * original,InternalEvent * master)348*4882a593Smuzhiyun FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
349*4882a593Smuzhiyun                     InternalEvent *original, InternalEvent *master)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun     verify_internal_event(original);
352*4882a593Smuzhiyun     verify_internal_event(master);
353*4882a593Smuzhiyun     /* Ensure chained button mappings, i.e. that the detail field is the
354*4882a593Smuzhiyun      * value of the mapped button on the SD, not the physical button */
355*4882a593Smuzhiyun     if (original->any.type == ET_ButtonPress ||
356*4882a593Smuzhiyun         original->any.type == ET_ButtonRelease) {
357*4882a593Smuzhiyun         int btn = original->device_event.detail.button;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun         if (!sdev->button)
360*4882a593Smuzhiyun             return;             /* Should never happen */
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun         master->device_event.detail.button = sdev->button->map[btn];
363*4882a593Smuzhiyun     }
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun /**
367*4882a593Smuzhiyun  * Copy the given event into master.
368*4882a593Smuzhiyun  * @param sdev The slave device the original event comes from
369*4882a593Smuzhiyun  * @param original The event as it came from the EQ
370*4882a593Smuzhiyun  * @param copy The event after being copied
371*4882a593Smuzhiyun  * @return The master device or NULL if the device is a floating slave.
372*4882a593Smuzhiyun  */
373*4882a593Smuzhiyun DeviceIntPtr
CopyGetMasterEvent(DeviceIntPtr sdev,InternalEvent * original,InternalEvent * copy)374*4882a593Smuzhiyun CopyGetMasterEvent(DeviceIntPtr sdev,
375*4882a593Smuzhiyun                    InternalEvent *original, InternalEvent *copy)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun     DeviceIntPtr mdev;
378*4882a593Smuzhiyun     int len = original->any.length;
379*4882a593Smuzhiyun     int type = original->any.type;
380*4882a593Smuzhiyun     int mtype;                  /* which master type? */
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun     verify_internal_event(original);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun     /* ET_XQuartz has sdev == NULL */
385*4882a593Smuzhiyun     if (!sdev || IsMaster(sdev) || IsFloating(sdev))
386*4882a593Smuzhiyun         return NULL;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun #ifdef XFreeXDGA
389*4882a593Smuzhiyun     if (type == ET_DGAEvent)
390*4882a593Smuzhiyun         type = original->dga_event.subtype;
391*4882a593Smuzhiyun #endif
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun     switch (type) {
394*4882a593Smuzhiyun     case ET_KeyPress:
395*4882a593Smuzhiyun     case ET_KeyRelease:
396*4882a593Smuzhiyun         mtype = MASTER_KEYBOARD;
397*4882a593Smuzhiyun         break;
398*4882a593Smuzhiyun     case ET_ButtonPress:
399*4882a593Smuzhiyun     case ET_ButtonRelease:
400*4882a593Smuzhiyun     case ET_Motion:
401*4882a593Smuzhiyun     case ET_ProximityIn:
402*4882a593Smuzhiyun     case ET_ProximityOut:
403*4882a593Smuzhiyun         mtype = MASTER_POINTER;
404*4882a593Smuzhiyun         break;
405*4882a593Smuzhiyun     default:
406*4882a593Smuzhiyun         mtype = MASTER_ATTACHED;
407*4882a593Smuzhiyun         break;
408*4882a593Smuzhiyun     }
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun     mdev = GetMaster(sdev, mtype);
411*4882a593Smuzhiyun     memcpy(copy, original, len);
412*4882a593Smuzhiyun     ChangeDeviceID(mdev, copy);
413*4882a593Smuzhiyun     FixUpEventForMaster(mdev, sdev, original, copy);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun     return mdev;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun static void
mieqMoveToNewScreen(DeviceIntPtr dev,ScreenPtr screen,DeviceEvent * event)419*4882a593Smuzhiyun mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun     if (dev && screen && screen != DequeueScreen(dev)) {
422*4882a593Smuzhiyun         int x = 0, y = 0;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun         DequeueScreen(dev) = screen;
425*4882a593Smuzhiyun         x = event->root_x;
426*4882a593Smuzhiyun         y = event->root_y;
427*4882a593Smuzhiyun         NewCurrentScreen(dev, DequeueScreen(dev), x, y);
428*4882a593Smuzhiyun     }
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun /**
432*4882a593Smuzhiyun  * Post the given @event through the device hierarchy, as appropriate.
433*4882a593Smuzhiyun  * Use this function if an event must be posted for a given device during the
434*4882a593Smuzhiyun  * usual event processing cycle.
435*4882a593Smuzhiyun  */
436*4882a593Smuzhiyun void
mieqProcessDeviceEvent(DeviceIntPtr dev,InternalEvent * event,ScreenPtr screen)437*4882a593Smuzhiyun mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun     mieqHandler handler;
440*4882a593Smuzhiyun     DeviceIntPtr master;
441*4882a593Smuzhiyun     InternalEvent mevent;       /* master event */
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun     verify_internal_event(event);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun     /* refuse events from disabled devices */
446*4882a593Smuzhiyun     if (dev && !dev->enabled)
447*4882a593Smuzhiyun         return;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun     /* Custom event handler */
450*4882a593Smuzhiyun     handler = miEventQueue.handlers[event->any.type];
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun     switch (event->any.type) {
453*4882a593Smuzhiyun         /* Catch events that include valuator information and check if they
454*4882a593Smuzhiyun          * are changing the screen */
455*4882a593Smuzhiyun     case ET_Motion:
456*4882a593Smuzhiyun     case ET_KeyPress:
457*4882a593Smuzhiyun     case ET_KeyRelease:
458*4882a593Smuzhiyun     case ET_ButtonPress:
459*4882a593Smuzhiyun     case ET_ButtonRelease:
460*4882a593Smuzhiyun         if (!handler)
461*4882a593Smuzhiyun             mieqMoveToNewScreen(dev, screen, &event->device_event);
462*4882a593Smuzhiyun         break;
463*4882a593Smuzhiyun     case ET_TouchBegin:
464*4882a593Smuzhiyun     case ET_TouchUpdate:
465*4882a593Smuzhiyun     case ET_TouchEnd:
466*4882a593Smuzhiyun         if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
467*4882a593Smuzhiyun             mieqMoveToNewScreen(dev, screen, &event->device_event);
468*4882a593Smuzhiyun         break;
469*4882a593Smuzhiyun     default:
470*4882a593Smuzhiyun         break;
471*4882a593Smuzhiyun     }
472*4882a593Smuzhiyun     master = CopyGetMasterEvent(dev, event, &mevent);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun     if (master)
475*4882a593Smuzhiyun         master->lastSlave = dev;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun     /* If someone's registered a custom event handler, let them
478*4882a593Smuzhiyun      * steal it. */
479*4882a593Smuzhiyun     if (handler) {
480*4882a593Smuzhiyun         int screenNum = dev &&
481*4882a593Smuzhiyun             DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
482*4882a593Smuzhiyun                                                               myNum : 0);
483*4882a593Smuzhiyun         handler(screenNum, event, dev);
484*4882a593Smuzhiyun         /* Check for the SD's master in case the device got detached
485*4882a593Smuzhiyun          * during event processing */
486*4882a593Smuzhiyun         if (master && !IsFloating(dev))
487*4882a593Smuzhiyun             handler(screenNum, &mevent, master);
488*4882a593Smuzhiyun     }
489*4882a593Smuzhiyun     else {
490*4882a593Smuzhiyun         /* process slave first, then master */
491*4882a593Smuzhiyun         dev->public.processInputProc(event, dev);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun         /* Check for the SD's master in case the device got detached
494*4882a593Smuzhiyun          * during event processing */
495*4882a593Smuzhiyun         if (master && !IsFloating(dev))
496*4882a593Smuzhiyun             master->public.processInputProc(&mevent, master);
497*4882a593Smuzhiyun     }
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun /* Call this from ProcessInputEvents(). */
501*4882a593Smuzhiyun void
mieqProcessInputEvents(void)502*4882a593Smuzhiyun mieqProcessInputEvents(void)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun     EventRec *e = NULL;
505*4882a593Smuzhiyun     ScreenPtr screen;
506*4882a593Smuzhiyun     InternalEvent event;
507*4882a593Smuzhiyun     DeviceIntPtr dev = NULL, master = NULL;
508*4882a593Smuzhiyun     static Bool inProcessInputEvents = FALSE;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun     input_lock();
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun     /*
513*4882a593Smuzhiyun      * report an error if mieqProcessInputEvents() is called recursively;
514*4882a593Smuzhiyun      * this can happen, e.g., if something in the mieqProcessDeviceEvent()
515*4882a593Smuzhiyun      * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
516*4882a593Smuzhiyun      */
517*4882a593Smuzhiyun     BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
518*4882a593Smuzhiyun     inProcessInputEvents = TRUE;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun     if (miEventQueue.dropped) {
521*4882a593Smuzhiyun         ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
522*4882a593Smuzhiyun                (unsigned long) miEventQueue.dropped);
523*4882a593Smuzhiyun         ErrorF
524*4882a593Smuzhiyun             ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
525*4882a593Smuzhiyun         miEventQueue.dropped = 0;
526*4882a593Smuzhiyun     }
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun     while (miEventQueue.head != miEventQueue.tail) {
529*4882a593Smuzhiyun         e = &miEventQueue.events[miEventQueue.head];
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun         event = *e->events;
532*4882a593Smuzhiyun         dev = e->pDev;
533*4882a593Smuzhiyun         screen = e->pScreen;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun         miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun         input_unlock();
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun         master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun         if (screenIsSaved == SCREEN_SAVER_ON)
542*4882a593Smuzhiyun             dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
543*4882a593Smuzhiyun #ifdef DPMSExtension
544*4882a593Smuzhiyun         else if (DPMSPowerLevel != DPMSModeOn)
545*4882a593Smuzhiyun             SetScreenSaverTimer();
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun         if (DPMSPowerLevel != DPMSModeOn)
548*4882a593Smuzhiyun             DPMSSet(serverClient, DPMSModeOn);
549*4882a593Smuzhiyun #endif
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun         mieqProcessDeviceEvent(dev, &event, screen);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun         /* Update the sprite now. Next event may be from different device. */
554*4882a593Smuzhiyun         if (master &&
555*4882a593Smuzhiyun             (event.any.type == ET_Motion ||
556*4882a593Smuzhiyun              ((event.any.type == ET_TouchBegin ||
557*4882a593Smuzhiyun                event.any.type == ET_TouchUpdate) &&
558*4882a593Smuzhiyun               event.device_event.flags & TOUCH_POINTER_EMULATED)))
559*4882a593Smuzhiyun             miPointerUpdateSprite(dev);
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun         input_lock();
562*4882a593Smuzhiyun     }
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun     inProcessInputEvents = FALSE;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun     input_unlock();
567*4882a593Smuzhiyun }
568