| 1 | /* |
| 2 | * Copyright 2007-2008 Peter Hutterer |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice (including the next |
| 12 | * paragraph) shall be included in all copies or substantial portions of the |
| 13 | * Software. |
| 14 | * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 21 | * DEALINGS IN THE SOFTWARE. |
| 22 | * |
| 23 | * Author: Peter Hutterer, University of South Australia, NICTA |
| 24 | */ |
| 25 | |
| 26 | /*********************************************************************** |
| 27 | * |
| 28 | * Request to query the pointer location of an extension input device. |
| 29 | * |
| 30 | */ |
| 31 | |
| 32 | #ifdef HAVE_DIX_CONFIG_H |
| 33 | #include <dix-config.h> |
| 34 | #endif |
| 35 | |
| 36 | #include <X11/X.h> /* for inputstr.h */ |
| 37 | #include <X11/Xproto.h> /* Request macro */ |
| 38 | #include "inputstr.h" /* DeviceIntPtr */ |
| 39 | #include "windowstr.h" /* window structure */ |
| 40 | #include <X11/extensions/XI.h> |
| 41 | #include <X11/extensions/XI2proto.h> |
| 42 | #include "extnsionst.h" |
| 43 | #include "exevents.h" |
| 44 | #include "exglobals.h" |
| 45 | #include "eventconvert.h" |
| 46 | #include "scrnintstr.h" |
| 47 | #include "xkbsrv.h" |
| 48 | |
| 49 | #ifdef PANORAMIX |
| 50 | #include "panoramiXsrv.h" |
| 51 | #endif |
| 52 | |
| 53 | #include "inpututils.h" |
| 54 | #include "xiquerypointer.h" |
| 55 | |
| 56 | /*********************************************************************** |
| 57 | * |
| 58 | * This procedure allows a client to query the pointer of a device. |
| 59 | * |
| 60 | */ |
| 61 | |
| 62 | int |
| 63 | SProcXIQueryPointer(ClientPtr client) |
| 64 | { |
| 65 | REQUEST(xXIQueryPointerReq); |
| 66 | swaps(&stuff->length); |
| 67 | swaps(&stuff->deviceid); |
| 68 | swapl(&stuff->win); |
| 69 | return (ProcXIQueryPointer(client)); |
| 70 | } |
| 71 | |
| 72 | int |
| 73 | ProcXIQueryPointer(ClientPtr client) |
| 74 | { |
| 75 | int rc; |
| 76 | xXIQueryPointerReply rep; |
| 77 | DeviceIntPtr pDev, kbd; |
| 78 | WindowPtr pWin, t; |
| 79 | SpritePtr pSprite; |
| 80 | XkbStatePtr state; |
| 81 | char *buttons = NULL; |
| 82 | int buttons_size = 0; /* size of buttons array */ |
| 83 | XIClientPtr xi_client; |
| 84 | Bool have_xi22 = FALSE; |
| 85 | |
| 86 | REQUEST(xXIQueryPointerReq); |
| 87 | REQUEST_SIZE_MATCH(xXIQueryPointerReq); |
| 88 | |
| 89 | /* Check if client is compliant with XInput 2.2 or later. Earlier clients |
| 90 | * do not know about touches, so we must report emulated button presses. 2.2 |
| 91 | * and later clients are aware of touches, so we don't include emulated |
| 92 | * button presses in the reply. */ |
| 93 | xi_client = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey); |
| 94 | if (version_compare(xi_client->major_version, |
| 95 | xi_client->minor_version, 2, 2) >= 0) |
| 96 | have_xi22 = TRUE; |
| 97 | |
| 98 | rc = dixLookupDevice(&pDev, stuff->deviceid, client, DixReadAccess); |
| 99 | if (rc != Success) { |
| 100 | client->errorValue = stuff->deviceid; |
| 101 | return rc; |
| 102 | } |
| 103 | |
| 104 | if (pDev->valuator == NULL || IsKeyboardDevice(pDev) || (!IsMaster(pDev) && !IsFloating(pDev))) { /* no attached devices */ |
| 105 | client->errorValue = stuff->deviceid; |
| 106 | return BadDevice; |
| 107 | } |
| 108 | |
| 109 | rc = dixLookupWindow(&pWin, stuff->win, client, DixGetAttrAccess); |
| 110 | if (rc != Success) { |
| 111 | SendErrorToClient(client, IReqCode, X_XIQueryPointer, stuff->win, rc); |
| 112 | return Success; |
| 113 | } |
| 114 | |
| 115 | if (pDev->valuator->motionHintWindow) |
| 116 | MaybeStopHint(pDev, client); |
| 117 | |
| 118 | if (IsMaster(pDev)) |
| 119 | kbd = GetMaster(pDev, MASTER_KEYBOARD); |
| 120 | else |
| 121 | kbd = (pDev->key) ? pDev : NULL; |
| 122 | |
| 123 | pSprite = pDev->spriteInfo->sprite; |
| 124 | |
| 125 | rep = (xXIQueryPointerReply) { |
| 126 | .repType = X_Reply, |
| 127 | .RepType = X_XIQueryPointer, |
| 128 | .sequenceNumber = client->sequence, |
| 129 | .length = 6, |
| 130 | .root = (GetCurrentRootWindow(pDev))->drawable.id, |
| 131 | .root_x = double_to_fp1616(pSprite->hot.x), |
| 132 | .root_y = double_to_fp1616(pSprite->hot.y), |
| 133 | .child = None |
| 134 | }; |
| 135 | |
| 136 | if (kbd) { |
| 137 | state = &kbd->key->xkbInfo->state; |
| 138 | rep.mods.base_mods = state->base_mods; |
| 139 | rep.mods.latched_mods = state->latched_mods; |
| 140 | rep.mods.locked_mods = state->locked_mods; |
| 141 | |
| 142 | rep.group.base_group = state->base_group; |
| 143 | rep.group.latched_group = state->latched_group; |
| 144 | rep.group.locked_group = state->locked_group; |
| 145 | } |
| 146 | |
| 147 | if (pDev->button) { |
| 148 | int i; |
| 149 | |
| 150 | rep.buttons_len = |
| 151 | bytes_to_int32(bits_to_bytes(pDev->button->numButtons)); |
| 152 | rep.length += rep.buttons_len; |
| 153 | buttons_size = rep.buttons_len * 4; |
| 154 | buttons = calloc(1, buttons_size); |
| 155 | if (!buttons) |
| 156 | return BadAlloc; |
| 157 | |
| 158 | for (i = 1; i < pDev->button->numButtons; i++) |
| 159 | if (BitIsOn(pDev->button->down, i)) |
| 160 | SetBit(buttons, pDev->button->map[i]); |
| 161 | |
| 162 | if (!have_xi22 && pDev->touch && pDev->touch->buttonsDown > 0) |
| 163 | SetBit(buttons, pDev->button->map[1]); |
| 164 | } |
| 165 | else |
| 166 | rep.buttons_len = 0; |
| 167 | |
| 168 | if (pSprite->hot.pScreen == pWin->drawable.pScreen) { |
| 169 | rep.same_screen = xTrue; |
| 170 | rep.win_x = double_to_fp1616(pSprite->hot.x - pWin->drawable.x); |
| 171 | rep.win_y = double_to_fp1616(pSprite->hot.y - pWin->drawable.y); |
| 172 | for (t = pSprite->win; t; t = t->parent) |
| 173 | if (t->parent == pWin) { |
| 174 | rep.child = t->drawable.id; |
| 175 | break; |
| 176 | } |
| 177 | } |
| 178 | else { |
| 179 | rep.same_screen = xFalse; |
| 180 | rep.win_x = 0; |
| 181 | rep.win_y = 0; |
| 182 | } |
| 183 | |
| 184 | #ifdef PANORAMIX |
| 185 | if (!noPanoramiXExtension) { |
| 186 | rep.root_x += double_to_fp1616(screenInfo.screens[0]->x); |
| 187 | rep.root_y += double_to_fp1616(screenInfo.screens[0]->y); |
| 188 | if (stuff->win == rep.root) { |
| 189 | rep.win_x += double_to_fp1616(screenInfo.screens[0]->x); |
| 190 | rep.win_y += double_to_fp1616(screenInfo.screens[0]->y); |
| 191 | } |
| 192 | } |
| 193 | #endif |
| 194 | |
| 195 | WriteReplyToClient(client, sizeof(xXIQueryPointerReply), &rep); |
| 196 | if (buttons) |
| 197 | WriteToClient(client, buttons_size, buttons); |
| 198 | |
| 199 | free(buttons); |
| 200 | |
| 201 | return Success; |
| 202 | } |
| 203 | |
| 204 | /*********************************************************************** |
| 205 | * |
| 206 | * This procedure writes the reply for the XIQueryPointer function, |
| 207 | * if the client and server have a different byte ordering. |
| 208 | * |
| 209 | */ |
| 210 | |
| 211 | void |
| 212 | SRepXIQueryPointer(ClientPtr client, int size, xXIQueryPointerReply * rep) |
| 213 | { |
| 214 | swaps(&rep->sequenceNumber); |
| 215 | swapl(&rep->length); |
| 216 | swapl(&rep->root); |
| 217 | swapl(&rep->child); |
| 218 | swapl(&rep->root_x); |
| 219 | swapl(&rep->root_y); |
| 220 | swapl(&rep->win_x); |
| 221 | swapl(&rep->win_y); |
| 222 | swaps(&rep->buttons_len); |
| 223 | |
| 224 | WriteToClient(client, size, rep); |
| 225 | } |