xserver

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

xichangehierarchy.c (14648B)


      1 /*
      2  * Copyright 2007-2008 Peter Hutterer
      3  * Copyright 2009 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: Peter Hutterer, University of South Australia, NICTA
     25  */
     26 
     27 /***********************************************************************
     28  *
     29  * Request change in the device hierarchy.
     30  *
     31  */
     32 
     33 #ifdef HAVE_DIX_CONFIG_H
     34 #include <dix-config.h>
     35 #endif
     36 
     37 #include <X11/X.h>              /* for inputstr.h    */
     38 #include <X11/Xproto.h>         /* Request macro     */
     39 #include "inputstr.h"           /* DeviceIntPtr      */
     40 #include "windowstr.h"          /* window structure  */
     41 #include "scrnintstr.h"         /* screen structure  */
     42 #include <X11/extensions/XI.h>
     43 #include <X11/extensions/XI2proto.h>
     44 #include <X11/extensions/geproto.h>
     45 #include "extnsionst.h"
     46 #include "exevents.h"
     47 #include "exglobals.h"
     48 #include "geext.h"
     49 #include "xace.h"
     50 #include "xiquerydevice.h"      /* for GetDeviceUse */
     51 
     52 #include "xkbsrv.h"
     53 
     54 #include "xichangehierarchy.h"
     55 #include "xibarriers.h"
     56 
     57 /**
     58  * Send the current state of the device hierarchy to all clients.
     59  */
     60 void
     61 XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
     62 {
     63     xXIHierarchyEvent *ev;
     64     xXIHierarchyInfo *info;
     65     DeviceIntRec dummyDev;
     66     DeviceIntPtr dev;
     67     int i;
     68 
     69     if (!flags)
     70         return;
     71 
     72     ev = calloc(1, sizeof(xXIHierarchyEvent) +
     73                 MAXDEVICES * sizeof(xXIHierarchyInfo));
     74     if (!ev)
     75         return;
     76     ev->type = GenericEvent;
     77     ev->extension = IReqCode;
     78     ev->evtype = XI_HierarchyChanged;
     79     ev->time = GetTimeInMillis();
     80     ev->flags = 0;
     81     ev->num_info = inputInfo.numDevices;
     82 
     83     info = (xXIHierarchyInfo *) &ev[1];
     84     for (dev = inputInfo.devices; dev; dev = dev->next) {
     85         info->deviceid = dev->id;
     86         info->enabled = dev->enabled;
     87         info->use = GetDeviceUse(dev, &info->attachment);
     88         info->flags = flags[dev->id];
     89         ev->flags |= info->flags;
     90         info++;
     91     }
     92     for (dev = inputInfo.off_devices; dev; dev = dev->next) {
     93         info->deviceid = dev->id;
     94         info->enabled = dev->enabled;
     95         info->use = GetDeviceUse(dev, &info->attachment);
     96         info->flags = flags[dev->id];
     97         ev->flags |= info->flags;
     98         info++;
     99     }
    100 
    101     for (i = 0; i < MAXDEVICES; i++) {
    102         if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) {
    103             info->deviceid = i;
    104             info->enabled = FALSE;
    105             info->flags = flags[i];
    106             info->use = 0;
    107             ev->flags |= info->flags;
    108             ev->num_info++;
    109             info++;
    110         }
    111     }
    112 
    113     ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
    114 
    115     memset(&dummyDev, 0, sizeof(dummyDev));
    116     dummyDev.id = XIAllDevices;
    117     dummyDev.type = SLAVE;
    118     SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8),
    119                           (xEvent *) ev, 1);
    120     free(ev);
    121 }
    122 
    123 /***********************************************************************
    124  *
    125  * This procedure allows a client to change the device hierarchy through
    126  * adding new master devices, removing them, etc.
    127  *
    128  */
    129 
    130 int _X_COLD
    131 SProcXIChangeHierarchy(ClientPtr client)
    132 {
    133     REQUEST(xXIChangeHierarchyReq);
    134     swaps(&stuff->length);
    135     return (ProcXIChangeHierarchy(client));
    136 }
    137 
    138 static int
    139 add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES])
    140 {
    141     DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
    142     char *name;
    143     int rc;
    144 
    145     name = calloc(c->name_len + 1, sizeof(char));
    146     if (name == NULL) {
    147         rc = BadAlloc;
    148         goto unwind;
    149     }
    150     strncpy(name, (char *) &c[1], c->name_len);
    151 
    152     rc = AllocDevicePair(client, name, &ptr, &keybd,
    153                          CorePointerProc, CoreKeyboardProc, TRUE);
    154     if (rc != Success)
    155         goto unwind;
    156 
    157     if (!c->send_core)
    158         ptr->coreEvents = keybd->coreEvents = FALSE;
    159 
    160     /* Allocate virtual slave devices for xtest events */
    161     rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
    162     if (rc != Success) {
    163         DeleteInputDeviceRequest(ptr);
    164         DeleteInputDeviceRequest(keybd);
    165         goto unwind;
    166     }
    167 
    168     ActivateDevice(ptr, FALSE);
    169     ActivateDevice(keybd, FALSE);
    170     flags[ptr->id] |= XIMasterAdded;
    171     flags[keybd->id] |= XIMasterAdded;
    172 
    173     ActivateDevice(XTestptr, FALSE);
    174     ActivateDevice(XTestkeybd, FALSE);
    175     flags[XTestptr->id] |= XISlaveAdded;
    176     flags[XTestkeybd->id] |= XISlaveAdded;
    177 
    178     if (c->enable) {
    179         EnableDevice(ptr, FALSE);
    180         EnableDevice(keybd, FALSE);
    181         flags[ptr->id] |= XIDeviceEnabled;
    182         flags[keybd->id] |= XIDeviceEnabled;
    183 
    184         EnableDevice(XTestptr, FALSE);
    185         EnableDevice(XTestkeybd, FALSE);
    186         flags[XTestptr->id] |= XIDeviceEnabled;
    187         flags[XTestkeybd->id] |= XIDeviceEnabled;
    188     }
    189 
    190     /* Attach the XTest virtual devices to the newly
    191        created master device */
    192     AttachDevice(NULL, XTestptr, ptr);
    193     AttachDevice(NULL, XTestkeybd, keybd);
    194     flags[XTestptr->id] |= XISlaveAttached;
    195     flags[XTestkeybd->id] |= XISlaveAttached;
    196 
    197     for (int i = 0; i < currentMaxClients; i++)
    198         XIBarrierNewMasterDevice(clients[i], ptr->id);
    199 
    200  unwind:
    201     free(name);
    202     return rc;
    203 }
    204 
    205 static void
    206 disable_clientpointer(DeviceIntPtr dev)
    207 {
    208     int i;
    209 
    210     for (i = 0; i < currentMaxClients; i++) {
    211         ClientPtr client = clients[i];
    212 
    213         if (client && client->clientPtr == dev)
    214             client->clientPtr = NULL;
    215     }
    216 }
    217 
    218 static int
    219 remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
    220 {
    221     DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
    222     int rc = Success;
    223 
    224     if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
    225         return BadValue;
    226 
    227     rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
    228     if (rc != Success)
    229         goto unwind;
    230 
    231     if (!IsMaster(ptr)) {
    232         client->errorValue = r->deviceid;
    233         rc = BadDevice;
    234         goto unwind;
    235     }
    236 
    237     /* XXX: For now, don't allow removal of VCP, VCK */
    238     if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
    239         rc = BadDevice;
    240         goto unwind;
    241     }
    242 
    243     ptr = GetMaster(ptr, MASTER_POINTER);
    244     rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
    245     if (rc != Success)
    246         goto unwind;
    247     keybd = GetMaster(ptr, MASTER_KEYBOARD);
    248     rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
    249     if (rc != Success)
    250         goto unwind;
    251 
    252     XTestptr = GetXTestDevice(ptr);
    253     rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
    254     if (rc != Success)
    255         goto unwind;
    256 
    257     XTestkeybd = GetXTestDevice(keybd);
    258     rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
    259     if (rc != Success)
    260         goto unwind;
    261 
    262     disable_clientpointer(ptr);
    263 
    264     /* Disabling sends the devices floating, reattach them if
    265      * desired. */
    266     if (r->return_mode == XIAttachToMaster) {
    267         DeviceIntPtr attached, newptr, newkeybd;
    268 
    269         rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
    270         if (rc != Success)
    271             goto unwind;
    272 
    273         if (!IsMaster(newptr)) {
    274             client->errorValue = r->return_pointer;
    275             rc = BadDevice;
    276             goto unwind;
    277         }
    278 
    279         rc = dixLookupDevice(&newkeybd, r->return_keyboard,
    280                              client, DixAddAccess);
    281         if (rc != Success)
    282             goto unwind;
    283 
    284         if (!IsMaster(newkeybd)) {
    285             client->errorValue = r->return_keyboard;
    286             rc = BadDevice;
    287             goto unwind;
    288         }
    289 
    290         for (attached = inputInfo.devices; attached; attached = attached->next) {
    291             if (!IsMaster(attached)) {
    292                 if (GetMaster(attached, MASTER_ATTACHED) == ptr) {
    293                     AttachDevice(client, attached, newptr);
    294                     flags[attached->id] |= XISlaveAttached;
    295                 }
    296                 if (GetMaster(attached, MASTER_ATTACHED) == keybd) {
    297                     AttachDevice(client, attached, newkeybd);
    298                     flags[attached->id] |= XISlaveAttached;
    299                 }
    300             }
    301         }
    302     }
    303 
    304     for (int i = 0; i < currentMaxClients; i++)
    305         XIBarrierRemoveMasterDevice(clients[i], ptr->id);
    306 
    307     /* disable the remove the devices, XTest devices must be done first
    308        else the sprites they rely on will be destroyed  */
    309     DisableDevice(XTestptr, FALSE);
    310     DisableDevice(XTestkeybd, FALSE);
    311     DisableDevice(keybd, FALSE);
    312     DisableDevice(ptr, FALSE);
    313     flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
    314     flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
    315     flags[keybd->id] |= XIDeviceDisabled;
    316     flags[ptr->id] |= XIDeviceDisabled;
    317 
    318     flags[XTestptr->id] |= XISlaveRemoved;
    319     flags[XTestkeybd->id] |= XISlaveRemoved;
    320     flags[keybd->id] |= XIMasterRemoved;
    321     flags[ptr->id] |= XIMasterRemoved;
    322 
    323     RemoveDevice(XTestptr, FALSE);
    324     RemoveDevice(XTestkeybd, FALSE);
    325     RemoveDevice(keybd, FALSE);
    326     RemoveDevice(ptr, FALSE);
    327 
    328  unwind:
    329     return rc;
    330 }
    331 
    332 static int
    333 detach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES])
    334 {
    335     DeviceIntPtr dev;
    336     int rc;
    337 
    338     rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
    339     if (rc != Success)
    340         goto unwind;
    341 
    342     if (IsMaster(dev)) {
    343         client->errorValue = c->deviceid;
    344         rc = BadDevice;
    345         goto unwind;
    346     }
    347 
    348     /* Don't allow changes to XTest Devices, these are fixed */
    349     if (IsXTestDevice(dev, NULL)) {
    350         client->errorValue = c->deviceid;
    351         rc = BadDevice;
    352         goto unwind;
    353     }
    354 
    355     ReleaseButtonsAndKeys(dev);
    356     AttachDevice(client, dev, NULL);
    357     flags[dev->id] |= XISlaveDetached;
    358 
    359  unwind:
    360     return rc;
    361 }
    362 
    363 static int
    364 attach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES])
    365 {
    366     DeviceIntPtr dev;
    367     DeviceIntPtr newmaster;
    368     int rc;
    369 
    370     rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
    371     if (rc != Success)
    372         goto unwind;
    373 
    374     if (IsMaster(dev)) {
    375         client->errorValue = c->deviceid;
    376         rc = BadDevice;
    377         goto unwind;
    378     }
    379 
    380     /* Don't allow changes to XTest Devices, these are fixed */
    381     if (IsXTestDevice(dev, NULL)) {
    382         client->errorValue = c->deviceid;
    383         rc = BadDevice;
    384         goto unwind;
    385     }
    386 
    387     rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
    388     if (rc != Success)
    389         goto unwind;
    390     if (!IsMaster(newmaster)) {
    391         client->errorValue = c->new_master;
    392         rc = BadDevice;
    393         goto unwind;
    394     }
    395 
    396     if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
    397           (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) {
    398         rc = BadDevice;
    399         goto unwind;
    400     }
    401 
    402     ReleaseButtonsAndKeys(dev);
    403     AttachDevice(client, dev, newmaster);
    404     flags[dev->id] |= XISlaveAttached;
    405 
    406  unwind:
    407     return rc;
    408 }
    409 
    410 #define SWAPIF(cmd) if (client->swapped) { cmd; }
    411 
    412 int
    413 ProcXIChangeHierarchy(ClientPtr client)
    414 {
    415     xXIAnyHierarchyChangeInfo *any;
    416     size_t len;			/* length of data remaining in request */
    417     int rc = Success;
    418     int flags[MAXDEVICES] = { 0 };
    419 
    420     REQUEST(xXIChangeHierarchyReq);
    421     REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
    422 
    423     if (!stuff->num_changes)
    424         return rc;
    425 
    426     len = ((size_t)client->req_len << 2) - sizeof(xXIChangeHierarchyReq);
    427 
    428     any = (xXIAnyHierarchyChangeInfo *) &stuff[1];
    429     while (stuff->num_changes--) {
    430         if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
    431             rc = BadLength;
    432             goto unwind;
    433         }
    434 
    435         SWAPIF(swaps(&any->type));
    436         SWAPIF(swaps(&any->length));
    437 
    438         if (len < ((size_t)any->length << 2))
    439             return BadLength;
    440 
    441 #define CHANGE_SIZE_MATCH(type) \
    442     do { \
    443         if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
    444             rc = BadLength; \
    445             goto unwind; \
    446         } \
    447     } while(0)
    448 
    449         switch (any->type) {
    450         case XIAddMaster:
    451         {
    452             xXIAddMasterInfo *c = (xXIAddMasterInfo *) any;
    453 
    454             /* Variable length, due to appended name string */
    455             if (len < sizeof(xXIAddMasterInfo)) {
    456                 rc = BadLength;
    457                 goto unwind;
    458             }
    459             SWAPIF(swaps(&c->name_len));
    460             if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
    461                 rc = BadLength;
    462                 goto unwind;
    463             }
    464 
    465             rc = add_master(client, c, flags);
    466             if (rc != Success)
    467                 goto unwind;
    468         }
    469             break;
    470         case XIRemoveMaster:
    471         {
    472             xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
    473 
    474             CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
    475             rc = remove_master(client, r, flags);
    476             if (rc != Success)
    477                 goto unwind;
    478         }
    479             break;
    480         case XIDetachSlave:
    481         {
    482             xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
    483 
    484             CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
    485             rc = detach_slave(client, c, flags);
    486             if (rc != Success)
    487                 goto unwind;
    488         }
    489             break;
    490         case XIAttachSlave:
    491         {
    492             xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
    493 
    494             CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
    495             rc = attach_slave(client, c, flags);
    496             if (rc != Success)
    497                 goto unwind;
    498         }
    499             break;
    500         }
    501 
    502         len -= any->length * 4;
    503         any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
    504     }
    505 
    506  unwind:
    507 
    508     XISendDeviceHierarchyEvent(flags);
    509     return rc;
    510 }