1 /* 2 * Copyright 2011 Collabra Ltd. 3 * Copyright 2011 Red Hat, Inc. 4 * Copyright 2020 Povilas Kanapickas <povilas (at) radix.lt> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26 #ifdef HAVE_DIX_CONFIG_H 27 #include <dix-config.h> 28 #endif 29 30 #include "inputstr.h" 31 #include "scrnintstr.h" 32 #include "dixgrabs.h" 33 34 #include "eventstr.h" 35 #include "exevents.h" 36 #include "exglobals.h" 37 #include "inpututils.h" 38 #include "eventconvert.h" 39 #include "windowstr.h" 40 #include "mi.h" 41 42 #define GESTURE_HISTORY_SIZE 100 43 44 Bool 45 GestureInitGestureInfo(GestureInfoPtr gi) 46 { 47 memset(gi, 0, sizeof(*gi)); 48 49 gi->sprite.spriteTrace = calloc(32, sizeof(*gi->sprite.spriteTrace)); 50 if (!gi->sprite.spriteTrace) { 51 return FALSE; 52 } 53 gi->sprite.spriteTraceSize = 32; 54 gi->sprite.spriteTrace[0] = screenInfo.screens[0]->root; 55 gi->sprite.hot.pScreen = screenInfo.screens[0]; 56 gi->sprite.hotPhys.pScreen = screenInfo.screens[0]; 57 58 return TRUE; 59 } 60 61 /** 62 * Given an event type returns the associated gesture event info. 63 */ 64 GestureInfoPtr 65 GestureFindActiveByEventType(DeviceIntPtr dev, int type) 66 { 67 GestureClassPtr g = dev->gesture; 68 enum EventType type_to_expect = GestureTypeToBegin(type); 69 70 if (!g || type_to_expect == 0 || !g->gesture.active || 71 g->gesture.type != type_to_expect) { 72 return NULL; 73 } 74 75 return &g->gesture; 76 } 77 78 /** 79 * Sets up gesture info for a new gesture. Returns NULL on failure. 80 */ 81 GestureInfoPtr 82 GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev) 83 { 84 GestureClassPtr g = dev->gesture; 85 enum EventType gesture_type = GestureTypeToBegin(ev->any.type); 86 87 /* Note that we ignore begin events when an existing gesture is active */ 88 if (!g || gesture_type == 0 || g->gesture.active) 89 return NULL; 90 91 g->gesture.type = gesture_type; 92 93 if (!GestureBuildSprite(dev, &g->gesture)) 94 return NULL; 95 96 g->gesture.active = TRUE; 97 g->gesture.num_touches = ev->gesture_event.num_touches; 98 g->gesture.sourceid = ev->gesture_event.sourceid; 99 g->gesture.has_listener = FALSE; 100 return &g->gesture; 101 } 102 103 /** 104 * Releases a gesture: this must only be called after all events 105 * related to that gesture have been sent and finalised. 106 */ 107 void 108 GestureEndGesture(GestureInfoPtr gi) 109 { 110 if (gi->has_listener) { 111 if (gi->listener.grab) { 112 FreeGrab(gi->listener.grab); 113 gi->listener.grab = NULL; 114 } 115 gi->listener.listener = 0; 116 gi->has_listener = FALSE; 117 } 118 119 gi->active = FALSE; 120 gi->num_touches = 0; 121 gi->sprite.spriteTraceGood = 0; 122 } 123 124 /** 125 * Ensure a window trace is present in gi->sprite, constructing one for 126 * Gesture{Pinch,Swipe}Begin events. 127 */ 128 Bool 129 GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi) 130 { 131 SpritePtr sprite = &gi->sprite; 132 133 if (!sourcedev->spriteInfo->sprite) 134 return FALSE; 135 136 if (!CopySprite(sourcedev->spriteInfo->sprite, sprite)) 137 return FALSE; 138 139 if (sprite->spriteTraceGood <= 0) 140 return FALSE; 141 142 return TRUE; 143 } 144 145 /** 146 * @returns TRUE if the specified grab or selection is the current owner of 147 * the gesture sequence. 148 */ 149 Bool 150 GestureResourceIsOwner(GestureInfoPtr gi, XID resource) 151 { 152 return (gi->listener.listener == resource); 153 } 154 155 void 156 GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type, 157 enum GestureListenerType type, WindowPtr window, const GrabPtr grab) 158 { 159 GrabPtr g = NULL; 160 161 BUG_RETURN(gi->has_listener); 162 163 /* We need a copy of the grab, not the grab itself since that may be deleted by 164 * a UngrabButton request and leaves us with a dangling pointer */ 165 if (grab) 166 g = AllocGrab(grab); 167 168 gi->listener.listener = resource; 169 gi->listener.resource_type = resource_type; 170 gi->listener.type = type; 171 gi->listener.window = window; 172 gi->listener.grab = g; 173 gi->has_listener = TRUE; 174 } 175 176 static void 177 GestureAddGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, GrabPtr grab) 178 { 179 enum GestureListenerType type; 180 181 /* FIXME: owner_events */ 182 183 if (grab->grabtype == XI2) { 184 if (xi2mask_isset(grab->xi2mask, dev, XI_GesturePinchBegin) || 185 xi2mask_isset(grab->xi2mask, dev, XI_GestureSwipeBegin)) { 186 type = GESTURE_LISTENER_GRAB; 187 } else 188 type = GESTURE_LISTENER_NONGESTURE_GRAB; 189 } 190 else if (grab->grabtype == XI || grab->grabtype == CORE) { 191 type = GESTURE_LISTENER_NONGESTURE_GRAB; 192 } 193 else { 194 BUG_RETURN_MSG(1, "Unsupported grab type\n"); 195 } 196 197 /* grab listeners are always RT_NONE since we keep the grab pointer */ 198 GestureAddListener(gi, grab->resource, RT_NONE, type, grab->window, grab); 199 } 200 201 /** 202 * Add one listener if there is a grab on the given window. 203 */ 204 static void 205 GestureAddPassiveGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev) 206 { 207 Bool activate = FALSE; 208 Bool check_core = FALSE; 209 210 GrabPtr grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core, 211 activate); 212 if (!grab) 213 return; 214 215 /* We'll deliver later in gesture-specific code */ 216 ActivateGrabNoDelivery(dev, grab, ev, ev); 217 GestureAddGrabListener(dev, gi, grab); 218 } 219 220 static void 221 GestureAddRegularListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev) 222 { 223 InputClients *iclients = NULL; 224 OtherInputMasks *inputMasks = NULL; 225 uint16_t evtype = GetXI2Type(ev->any.type); 226 int mask; 227 228 mask = EventIsDeliverable(dev, ev->any.type, win); 229 if (!mask) 230 return; 231 232 inputMasks = wOtherInputMasks(win); 233 BUG_RETURN(!inputMasks); 234 235 if (mask & EVENT_XI2_MASK) { 236 nt_list_for_each_entry(iclients, inputMasks->inputClients, next) { 237 if (!xi2mask_isset(iclients->xi2mask, dev, evtype)) 238 continue; 239 240 GestureAddListener(gi, iclients->resource, RT_INPUTCLIENT, 241 GESTURE_LISTENER_REGULAR, win, NULL); 242 return; 243 } 244 } 245 } 246 247 void 248 GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev) 249 { 250 int i; 251 SpritePtr sprite = &gi->sprite; 252 WindowPtr win; 253 254 /* Any current grab will consume all gesture events */ 255 if (dev->deviceGrab.grab) { 256 GestureAddGrabListener(dev, gi, dev->deviceGrab.grab); 257 return; 258 } 259 260 /* Find passive grab that would be activated by this event, if any. If we're handling 261 * ReplayDevice then the search starts from the descendant of the grab window, otherwise 262 * the search starts at the root window. The search ends at deepest child window. */ 263 i = 0; 264 if (syncEvents.playingEvents) { 265 while (i < dev->spriteInfo->sprite->spriteTraceGood) { 266 if (dev->spriteInfo->sprite->spriteTrace[i++] == syncEvents.replayWin) 267 break; 268 } 269 } 270 271 for (; i < sprite->spriteTraceGood; i++) { 272 win = sprite->spriteTrace[i]; 273 GestureAddPassiveGrabListener(dev, gi, win, ev); 274 if (gi->has_listener) 275 return; 276 } 277 278 /* Find the first client with an applicable event selection, 279 * going from deepest child window back up to the root window. */ 280 for (i = sprite->spriteTraceGood - 1; i >= 0; i--) { 281 win = sprite->spriteTrace[i]; 282 GestureAddRegularListener(dev, gi, win, ev); 283 if (gi->has_listener) 284 return; 285 } 286 } 287 288 /* As gesture grabs don't turn into active grabs with their own resources, we 289 * need to walk all the gestures and remove this grab from listener */ 290 void 291 GestureListenerGone(XID resource) 292 { 293 GestureInfoPtr gi; 294 DeviceIntPtr dev; 295 InternalEvent *events = InitEventList(GetMaximumEventsNum()); 296 297 if (!events) 298 FatalError("GestureListenerGone: couldn't allocate events\n"); 299 300 for (dev = inputInfo.devices; dev; dev = dev->next) { 301 if (!dev->gesture) 302 continue; 303 304 gi = &dev->gesture->gesture; 305 if (!gi->active) 306 continue; 307 308 if (CLIENT_BITS(gi->listener.listener) == resource) 309 GestureEndGesture(gi); 310 } 311 312 FreeEventList(events, GetMaximumEventsNum()); 313 } 314 315 /** 316 * End physically active gestures for a device. 317 */ 318 void 319 GestureEndActiveGestures(DeviceIntPtr dev) 320 { 321 GestureClassPtr g = dev->gesture; 322 InternalEvent *eventlist; 323 324 if (!g) 325 return; 326 327 eventlist = InitEventList(GetMaximumEventsNum()); 328 329 input_lock(); 330 mieqProcessInputEvents(); 331 if (g->gesture.active) { 332 int j; 333 int type = GetXI2Type(GestureTypeToEnd(g->gesture.type)); 334 int nevents = GetGestureEvents(eventlist, dev, type, g->gesture.num_touches, 335 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); 336 337 for (j = 0; j < nevents; j++) 338 mieqProcessDeviceEvent(dev, eventlist + j, NULL); 339 } 340 input_unlock(); 341 342 FreeEventList(eventlist, GetMaximumEventsNum()); 343 } 344 345 /** 346 * Generate and deliver a Gesture{Pinch,Swipe}End event to the owner. 347 * 348 * @param dev The device to deliver the event for. 349 * @param gi The gesture record to deliver the event for. 350 */ 351 void 352 GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi) 353 { 354 InternalEvent event; 355 /* We're not processing a gesture end for a frozen device */ 356 if (dev->deviceGrab.sync.frozen) 357 return; 358 359 DeliverDeviceClassesChangedEvent(gi->sourceid, GetTimeInMillis()); 360 InitGestureEvent(&event, dev, GetTimeInMillis(), GestureTypeToEnd(gi->type), 361 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); 362 DeliverGestureEventToOwner(dev, gi, &event); 363 } 364