1 /* WindowsWM extension is based on AppleWM extension */
2 /**************************************************************************
3 
4 Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
5 Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sub license, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
17 of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 **************************************************************************/
28 
29 #ifdef HAVE_XWIN_CONFIG_H
30 #include <xwin-config.h>
31 #endif
32 #include "win.h"
33 
34 #include "misc.h"
35 #include "dixstruct.h"
36 #include "extnsionst.h"
37 #include "colormapst.h"
38 #include "cursorstr.h"
39 #include "scrnintstr.h"
40 #include "servermd.h"
41 #include "swaprep.h"
42 #define _WINDOWSWM_SERVER_
43 #include <X11/extensions/windowswmstr.h>
44 #include "protocol-versions.h"
45 
46 static int WMErrorBase;
47 static unsigned char WMReqCode = 0;
48 static int WMEventBase = 0;
49 
50 static RESTYPE ClientType, eventResourceType;   /* resource types for event masks */
51 static XID eventResource;
52 
53 /* Currently selected events */
54 static unsigned int eventMask = 0;
55 
56 static int WMFreeClient(void *data, XID id);
57 static int WMFreeEvents(void *data, XID id);
58 static void SNotifyEvent(xWindowsWMNotifyEvent * from,
59                          xWindowsWMNotifyEvent * to);
60 
61 typedef struct _WMEvent *WMEventPtr;
62 typedef struct _WMEvent {
63     WMEventPtr next;
64     ClientPtr client;
65     XID clientResource;
66     unsigned int mask;
67 } WMEventRec;
68 
69 static int
ProcWindowsWMQueryVersion(ClientPtr client)70 ProcWindowsWMQueryVersion(ClientPtr client)
71 {
72     xWindowsWMQueryVersionReply rep;
73 
74     REQUEST_SIZE_MATCH(xWindowsWMQueryVersionReq);
75     rep.type = X_Reply;
76     rep.length = 0;
77     rep.sequenceNumber = client->sequence;
78     rep.majorVersion = SERVER_WINDOWSWM_MAJOR_VERSION;
79     rep.minorVersion = SERVER_WINDOWSWM_MINOR_VERSION;
80     rep.patchVersion = SERVER_WINDOWSWM_PATCH_VERSION;
81     if (client->swapped) {
82         swaps(&rep.sequenceNumber);
83         swapl(&rep.length);
84     }
85     WriteToClient(client, sizeof(xWindowsWMQueryVersionReply), &rep);
86     return Success;
87 }
88 
89 /* events */
90 
91 static inline void
updateEventMask(WMEventPtr * pHead)92 updateEventMask(WMEventPtr * pHead)
93 {
94     WMEventPtr pCur;
95 
96     eventMask = 0;
97     for (pCur = *pHead; pCur != NULL; pCur = pCur->next)
98         eventMask |= pCur->mask;
99 }
100 
101  /*ARGSUSED*/ static int
WMFreeClient(void * data,XID id)102 WMFreeClient(void *data, XID id)
103 {
104     WMEventPtr pEvent;
105     WMEventPtr *pHead, pCur, pPrev;
106 
107     pEvent = (WMEventPtr) data;
108     dixLookupResourceByType((void *) &pHead, eventResource, eventResourceType,
109                             NullClient, DixUnknownAccess);
110     if (pHead) {
111         pPrev = 0;
112         for (pCur = *pHead; pCur && pCur != pEvent; pCur = pCur->next)
113             pPrev = pCur;
114         if (pCur) {
115             if (pPrev)
116                 pPrev->next = pEvent->next;
117             else
118                 *pHead = pEvent->next;
119         }
120         updateEventMask(pHead);
121     }
122     free((void *) pEvent);
123     return 1;
124 }
125 
126  /*ARGSUSED*/ static int
WMFreeEvents(void * data,XID id)127 WMFreeEvents(void *data, XID id)
128 {
129     WMEventPtr *pHead, pCur, pNext;
130 
131     pHead = (WMEventPtr *) data;
132     for (pCur = *pHead; pCur; pCur = pNext) {
133         pNext = pCur->next;
134         FreeResource(pCur->clientResource, ClientType);
135         free((void *) pCur);
136     }
137     free((void *) pHead);
138     eventMask = 0;
139     return 1;
140 }
141 
142 static int
ProcWindowsWMSelectInput(ClientPtr client)143 ProcWindowsWMSelectInput(ClientPtr client)
144 {
145     REQUEST(xWindowsWMSelectInputReq);
146     WMEventPtr pEvent, pNewEvent, *pHead;
147     XID clientResource;
148 
149     REQUEST_SIZE_MATCH(xWindowsWMSelectInputReq);
150     dixLookupResourceByType((void *) &pHead, eventResource, eventResourceType,
151                             client, DixWriteAccess);
152     if (stuff->mask != 0) {
153         if (pHead) {
154             /* check for existing entry. */
155             for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
156                 if (pEvent->client == client) {
157                     pEvent->mask = stuff->mask;
158                     updateEventMask(pHead);
159                     return Success;
160                 }
161             }
162         }
163 
164         /* build the entry */
165         pNewEvent = malloc(sizeof(WMEventRec));
166         if (!pNewEvent)
167             return BadAlloc;
168         pNewEvent->next = 0;
169         pNewEvent->client = client;
170         pNewEvent->mask = stuff->mask;
171         /*
172          * add a resource that will be deleted when
173          * the client goes away
174          */
175         clientResource = FakeClientID(client->index);
176         pNewEvent->clientResource = clientResource;
177         if (!AddResource(clientResource, ClientType, (void *) pNewEvent))
178             return BadAlloc;
179         /*
180          * create a resource to contain a pointer to the list
181          * of clients selecting input.  This must be indirect as
182          * the list may be arbitrarily rearranged which cannot be
183          * done through the resource database.
184          */
185         if (!pHead) {
186             pHead = malloc(sizeof(WMEventPtr));
187             if (!pHead ||
188                 !AddResource(eventResource, eventResourceType, (void *) pHead))
189             {
190                 FreeResource(clientResource, RT_NONE);
191                 return BadAlloc;
192             }
193             *pHead = 0;
194         }
195         pNewEvent->next = *pHead;
196         *pHead = pNewEvent;
197         updateEventMask(pHead);
198     }
199     else if (stuff->mask == 0) {
200         /* delete the interest */
201         if (pHead) {
202             pNewEvent = 0;
203             for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
204                 if (pEvent->client == client)
205                     break;
206                 pNewEvent = pEvent;
207             }
208             if (pEvent) {
209                 FreeResource(pEvent->clientResource, ClientType);
210                 if (pNewEvent)
211                     pNewEvent->next = pEvent->next;
212                 else
213                     *pHead = pEvent->next;
214                 free(pEvent);
215                 updateEventMask(pHead);
216             }
217         }
218     }
219     else {
220         client->errorValue = stuff->mask;
221         return BadValue;
222     }
223     return Success;
224 }
225 
226 /*
227  * deliver the event
228  */
229 
230 void
winWindowsWMSendEvent(int type,unsigned int mask,int which,int arg,Window window,int x,int y,int w,int h)231 winWindowsWMSendEvent(int type, unsigned int mask, int which, int arg,
232                       Window window, int x, int y, int w, int h)
233 {
234     WMEventPtr *pHead, pEvent;
235     ClientPtr client;
236     xWindowsWMNotifyEvent se;
237 
238 #if CYGMULTIWINDOW_DEBUG
239     ErrorF("winWindowsWMSendEvent %d %d %d %d,  %d %d - %d %d\n",
240            type, mask, which, arg, x, y, w, h);
241 #endif
242     dixLookupResourceByType((void *) &pHead, eventResource, eventResourceType,
243                             NullClient, DixUnknownAccess);
244     if (!pHead)
245         return;
246     for (pEvent = *pHead; pEvent; pEvent = pEvent->next) {
247         client = pEvent->client;
248 #if CYGMULTIWINDOW_DEBUG
249         ErrorF("winWindowsWMSendEvent - %p\n", client);
250 #endif
251         if ((pEvent->mask & mask) == 0) {
252             continue;
253         }
254 #if CYGMULTIWINDOW_DEBUG
255         ErrorF("winWindowsWMSendEvent - send\n");
256 #endif
257         se.type = type + WMEventBase;
258         se.kind = which;
259         se.window = window;
260         se.arg = arg;
261         se.x = x;
262         se.y = y;
263         se.w = w;
264         se.h = h;
265         se.time = currentTime.milliseconds;
266         WriteEventsToClient(client, 1, (xEvent *) &se);
267     }
268 }
269 
270 /* general utility functions */
271 
272 static int
ProcWindowsWMDisableUpdate(ClientPtr client)273 ProcWindowsWMDisableUpdate(ClientPtr client)
274 {
275     REQUEST_SIZE_MATCH(xWindowsWMDisableUpdateReq);
276 
277     //winDisableUpdate();
278 
279     return Success;
280 }
281 
282 static int
ProcWindowsWMReenableUpdate(ClientPtr client)283 ProcWindowsWMReenableUpdate(ClientPtr client)
284 {
285     REQUEST_SIZE_MATCH(xWindowsWMReenableUpdateReq);
286 
287     //winEnableUpdate();
288 
289     return Success;
290 }
291 
292 /* window functions */
293 
294 static int
ProcWindowsWMSetFrontProcess(ClientPtr client)295 ProcWindowsWMSetFrontProcess(ClientPtr client)
296 {
297     REQUEST_SIZE_MATCH(xWindowsWMSetFrontProcessReq);
298 
299     //QuartzMessageMainThread(kWindowsSetFrontProcess, NULL, 0);
300 
301     return Success;
302 }
303 
304 /* frame functions */
305 
306 static int
ProcWindowsWMFrameGetRect(ClientPtr client)307 ProcWindowsWMFrameGetRect(ClientPtr client)
308 {
309     xWindowsWMFrameGetRectReply rep;
310     RECT rcNew;
311 
312     REQUEST(xWindowsWMFrameGetRectReq);
313 
314 #if CYGMULTIWINDOW_DEBUG
315     ErrorF("ProcWindowsWMFrameGetRect %zu %d\n",
316            (sizeof(xWindowsWMFrameGetRectReq) >> 2), (int) client->req_len);
317 #endif
318 
319     REQUEST_SIZE_MATCH(xWindowsWMFrameGetRectReq);
320     rep.type = X_Reply;
321     rep.length = 0;
322     rep.sequenceNumber = client->sequence;
323 
324     if (stuff->frame_rect != 0) {
325         ErrorF("ProcWindowsWMFrameGetRect - stuff->frame_rect != 0\n");
326         return BadValue;
327     }
328 
329     /* Store the origin, height, and width in a rectangle structure */
330     SetRect(&rcNew, stuff->ix, stuff->iy,
331             stuff->ix + stuff->iw, stuff->iy + stuff->ih);
332 
333 #if CYGMULTIWINDOW_DEBUG
334     ErrorF("ProcWindowsWMFrameGetRect - %d %d %d %d\n",
335            stuff->ix, stuff->iy, stuff->ix + stuff->iw, stuff->iy + stuff->ih);
336 #endif
337 
338     /*
339      * Calculate the required size of the Windows window rectangle,
340      * given the size of the Windows window client area.
341      */
342     AdjustWindowRectEx(&rcNew, stuff->frame_style, FALSE,
343                        stuff->frame_style_ex);
344     rep.x = rcNew.left;
345     rep.y = rcNew.top;
346     rep.w = rcNew.right - rcNew.left;
347     rep.h = rcNew.bottom - rcNew.top;
348 #if CYGMULTIWINDOW_DEBUG
349     ErrorF("ProcWindowsWMFrameGetRect - %d %d %d %d\n",
350            rep.x, rep.y, rep.w, rep.h);
351 #endif
352 
353     WriteToClient(client, sizeof(xWindowsWMFrameGetRectReply), &rep);
354     return Success;
355 }
356 
357 static int
ProcWindowsWMFrameDraw(ClientPtr client)358 ProcWindowsWMFrameDraw(ClientPtr client)
359 {
360     REQUEST(xWindowsWMFrameDrawReq);
361     WindowPtr pWin;
362     win32RootlessWindowPtr pRLWinPriv;
363     RECT rcNew;
364     int nCmdShow, rc;
365     RegionRec newShape;
366 
367     REQUEST_SIZE_MATCH(xWindowsWMFrameDrawReq);
368 
369 #if CYGMULTIWINDOW_DEBUG
370     ErrorF("ProcWindowsWMFrameDraw\n");
371 #endif
372     rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
373     if (rc != Success)
374         return rc;
375 #if CYGMULTIWINDOW_DEBUG
376     ErrorF("ProcWindowsWMFrameDraw - Window found\n");
377 #endif
378 
379     pRLWinPriv = (win32RootlessWindowPtr) RootlessFrameForWindow(pWin, TRUE);
380     if (pRLWinPriv == 0)
381         return BadWindow;
382 
383 #if CYGMULTIWINDOW_DEBUG
384     ErrorF("ProcWindowsWMFrameDraw - HWND %p 0x%08x 0x%08x\n",
385            pRLWinPriv->hWnd, (int) stuff->frame_style,
386            (int) stuff->frame_style_ex);
387     ErrorF("ProcWindowsWMFrameDraw - %d %d %d %d\n",
388            stuff->ix, stuff->iy, stuff->iw, stuff->ih);
389 #endif
390 
391     /* Store the origin, height, and width in a rectangle structure */
392     SetRect(&rcNew, stuff->ix, stuff->iy,
393             stuff->ix + stuff->iw, stuff->iy + stuff->ih);
394 
395     /*
396      * Calculate the required size of the Windows window rectangle,
397      * given the size of the Windows window client area.
398      */
399     AdjustWindowRectEx(&rcNew, stuff->frame_style, FALSE,
400                        stuff->frame_style_ex);
401 
402     /* Set the window extended style flags */
403     if (!SetWindowLongPtr(pRLWinPriv->hWnd, GWL_EXSTYLE, stuff->frame_style_ex)) {
404         return BadValue;
405     }
406 
407     /* Set the window standard style flags */
408     if (!SetWindowLongPtr(pRLWinPriv->hWnd, GWL_STYLE, stuff->frame_style)) {
409         return BadValue;
410     }
411 
412     /* Flush the window style */
413     if (!SetWindowPos(pRLWinPriv->hWnd, NULL,
414                       rcNew.left, rcNew.top,
415                       rcNew.right - rcNew.left, rcNew.bottom - rcNew.top,
416                       SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE)) {
417         return BadValue;
418     }
419     if (!IsWindowVisible(pRLWinPriv->hWnd))
420         nCmdShow = SW_HIDE;
421     else
422         nCmdShow = SW_SHOWNA;
423 
424     ShowWindow(pRLWinPriv->hWnd, nCmdShow);
425 
426     if (wBoundingShape(pWin) != NULL) {
427         /* wBoundingShape is relative to *inner* origin of window.
428            Translate by borderWidth to get the outside-relative position. */
429 
430         RegionNull(&newShape);
431         RegionCopy(&newShape, wBoundingShape(pWin));
432         RegionTranslate(&newShape, pWin->borderWidth, pWin->borderWidth);
433         winMWExtWMReshapeFrame(pRLWinPriv, &newShape);
434         RegionUninit(&newShape);
435     }
436 #if CYGMULTIWINDOW_DEBUG
437     ErrorF("ProcWindowsWMFrameDraw - done\n");
438 #endif
439 
440     return Success;
441 }
442 
443 static int
ProcWindowsWMFrameSetTitle(ClientPtr client)444 ProcWindowsWMFrameSetTitle(ClientPtr client)
445 {
446     unsigned int title_length, title_max;
447     char *title_bytes;
448 
449     REQUEST(xWindowsWMFrameSetTitleReq);
450     WindowPtr pWin;
451     win32RootlessWindowPtr pRLWinPriv;
452     int rc;
453 
454 #if CYGMULTIWINDOW_DEBUG
455     ErrorF("ProcWindowsWMFrameSetTitle\n");
456 #endif
457 
458     REQUEST_AT_LEAST_SIZE(xWindowsWMFrameSetTitleReq);
459 
460     rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
461     if (rc != Success)
462         return rc;
463 #if CYGMULTIWINDOW_DEBUG
464     ErrorF("ProcWindowsWMFrameSetTitle - Window found\n");
465 #endif
466 
467     title_length = stuff->title_length;
468     title_max = (stuff->length << 2) - sizeof(xWindowsWMFrameSetTitleReq);
469 
470     if (title_max < title_length)
471         return BadValue;
472 
473 #if CYGMULTIWINDOW_DEBUG
474     ErrorF("ProcWindowsWMFrameSetTitle - length is valid\n");
475 #endif
476 
477     title_bytes = malloc(title_length + 1);
478     strncpy(title_bytes, (char *) &stuff[1], title_length);
479     title_bytes[title_length] = '\0';
480 
481     pRLWinPriv = (win32RootlessWindowPtr) RootlessFrameForWindow(pWin, FALSE);
482 
483     if (pRLWinPriv == 0) {
484         free(title_bytes);
485         return BadWindow;
486     }
487 
488     /* Flush the window style */
489     SetWindowText(pRLWinPriv->hWnd, title_bytes);
490 
491     free(title_bytes);
492 
493 #if CYGMULTIWINDOW_DEBUG
494     ErrorF("ProcWindowsWMFrameSetTitle - done\n");
495 #endif
496 
497     return Success;
498 }
499 
500 /* dispatch */
501 
502 static int
ProcWindowsWMDispatch(ClientPtr client)503 ProcWindowsWMDispatch(ClientPtr client)
504 {
505     REQUEST(xReq);
506 
507     switch (stuff->data) {
508     case X_WindowsWMQueryVersion:
509         return ProcWindowsWMQueryVersion(client);
510     }
511 
512     if (!client->local)
513         return WMErrorBase + WindowsWMClientNotLocal;
514 
515     switch (stuff->data) {
516     case X_WindowsWMSelectInput:
517         return ProcWindowsWMSelectInput(client);
518     case X_WindowsWMDisableUpdate:
519         return ProcWindowsWMDisableUpdate(client);
520     case X_WindowsWMReenableUpdate:
521         return ProcWindowsWMReenableUpdate(client);
522     case X_WindowsWMSetFrontProcess:
523         return ProcWindowsWMSetFrontProcess(client);
524     case X_WindowsWMFrameGetRect:
525         return ProcWindowsWMFrameGetRect(client);
526     case X_WindowsWMFrameDraw:
527         return ProcWindowsWMFrameDraw(client);
528     case X_WindowsWMFrameSetTitle:
529         return ProcWindowsWMFrameSetTitle(client);
530     default:
531         return BadRequest;
532     }
533 }
534 
535 static void
SNotifyEvent(xWindowsWMNotifyEvent * from,xWindowsWMNotifyEvent * to)536 SNotifyEvent(xWindowsWMNotifyEvent * from, xWindowsWMNotifyEvent * to)
537 {
538     to->type = from->type;
539     to->kind = from->kind;
540     cpswaps(from->sequenceNumber, to->sequenceNumber);
541     cpswapl(from->window, to->window);
542     cpswapl(from->time, to->time);
543     cpswapl(from->arg, to->arg);
544 }
545 
546 static int
SProcWindowsWMQueryVersion(ClientPtr client)547 SProcWindowsWMQueryVersion(ClientPtr client)
548 {
549     REQUEST(xWindowsWMQueryVersionReq);
550     swaps(&stuff->length);
551     return ProcWindowsWMQueryVersion(client);
552 }
553 
554 static int
SProcWindowsWMDispatch(ClientPtr client)555 SProcWindowsWMDispatch(ClientPtr client)
556 {
557     REQUEST(xReq);
558 
559     /* It is bound to be non-local when there is byte swapping */
560     if (!client->local)
561         return WMErrorBase + WindowsWMClientNotLocal;
562 
563     /* only local clients are allowed WM access */
564     switch (stuff->data) {
565     case X_WindowsWMQueryVersion:
566         return SProcWindowsWMQueryVersion(client);
567     default:
568         return BadRequest;
569     }
570 }
571 
572 void
winWindowsWMExtensionInit(void)573 winWindowsWMExtensionInit(void)
574 {
575     ExtensionEntry *extEntry;
576 
577     ClientType = CreateNewResourceType(WMFreeClient, "WMClient");
578     eventResourceType = CreateNewResourceType(WMFreeEvents, "WMEvent");
579     eventResource = FakeClientID(0);
580 
581     if (ClientType && eventResourceType &&
582         (extEntry = AddExtension(WINDOWSWMNAME,
583                                  WindowsWMNumberEvents,
584                                  WindowsWMNumberErrors,
585                                  ProcWindowsWMDispatch,
586                                  SProcWindowsWMDispatch,
587                                  NULL, StandardMinorOpcode))) {
588         size_t i;
589 
590         WMReqCode = (unsigned char) extEntry->base;
591         WMErrorBase = extEntry->errorBase;
592         WMEventBase = extEntry->eventBase;
593         for (i = 0; i < WindowsWMNumberEvents; i++)
594             EventSwapVector[WMEventBase + i] = (EventSwapPtr) SNotifyEvent;
595     }
596 }
597