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