tizen 2.4 release
[framework/uifw/xorg/server/xorg-server.git] / hw / xwin / winmultiwindowwm.c
1 /*
2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3  *Copyright (C) Colin Harrison 2005-2009
4  *
5  *Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  *"Software"), to deal in the Software without restriction, including
8  *without limitation the rights to use, copy, modify, merge, publish,
9  *distribute, sublicense, and/or sell copies of the Software, and to
10  *permit persons to whom the Software is furnished to do so, subject to
11  *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 XFREE86 PROJECT BE LIABLE FOR
20  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  *Except as contained in this notice, the name of the XFree86 Project
25  *shall not be used in advertising or otherwise to promote the sale, use
26  *or other dealings in this Software without prior written authorization
27  *from the XFree86 Project.
28  *
29  * Authors:     Kensuke Matsuzaki
30  *              Colin Harrison
31  */
32
33 /* X headers */
34 #ifdef HAVE_XWIN_CONFIG_H
35 #include <xwin-config.h>
36 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #ifdef __CYGWIN__
41 #include <sys/select.h>
42 #endif
43 #include <fcntl.h>
44 #include <setjmp.h>
45 #define HANDLE void *
46 #include <pthread.h>
47 #undef HANDLE
48 #include <X11/X.h>
49 #include <X11/Xatom.h>
50 #include <X11/Xlib.h>
51 #include <X11/Xlocale.h>
52 #include <X11/Xproto.h>
53 #include <X11/Xutil.h>
54 #include <X11/cursorfont.h>
55 #include <X11/Xwindows.h>
56
57 /* Local headers */
58 #include "winwindow.h"
59 #include "winprefs.h"
60 #include "window.h"
61 #include "pixmapstr.h"
62 #include "windowstr.h"
63 #include "winglobals.h"
64
65 #ifdef XWIN_MULTIWINDOWEXTWM
66 #include <X11/extensions/windowswmstr.h>
67 #else
68 /* We need the native HWND atom for intWM, so for consistency use the
69    same name as extWM would if we were building with enabled... */
70 #define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND"
71 #endif
72
73 #ifndef HOST_NAME_MAX
74 #define HOST_NAME_MAX 255
75 #endif
76
77 extern void winDebug(const char *format, ...);
78 extern void winReshapeMultiWindow(WindowPtr pWin);
79 extern void winUpdateRgnMultiWindow(WindowPtr pWin);
80
81 #ifndef CYGDEBUG
82 #define CYGDEBUG NO
83 #endif
84
85 /*
86  * Constant defines
87  */
88
89 #define WIN_CONNECT_RETRIES     5
90 #define WIN_CONNECT_DELAY       5
91 #ifdef HAS_DEVWINDOWS
92 #define WIN_MSG_QUEUE_FNAME     "/dev/windows"
93 #endif
94 #define WIN_JMP_OKAY            0
95 #define WIN_JMP_ERROR_IO        2
96
97 /*
98  * Local structures
99  */
100
101 typedef struct _WMMsgNodeRec {
102     winWMMessageRec msg;
103     struct _WMMsgNodeRec *pNext;
104 } WMMsgNodeRec, *WMMsgNodePtr;
105
106 typedef struct _WMMsgQueueRec {
107     struct _WMMsgNodeRec *pHead;
108     struct _WMMsgNodeRec *pTail;
109     pthread_mutex_t pmMutex;
110     pthread_cond_t pcNotEmpty;
111     int nQueueSize;
112 } WMMsgQueueRec, *WMMsgQueuePtr;
113
114 typedef struct _WMInfo {
115     Display *pDisplay;
116     WMMsgQueueRec wmMsgQueue;
117     Atom atmWmProtos;
118     Atom atmWmDelete;
119     Atom atmWmTakeFocus;
120     Atom atmPrivMap;
121     Bool fAllowOtherWM;
122 } WMInfoRec, *WMInfoPtr;
123
124 typedef struct _WMProcArgRec {
125     DWORD dwScreen;
126     WMInfoPtr pWMInfo;
127     pthread_mutex_t *ppmServerStarted;
128 } WMProcArgRec, *WMProcArgPtr;
129
130 typedef struct _XMsgProcArgRec {
131     Display *pDisplay;
132     DWORD dwScreen;
133     WMInfoPtr pWMInfo;
134     pthread_mutex_t *ppmServerStarted;
135     HWND hwndScreen;
136 } XMsgProcArgRec, *XMsgProcArgPtr;
137
138 /*
139  * Prototypes for local functions
140  */
141
142 static void
143  PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode);
144
145 static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo);
146
147 static Bool
148  InitQueue(WMMsgQueuePtr pQueue);
149
150 static void
151  GetWindowName(Display * pDpy, Window iWin, char **ppWindowName);
152
153 static int
154  SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData);
155
156 static void
157  UpdateName(WMInfoPtr pWMInfo, Window iWindow);
158
159 static void *winMultiWindowWMProc(void *pArg);
160
161 static int
162  winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr);
163
164 static int
165  winMultiWindowWMIOErrorHandler(Display * pDisplay);
166
167 static void *winMultiWindowXMsgProc(void *pArg);
168
169 static int
170  winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr);
171
172 static int
173  winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay);
174
175 static int
176  winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr);
177
178 static void
179  winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg);
180
181 #if 0
182 static void
183  PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction);
184 #endif
185
186 static Bool
187
188 CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen,
189                           Bool fAllowOtherWM);
190
191 static void
192  winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle);
193
194 void
195  winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
196
197 /*
198  * Local globals
199  */
200
201 static jmp_buf g_jmpWMEntry;
202 static XIOErrorHandler g_winMultiWindowWMOldIOErrorHandler;
203 static pthread_t g_winMultiWindowWMThread;
204 static jmp_buf g_jmpXMsgProcEntry;
205 static XIOErrorHandler g_winMultiWindowXMsgProcOldIOErrorHandler;
206 static pthread_t g_winMultiWindowXMsgProcThread;
207 static Bool g_shutdown = FALSE;
208 static Bool redirectError = FALSE;
209 static Bool g_fAnotherWMRunning = FALSE;
210
211 /*
212  * PushMessage - Push a message onto the queue
213  */
214
215 static void
216 PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode)
217 {
218
219     /* Lock the queue mutex */
220     pthread_mutex_lock(&pQueue->pmMutex);
221
222     pNode->pNext = NULL;
223
224     if (pQueue->pTail != NULL) {
225         pQueue->pTail->pNext = pNode;
226     }
227     pQueue->pTail = pNode;
228
229     if (pQueue->pHead == NULL) {
230         pQueue->pHead = pNode;
231     }
232
233 #if 0
234     switch (pNode->msg.msg) {
235     case WM_WM_MOVE:
236         ErrorF("\tWM_WM_MOVE\n");
237         break;
238     case WM_WM_SIZE:
239         ErrorF("\tWM_WM_SIZE\n");
240         break;
241     case WM_WM_RAISE:
242         ErrorF("\tWM_WM_RAISE\n");
243         break;
244     case WM_WM_LOWER:
245         ErrorF("\tWM_WM_LOWER\n");
246         break;
247     case WM_WM_MAP:
248         ErrorF("\tWM_WM_MAP\n");
249         break;
250     case WM_WM_MAP2:
251         ErrorF("\tWM_WM_MAP2\n");
252         break;
253     case WM_WM_MAP3:
254         ErrorF("\tWM_WM_MAP3\n");
255         break;
256     case WM_WM_UNMAP:
257         ErrorF("\tWM_WM_UNMAP\n");
258         break;
259     case WM_WM_KILL:
260         ErrorF("\tWM_WM_KILL\n");
261         break;
262     case WM_WM_ACTIVATE:
263         ErrorF("\tWM_WM_ACTIVATE\n");
264         break;
265     default:
266         ErrorF("\tUnknown Message.\n");
267         break;
268     }
269 #endif
270
271     /* Increase the count of elements in the queue by one */
272     ++(pQueue->nQueueSize);
273
274     /* Release the queue mutex */
275     pthread_mutex_unlock(&pQueue->pmMutex);
276
277     /* Signal that the queue is not empty */
278     pthread_cond_signal(&pQueue->pcNotEmpty);
279 }
280
281 #if CYGMULTIWINDOW_DEBUG
282 /*
283  * QueueSize - Return the size of the queue
284  */
285
286 static int
287 QueueSize(WMMsgQueuePtr pQueue)
288 {
289     WMMsgNodePtr pNode;
290     int nSize = 0;
291
292     /* Loop through all elements in the queue */
293     for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext)
294         ++nSize;
295
296     return nSize;
297 }
298 #endif
299
300 /*
301  * PopMessage - Pop a message from the queue
302  */
303
304 static WMMsgNodePtr
305 PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo)
306 {
307     WMMsgNodePtr pNode;
308
309     /* Lock the queue mutex */
310     pthread_mutex_lock(&pQueue->pmMutex);
311
312     /* Wait for --- */
313     while (pQueue->pHead == NULL) {
314         pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex);
315     }
316
317     pNode = pQueue->pHead;
318     if (pQueue->pHead != NULL) {
319         pQueue->pHead = pQueue->pHead->pNext;
320     }
321
322     if (pQueue->pTail == pNode) {
323         pQueue->pTail = NULL;
324     }
325
326     /* Drop the number of elements in the queue by one */
327     --(pQueue->nQueueSize);
328
329 #if CYGMULTIWINDOW_DEBUG
330     ErrorF("Queue Size %d %d\n", pQueue->nQueueSize, QueueSize(pQueue));
331 #endif
332
333     /* Release the queue mutex */
334     pthread_mutex_unlock(&pQueue->pmMutex);
335
336     return pNode;
337 }
338
339 #if 0
340 /*
341  * HaveMessage - 
342  */
343
344 static Bool
345 HaveMessage(WMMsgQueuePtr pQueue, UINT msg, Window iWindow)
346 {
347     WMMsgNodePtr pNode;
348
349     for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) {
350         if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow)
351             return True;
352     }
353
354     return False;
355 }
356 #endif
357
358 /*
359  * InitQueue - Initialize the Window Manager message queue
360  */
361
362 static
363     Bool
364 InitQueue(WMMsgQueuePtr pQueue)
365 {
366     /* Check if the pQueue pointer is NULL */
367     if (pQueue == NULL) {
368         ErrorF("InitQueue - pQueue is NULL.  Exiting.\n");
369         return FALSE;
370     }
371
372     /* Set the head and tail to NULL */
373     pQueue->pHead = NULL;
374     pQueue->pTail = NULL;
375
376     /* There are no elements initially */
377     pQueue->nQueueSize = 0;
378
379 #if CYGMULTIWINDOW_DEBUG
380     winDebug("InitQueue - Queue Size %d %d\n", pQueue->nQueueSize,
381              QueueSize(pQueue));
382 #endif
383
384     winDebug("InitQueue - Calling pthread_mutex_init\n");
385
386     /* Create synchronization objects */
387     pthread_mutex_init(&pQueue->pmMutex, NULL);
388
389     winDebug("InitQueue - pthread_mutex_init returned\n");
390     winDebug("InitQueue - Calling pthread_cond_init\n");
391
392     pthread_cond_init(&pQueue->pcNotEmpty, NULL);
393
394     winDebug("InitQueue - pthread_cond_init returned\n");
395
396     return TRUE;
397 }
398
399 static
400 char *
401 Xutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp)
402 {
403     int nNum;
404     char **ppList;
405     char *pszReturnData;
406
407     if (Xutf8TextPropertyToTextList(pDisplay, xtp, &ppList, &nNum) >= Success &&
408         nNum > 0 && *ppList) {
409         int i;
410         int iLen = 0;
411
412         for (i = 0; i < nNum; i++)
413             iLen += strlen(ppList[i]);
414         pszReturnData = malloc(iLen + 1);
415         pszReturnData[0] = '\0';
416         for (i = 0; i < nNum; i++)
417             strcat(pszReturnData, ppList[i]);
418         if (ppList)
419             XFreeStringList(ppList);
420     }
421     else {
422         pszReturnData = malloc(1);
423         pszReturnData[0] = '\0';
424     }
425
426     return pszReturnData;
427 }
428
429 /*
430  * GetWindowName - Retrieve the title of an X Window
431  */
432
433 static void
434 GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName)
435 {
436     int nResult;
437     XTextProperty xtpWindowName;
438     XTextProperty xtpClientMachine;
439     char *pszWindowName;
440     char *pszClientMachine;
441     char hostname[HOST_NAME_MAX + 1];
442
443 #if CYGMULTIWINDOW_DEBUG
444     ErrorF("GetWindowName\n");
445 #endif
446
447     /* Intialize ppWindowName to NULL */
448     *ppWindowName = NULL;
449
450     /* Try to get window name */
451     nResult = XGetWMName(pDisplay, iWin, &xtpWindowName);
452     if (!nResult || !xtpWindowName.value || !xtpWindowName.nitems) {
453 #if CYGMULTIWINDOW_DEBUG
454         ErrorF("GetWindowName - XGetWMName failed.  No name.\n");
455 #endif
456         return;
457     }
458
459     pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName);
460     XFree(xtpWindowName.value);
461
462     if (g_fHostInTitle) {
463         /* Try to get client machine name */
464         nResult = XGetWMClientMachine(pDisplay, iWin, &xtpClientMachine);
465         if (nResult && xtpClientMachine.value && xtpClientMachine.nitems) {
466             pszClientMachine =
467                 Xutf8TextPropertyToString(pDisplay, &xtpClientMachine);
468             XFree(xtpClientMachine.value);
469
470             /*
471                If we have a client machine name
472                and it's not the local host name
473                and it's not already in the window title...
474              */
475             if (strlen(pszClientMachine) &&
476                 !gethostname(hostname, HOST_NAME_MAX + 1) &&
477                 strcmp(hostname, pszClientMachine) &&
478                 (strstr(pszWindowName, pszClientMachine) == 0)) {
479                 /* ... add '@<clientmachine>' to end of window name */
480                 *ppWindowName =
481                     malloc(strlen(pszWindowName) +
482                            strlen(pszClientMachine) + 2);
483                 strcpy(*ppWindowName, pszWindowName);
484                 strcat(*ppWindowName, "@");
485                 strcat(*ppWindowName, pszClientMachine);
486
487                 free(pszWindowName);
488                 free(pszClientMachine);
489
490                 return;
491             }
492         }
493     }
494
495     /* otherwise just return the window name */
496     *ppWindowName = pszWindowName;
497 }
498
499 /*
500  * Does the client support the specified WM_PROTOCOLS protocol?
501  */
502
503 static Bool
504 IsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom atmProtocol)
505 {
506   int i, n, found = 0;
507   Atom *protocols;
508
509   if (XGetWMProtocols(pDisplay, iWindow, &protocols, &n)) {
510     for (i = 0; i < n; ++i)
511       if (protocols[i] == atmProtocol)
512         ++found;
513
514     XFree(protocols);
515   }
516
517   return found > 0;
518 }
519
520 /*
521  * Send a message to the X server from the WM thread
522  */
523
524 static int
525 SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData)
526 {
527     XEvent e;
528
529     /* Prepare the X event structure */
530     e.type = ClientMessage;
531     e.xclient.window = iWin;
532     e.xclient.message_type = atmType;
533     e.xclient.format = 32;
534     e.xclient.data.l[0] = nData;
535     e.xclient.data.l[1] = CurrentTime;
536
537     /* Send the event to X */
538     return XSendEvent(pDisplay, iWin, False, NoEventMask, &e);
539 }
540
541 /*
542  * See if we can get the stored HWND for this window...
543  */
544 static HWND
545 getHwnd(WMInfoPtr pWMInfo, Window iWindow)
546 {
547     Atom atmType;
548     int fmtRet;
549     unsigned long items, remain;
550     HWND *retHwnd, hWnd = NULL;
551
552     if (XGetWindowProperty(pWMInfo->pDisplay,
553                            iWindow,
554                            pWMInfo->atmPrivMap,
555                            0,
556                            sizeof(HWND)/4,
557                            False,
558                            XA_INTEGER,
559                            &atmType,
560                            &fmtRet,
561                            &items,
562                            &remain, (unsigned char **) &retHwnd) == Success) {
563         if (retHwnd) {
564             hWnd = *retHwnd;
565             XFree(retHwnd);
566         }
567     }
568
569     /* Some sanity checks */
570     if (!hWnd)
571         return NULL;
572     if (!IsWindow(hWnd))
573         return NULL;
574
575     return hWnd;
576 }
577
578 /*
579  * Updates the name of a HWND according to its X WM_NAME property
580  */
581
582 static void
583 UpdateName(WMInfoPtr pWMInfo, Window iWindow)
584 {
585     HWND hWnd;
586     XWindowAttributes attr;
587
588     hWnd = getHwnd(pWMInfo, iWindow);
589     if (!hWnd)
590         return;
591
592     /* If window isn't override-redirect */
593     XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr);
594     if (!attr.override_redirect) {
595         char *pszWindowName;
596
597         /* Get the X windows window name */
598         GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName);
599
600         if (pszWindowName) {
601             /* Convert from UTF-8 to wide char */
602             int iLen =
603                 MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0);
604             wchar_t *pwszWideWindowName =
605                 malloc(sizeof(wchar_t)*(iLen + 1));
606             MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1,
607                                 pwszWideWindowName, iLen);
608
609             /* Set the Windows window name */
610             SetWindowTextW(hWnd, pwszWideWindowName);
611
612             free(pwszWideWindowName);
613             free(pszWindowName);
614         }
615     }
616 }
617
618 /*
619  * Updates the icon of a HWND according to its X icon properties
620  */
621
622 static void
623 UpdateIcon(WMInfoPtr pWMInfo, Window iWindow)
624 {
625     HWND hWnd;
626     HICON hIconNew = NULL;
627     XWindowAttributes attr;
628
629     hWnd = getHwnd(pWMInfo, iWindow);
630     if (!hWnd)
631         return;
632
633     /* If window isn't override-redirect */
634     XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr);
635     if (!attr.override_redirect) {
636         XClassHint class_hint = { 0, 0 };
637         char *window_name = 0;
638
639         if (XGetClassHint(pWMInfo->pDisplay, iWindow, &class_hint)) {
640             XFetchName(pWMInfo->pDisplay, iWindow, &window_name);
641
642             hIconNew =
643                 (HICON) winOverrideIcon(class_hint.res_name,
644                                         class_hint.res_class, window_name);
645
646             if (class_hint.res_name)
647                 XFree(class_hint.res_name);
648             if (class_hint.res_class)
649                 XFree(class_hint.res_class);
650             if (window_name)
651                 XFree(window_name);
652         }
653     }
654
655     winUpdateIcon(hWnd, pWMInfo->pDisplay, iWindow, hIconNew);
656 }
657
658 /*
659  * Updates the style of a HWND according to its X style properties
660  */
661
662 static void
663 UpdateStyle(WMInfoPtr pWMInfo, Window iWindow)
664 {
665     HWND hWnd;
666     HWND zstyle = HWND_NOTOPMOST;
667     UINT flags;
668
669     hWnd = getHwnd(pWMInfo, iWindow);
670     if (!hWnd)
671         return;
672
673     /* Determine the Window style, which determines borders and clipping region... */
674     winApplyHints(pWMInfo->pDisplay, iWindow, hWnd, &zstyle);
675     winUpdateWindowPosition(hWnd, &zstyle);
676
677     /* Apply the updated window style, without changing it's show or activation state */
678     flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
679     if (zstyle == HWND_NOTOPMOST)
680         flags |= SWP_NOZORDER | SWP_NOOWNERZORDER;
681     SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags);
682
683     /*
684        Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
685
686        According to MSDN, this is supposed to remove the window from the taskbar as well,
687        if we SW_HIDE before changing the style followed by SW_SHOW afterwards.
688
689        But that doesn't seem to work reliably, and causes the window to flicker, so use
690        the iTaskbarList interface to tell the taskbar to show or hide this window.
691      */
692     winShowWindowOnTaskbar(hWnd,
693                            (GetWindowLongPtr(hWnd, GWL_EXSTYLE) &
694                             WS_EX_APPWINDOW) ? TRUE : FALSE);
695 }
696
697 #if 0
698 /*
699  * Fix up any differences between the X11 and Win32 window stacks
700  * starting at the window passed in
701  */
702 static void
703 PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction)
704 {
705     HWND hWnd;
706     DWORD myWinProcID, winProcID;
707     Window xWindow;
708     WINDOWPLACEMENT wndPlace;
709
710     hWnd = getHwnd(pWMInfo, iWindow);
711     if (!hWnd)
712         return;
713
714     GetWindowThreadProcessId(hWnd, &myWinProcID);
715     hWnd = GetNextWindow(hWnd, direction);
716
717     while (hWnd) {
718         GetWindowThreadProcessId(hWnd, &winProcID);
719         if (winProcID == myWinProcID) {
720             wndPlace.length = sizeof(WINDOWPLACEMENT);
721             GetWindowPlacement(hWnd, &wndPlace);
722             if (!(wndPlace.showCmd == SW_HIDE ||
723                   wndPlace.showCmd == SW_MINIMIZE)) {
724                 xWindow = (Window) GetProp(hWnd, WIN_WID_PROP);
725                 if (xWindow) {
726                     if (direction == GW_HWNDPREV)
727                         XRaiseWindow(pWMInfo->pDisplay, xWindow);
728                     else
729                         XLowerWindow(pWMInfo->pDisplay, xWindow);
730                 }
731             }
732         }
733         hWnd = GetNextWindow(hWnd, direction);
734     }
735 }
736 #endif                          /* PreserveWin32Stack */
737
738 /*
739  * winMultiWindowWMProc
740  */
741
742 static void *
743 winMultiWindowWMProc(void *pArg)
744 {
745     WMProcArgPtr pProcArg = (WMProcArgPtr) pArg;
746     WMInfoPtr pWMInfo = pProcArg->pWMInfo;
747
748     /* Initialize the Window Manager */
749     winInitMultiWindowWM(pWMInfo, pProcArg);
750
751 #if CYGMULTIWINDOW_DEBUG
752     ErrorF("winMultiWindowWMProc ()\n");
753 #endif
754
755     /* Loop until we explicitly break out */
756     for (;;) {
757         WMMsgNodePtr pNode;
758
759         if (g_fAnotherWMRunning) {      /* Another Window manager exists. */
760             Sleep(1000);
761             continue;
762         }
763
764         /* Pop a message off of our queue */
765         pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo);
766         if (pNode == NULL) {
767             /* Bail if PopMessage returns without a message */
768             /* NOTE: Remember that PopMessage is a blocking function. */
769             ErrorF("winMultiWindowWMProc - Queue is Empty?  Exiting.\n");
770             pthread_exit(NULL);
771         }
772
773 #if CYGMULTIWINDOW_DEBUG
774         ErrorF("winMultiWindowWMProc - %d ms MSG: %d ID: %d\n",
775                GetTickCount(), (int) pNode->msg.msg, (int) pNode->msg.dwID);
776 #endif
777
778         /* Branch on the message type */
779         switch (pNode->msg.msg) {
780 #if 0
781         case WM_WM_MOVE:
782             ErrorF("\tWM_WM_MOVE\n");
783             break;
784
785         case WM_WM_SIZE:
786             ErrorF("\tWM_WM_SIZE\n");
787             break;
788 #endif
789
790         case WM_WM_RAISE:
791 #if CYGMULTIWINDOW_DEBUG
792             ErrorF("\tWM_WM_RAISE\n");
793 #endif
794             /* Raise the window */
795             XRaiseWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
796 #if 0
797             PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV);
798 #endif
799             break;
800
801         case WM_WM_LOWER:
802 #if CYGMULTIWINDOW_DEBUG
803             ErrorF("\tWM_WM_LOWER\n");
804 #endif
805
806             /* Lower the window */
807             XLowerWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
808             break;
809
810         case WM_WM_MAP:
811 #if CYGMULTIWINDOW_DEBUG
812             ErrorF("\tWM_WM_MAP\n");
813 #endif
814             /* Put a note as to the HWND associated with this Window */
815             XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
816                             32,
817                             PropModeReplace,
818                             (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
819             UpdateName(pWMInfo, pNode->msg.iWindow);
820             UpdateIcon(pWMInfo, pNode->msg.iWindow);
821             break;
822
823         case WM_WM_MAP2:
824 #if CYGMULTIWINDOW_DEBUG
825             ErrorF("\tWM_WM_MAP2\n");
826 #endif
827             XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
828                             32,
829                             PropModeReplace,
830                             (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
831             break;
832
833         case WM_WM_MAP3:
834 #if CYGMULTIWINDOW_DEBUG
835             ErrorF("\tWM_WM_MAP3\n");
836 #endif
837             /* Put a note as to the HWND associated with this Window */
838             XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
839                             32,
840                             PropModeReplace,
841                             (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
842             UpdateName(pWMInfo, pNode->msg.iWindow);
843             UpdateIcon(pWMInfo, pNode->msg.iWindow);
844             UpdateStyle(pWMInfo, pNode->msg.iWindow);
845
846
847             /* Reshape */
848             {
849                 WindowPtr pWin =
850                     GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP);
851                 if (pWin) {
852                     winReshapeMultiWindow(pWin);
853                     winUpdateRgnMultiWindow(pWin);
854                 }
855             }
856
857             break;
858
859         case WM_WM_UNMAP:
860 #if CYGMULTIWINDOW_DEBUG
861             ErrorF("\tWM_WM_UNMAP\n");
862 #endif
863
864             /* Unmap the window */
865             XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
866             break;
867
868         case WM_WM_KILL:
869 #if CYGMULTIWINDOW_DEBUG
870             ErrorF("\tWM_WM_KILL\n");
871 #endif
872             {
873                 /* --- */
874                 if (IsWmProtocolAvailable(pWMInfo->pDisplay,
875                                           pNode->msg.iWindow,
876                                           pWMInfo->atmWmDelete))
877                     SendXMessage(pWMInfo->pDisplay,
878                                  pNode->msg.iWindow,
879                                  pWMInfo->atmWmProtos, pWMInfo->atmWmDelete);
880                 else
881                     XKillClient(pWMInfo->pDisplay, pNode->msg.iWindow);
882             }
883             break;
884
885         case WM_WM_ACTIVATE:
886 #if CYGMULTIWINDOW_DEBUG
887             ErrorF("\tWM_WM_ACTIVATE\n");
888 #endif
889             /* Set the input focus */
890
891             /*
892                ICCCM 4.1.7 is pretty opaque, but it appears that the rules are
893                actually quite simple:
894                -- the WM_HINTS input field determines whether the WM should call
895                XSetInputFocus()
896                -- independently, the WM_TAKE_FOCUS protocol determines whether
897                the WM should send a WM_TAKE_FOCUS ClientMessage.
898             */
899             {
900               Bool neverFocus = FALSE;
901               XWMHints *hints = XGetWMHints(pWMInfo->pDisplay, pNode->msg.iWindow);
902
903               if (hints) {
904                 if (hints->flags & InputHint)
905                   neverFocus = !hints->input;
906                 XFree(hints);
907               }
908
909               if (!neverFocus)
910                 XSetInputFocus(pWMInfo->pDisplay,
911                                pNode->msg.iWindow,
912                                RevertToPointerRoot, CurrentTime);
913
914               if (IsWmProtocolAvailable(pWMInfo->pDisplay,
915                                         pNode->msg.iWindow,
916                                         pWMInfo->atmWmTakeFocus))
917                 SendXMessage(pWMInfo->pDisplay,
918                              pNode->msg.iWindow,
919                              pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus);
920
921             }
922             break;
923
924         case WM_WM_NAME_EVENT:
925             UpdateName(pWMInfo, pNode->msg.iWindow);
926             break;
927
928         case WM_WM_ICON_EVENT:
929             UpdateIcon(pWMInfo, pNode->msg.iWindow);
930             break;
931
932         case WM_WM_HINTS_EVENT:
933             {
934             XWindowAttributes attr;
935
936             /* Don't do anything if this is an override-redirect window */
937             XGetWindowAttributes (pWMInfo->pDisplay, pNode->msg.iWindow, &attr);
938             if (attr.override_redirect)
939               break;
940
941             UpdateStyle(pWMInfo, pNode->msg.iWindow);
942             }
943             break;
944
945         case WM_WM_CHANGE_STATE:
946             /* Minimize the window in Windows */
947             winMinimizeWindow(pNode->msg.iWindow);
948             break;
949
950         default:
951             ErrorF("winMultiWindowWMProc - Unknown Message.  Exiting.\n");
952             pthread_exit(NULL);
953             break;
954         }
955
956         /* Free the retrieved message */
957         free(pNode);
958
959         /* Flush any pending events on our display */
960         XFlush(pWMInfo->pDisplay);
961     }
962
963     /* Free the condition variable */
964     pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty);
965
966     /* Free the mutex variable */
967     pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex);
968
969     /* Free the passed-in argument */
970     free(pProcArg);
971
972 #if CYGMULTIWINDOW_DEBUG
973     ErrorF("-winMultiWindowWMProc ()\n");
974 #endif
975     return NULL;
976 }
977
978 /*
979  * X message procedure
980  */
981
982 static void *
983 winMultiWindowXMsgProc(void *pArg)
984 {
985     winWMMessageRec msg;
986     XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg;
987     char pszDisplay[512];
988     int iRetries;
989     XEvent event;
990     Atom atmWmName;
991     Atom atmWmHints;
992     Atom atmWmChange;
993     Atom atmNetWmIcon;
994     Atom atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
995     int iReturn;
996     XIconSize *xis;
997
998     winDebug("winMultiWindowXMsgProc - Hello\n");
999
1000     /* Check that argument pointer is not invalid */
1001     if (pProcArg == NULL) {
1002         ErrorF("winMultiWindowXMsgProc - pProcArg is NULL.  Exiting.\n");
1003         pthread_exit(NULL);
1004     }
1005
1006     ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
1007
1008     /* Grab the server started mutex - pause until we get it */
1009     iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
1010     if (iReturn != 0) {
1011         ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d.  "
1012                "Exiting.\n", iReturn);
1013         pthread_exit(NULL);
1014     }
1015
1016     ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
1017
1018     /* Allow multiple threads to access Xlib */
1019     if (XInitThreads() == 0) {
1020         ErrorF("winMultiWindowXMsgProc - XInitThreads () failed.  Exiting.\n");
1021         pthread_exit(NULL);
1022     }
1023
1024     /* See if X supports the current locale */
1025     if (XSupportsLocale() == False) {
1026         ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n");
1027     }
1028
1029     /* Release the server started mutex */
1030     pthread_mutex_unlock(pProcArg->ppmServerStarted);
1031
1032     ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
1033
1034     /* Install our error handler */
1035     XSetErrorHandler(winMultiWindowXMsgProcErrorHandler);
1036     g_winMultiWindowXMsgProcThread = pthread_self();
1037     g_winMultiWindowXMsgProcOldIOErrorHandler =
1038         XSetIOErrorHandler(winMultiWindowXMsgProcIOErrorHandler);
1039
1040     /* Set jump point for IO Error exits */
1041     iReturn = setjmp(g_jmpXMsgProcEntry);
1042
1043     /* Check if we should continue operations */
1044     if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) {
1045         /* setjmp returned an unknown value, exit */
1046         ErrorF("winInitMultiWindowXMsgProc - setjmp returned: %d.  Exiting.\n",
1047                iReturn);
1048         pthread_exit(NULL);
1049     }
1050     else if (iReturn == WIN_JMP_ERROR_IO) {
1051         ErrorF("winInitMultiWindowXMsgProc - Caught IO Error.  Exiting.\n");
1052         pthread_exit(NULL);
1053     }
1054
1055     /* Setup the display connection string x */
1056     snprintf(pszDisplay,
1057              512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen);
1058
1059     /* Print the display connection string */
1060     ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay);
1061
1062     /* Use our generated cookie for authentication */
1063     winSetAuthorization();
1064
1065     /* Initialize retry count */
1066     iRetries = 0;
1067
1068     /* Open the X display */
1069     do {
1070         /* Try to open the display */
1071         pProcArg->pDisplay = XOpenDisplay(pszDisplay);
1072         if (pProcArg->pDisplay == NULL) {
1073             ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, "
1074                    "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
1075             ++iRetries;
1076             sleep(WIN_CONNECT_DELAY);
1077             continue;
1078         }
1079         else
1080             break;
1081     }
1082     while (pProcArg->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
1083
1084     /* Make sure that the display opened */
1085     if (pProcArg->pDisplay == NULL) {
1086         ErrorF("winMultiWindowXMsgProc - Failed opening the display.  "
1087                "Exiting.\n");
1088         pthread_exit(NULL);
1089     }
1090
1091     ErrorF("winMultiWindowXMsgProc - XOpenDisplay () returned and "
1092            "successfully opened the display.\n");
1093
1094     /* Check if another window manager is already running */
1095     g_fAnotherWMRunning =
1096         CheckAnotherWindowManager(pProcArg->pDisplay, pProcArg->dwScreen,
1097                                   pProcArg->pWMInfo->fAllowOtherWM);
1098
1099     if (g_fAnotherWMRunning && !pProcArg->pWMInfo->fAllowOtherWM) {
1100         ErrorF("winMultiWindowXMsgProc - "
1101                "another window manager is running.  Exiting.\n");
1102         pthread_exit(NULL);
1103     }
1104
1105     /* Set up the supported icon sizes */
1106     xis = XAllocIconSize();
1107     if (xis) {
1108         xis->min_width = xis->min_height = 16;
1109         xis->max_width = xis->max_height = 48;
1110         xis->width_inc = xis->height_inc = 16;
1111         XSetIconSizes(pProcArg->pDisplay,
1112                       RootWindow(pProcArg->pDisplay, pProcArg->dwScreen),
1113                       xis, 1);
1114         XFree(xis);
1115     }
1116
1117     atmWmName = XInternAtom(pProcArg->pDisplay, "WM_NAME", False);
1118     atmWmHints = XInternAtom(pProcArg->pDisplay, "WM_HINTS", False);
1119     atmWmChange = XInternAtom(pProcArg->pDisplay, "WM_CHANGE_STATE", False);
1120     atmNetWmIcon = XInternAtom(pProcArg->pDisplay, "_NET_WM_ICON", False);
1121     atmWindowState = XInternAtom(pProcArg->pDisplay, "_NET_WM_STATE", False);
1122     atmMotifWmHints = XInternAtom(pProcArg->pDisplay, "_MOTIF_WM_HINTS", False);
1123     atmWindowType = XInternAtom(pProcArg->pDisplay, "_NET_WM_WINDOW_TYPE", False);
1124     atmNormalHints = XInternAtom(pProcArg->pDisplay, "WM_NORMAL_HINTS", False);
1125
1126     /*
1127        iiimxcf had a bug until 2009-04-27, assuming that the
1128        WM_STATE atom exists, causing clients to fail with
1129        a BadAtom X error if it doesn't.
1130
1131        Since this is on in the default Solaris 10 install,
1132        workaround this by making sure it does exist...
1133      */
1134     XInternAtom(pProcArg->pDisplay, "WM_STATE", 0);
1135
1136     /* Loop until we explicitly break out */
1137     while (1) {
1138         if (g_shutdown)
1139             break;
1140
1141         if (pProcArg->pWMInfo->fAllowOtherWM && !XPending(pProcArg->pDisplay)) {
1142             if (CheckAnotherWindowManager
1143                 (pProcArg->pDisplay, pProcArg->dwScreen, TRUE)) {
1144                 if (!g_fAnotherWMRunning) {
1145                     g_fAnotherWMRunning = TRUE;
1146                     SendMessage(pProcArg->hwndScreen, WM_UNMANAGE, 0, 0);
1147                 }
1148             }
1149             else {
1150                 if (g_fAnotherWMRunning) {
1151                     g_fAnotherWMRunning = FALSE;
1152                     SendMessage(pProcArg->hwndScreen, WM_MANAGE, 0, 0);
1153                 }
1154             }
1155             Sleep(500);
1156             continue;
1157         }
1158
1159         /* Fetch next event */
1160         XNextEvent(pProcArg->pDisplay, &event);
1161
1162         /* Branch on event type */
1163         if (event.type == CreateNotify) {
1164             XWindowAttributes attr;
1165
1166             XSelectInput(pProcArg->pDisplay,
1167                          event.xcreatewindow.window, PropertyChangeMask);
1168
1169             /* Get the window attributes */
1170             XGetWindowAttributes(pProcArg->pDisplay,
1171                                  event.xcreatewindow.window, &attr);
1172
1173             if (!attr.override_redirect)
1174                 XSetWindowBorderWidth(pProcArg->pDisplay,
1175                                       event.xcreatewindow.window, 0);
1176         }
1177         else if (event.type == MapNotify) {
1178             /* Fake a reparentNotify event as SWT/Motif expects a
1179                Window Manager to reparent a top-level window when
1180                it is mapped and waits until they do.
1181
1182                We don't actually need to reparent, as the frame is
1183                a native window, not an X window
1184
1185                We do this on MapNotify, not MapRequest like a real
1186                Window Manager would, so we don't have do get involved
1187                in actually mapping the window via it's (non-existent)
1188                parent...
1189
1190                See sourceware bugzilla #9848
1191              */
1192
1193             XWindowAttributes attr;
1194             Window root;
1195             Window parent;
1196             Window *children;
1197             unsigned int nchildren;
1198
1199             if (XGetWindowAttributes(event.xmap.display,
1200                                      event.xmap.window,
1201                                      &attr) &&
1202                 XQueryTree(event.xmap.display,
1203                            event.xmap.window,
1204                            &root, &parent, &children, &nchildren)) {
1205                 if (children)
1206                     XFree(children);
1207
1208                 /*
1209                    It's a top-level window if the parent window is a root window
1210                    Only non-override_redirect windows can get reparented
1211                  */
1212                 if ((attr.root == parent) && !event.xmap.override_redirect) {
1213                     XEvent event_send;
1214
1215                     event_send.type = ReparentNotify;
1216                     event_send.xreparent.event = event.xmap.window;
1217                     event_send.xreparent.window = event.xmap.window;
1218                     event_send.xreparent.parent = parent;
1219                     event_send.xreparent.x = attr.x;
1220                     event_send.xreparent.y = attr.y;
1221
1222                     XSendEvent(event.xmap.display,
1223                                event.xmap.window,
1224                                True, StructureNotifyMask, &event_send);
1225                 }
1226             }
1227         }
1228         else if (event.type == ConfigureNotify) {
1229             if (!event.xconfigure.send_event) {
1230                 /*
1231                    Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT
1232                    doesn't explicitly know about (See sun bug #6434227)
1233
1234                    XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic
1235                    ConfigureNotify events to update window location if it's identified the
1236                    WM as a non-reparenting WM it knows about (compiz or lookingglass)
1237
1238                    Rather than tell all sorts of lies to get XWM to recognize us as one of
1239                    those, simply send a synthetic ConfigureNotify for every non-synthetic one
1240                  */
1241                 XEvent event_send = event;
1242
1243                 event_send.xconfigure.send_event = TRUE;
1244                 event_send.xconfigure.event = event.xconfigure.window;
1245                 XSendEvent(event.xconfigure.display,
1246                            event.xconfigure.window,
1247                            True, StructureNotifyMask, &event_send);
1248             }
1249         }
1250         else if (event.type == PropertyNotify) {
1251             if (event.xproperty.atom == atmWmName) {
1252                 memset(&msg, 0, sizeof(msg));
1253
1254                 msg.msg = WM_WM_NAME_EVENT;
1255                 msg.iWindow = event.xproperty.window;
1256
1257                 /* Other fields ignored */
1258                 winSendMessageToWM(pProcArg->pWMInfo, &msg);
1259             }
1260             else {
1261                 /*
1262                    Several properties are considered for WM hints, check if this property change affects any of them...
1263                    (this list needs to be kept in sync with winApplyHints())
1264                  */
1265                 if ((event.xproperty.atom == atmWmHints) ||
1266                     (event.xproperty.atom == atmWindowState) ||
1267                     (event.xproperty.atom == atmMotifWmHints) ||
1268                     (event.xproperty.atom == atmWindowType) ||
1269                     (event.xproperty.atom == atmNormalHints)) {
1270                     memset(&msg, 0, sizeof(msg));
1271                     msg.msg = WM_WM_HINTS_EVENT;
1272                     msg.iWindow = event.xproperty.window;
1273
1274                     /* Other fields ignored */
1275                     winSendMessageToWM(pProcArg->pWMInfo, &msg);
1276                 }
1277
1278                 /* Not an else as WM_HINTS affects both style and icon */
1279                 if ((event.xproperty.atom == atmWmHints) ||
1280                     (event.xproperty.atom == atmNetWmIcon)) {
1281                     memset(&msg, 0, sizeof(msg));
1282                     msg.msg = WM_WM_ICON_EVENT;
1283                     msg.iWindow = event.xproperty.window;
1284
1285                     /* Other fields ignored */
1286                     winSendMessageToWM(pProcArg->pWMInfo, &msg);
1287                 }
1288             }
1289         }
1290         else if (event.type == ClientMessage
1291                  && event.xclient.message_type == atmWmChange
1292                  && event.xclient.data.l[0] == IconicState) {
1293             ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n");
1294
1295             memset(&msg, 0, sizeof(msg));
1296
1297             msg.msg = WM_WM_CHANGE_STATE;
1298             msg.iWindow = event.xclient.window;
1299
1300             winSendMessageToWM(pProcArg->pWMInfo, &msg);
1301         }
1302     }
1303
1304     XCloseDisplay(pProcArg->pDisplay);
1305     pthread_exit(NULL);
1306     return NULL;
1307 }
1308
1309 /*
1310  * winInitWM - Entry point for the X server to spawn
1311  * the Window Manager thread.  Called from
1312  * winscrinit.c/winFinishScreenInitFB ().
1313  */
1314
1315 Bool
1316 winInitWM(void **ppWMInfo,
1317           pthread_t * ptWMProc,
1318           pthread_t * ptXMsgProc,
1319           pthread_mutex_t * ppmServerStarted,
1320           int dwScreen, HWND hwndScreen, BOOL allowOtherWM)
1321 {
1322     WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
1323     WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
1324     XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec));
1325
1326     /* Bail if the input parameters are bad */
1327     if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) {
1328         ErrorF("winInitWM - malloc failed.\n");
1329         free(pArg);
1330         free(pWMInfo);
1331         free(pXMsgArg);
1332         return FALSE;
1333     }
1334
1335     /* Zero the allocated memory */
1336     ZeroMemory(pArg, sizeof(WMProcArgRec));
1337     ZeroMemory(pWMInfo, sizeof(WMInfoRec));
1338     ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec));
1339
1340     /* Set a return pointer to the Window Manager info structure */
1341     *ppWMInfo = pWMInfo;
1342     pWMInfo->fAllowOtherWM = allowOtherWM;
1343
1344     /* Setup the argument structure for the thread function */
1345     pArg->dwScreen = dwScreen;
1346     pArg->pWMInfo = pWMInfo;
1347     pArg->ppmServerStarted = ppmServerStarted;
1348
1349     /* Intialize the message queue */
1350     if (!InitQueue(&pWMInfo->wmMsgQueue)) {
1351         ErrorF("winInitWM - InitQueue () failed.\n");
1352         return FALSE;
1353     }
1354
1355     /* Spawn a thread for the Window Manager */
1356     if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) {
1357         /* Bail if thread creation failed */
1358         ErrorF("winInitWM - pthread_create failed for Window Manager.\n");
1359         return FALSE;
1360     }
1361
1362     /* Spawn the XNextEvent thread, will send messages to WM */
1363     pXMsgArg->dwScreen = dwScreen;
1364     pXMsgArg->pWMInfo = pWMInfo;
1365     pXMsgArg->ppmServerStarted = ppmServerStarted;
1366     pXMsgArg->hwndScreen = hwndScreen;
1367     if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) {
1368         /* Bail if thread creation failed */
1369         ErrorF("winInitWM - pthread_create failed on XMSG.\n");
1370         return FALSE;
1371     }
1372
1373 #if CYGDEBUG || YES
1374     winDebug("winInitWM - Returning.\n");
1375 #endif
1376
1377     return TRUE;
1378 }
1379
1380 /*
1381  * Window manager thread - setup
1382  */
1383
1384 static void
1385 winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
1386 {
1387     int iRetries = 0;
1388     char pszDisplay[512];
1389     int iReturn;
1390
1391     winDebug("winInitMultiWindowWM - Hello\n");
1392
1393     /* Check that argument pointer is not invalid */
1394     if (pProcArg == NULL) {
1395         ErrorF("winInitMultiWindowWM - pProcArg is NULL.  Exiting.\n");
1396         pthread_exit(NULL);
1397     }
1398
1399     ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
1400
1401     /* Grab our garbage mutex to satisfy pthread_cond_wait */
1402     iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
1403     if (iReturn != 0) {
1404         ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d.  "
1405                "Exiting.\n", iReturn);
1406         pthread_exit(NULL);
1407     }
1408
1409     ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
1410
1411     /* Allow multiple threads to access Xlib */
1412     if (XInitThreads() == 0) {
1413         ErrorF("winInitMultiWindowWM - XInitThreads () failed.  Exiting.\n");
1414         pthread_exit(NULL);
1415     }
1416
1417     /* See if X supports the current locale */
1418     if (XSupportsLocale() == False) {
1419         ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n");
1420     }
1421
1422     /* Release the server started mutex */
1423     pthread_mutex_unlock(pProcArg->ppmServerStarted);
1424
1425     ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
1426
1427     /* Install our error handler */
1428     XSetErrorHandler(winMultiWindowWMErrorHandler);
1429     g_winMultiWindowWMThread = pthread_self();
1430     g_winMultiWindowWMOldIOErrorHandler =
1431         XSetIOErrorHandler(winMultiWindowWMIOErrorHandler);
1432
1433     /* Set jump point for IO Error exits */
1434     iReturn = setjmp(g_jmpWMEntry);
1435
1436     /* Check if we should continue operations */
1437     if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) {
1438         /* setjmp returned an unknown value, exit */
1439         ErrorF("winInitMultiWindowWM - setjmp returned: %d.  Exiting.\n",
1440                iReturn);
1441         pthread_exit(NULL);
1442     }
1443     else if (iReturn == WIN_JMP_ERROR_IO) {
1444         ErrorF("winInitMultiWindowWM - Caught IO Error.  Exiting.\n");
1445         pthread_exit(NULL);
1446     }
1447
1448     /* Setup the display connection string x */
1449     snprintf(pszDisplay,
1450              512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen);
1451
1452     /* Print the display connection string */
1453     ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay);
1454
1455     /* Use our generated cookie for authentication */
1456     winSetAuthorization();
1457
1458     /* Open the X display */
1459     do {
1460         /* Try to open the display */
1461         pWMInfo->pDisplay = XOpenDisplay(pszDisplay);
1462         if (pWMInfo->pDisplay == NULL) {
1463             ErrorF("winInitMultiWindowWM - Could not open display, try: %d, "
1464                    "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
1465             ++iRetries;
1466             sleep(WIN_CONNECT_DELAY);
1467             continue;
1468         }
1469         else
1470             break;
1471     }
1472     while (pWMInfo->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
1473
1474     /* Make sure that the display opened */
1475     if (pWMInfo->pDisplay == NULL) {
1476         ErrorF("winInitMultiWindowWM - Failed opening the display.  "
1477                "Exiting.\n");
1478         pthread_exit(NULL);
1479     }
1480
1481     ErrorF("winInitMultiWindowWM - XOpenDisplay () returned and "
1482            "successfully opened the display.\n");
1483
1484     /* Create some atoms */
1485     pWMInfo->atmWmProtos = XInternAtom(pWMInfo->pDisplay,
1486                                        "WM_PROTOCOLS", False);
1487     pWMInfo->atmWmDelete = XInternAtom(pWMInfo->pDisplay,
1488                                        "WM_DELETE_WINDOW", False);
1489     pWMInfo->atmWmTakeFocus = XInternAtom(pWMInfo->pDisplay,
1490                                        "WM_TAKE_FOCUS", False);
1491
1492     pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay,
1493                                       WINDOWSWM_NATIVE_HWND, False);
1494
1495     if (1) {
1496         Cursor cursor = XCreateFontCursor(pWMInfo->pDisplay, XC_left_ptr);
1497
1498         if (cursor) {
1499             XDefineCursor(pWMInfo->pDisplay,
1500                           DefaultRootWindow(pWMInfo->pDisplay), cursor);
1501             XFreeCursor(pWMInfo->pDisplay, cursor);
1502         }
1503     }
1504 }
1505
1506 /*
1507  * winSendMessageToWM - Send a message from the X thread to the WM thread
1508  */
1509
1510 void
1511 winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg)
1512 {
1513     WMMsgNodePtr pNode;
1514
1515 #if CYGMULTIWINDOW_DEBUG
1516     ErrorF("winSendMessageToWM ()\n");
1517 #endif
1518
1519     pNode = malloc(sizeof(WMMsgNodeRec));
1520     if (pNode != NULL) {
1521         memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec));
1522         PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode);
1523     }
1524 }
1525
1526 /*
1527  * Window manager error handler
1528  */
1529
1530 static int
1531 winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr)
1532 {
1533     char pszErrorMsg[100];
1534
1535     if (pErr->request_code == X_ChangeWindowAttributes
1536         && pErr->error_code == BadAccess) {
1537         ErrorF("winMultiWindowWMErrorHandler - ChangeWindowAttributes "
1538                "BadAccess.\n");
1539         return 0;
1540     }
1541
1542     XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
1543     ErrorF("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg);
1544
1545     return 0;
1546 }
1547
1548 /*
1549  * Window manager IO error handler
1550  */
1551
1552 static int
1553 winMultiWindowWMIOErrorHandler(Display * pDisplay)
1554 {
1555     ErrorF("winMultiWindowWMIOErrorHandler!\n");
1556
1557     if (pthread_equal(pthread_self(), g_winMultiWindowWMThread)) {
1558         if (g_shutdown)
1559             pthread_exit(NULL);
1560
1561         /* Restart at the main entry point */
1562         longjmp(g_jmpWMEntry, WIN_JMP_ERROR_IO);
1563     }
1564
1565     if (g_winMultiWindowWMOldIOErrorHandler)
1566         g_winMultiWindowWMOldIOErrorHandler(pDisplay);
1567
1568     return 0;
1569 }
1570
1571 /*
1572  * X message procedure error handler
1573  */
1574
1575 static int
1576 winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr)
1577 {
1578     char pszErrorMsg[100];
1579
1580     XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
1581 #if CYGMULTIWINDOW_DEBUG
1582     ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg);
1583 #endif
1584
1585     return 0;
1586 }
1587
1588 /*
1589  * X message procedure IO error handler
1590  */
1591
1592 static int
1593 winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay)
1594 {
1595     ErrorF("winMultiWindowXMsgProcIOErrorHandler!\n");
1596
1597     if (pthread_equal(pthread_self(), g_winMultiWindowXMsgProcThread)) {
1598         /* Restart at the main entry point */
1599         longjmp(g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO);
1600     }
1601
1602     if (g_winMultiWindowXMsgProcOldIOErrorHandler)
1603         g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay);
1604
1605     return 0;
1606 }
1607
1608 /*
1609  * Catch RedirectError to detect other window manager running
1610  */
1611
1612 static int
1613 winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr)
1614 {
1615     redirectError = TRUE;
1616     return 0;
1617 }
1618
1619 /*
1620  * Check if another window manager is running
1621  */
1622
1623 static Bool
1624 CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen,
1625                           Bool fAllowOtherWM)
1626 {
1627     /*
1628        Try to select the events which only one client at a time is allowed to select.
1629        If this causes an error, another window manager is already running...
1630      */
1631     redirectError = FALSE;
1632     XSetErrorHandler(winRedirectErrorHandler);
1633     XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen),
1634                  ResizeRedirectMask | SubstructureRedirectMask |
1635                  ButtonPressMask);
1636     XSync(pDisplay, 0);
1637     XSetErrorHandler(winMultiWindowXMsgProcErrorHandler);
1638
1639     /*
1640        Side effect: select the events we are actually interested in...
1641
1642        If other WMs are not allowed, also select one of the events which only one client
1643        at a time is allowed to select, so other window managers won't start...
1644      */
1645     XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen),
1646                  SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask :
1647                                            0));
1648     XSync(pDisplay, 0);
1649     return redirectError;
1650 }
1651
1652 /*
1653  * Notify the MWM thread we're exiting and not to reconnect
1654  */
1655
1656 void
1657 winDeinitMultiWindowWM(void)
1658 {
1659     ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
1660     g_shutdown = TRUE;
1661 }
1662
1663 /* Windows window styles */
1664 #define HINT_NOFRAME    (1L<<0)
1665 #define HINT_BORDER     (1L<<1)
1666 #define HINT_SIZEBOX    (1L<<2)
1667 #define HINT_CAPTION    (1L<<3)
1668 #define HINT_NOMAXIMIZE (1L<<4)
1669 #define HINT_NOMINIMIZE (1L<<5)
1670 #define HINT_NOSYSMENU  (1L<<6)
1671 #define HINT_SKIPTASKBAR (1L<<7)
1672 /* These two are used on their own */
1673 #define HINT_MAX        (1L<<0)
1674 #define HINT_MIN        (1L<<1)
1675
1676 static void
1677 winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle)
1678 {
1679     static Atom windowState, motif_wm_hints, windowType;
1680     static Atom hiddenState, fullscreenState, belowState, aboveState,
1681         skiptaskbarState;
1682     static Atom dockWindow;
1683     static int generation;
1684     Atom type, *pAtom = NULL;
1685     int format;
1686     unsigned long hint = 0, maxmin = 0, nitems = 0, left = 0;
1687     unsigned long style, exStyle;
1688     MwmHints *mwm_hint = NULL;
1689
1690     if (!hWnd)
1691         return;
1692     if (!IsWindow(hWnd))
1693         return;
1694
1695     if (generation != serverGeneration) {
1696         generation = serverGeneration;
1697         windowState = XInternAtom(pDisplay, "_NET_WM_STATE", False);
1698         motif_wm_hints = XInternAtom(pDisplay, "_MOTIF_WM_HINTS", False);
1699         windowType = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE", False);
1700         hiddenState = XInternAtom(pDisplay, "_NET_WM_STATE_HIDDEN", False);
1701         fullscreenState =
1702             XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", False);
1703         belowState = XInternAtom(pDisplay, "_NET_WM_STATE_BELOW", False);
1704         aboveState = XInternAtom(pDisplay, "_NET_WM_STATE_ABOVE", False);
1705         dockWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_DOCK", False);
1706         skiptaskbarState =
1707             XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False);
1708     }
1709
1710     if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L,
1711                            MAXINT, False, XA_ATOM, &type, &format,
1712                            &nitems, &left,
1713                            (unsigned char **) &pAtom) == Success) {
1714         if (pAtom ) {
1715             unsigned long i;
1716
1717             for (i = 0; i < nitems; i++) {
1718                 if (pAtom[i] == skiptaskbarState)
1719                     hint |= HINT_SKIPTASKBAR;
1720                 if (pAtom[i] == hiddenState)
1721                     maxmin |= HINT_MIN;
1722                 else if (pAtom[i] == fullscreenState)
1723                     maxmin |= HINT_MAX;
1724                 if (pAtom[i] == belowState)
1725                     *zstyle = HWND_BOTTOM;
1726                 else if (pAtom[i] == aboveState)
1727                     *zstyle = HWND_TOPMOST;
1728             }
1729
1730             XFree(pAtom);
1731         }
1732     }
1733
1734     nitems = left = 0;
1735     if (XGetWindowProperty(pDisplay, iWindow, motif_wm_hints, 0L,
1736                            PropMwmHintsElements, False, motif_wm_hints, &type,
1737                            &format, &nitems, &left,
1738                            (unsigned char **) &mwm_hint) == Success) {
1739         if (mwm_hint && nitems == PropMwmHintsElements &&
1740             (mwm_hint->flags & MwmHintsDecorations)) {
1741             if (!mwm_hint->decorations)
1742                 hint |= HINT_NOFRAME;
1743             else if (!(mwm_hint->decorations & MwmDecorAll)) {
1744                 if (mwm_hint->decorations & MwmDecorBorder)
1745                     hint |= HINT_BORDER;
1746                 if (mwm_hint->decorations & MwmDecorHandle)
1747                     hint |= HINT_SIZEBOX;
1748                 if (mwm_hint->decorations & MwmDecorTitle)
1749                     hint |= HINT_CAPTION;
1750                 if (!(mwm_hint->decorations & MwmDecorMenu))
1751                     hint |= HINT_NOSYSMENU;
1752                 if (!(mwm_hint->decorations & MwmDecorMinimize))
1753                     hint |= HINT_NOMINIMIZE;
1754                 if (!(mwm_hint->decorations & MwmDecorMaximize))
1755                     hint |= HINT_NOMAXIMIZE;
1756             }
1757             else {
1758                 /*
1759                    MwmDecorAll means all decorations *except* those specified by other flag
1760                    bits that are set.  Not yet implemented.
1761                  */
1762             }
1763         }
1764         if (mwm_hint)
1765             XFree(mwm_hint);
1766     }
1767
1768     nitems = left = 0;
1769     pAtom = NULL;
1770     if (XGetWindowProperty(pDisplay, iWindow, windowType, 0L,
1771                            1L, False, XA_ATOM, &type, &format,
1772                            &nitems, &left,
1773                            (unsigned char **) &pAtom) == Success) {
1774         if (pAtom && nitems == 1) {
1775             if (*pAtom == dockWindow) {
1776                 hint = (hint & ~HINT_NOFRAME) | HINT_SIZEBOX;   /* Xming puts a sizebox on dock windows */
1777                 *zstyle = HWND_TOPMOST;
1778             }
1779         }
1780         if (pAtom)
1781             XFree(pAtom);
1782     }
1783
1784     {
1785         XSizeHints *normal_hint = XAllocSizeHints();
1786         long supplied;
1787
1788         if (normal_hint &&
1789             (XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied) ==
1790              Success)) {
1791             if (normal_hint->flags & PMaxSize) {
1792                 /* Not maximizable if a maximum size is specified */
1793                 hint |= HINT_NOMAXIMIZE;
1794
1795                 if (normal_hint->flags & PMinSize) {
1796                     /*
1797                        If both minimum size and maximum size are specified and are the same,
1798                        don't bother with a resizing frame
1799                      */
1800                     if ((normal_hint->min_width == normal_hint->max_width)
1801                         && (normal_hint->min_height == normal_hint->max_height))
1802                         hint = (hint & ~HINT_SIZEBOX);
1803                 }
1804             }
1805         }
1806         XFree(normal_hint);
1807     }
1808
1809     /*
1810        Override hint settings from above with settings from config file and set
1811        application id for grouping.
1812      */
1813     {
1814         XClassHint class_hint = { 0, 0 };
1815         char *window_name = 0;
1816         char *application_id = 0;
1817
1818         if (XGetClassHint(pDisplay, iWindow, &class_hint)) {
1819             XFetchName(pDisplay, iWindow, &window_name);
1820
1821             style =
1822                 winOverrideStyle(class_hint.res_name, class_hint.res_class,
1823                                  window_name);
1824
1825 #define APPLICATION_ID_FORMAT   "%s.xwin.%s"
1826 #define APPLICATION_ID_UNKNOWN "unknown"
1827             if (class_hint.res_class) {
1828                 asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
1829                          class_hint.res_class);
1830             }
1831             else {
1832                 asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
1833                          APPLICATION_ID_UNKNOWN);
1834             }
1835             winSetAppUserModelID(hWnd, application_id);
1836
1837             if (class_hint.res_name)
1838                 XFree(class_hint.res_name);
1839             if (class_hint.res_class)
1840                 XFree(class_hint.res_class);
1841             if (application_id)
1842                 free(application_id);
1843             if (window_name)
1844                 XFree(window_name);
1845         }
1846         else {
1847             style = STYLE_NONE;
1848         }
1849     }
1850
1851     if (style & STYLE_TOPMOST)
1852         *zstyle = HWND_TOPMOST;
1853     else if (style & STYLE_MAXIMIZE)
1854         maxmin = (hint & ~HINT_MIN) | HINT_MAX;
1855     else if (style & STYLE_MINIMIZE)
1856         maxmin = (hint & ~HINT_MAX) | HINT_MIN;
1857     else if (style & STYLE_BOTTOM)
1858         *zstyle = HWND_BOTTOM;
1859
1860     if (maxmin & HINT_MAX)
1861         SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1862     else if (maxmin & HINT_MIN)
1863         SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1864
1865     if (style & STYLE_NOTITLE)
1866         hint =
1867             (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) |
1868             HINT_SIZEBOX;
1869     else if (style & STYLE_OUTLINE)
1870         hint =
1871             (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) |
1872             HINT_BORDER;
1873     else if (style & STYLE_NOFRAME)
1874         hint =
1875             (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) |
1876             HINT_NOFRAME;
1877
1878     /* Now apply styles to window */
1879     style = GetWindowLongPtr(hWnd, GWL_STYLE);
1880     if (!style)
1881         return;                 /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
1882
1883     style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */
1884
1885     if (!(hint & ~HINT_SKIPTASKBAR))    /* No hints, default */
1886         style = style | WS_CAPTION | WS_SIZEBOX;
1887     else if (hint & HINT_NOFRAME)       /* No frame, no decorations */
1888         style = style & ~WS_CAPTION & ~WS_SIZEBOX;
1889     else
1890         style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) |
1891             ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) |
1892             ((hint & HINT_CAPTION) ? WS_CAPTION : 0);
1893
1894     if (hint & HINT_NOMAXIMIZE)
1895         style = style & ~WS_MAXIMIZEBOX;
1896
1897     if (hint & HINT_NOMINIMIZE)
1898         style = style & ~WS_MINIMIZEBOX;
1899
1900     if (hint & HINT_NOSYSMENU)
1901         style = style & ~WS_SYSMENU;
1902
1903     if (hint & HINT_SKIPTASKBAR)
1904         style = style & ~WS_MINIMIZEBOX;        /* window will become lost if minimized */
1905
1906     SetWindowLongPtr(hWnd, GWL_STYLE, style);
1907
1908     exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
1909     if (hint & HINT_SKIPTASKBAR)
1910         exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW;
1911     else
1912         exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW;
1913     SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
1914
1915     winDebug
1916         ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
1917          iWindow, hint, style, exStyle);
1918 }
1919
1920 void
1921 winUpdateWindowPosition(HWND hWnd, HWND * zstyle)
1922 {
1923     int iX, iY, iWidth, iHeight;
1924     int iDx, iDy;
1925     RECT rcNew;
1926     WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP);
1927     DrawablePtr pDraw = NULL;
1928
1929     if (!pWin)
1930         return;
1931     pDraw = &pWin->drawable;
1932     if (!pDraw)
1933         return;
1934
1935     /* Get the X and Y location of the X window */
1936     iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
1937     iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
1938
1939     /* Get the height and width of the X window */
1940     iWidth = pWin->drawable.width;
1941     iHeight = pWin->drawable.height;
1942
1943     /* Setup a rectangle with the X window position and size */
1944     SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
1945
1946     winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
1947              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
1948
1949     AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE,
1950                        GetWindowLongPtr(hWnd, GWL_EXSTYLE));
1951
1952     /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */
1953     if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) {
1954         iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left;
1955         rcNew.left += iDx;
1956         rcNew.right += iDx;
1957     }
1958
1959     if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) {
1960         iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top;
1961         rcNew.top += iDy;
1962         rcNew.bottom += iDy;
1963     }
1964
1965     winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
1966              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
1967
1968     /* Position the Windows window */
1969     SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top,
1970                  rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0);
1971
1972 }