applewm.c revision 706f2543
1/**************************************************************************
2
3Copyright (c) 2002-2007 Apple Inc. All Rights Reserved.
4Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sub license, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice (including the
15next paragraph) shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26**************************************************************************/
27
28#include "sanitizedCarbon.h"
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#include "quartzCommon.h"
35
36#include "misc.h"
37#include "dixstruct.h"
38#include "globals.h"
39#include "extnsionst.h"
40#include "colormapst.h"
41#include "cursorstr.h"
42#include "scrnintstr.h"
43#include "windowstr.h"
44#include "servermd.h"
45#include "swaprep.h"
46#include "propertyst.h"
47#include <X11/Xatom.h>
48#include "darwin.h"
49#define _APPLEWM_SERVER_
50#include <X11/extensions/applewmproto.h>
51#include "applewmExt.h"
52#include "X11Application.h"
53#include "protocol-versions.h"
54
55#define DEFINE_ATOM_HELPER(func,atom_name)                      \
56static Atom func (void) {                                       \
57    static int generation;                                      \
58    static Atom atom;                                           \
59    if (generation != serverGeneration) {                       \
60        generation = serverGeneration;                          \
61        atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
62    }                                                           \
63    return atom;                                                \
64}
65
66DEFINE_ATOM_HELPER(xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN")
67DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN")
68
69static AppleWMProcsPtr appleWMProcs;
70
71static int WMErrorBase;
72
73
74static unsigned char WMReqCode = 0;
75static int WMEventBase = 0;
76
77static RESTYPE ClientType, EventType; /* resource types for event masks */
78static XID eventResource;
79
80/* Currently selected events */
81static unsigned int eventMask = 0;
82
83static int WMFreeClient (pointer data, XID id);
84static int WMFreeEvents (pointer data, XID id);
85static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to);
86
87typedef struct _WMEvent *WMEventPtr;
88typedef struct _WMEvent {
89    WMEventPtr      next;
90    ClientPtr       client;
91    XID             clientResource;
92    unsigned int    mask;
93} WMEventRec;
94
95static inline BoxRec
96make_box (int x, int y, int w, int h)
97{
98    BoxRec r;
99    r.x1 = x;
100    r.y1 = y;
101    r.x2 = x + w;
102    r.y2 = y + h;
103    return r;
104}
105
106/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */
107void
108AppleWMSetScreenOrigin(
109    WindowPtr pWin
110)
111{
112    int32_t data[2];
113
114    data[0] = pWin->drawable.pScreen->x + darwinMainScreenX;
115    data[1] = pWin->drawable.pScreen->y + darwinMainScreenY;
116
117    dixChangeWindowProperty(serverClient, pWin, xa_native_screen_origin(),
118			    XA_INTEGER, 32, PropModeReplace, 2, data, TRUE);
119}
120
121/* Window managers can set the _APPLE_NO_ORDER_IN property on windows
122   that are being genie-restored from the Dock. We want them to
123   be mapped but remain ordered-out until the animation
124   completes (when the Dock will order them in). */
125Bool
126AppleWMDoReorderWindow(
127    WindowPtr pWin
128)
129{
130    Atom atom;
131    PropertyPtr prop;
132    int rc;
133
134    atom = xa_apple_no_order_in();
135    rc = dixLookupProperty(&prop, pWin, atom, serverClient, DixReadAccess);
136
137    if(Success == rc && prop->type == atom)
138	return 0;
139
140    return 1;
141}
142
143
144static int
145ProcAppleWMQueryVersion(
146    register ClientPtr client
147)
148{
149    xAppleWMQueryVersionReply rep;
150    register int n;
151
152    REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq);
153    rep.type = X_Reply;
154    rep.length = 0;
155    rep.sequenceNumber = client->sequence;
156    rep.majorVersion = SERVER_APPLEWM_MAJOR_VERSION;
157    rep.minorVersion = SERVER_APPLEWM_MINOR_VERSION;
158    rep.patchVersion = SERVER_APPLEWM_PATCH_VERSION;
159    if (client->swapped) {
160        swaps(&rep.sequenceNumber, n);
161        swapl(&rep.length, n);
162    }
163    WriteToClient(client, sizeof(xAppleWMQueryVersionReply), (char *)&rep);
164    return Success;
165}
166
167
168/* events */
169
170static inline void
171updateEventMask (WMEventPtr *pHead)
172{
173    WMEventPtr pCur;
174
175    eventMask = 0;
176    for (pCur = *pHead; pCur != NULL; pCur = pCur->next)
177        eventMask |= pCur->mask;
178}
179
180/*ARGSUSED*/
181static int
182WMFreeClient (pointer data, XID id) {
183    WMEventPtr   pEvent;
184    WMEventPtr   *pHead, pCur, pPrev;
185    int i;
186
187    pEvent = (WMEventPtr) data;
188    i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess | DixWriteAccess | DixDestroyAccess);
189    if (i == Success && pHead) {
190        pPrev = 0;
191        for (pCur = *pHead; pCur && pCur != pEvent; pCur=pCur->next)
192            pPrev = pCur;
193        if (pCur) {
194            if (pPrev)
195                pPrev->next = pEvent->next;
196            else
197                *pHead = pEvent->next;
198        }
199        updateEventMask (pHead);
200    }
201    free((pointer) pEvent);
202    return 1;
203}
204
205/*ARGSUSED*/
206static int
207WMFreeEvents (pointer data, XID id) {
208    WMEventPtr   *pHead, pCur, pNext;
209
210    pHead = (WMEventPtr *) data;
211    for (pCur = *pHead; pCur; pCur = pNext) {
212        pNext = pCur->next;
213        FreeResource (pCur->clientResource, ClientType);
214        free((pointer) pCur);
215    }
216    free((pointer) pHead);
217    eventMask = 0;
218    return 1;
219}
220
221static int
222ProcAppleWMSelectInput (register ClientPtr client)
223{
224    REQUEST(xAppleWMSelectInputReq);
225    WMEventPtr      pEvent, pNewEvent, *pHead;
226    XID             clientResource;
227    int             i;
228
229    REQUEST_SIZE_MATCH (xAppleWMSelectInputReq);
230    i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, client, DixWriteAccess);
231    if (stuff->mask != 0) {
232        if (i == Success && pHead) {
233            /* check for existing entry. */
234            for (pEvent = *pHead; pEvent; pEvent = pEvent->next)
235            {
236                if (pEvent->client == client)
237                {
238                    pEvent->mask = stuff->mask;
239                    updateEventMask (pHead);
240                    return Success;
241                }
242            }
243        }
244
245        /* build the entry */
246        pNewEvent = (WMEventPtr) malloc(sizeof (WMEventRec));
247        if (!pNewEvent)
248            return BadAlloc;
249        pNewEvent->next = 0;
250        pNewEvent->client = client;
251        pNewEvent->mask = stuff->mask;
252        /*
253         * add a resource that will be deleted when
254         * the client goes away
255         */
256        clientResource = FakeClientID (client->index);
257        pNewEvent->clientResource = clientResource;
258        if (!AddResource (clientResource, ClientType, (pointer)pNewEvent))
259            return BadAlloc;
260        /*
261         * create a resource to contain a pointer to the list
262         * of clients selecting input.  This must be indirect as
263         * the list may be arbitrarily rearranged which cannot be
264         * done through the resource database.
265         */
266        if (i != Success || !pHead)
267        {
268            pHead = (WMEventPtr *) malloc(sizeof (WMEventPtr));
269            if (!pHead ||
270                !AddResource (eventResource, EventType, (pointer)pHead))
271            {
272                FreeResource (clientResource, RT_NONE);
273                return BadAlloc;
274            }
275            *pHead = 0;
276        }
277        pNewEvent->next = *pHead;
278        *pHead = pNewEvent;
279        updateEventMask (pHead);
280    } else if (stuff->mask == 0) {
281        /* delete the interest */
282        if (i == Success && pHead) {
283            pNewEvent = 0;
284            for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
285                if (pEvent->client == client)
286                    break;
287                pNewEvent = pEvent;
288            }
289            if (pEvent) {
290                FreeResource (pEvent->clientResource, ClientType);
291                if (pNewEvent)
292                    pNewEvent->next = pEvent->next;
293                else
294                    *pHead = pEvent->next;
295                free(pEvent);
296                updateEventMask (pHead);
297            }
298        }
299    } else {
300        client->errorValue = stuff->mask;
301        return BadValue;
302    }
303    return Success;
304}
305
306/*
307 * deliver the event
308 */
309
310void
311AppleWMSendEvent (int type, unsigned int mask, int which, int arg) {
312    WMEventPtr      *pHead, pEvent;
313    xAppleWMNotifyEvent se;
314    int             i;
315
316    i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess);
317    if (i != Success || !pHead)
318        return;
319    for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
320        if ((pEvent->mask & mask) == 0)
321            continue;
322        se.type = type + WMEventBase;
323        se.kind = which;
324        se.arg = arg;
325        se.time = currentTime.milliseconds;
326        WriteEventsToClient (pEvent->client, 1, (xEvent *) &se);
327    }
328}
329
330/* Safe to call from any thread. */
331unsigned int
332AppleWMSelectedEvents (void)
333{
334    return eventMask;
335}
336
337
338/* general utility functions */
339
340static int
341ProcAppleWMDisableUpdate(
342    register ClientPtr client
343)
344{
345    REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq);
346
347    appleWMProcs->DisableUpdate();
348
349    return Success;
350}
351
352static int
353ProcAppleWMReenableUpdate(
354    register ClientPtr client
355)
356{
357    REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq);
358
359    appleWMProcs->EnableUpdate();
360
361    return Success;
362}
363
364
365/* window functions */
366
367static int
368ProcAppleWMSetWindowMenu(
369    register ClientPtr client
370)
371{
372    const char *bytes, **items;
373    char *shortcuts;
374    int max_len, nitems, i, j;
375    REQUEST(xAppleWMSetWindowMenuReq);
376
377    REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq);
378
379    nitems = stuff->nitems;
380    items = malloc(sizeof (char *) * nitems);
381    shortcuts = malloc(sizeof (char) * nitems);
382
383    max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq);
384    bytes = (char *) &stuff[1];
385
386    for (i = j = 0; i < max_len && j < nitems;)
387    {
388        shortcuts[j] = bytes[i++];
389        items[j++] = bytes + i;
390
391        while (i < max_len)
392        {
393            if (bytes[i++] == 0)
394                break;
395        }
396    }
397    X11ApplicationSetWindowMenu (nitems, items, shortcuts);
398    free(items);
399    free(shortcuts);
400
401    return Success;
402}
403
404static int
405ProcAppleWMSetWindowMenuCheck(
406    register ClientPtr client
407)
408{
409    REQUEST(xAppleWMSetWindowMenuCheckReq);
410
411    REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq);
412    X11ApplicationSetWindowMenuCheck(stuff->index);
413    return Success;
414}
415
416static int
417ProcAppleWMSetFrontProcess(
418    register ClientPtr client
419)
420{
421    REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq);
422
423    X11ApplicationSetFrontProcess();
424    return Success;
425}
426
427static int
428ProcAppleWMSetWindowLevel(register ClientPtr client)
429{
430    REQUEST(xAppleWMSetWindowLevelReq);
431    WindowPtr pWin;
432    int err;
433
434    REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq);
435
436    if (Success != dixLookupWindow(&pWin, stuff->window, client,
437				   DixReadAccess))
438        return BadValue;
439
440    if (stuff->level < 0 || stuff->level >= AppleWMNumWindowLevels) {
441        return BadValue;
442    }
443
444     err = appleWMProcs->SetWindowLevel(pWin, stuff->level);
445     if (err != Success) {
446        return err;
447    }
448
449    return Success;
450}
451
452static int
453ProcAppleWMSendPSN(register ClientPtr client)
454{
455    REQUEST(xAppleWMSendPSNReq);
456    int err;
457
458    REQUEST_SIZE_MATCH(xAppleWMSendPSNReq);
459
460    if(!appleWMProcs->SendPSN)
461        return BadRequest;
462
463    err = appleWMProcs->SendPSN(stuff->psn_hi, stuff->psn_lo);
464    if (err != Success) {
465        return err;
466    }
467
468    return Success;
469}
470
471static int
472ProcAppleWMAttachTransient(register ClientPtr client)
473{
474    WindowPtr pWinChild, pWinParent;
475    REQUEST(xAppleWMAttachTransientReq);
476    int err;
477
478    REQUEST_SIZE_MATCH(xAppleWMAttachTransientReq);
479
480    if(!appleWMProcs->AttachTransient)
481        return BadRequest;
482
483    if (Success != dixLookupWindow(&pWinChild, stuff->child, client, DixReadAccess))
484        return BadValue;
485
486    if(stuff->parent) {
487        if(Success != dixLookupWindow(&pWinParent, stuff->parent, client, DixReadAccess))
488            return BadValue;
489    } else {
490        pWinParent = NULL;
491    }
492
493    err = appleWMProcs->AttachTransient(pWinChild, pWinParent);
494    if (err != Success) {
495        return err;
496    }
497
498    return Success;
499}
500
501static int
502ProcAppleWMSetCanQuit(
503    register ClientPtr client
504)
505{
506    REQUEST(xAppleWMSetCanQuitReq);
507
508    REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq);
509
510    X11ApplicationSetCanQuit(stuff->state);
511    return Success;
512}
513
514
515/* frame functions */
516
517static int
518ProcAppleWMFrameGetRect(
519    register ClientPtr client
520)
521{
522    xAppleWMFrameGetRectReply rep;
523    BoxRec ir, or, rr;
524    REQUEST(xAppleWMFrameGetRectReq);
525
526    REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq);
527    rep.type = X_Reply;
528    rep.length = 0;
529    rep.sequenceNumber = client->sequence;
530
531    ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih);
532    or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh);
533
534    if (appleWMProcs->FrameGetRect(stuff->frame_rect,
535                                   stuff->frame_class,
536                                   &or, &ir, &rr) != Success)
537    {
538        return BadValue;
539    }
540
541    rep.x = rr.x1;
542    rep.y = rr.y1;
543    rep.w = rr.x2 - rr.x1;
544    rep.h = rr.y2 - rr.y1;
545
546    WriteToClient(client, sizeof(xAppleWMFrameGetRectReply), (char *)&rep);
547    return Success;
548}
549
550static int
551ProcAppleWMFrameHitTest(
552    register ClientPtr client
553)
554{
555    xAppleWMFrameHitTestReply rep;
556    BoxRec ir, or;
557    int ret;
558    REQUEST(xAppleWMFrameHitTestReq);
559
560    REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq);
561    rep.type = X_Reply;
562    rep.length = 0;
563    rep.sequenceNumber = client->sequence;
564
565    ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih);
566    or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh);
567
568    if (appleWMProcs->FrameHitTest(stuff->frame_class, stuff->px,
569                                   stuff->py, &or, &ir, &ret) != Success)
570    {
571        return BadValue;
572    }
573
574    rep.ret = ret;
575
576    WriteToClient(client, sizeof(xAppleWMFrameHitTestReply), (char *)&rep);
577    return Success;
578}
579
580static int
581ProcAppleWMFrameDraw(
582    register ClientPtr client
583)
584{
585    BoxRec ir, or;
586    unsigned int title_length, title_max;
587    unsigned char *title_bytes;
588    REQUEST(xAppleWMFrameDrawReq);
589    WindowPtr pWin;
590
591    REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq);
592
593    if (Success != dixLookupWindow(&pWin, stuff->window, client,
594				   DixReadAccess))
595        return BadValue;
596
597    ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih);
598    or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh);
599
600    title_length = stuff->title_length;
601    title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq);
602
603    if (title_max < title_length)
604        return BadValue;
605
606    title_bytes = (unsigned char *) &stuff[1];
607
608    errno = appleWMProcs->FrameDraw(pWin, stuff->frame_class,
609                                    stuff->frame_attr, &or, &ir,
610                                    title_length, title_bytes);
611    if (errno != Success) {
612        return errno;
613    }
614
615    return Success;
616}
617
618
619/* dispatch */
620
621static int
622ProcAppleWMDispatch (
623    register ClientPtr  client
624)
625{
626    REQUEST(xReq);
627
628    switch (stuff->data)
629    {
630    case X_AppleWMQueryVersion:
631        return ProcAppleWMQueryVersion(client);
632    }
633
634    if (!LocalClient(client))
635        return WMErrorBase + AppleWMClientNotLocal;
636
637    switch (stuff->data)
638    {
639    case X_AppleWMSelectInput:
640        return ProcAppleWMSelectInput(client);
641    case X_AppleWMDisableUpdate:
642        return ProcAppleWMDisableUpdate(client);
643    case X_AppleWMReenableUpdate:
644        return ProcAppleWMReenableUpdate(client);
645    case X_AppleWMSetWindowMenu:
646        return ProcAppleWMSetWindowMenu(client);
647    case X_AppleWMSetWindowMenuCheck:
648        return ProcAppleWMSetWindowMenuCheck(client);
649    case X_AppleWMSetFrontProcess:
650        return ProcAppleWMSetFrontProcess(client);
651    case X_AppleWMSetWindowLevel:
652        return ProcAppleWMSetWindowLevel(client);
653    case X_AppleWMSetCanQuit:
654        return ProcAppleWMSetCanQuit(client);
655    case X_AppleWMFrameGetRect:
656        return ProcAppleWMFrameGetRect(client);
657    case X_AppleWMFrameHitTest:
658        return ProcAppleWMFrameHitTest(client);
659    case X_AppleWMFrameDraw:
660        return ProcAppleWMFrameDraw(client);
661    case X_AppleWMSendPSN:
662        return ProcAppleWMSendPSN(client);
663    case X_AppleWMAttachTransient:
664        return ProcAppleWMAttachTransient(client);
665    default:
666        return BadRequest;
667    }
668}
669
670static void
671SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to) {
672    to->type = from->type;
673    to->kind = from->kind;
674    cpswaps (from->sequenceNumber, to->sequenceNumber);
675    cpswapl (from->time, to->time);
676    cpswapl (from->arg, to->arg);
677}
678
679static int
680SProcAppleWMQueryVersion(
681    register ClientPtr  client
682)
683{
684    register int n;
685    REQUEST(xAppleWMQueryVersionReq);
686    swaps(&stuff->length, n);
687    return ProcAppleWMQueryVersion(client);
688}
689
690static int
691SProcAppleWMDispatch (
692    register ClientPtr  client
693)
694{
695    REQUEST(xReq);
696
697    /* It is bound to be non-local when there is byte swapping */
698    if (!LocalClient(client))
699        return WMErrorBase + AppleWMClientNotLocal;
700
701    /* only local clients are allowed WM access */
702    switch (stuff->data)
703    {
704    case X_AppleWMQueryVersion:
705        return SProcAppleWMQueryVersion(client);
706    default:
707        return BadRequest;
708    }
709}
710
711void
712AppleWMExtensionInit(
713    AppleWMProcsPtr procsPtr)
714{
715    ExtensionEntry* extEntry;
716
717    ClientType = CreateNewResourceType(WMFreeClient, "WMClient");
718    EventType = CreateNewResourceType(WMFreeEvents, "WMEvent");
719    eventResource = FakeClientID(0);
720
721    if (ClientType && EventType &&
722        (extEntry = AddExtension(APPLEWMNAME,
723                                 AppleWMNumberEvents,
724                                 AppleWMNumberErrors,
725                                 ProcAppleWMDispatch,
726                                 SProcAppleWMDispatch,
727                                 NULL,
728                                 StandardMinorOpcode)))
729    {
730        size_t i;
731        WMReqCode = (unsigned char)extEntry->base;
732        WMErrorBase = extEntry->errorBase;
733        WMEventBase = extEntry->eventBase;
734        for (i=0; i < AppleWMNumberEvents; i++)
735            EventSwapVector[WMEventBase + i] = (EventSwapPtr) SNotifyEvent;
736        appleWMProcs = procsPtr;
737    }
738}
739