geext.c revision 4642e01f
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#ifdef HAVE_DIX_CONFIG_H 27#include <dix-config.h> 28#endif 29#include "windowstr.h" 30#include <X11/extensions/ge.h> 31#include "registry.h" 32 33#include "geint.h" 34#include "geext.h" 35 36/* Currently supported XGE version */ 37#define SERVER_GE_MAJOR 1 38#define SERVER_GE_MINOR 0 39 40#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) 41 42int GEEventBase; 43int GEErrorBase; 44static int GEClientPrivateKeyIndex; 45DevPrivateKey GEClientPrivateKey = &GEClientPrivateKeyIndex; 46int GEEventType; /* The opcode for all GenericEvents will have. */ 47 48int RT_GECLIENT = 0; 49 50 51GEExtension GEExtensions[MAXEXTENSIONS]; 52 53/* Major available requests */ 54static const int version_requests[] = { 55 X_GEQueryVersion, /* before client sends QueryVersion */ 56 X_GEQueryVersion, /* must be set to last request in version 1 */ 57}; 58 59/* Forward declarations */ 60static void SGEGenericEvent(xEvent* from, xEvent* to); 61static void GERecalculateWinMask(WindowPtr pWin); 62 63#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) 64 65/************************************************************/ 66/* request handlers */ 67/************************************************************/ 68 69static int 70ProcGEQueryVersion(ClientPtr client) 71{ 72 int n; 73 GEClientInfoPtr pGEClient = GEGetClient(client); 74 xGEQueryVersionReply rep; 75 REQUEST(xGEQueryVersionReq); 76 77 REQUEST_SIZE_MATCH(xGEQueryVersionReq); 78 79 rep.repType = X_Reply; 80 rep.RepType = X_GEQueryVersion; 81 rep.length = 0; 82 rep.sequenceNumber = client->sequence; 83 84 /* return the supported version by the server */ 85 rep.majorVersion = SERVER_GE_MAJOR; 86 rep.minorVersion = SERVER_GE_MINOR; 87 88 /* Remember version the client requested */ 89 pGEClient->major_version = stuff->majorVersion; 90 pGEClient->minor_version = stuff->minorVersion; 91 92 if (client->swapped) 93 { 94 swaps(&rep.sequenceNumber, n); 95 swapl(&rep.length, n); 96 swaps(&rep.majorVersion, n); 97 swaps(&rep.minorVersion, n); 98 } 99 100 WriteToClient(client, sizeof(xGEQueryVersionReply), (char*)&rep); 101 return(client->noClientException); 102} 103 104int (*ProcGEVector[GENumberRequests])(ClientPtr) = { 105 /* Version 1.0 */ 106 ProcGEQueryVersion 107}; 108 109/************************************************************/ 110/* swapped request handlers */ 111/************************************************************/ 112static int 113SProcGEQueryVersion(ClientPtr client) 114{ 115 int n; 116 REQUEST(xGEQueryVersionReq); 117 118 swaps(&stuff->length, n); 119 REQUEST_SIZE_MATCH(xGEQueryVersionReq); 120 swaps(&stuff->majorVersion, n); 121 swaps(&stuff->minorVersion, n); 122 return(*ProcGEVector[stuff->ReqType])(client); 123} 124 125int (*SProcGEVector[GENumberRequests])(ClientPtr) = { 126 /* Version 1.0 */ 127 SProcGEQueryVersion 128}; 129 130 131/************************************************************/ 132/* callbacks */ 133/************************************************************/ 134 135/* dispatch requests */ 136static int 137ProcGEDispatch(ClientPtr client) 138{ 139 GEClientInfoPtr pGEClient = GEGetClient(client); 140 REQUEST(xGEReq); 141 142 if (pGEClient->major_version >= NUM_VERSION_REQUESTS) 143 return BadRequest; 144 if (stuff->ReqType > version_requests[pGEClient->major_version]) 145 return BadRequest; 146 147 return (ProcGEVector[stuff->ReqType])(client); 148} 149 150/* dispatch swapped requests */ 151static int 152SProcGEDispatch(ClientPtr client) 153{ 154 REQUEST(xGEReq); 155 if (stuff->ReqType >= GENumberRequests) 156 return BadRequest; 157 return (*SProcGEVector[stuff->ReqType])(client); 158} 159 160/** 161 * Called when a new client inits a connection to the X server. 162 * 163 * We alloc a simple struct to store the client's major/minor version. Can be 164 * used in the furture for versioning support. 165 */ 166static void 167GEClientCallback(CallbackListPtr *list, 168 pointer closure, 169 pointer data) 170{ 171 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; 172 ClientPtr pClient = clientinfo->client; 173 GEClientInfoPtr pGEClient = GEGetClient(pClient); 174 175 if (pGEClient == NULL) 176 { 177 pGEClient = xcalloc(1, sizeof(GEClientInfoRec)); 178 dixSetPrivate(&pClient->devPrivates, GEClientPrivateKey, pGEClient); 179 } 180 181 pGEClient->major_version = 0; 182 pGEClient->minor_version = 0; 183} 184 185/* Reset extension. Called on server shutdown. */ 186static void 187GEResetProc(ExtensionEntry *extEntry) 188{ 189 DeleteCallback(&ClientStateCallback, GEClientCallback, 0); 190 EventSwapVector[GenericEvent] = NotImplemented; 191 192 GEEventBase = 0; 193 GEErrorBase = 0; 194 GEEventType = 0; 195} 196 197/* Calls the registered event swap function for the extension. 198 * 199 * Each extension can register a swap function to handle GenericEvents being 200 * swapped properly. The server calls SGEGenericEvent() before the event is 201 * written on the wire, this one calls the registered swap function to do the 202 * work. 203 */ 204static void 205SGEGenericEvent(xEvent* from, xEvent* to) 206{ 207 xGenericEvent* gefrom = (xGenericEvent*)from; 208 xGenericEvent* geto = (xGenericEvent*)to; 209 210 if (gefrom->extension > MAXEXTENSIONS) 211 { 212 ErrorF("GE: Invalid extension offset for event.\n"); 213 return; 214 } 215 216 if (GEExtensions[gefrom->extension & 0x7F].evswap) 217 GEExtensions[gefrom->extension & 0x7F].evswap(gefrom, geto); 218} 219 220/** 221 * Resource callback, invoked when the client disconnects and the associated 222 * GE masks must be destroyed. 223 */ 224static int 225GEClientGone(WindowPtr pWin, XID id) 226{ 227 GenericClientMasksPtr gclmask; 228 GenericMaskPtr gmask, prev = NULL; 229 230 if (!pWin || !pWin->optional) 231 return Success; 232 233 gclmask = pWin->optional->geMasks; 234 for (gmask = gclmask->geClients; gmask; gmask = gmask->next) 235 { 236 if (gmask->resource == id) 237 { 238 if (prev) 239 { 240 prev->next = gmask->next; 241 xfree(gmask); 242 } else { 243 gclmask->geClients = NULL; 244 CheckWindowOptionalNeed(pWin); 245 GERecalculateWinMask(pWin); 246 xfree(gmask); 247 } 248 return Success; 249 } 250 prev = gmask; 251 } 252 253 FatalError("Client not a GE client"); 254 return BadImplementation; 255} 256 257/* Init extension, register at server. 258 * Since other extensions may rely on XGE (XInput does already), it is a good 259 * idea to init XGE first, before any other extension. 260 */ 261void 262GEExtensionInit(void) 263{ 264 ExtensionEntry *extEntry; 265 266 if(!AddCallback(&ClientStateCallback, GEClientCallback, 0)) 267 { 268 FatalError("GEExtensionInit: register client callback failed.\n"); 269 } 270 271 if((extEntry = AddExtension(GE_NAME, 272 GENumberEvents, GENumberErrors, 273 ProcGEDispatch, SProcGEDispatch, 274 GEResetProc, StandardMinorOpcode)) != 0) 275 { 276 GEEventBase = extEntry->eventBase; 277 GEErrorBase = extEntry->errorBase; 278 GEEventType = GEEventBase; 279 280 RT_GECLIENT = CreateNewResourceType((DeleteType)GEClientGone); 281 RegisterResourceName(RT_GECLIENT, "GECLIENT"); 282 283 memset(GEExtensions, 0, sizeof(GEExtensions)); 284 285 EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent; 286 } else { 287 FatalError("GEInit: AddExtensions failed.\n"); 288 } 289 290} 291 292/************************************************************/ 293/* interface for extensions */ 294/************************************************************/ 295 296/* Register an extension with GE. The given swap function will be called each 297 * time an event is sent to a client with different byte order. 298 * @param extension The extensions major opcode 299 * @param ev_swap The event swap function. 300 * @param ev_fill Called for an event before delivery. The extension now has 301 * the chance to fill in necessary fields for the event. 302 */ 303void 304GERegisterExtension(int extension, 305 void (*ev_swap)(xGenericEvent* from, xGenericEvent* to), 306 void (*ev_fill)(xGenericEvent* ev, DeviceIntPtr pDev, 307 WindowPtr pWin, GrabPtr pGrab)) 308{ 309 if ((extension & 0x7F) >= MAXEXTENSIONS) 310 FatalError("GE: extension > MAXEXTENSIONS. This should not happen.\n"); 311 312 /* extension opcodes are > 128, might as well save some space here */ 313 GEExtensions[extension & 0x7f].evswap = ev_swap; 314 GEExtensions[extension & 0x7f].evfill = ev_fill; 315} 316 317 318/* Sets type and extension field for a generic event. This is just an 319 * auxiliary function, extensions could do it manually too. 320 */ 321void 322GEInitEvent(xGenericEvent* ev, int extension) 323{ 324 ev->type = GenericEvent; 325 ev->extension = extension; 326 ev->length = 0; 327} 328 329/* Recalculates the summary mask for the window. */ 330static void 331GERecalculateWinMask(WindowPtr pWin) 332{ 333 int i; 334 GenericMaskPtr it; 335 GenericClientMasksPtr evmasks; 336 337 if (!pWin->optional) 338 return; 339 340 evmasks = pWin->optional->geMasks; 341 342 for (i = 0; i < MAXEXTENSIONS; i++) 343 { 344 evmasks->eventMasks[i] = 0; 345 } 346 347 it = pWin->optional->geMasks->geClients; 348 while(it) 349 { 350 for (i = 0; i < MAXEXTENSIONS; i++) 351 { 352 evmasks->eventMasks[i] |= it->eventMask[i]; 353 } 354 it = it->next; 355 } 356} 357 358/* Set generic event mask for given window. */ 359void 360GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev, 361 WindowPtr pWin, int extension, Mask mask) 362{ 363 GenericMaskPtr cli; 364 365 extension = (extension & 0x7F); 366 367 if (extension > MAXEXTENSIONS) 368 { 369 ErrorF("Invalid extension number.\n"); 370 return; 371 } 372 373 if (!pWin->optional && !MakeWindowOptional(pWin)) 374 { 375 ErrorF("GE: Could not make window optional.\n"); 376 return; 377 } 378 379 if (mask) 380 { 381 GenericClientMasksPtr evmasks = pWin->optional->geMasks; 382 383 /* check for existing client */ 384 cli = evmasks->geClients; 385 while(cli) 386 { 387 if (rClient(cli) == pClient && cli->dev == pDev) 388 break; 389 cli = cli->next; 390 } 391 if (!cli) 392 { 393 /* new client and/or new device */ 394 cli = (GenericMaskPtr)xcalloc(1, sizeof(GenericMaskRec)); 395 if (!cli) 396 { 397 ErrorF("GE: Insufficient memory to alloc client.\n"); 398 return; 399 } 400 cli->next = evmasks->geClients; 401 cli->resource = FakeClientID(pClient->index); 402 cli->dev = pDev; 403 evmasks->geClients = cli; 404 AddResource(cli->resource, RT_GECLIENT, (pointer)pWin); 405 } 406 cli->eventMask[extension] = mask; 407 } else 408 { 409 /* remove client. */ 410 cli = pWin->optional->geMasks->geClients; 411 if (rClient(cli) == pClient && cli->dev == pDev) 412 { 413 pWin->optional->geMasks->geClients = cli->next; 414 xfree(cli); 415 } else 416 { 417 GenericMaskPtr prev = cli; 418 cli = cli->next; 419 420 while(cli) 421 { 422 if (rClient(cli) == pClient && cli->dev == pDev) 423 { 424 prev->next = cli->next; 425 xfree(cli); 426 break; 427 } 428 prev = cli; 429 cli = cli->next; 430 } 431 } 432 if (!cli) 433 return; 434 } 435 436 GERecalculateWinMask(pWin); 437} 438 439/** 440 * Return TRUE if the mask for the given device is set. 441 * @param pWin Window the event may be delivered to. 442 * @param pDev Device the device originating the event. May be NULL. 443 * @param extension Extension ID 444 * @param mask Event mask 445 */ 446BOOL 447GEDeviceMaskIsSet(WindowPtr pWin, DeviceIntPtr pDev, 448 int extension, Mask mask) 449{ 450 GenericMaskPtr gemask; 451 452 if (!pWin->optional || !pWin->optional->geMasks) 453 return FALSE; 454 455 extension &= 0x7F; 456 457 if (!pWin->optional->geMasks->eventMasks[extension] & mask) 458 return FALSE; 459 460 461 gemask = pWin->optional->geMasks->geClients; 462 463 while(gemask) 464 { 465 if ((!gemask->dev || gemask->dev == pDev) && 466 (gemask->eventMask[extension] & mask)) 467 return TRUE; 468 469 gemask = gemask->next; 470 } 471 472 return FALSE; 473} 474 475