diff options
-rw-r--r-- | dix/events.c | 46 | ||||
-rw-r--r-- | include/dix.h | 1 | ||||
-rw-r--r-- | include/inputstr.h | 6 | ||||
-rw-r--r-- | test/input.c | 67 |
4 files changed, 92 insertions, 28 deletions
diff --git a/dix/events.c b/dix/events.c index 4847db005..3c21a964c 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1132,12 +1132,14 @@ NoticeEventTime(InternalEvent *ev) void EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) { - QdEventPtr tail = *syncEvents.pendtail; + QdEventPtr tail; QdEventPtr qe; SpritePtr pSprite = device->spriteInfo->sprite; int eventlen; DeviceEvent *event = &ev->device_event; + tail = list_last_entry(&syncEvents.pending, QdEventRec, next); + NoticeTime((InternalEvent*)event); /* Fix for key repeating bug. */ @@ -1196,15 +1198,13 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) qe = malloc(sizeof(QdEventRec) + eventlen); if (!qe) return; - qe->next = (QdEventPtr)NULL; + list_init(&qe->next); qe->device = device; qe->pScreen = pSprite->hotPhys.pScreen; qe->months = currentTime.months; qe->event = (InternalEvent *)(qe + 1); memcpy(qe->event, event, eventlen); - if (tail) - syncEvents.pendtail = &tail->next; - *syncEvents.pendtail = qe; + list_append(&qe->next, &syncEvents.pending); } /** @@ -1216,22 +1216,20 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) * If there is none, we're done. If there is at least one device that is not * frozen, then re-run from the beginning of the event queue. */ -static void +void PlayReleasedEvents(void) { - QdEventPtr *prev, qe; + QdEventPtr tmp; + QdEventPtr qe; DeviceIntPtr dev; DeviceIntPtr pDev; - prev = &syncEvents.pending; - while ( (qe = *prev) ) - { +restart: + list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) { if (!qe->device->deviceGrab.sync.frozen) { - *prev = qe->next; - pDev = qe->device; - if (*syncEvents.pendtail == *prev) - syncEvents.pendtail = prev; + list_del(&qe->next); + pDev = qe->device; if (qe->event->any.type == ET_Motion) CheckVirtualMotion(pDev, qe, NullWindow); syncEvents.time.months = qe->months; @@ -1268,12 +1266,11 @@ PlayReleasedEvents(void) ; if (!dev) break; + /* Playing the event may have unfrozen another device. */ /* So to play it safe, restart at the head of the queue */ - prev = &syncEvents.pending; + goto restart; } - else - prev = &qe->next; } } @@ -1314,7 +1311,8 @@ ComputeFreezes(void) for (dev = inputInfo.devices; dev; dev = dev->next) FreezeThaw(dev, dev->deviceGrab.sync.other || (dev->deviceGrab.sync.state >= FROZEN)); - if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) + if (syncEvents.playingEvents || + (!replayDev && list_is_empty(&syncEvents.pending))) return; syncEvents.playingEvents = TRUE; if (replayDev) @@ -5258,6 +5256,7 @@ void InitEvents(void) { int i; + QdEventPtr qe, tmp; inputInfo.numDevices = 0; inputInfo.devices = (DeviceIntPtr)NULL; @@ -5271,13 +5270,10 @@ InitEvents(void) syncEvents.replayDev = (DeviceIntPtr)NULL; syncEvents.replayWin = NullWindow; - while (syncEvents.pending) - { - QdEventPtr next = syncEvents.pending->next; - free(syncEvents.pending); - syncEvents.pending = next; - } - syncEvents.pendtail = &syncEvents.pending; + if (syncEvents.pending.next) + list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) + free(qe); + list_init(&syncEvents.pending); syncEvents.playingEvents = FALSE; syncEvents.time.months = 0; syncEvents.time.milliseconds = 0; /* hardly matters */ diff --git a/include/dix.h b/include/dix.h index 34661f3b6..8e35d2cf5 100644 --- a/include/dix.h +++ b/include/dix.h @@ -339,6 +339,7 @@ extern _X_EXPORT void NoticeEventTime(InternalEvent *ev); extern void EnqueueEvent( InternalEvent * /* ev */, DeviceIntPtr /* device */); +extern void PlayReleasedEvents(void); extern void ActivatePointerGrab( DeviceIntPtr /* mouse */, diff --git a/include/inputstr.h b/include/inputstr.h index f482a2294..0568e0c9d 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -575,7 +575,7 @@ extern _X_EXPORT InputInfo inputInfo; /* for keeping the events for devices grabbed synchronously */ typedef struct _QdEvent *QdEventPtr; typedef struct _QdEvent { - QdEventPtr next; + struct list next; DeviceIntPtr device; ScreenPtr pScreen; /* what screen the pointer was on */ unsigned long months; /* milliseconds is in the event */ @@ -591,8 +591,8 @@ typedef struct _QdEvent { * replayed and processed as if they would come from the device directly. */ typedef struct _EventSyncInfo { - QdEventPtr pending, /**< list of queued events */ - *pendtail; /**< last event in list */ + struct list pending; + /** The device to replay events for. Only set in AllowEvents(), in which * case it is set to the device specified in the request. */ DeviceIntPtr replayDev; /* kludgy rock to put flag for */ diff --git a/test/input.c b/test/input.c index 5b4c8c193..c44e5f613 100644 --- a/test/input.c +++ b/test/input.c @@ -1674,8 +1674,75 @@ mieq_test(void) { mieqFini(); } +/* Simple check that we're replaying events in-order */ +static void +process_input_proc(InternalEvent *ev, DeviceIntPtr device) +{ + static int last_evtype = -1; + + if (ev->any.header == 0xac) + last_evtype = -1; + + assert(ev->any.type == ++last_evtype); +} + +static void +dix_enqueue_events(void) { +#define NEVENTS 5 + DeviceIntRec dev; + InternalEvent ev[NEVENTS]; + SpriteInfoRec spriteInfo; + SpriteRec sprite; + QdEventPtr qe; + int i; + + memset(&dev, 0, sizeof(dev)); + dev.public.processInputProc = process_input_proc; + + memset(&spriteInfo, 0, sizeof(spriteInfo)); + memset(&sprite, 0, sizeof(sprite)); + dev.spriteInfo = &spriteInfo; + spriteInfo.sprite = &sprite; + + InitEvents(); + assert(list_is_empty(&syncEvents.pending)); + + /* this way PlayReleasedEvents really runs through all events in the + * queue */ + inputInfo.devices = &dev; + + /* to reset process_input_proc */ + ev[0].any.header = 0xac; + + for (i = 0; i < NEVENTS; i++) + { + ev[i].any.length = sizeof(*ev); + ev[i].any.type = i; + EnqueueEvent(&ev[i], &dev); + assert(!list_is_empty(&syncEvents.pending)); + qe = list_last_entry(&syncEvents.pending, QdEventRec, next); + assert(memcmp(qe->event, &ev[i], ev[i].any.length) == 0); + qe = list_first_entry(&syncEvents.pending, QdEventRec, next); + assert(memcmp(qe->event, &ev[0], ev[i].any.length) == 0); + } + + /* calls process_input_proc */ + dev.deviceGrab.sync.frozen = 1; + PlayReleasedEvents(); + assert(!list_is_empty(&syncEvents.pending)); + + + dev.deviceGrab.sync.frozen = 0; + PlayReleasedEvents(); + assert(list_is_empty(&syncEvents.pending)); + + inputInfo.devices = NULL; +} + + int main(int argc, char** argv) { + dix_enqueue_events(); dix_double_fp_conversion(); dix_input_valuator_masks(); dix_input_attributes(); |