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