1 Index: xorg-server/include/protocol-versions.h
2 ===================================================================
3 --- xorg-server.orig/include/protocol-versions.h 2012-03-07 22:24:45.540697115 +1100
4 +++ xorg-server/include/protocol-versions.h 2012-03-08 07:40:35.472111389 +1100
5 @@ -122,7 +122,7 @@
6 #define SERVER_XF86VIDMODE_MINOR_VERSION 2
8 /* Fixes */
9 -#define SERVER_XFIXES_MAJOR_VERSION 5
10 +#define SERVER_XFIXES_MAJOR_VERSION 6
11 #define SERVER_XFIXES_MINOR_VERSION 0
13 /* X Input */
14 Index: xorg-server/xfixes/cursor.c
15 ===================================================================
16 --- xorg-server.orig/xfixes/cursor.c 2012-03-07 22:24:45.580697117 +1100
17 +++ xorg-server/xfixes/cursor.c 2012-03-08 11:00:53.155469738 +1100
18 @@ -61,6 +61,7 @@
19 static RESTYPE CursorHideCountType;
20 static RESTYPE CursorWindowType;
21 RESTYPE PointerBarrierType;
22 +static RESTYPE PointerBarrierClientType;
23 static CursorPtr CursorCurrent[MAXDEVICES];
25 static DevPrivateKeyRec CursorScreenPrivateKeyRec;
26 @@ -119,6 +120,11 @@
27 struct list entry;
28 };
30 +/**
31 + * Pick up unclamped (x,y) coordinates from dix/getevents
32 + */
33 +extern int unclamped_prex, unclamped_prey;
34 +
35 /*
36 * Wrap DisplayCursor to catch cursor change events
37 */
38 @@ -129,6 +135,7 @@
39 ConstrainCursorHarderProcPtr ConstrainCursorHarder;
40 CursorHideCountPtr pCursorHideCounts;
41 struct list barriers;
42 + struct list barrierClients;
43 } CursorScreenRec, *CursorScreenPtr;
45 #define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
46 @@ -1118,7 +1125,8 @@
48 /* Algorithm below doesn't handle edge cases well, hence the extra
49 * checks. */
50 - if (barrier_is_vertical(barrier)) {
51 + if (barrier_is_vertical(barrier) &&
52 + (dir & (BarrierPositiveX | BarrierNegativeX))) {
53 /* handle immediate barrier adjacency, moving away */
54 if (dir & BarrierPositiveX && x1 == barrier->x1)
55 return FALSE;
56 @@ -1129,7 +1137,8 @@
57 *distance = 0;
58 return TRUE;
59 }
60 - } else {
61 + } else if (barrier_is_horizontal(barrier) &&
62 + (dir & (BarrierPositiveY | BarrierNegativeY))){
63 /* handle immediate barrier adjacency, moving away */
64 if (dir & BarrierPositiveY && y1 == barrier->y1)
65 return FALSE;
66 @@ -1231,6 +1240,127 @@
67 }
68 }
70 +/*
71 + * ConstrainCursorHarder is called from the SIGIO context.
72 + * This means we cannot safely send a client event from anything in
73 + * CursorConstrainCursorHarder's callgraph.
74 + *
75 + * Allocate a set of WorkQueue items to use.
76 + */
77 +
78 +struct BarrierEventStore {
79 + WorkQueueRec wq_item;
80 + xXFixesBarrierNotifyEvent ev;
81 + Bool in_use;
82 +};
83 +
84 +/* Let's guess that 100 events is enough of a buffer. */
85 +#define BARRIER_EVENT_QUEUE_SIZE 100
86 +struct BarrierEventStore barrierEventQueue[BARRIER_EVENT_QUEUE_SIZE];
87 +
88 +static void
89 +CursorWorkQueueDestroyProc (WorkQueuePtr this)
90 +{
91 + struct BarrierEventStore *store;
92 + store = container_of (this, struct BarrierEventStore, wq_item);
93 +
94 + store->in_use = FALSE;
95 +}
96 +
97 +static Bool
98 +CursorSendBarrierEvent (ClientPtr client, pointer eventStore)
99 +{
100 + struct BarrierEventStore *store = (struct BarrierEventStore *)eventStore;
101 + WriteEventsToClient (client, 1, (xEvent *)&store->ev);
102 +
103 + return TRUE;
104 +}
105 +
106 +static struct BarrierEventStore *
107 +CursorFindFreeEventStore (void)
108 +{
109 + for (int i = 0; i < BARRIER_EVENT_QUEUE_SIZE; ++i) {
110 + if (!barrierEventQueue[i].in_use) {
111 + return &barrierEventQueue[i];
112 + }
113 + }
114 + return NULL;
115 +}
116 +
117 +static void
118 +QueueBarrierEvent(CursorScreenPtr cs, struct PointerBarrier *barrier,
119 + int x, int y, int velocity, Bool threshold_exceeded)
120 +{
121 + PointerBarrierEventClientPtr client;
122 + struct BarrierEventStore *store;
123 + list_for_each_entry(client, &cs->barrierClients, entry) {
124 + store = CursorFindFreeEventStore ();
125 + if (store == NULL) {
126 + ErrorF ("[xfixes] Barrier event queue full. Dropping further events\n");
127 + return;
128 + }
129 +
130 + store->in_use = TRUE;
131 +
132 + store->ev.type = XFixesEventBase + XFixesBarrierNotify;
133 + store->ev.subtype = threshold_exceeded ? XFixesBarrierThresholdExceededNotify :
134 + XFixesBarrierHitNotify;
135 + store->ev.event_id = barrier->barrierEventID;
136 + store->ev.barrier = barrier->barrier;
137 + store->ev.x = x;
138 + store->ev.y = y;
139 + store->ev.velocity = velocity;
140 + store->ev.timestamp = currentTime.milliseconds;
141 +
142 + if (client->client->swapped) {
143 + int n;
144 +
145 + swapl(&store->ev.event_id, n);
146 + swapl(&store->ev.barrier, n);
147 + swaps(&store->ev.x, n);
148 + swaps(&store->ev.y, n);
149 + swapl(&store->ev.velocity, n);
150 + swapl(&store->ev.timestamp, n);
151 + }
152 +
153 + store->wq_item.function = CursorSendBarrierEvent;
154 + store->wq_item.client = client->client;
155 + store->wq_item.closure = store;
156 + store->wq_item.destroyProc = CursorWorkQueueDestroyProc;
157 +
158 + QueueWorkItem (&store->wq_item);
159 + }
160 +}
161 +
162 +static void
163 +barrier_calculate_velocity_components (int x1, int y1, int x2, int y2,
164 + int *vel_x, int *vel_y)
165 +{
166 + static CARD32 last_timestamp = 0;
167 + CARD32 timestamp = GetTimeInMillis();
168 + int dx, dy;
169 + int dt = timestamp - last_timestamp;
170 +
171 + if (last_timestamp == 0) {
172 + /* Not much we can do for the first event */
173 + *vel_x = 0;
174 + *vel_y = 0;
175 + last_timestamp = timestamp;
176 + return;
177 + }
178 +
179 + /* Lets not divide by zero if we can avoid it */
180 + dt = dt > 0 ? dt : 1;
181 +
182 + dx = x2 - x1;
183 + dy = y2 - y1;
184 +
185 + *vel_x = abs(dx) * 1000.0 / dt;
186 + *vel_y = abs(dy) * 1000.0 / dt;
187 +
188 + last_timestamp = timestamp;
189 +}
190 +
191 static void
192 CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y)
193 {
194 @@ -1238,12 +1368,23 @@
196 if (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) {
197 int ox, oy;
198 + int vel_x, vel_y;
199 int dir;
200 struct PointerBarrier *nearest = NULL;
201 + PointerBarrierClientPtr c;
203 /* where are we coming from */
204 miPointerGetPosition(dev, &ox, &oy);
206 + /* Use the unclamped values, if available. If not, *x, *y
207 + * will have to do.
208 + * NOTE: We should never get here with unclamped values unset.
209 + */
210 + if (unclamped_prex == -1 || unclamped_prey == -1) {
211 + unclamped_prex = *x;
212 + unclamped_prey = *y;
213 + }
214 +
215 /* How this works:
216 * Given the origin and the movement vector, get the nearest barrier
217 * to the origin that is blocking the movement.
218 @@ -1251,11 +1392,27 @@
219 * Then, check from the clamped intersection to the original
220 * destination, again finding the nearest barrier and clamping.
221 */
222 - dir = barrier_get_direction(ox, oy, *x, *y);
223 + dir = barrier_get_direction(ox, oy, unclamped_prex, unclamped_prey);
224 + barrier_calculate_velocity_components(ox, oy, unclamped_prex, unclamped_prey, &vel_x, &vel_y);
226 - nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
227 + nearest = barrier_find_nearest(cs, dir, ox, oy, unclamped_prex, unclamped_prey);
228 if (nearest) {
229 - barrier_clamp_to_barrier(nearest, dir, x, y);
230 + int velocity = barrier_is_vertical(nearest) ? vel_x : vel_y;
231 + Bool threshold_exceeded = (nearest->velocity != 0) &&
232 + (velocity > nearest->velocity);
233 +
234 + if (!nearest->lastHit) {
235 + /* This is the start of a new barrier event */
236 + nearest->barrierEventID++;
237 + }
238 +
239 + if ((!threshold_exceeded || nearest->lastHit) &&
240 + (nearest->barrierEventID != nearest->releaseEventID)) {
241 + barrier_clamp_to_barrier(nearest, dir, x, y);
242 + nearest->hit = TRUE;
243 + }
244 +
245 + QueueBarrierEvent(cs, nearest, *x, *y, velocity, threshold_exceeded);
247 if (barrier_is_vertical(nearest)) {
248 dir &= ~(BarrierNegativeX | BarrierPositiveX);
249 @@ -1265,11 +1422,31 @@
250 oy = *y;
251 }
253 - nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
254 + nearest = barrier_find_nearest(cs, dir, ox, oy, unclamped_prex, unclamped_prey);
255 if (nearest) {
256 - barrier_clamp_to_barrier(nearest, dir, x, y);
257 + velocity = barrier_is_vertical(nearest) ? vel_x : vel_y;
258 + threshold_exceeded = (nearest->velocity != 0) &&
259 + (velocity > nearest->velocity);
260 +
261 + if (!nearest->lastHit) {
262 + /* This is the start of a new barrier event */
263 + nearest->barrierEventID++;
264 + }
265 +
266 + if ((!threshold_exceeded || nearest->lastHit) &&
267 + (nearest->barrierEventID != nearest->releaseEventID)) {
268 + barrier_clamp_to_barrier(nearest, dir, x, y);
269 + nearest->hit = TRUE;
270 + }
271 +
272 + QueueBarrierEvent(cs, nearest, *x, *y, velocity, threshold_exceeded);
273 }
274 }
275 +
276 + list_for_each_entry(c, &cs->barriers, entry) {
277 + c->barrier.lastHit = c->barrier.hit;
278 + c->barrier.hit = FALSE;
279 + }
280 }
282 if (cs->ConstrainCursorHarder) {
283 @@ -1284,15 +1461,45 @@
284 xXFixesCreatePointerBarrierReq *stuff)
285 {
286 CursorScreenPtr cs = GetCursorScreen(screen);
287 - struct PointerBarrierClient *ret = malloc(sizeof(*ret));
288 + struct PointerBarrierClient *ret = calloc(sizeof(*ret), 1);
290 if (ret) {
291 ret->screen = screen;
292 + ret->barrier.barrier = stuff->barrier;
293 ret->barrier.x1 = min(stuff->x1, stuff->x2);
294 ret->barrier.x2 = max(stuff->x1, stuff->x2);
295 ret->barrier.y1 = min(stuff->y1, stuff->y2);
296 ret->barrier.y2 = max(stuff->y1, stuff->y2);
297 ret->barrier.directions = stuff->directions & 0x0f;
298 + ret->barrier.velocity = 0;
299 + ret->barrier.barrierEventID = 0;
300 + if (barrier_is_horizontal(&ret->barrier))
301 + ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
302 + if (barrier_is_vertical(&ret->barrier))
303 + ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
304 + list_add(&ret->entry, &cs->barriers);
305 + }
306 +
307 + return ret;
308 +}
309 +
310 +static struct PointerBarrierClient *
311 +CreatePointerBarrierVelocityClient(ScreenPtr screen, ClientPtr client,
312 + xXFixesCreatePointerBarrierVelocityReq *stuff)
313 +{
314 + CursorScreenPtr cs = GetCursorScreen(screen);
315 + struct PointerBarrierClient *ret = calloc(sizeof(*ret), 1);
316 +
317 + if (ret) {
318 + ret->screen = screen;
319 + ret->barrier.barrier = stuff->barrier;
320 + ret->barrier.x1 = min(stuff->x1, stuff->x2);
321 + ret->barrier.x2 = max(stuff->x1, stuff->x2);
322 + ret->barrier.y1 = min(stuff->y1, stuff->y2);
323 + ret->barrier.y2 = max(stuff->y1, stuff->y2);
324 + ret->barrier.directions = stuff->directions & 0x0f;
325 + ret->barrier.velocity = stuff->velocity;
326 + ret->barrier.barrierEventID = 0;
327 if (barrier_is_horizontal(&ret->barrier))
328 ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
329 if (barrier_is_vertical(&ret->barrier))
330 @@ -1365,6 +1572,69 @@
331 return ProcXFixesVector[stuff->xfixesReqType](client);
332 }
334 +int
335 +ProcXFixesCreatePointerBarrierVelocity (ClientPtr client)
336 +{
337 + int err;
338 + WindowPtr pWin;
339 + struct PointerBarrierClient *barrier;
340 + struct PointerBarrier b;
341 + REQUEST (xXFixesCreatePointerBarrierVelocityReq);
342 +
343 + REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierVelocityReq);
344 + LEGAL_NEW_RESOURCE(stuff->barrier, client);
345 +
346 + err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
347 + if (err != Success) {
348 + client->errorValue = stuff->window;
349 + return err;
350 + }
351 +
352 + /* This sure does need fixing. */
353 + if (stuff->num_devices)
354 + return BadImplementation;
355 +
356 + b.x1 = stuff->x1;
357 + b.x2 = stuff->x2;
358 + b.y1 = stuff->y1;
359 + b.y2 = stuff->y2;
360 +
361 + if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
362 + return BadValue;
363 +
364 + /* no 0-sized barriers */
365 + if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
366 + return BadValue;
367 +
368 + if (!(barrier = CreatePointerBarrierVelocityClient(pWin->drawable.pScreen,
369 + client, stuff)))
370 + return BadAlloc;
371 +
372 + if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
373 + return BadAlloc;
374 +
375 + return Success;
376 +}
377 +
378 +int
379 +SProcXFixesCreatePointerBarrierVelocity (ClientPtr client)
380 +{
381 + int n;
382 + REQUEST(xXFixesCreatePointerBarrierVelocityReq);
383 +
384 + swaps(&stuff->length, n);
385 + REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
386 + swapl(&stuff->barrier, n);
387 + swapl(&stuff->window, n);
388 + swaps(&stuff->x1, n);
389 + swaps(&stuff->y1, n);
390 + swaps(&stuff->x2, n);
391 + swaps(&stuff->y2, n);
392 + swapl(&stuff->directions, n);
393 + swapl(&stuff->velocity, n);
394 + return ProcXFixesVector[stuff->xfixesReqType](client);
395 +}
396 +
397 static int
398 CursorFreeBarrier(void *data, XID id)
399 {
400 @@ -1421,6 +1691,118 @@
401 return ProcXFixesVector[stuff->xfixesReqType](client);
402 }
404 +static int
405 +CursorFreeBarrierClient(void *data, XID id)
406 +{
407 + PointerBarrierEventClientPtr client = data, c;
408 + ScreenPtr screen = client->screen;
409 + CursorScreenPtr cs = GetCursorScreen(screen);
410 +
411 + /* find and unlink from the screen private */
412 + list_for_each_entry(c, &cs->barrierClients, entry) {
413 + if (c == client) {
414 + list_del(&c->entry);
415 + break;
416 + }
417 + }
418 +
419 + free(client);
420 + return Success;
421 +}
422 +
423 +static struct PointerBarrierEventClient *
424 +CreatePointerBarrierEventClient(ScreenPtr screen, ClientPtr client,
425 + xXFixesSelectBarrierInputReq *stuff)
426 +{
427 + CursorScreenPtr cs = GetCursorScreen(screen);
428 + struct PointerBarrierEventClient *ret = malloc(sizeof(*ret));
429 +
430 + if (ret) {
431 + ret->screen = screen;
432 + ret->client = client;
433 + ret->eventMask = stuff->eventMask;
434 + ret->window = stuff->window;
435 + ret->resource = FakeClientID (client->index);
436 + list_add(&ret->entry, &cs->barrierClients);
437 + }
438 +
439 + return ret;
440 +}
441 +
442 +int
443 +ProcXFixesSelectBarrierInput (ClientPtr client)
444 +{
445 + int err;
446 + WindowPtr pWin;
447 + struct PointerBarrierEventClient *eventClient;
448 + REQUEST (xXFixesSelectBarrierInputReq);
449 +
450 + REQUEST_SIZE_MATCH(xXFixesSelectBarrierInputReq);
451 +
452 + err = dixLookupWindow(&pWin , stuff->window, client, DixReadAccess);
453 + if (err != Success) {
454 + client->errorValue = stuff->window;
455 + return err;
456 + }
457 +
458 + if (!(eventClient = CreatePointerBarrierEventClient(pWin->drawable.pScreen,
459 + client,
460 + stuff)))
461 + return BadAlloc;
462 +
463 + if (!AddResource (eventClient->resource, PointerBarrierClientType, eventClient))
464 + return BadAlloc;
465 +
466 + return Success;
467 +}
468 +
469 +int
470 +SProcXFixesSelectBarrierInput (ClientPtr client)
471 +{
472 + int n;
473 + REQUEST(xXFixesSelectBarrierInputReq);
474 +
475 + swaps(&stuff->length, n);
476 + REQUEST_SIZE_MATCH(xXFixesSelectBarrierInputReq);
477 + swapl(&stuff->window, n);
478 + swapl(&stuff->eventMask, n);
479 + return ProcXFixesVector[stuff->xfixesReqType](client);
480 +}
481 +
482 +int
483 +ProcXFixesBarrierReleasePointer (ClientPtr client)
484 +{
485 + int err;
486 + struct PointerBarrier *barrier;
487 + REQUEST (xXFixesBarrierReleasePointerReq);
488 + REQUEST_SIZE_MATCH(xXFixesBarrierReleasePointerReq);
489 +
490 + err = dixLookupResourceByType((void **)&barrier, stuff->barrier,
491 + PointerBarrierType, client,
492 + DixReadAccess);
493 + if (err != Success) {
494 + client->errorValue = stuff->barrier;
495 + return err;
496 + }
497 +
498 + barrier->releaseEventID = stuff->event_id;
499 +
500 + return Success;
501 +}
502 +
503 +int
504 +SProcXFixesBarrierReleasePointer (ClientPtr client)
505 +{
506 + int n;
507 + REQUEST(xXFixesBarrierReleasePointerReq);
508 +
509 + swaps(&stuff->length, n);
510 + REQUEST_SIZE_MATCH(xXFixesBarrierReleasePointerReq);
511 + swapl(&stuff->barrier, n);
512 + swapl(&stuff->event_id, n);
513 + return ProcXFixesVector[stuff->xfixesReqType](client);
514 +}
515 +
516 Bool
517 XFixesCursorInit (void)
518 {
519 @@ -1441,6 +1823,7 @@
520 if (!cs)
521 return FALSE;
522 list_init(&cs->barriers);
523 + list_init(&cs->barrierClients);
524 Wrap (cs, pScreen, CloseScreen, CursorCloseScreen);
525 Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor);
526 Wrap (cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder);
527 @@ -1455,8 +1838,10 @@
528 "XFixesCursorWindow");
529 PointerBarrierType = CreateNewResourceType(CursorFreeBarrier,
530 "XFixesPointerBarrier");
531 + PointerBarrierClientType = CreateNewResourceType(CursorFreeBarrierClient,
532 + "XFixesPointerBarrierClient");
534 return CursorClientType && CursorHideCountType && CursorWindowType &&
535 - PointerBarrierType;
536 + PointerBarrierType && PointerBarrierClientType;
537 }
539 Index: xorg-server/xfixes/xfixes.c
540 ===================================================================
541 --- xorg-server.orig/xfixes/xfixes.c 2012-03-07 22:24:45.592697117 +1100
542 +++ xorg-server/xfixes/xfixes.c 2012-03-08 07:40:35.480111388 +1100
543 @@ -100,6 +100,7 @@
544 X_XFixesExpandRegion, /* Version 3 */
545 X_XFixesShowCursor, /* Version 4 */
546 X_XFixesDestroyPointerBarrier, /* Version 5 */
547 + X_XFixesBarrierReleasePointer, /* Version 6 */
548 };
550 #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
551 @@ -143,6 +144,10 @@
552 /*************** Version 5 ****************/
553 ProcXFixesCreatePointerBarrier,
554 ProcXFixesDestroyPointerBarrier,
555 +/*************** Version 6 ****************/
556 + ProcXFixesCreatePointerBarrierVelocity,
557 + ProcXFixesSelectBarrierInput,
558 + ProcXFixesBarrierReleasePointer,
559 };
561 static int
562 @@ -209,6 +214,10 @@
563 /*************** Version 5 ****************/
564 SProcXFixesCreatePointerBarrier,
565 SProcXFixesDestroyPointerBarrier,
566 +/*************** Version 6 ****************/
567 + SProcXFixesCreatePointerBarrierVelocity,
568 + SProcXFixesSelectBarrierInput,
569 + SProcXFixesBarrierReleasePointer,
570 };
572 static int
573 Index: xorg-server/xfixes/xfixes.h
574 ===================================================================
575 --- xorg-server.orig/xfixes/xfixes.h 2012-03-07 22:24:45.608697118 +1100
576 +++ xorg-server/xfixes/xfixes.h 2012-03-08 07:40:35.480111388 +1100
577 @@ -28,6 +28,7 @@
578 #define _XFIXES_H_
580 #include "resource.h"
581 +#include "list.h"
583 extern _X_EXPORT RESTYPE RegionResType;
584 extern _X_EXPORT RESTYPE PointerBarrierType;
585 @@ -52,9 +53,25 @@
586 extern _X_EXPORT RegionPtr
587 XFixesRegionCopy (RegionPtr pRegion);
589 +typedef struct PointerBarrierEventClient *PointerBarrierEventClientPtr;
590 +
591 +struct PointerBarrierEventClient {
592 + ScreenPtr screen;
593 + ClientPtr client;
594 + CARD32 eventMask;
595 + XID window;
596 + XID resource;
597 + struct list entry;
598 +};
599 +
600 struct PointerBarrier {
601 + XID barrier;
602 CARD16 x1, x2, y1, y2;
603 CARD32 directions;
604 + CARD32 velocity;
605 + CARD32 barrierEventID;
606 + CARD32 releaseEventID;
607 + Bool hit, lastHit;
608 };
611 Index: xorg-server/xfixes/xfixesint.h
612 ===================================================================
613 --- xorg-server.orig/xfixes/xfixesint.h 2012-03-07 22:24:45.616697118 +1100
614 +++ xorg-server/xfixes/xfixesint.h 2012-03-08 07:40:35.480111388 +1100
615 @@ -59,6 +59,7 @@
616 #include "windowstr.h"
617 #include "selection.h"
618 #include "xfixes.h"
619 +#include "list.h"
621 extern int XFixesEventBase;
623 @@ -293,6 +294,26 @@
624 int
625 SProcXFixesDestroyPointerBarrier (ClientPtr client);
627 +/* Version 6 */
628 +
629 +int
630 +ProcXFixesSelectBarrierInput (ClientPtr client);
631 +
632 +int
633 +SProcXFixesSelectBarrierInput (ClientPtr client);
634 +
635 +int
636 +ProcXFixesCreatePointerBarrierVelocity (ClientPtr client);
637 +
638 +int
639 +SProcXFixesCreatePointerBarrierVelocity (ClientPtr client);
640 +
641 +int
642 +ProcXFixesBarrierReleasePointer (ClientPtr client);
643 +
644 +int
645 +SProcXFixesBarrierReleasePointer (ClientPtr client);
646 +
647 /* Xinerama */
648 extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr);
649 void PanoramiXFixesInit (void);
650 Index: xorg-server/dix/getevents.c
651 ===================================================================
652 --- xorg-server.orig/dix/getevents.c 2012-03-07 22:24:45.624697119 +1100
653 +++ xorg-server/dix/getevents.c 2012-03-08 11:02:31.739464474 +1100
654 @@ -79,6 +79,12 @@
655 InternalEvent* InputEventList = NULL;
657 /**
658 + * xfixes/cursor.c wants the unclamped (x,y) values for velocity
659 + * calculation. Export them here.
660 + */
661 +int unclamped_prex = -1, unclamped_prey = -1;
662 +
663 +/**
664 * Pick some arbitrary size for Xi motion history.
665 */
666 int
667 @@ -903,7 +909,15 @@
668 /* miPointerSetPosition takes care of crossing screens for us, as well as
669 * clipping to the current screen. Coordinates returned are in desktop
670 * coord system */
671 + /**
672 + * Hack to pass the unclipped values through to the pointer barrier code.
673 + * Required (for now) to calculate the velocity.
674 + */
675 + unclamped_prex = (int)floor(*screenx) - scr->x;
676 + unclamped_prey = (int)floor(*screeny) - scr->y;
677 scr = miPointerSetPosition(dev, mode, screenx, screeny);
678 + unclamped_prex = -1;
679 + unclamped_prey = -1;
681 /* If we were constrained, rescale x/y from the screen coordinates so
682 * the device valuators reflect the correct position. For screen
683 Index: xorg-server/test/gtest/xfixes_barriers.cpp
684 ===================================================================
685 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
686 +++ xorg-server/test/gtest/xfixes_barriers.cpp 2012-03-08 07:42:49.188104249 +1100
687 @@ -0,0 +1,828 @@
688 +/*
689 +
690 +Copyright (c) 2012, Canonical Ltd
691 +
692 +Permission is hereby granted, free of charge, to any person obtaining a
693 +copy of this software and associated documentation files (the "Software"),
694 +to deal in the Software without restriction, including without limitation
695 +the rights to use, copy, modify, merge, publish, distribute, sublicense,
696 +and/or sell copies of the Software, and to permit persons to whom the
697 +Software is furnished to do so, subject to the following conditions:
698 +
699 +The above copyright notice and this permission notice (including the next
700 +paragraph) shall be included in all copies or substantial portions of the
701 +Software.
702 +
703 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
704 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
705 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
706 +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
707 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
708 +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
709 +DEALINGS IN THE SOFTWARE.
710 +*/
711 +
712 +#include <iostream>
713 +#include <sys/time.h>
714 +#include <unistd.h>
715 +#include <gtest/gtest.h>
716 +#include <xorg/gtest/test.h>
717 +#include <xorg/gtest/environment.h>
718 +#include <X11/Xlib.h>
719 +#include <X11/extensions/XTest.h>
720 +#include <X11/extensions/Xfixes.h>
721 +
722 +
723 +int main (int argc, char **argv)
724 +{
725 + ::testing::InitGoogleTest (&argc, argv);
726 + xorg::testing::Environment* environment = new xorg::testing::Environment ();
727 + environment->set_conf_file (XORG_DUMMY_CONF);
728 + environment->set_server (XORG_BINARY);
729 + testing::AddGlobalTestEnvironment (environment);
730 + return RUN_ALL_TESTS ();
731 +}
732 +
733 +class BarrierTest : public xorg::testing::Test {
734 + public:
735 + ::Display *dpy;
736 + static XErrorEvent *lastError;
737 + int xtest_eventbase;
738 + int xtest_errorbase;
739 + int fixes_eventbase;
740 + int fixes_errorbase;
741 +
742 + void AssertPointerPosition (int expected_x, int expected_y)
743 + {
744 + int x, y, unused_int;
745 + unsigned int unused_uint;
746 + Window unused_win;
747 +
748 + XQueryPointer (Display (), DefaultRootWindow (Display ()),
749 + &unused_win, &unused_win, &x, &y,
750 + &unused_int, &unused_int, &unused_uint);
751 +
752 + ASSERT_TRUE (x == expected_x && y == expected_y) <<
753 + "Incorrect pointer position: Expected ("<<
754 + expected_x<< ", "<<expected_y<<"), got "<<
755 + "("<<x<<", "<<y<<")\n";
756 + }
757 +
758 + bool WaitForXEvent (int msTimeout = 1000)
759 + {
760 + fd_set fds;
761 + int xfd = ConnectionNumber (Display ());
762 + struct timeval tv;
763 + int retval;
764 +
765 + FD_ZERO (&fds);
766 + FD_SET (xfd, &fds);
767 +
768 + tv.tv_sec = msTimeout / 1000;
769 + tv.tv_usec = (msTimeout % 1000) * 1000;
770 +
771 + retval = select (xfd + 1, &fds, NULL, NULL, &tv);
772 +
773 + EXPECT_NE (-1, retval)<<"Error waiting for X event";
774 +
775 + return retval;
776 + }
777 +
778 + protected:
779 + virtual void SetUp ()
780 + {
781 + ASSERT_NO_FATAL_FAILURE (xorg::testing::Test::SetUp());
782 +
783 + dpy = Display ();
784 + int major = 2, minor = 2;
785 + ASSERT_TRUE (XTestQueryExtension (dpy,
786 + &xtest_eventbase, &xtest_errorbase,
787 + &major, &minor));
788 + ASSERT_EQ (2, major);
789 + ASSERT_TRUE (minor >= 2);
790 +
791 + major = 6;
792 + minor = 0;
793 + XFixesQueryVersion (dpy, &major, &minor);
794 + ASSERT_EQ (6, major);
795 + ASSERT_TRUE (minor >= 0);
796 +
797 + ASSERT_TRUE (XFixesQueryExtension (dpy,
798 + &fixes_eventbase, &fixes_errorbase));
799 +
800 + lastError = new XErrorEvent;
801 + XSetErrorHandler (ErrorHandler);
802 + }
803 +
804 + private:
805 + static int ErrorHandler (::Display *dpy, XErrorEvent *error)
806 + {
807 + memcpy (lastError, error, sizeof (*lastError));
808 + return 0;
809 + }
810 +};
811 +
812 +XErrorEvent *BarrierTest::lastError = NULL;
813 +
814 +TEST_F (BarrierTest, CreateVerticalBarrierSucceeds)
815 +{
816 + PointerBarrier barrier;
817 + barrier = XFixesCreatePointerBarrier (dpy, DefaultRootWindow(dpy),
818 + 100, 0,
819 + 100, 100,
820 + 0,
821 + 0, NULL);
822 + ASSERT_NE(None, barrier);
823 +}
824 +
825 +TEST_F (BarrierTest, CreateHorizontalBarrierSucceds)
826 +{
827 + PointerBarrier barrier;
828 + barrier = XFixesCreatePointerBarrier (dpy, DefaultRootWindow(dpy),
829 + 100, 100,
830 + 200, 100,
831 + 0,
832 + 0, NULL);
833 + ASSERT_NE(None, barrier);
834 +}
835 +
836 +TEST_F (BarrierTest, CreateNonAxisAlignedBarrierFails)
837 +{
838 + XFixesCreatePointerBarrier (dpy, DefaultRootWindow(dpy),
839 + 0, 0,
840 + 100, 100,
841 + 0,
842 + 0, NULL);
843 + XSync (Display (), false);
844 + ASSERT_EQ(BadValue, lastError->error_code);
845 +}
846 +
847 +TEST_F (BarrierTest, VerticalBidirectionalBarrierBlocksRelativeMotion)
848 +{
849 + int barrier_x = 100;
850 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
851 + barrier_x, 0,
852 + barrier_x, 300,
853 + 0, 0, NULL);
854 +
855 + int x = 200, y = 100, dx = -200, dy = 0;
856 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
857 + x, y, 0);
858 +
859 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
860 +
861 + // Relative motion should block on barrier
862 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
863 +
864 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x, y));
865 +}
866 +
867 +TEST_F (BarrierTest, VerticalPositiveXBarrierBlocksMotion)
868 +{
869 + int barrier_x = 100;
870 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
871 + barrier_x, 0,
872 + barrier_x, 300,
873 + BarrierPositiveX, 0, NULL);
874 + int x = 200, y = 100, dx = -200, dy = 0;
875 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
876 + x, y, 0);
877 +
878 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
879 +
880 + // Relative motion in -ve X direction should block on barrier
881 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
882 +
883 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x, y + dy));
884 +
885 + x = 0, y = 100, dx = 200, dy = 0;
886 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
887 + x, y, 0);
888 +
889 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
890 +
891 + // Relative motion in +ve X direction should ignore barrier
892 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
893 +
894 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
895 +}
896 +
897 +TEST_F (BarrierTest, VerticalNegativeXBarrierBlocksMotion)
898 +{
899 + int barrier_x = 100;
900 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
901 + barrier_x, 0,
902 + barrier_x, 300,
903 + BarrierNegativeX,
904 + 0, NULL);
905 +
906 + int x = 200, y = 100, dx = -200, dy = 0;
907 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
908 + x, y, 0);
909 +
910 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
911 +
912 + // Relative motion in -ve X direction should ignore barrier
913 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
914 +
915 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
916 +
917 + x = 0, y = 100, dx = 200, dy = 0;
918 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
919 + x, y, 0);
920 +
921 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
922 +
923 + // Relative motion in +ve X direction should block on barrier
924 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
925 +
926 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x - 1, y + dy));
927 +}
928 +
929 +TEST_F (BarrierTest, HorizontalBidirectionalBarrierBlocksRelativeMotion)
930 +{
931 + int barrier_y = 100;
932 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
933 + 0, barrier_y,
934 + 300, barrier_y,
935 + 0, 0, NULL);
936 +
937 + int x = 200, y = 0;
938 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
939 + x, y, 0);
940 +
941 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
942 +
943 + // Relative motion in +ve Y direction should block on barrier
944 + int dx = 0, dy = 200;
945 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
946 +
947 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y - 1));
948 +
949 + x = 100, y = 200;
950 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
951 + x, y, 0);
952 +
953 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
954 +
955 + // Relative motion in -ve Y direction should block on barrier
956 + dx = 0, dy = -200;
957 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
958 +
959 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y));
960 +}
961 +
962 +TEST_F (BarrierTest, HorizontalPositiveYBarrierBlocksMotion)
963 +{
964 + int barrier_y = 100;
965 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
966 + 0, barrier_y,
967 + 300, barrier_y,
968 + BarrierPositiveY, 0, NULL);
969 +
970 + int x = 200, y = 0;
971 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
972 + x, y, 0);
973 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
974 +
975 + // Relative motion in +ve Y direction should ignore barrier
976 + int dx = 0, dy = 200;
977 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
978 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
979 +
980 + x = 100, y = 200;
981 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
982 + x, y, 0);
983 +
984 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
985 +
986 + // Relative motion in -ve Y direction should block on barrier
987 + dx = 0, dy = -200;
988 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
989 +
990 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y));
991 +}
992 +
993 +TEST_F (BarrierTest, HorizontalNegativeYBarrierBlocksMotion)
994 +{
995 + int barrier_y = 100;
996 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
997 + 0, barrier_y,
998 + 300, barrier_y,
999 + BarrierNegativeY, 0, NULL);
1000 +
1001 + int x = 200, y = 0;
1002 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1003 + x, y, 0);
1004 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1005 +
1006 + // Relative motion in +ve Y direction should block on barrier
1007 + int dx = 0, dy = 200;
1008 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1009 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y - 1));
1010 +
1011 + x = 100, y = 200;
1012 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1013 + x, y, 0);
1014 +
1015 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1016 +
1017 + // Relative motion in -ve Y direction should ignore barrier
1018 + dx = 0, dy = -200;
1019 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1020 +
1021 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1022 +}
1023 +
1024 +TEST_F (BarrierTest, DestroyPointerBarrierSucceeds)
1025 +{
1026 + int barrier_x = 100;
1027 + PointerBarrier barrier;
1028 + barrier = XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1029 + barrier_x, 0,
1030 + barrier_x, 300,
1031 + 0, 0, NULL);
1032 +
1033 + int x = 0, y = 200;
1034 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1035 + x, y, 0);
1036 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1037 +
1038 + // Check that the barrier exists before we destroy it.
1039 + int dx = 200, dy = 0;
1040 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1041 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x - 1, y + dy));
1042 +
1043 + // Destroy the barrier...
1044 + XFixesDestroyPointerBarrier (Display (), barrier);
1045 +
1046 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1047 + x, y, 0);
1048 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1049 +
1050 + // There should be no barrier to block this.
1051 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1052 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1053 +}
1054 +
1055 +TEST_F (BarrierTest, BarrierIgnoresNonsensicalDirections)
1056 +{
1057 + int barrier_x = 100;
1058 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1059 + barrier_x, 0,
1060 + barrier_x, 300,
1061 + BarrierPositiveY | BarrierNegativeY,
1062 + 0, NULL);
1063 +
1064 + int x = 200, y = 100;
1065 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1066 + x, y, 0);
1067 +
1068 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1069 +
1070 + int dx = -200, dy = 0;
1071 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1072 +
1073 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x, y + dy));
1074 +
1075 + int barrier_y = 100;
1076 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1077 + 0, barrier_y,
1078 + 400, barrier_y,
1079 + BarrierPositiveX | BarrierNegativeX,
1080 + 0, NULL);
1081 +
1082 + x = 100, y = 200;
1083 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1084 + x, y, 0);
1085 +
1086 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1087 +
1088 + dx = 0, dy = -200;
1089 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1090 +
1091 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y));
1092 +}
1093 +
1094 +TEST_F (BarrierTest, VerticalBarrierEdges)
1095 +{
1096 + int barrier_x = 300, barrier_y1 = 300 , barrier_y2 = 500;
1097 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1098 + barrier_x, barrier_y1,
1099 + barrier_x, barrier_y2,
1100 + 0, 0, NULL);
1101 +
1102 + int x = barrier_x + 100, y = barrier_y1 - 1;
1103 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1104 + x, y, 0);
1105 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1106 +
1107 + // Motion should take us past the top of the barrier...
1108 + int dx = -200, dy = 0;
1109 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1110 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1111 +
1112 + x = barrier_x + 100, y = barrier_y1;
1113 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1114 + x, y, 0);
1115 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1116 +
1117 + // Motion should hit the top of the barrier...
1118 + dx = -200, dy = 0;
1119 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1120 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x, y + dy));
1121 +
1122 + x = barrier_x + 100, y = barrier_y2;
1123 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1124 + x, y, 0);
1125 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1126 +
1127 + // Motion should hit the bottom of the barrier...
1128 + dx = -200, dy = 0;
1129 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1130 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x, y + dy));
1131 +
1132 + x = barrier_x + 100, y = barrier_y2 + 1;
1133 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1134 + x, y, 0);
1135 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1136 +
1137 + // Motion should take us past the bottom of the barrier...
1138 + dx = -200, dy = 0;
1139 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1140 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1141 +}
1142 +
1143 +TEST_F (BarrierTest, HorizontalBarrierEdges)
1144 +{
1145 + int barrier_x1 = 200, barrier_x2 = 500, barrier_y = 300;
1146 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1147 + barrier_x1, barrier_y,
1148 + barrier_x2, barrier_y,
1149 + 0, 0, NULL);
1150 +
1151 + int x = barrier_x1 - 1, y = barrier_y - 100;
1152 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1153 + x, y, 0);
1154 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1155 +
1156 + // Motion should take us past the left edge of the barrier...
1157 + int dx = 0, dy = 200;
1158 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1159 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1160 +
1161 + x = barrier_x1, y = barrier_y - 100;
1162 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1163 + x, y, 0);
1164 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1165 +
1166 + // Motion should hit the top of the barrier...
1167 + dx = 0, dy = 200;
1168 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1169 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, barrier_y - 1));
1170 +
1171 + x = barrier_x2, y = barrier_y - 100;
1172 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1173 + x, y, 0);
1174 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1175 +
1176 + // Motion should hit the bottom of the barrier...
1177 + dx = 0, dy = 200;
1178 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1179 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y - 1));
1180 +
1181 + x = barrier_x2 + 1, y = barrier_y - 100;
1182 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1183 + x, y, 0);
1184 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1185 +
1186 + // Motion should take us past the bottom of the barrier...
1187 + dx = 0, dy = 200;
1188 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1189 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1190 +}
1191 +
1192 +TEST_F (BarrierTest, CornerBlocksMotion)
1193 +{
1194 + int corner_x, corner_y;
1195 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1196 + corner_x, corner_y,
1197 + corner_x, corner_y + 300,
1198 + 0, 0, NULL);
1199 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1200 + corner_x, corner_y,
1201 + corner_x + 300, corner_y,
1202 + 0, 0, NULL);
1203 +
1204 + int x = corner_x + 100, y = corner_y + 100;
1205 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1206 + x, y, 0);
1207 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1208 +
1209 + XTestFakeRelativeMotionEvent (Display (), -200, -200, 0);
1210 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (corner_x, corner_y));
1211 +}
1212 +
1213 +TEST_F (BarrierTest, VerticalBarrierWithAdjacentStart)
1214 +{
1215 + int barrier_x = 350;
1216 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1217 + barrier_x, 100,
1218 + barrier_x, 300,
1219 + 0, 0, NULL);
1220 +
1221 + int x = barrier_x, y = 200;
1222 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1223 + x, y, 0);
1224 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1225 +
1226 + int dx = -10, dy = 0;
1227 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1228 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x, y + dy));
1229 +
1230 + x = barrier_x, y = 200;
1231 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1232 + x, y, 0);
1233 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1234 +
1235 + dx = 10, dy = 0;
1236 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1237 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1238 +
1239 + x = barrier_x - 1, y = 200;
1240 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1241 + x, y, 0);
1242 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1243 +
1244 + dx = 10, dy = 0;
1245 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1246 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (barrier_x - 1, y + dy));
1247 +
1248 + x = barrier_x - 1, y = 200;
1249 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1250 + x, y, 0);
1251 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1252 +
1253 + dx = -10, dy = 0;
1254 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1255 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1256 +}
1257 +
1258 +TEST_F (BarrierTest, HorizontalBarrierWithAdjacentStart)
1259 +{
1260 + int barrier_y = 300;
1261 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1262 + 100, barrier_y,
1263 + 400, barrier_y,
1264 + 0, 0, NULL);
1265 +
1266 + int x = 240, y = barrier_y;
1267 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1268 + x, y, 0);
1269 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1270 +
1271 + int dx = 0, dy = -10;
1272 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1273 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y));
1274 +
1275 + x = 240, y = barrier_y;
1276 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1277 + x, y, 0);
1278 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1279 +
1280 + dx = 0, dy = 10;
1281 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1282 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1283 +
1284 + x = 240, y = barrier_y - 1;
1285 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1286 + x, y, 0);
1287 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1288 +
1289 + dx = 0, dy = 10;
1290 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1291 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, barrier_y - 1));
1292 +
1293 + x = 240, y = barrier_y - 1;
1294 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1295 + x, y, 0);
1296 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1297 +
1298 + dx = 0, dy = -10;
1299 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1300 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x + dx, y + dy));
1301 +}
1302 +
1303 +TEST_F (BarrierTest, BarrierNotifyEventFires)
1304 +{
1305 + int barrier_y = 300;
1306 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1307 + 100, barrier_y,
1308 + 400, barrier_y,
1309 + 0, 0, NULL);
1310 +
1311 + XFixesSelectBarrierInput (Display (), DefaultRootWindow (Display ()),
1312 + XFixesBarrierHitNotifyMask);
1313 +
1314 + int x = 240, y = barrier_y + 50;
1315 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1316 + x, y, 0);
1317 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1318 +
1319 + XTestFakeRelativeMotionEvent (Display (), 0, -100, 0);
1320 +
1321 + XFlush (Display ());
1322 + ASSERT_TRUE (WaitForXEvent ())<<"Timed out waiting to receive X event";
1323 + while (XPending (Display ())) {
1324 + XEvent e;
1325 + XNextEvent (Display (), &e);
1326 + switch (e.xany.type - fixes_eventbase) {
1327 + case XFixesBarrierNotify:
1328 + return;
1329 + }
1330 + }
1331 + FAIL () << "Failed to recieve BarrierNotify event";
1332 +}
1333 +
1334 +TEST_F (BarrierTest, RecieveOneNotifyEventPerHit)
1335 +{
1336 + int barrier_x = 100;
1337 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1338 + barrier_x, 0,
1339 + barrier_x, 300,
1340 + 0, 0, NULL);
1341 +
1342 + XFixesSelectBarrierInput (Display (), DefaultRootWindow (Display ()),
1343 + XFixesBarrierHitNotifyMask);
1344 +
1345 + int x = 200, y = 100, dx = -200, dy = 0;
1346 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1347 + x, y, 0);
1348 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1349 +
1350 + /* Generate 5 barrier events */
1351 + for (int i = 0; i < 5; ++i) {
1352 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1353 + }
1354 +
1355 + int barrierEventCount = 0;
1356 + XFlush (Display ());
1357 + ASSERT_TRUE (WaitForXEvent ())<<"Timed out waiting to receive X event";
1358 + while (XPending (Display ())) {
1359 + XEvent e;
1360 + XNextEvent (Display (), &e);
1361 + switch (e.xany.type - fixes_eventbase) {
1362 + case XFixesBarrierNotify:
1363 + barrierEventCount++;
1364 + break;
1365 + }
1366 + }
1367 + ASSERT_EQ (5, barrierEventCount);
1368 +}
1369 +
1370 +TEST_F (BarrierTest, BarrierEventHasNonZeroVelocity)
1371 +{
1372 + int barrier_x = 100;
1373 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1374 + barrier_x, 0,
1375 + barrier_x, 300,
1376 + 0, 0, NULL);
1377 +
1378 + XFixesSelectBarrierInput (Display (), DefaultRootWindow (Display ()),
1379 + XFixesBarrierHitNotifyMask);
1380 +
1381 + int x = 200, y = 100, dx = -200, dy = 0;
1382 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1383 + x, y, 0);
1384 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1385 +
1386 + /* One relative event to ensure the server has a non-zero
1387 + * last-event-time */
1388 + XTestFakeRelativeMotionEvent (Display (), 10, 10, 0);
1389 + /* Run the pointer into the barrier */
1390 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1391 +
1392 + XFlush (Display ());
1393 + ASSERT_TRUE (WaitForXEvent ())<<"Timed out waiting to receive X event";
1394 + while (XPending (Display ())) {
1395 + XEvent e;
1396 + XNextEvent (Display (), &e);
1397 + switch (e.xany.type - fixes_eventbase) {
1398 + case XFixesBarrierNotify:
1399 + XFixesBarrierNotifyEvent *notify = (XFixesBarrierNotifyEvent *)&e;
1400 + ASSERT_LT (0, notify->velocity);
1401 + return;
1402 + }
1403 + }
1404 + FAIL () << "Failed to receive barrier event";
1405 +}
1406 +
1407 +TEST_F (BarrierTest, ScreenEdgeVerticalBarrierEventHasNonZeroVelocity)
1408 +{
1409 + int barrier_x = 0;
1410 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1411 + barrier_x, 0,
1412 + barrier_x, 300,
1413 + 0, 0, NULL);
1414 +
1415 + XFixesSelectBarrierInput (Display (), DefaultRootWindow (Display ()),
1416 + XFixesBarrierHitNotifyMask);
1417 +
1418 + int x = 100, y = 100, dx = -200, dy = 0;
1419 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1420 + x, y, 0);
1421 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1422 +
1423 + /* One relative event to ensure the server has a non-zero
1424 + * last-event-time */
1425 + XTestFakeRelativeMotionEvent (Display (), 10, 10, 0);
1426 + /* Run the pointer into the barrier */
1427 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1428 +
1429 + XFlush (Display ());
1430 + ASSERT_TRUE (WaitForXEvent ())<<"Timed out waiting to receive X event";
1431 + while (XPending (Display ())) {
1432 + XEvent e;
1433 + XNextEvent (Display (), &e);
1434 + switch (e.xany.type - fixes_eventbase) {
1435 + case XFixesBarrierNotify:
1436 + XFixesBarrierNotifyEvent *notify = (XFixesBarrierNotifyEvent *)&e;
1437 + ASSERT_LT (0, notify->velocity);
1438 + return;
1439 + }
1440 + }
1441 + FAIL () << "Failed to receive barrier event";
1442 +}
1443 +
1444 +TEST_F (BarrierTest, ScreenEdgeHorizontalBarrierEventHasNonZeroVelocity)
1445 +{
1446 + int barrier_y = 0;
1447 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1448 + 0, barrier_y,
1449 + 300, barrier_y,
1450 + 0, 0, NULL);
1451 +
1452 + XFixesSelectBarrierInput (Display (), DefaultRootWindow (Display ()),
1453 + XFixesBarrierHitNotifyMask);
1454 +
1455 + int x = 100, y = 100, dx = 0, dy = -200;
1456 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1457 + x, y, 0);
1458 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1459 +
1460 + /* One relative event to ensure the server has a non-zero
1461 + * last-event-time */
1462 + XTestFakeRelativeMotionEvent (Display (), 10, 10, 0);
1463 + /* Run the pointer into the barrier */
1464 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1465 +
1466 + XFlush (Display ());
1467 + ASSERT_TRUE (WaitForXEvent ())<<"Timed out waiting to receive X event";
1468 + while (XPending (Display ())) {
1469 + XEvent e;
1470 + XNextEvent (Display (), &e);
1471 + switch (e.xany.type - fixes_eventbase) {
1472 + case XFixesBarrierNotify:
1473 + XFixesBarrierNotifyEvent *notify = (XFixesBarrierNotifyEvent *)&e;
1474 + ASSERT_LT (0, notify->velocity);
1475 + return;
1476 + }
1477 + }
1478 + FAIL () << "Failed to receive barrier event";
1479 +}
1480 +
1481 +TEST_F (BarrierTest, ReceiveOneBarrierEventPerHitOnScreenEdge)
1482 +{
1483 + int barrier_x = 0;
1484 + XFixesCreatePointerBarrier (Display (), DefaultRootWindow (Display ()),
1485 + barrier_x, 0,
1486 + barrier_x, 300,
1487 + 0, 0, NULL);
1488 +
1489 + XFixesSelectBarrierInput (Display (), DefaultRootWindow (Display ()),
1490 + XFixesBarrierHitNotifyMask);
1491 +
1492 + int x = 20, y = 100, dx = -40, dy = 0;
1493 + XTestFakeMotionEvent (Display (), DefaultScreen (Display ()),
1494 + x, y, 0);
1495 + ASSERT_NO_FATAL_FAILURE (AssertPointerPosition (x, y));
1496 +
1497 + /* Generate 5 barrier events */
1498 + for (int i = 0; i < 5; ++i) {
1499 + XTestFakeRelativeMotionEvent (Display (), dx, dy, 0);
1500 + }
1501 +
1502 + int barrierEventCount = 0;
1503 + XFlush (Display ());
1504 + ASSERT_TRUE (WaitForXEvent ())<<"Timed out waiting to receive X event";
1505 + while (XPending (Display ())) {
1506 + XEvent e;
1507 + XNextEvent (Display (), &e);
1508 + switch (e.xany.type - fixes_eventbase) {
1509 + case XFixesBarrierNotify:
1510 + barrierEventCount++;
1511 + break;
1512 + }
1513 + }
1514 + ASSERT_EQ (5, barrierEventCount);
1515 +}
1516 Index: xorg-server/configure.ac
1517 ===================================================================
1518 --- xorg-server.orig/configure.ac 2012-03-08 07:40:35.416111392 +1100
1519 +++ xorg-server/configure.ac 2012-03-08 11:02:31.783464472 +1100
1520 @@ -2155,6 +2155,25 @@
1522 AC_CONFIG_COMMANDS([sdksyms], [touch hw/xfree86/sdksyms.dep])
1524 +AC_PROG_CXX
1525 +
1526 +PKG_CHECK_MODULES(XORG_GTEST, xorg-gtest,
1527 + [have_xorg_gtest="yes"],
1528 + [AC_MSG_WARN([xorg-gtest not installed, tests will not be built])])
1529 +AM_CONDITIONAL([HAVE_XORG_GTEST], [test "x$have_xorg_gtest" = xyes])
1530 +AC_SUBST([XORG_GTEST_CFLAGS])
1531 +AC_SUBST([XORG_GTEST_LIBS])
1532 +
1533 +PKG_CHECK_MODULES([XFIXES], xfixes, [have_xfixes="yes"], [have_xfixes="no"])
1534 +AM_CONDITIONAL([HAVE_XFIXES], [test "x$have_xfixes" = xyes])
1535 +AC_SUBST([XFIXES_CFLAGS])
1536 +AC_SUBST([XFIXES_LIBS])
1537 +
1538 +PKG_CHECK_MODULES([XTEST], xtst, [have_xtest="yes"], [have_xtest="no"])
1539 +AM_CONDITIONAL([HAVE_XTEST], [test "x$have_xtest" = xyes])
1540 +AC_SUBST([XTEST_CFLAGS])
1541 +AC_SUBST([XTEST_LIBS])
1542 +
1543 AC_OUTPUT([
1544 Makefile
1545 glx/Makefile
1546 @@ -2254,6 +2273,7 @@
1547 hw/kdrive/src/Makefile
1548 test/Makefile
1549 test/xi2/Makefile
1550 +test/gtest/Makefile
1551 xserver.ent
1552 xorg-server.pc
1553 ])
1554 Index: xorg-server/test/gtest/Makefile.am
1555 ===================================================================
1556 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1557 +++ xorg-server/test/gtest/Makefile.am 2012-03-08 07:40:35.488111388 +1100
1558 @@ -0,0 +1,27 @@
1559 +check_PROGRAMS = xfixes_barriers
1560 +check_DATA = dummy.conf
1561 +
1562 +TESTS=xfixes_barriers
1563 +
1564 +GTEST_SRC_DIR = /usr/src/gtest
1565 +GTEST_SOURCES = $(GTEST_SRC_DIR)/src/gtest-all.cc
1566 +
1567 +xfixes_barriers_CXXFLAGS = $(AM_CXXFLAGS) \
1568 + -I$(GTEST_SRC_DIR) \
1569 + $(XORG_GTEST_CFLAGS) \
1570 + $(XTEST_CFLAGS) \
1571 + $(XFIXES_CFLAGS) \
1572 + -DXORG_BINARY=\"$(top_builddir)/hw/xfree86/Xorg\" \
1573 + -DXORG_DUMMY_CONF=\"$(abs_srcdir)/dummy.conf\"
1574 +
1575 +xfixes_barriers_LDADD = \
1576 + $(XFIXES_LIBS) \
1577 + $(XTEST_LIBS) \
1578 + $(XORG_GTEST_LIBS) \
1579 + -lpthread
1580 +
1581 +xfixes_barriers_SOURCES = \
1582 + xfixes_barriers.cpp
1583 +
1584 +nodist_xfixes_barriers_SOURCES = \
1585 + $(GTEST_SOURCES)
1586 Index: xorg-server/test/Makefile.am
1587 ===================================================================
1588 --- xorg-server.orig/test/Makefile.am 2012-03-07 22:24:45.684697122 +1100
1589 +++ xorg-server/test/Makefile.am 2012-03-08 07:40:35.488111388 +1100
1590 @@ -1,5 +1,10 @@
1591 if ENABLE_UNIT_TESTS
1592 SUBDIRS= . xi2
1593 +
1594 +if HAVE_XORG_GTEST
1595 +SUBDIRS+= gtest
1596 +endif
1597 +
1598 noinst_PROGRAMS = xkb input xtest list misc fixes xfree86 touch
1599 check_LTLIBRARIES = libxservertest.la
1601 Index: xorg-server/test/gtest/dummy.conf
1602 ===================================================================
1603 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1604 +++ xorg-server/test/gtest/dummy.conf 2012-03-08 07:40:35.488111388 +1100
1605 @@ -0,0 +1,4 @@
1606 +Section "Device"
1607 + Identifier "Dummy video device"
1608 + Driver "dummy"
1609 +EndSection
1610 Index: xorg-server/dix/dixutils.c
1611 ===================================================================
1612 --- xorg-server.orig/dix/dixutils.c 2012-03-08 07:40:35.392111393 +1100
1613 +++ xorg-server/dix/dixutils.c 2012-03-08 07:40:35.488111388 +1100
1614 @@ -537,7 +537,7 @@
1615 {
1616 /* remove q from the list */
1617 *p = q->next; /* don't fetch until after func called */
1618 - free(q);
1619 + (*q->destroyProc) (q);
1620 }
1621 else
1622 {
1623 @@ -560,7 +560,7 @@
1624 (void) (*q->function) (q->client, q->closure);
1625 /* remove q from the list */
1626 *p = q->next; /* don't fetch until after func called */
1627 - free(q);
1628 + (*q->destroyProc) (q);
1629 }
1630 else
1631 {
1632 @@ -570,6 +570,12 @@
1633 workQueueLast = p;
1634 }
1636 +static void
1637 +FreeWorkQueueItem (WorkQueuePtr this)
1638 +{
1639 + free(this);
1640 +}
1641 +
1642 Bool
1643 QueueWorkProc (
1644 Bool (*function)(ClientPtr /* pClient */, pointer /* closure */),
1645 @@ -583,12 +589,22 @@
1646 q->function = function;
1647 q->client = client;
1648 q->closure = closure;
1649 + q->destroyProc = FreeWorkQueueItem;
1650 q->next = NULL;
1651 *workQueueLast = q;
1652 workQueueLast = &q->next;
1653 return TRUE;
1654 }
1656 +Bool
1657 +QueueWorkItem (WorkQueuePtr item)
1658 +{
1659 + item->next = NULL;
1660 + *workQueueLast = item;
1661 + workQueueLast = &item->next;
1662 + return TRUE;
1663 +}
1664 +
1665 /*
1666 * Manage a queue of sleeping clients, awakening them
1667 * when requested, by using the OS functions IgnoreClient
1668 Index: xorg-server/include/dixstruct.h
1669 ===================================================================
1670 --- xorg-server.orig/include/dixstruct.h 2012-03-07 22:24:45.552697115 +1100
1671 +++ xorg-server/include/dixstruct.h 2012-03-08 07:40:35.492111388 +1100
1672 @@ -153,6 +153,9 @@
1673 );
1674 ClientPtr client;
1675 pointer closure;
1676 + void (*destroyProc) (
1677 + struct _WorkQueue * /* this */
1678 +);
1679 } WorkQueueRec;
1681 extern _X_EXPORT TimeStamp currentTime;
1682 Index: xorg-server/include/dix.h
1683 ===================================================================
1684 --- xorg-server.orig/include/dix.h 2012-03-07 22:24:45.568697116 +1100
1685 +++ xorg-server/include/dix.h 2012-03-08 07:40:35.492111388 +1100
1686 @@ -266,6 +266,8 @@
1687 pointer /*closure*/
1688 );
1690 +extern _X_EXPORT Bool QueueWorkItem(WorkQueuePtr item);
1691 +
1692 typedef Bool (* ClientSleepProcPtr)(
1693 ClientPtr /*client*/,
1694 pointer /*closure*/);