xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

gestures.c (10572B)


      1 /*
      2  * Copyright © 2011 Collabra Ltd.
      3  * Copyright © 2011 Red Hat, Inc.
      4  * Copyright © 2020 Povilas Kanapickas  <povilas@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 
    234     if (mask & EVENT_XI2_MASK) {
    235         nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
    236             if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
    237                 continue;
    238 
    239             GestureAddListener(gi, iclients->resource, RT_INPUTCLIENT,
    240                                GESTURE_LISTENER_REGULAR, win, NULL);
    241             return;
    242         }
    243     }
    244 }
    245 
    246 void
    247 GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
    248 {
    249     int i;
    250     SpritePtr sprite = &gi->sprite;
    251     WindowPtr win;
    252 
    253     /* Any current grab will consume all gesture events */
    254     if (dev->deviceGrab.grab) {
    255         GestureAddGrabListener(dev, gi, dev->deviceGrab.grab);
    256         return;
    257     }
    258 
    259     /* Find passive grab that would be activated by this event, if any. If we're handling
    260      * ReplayDevice then the search starts from the descendant of the grab window, otherwise
    261      * the search starts at the root window. The search ends at deepest child window. */
    262     i = 0;
    263     if (syncEvents.playingEvents) {
    264         while (i < dev->spriteInfo->sprite->spriteTraceGood) {
    265             if (dev->spriteInfo->sprite->spriteTrace[i++] == syncEvents.replayWin)
    266                 break;
    267         }
    268     }
    269 
    270     for (; i < sprite->spriteTraceGood; i++) {
    271         win = sprite->spriteTrace[i];
    272         GestureAddPassiveGrabListener(dev, gi, win, ev);
    273         if (gi->has_listener)
    274             return;
    275     }
    276 
    277     /* Find the first client with an applicable event selection,
    278      * going from deepest child window back up to the root window. */
    279     for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
    280         win = sprite->spriteTrace[i];
    281         GestureAddRegularListener(dev, gi, win, ev);
    282         if (gi->has_listener)
    283             return;
    284     }
    285 }
    286 
    287 /* As gesture grabs don't turn into active grabs with their own resources, we
    288  * need to walk all the gestures and remove this grab from listener */
    289 void
    290 GestureListenerGone(XID resource)
    291 {
    292     GestureInfoPtr gi;
    293     DeviceIntPtr dev;
    294     InternalEvent *events = InitEventList(GetMaximumEventsNum());
    295 
    296     if (!events)
    297         FatalError("GestureListenerGone: couldn't allocate events\n");
    298 
    299     for (dev = inputInfo.devices; dev; dev = dev->next) {
    300         if (!dev->gesture)
    301             continue;
    302 
    303         gi = &dev->gesture->gesture;
    304         if (!gi->active)
    305             continue;
    306 
    307         if (CLIENT_BITS(gi->listener.listener) == resource)
    308             GestureEndGesture(gi);
    309     }
    310 
    311     FreeEventList(events, GetMaximumEventsNum());
    312 }
    313 
    314 /**
    315  * End physically active gestures for a device.
    316  */
    317 void
    318 GestureEndActiveGestures(DeviceIntPtr dev)
    319 {
    320     GestureClassPtr g = dev->gesture;
    321     InternalEvent *eventlist;
    322 
    323     if (!g)
    324         return;
    325 
    326     eventlist = InitEventList(GetMaximumEventsNum());
    327 
    328     input_lock();
    329     mieqProcessInputEvents();
    330     if (g->gesture.active) {
    331         int j;
    332         int type = GetXI2Type(GestureTypeToEnd(g->gesture.type));
    333         int nevents = GetGestureEvents(eventlist, dev, type, g->gesture.num_touches,
    334                                        0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
    335 
    336         for (j = 0; j < nevents; j++)
    337             mieqProcessDeviceEvent(dev, eventlist + j, NULL);
    338     }
    339     input_unlock();
    340 
    341     FreeEventList(eventlist, GetMaximumEventsNum());
    342 }
    343 
    344 /**
    345  * Generate and deliver a Gesture{Pinch,Swipe}End event to the owner.
    346  *
    347  * @param dev The device to deliver the event for.
    348  * @param gi The gesture record to deliver the event for.
    349  */
    350 void
    351 GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi)
    352 {
    353     InternalEvent event;
    354     /* We're not processing a gesture end for a frozen device */
    355     if (dev->deviceGrab.sync.frozen)
    356         return;
    357 
    358     DeliverDeviceClassesChangedEvent(gi->sourceid, GetTimeInMillis());
    359     InitGestureEvent(&event, dev, GetTimeInMillis(), GestureTypeToEnd(gi->type),
    360                      0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
    361     DeliverGestureEventToOwner(dev, gi, &event);
    362 }