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