1 /* 2 * Copyright 2011 Collabra Ltd. 3 * Copyright 2011 Red Hat, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Author: Daniel Stone <daniel (at) fooishbar.org> 25 */ 26 27 #ifdef HAVE_DIX_CONFIG_H 28 #include <dix-config.h> 29 #endif 30 31 #include "inputstr.h" 32 #include "scrnintstr.h" 33 #include "dixgrabs.h" 34 35 #include "eventstr.h" 36 #include "exevents.h" 37 #include "exglobals.h" 38 #include "inpututils.h" 39 #include "eventconvert.h" 40 #include "windowstr.h" 41 #include "mi.h" 42 43 #define TOUCH_HISTORY_SIZE 100 44 45 Bool touchEmulatePointer = TRUE; 46 47 /** 48 * Some documentation about touch points: 49 * The driver submits touch events with its own (unique) touch point ID. 50 * The driver may re-use those IDs, the DDX doesn't care. It just passes on 51 * the data to the DIX. In the server, the driver's ID is referred to as the 52 * DDX id anyway. 53 * 54 * On a TouchBegin, we create a DDXTouchPointInfo that contains the DDX id 55 * and the client ID that this touchpoint will have. The client ID is the 56 * one visible on the protocol. 57 * 58 * TouchUpdate and TouchEnd will only be processed if there is an active 59 * touchpoint with the same DDX id. 60 * 61 * The DDXTouchPointInfo struct is stored dev->last.touches. When the event 62 * being processed, it becomes a TouchPointInfo in dev->touch-touches which 63 * contains amongst other things the sprite trace and delivery information. 64 */ 65 66 /** 67 * Check which devices need a bigger touch event queue and grow their 68 * last.touches by half its current size. 69 * 70 * @param client Always the serverClient 71 * @param closure Always NULL 72 * 73 * @return Always True. If we fail to grow we probably will topple over soon 74 * anyway and re-executing this won't help. 75 */ 76 77 static Bool 78 TouchResizeQueue(DeviceIntPtr dev) 79 { 80 DDXTouchPointInfoPtr tmp; 81 size_t size; 82 83 /* Grow sufficiently so we don't need to do it often */ 84 size = dev->last.num_touches + dev->last.num_touches / 2 + 1; 85 86 tmp = reallocarray(dev->last.touches, size, sizeof(*dev->last.touches)); 87 if (tmp) { 88 int j; 89 90 dev->last.touches = tmp; 91 for (j = dev->last.num_touches; j < size; j++) 92 TouchInitDDXTouchPoint(dev, &dev->last.touches[j]); 93 dev->last.num_touches = size; 94 return TRUE; 95 } 96 return FALSE; 97 } 98 99 /** 100 * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the 101 * associated DDXTouchPointInfoRec. 102 * 103 * @param dev The device to create the touch point for 104 * @param ddx_id Touch id assigned by the driver/ddx 105 * @param create Create the touchpoint if it cannot be found 106 */ 107 DDXTouchPointInfoPtr 108 TouchFindByDDXID(DeviceIntPtr dev, uint32_t ddx_id, Bool create) 109 { 110 DDXTouchPointInfoPtr ti; 111 int i; 112 113 if (!dev->touch) 114 return NULL; 115 116 for (i = 0; i < dev->last.num_touches; i++) { 117 ti = &dev->last.touches[i]; 118 if (ti->active && ti->ddx_id == ddx_id) 119 return ti; 120 } 121 122 return create ? TouchBeginDDXTouch(dev, ddx_id) : NULL; 123 } 124 125 /** 126 * Given a unique DDX ID for a touchpoint, create a touchpoint record and 127 * return it. 128 * 129 * If no other touch points are active, mark new touchpoint for pointer 130 * emulation. 131 * 132 * Returns NULL on failure (i.e. if another touch with that ID is already active, 133 * allocation failure). 134 */ 135 DDXTouchPointInfoPtr 136 TouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id) 137 { 138 static int next_client_id = 1; 139 int i; 140 TouchClassPtr t = dev->touch; 141 DDXTouchPointInfoPtr ti = NULL; 142 Bool emulate_pointer; 143 144 if (!t) 145 return NULL; 146 147 emulate_pointer = touchEmulatePointer && (t->mode == XIDirectTouch); 148 149 /* Look for another active touchpoint with the same DDX ID. DDX 150 * touchpoints must be unique. */ 151 if (TouchFindByDDXID(dev, ddx_id, FALSE)) 152 return NULL; 153 154 for (;;) { 155 for (i = 0; i < dev->last.num_touches; i++) { 156 /* Only emulate pointer events on the first touch */ 157 if (dev->last.touches[i].active) 158 emulate_pointer = FALSE; 159 else if (!ti) /* ti is now first non-active touch rec */ 160 ti = &dev->last.touches[i]; 161 162 if (!emulate_pointer && ti) 163 break; 164 } 165 if (ti) 166 break; 167 if (!TouchResizeQueue(dev)) 168 break; 169 } 170 171 if (ti) { 172 int client_id; 173 174 ti->active = TRUE; 175 ti->ddx_id = ddx_id; 176 client_id = next_client_id; 177 next_client_id++; 178 if (next_client_id == 0) 179 next_client_id = 1; 180 ti->client_id = client_id; 181 ti->emulate_pointer = emulate_pointer; 182 } 183 return ti; 184 } 185 186 void 187 TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti) 188 { 189 TouchClassPtr t = dev->touch; 190 191 if (!t) 192 return; 193 194 ti->active = FALSE; 195 } 196 197 void 198 TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch) 199 { 200 memset(ddxtouch, 0, sizeof(*ddxtouch)); 201 ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes); 202 } 203 204 Bool 205 TouchInitTouchPoint(TouchClassPtr t, ValuatorClassPtr v, int index) 206 { 207 TouchPointInfoPtr ti; 208 209 if (index >= t->num_touches) 210 return FALSE; 211 ti = &t->touches[index]; 212 213 memset(ti, 0, sizeof(*ti)); 214 215 ti->valuators = valuator_mask_new(v->numAxes); 216 if (!ti->valuators) 217 return FALSE; 218 219 ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace)); 220 if (!ti->sprite.spriteTrace) { 221 valuator_mask_free(&ti->valuators); 222 return FALSE; 223 } 224 ti->sprite.spriteTraceSize = 32; 225 ti->sprite.spriteTrace[0] = screenInfo.screens[0]->root; 226 ti->sprite.hot.pScreen = screenInfo.screens[0]; 227 ti->sprite.hotPhys.pScreen = screenInfo.screens[0]; 228 229 ti->client_id = -1; 230 231 return TRUE; 232 } 233 234 void 235 TouchFreeTouchPoint(DeviceIntPtr device, int index) 236 { 237 TouchPointInfoPtr ti; 238 int i; 239 240 if (!device->touch || index >= device->touch->num_touches) 241 return; 242 ti = &device->touch->touches[index]; 243 244 if (ti->active) 245 TouchEndTouch(device, ti); 246 247 for (i = 0; i < ti->num_listeners; i++) 248 TouchRemoveListener(ti, ti->listeners[0].listener); 249 250 valuator_mask_free(&ti->valuators); 251 free(ti->sprite.spriteTrace); 252 ti->sprite.spriteTrace = NULL; 253 free(ti->listeners); 254 ti->listeners = NULL; 255 free(ti->history); 256 ti->history = NULL; 257 ti->history_size = 0; 258 ti->history_elements = 0; 259 } 260 261 /** 262 * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the 263 * associated TouchPointInfoRec. 264 */ 265 TouchPointInfoPtr 266 TouchFindByClientID(DeviceIntPtr dev, uint32_t client_id) 267 { 268 TouchClassPtr t = dev->touch; 269 TouchPointInfoPtr ti; 270 int i; 271 272 if (!t) 273 return NULL; 274 275 for (i = 0; i < t->num_touches; i++) { 276 ti = &t->touches[i]; 277 if (ti->active && ti->client_id == client_id) 278 return ti; 279 } 280 281 return NULL; 282 } 283 284 /** 285 * Given a unique ID for a touchpoint, create a touchpoint record in the 286 * server. 287 * 288 * Returns NULL on failure (i.e. if another touch with that ID is already active, 289 * allocation failure). 290 */ 291 TouchPointInfoPtr 292 TouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid, 293 Bool emulate_pointer) 294 { 295 int i; 296 TouchClassPtr t = dev->touch; 297 TouchPointInfoPtr ti; 298 void *tmp; 299 300 if (!t) 301 return NULL; 302 303 /* Look for another active touchpoint with the same client ID. It's 304 * technically legitimate for a touchpoint to still exist with the same 305 * ID but only once the 32 bits wrap over and you've used up 4 billion 306 * touch ids without lifting that one finger off once. In which case 307 * you deserve a medal or something, but not error handling code. */ 308 if (TouchFindByClientID(dev, touchid)) 309 return NULL; 310 311 try_find_touch: 312 for (i = 0; i < t->num_touches; i++) { 313 ti = &t->touches[i]; 314 if (!ti->active) { 315 ti->active = TRUE; 316 ti->client_id = touchid; 317 ti->sourceid = sourceid; 318 ti->emulate_pointer = emulate_pointer; 319 return ti; 320 } 321 } 322 323 /* If we get here, then we've run out of touches: enlarge dev->touch and 324 * try again. */ 325 tmp = reallocarray(t->touches, t->num_touches + 1, sizeof(*ti)); 326 if (tmp) { 327 t->touches = tmp; 328 t->num_touches++; 329 if (TouchInitTouchPoint(t, dev->valuator, t->num_touches - 1)) 330 goto try_find_touch; 331 } 332 333 return NULL; 334 } 335 336 /** 337 * Releases a touchpoint for use: this must only be called after all events 338 * related to that touchpoint have been sent and finalised. Called from 339 * ProcessTouchEvent and friends. Not by you. 340 */ 341 void 342 TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti) 343 { 344 int i; 345 346 if (ti->emulate_pointer) { 347 GrabPtr grab; 348 349 if ((grab = dev->deviceGrab.grab)) { 350 if (dev->deviceGrab.fromPassiveGrab && 351 !dev->button->buttonsDown && 352 !dev->touch->buttonsDown && GrabIsPointerGrab(grab)) 353 (*dev->deviceGrab.DeactivateGrab) (dev); 354 } 355 } 356 357 for (i = 0; i < ti->num_listeners; i++) 358 TouchRemoveListener(ti, ti->listeners[0].listener); 359 360 ti->active = FALSE; 361 ti->pending_finish = FALSE; 362 ti->sprite.spriteTraceGood = 0; 363 free(ti->listeners); 364 ti->listeners = NULL; 365 ti->num_listeners = 0; 366 ti->num_grabs = 0; 367 ti->client_id = 0; 368 369 TouchEventHistoryFree(ti); 370 371 valuator_mask_zero(ti->valuators); 372 } 373 374 /** 375 * Allocate the event history for this touch pointer. Calling this on a 376 * touchpoint that already has an event history does nothing but counts as 377 * as success. 378 * 379 * @return TRUE on success, FALSE on allocation errors 380 */ 381 Bool 382 TouchEventHistoryAllocate(TouchPointInfoPtr ti) 383 { 384 if (ti->history) 385 return TRUE; 386 387 ti->history = calloc(TOUCH_HISTORY_SIZE, sizeof(*ti->history)); 388 ti->history_elements = 0; 389 if (ti->history) 390 ti->history_size = TOUCH_HISTORY_SIZE; 391 return ti->history != NULL; 392 } 393 394 void 395 TouchEventHistoryFree(TouchPointInfoPtr ti) 396 { 397 free(ti->history); 398 ti->history = NULL; 399 ti->history_size = 0; 400 ti->history_elements = 0; 401 } 402 403 /** 404 * Store the given event on the event history (if one exists) 405 * A touch event history consists of one TouchBegin and several TouchUpdate 406 * events (if applicable) but no TouchEnd event. 407 * If more than one TouchBegin is pushed onto the stack, the push is 408 * ignored, calling this function multiple times for the TouchBegin is 409 * valid. 410 */ 411 void 412 TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev) 413 { 414 if (!ti->history) 415 return; 416 417 switch (ev->type) { 418 case ET_TouchBegin: 419 /* don't store the same touchbegin twice */ 420 if (ti->history_elements > 0) 421 return; 422 break; 423 case ET_TouchUpdate: 424 break; 425 case ET_TouchEnd: 426 return; /* no TouchEnd events in the history */ 427 default: 428 return; 429 } 430 431 /* We only store real events in the history */ 432 if (ev->flags & (TOUCH_CLIENT_ID | TOUCH_REPLAYING)) 433 return; 434 435 ti->history[ti->history_elements++] = *ev; 436 /* FIXME: proper overflow fixes */ 437 if (ti->history_elements > ti->history_size - 1) { 438 ti->history_elements = ti->history_size - 1; 439 DebugF("source device %d: history size %zu overflowing for touch %u\n", 440 ti->sourceid, ti->history_size, ti->client_id); 441 } 442 } 443 444 void 445 TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource) 446 { 447 int i; 448 449 if (!ti->history) 450 return; 451 452 DeliverDeviceClassesChangedEvent(ti->sourceid, ti->history[0].time); 453 454 for (i = 0; i < ti->history_elements; i++) { 455 DeviceEvent *ev = &ti->history[i]; 456 457 ev->flags |= TOUCH_REPLAYING; 458 ev->resource = resource; 459 /* FIXME: 460 We're replaying ti->history which contains the TouchBegin + 461 all TouchUpdates for ti. This needs to be passed on to the next 462 listener. If that is a touch listener, everything is dandy. 463 If the TouchBegin however triggers a sync passive grab, the 464 TouchUpdate events must be sent to EnqueueEvent so the events end 465 up in syncEvents.pending to be forwarded correctly in a 466 subsequent ComputeFreeze(). 467 468 However, if we just send them to EnqueueEvent the sync'ing device 469 prevents handling of touch events for ownership listeners who 470 want the events right here, right now. 471 */ 472 dev->public.processInputProc((InternalEvent*)ev, dev); 473 } 474 } 475 476 Bool 477 TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite) 478 { 479 int i; 480 TouchClassPtr t = dev->touch; 481 SpritePtr srcsprite; 482 483 /* All touches should have the same sprite trace, so find and reuse an 484 * existing touch's sprite if possible, else use the device's sprite. */ 485 for (i = 0; i < t->num_touches; i++) 486 if (!t->touches[i].pending_finish && 487 t->touches[i].sprite.spriteTraceGood > 0) 488 break; 489 if (i < t->num_touches) 490 srcsprite = &t->touches[i].sprite; 491 else if (dev->spriteInfo->sprite) 492 srcsprite = dev->spriteInfo->sprite; 493 else 494 return FALSE; 495 496 return CopySprite(srcsprite, sprite); 497 } 498 499 /** 500 * Ensure a window trace is present in ti->sprite, constructing one for 501 * TouchBegin events. 502 */ 503 Bool 504 TouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, 505 InternalEvent *ev) 506 { 507 TouchClassPtr t = sourcedev->touch; 508 SpritePtr sprite = &ti->sprite; 509 510 if (t->mode == XIDirectTouch) { 511 /* Focus immediately under the touchpoint in direct touch mode. 512 * XXX: Do we need to handle crossing screens here? */ 513 sprite->spriteTrace[0] = 514 sourcedev->spriteInfo->sprite->hotPhys.pScreen->root; 515 XYToWindow(sprite, ev->device_event.root_x, ev->device_event.root_y); 516 } 517 else if (!TouchBuildDependentSpriteTrace(sourcedev, sprite)) 518 return FALSE; 519 520 if (sprite->spriteTraceGood <= 0) 521 return FALSE; 522 523 /* Mark which grabs/event selections we're delivering to: max one grab per 524 * window plus the bottom-most event selection, plus any active grab. */ 525 ti->listeners = calloc(sprite->spriteTraceGood + 2, sizeof(*ti->listeners)); 526 if (!ti->listeners) { 527 sprite->spriteTraceGood = 0; 528 return FALSE; 529 } 530 ti->num_listeners = 0; 531 532 return TRUE; 533 } 534 535 /** 536 * Copy the touch event into the pointer_event, switching the required 537 * fields to make it a correct pointer event. 538 * 539 * @param event The original touch event 540 * @param[in] motion_event The respective motion event 541 * @param[in] button_event The respective button event (if any) 542 * 543 * @returns The number of converted events. 544 * @retval 0 An error occurred 545 * @retval 1 only the motion event is valid 546 * @retval 2 motion and button event are valid 547 */ 548 int 549 TouchConvertToPointerEvent(const InternalEvent *event, 550 InternalEvent *motion_event, 551 InternalEvent *button_event) 552 { 553 int ptrtype; 554 int nevents = 0; 555 556 BUG_RETURN_VAL(!event, 0); 557 BUG_RETURN_VAL(!motion_event, 0); 558 559 switch (event->any.type) { 560 case ET_TouchUpdate: 561 nevents = 1; 562 break; 563 case ET_TouchBegin: 564 nevents = 2; /* motion + press */ 565 ptrtype = ET_ButtonPress; 566 break; 567 case ET_TouchEnd: 568 nevents = 2; /* motion + release */ 569 ptrtype = ET_ButtonRelease; 570 break; 571 default: 572 BUG_WARN_MSG(1, "Invalid event type %d\n", event->any.type); 573 return 0; 574 } 575 576 BUG_WARN_MSG(!(event->device_event.flags & TOUCH_POINTER_EMULATED), 577 "Non-emulating touch event\n"); 578 579 motion_event->device_event = event->device_event; 580 motion_event->any.type = ET_Motion; 581 motion_event->device_event.detail.button = 0; 582 motion_event->device_event.flags = XIPointerEmulated; 583 584 if (nevents > 1) { 585 BUG_RETURN_VAL(!button_event, 0); 586 button_event->device_event = event->device_event; 587 button_event->any.type = ptrtype; 588 button_event->device_event.flags = XIPointerEmulated; 589 /* detail is already correct */ 590 } 591 592 return nevents; 593 } 594 595 /** 596 * Return the corresponding pointer emulation internal event type for the given 597 * touch event or 0 if no such event type exists. 598 */ 599 int 600 TouchGetPointerEventType(const InternalEvent *event) 601 { 602 int type = 0; 603 604 switch (event->any.type) { 605 case ET_TouchBegin: 606 type = ET_ButtonPress; 607 break; 608 case ET_TouchUpdate: 609 type = ET_Motion; 610 break; 611 case ET_TouchEnd: 612 type = ET_ButtonRelease; 613 break; 614 default: 615 break; 616 } 617 return type; 618 } 619 620 /** 621 * @returns TRUE if the specified grab or selection is the current owner of 622 * the touch sequence. 623 */ 624 Bool 625 TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource) 626 { 627 return (ti->listeners[0].listener == resource); 628 } 629 630 /** 631 * Add the resource to this touch's listeners. 632 */ 633 void 634 TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type, 635 enum InputLevel level, enum TouchListenerType type, 636 enum TouchListenerState state, WindowPtr window, 637 const GrabPtr grab) 638 { 639 GrabPtr g = NULL; 640 641 /* We need a copy of the grab, not the grab itself since that may be 642 * deleted by a UngrabButton request and leaves us with a dangling 643 * pointer */ 644 if (grab) 645 g = AllocGrab(grab); 646 647 ti->listeners[ti->num_listeners].listener = resource; 648 ti->listeners[ti->num_listeners].resource_type = resource_type; 649 ti->listeners[ti->num_listeners].level = level; 650 ti->listeners[ti->num_listeners].state = state; 651 ti->listeners[ti->num_listeners].type = type; 652 ti->listeners[ti->num_listeners].window = window; 653 ti->listeners[ti->num_listeners].grab = g; 654 if (grab) 655 ti->num_grabs++; 656 ti->num_listeners++; 657 } 658 659 /** 660 * Remove the resource from this touch's listeners. 661 * 662 * @return TRUE if the resource was removed, FALSE if the resource was not 663 * in the list 664 */ 665 Bool 666 TouchRemoveListener(TouchPointInfoPtr ti, XID resource) 667 { 668 int i; 669 670 for (i = 0; i < ti->num_listeners; i++) { 671 int j; 672 TouchListener *listener = &ti->listeners[i]; 673 674 if (listener->listener != resource) 675 continue; 676 677 if (listener->grab) { 678 FreeGrab(listener->grab); 679 listener->grab = NULL; 680 ti->num_grabs--; 681 } 682 683 for (j = i; j < ti->num_listeners - 1; j++) 684 ti->listeners[j] = ti->listeners[j + 1]; 685 ti->num_listeners--; 686 ti->listeners[ti->num_listeners].listener = 0; 687 ti->listeners[ti->num_listeners].state = TOUCH_LISTENER_AWAITING_BEGIN; 688 689 return TRUE; 690 } 691 return FALSE; 692 } 693 694 static void 695 TouchAddGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti, 696 InternalEvent *ev, GrabPtr grab) 697 { 698 enum TouchListenerType type = TOUCH_LISTENER_GRAB; 699 700 /* FIXME: owner_events */ 701 702 if (grab->grabtype == XI2) { 703 if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchOwnership)) 704 TouchEventHistoryAllocate(ti); 705 if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin)) 706 type = TOUCH_LISTENER_POINTER_GRAB; 707 } 708 else if (grab->grabtype == XI || grab->grabtype == CORE) { 709 TouchEventHistoryAllocate(ti); 710 type = TOUCH_LISTENER_POINTER_GRAB; 711 } 712 713 /* grab listeners are always RT_NONE since we keep the grab pointer */ 714 TouchAddListener(ti, grab->resource, RT_NONE, grab->grabtype, 715 type, TOUCH_LISTENER_AWAITING_BEGIN, grab->window, grab); 716 } 717 718 /** 719 * Add one listener if there is a grab on the given window. 720 */ 721 static void 722 TouchAddPassiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti, 723 WindowPtr win, InternalEvent *ev) 724 { 725 GrabPtr grab; 726 Bool check_core = IsMaster(dev) && ti->emulate_pointer; 727 728 /* FIXME: make CheckPassiveGrabsOnWindow only trigger on TouchBegin */ 729 grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core, FALSE); 730 if (!grab) 731 return; 732 733 TouchAddGrabListener(dev, ti, ev, grab); 734 } 735 736 static Bool 737 TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti, 738 WindowPtr win, InternalEvent *ev) 739 { 740 InputClients *iclients = NULL; 741 OtherInputMasks *inputMasks = NULL; 742 uint16_t evtype = 0; /* may be event type or emulated event type */ 743 enum TouchListenerType type = TOUCH_LISTENER_REGULAR; 744 int mask; 745 746 evtype = GetXI2Type(ev->any.type); 747 mask = EventIsDeliverable(dev, ev->any.type, win); 748 if (!mask && !ti->emulate_pointer) 749 return FALSE; 750 else if (!mask) { /* now try for pointer event */ 751 mask = EventIsDeliverable(dev, TouchGetPointerEventType(ev), win); 752 if (mask) { 753 evtype = GetXI2Type(TouchGetPointerEventType(ev)); 754 type = TOUCH_LISTENER_POINTER_REGULAR; 755 } 756 } 757 if (!mask) 758 return FALSE; 759 760 inputMasks = wOtherInputMasks(win); 761 762 if (mask & EVENT_XI2_MASK) { 763 BUG_RETURN_VAL(!inputMasks, FALSE); 764 765 nt_list_for_each_entry(iclients, inputMasks->inputClients, next) { 766 if (!xi2mask_isset(iclients->xi2mask, dev, evtype)) 767 continue; 768 769 if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership)) 770 TouchEventHistoryAllocate(ti); 771 772 TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI2, 773 type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL); 774 return TRUE; 775 } 776 } 777 778 if (mask & EVENT_XI1_MASK) { 779 int xitype = GetXIType(TouchGetPointerEventType(ev)); 780 Mask xi_filter = event_get_filter_from_type(dev, xitype); 781 782 BUG_RETURN_VAL(!inputMasks, FALSE); 783 784 nt_list_for_each_entry(iclients, inputMasks->inputClients, next) { 785 if (!(iclients->mask[dev->id] & xi_filter)) 786 continue; 787 788 TouchEventHistoryAllocate(ti); 789 TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI, 790 TOUCH_LISTENER_POINTER_REGULAR, 791 TOUCH_LISTENER_AWAITING_BEGIN, 792 win, NULL); 793 return TRUE; 794 } 795 } 796 797 if (mask & EVENT_CORE_MASK) { 798 int coretype = GetCoreType(TouchGetPointerEventType(ev)); 799 Mask core_filter = event_get_filter_from_type(dev, coretype); 800 OtherClients *oclients; 801 802 /* window owner */ 803 if (IsMaster(dev) && (win->eventMask & core_filter)) { 804 TouchEventHistoryAllocate(ti); 805 TouchAddListener(ti, win->drawable.id, RT_WINDOW, CORE, 806 TOUCH_LISTENER_POINTER_REGULAR, 807 TOUCH_LISTENER_AWAITING_BEGIN, 808 win, NULL); 809 return TRUE; 810 } 811 812 /* all others */ 813 nt_list_for_each_entry(oclients, wOtherClients(win), next) { 814 if (!(oclients->mask & core_filter)) 815 continue; 816 817 TouchEventHistoryAllocate(ti); 818 TouchAddListener(ti, oclients->resource, RT_OTHERCLIENT, CORE, 819 type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL); 820 return TRUE; 821 } 822 } 823 824 return FALSE; 825 } 826 827 static void 828 TouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti, 829 InternalEvent *ev, GrabPtr grab) 830 { 831 if (!ti->emulate_pointer && 832 (grab->grabtype == CORE || grab->grabtype == XI)) 833 return; 834 835 if (!ti->emulate_pointer && 836 grab->grabtype == XI2 && 837 !xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin)) 838 return; 839 840 TouchAddGrabListener(dev, ti, ev, grab); 841 } 842 843 void 844 TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev) 845 { 846 int i; 847 SpritePtr sprite = &ti->sprite; 848 WindowPtr win; 849 850 if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab) 851 TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab); 852 853 /* We set up an active touch listener for existing touches, but not any 854 * passive grab or regular listeners. */ 855 if (ev->any.type != ET_TouchBegin) 856 return; 857 858 /* First, find all grabbing clients from the root window down 859 * to the deepest child window. */ 860 for (i = 0; i < sprite->spriteTraceGood; i++) { 861 win = sprite->spriteTrace[i]; 862 TouchAddPassiveGrabListener(dev, ti, win, ev); 863 } 864 865 /* Find the first client with an applicable event selection, 866 * going from deepest child window back up to the root window. */ 867 for (i = sprite->spriteTraceGood - 1; i >= 0; i--) { 868 Bool delivered; 869 870 win = sprite->spriteTrace[i]; 871 delivered = TouchAddRegularListener(dev, ti, win, ev); 872 if (delivered) 873 return; 874 } 875 } 876 877 /** 878 * Remove the touch pointer grab from the device. Called from 879 * DeactivatePointerGrab() 880 */ 881 void 882 TouchRemovePointerGrab(DeviceIntPtr dev) 883 { 884 TouchPointInfoPtr ti; 885 GrabPtr grab; 886 InternalEvent *ev; 887 888 if (!dev->touch) 889 return; 890 891 grab = dev->deviceGrab.grab; 892 if (!grab) 893 return; 894 895 ev = dev->deviceGrab.sync.event; 896 if (!IsTouchEvent(ev)) 897 return; 898 899 ti = TouchFindByClientID(dev, ev->device_event.touchid); 900 if (!ti) 901 return; 902 903 /* FIXME: missing a bit of code here... */ 904 } 905 906 /* As touch grabs don't turn into active grabs with their own resources, we 907 * need to walk all the touches and remove this grab from any delivery 908 * lists. */ 909 void 910 TouchListenerGone(XID resource) 911 { 912 TouchPointInfoPtr ti; 913 DeviceIntPtr dev; 914 InternalEvent *events = InitEventList(GetMaximumEventsNum()); 915 int i, j, k, nev; 916 917 if (!events) 918 FatalError("TouchListenerGone: couldn't allocate events\n"); 919 920 for (dev = inputInfo.devices; dev; dev = dev->next) { 921 if (!dev->touch) 922 continue; 923 924 for (i = 0; i < dev->touch->num_touches; i++) { 925 ti = &dev->touch->touches[i]; 926 if (!ti->active) 927 continue; 928 929 for (j = 0; j < ti->num_listeners; j++) { 930 if (CLIENT_BITS(ti->listeners[j].listener) != resource) 931 continue; 932 933 nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch, 934 ti->listeners[j].listener, 0); 935 for (k = 0; k < nev; k++) 936 mieqProcessDeviceEvent(dev, events + k, NULL); 937 938 break; 939 } 940 } 941 } 942 943 FreeEventList(events, GetMaximumEventsNum()); 944 } 945 946 int 947 TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener, 948 int mode) 949 { 950 InternalEvent *events; 951 int nev; 952 int i; 953 954 BUG_RETURN_VAL(listener < 0, BadMatch); 955 BUG_RETURN_VAL(listener >= ti->num_listeners, BadMatch); 956 957 if (listener > 0) { 958 if (mode == XIRejectTouch) 959 TouchRejected(dev, ti, ti->listeners[listener].listener, NULL); 960 else 961 ti->listeners[listener].state = TOUCH_LISTENER_EARLY_ACCEPT; 962 963 return Success; 964 } 965 966 events = InitEventList(GetMaximumEventsNum()); 967 BUG_RETURN_VAL_MSG(!events, BadAlloc, "Failed to allocate touch ownership events\n"); 968 969 nev = GetTouchOwnershipEvents(events, dev, ti, mode, 970 ti->listeners[0].listener, 0); 971 BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n"); 972 973 for (i = 0; i < nev; i++) 974 mieqProcessDeviceEvent(dev, events + i, NULL); 975 976 FreeEventList(events, GetMaximumEventsNum()); 977 978 return nev ? Success : BadMatch; 979 } 980 981 int 982 TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode, 983 uint32_t touchid, Window grab_window, XID *error) 984 { 985 TouchPointInfoPtr ti; 986 int i; 987 988 if (!dev->touch) { 989 *error = dev->id; 990 return BadDevice; 991 } 992 993 ti = TouchFindByClientID(dev, touchid); 994 if (!ti) { 995 *error = touchid; 996 return BadValue; 997 } 998 999 for (i = 0; i < ti->num_listeners; i++) { 1000 if (CLIENT_ID(ti->listeners[i].listener) == client->index && 1001 ti->listeners[i].window->drawable.id == grab_window) 1002 break; 1003 } 1004 if (i == ti->num_listeners) 1005 return BadAccess; 1006 1007 return TouchListenerAcceptReject(dev, ti, i, mode); 1008 } 1009 1010 /** 1011 * End physically active touches for a device. 1012 */ 1013 void 1014 TouchEndPhysicallyActiveTouches(DeviceIntPtr dev) 1015 { 1016 InternalEvent *eventlist = InitEventList(GetMaximumEventsNum()); 1017 int i; 1018 1019 input_lock(); 1020 mieqProcessInputEvents(); 1021 for (i = 0; i < dev->last.num_touches; i++) { 1022 DDXTouchPointInfoPtr ddxti = dev->last.touches + i; 1023 1024 if (ddxti->active) { 1025 int j; 1026 int nevents = GetTouchEvents(eventlist, dev, ddxti->ddx_id, 1027 XI_TouchEnd, 0, NULL); 1028 1029 for (j = 0; j < nevents; j++) 1030 mieqProcessDeviceEvent(dev, eventlist + j, NULL); 1031 } 1032 } 1033 input_unlock(); 1034 1035 FreeEventList(eventlist, GetMaximumEventsNum()); 1036 } 1037 1038 /** 1039 * Generate and deliver a TouchEnd event. 1040 * 1041 * @param dev The device to deliver the event for. 1042 * @param ti The touch point record to deliver the event for. 1043 * @param flags Internal event flags. The called does not need to provide 1044 * TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure 1045 * they are set appropriately. 1046 * @param resource The client resource to deliver to, or 0 for all clients. 1047 */ 1048 void 1049 TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource) 1050 { 1051 InternalEvent event; 1052 1053 /* We're not processing a touch end for a frozen device */ 1054 if (dev->deviceGrab.sync.frozen) 1055 return; 1056 1057 flags |= TOUCH_CLIENT_ID; 1058 if (ti->emulate_pointer) 1059 flags |= TOUCH_POINTER_EMULATED; 1060 DeliverDeviceClassesChangedEvent(ti->sourceid, GetTimeInMillis()); 1061 GetDixTouchEnd(&event, dev, ti, flags); 1062 DeliverTouchEvents(dev, ti, &event, resource); 1063 if (ti->num_grabs == 0) 1064 UpdateDeviceState(dev, &event.device_event); 1065 } 1066 1067 void 1068 TouchAcceptAndEnd(DeviceIntPtr dev, int touchid) 1069 { 1070 TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid); 1071 if (!ti) 1072 return; 1073 1074 TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch); 1075 if (ti->pending_finish) 1076 TouchEmitTouchEnd(dev, ti, 0, 0); 1077 if (ti->num_listeners <= 1) 1078 TouchEndTouch(dev, ti); 1079 } 1080