Lots more changes which hopefully change nothing but the clarity.
[synfig.git] / synfig-osx / trunk / launcher / applewm-impl.c
1 /* $XFree86: xc/programs/Xserver/GL/dri/xf86dri.c,v 1.10 2000/12/07 20:26:14 dawes Exp $ */
2 /**************************************************************************
3
4 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5 Copyright 2000 VA Linux Systems, Inc.
6 Copyright (c) 2002 Apple Computer, Inc.
7 All Rights Reserved.
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 #define NEED_REPLIES
32 #define NEED_EVENTS
33 #include "X.h"
34 #include "Xproto.h"
35 #include "misc.h"
36 #include "dixstruct.h"
37 #include "extnsionst.h"
38 #include "colormapst.h"
39 #include "cursorstr.h"
40 #include "scrnintstr.h"
41 #include "servermd.h"
42 #define _APPLEWM_SERVER_
43 #include "applewmstr.h"
44 #include "swaprep.h"
45 #include "rootless-common.h"
46 #include "X11Application.h"
47
48 static int WMErrorBase;
49
50 static DISPATCH_PROC(ProcAppleWMDispatch);
51 static DISPATCH_PROC(SProcAppleWMDispatch);
52
53 static void AppleWMResetProc(ExtensionEntry* extEntry);
54
55 static unsigned char WMReqCode = 0;
56 static int WMEventBase = 0;
57
58 static RESTYPE ClientType, EventType; /* resource types for event masks */
59 static XID eventResource;
60
61 /* Currently selected events */
62 static unsigned int eventMask = 0;
63
64 extern void AppleWMExtensionInit(void);
65
66 static int WMFreeClient (pointer data, XID id);
67 static int WMFreeEvents (pointer data, XID id);
68 static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to);
69
70 typedef struct _WMEvent *WMEventPtr;
71 typedef struct _WMEvent {
72     WMEventPtr     next;
73     ClientPtr       client;
74     XID             clientResource;
75     unsigned int    mask;
76 } WMEventRec;
77
78 static inline BoxRec
79 make_box (int x, int y, int w, int h)
80 {
81     BoxRec r;
82     r.x1 = x;
83     r.y1 = y;
84     r.x2 = x + w;
85     r.y2 = y + h;
86     return r;
87 }
88
89 void
90 AppleWMExtensionInit(void)
91 {
92     ExtensionEntry* extEntry;
93
94     ClientType = CreateNewResourceType(WMFreeClient);
95     EventType = CreateNewResourceType(WMFreeEvents);
96     eventResource = FakeClientID(0);
97
98     if (ClientType && EventType &&
99         (extEntry = AddExtension(APPLEWMNAME,
100                                  AppleWMNumberEvents,
101                                  AppleWMNumberErrors,
102                                  ProcAppleWMDispatch,
103                                  SProcAppleWMDispatch,
104                                  AppleWMResetProc,
105                                  StandardMinorOpcode))) {
106         WMReqCode = (unsigned char)extEntry->base;
107         WMErrorBase = extEntry->errorBase;
108         WMEventBase = extEntry->eventBase;
109         EventSwapVector[WMEventBase] = (EventSwapPtr) SNotifyEvent;
110     }
111 }
112
113 /*ARGSUSED*/
114 static void
115 AppleWMResetProc (
116     ExtensionEntry* extEntry
117 )
118 {
119 }
120
121 static int
122 ProcAppleWMQueryVersion(
123     register ClientPtr client
124 )
125 {
126     xAppleWMQueryVersionReply rep;
127     register int n;
128
129     REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq);
130     rep.type = X_Reply;
131     rep.length = 0;
132     rep.sequenceNumber = client->sequence;
133     rep.majorVersion = APPLE_WM_MAJOR_VERSION;
134     rep.minorVersion = APPLE_WM_MINOR_VERSION;
135     rep.patchVersion = APPLE_WM_PATCH_VERSION;
136     if (client->swapped) {
137         swaps(&rep.sequenceNumber, n);
138         swapl(&rep.length, n);
139     }
140     WriteToClient(client, sizeof(xAppleWMQueryVersionReply), (char *)&rep);
141     return (client->noClientException);
142 }
143
144 \f
145 /* events */
146
147 static inline void
148 updateEventMask (WMEventPtr *pHead)
149 {
150     WMEventPtr pCur;
151
152     eventMask = 0;
153     for (pCur = *pHead; pCur != NULL; pCur = pCur->next)
154         eventMask |= pCur->mask;
155 }
156
157 /*ARGSUSED*/
158 static int
159 WMFreeClient (data, id)
160     pointer         data;
161     XID             id;
162 {
163     WMEventPtr   pEvent;
164     WMEventPtr   *pHead, pCur, pPrev;
165
166     pEvent = (WMEventPtr) data;
167     pHead = (WMEventPtr *) LookupIDByType(eventResource, EventType);
168     if (pHead) {
169         pPrev = 0;
170         for (pCur = *pHead; pCur && pCur != pEvent; pCur=pCur->next)
171             pPrev = pCur;
172         if (pCur)
173         {
174             if (pPrev)
175                 pPrev->next = pEvent->next;
176             else
177                 *pHead = pEvent->next;
178         }
179         updateEventMask (pHead);
180     }
181     xfree ((pointer) pEvent);
182     return 1;
183 }
184
185 /*ARGSUSED*/
186 static int
187 WMFreeEvents (data, id)
188     pointer         data;
189     XID             id;
190 {
191     WMEventPtr   *pHead, pCur, pNext;
192
193     pHead = (WMEventPtr *) data;
194     for (pCur = *pHead; pCur; pCur = pNext) {
195         pNext = pCur->next;
196         FreeResource (pCur->clientResource, ClientType);
197         xfree ((pointer) pCur);
198     }
199     xfree ((pointer) pHead);
200     eventMask = 0;
201     return 1;
202 }
203
204 static int
205 ProcAppleWMSelectInput (client)
206     register ClientPtr  client;
207 {
208     REQUEST(xAppleWMSelectInputReq);
209     WMEventPtr  pEvent, pNewEvent, *pHead;
210     XID                 clientResource;
211
212     REQUEST_SIZE_MATCH (xAppleWMSelectInputReq);
213     pHead = (WMEventPtr *)SecurityLookupIDByType(client,
214                         eventResource, EventType, SecurityWriteAccess);
215     if (stuff->mask != 0) {
216         if (pHead) {
217             /* check for existing entry. */
218             for (pEvent = *pHead; pEvent; pEvent = pEvent->next)
219             {
220                 if (pEvent->client == client)
221                 {
222                     pEvent->mask = stuff->mask;
223                     updateEventMask (pHead);
224                     return Success;
225                 }
226             }
227         }
228
229         /* build the entry */
230         pNewEvent = (WMEventPtr) xalloc (sizeof (WMEventRec));
231         if (!pNewEvent)
232             return BadAlloc;
233         pNewEvent->next = 0;
234         pNewEvent->client = client;
235         pNewEvent->mask = stuff->mask;
236         /*
237          * add a resource that will be deleted when
238          * the client goes away
239          */
240         clientResource = FakeClientID (client->index);
241         pNewEvent->clientResource = clientResource;
242         if (!AddResource (clientResource, ClientType, (pointer)pNewEvent))
243             return BadAlloc;
244         /*
245          * create a resource to contain a pointer to the list
246          * of clients selecting input.  This must be indirect as
247          * the list may be arbitrarily rearranged which cannot be
248          * done through the resource database.
249          */
250         if (!pHead)
251         {
252             pHead = (WMEventPtr *) xalloc (sizeof (WMEventPtr));
253             if (!pHead ||
254                 !AddResource (eventResource, EventType, (pointer)pHead))
255             {
256                 FreeResource (clientResource, RT_NONE);
257                 return BadAlloc;
258             }
259             *pHead = 0;
260         }
261         pNewEvent->next = *pHead;
262         *pHead = pNewEvent;
263         updateEventMask (pHead);
264     } else if (stuff->mask == 0) {
265         /* delete the interest */
266         if (pHead) {
267             pNewEvent = 0;
268             for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
269                 if (pEvent->client == client)
270                     break;
271                 pNewEvent = pEvent;
272             }
273             if (pEvent) {
274                 FreeResource (pEvent->clientResource, ClientType);
275                 if (pNewEvent)
276                     pNewEvent->next = pEvent->next;
277                 else
278                     *pHead = pEvent->next;
279                 xfree (pEvent);
280                 updateEventMask (pHead);
281             }
282         }
283     } else {
284         client->errorValue = stuff->mask;
285         return BadValue;
286     }
287     return Success;
288 }
289
290 /*
291  * deliver the event
292  */
293
294 void
295 AppleWMSendEvent (type, mask, which, arg)
296     int type, which, arg;
297     unsigned int mask;
298 {
299     WMEventPtr  *pHead, pEvent;
300     ClientPtr           client;
301     xAppleWMNotifyEvent se;
302
303     pHead = (WMEventPtr *) LookupIDByType(eventResource, EventType);
304     if (!pHead)
305         return;
306     for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
307         client = pEvent->client;
308         if ((pEvent->mask & mask) == 0
309             || client == serverClient || client->clientGone)
310         {
311             continue;
312         }
313         se.type = type + WMEventBase;
314         se.kind = which;
315         se.arg = arg;
316         se.sequenceNumber = client->sequence;
317         se.time = currentTime.milliseconds;
318         WriteEventsToClient (client, 1, (xEvent *) &se);
319     }
320 }
321
322 /* Safe to call from any thread. */
323 unsigned int
324 AppleWMSelectedEvents (void)
325 {
326     return eventMask;
327 }
328
329 \f
330 /* general utility functions */
331
332 static int
333 ProcAppleWMDisableUpdate(
334     register ClientPtr client
335 )
336 {
337     REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq);
338
339     xp_disable_update ();
340
341     return (client->noClientException);
342 }
343
344 static int
345 ProcAppleWMReenableUpdate(
346     register ClientPtr client
347 )
348 {
349     REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq);
350
351     xp_reenable_update ();
352
353     return (client->noClientException);
354 }
355
356 \f
357 /* window functions */
358
359 static int
360 ProcAppleWMSetWindowMenu(
361     register ClientPtr client
362 )
363 {
364     const char *bytes, **items;
365     char *shortcuts;
366     int max_len, nitems, i, j;
367     REQUEST(xAppleWMSetWindowMenuReq);
368
369     REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq);
370
371     nitems = stuff->nitems;
372     items = alloca (sizeof (char *) * nitems);
373     shortcuts = alloca (sizeof (char) * nitems);
374
375     max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq);
376     bytes = (char *) &stuff[1];
377
378     for (i = j = 0; i < max_len && j < nitems;)
379     {
380         shortcuts[j] = bytes[i++];
381         items[j++] = bytes + i;
382
383         while (i < max_len)
384         {
385             if (bytes[i++] == 0)
386                 break;
387         }
388     }
389
390     X11ApplicationSetWindowMenu (nitems, items, shortcuts);
391
392     return (client->noClientException);
393 }
394
395 static int
396 ProcAppleWMSetWindowMenuCheck(
397     register ClientPtr client
398 )
399 {
400     REQUEST(xAppleWMSetWindowMenuCheckReq);
401
402     REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq);
403
404     X11ApplicationSetWindowMenuCheck (stuff->index);
405
406     return (client->noClientException);
407 }
408
409 static int
410 ProcAppleWMSetFrontProcess(
411     register ClientPtr client
412 )
413 {
414     REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq);
415
416     X11ApplicationSetFrontProcess ();
417
418     return (client->noClientException);
419 }
420
421 static int
422 ProcAppleWMSetWindowLevel(
423     register ClientPtr client
424 )
425 {
426     REQUEST(xAppleWMSetWindowLevelReq);
427     WindowPtr pWin;
428
429     REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq);
430
431     if (!(pWin = SecurityLookupWindow((Drawable)stuff->window,
432                                       client, SecurityReadAccess))) {
433         return BadValue;
434     }
435
436     if (stuff->level < 0 || stuff->level >= AppleWMNumWindowLevels) {
437         return BadValue;
438     }
439
440     RootlessSetWindowLevel (pWin, stuff->level);
441
442     return (client->noClientException);
443 }
444
445 static int
446 ProcAppleWMSetCanQuit(
447     register ClientPtr client
448 )
449 {
450     REQUEST(xAppleWMSetCanQuitReq);
451
452     REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq);
453
454     X11ApplicationSetCanQuit (stuff->state);
455
456     return (client->noClientException);
457 }
458
459 \f
460 /* frame functions */
461
462 static int
463 ProcAppleWMFrameGetRect(
464     register ClientPtr client
465 )
466 {
467     xAppleWMFrameGetRectReply rep;
468     BoxRec ir, or, rr;
469     REQUEST(xAppleWMFrameGetRectReq);
470
471     REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq);
472     rep.type = X_Reply;
473     rep.length = 0;
474     rep.sequenceNumber = client->sequence;
475
476     ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih);
477     or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh);
478
479     if (xp_frame_get_rect (stuff->frame_rect,
480                            stuff->frame_class,
481                            &or, &ir, &rr) != Success) {
482         return BadValue;
483     }
484
485     rep.x = rr.x1;
486     rep.y = rr.y1;
487     rep.w = rr.x2 - rr.x1;
488     rep.h = rr.y2 - rr.y1;
489
490     WriteToClient(client, sizeof(xAppleWMFrameGetRectReply), (char *)&rep);
491     return (client->noClientException);
492 }
493
494 static int
495 ProcAppleWMFrameHitTest(
496     register ClientPtr client
497 )
498 {
499     xAppleWMFrameHitTestReply rep;
500     BoxRec ir, or;
501     int ret;
502     REQUEST(xAppleWMFrameHitTestReq);
503
504     REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq);
505     rep.type = X_Reply;
506     rep.length = 0;
507     rep.sequenceNumber = client->sequence;
508
509     ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih);
510     or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh);
511
512     if (xp_frame_hit_test (stuff->frame_class, stuff->px,
513                            stuff->py, &or, &ir, &ret) != Success)
514     {
515         return BadValue;
516     }
517
518     rep.ret = ret;
519
520     WriteToClient(client, sizeof(xAppleWMFrameHitTestReply), (char *)&rep);
521     return (client->noClientException);
522 }
523
524 static int
525 ProcAppleWMFrameDraw(
526     register ClientPtr client
527 )
528 {
529     BoxRec ir, or;
530     unsigned int title_length, title_max;
531     unsigned char *title_bytes;
532     REQUEST(xAppleWMFrameDrawReq);
533     WindowPtr pWin;
534     xp_window_id wid;
535
536     REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq);
537
538     if (!(pWin = SecurityLookupWindow((Drawable)stuff->window,
539                                       client, SecurityReadAccess))) {
540         return BadValue;
541     }
542
543     ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih);
544     or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh);
545
546     title_length = stuff->title_length;
547     title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq);
548
549     if (title_max < title_length)
550         return BadValue;
551
552     title_bytes = (unsigned char *) &stuff[1];
553
554     wid = RootlessGetPhysicalWindow (pWin, FALSE);
555     if (wid == 0)
556         return BadWindow;
557
558     if (xp_frame_draw (wid, stuff->frame_class,
559                        stuff->frame_attr, &or, &ir,
560                        title_length, title_bytes) != Success) {
561         return BadValue;
562     }
563
564     return (client->noClientException);
565 }
566
567 \f
568 /* dispatch */
569
570 static int
571 ProcAppleWMDispatch (
572     register ClientPtr  client
573 )
574 {
575     REQUEST(xReq);
576
577     switch (stuff->data)
578     {
579     case X_AppleWMQueryVersion:
580         return ProcAppleWMQueryVersion(client);
581     }
582
583     if (!LocalClient(client))
584         return WMErrorBase + AppleWMClientNotLocal;
585
586     switch (stuff->data)
587     {
588     case X_AppleWMSelectInput:
589         return ProcAppleWMSelectInput(client);
590     case X_AppleWMDisableUpdate:
591         return ProcAppleWMDisableUpdate(client);
592     case X_AppleWMReenableUpdate:
593         return ProcAppleWMReenableUpdate(client);
594     case X_AppleWMSetWindowMenu:
595         return ProcAppleWMSetWindowMenu(client);
596     case X_AppleWMSetWindowMenuCheck:
597         return ProcAppleWMSetWindowMenuCheck(client);
598     case X_AppleWMSetFrontProcess:
599         return ProcAppleWMSetFrontProcess(client);
600     case X_AppleWMSetWindowLevel:
601         return ProcAppleWMSetWindowLevel(client);
602     case X_AppleWMSetCanQuit:
603         return ProcAppleWMSetCanQuit(client);
604     case X_AppleWMFrameGetRect:
605         return ProcAppleWMFrameGetRect(client);
606     case X_AppleWMFrameHitTest:
607         return ProcAppleWMFrameHitTest(client);
608     case X_AppleWMFrameDraw:
609         return ProcAppleWMFrameDraw(client);
610     default:
611         return BadRequest;
612     }
613 }
614
615 static void
616 SNotifyEvent(from, to)
617     xAppleWMNotifyEvent *from, *to;
618 {
619     to->type = from->type;
620     to->kind = from->kind;
621     cpswaps (from->sequenceNumber, to->sequenceNumber);
622     cpswapl (from->time, to->time);
623     cpswapl (from->arg, to->arg);
624 }
625
626 static int
627 SProcAppleWMQueryVersion(
628     register ClientPtr  client
629 )
630 {
631     register int n;
632     REQUEST(xAppleWMQueryVersionReq);
633     swaps(&stuff->length, n);
634     return ProcAppleWMQueryVersion(client);
635 }
636
637 static int
638 SProcAppleWMDispatch (
639     register ClientPtr  client
640 )
641 {
642     REQUEST(xReq);
643
644     /* It is bound to be non-local when there is byte swapping */
645     if (!LocalClient(client))
646         return WMErrorBase + AppleWMClientNotLocal;
647
648     /* only local clients are allowed WM access */
649     switch (stuff->data)
650     {
651     case X_AppleWMQueryVersion:
652         return SProcAppleWMQueryVersion(client);
653     default:
654         return BadRequest;
655     }
656 }