initial commit
[profile/ivi/xorg-x11-server.git] / hw / xquartz / applewm.c
1 /**************************************************************************
2
3 Copyright (c) 2002-2007 Apple Inc. All Rights Reserved.
4 Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE 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)                      \
56 static 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
66 DEFINE_ATOM_HELPER(xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN")
67 DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN")
68
69 static AppleWMProcsPtr appleWMProcs;
70
71 static int WMErrorBase;
72
73 static DISPATCH_PROC(ProcAppleWMDispatch);
74 static DISPATCH_PROC(SProcAppleWMDispatch);
75
76 static unsigned char WMReqCode = 0;
77 static int WMEventBase = 0;
78
79 static RESTYPE ClientType, EventType; /* resource types for event masks */
80 static XID eventResource;
81
82 /* Currently selected events */
83 static unsigned int eventMask = 0;
84
85 static int WMFreeClient (pointer data, XID id);
86 static int WMFreeEvents (pointer data, XID id);
87 static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to);
88
89 typedef struct _WMEvent *WMEventPtr;
90 typedef struct _WMEvent {
91     WMEventPtr      next;
92     ClientPtr       client;
93     XID             clientResource;
94     unsigned int    mask;
95 } WMEventRec;
96
97 static inline BoxRec
98 make_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
108 void
109 AppleWMExtensionInit(
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. */
136 void
137 AppleWMSetScreenOrigin(
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). */
154 Bool
155 AppleWMDoReorderWindow(
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
173 static int
174 ProcAppleWMQueryVersion(
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 \f
197 /* events */
198
199 static inline void
200 updateEventMask (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*/
210 static int
211 WMFreeClient (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*/
235 static int
236 WMFreeEvents (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
250 static int
251 ProcAppleWMSelectInput (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
339 void
340 AppleWMSendEvent (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. */
360 unsigned int
361 AppleWMSelectedEvents (void)
362 {
363     return eventMask;
364 }
365
366 \f
367 /* general utility functions */
368
369 static int
370 ProcAppleWMDisableUpdate(
371     register ClientPtr client
372 )
373 {
374     REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq);
375
376     appleWMProcs->DisableUpdate();
377
378     return Success;
379 }
380
381 static int
382 ProcAppleWMReenableUpdate(
383     register ClientPtr client
384 )
385 {
386     REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq);
387
388     appleWMProcs->EnableUpdate();
389
390     return Success;
391 }
392
393 \f
394 /* window functions */
395
396 static int
397 ProcAppleWMSetWindowMenu(
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
433 static int
434 ProcAppleWMSetWindowMenuCheck(
435     register ClientPtr client
436 )
437 {
438     REQUEST(xAppleWMSetWindowMenuCheckReq);
439
440     REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq);
441     X11ApplicationSetWindowMenuCheck(stuff->index);
442     return Success;
443 }
444
445 static int
446 ProcAppleWMSetFrontProcess(
447     register ClientPtr client
448 )
449 {
450     REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq);
451
452     X11ApplicationSetFrontProcess();
453     return Success;
454 }
455
456 static int
457 ProcAppleWMSetWindowLevel(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
481 static int
482 ProcAppleWMSendPSN(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
500 static int
501 ProcAppleWMAttachTransient(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
530 static int
531 ProcAppleWMSetCanQuit(
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 \f
544 /* frame functions */
545
546 static int
547 ProcAppleWMFrameGetRect(
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
579 static int
580 ProcAppleWMFrameHitTest(
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
609 static int
610 ProcAppleWMFrameDraw(
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 \f
648 /* dispatch */
649
650 static int
651 ProcAppleWMDispatch (
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
699 static void
700 SNotifyEvent(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
708 static int
709 SProcAppleWMQueryVersion(
710     register ClientPtr  client
711 )
712 {
713     register int n;
714     REQUEST(xAppleWMQueryVersionReq);
715     swaps(&stuff->length, n);
716     return ProcAppleWMQueryVersion(client);
717 }
718
719 static int
720 SProcAppleWMDispatch (
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 }