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 45Bool 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 77static Bool 78TouchResizeQueue(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 */ 107DDXTouchPointInfoPtr 108TouchFindByDDXID(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 */ 135DDXTouchPointInfoPtr 136TouchBeginDDXTouch(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 186void 187TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti) 188{ 189 TouchClassPtr t = dev->touch; 190 191 if (!t) 192 return; 193 194 ti->active = FALSE; 195} 196 197void 198TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch) 199{ 200 memset(ddxtouch, 0, sizeof(*ddxtouch)); 201 ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes); 202} 203 204Bool 205TouchInitTouchPoint(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 234void 235TouchFreeTouchPoint(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 */ 265TouchPointInfoPtr 266TouchFindByClientID(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 */ 291TouchPointInfoPtr 292TouchBeginTouch(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 */ 341void 342TouchEndTouch(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 */ 381Bool 382TouchEventHistoryAllocate(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 394void 395TouchEventHistoryFree(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 */ 411void 412TouchEventHistoryPush(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 444void 445TouchEventHistoryReplay(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 476Bool 477TouchBuildDependentSpriteTrace(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 */ 503Bool 504TouchBuildSprite(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 */ 548int 549TouchConvertToPointerEvent(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 */ 599int 600TouchGetPointerEventType(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 */ 624Bool 625TouchResourceIsOwner(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 */ 633void 634TouchAddListener(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 */ 665Bool 666TouchRemoveListener(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 694static void 695TouchAddGrabListener(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 */ 721static void 722TouchAddPassiveGrabListener(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 736static Bool 737TouchAddRegularListener(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 nt_list_for_each_entry(iclients, inputMasks->inputClients, next) { 764 if (!xi2mask_isset(iclients->xi2mask, dev, evtype)) 765 continue; 766 767 if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership)) 768 TouchEventHistoryAllocate(ti); 769 770 TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI2, 771 type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL); 772 return TRUE; 773 } 774 } 775 776 if (mask & EVENT_XI1_MASK) { 777 int xitype = GetXIType(TouchGetPointerEventType(ev)); 778 Mask xi_filter = event_get_filter_from_type(dev, xitype); 779 780 nt_list_for_each_entry(iclients, inputMasks->inputClients, next) { 781 if (!(iclients->mask[dev->id] & xi_filter)) 782 continue; 783 784 TouchEventHistoryAllocate(ti); 785 TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI, 786 TOUCH_LISTENER_POINTER_REGULAR, 787 TOUCH_LISTENER_AWAITING_BEGIN, 788 win, NULL); 789 return TRUE; 790 } 791 } 792 793 if (mask & EVENT_CORE_MASK) { 794 int coretype = GetCoreType(TouchGetPointerEventType(ev)); 795 Mask core_filter = event_get_filter_from_type(dev, coretype); 796 OtherClients *oclients; 797 798 /* window owner */ 799 if (IsMaster(dev) && (win->eventMask & core_filter)) { 800 TouchEventHistoryAllocate(ti); 801 TouchAddListener(ti, win->drawable.id, RT_WINDOW, CORE, 802 TOUCH_LISTENER_POINTER_REGULAR, 803 TOUCH_LISTENER_AWAITING_BEGIN, 804 win, NULL); 805 return TRUE; 806 } 807 808 /* all others */ 809 nt_list_for_each_entry(oclients, wOtherClients(win), next) { 810 if (!(oclients->mask & core_filter)) 811 continue; 812 813 TouchEventHistoryAllocate(ti); 814 TouchAddListener(ti, oclients->resource, RT_OTHERCLIENT, CORE, 815 type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL); 816 return TRUE; 817 } 818 } 819 820 return FALSE; 821} 822 823static void 824TouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti, 825 InternalEvent *ev, GrabPtr grab) 826{ 827 if (!ti->emulate_pointer && 828 (grab->grabtype == CORE || grab->grabtype == XI)) 829 return; 830 831 if (!ti->emulate_pointer && 832 grab->grabtype == XI2 && 833 !xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin)) 834 return; 835 836 TouchAddGrabListener(dev, ti, ev, grab); 837} 838 839void 840TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev) 841{ 842 int i; 843 SpritePtr sprite = &ti->sprite; 844 WindowPtr win; 845 846 if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab) 847 TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab); 848 849 /* We set up an active touch listener for existing touches, but not any 850 * passive grab or regular listeners. */ 851 if (ev->any.type != ET_TouchBegin) 852 return; 853 854 /* First, find all grabbing clients from the root window down 855 * to the deepest child window. */ 856 for (i = 0; i < sprite->spriteTraceGood; i++) { 857 win = sprite->spriteTrace[i]; 858 TouchAddPassiveGrabListener(dev, ti, win, ev); 859 } 860 861 /* Find the first client with an applicable event selection, 862 * going from deepest child window back up to the root window. */ 863 for (i = sprite->spriteTraceGood - 1; i >= 0; i--) { 864 Bool delivered; 865 866 win = sprite->spriteTrace[i]; 867 delivered = TouchAddRegularListener(dev, ti, win, ev); 868 if (delivered) 869 return; 870 } 871} 872 873/** 874 * Remove the touch pointer grab from the device. Called from 875 * DeactivatePointerGrab() 876 */ 877void 878TouchRemovePointerGrab(DeviceIntPtr dev) 879{ 880 TouchPointInfoPtr ti; 881 GrabPtr grab; 882 InternalEvent *ev; 883 884 if (!dev->touch) 885 return; 886 887 grab = dev->deviceGrab.grab; 888 if (!grab) 889 return; 890 891 ev = dev->deviceGrab.sync.event; 892 if (!IsTouchEvent(ev)) 893 return; 894 895 ti = TouchFindByClientID(dev, ev->device_event.touchid); 896 if (!ti) 897 return; 898 899 /* FIXME: missing a bit of code here... */ 900} 901 902/* As touch grabs don't turn into active grabs with their own resources, we 903 * need to walk all the touches and remove this grab from any delivery 904 * lists. */ 905void 906TouchListenerGone(XID resource) 907{ 908 TouchPointInfoPtr ti; 909 DeviceIntPtr dev; 910 InternalEvent *events = InitEventList(GetMaximumEventsNum()); 911 int i, j, k, nev; 912 913 if (!events) 914 FatalError("TouchListenerGone: couldn't allocate events\n"); 915 916 for (dev = inputInfo.devices; dev; dev = dev->next) { 917 if (!dev->touch) 918 continue; 919 920 for (i = 0; i < dev->touch->num_touches; i++) { 921 ti = &dev->touch->touches[i]; 922 if (!ti->active) 923 continue; 924 925 for (j = 0; j < ti->num_listeners; j++) { 926 if (CLIENT_BITS(ti->listeners[j].listener) != resource) 927 continue; 928 929 nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch, 930 ti->listeners[j].listener, 0); 931 for (k = 0; k < nev; k++) 932 mieqProcessDeviceEvent(dev, events + k, NULL); 933 934 break; 935 } 936 } 937 } 938 939 FreeEventList(events, GetMaximumEventsNum()); 940} 941 942int 943TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener, 944 int mode) 945{ 946 InternalEvent *events; 947 int nev; 948 int i; 949 950 BUG_RETURN_VAL(listener < 0, BadMatch); 951 BUG_RETURN_VAL(listener >= ti->num_listeners, BadMatch); 952 953 if (listener > 0) { 954 if (mode == XIRejectTouch) 955 TouchRejected(dev, ti, ti->listeners[listener].listener, NULL); 956 else 957 ti->listeners[listener].state = TOUCH_LISTENER_EARLY_ACCEPT; 958 959 return Success; 960 } 961 962 events = InitEventList(GetMaximumEventsNum()); 963 BUG_RETURN_VAL_MSG(!events, BadAlloc, "Failed to allocate touch ownership events\n"); 964 965 nev = GetTouchOwnershipEvents(events, dev, ti, mode, 966 ti->listeners[0].listener, 0); 967 BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n"); 968 969 for (i = 0; i < nev; i++) 970 mieqProcessDeviceEvent(dev, events + i, NULL); 971 972 FreeEventList(events, GetMaximumEventsNum()); 973 974 return nev ? Success : BadMatch; 975} 976 977int 978TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode, 979 uint32_t touchid, Window grab_window, XID *error) 980{ 981 TouchPointInfoPtr ti; 982 int i; 983 984 if (!dev->touch) { 985 *error = dev->id; 986 return BadDevice; 987 } 988 989 ti = TouchFindByClientID(dev, touchid); 990 if (!ti) { 991 *error = touchid; 992 return BadValue; 993 } 994 995 for (i = 0; i < ti->num_listeners; i++) { 996 if (CLIENT_ID(ti->listeners[i].listener) == client->index && 997 ti->listeners[i].window->drawable.id == grab_window) 998 break; 999 } 1000 if (i == ti->num_listeners) 1001 return BadAccess; 1002 1003 return TouchListenerAcceptReject(dev, ti, i, mode); 1004} 1005 1006/** 1007 * End physically active touches for a device. 1008 */ 1009void 1010TouchEndPhysicallyActiveTouches(DeviceIntPtr dev) 1011{ 1012 InternalEvent *eventlist = InitEventList(GetMaximumEventsNum()); 1013 int i; 1014 1015 input_lock(); 1016 mieqProcessInputEvents(); 1017 for (i = 0; i < dev->last.num_touches; i++) { 1018 DDXTouchPointInfoPtr ddxti = dev->last.touches + i; 1019 1020 if (ddxti->active) { 1021 int j; 1022 int nevents = GetTouchEvents(eventlist, dev, ddxti->ddx_id, 1023 XI_TouchEnd, 0, NULL); 1024 1025 for (j = 0; j < nevents; j++) 1026 mieqProcessDeviceEvent(dev, eventlist + j, NULL); 1027 } 1028 } 1029 input_unlock(); 1030 1031 FreeEventList(eventlist, GetMaximumEventsNum()); 1032} 1033 1034/** 1035 * Generate and deliver a TouchEnd event. 1036 * 1037 * @param dev The device to deliver the event for. 1038 * @param ti The touch point record to deliver the event for. 1039 * @param flags Internal event flags. The called does not need to provide 1040 * TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure 1041 * they are set appropriately. 1042 * @param resource The client resource to deliver to, or 0 for all clients. 1043 */ 1044void 1045TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource) 1046{ 1047 InternalEvent event; 1048 1049 /* We're not processing a touch end for a frozen device */ 1050 if (dev->deviceGrab.sync.frozen) 1051 return; 1052 1053 flags |= TOUCH_CLIENT_ID; 1054 if (ti->emulate_pointer) 1055 flags |= TOUCH_POINTER_EMULATED; 1056 DeliverDeviceClassesChangedEvent(ti->sourceid, GetTimeInMillis()); 1057 GetDixTouchEnd(&event, dev, ti, flags); 1058 DeliverTouchEvents(dev, ti, &event, resource); 1059 if (ti->num_grabs == 0) 1060 UpdateDeviceState(dev, &event.device_event); 1061} 1062 1063void 1064TouchAcceptAndEnd(DeviceIntPtr dev, int touchid) 1065{ 1066 TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid); 1067 if (!ti) 1068 return; 1069 1070 TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch); 1071 if (ti->pending_finish) 1072 TouchEmitTouchEnd(dev, ti, 0, 0); 1073 if (ti->num_listeners <= 1) 1074 TouchEndTouch(dev, ti); 1075} 1076