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