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