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
make_box(int x,int y,int w,int h)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
AppleWMExtensionInit(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
AppleWMResetProc(ExtensionEntry * extEntry)115 AppleWMResetProc (
116     ExtensionEntry* extEntry
117 )
118 {
119 }
120 
121 static int
ProcAppleWMQueryVersion(register ClientPtr client)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 
145 /* events */
146 
147 static inline void
updateEventMask(WMEventPtr * pHead)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
WMFreeClient(data,id)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
WMFreeEvents(data,id)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
ProcAppleWMSelectInput(client)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
AppleWMSendEvent(type,mask,which,arg)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
AppleWMSelectedEvents(void)324 AppleWMSelectedEvents (void)
325 {
326     return eventMask;
327 }
328 
329 
330 /* general utility functions */
331 
332 static int
ProcAppleWMDisableUpdate(register ClientPtr client)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
ProcAppleWMReenableUpdate(register ClientPtr client)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 
357 /* window functions */
358 
359 static int
ProcAppleWMSetWindowMenu(register ClientPtr client)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
ProcAppleWMSetWindowMenuCheck(register ClientPtr client)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
ProcAppleWMSetFrontProcess(register ClientPtr client)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
ProcAppleWMSetWindowLevel(register ClientPtr client)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
ProcAppleWMSetCanQuit(register ClientPtr client)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 
460 /* frame functions */
461 
462 static int
ProcAppleWMFrameGetRect(register ClientPtr client)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
ProcAppleWMFrameHitTest(register ClientPtr client)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
ProcAppleWMFrameDraw(register ClientPtr client)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 
568 /* dispatch */
569 
570 static int
ProcAppleWMDispatch(register ClientPtr client)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
SNotifyEvent(from,to)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
SProcAppleWMQueryVersion(register ClientPtr client)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
SProcAppleWMDispatch(register ClientPtr client)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 }
657