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