16747b715Smrg/*
26747b715Smrg * Copyright 2007-2008 Peter Hutterer
36747b715Smrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
106747b715Smrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216747b715Smrg * DEALINGS IN THE SOFTWARE.
226747b715Smrg *
236747b715Smrg * Author: Peter Hutterer, University of South Australia, NICTA
246747b715Smrg */
256747b715Smrg
266747b715Smrg/***********************************************************************
276747b715Smrg *
286747b715Smrg * Request to query the pointer location of an extension input device.
296747b715Smrg *
306747b715Smrg */
316747b715Smrg
326747b715Smrg#ifdef HAVE_DIX_CONFIG_H
336747b715Smrg#include <dix-config.h>
346747b715Smrg#endif
356747b715Smrg
36f7df2e56Smrg#include <X11/X.h>              /* for inputstr.h    */
37f7df2e56Smrg#include <X11/Xproto.h>         /* Request macro     */
38f7df2e56Smrg#include "inputstr.h"           /* DeviceIntPtr      */
39f7df2e56Smrg#include "windowstr.h"          /* window structure  */
406747b715Smrg#include <X11/extensions/XI.h>
416747b715Smrg#include <X11/extensions/XI2proto.h>
426747b715Smrg#include "extnsionst.h"
436747b715Smrg#include "exevents.h"
446747b715Smrg#include "exglobals.h"
456747b715Smrg#include "eventconvert.h"
466747b715Smrg#include "scrnintstr.h"
476747b715Smrg#include "xkbsrv.h"
486747b715Smrg
496747b715Smrg#ifdef PANORAMIX
506747b715Smrg#include "panoramiXsrv.h"
516747b715Smrg#endif
526747b715Smrg
53f7df2e56Smrg#include "inpututils.h"
546747b715Smrg#include "xiquerypointer.h"
556747b715Smrg
566747b715Smrg/***********************************************************************
576747b715Smrg *
586747b715Smrg * This procedure allows a client to query the pointer of a device.
596747b715Smrg *
606747b715Smrg */
616747b715Smrg
627e31ba66Smrgint _X_COLD
636747b715SmrgSProcXIQueryPointer(ClientPtr client)
646747b715Smrg{
656747b715Smrg    REQUEST(xXIQueryPointerReq);
660b0d8713Smrg    REQUEST_SIZE_MATCH(xXIQueryPointerReq);
670b0d8713Smrg
68f7df2e56Smrg    swaps(&stuff->length);
69f7df2e56Smrg    swaps(&stuff->deviceid);
70f7df2e56Smrg    swapl(&stuff->win);
716747b715Smrg    return (ProcXIQueryPointer(client));
726747b715Smrg}
736747b715Smrg
746747b715Smrgint
756747b715SmrgProcXIQueryPointer(ClientPtr client)
766747b715Smrg{
776747b715Smrg    int rc;
786747b715Smrg    xXIQueryPointerReply rep;
796747b715Smrg    DeviceIntPtr pDev, kbd;
806747b715Smrg    WindowPtr pWin, t;
816747b715Smrg    SpritePtr pSprite;
826747b715Smrg    XkbStatePtr state;
836747b715Smrg    char *buttons = NULL;
84f7df2e56Smrg    int buttons_size = 0;       /* size of buttons array */
85f7df2e56Smrg    XIClientPtr xi_client;
86f7df2e56Smrg    Bool have_xi22 = FALSE;
876747b715Smrg
886747b715Smrg    REQUEST(xXIQueryPointerReq);
896747b715Smrg    REQUEST_SIZE_MATCH(xXIQueryPointerReq);
906747b715Smrg
91f7df2e56Smrg    /* Check if client is compliant with XInput 2.2 or later. Earlier clients
92f7df2e56Smrg     * do not know about touches, so we must report emulated button presses. 2.2
93f7df2e56Smrg     * and later clients are aware of touches, so we don't include emulated
94f7df2e56Smrg     * button presses in the reply. */
95f7df2e56Smrg    xi_client = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
96f7df2e56Smrg    if (version_compare(xi_client->major_version,
97f7df2e56Smrg                        xi_client->minor_version, 2, 2) >= 0)
98f7df2e56Smrg        have_xi22 = TRUE;
99f7df2e56Smrg
1006747b715Smrg    rc = dixLookupDevice(&pDev, stuff->deviceid, client, DixReadAccess);
101f7df2e56Smrg    if (rc != Success) {
1026747b715Smrg        client->errorValue = stuff->deviceid;
1036747b715Smrg        return rc;
1046747b715Smrg    }
1056747b715Smrg
106f7df2e56Smrg    if (pDev->valuator == NULL || IsKeyboardDevice(pDev) || (!IsMaster(pDev) && !IsFloating(pDev))) {   /* no attached devices */
1076747b715Smrg        client->errorValue = stuff->deviceid;
1086747b715Smrg        return BadDevice;
1096747b715Smrg    }
1106747b715Smrg
1116747b715Smrg    rc = dixLookupWindow(&pWin, stuff->win, client, DixGetAttrAccess);
112f7df2e56Smrg    if (rc != Success) {
1137e31ba66Smrg        client->errorValue = stuff->win;
1147e31ba66Smrg        return rc;
1156747b715Smrg    }
1166747b715Smrg
1176747b715Smrg    if (pDev->valuator->motionHintWindow)
1186747b715Smrg        MaybeStopHint(pDev, client);
1196747b715Smrg
1206747b715Smrg    if (IsMaster(pDev))
121f7df2e56Smrg        kbd = GetMaster(pDev, MASTER_KEYBOARD);
1226747b715Smrg    else
1236747b715Smrg        kbd = (pDev->key) ? pDev : NULL;
1246747b715Smrg
1256747b715Smrg    pSprite = pDev->spriteInfo->sprite;
1266747b715Smrg
127f7df2e56Smrg    rep = (xXIQueryPointerReply) {
128f7df2e56Smrg        .repType = X_Reply,
129f7df2e56Smrg        .RepType = X_XIQueryPointer,
130f7df2e56Smrg        .sequenceNumber = client->sequence,
131f7df2e56Smrg        .length = 6,
132f7df2e56Smrg        .root = (GetCurrentRootWindow(pDev))->drawable.id,
133f7df2e56Smrg        .root_x = double_to_fp1616(pSprite->hot.x),
134f7df2e56Smrg        .root_y = double_to_fp1616(pSprite->hot.y),
135f7df2e56Smrg        .child = None
136f7df2e56Smrg    };
137f7df2e56Smrg
138f7df2e56Smrg    if (kbd) {
1399ace9065Smrg        state = &kbd->key->xkbInfo->state;
1406747b715Smrg        rep.mods.base_mods = state->base_mods;
1416747b715Smrg        rep.mods.latched_mods = state->latched_mods;
1426747b715Smrg        rep.mods.locked_mods = state->locked_mods;
1436747b715Smrg
1446747b715Smrg        rep.group.base_group = state->base_group;
1456747b715Smrg        rep.group.latched_group = state->latched_group;
1466747b715Smrg        rep.group.locked_group = state->locked_group;
1476747b715Smrg    }
1486747b715Smrg
149f7df2e56Smrg    if (pDev->button) {
150f7df2e56Smrg        int i;
151f7df2e56Smrg
152875c6e4fSmrg        rep.buttons_len = bytes_to_int32(bits_to_bytes(256)); /* button map up to 255 */
1536747b715Smrg        rep.length += rep.buttons_len;
154f7df2e56Smrg        buttons = calloc(rep.buttons_len, 4);
1556747b715Smrg        if (!buttons)
1566747b715Smrg            return BadAlloc;
157f7df2e56Smrg        buttons_size = rep.buttons_len * 4;
1586747b715Smrg
159f7df2e56Smrg        for (i = 1; i < pDev->button->numButtons; i++)
1606747b715Smrg            if (BitIsOn(pDev->button->down, i))
161f7df2e56Smrg                SetBit(buttons, pDev->button->map[i]);
162f7df2e56Smrg
163f7df2e56Smrg        if (!have_xi22 && pDev->touch && pDev->touch->buttonsDown > 0)
164f7df2e56Smrg            SetBit(buttons, pDev->button->map[1]);
165f7df2e56Smrg    }
166f7df2e56Smrg    else
1676747b715Smrg        rep.buttons_len = 0;
1686747b715Smrg
169f7df2e56Smrg    if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
1706747b715Smrg        rep.same_screen = xTrue;
171f7df2e56Smrg        rep.win_x = double_to_fp1616(pSprite->hot.x - pWin->drawable.x);
172f7df2e56Smrg        rep.win_y = double_to_fp1616(pSprite->hot.y - pWin->drawable.y);
1736747b715Smrg        for (t = pSprite->win; t; t = t->parent)
174f7df2e56Smrg            if (t->parent == pWin) {
1756747b715Smrg                rep.child = t->drawable.id;
1766747b715Smrg                break;
1776747b715Smrg            }
178f7df2e56Smrg    }
179f7df2e56Smrg    else {
1806747b715Smrg        rep.same_screen = xFalse;
1816747b715Smrg        rep.win_x = 0;
1826747b715Smrg        rep.win_y = 0;
1836747b715Smrg    }
1846747b715Smrg
1856747b715Smrg#ifdef PANORAMIX
186f7df2e56Smrg    if (!noPanoramiXExtension) {
187f7df2e56Smrg        rep.root_x += double_to_fp1616(screenInfo.screens[0]->x);
188f7df2e56Smrg        rep.root_y += double_to_fp1616(screenInfo.screens[0]->y);
189f7df2e56Smrg        if (stuff->win == rep.root) {
190f7df2e56Smrg            rep.win_x += double_to_fp1616(screenInfo.screens[0]->x);
191f7df2e56Smrg            rep.win_y += double_to_fp1616(screenInfo.screens[0]->y);
1926747b715Smrg        }
1936747b715Smrg    }
1946747b715Smrg#endif
1956747b715Smrg
1966747b715Smrg    WriteReplyToClient(client, sizeof(xXIQueryPointerReply), &rep);
1976747b715Smrg    if (buttons)
1986747b715Smrg        WriteToClient(client, buttons_size, buttons);
1996747b715Smrg
2006747b715Smrg    free(buttons);
2016747b715Smrg
2026747b715Smrg    return Success;
2036747b715Smrg}
2046747b715Smrg
2056747b715Smrg/***********************************************************************
2066747b715Smrg *
2076747b715Smrg * This procedure writes the reply for the XIQueryPointer function,
2086747b715Smrg * if the client and server have a different byte ordering.
2096747b715Smrg *
2106747b715Smrg */
2116747b715Smrg
2126747b715Smrgvoid
213f7df2e56SmrgSRepXIQueryPointer(ClientPtr client, int size, xXIQueryPointerReply * rep)
2146747b715Smrg{
215f7df2e56Smrg    swaps(&rep->sequenceNumber);
216f7df2e56Smrg    swapl(&rep->length);
217f7df2e56Smrg    swapl(&rep->root);
218f7df2e56Smrg    swapl(&rep->child);
219f7df2e56Smrg    swapl(&rep->root_x);
220f7df2e56Smrg    swapl(&rep->root_y);
221f7df2e56Smrg    swapl(&rep->win_x);
222f7df2e56Smrg    swapl(&rep->win_y);
223f7df2e56Smrg    swaps(&rep->buttons_len);
224f7df2e56Smrg
225f7df2e56Smrg    WriteToClient(client, size, rep);
2266747b715Smrg}
227