1706f2543Smrg/*
2706f2543Smrg * Copyright 2007-2008 Peter Hutterer
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice (including the next
12706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the
13706f2543Smrg * Software.
14706f2543Smrg *
15706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21706f2543Smrg * DEALINGS IN THE SOFTWARE.
22706f2543Smrg *
23706f2543Smrg * Author: Peter Hutterer, University of South Australia, NICTA
24706f2543Smrg */
25706f2543Smrg
26706f2543Smrg/***********************************************************************
27706f2543Smrg *
28706f2543Smrg * Request to Warp the pointer location of an extension input device.
29706f2543Smrg *
30706f2543Smrg */
31706f2543Smrg
32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
33706f2543Smrg#include <dix-config.h>
34706f2543Smrg#endif
35706f2543Smrg
36706f2543Smrg#include <X11/X.h>	/* for inputstr.h    */
37706f2543Smrg#include <X11/Xproto.h>	/* Request macro     */
38706f2543Smrg#include "inputstr.h"	/* DeviceIntPtr      */
39706f2543Smrg#include "windowstr.h"	/* window structure  */
40706f2543Smrg#include "scrnintstr.h"	/* screen structure  */
41706f2543Smrg#include <X11/extensions/XI.h>
42706f2543Smrg#include <X11/extensions/XI2proto.h>
43706f2543Smrg#include "extnsionst.h"
44706f2543Smrg#include "exevents.h"
45706f2543Smrg#include "exglobals.h"
46706f2543Smrg#include "mipointer.h" /* for miPointerUpdateSprite */
47706f2543Smrg
48706f2543Smrg
49706f2543Smrg#include "xiwarppointer.h"
50706f2543Smrg/***********************************************************************
51706f2543Smrg *
52706f2543Smrg * This procedure allows a client to warp the pointer of a device.
53706f2543Smrg *
54706f2543Smrg */
55706f2543Smrg
56706f2543Smrgint
57706f2543SmrgSProcXIWarpPointer(ClientPtr client)
58706f2543Smrg{
59706f2543Smrg    char n;
60706f2543Smrg
61706f2543Smrg    REQUEST(xXIWarpPointerReq);
62706f2543Smrg    REQUEST_SIZE_MATCH(xXIWarpPointerReq);
63706f2543Smrg
64706f2543Smrg    swaps(&stuff->length, n);
65706f2543Smrg    swapl(&stuff->src_win, n);
66706f2543Smrg    swapl(&stuff->dst_win, n);
67706f2543Smrg    swapl(&stuff->src_x, n);
68706f2543Smrg    swapl(&stuff->src_y, n);
69706f2543Smrg    swaps(&stuff->src_width, n);
70706f2543Smrg    swaps(&stuff->src_height, n);
71706f2543Smrg    swapl(&stuff->dst_x, n);
72706f2543Smrg    swapl(&stuff->dst_y, n);
73706f2543Smrg    swaps(&stuff->deviceid, n);
74706f2543Smrg    return (ProcXIWarpPointer(client));
75706f2543Smrg}
76706f2543Smrg
77706f2543Smrgint
78706f2543SmrgProcXIWarpPointer(ClientPtr client)
79706f2543Smrg{
80706f2543Smrg    int rc;
81706f2543Smrg    int x, y;
82706f2543Smrg    WindowPtr dest = NULL;
83706f2543Smrg    DeviceIntPtr pDev;
84706f2543Smrg    SpritePtr pSprite;
85706f2543Smrg    ScreenPtr newScreen;
86706f2543Smrg    int src_x, src_y;
87706f2543Smrg    int dst_x, dst_y;
88706f2543Smrg
89706f2543Smrg    REQUEST(xXIWarpPointerReq);
90706f2543Smrg    REQUEST_SIZE_MATCH(xXIWarpPointerReq);
91706f2543Smrg
92706f2543Smrg    /* FIXME: panoramix stuff is missing, look at ProcWarpPointer */
93706f2543Smrg
94706f2543Smrg    rc = dixLookupDevice(&pDev, stuff->deviceid, client, DixWriteAccess);
95706f2543Smrg
96706f2543Smrg    if (rc != Success)
97706f2543Smrg    {
98706f2543Smrg        client->errorValue = stuff->deviceid;
99706f2543Smrg        return rc;
100706f2543Smrg    }
101706f2543Smrg
102706f2543Smrg    if ((!IsMaster(pDev) && pDev->u.master) ||
103706f2543Smrg        (IsMaster(pDev) && !IsPointerDevice(pDev)))
104706f2543Smrg    {
105706f2543Smrg        client->errorValue = stuff->deviceid;
106706f2543Smrg        return BadDevice;
107706f2543Smrg    }
108706f2543Smrg
109706f2543Smrg    if (stuff->dst_win != None)
110706f2543Smrg    {
111706f2543Smrg        rc = dixLookupWindow(&dest, stuff->dst_win, client, DixGetAttrAccess);
112706f2543Smrg        if (rc != Success)
113706f2543Smrg        {
114706f2543Smrg            client->errorValue = stuff->dst_win;
115706f2543Smrg            return rc;
116706f2543Smrg        }
117706f2543Smrg    }
118706f2543Smrg
119706f2543Smrg    pSprite = pDev->spriteInfo->sprite;
120706f2543Smrg    x = pSprite->hotPhys.x;
121706f2543Smrg    y = pSprite->hotPhys.y;
122706f2543Smrg
123706f2543Smrg    src_x = stuff->src_x / (double)(1 << 16);
124706f2543Smrg    src_y = stuff->src_y / (double)(1 << 16);
125706f2543Smrg    dst_x = stuff->dst_x / (double)(1 << 16);
126706f2543Smrg    dst_y = stuff->dst_y / (double)(1 << 16);
127706f2543Smrg
128706f2543Smrg    if (stuff->src_win != None)
129706f2543Smrg    {
130706f2543Smrg        int winX, winY;
131706f2543Smrg        WindowPtr src;
132706f2543Smrg
133706f2543Smrg        rc = dixLookupWindow(&src, stuff->src_win, client, DixGetAttrAccess);
134706f2543Smrg        if (rc != Success)
135706f2543Smrg        {
136706f2543Smrg            client->errorValue = stuff->src_win;
137706f2543Smrg            return rc;
138706f2543Smrg        }
139706f2543Smrg
140706f2543Smrg        winX = src->drawable.x;
141706f2543Smrg        winY = src->drawable.y;
142706f2543Smrg        if (src->drawable.pScreen != pSprite->hotPhys.pScreen ||
143706f2543Smrg                x < winX + src_x ||
144706f2543Smrg                y < winY + src_y ||
145706f2543Smrg                (stuff->src_width != 0 &&
146706f2543Smrg                 winX + src_x + (int)stuff->src_width < 0) ||
147706f2543Smrg                (stuff->src_height != 0 &&
148706f2543Smrg                 winY + src_y + (int)stuff->src_height < y) ||
149706f2543Smrg                !PointInWindowIsVisible(src, x, y))
150706f2543Smrg            return Success;
151706f2543Smrg    }
152706f2543Smrg
153706f2543Smrg    if (dest)
154706f2543Smrg    {
155706f2543Smrg        x = dest->drawable.x;
156706f2543Smrg        y = dest->drawable.y;
157706f2543Smrg        newScreen = dest->drawable.pScreen;
158706f2543Smrg    } else
159706f2543Smrg        newScreen = pSprite->hotPhys.pScreen;
160706f2543Smrg
161706f2543Smrg    x += dst_x;
162706f2543Smrg    y += dst_y;
163706f2543Smrg
164706f2543Smrg    if (x < 0)
165706f2543Smrg        x = 0;
166706f2543Smrg    else if (x > newScreen->width)
167706f2543Smrg        x = newScreen->width - 1;
168706f2543Smrg
169706f2543Smrg    if (y < 0)
170706f2543Smrg        y = 0;
171706f2543Smrg    else if (y > newScreen->height)
172706f2543Smrg        y = newScreen->height - 1;
173706f2543Smrg
174706f2543Smrg    if (newScreen == pSprite->hotPhys.pScreen)
175706f2543Smrg    {
176706f2543Smrg        if (x < pSprite->physLimits.x1)
177706f2543Smrg            x = pSprite->physLimits.x1;
178706f2543Smrg        else if (x >= pSprite->physLimits.x2)
179706f2543Smrg            x = pSprite->physLimits.x2 - 1;
180706f2543Smrg
181706f2543Smrg        if (y < pSprite->physLimits.y1)
182706f2543Smrg            y = pSprite->physLimits.y1;
183706f2543Smrg        else if (y >= pSprite->physLimits.y2)
184706f2543Smrg            y = pSprite->physLimits.y2 - 1;
185706f2543Smrg
186706f2543Smrg        if (pSprite->hotShape)
187706f2543Smrg            ConfineToShape(pDev, pSprite->hotShape, &x, &y);
188706f2543Smrg        (*newScreen->SetCursorPosition)(pDev, newScreen, x, y, TRUE);
189706f2543Smrg    } else if (!PointerConfinedToScreen(pDev))
190706f2543Smrg    {
191706f2543Smrg        NewCurrentScreen(pDev, newScreen, x, y);
192706f2543Smrg    }
193706f2543Smrg
194706f2543Smrg    /* if we don't update the device, we get a jump next time it moves */
195706f2543Smrg    pDev->last.valuators[0] = x;
196706f2543Smrg    pDev->last.valuators[1] = y;
197706f2543Smrg    pDev->last.remainder[0] = 0;
198706f2543Smrg    pDev->last.remainder[1] = 0;
199706f2543Smrg    miPointerUpdateSprite(pDev);
200706f2543Smrg
201706f2543Smrg    /* FIXME: XWarpPointer is supposed to generate an event. It doesn't do it
202706f2543Smrg       here though. */
203706f2543Smrg    return Success;
204706f2543Smrg}
205706f2543Smrg
206