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