Edit

IABSD.fr/xenocara/xserver/Xi/xiquerydevice.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2021-11-11 09:03:02
    Hash : e086cf5a
    Message : Update to xserver 21.1.0

  • xserver/Xi/xiquerydevice.c
  • /*
     * Copyright © 2009 Red Hat, Inc.
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     *
     * Authors: Peter Hutterer
     *
     */
    
    /**
     * @file Protocol handling for the XIQueryDevice request/reply.
     */
    
    #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #include "inputstr.h"
    #include <X11/X.h>
    #include <X11/Xatom.h>
    #include <X11/extensions/XI2proto.h>
    #include "xkbstr.h"
    #include "xkbsrv.h"
    #include "xserver-properties.h"
    #include "exevents.h"
    #include "xace.h"
    #include "inpututils.h"
    
    #include "exglobals.h"
    #include "privates.h"
    
    #include "xiquerydevice.h"
    
    static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
    static int
     ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info);
    static int SizeDeviceInfo(DeviceIntPtr dev);
    static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info);
    int _X_COLD
    SProcXIQueryDevice(ClientPtr client)
    {
        REQUEST(xXIQueryDeviceReq);
        REQUEST_SIZE_MATCH(xXIQueryDeviceReq);
    
        swaps(&stuff->length);
        swaps(&stuff->deviceid);
    
        return ProcXIQueryDevice(client);
    }
    
    int
    ProcXIQueryDevice(ClientPtr client)
    {
        xXIQueryDeviceReply rep;
        DeviceIntPtr dev = NULL;
        int rc = Success;
        int i = 0, len = 0;
        char *info, *ptr;
        Bool *skip = NULL;
    
        REQUEST(xXIQueryDeviceReq);
        REQUEST_SIZE_MATCH(xXIQueryDeviceReq);
    
        if (stuff->deviceid != XIAllDevices &&
            stuff->deviceid != XIAllMasterDevices) {
            rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess);
            if (rc != Success) {
                client->errorValue = stuff->deviceid;
                return rc;
            }
            len += SizeDeviceInfo(dev);
        }
        else {
            skip = calloc(sizeof(Bool), inputInfo.numDevices);
            if (!skip)
                return BadAlloc;
    
            for (dev = inputInfo.devices; dev; dev = dev->next, i++) {
                skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
                if (!skip[i])
                    len += SizeDeviceInfo(dev);
            }
    
            for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) {
                skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
                if (!skip[i])
                    len += SizeDeviceInfo(dev);
            }
        }
    
        info = calloc(1, len);
        if (!info) {
            free(skip);
            return BadAlloc;
        }
    
        rep = (xXIQueryDeviceReply) {
            .repType = X_Reply,
            .RepType = X_XIQueryDevice,
            .sequenceNumber = client->sequence,
            .length = len / 4,
            .num_devices = 0
        };
    
        ptr = info;
        if (dev) {
            len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
            if (client->swapped)
                SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
            info += len;
            rep.num_devices = 1;
        }
        else {
            i = 0;
            for (dev = inputInfo.devices; dev; dev = dev->next, i++) {
                if (!skip[i]) {
                    len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
                    if (client->swapped)
                        SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
                    info += len;
                    rep.num_devices++;
                }
            }
    
            for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) {
                if (!skip[i]) {
                    len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
                    if (client->swapped)
                        SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
                    info += len;
                    rep.num_devices++;
                }
            }
        }
    
        len = rep.length * 4;
        WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep);
        WriteToClient(client, len, ptr);
        free(ptr);
        free(skip);
        return rc;
    }
    
    void
    SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply * rep)
    {
        swaps(&rep->sequenceNumber);
        swapl(&rep->length);
        swaps(&rep->num_devices);
    
        /* Device info is already swapped, see ProcXIQueryDevice */
    
        WriteToClient(client, size, rep);
    }
    
    /**
     * @return Whether the device should be included in the returned list.
     */
    static Bool
    ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev)
    {
        /* if all devices are not being queried, only master devices are */
        if (deviceid == XIAllDevices || IsMaster(dev)) {
            int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
    
            if (rc == Success)
                return FALSE;
        }
        return TRUE;
    }
    
    /**
     * @return The number of bytes needed to store this device's xXIDeviceInfo
     * (and its classes).
     */
    static int
    SizeDeviceInfo(DeviceIntPtr dev)
    {
        int len = sizeof(xXIDeviceInfo);
    
        /* 4-padded name */
        len += pad_to_int32(strlen(dev->name));
    
        return len + SizeDeviceClasses(dev);
    
    }
    
    /*
     * @return The number of bytes needed to store this device's classes.
     */
    int
    SizeDeviceClasses(DeviceIntPtr dev)
    {
        int len = 0;
    
        if (dev->button) {
            len += sizeof(xXIButtonInfo);
            len += dev->button->numButtons * sizeof(Atom);
            len += pad_to_int32(bits_to_bytes(dev->button->numButtons));
        }
    
        if (dev->key) {
            XkbDescPtr xkb = dev->key->xkbInfo->desc;
    
            len += sizeof(xXIKeyInfo);
            len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t);
        }
    
        if (dev->valuator) {
            int i;
    
            len += (sizeof(xXIValuatorInfo)) * dev->valuator->numAxes;
    
            for (i = 0; i < dev->valuator->numAxes; i++) {
                if (dev->valuator->axes[i].scroll.type != SCROLL_TYPE_NONE)
                    len += sizeof(xXIScrollInfo);
            }
        }
    
        if (dev->touch)
            len += sizeof(xXITouchInfo);
    
        if (dev->gesture)
            len += sizeof(xXIGestureInfo);
    
        return len;
    }
    
    /**
     * Get pointers to button information areas holding button mask and labels.
     */
    static void
    ButtonInfoData(xXIButtonInfo *info, int *mask_words, unsigned char **mask,
                   Atom **atoms)
    {
        *mask_words = bytes_to_int32(bits_to_bytes(info->num_buttons));
        *mask = (unsigned char*) &info[1];
        *atoms = (Atom*) ((*mask) + (*mask_words) * 4);
    }
    
    /**
     * Write button information into info.
     * @return Number of bytes written into info.
     */
    int
    ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info, Bool reportState)
    {
        unsigned char *bits;
        Atom *labels;
        int mask_len;
        int i;
    
        if (!dev || !dev->button)
            return 0;
    
        info->type = ButtonClass;
        info->num_buttons = dev->button->numButtons;
        ButtonInfoData(info, &mask_len, &bits, &labels);
        info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
            info->num_buttons + mask_len;
        info->sourceid = dev->button->sourceid;
    
        memset(bits, 0, mask_len * 4);
    
        if (reportState)
            for (i = 0; i < dev->button->numButtons; i++)
                if (BitIsOn(dev->button->down, i))
                    SetBit(bits, i);
    
        memcpy(labels, dev->button->labels, dev->button->numButtons * sizeof(Atom));
    
        return info->length * 4;
    }
    
    static void
    SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info)
    {
        Atom *btn;
        int mask_len;
        unsigned char *mask;
    
        int i;
        ButtonInfoData(info, &mask_len, &mask, &btn);
    
        swaps(&info->type);
        swaps(&info->length);
        swaps(&info->sourceid);
    
        for (i = 0 ; i < info->num_buttons; i++, btn++)
            swapl(btn);
    
        swaps(&info->num_buttons);
    }
    
    /**
     * Write key information into info.
     * @return Number of bytes written into info.
     */
    int
    ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
    {
        int i;
        XkbDescPtr xkb = dev->key->xkbInfo->desc;
        uint32_t *kc;
    
        info->type = KeyClass;
        info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1;
        info->length = sizeof(xXIKeyInfo) / 4 + info->num_keycodes;
        info->sourceid = dev->key->sourceid;
    
        kc = (uint32_t *) &info[1];
        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++)
            *kc = i;
    
        return info->length * 4;
    }
    
    static void
    SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
    {
        uint32_t *key;
        int i;
    
        swaps(&info->type);
        swaps(&info->length);
        swaps(&info->sourceid);
    
        for (i = 0, key = (uint32_t *) &info[1]; i < info->num_keycodes;
             i++, key++)
            swapl(key);
    
        swaps(&info->num_keycodes);
    }
    
    /**
     * List axis information for the given axis.
     *
     * @return The number of bytes written into info.
     */
    int
    ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info, int axisnumber,
                     Bool reportState)
    {
        ValuatorClassPtr v = dev->valuator;
    
        info->type = ValuatorClass;
        info->length = sizeof(xXIValuatorInfo) / 4;
        info->label = v->axes[axisnumber].label;
        info->min.integral = v->axes[axisnumber].min_value;
        info->min.frac = 0;
        info->max.integral = v->axes[axisnumber].max_value;
        info->max.frac = 0;
        info->value = double_to_fp3232(v->axisVal[axisnumber]);
        info->resolution = v->axes[axisnumber].resolution;
        info->number = axisnumber;
        info->mode = valuator_get_mode(dev, axisnumber);
        info->sourceid = v->sourceid;
    
        if (!reportState)
            info->value = info->min;
    
        return info->length * 4;
    }
    
    static void
    SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info)
    {
        swaps(&info->type);
        swaps(&info->length);
        swapl(&info->label);
        swapl(&info->min.integral);
        swapl(&info->min.frac);
        swapl(&info->max.integral);
        swapl(&info->max.frac);
        swapl(&info->value.integral);
        swapl(&info->value.frac);
        swapl(&info->resolution);
        swaps(&info->number);
        swaps(&info->sourceid);
    }
    
    int
    ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info, int axisnumber)
    {
        ValuatorClassPtr v = dev->valuator;
        AxisInfoPtr axis = &v->axes[axisnumber];
    
        if (axis->scroll.type == SCROLL_TYPE_NONE)
            return 0;
    
        info->type = XIScrollClass;
        info->length = sizeof(xXIScrollInfo) / 4;
        info->number = axisnumber;
        switch (axis->scroll.type) {
        case SCROLL_TYPE_VERTICAL:
            info->scroll_type = XIScrollTypeVertical;
            break;
        case SCROLL_TYPE_HORIZONTAL:
            info->scroll_type = XIScrollTypeHorizontal;
            break;
        default:
            ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n",
                   axis->scroll.type);
            break;
        }
        info->increment = double_to_fp3232(axis->scroll.increment);
        info->sourceid = v->sourceid;
    
        info->flags = 0;
    
        if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE)
            info->flags |= XIScrollFlagNoEmulation;
        if (axis->scroll.flags & SCROLL_FLAG_PREFERRED)
            info->flags |= XIScrollFlagPreferred;
    
        return info->length * 4;
    }
    
    static void
    SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info)
    {
        swaps(&info->type);
        swaps(&info->length);
        swaps(&info->number);
        swaps(&info->sourceid);
        swaps(&info->scroll_type);
        swapl(&info->increment.integral);
        swapl(&info->increment.frac);
    }
    
    /**
     * List multitouch information
     *
     * @return The number of bytes written into info.
     */
    int
    ListTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
    {
        touch->type = XITouchClass;
        touch->length = sizeof(xXITouchInfo) >> 2;
        touch->sourceid = dev->touch->sourceid;
        touch->mode = dev->touch->mode;
        touch->num_touches = dev->touch->num_touches;
    
        return touch->length << 2;
    }
    
    static void
    SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
    {
        swaps(&touch->type);
        swaps(&touch->length);
        swaps(&touch->sourceid);
    }
    
    static Bool ShouldListGestureInfo(ClientPtr client)
    {
        /* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
         * properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
         * applications, we instead report Gesture device class only if the client advertised support
         * for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
         * and then a completely separate module within the client uses broken libxcb to call
         * XIQueryDevice.
         */
        XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
        if (pXIClient->major_version) {
            return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0;
        }
        return FALSE;
    }
    
    /**
     * List gesture information
     *
     * @return The number of bytes written into info.
     */
    static int
    ListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
    {
        gesture->type = XIGestureClass;
        gesture->length = sizeof(xXIGestureInfo) >> 2;
        gesture->sourceid = dev->gesture->sourceid;
        gesture->num_touches = dev->gesture->max_touches;
    
        return gesture->length << 2;
    }
    
    static void
    SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
    {
        swaps(&gesture->type);
        swaps(&gesture->length);
        swaps(&gesture->sourceid);
    }
    
    int
    GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment)
    {
        DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED);
        int use;
    
        if (IsMaster(dev)) {
            DeviceIntPtr paired = GetPairedDevice(dev);
    
            use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard;
            *attachment = (paired ? paired->id : 0);
        }
        else if (!IsFloating(dev)) {
            use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard;
            *attachment = master->id;
        }
        else
            use = XIFloatingSlave;
    
        return use;
    }
    
    /**
     * Write the info for device dev into the buffer pointed to by info.
     *
     * @return The number of bytes used.
     */
    static int
    ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info)
    {
        char *any = (char *) &info[1];
        int len = 0, total_len = 0;
    
        info->deviceid = dev->id;
        info->use = GetDeviceUse(dev, &info->attachment);
        info->num_classes = 0;
        info->name_len = strlen(dev->name);
        info->enabled = dev->enabled;
        total_len = sizeof(xXIDeviceInfo);
    
        len = pad_to_int32(info->name_len);
        memset(any, 0, len);
        strncpy(any, dev->name, info->name_len);
        any += len;
        total_len += len;
    
        total_len += ListDeviceClasses(client, dev, any, &info->num_classes);
        return total_len;
    }
    
    /**
     * Write the class info of the device into the memory pointed to by any, set
     * nclasses to the number of classes in total and return the number of bytes
     * written.
     */
    int
    ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
                      char *any, uint16_t * nclasses)
    {
        int total_len = 0;
        int len;
        int i;
        int rc;
    
        /* Check if the current device state should be suppressed */
        rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess);
    
        if (dev->button) {
            (*nclasses)++;
            len = ListButtonInfo(dev, (xXIButtonInfo *) any, rc == Success);
            any += len;
            total_len += len;
        }
    
        if (dev->key) {
            (*nclasses)++;
            len = ListKeyInfo(dev, (xXIKeyInfo *) any);
            any += len;
            total_len += len;
        }
    
        for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) {
            (*nclasses)++;
            len = ListValuatorInfo(dev, (xXIValuatorInfo *) any, i, rc == Success);
            any += len;
            total_len += len;
        }
    
        for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) {
            len = ListScrollInfo(dev, (xXIScrollInfo *) any, i);
            if (len)
                (*nclasses)++;
            any += len;
            total_len += len;
        }
    
        if (dev->touch) {
            (*nclasses)++;
            len = ListTouchInfo(dev, (xXITouchInfo *) any);
            any += len;
            total_len += len;
        }
    
        if (dev->gesture && ShouldListGestureInfo(client)) {
            (*nclasses)++;
            len = ListGestureInfo(dev, (xXIGestureInfo *) any);
            any += len;
            total_len += len;
        }
    
        return total_len;
    }
    
    static void
    SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
    {
        char *any = (char *) &info[1];
        int i;
    
        /* Skip over name */
        any += pad_to_int32(info->name_len);
    
        for (i = 0; i < info->num_classes; i++) {
            int len = ((xXIAnyInfo *) any)->length;
    
            switch (((xXIAnyInfo *) any)->type) {
            case XIButtonClass:
                SwapButtonInfo(dev, (xXIButtonInfo *) any);
                break;
            case XIKeyClass:
                SwapKeyInfo(dev, (xXIKeyInfo *) any);
                break;
            case XIValuatorClass:
                SwapValuatorInfo(dev, (xXIValuatorInfo *) any);
                break;
            case XIScrollClass:
                SwapScrollInfo(dev, (xXIScrollInfo *) any);
                break;
            case XITouchClass:
                SwapTouchInfo(dev, (xXITouchInfo *) any);
                break;
            case XIGestureClass:
                SwapGestureInfo(dev, (xXIGestureInfo *) any);
                break;
            }
    
            any += len * 4;
        }
    
        swaps(&info->deviceid);
        swaps(&info->use);
        swaps(&info->attachment);
        swaps(&info->num_classes);
        swaps(&info->name_len);
    
    }