2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3 *Copyright (C) Colin Harrison 2005-2009
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:
13 *The above copyright notice and this permission notice shall be
14 *included in all copies or substantial portions of the Software.
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.
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.
29 * Authors: Kensuke Matsuzaki
34 #ifdef HAVE_XWIN_CONFIG_H
35 #include <xwin-config.h>
41 #include <sys/select.h>
49 #include <X11/Xatom.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>
58 #include "winwindow.h"
61 #include "pixmapstr.h"
62 #include "windowstr.h"
63 #include "winglobals.h"
65 #ifdef XWIN_MULTIWINDOWEXTWM
66 #include <X11/extensions/windowswmstr.h>
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"
74 #define HOST_NAME_MAX 255
77 extern void winDebug(const char *format, ...);
78 extern void winReshapeMultiWindow(WindowPtr pWin);
79 extern void winUpdateRgnMultiWindow(WindowPtr pWin);
89 #define WIN_CONNECT_RETRIES 5
90 #define WIN_CONNECT_DELAY 5
92 #define WIN_MSG_QUEUE_FNAME "/dev/windows"
94 #define WIN_JMP_OKAY 0
95 #define WIN_JMP_ERROR_IO 2
101 typedef struct _WMMsgNodeRec {
103 struct _WMMsgNodeRec *pNext;
104 } WMMsgNodeRec, *WMMsgNodePtr;
106 typedef struct _WMMsgQueueRec {
107 struct _WMMsgNodeRec *pHead;
108 struct _WMMsgNodeRec *pTail;
109 pthread_mutex_t pmMutex;
110 pthread_cond_t pcNotEmpty;
112 } WMMsgQueueRec, *WMMsgQueuePtr;
114 typedef struct _WMInfo {
116 WMMsgQueueRec wmMsgQueue;
122 } WMInfoRec, *WMInfoPtr;
124 typedef struct _WMProcArgRec {
127 pthread_mutex_t *ppmServerStarted;
128 } WMProcArgRec, *WMProcArgPtr;
130 typedef struct _XMsgProcArgRec {
134 pthread_mutex_t *ppmServerStarted;
136 } XMsgProcArgRec, *XMsgProcArgPtr;
139 * Prototypes for local functions
143 PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode);
145 static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo);
148 InitQueue(WMMsgQueuePtr pQueue);
151 GetWindowName(Display * pDpy, Window iWin, char **ppWindowName);
154 SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData);
157 UpdateName(WMInfoPtr pWMInfo, Window iWindow);
159 static void *winMultiWindowWMProc(void *pArg);
162 winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr);
165 winMultiWindowWMIOErrorHandler(Display * pDisplay);
167 static void *winMultiWindowXMsgProc(void *pArg);
170 winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr);
173 winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay);
176 winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr);
179 winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg);
183 PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction);
188 CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen,
192 winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle);
195 winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
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;
212 * PushMessage - Push a message onto the queue
216 PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode)
219 /* Lock the queue mutex */
220 pthread_mutex_lock(&pQueue->pmMutex);
224 if (pQueue->pTail != NULL) {
225 pQueue->pTail->pNext = pNode;
227 pQueue->pTail = pNode;
229 if (pQueue->pHead == NULL) {
230 pQueue->pHead = pNode;
234 switch (pNode->msg.msg) {
236 ErrorF("\tWM_WM_MOVE\n");
239 ErrorF("\tWM_WM_SIZE\n");
242 ErrorF("\tWM_WM_RAISE\n");
245 ErrorF("\tWM_WM_LOWER\n");
248 ErrorF("\tWM_WM_MAP\n");
251 ErrorF("\tWM_WM_MAP2\n");
254 ErrorF("\tWM_WM_MAP3\n");
257 ErrorF("\tWM_WM_UNMAP\n");
260 ErrorF("\tWM_WM_KILL\n");
263 ErrorF("\tWM_WM_ACTIVATE\n");
266 ErrorF("\tUnknown Message.\n");
271 /* Increase the count of elements in the queue by one */
272 ++(pQueue->nQueueSize);
274 /* Release the queue mutex */
275 pthread_mutex_unlock(&pQueue->pmMutex);
277 /* Signal that the queue is not empty */
278 pthread_cond_signal(&pQueue->pcNotEmpty);
281 #if CYGMULTIWINDOW_DEBUG
283 * QueueSize - Return the size of the queue
287 QueueSize(WMMsgQueuePtr pQueue)
292 /* Loop through all elements in the queue */
293 for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext)
301 * PopMessage - Pop a message from the queue
305 PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo)
309 /* Lock the queue mutex */
310 pthread_mutex_lock(&pQueue->pmMutex);
313 while (pQueue->pHead == NULL) {
314 pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex);
317 pNode = pQueue->pHead;
318 if (pQueue->pHead != NULL) {
319 pQueue->pHead = pQueue->pHead->pNext;
322 if (pQueue->pTail == pNode) {
323 pQueue->pTail = NULL;
326 /* Drop the number of elements in the queue by one */
327 --(pQueue->nQueueSize);
329 #if CYGMULTIWINDOW_DEBUG
330 ErrorF("Queue Size %d %d\n", pQueue->nQueueSize, QueueSize(pQueue));
333 /* Release the queue mutex */
334 pthread_mutex_unlock(&pQueue->pmMutex);
345 HaveMessage(WMMsgQueuePtr pQueue, UINT msg, Window iWindow)
349 for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) {
350 if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow)
359 * InitQueue - Initialize the Window Manager message queue
364 InitQueue(WMMsgQueuePtr pQueue)
366 /* Check if the pQueue pointer is NULL */
367 if (pQueue == NULL) {
368 ErrorF("InitQueue - pQueue is NULL. Exiting.\n");
372 /* Set the head and tail to NULL */
373 pQueue->pHead = NULL;
374 pQueue->pTail = NULL;
376 /* There are no elements initially */
377 pQueue->nQueueSize = 0;
379 #if CYGMULTIWINDOW_DEBUG
380 winDebug("InitQueue - Queue Size %d %d\n", pQueue->nQueueSize,
384 winDebug("InitQueue - Calling pthread_mutex_init\n");
386 /* Create synchronization objects */
387 pthread_mutex_init(&pQueue->pmMutex, NULL);
389 winDebug("InitQueue - pthread_mutex_init returned\n");
390 winDebug("InitQueue - Calling pthread_cond_init\n");
392 pthread_cond_init(&pQueue->pcNotEmpty, NULL);
394 winDebug("InitQueue - pthread_cond_init returned\n");
401 Xutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp)
407 if (Xutf8TextPropertyToTextList(pDisplay, xtp, &ppList, &nNum) >= Success &&
408 nNum > 0 && *ppList) {
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]);
419 XFreeStringList(ppList);
422 pszReturnData = malloc(1);
423 pszReturnData[0] = '\0';
426 return pszReturnData;
430 * GetWindowName - Retrieve the title of an X Window
434 GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName)
437 XTextProperty xtpWindowName;
438 XTextProperty xtpClientMachine;
440 char *pszClientMachine;
441 char hostname[HOST_NAME_MAX + 1];
443 #if CYGMULTIWINDOW_DEBUG
444 ErrorF("GetWindowName\n");
447 /* Intialize ppWindowName to NULL */
448 *ppWindowName = NULL;
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");
459 pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName);
460 XFree(xtpWindowName.value);
462 if (g_fHostInTitle) {
463 /* Try to get client machine name */
464 nResult = XGetWMClientMachine(pDisplay, iWin, &xtpClientMachine);
465 if (nResult && xtpClientMachine.value && xtpClientMachine.nitems) {
467 Xutf8TextPropertyToString(pDisplay, &xtpClientMachine);
468 XFree(xtpClientMachine.value);
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...
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 */
481 malloc(strlen(pszWindowName) +
482 strlen(pszClientMachine) + 2);
483 strcpy(*ppWindowName, pszWindowName);
484 strcat(*ppWindowName, "@");
485 strcat(*ppWindowName, pszClientMachine);
488 free(pszClientMachine);
495 /* otherwise just return the window name */
496 *ppWindowName = pszWindowName;
500 * Does the client support the specified WM_PROTOCOLS protocol?
504 IsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom atmProtocol)
509 if (XGetWMProtocols(pDisplay, iWindow, &protocols, &n)) {
510 for (i = 0; i < n; ++i)
511 if (protocols[i] == atmProtocol)
521 * Send a message to the X server from the WM thread
525 SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData)
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;
537 /* Send the event to X */
538 return XSendEvent(pDisplay, iWin, False, NoEventMask, &e);
542 * See if we can get the stored HWND for this window...
545 getHwnd(WMInfoPtr pWMInfo, Window iWindow)
549 unsigned long items, remain;
550 HWND *retHwnd, hWnd = NULL;
552 if (XGetWindowProperty(pWMInfo->pDisplay,
562 &remain, (unsigned char **) &retHwnd) == Success) {
569 /* Some sanity checks */
579 * Updates the name of a HWND according to its X WM_NAME property
583 UpdateName(WMInfoPtr pWMInfo, Window iWindow)
586 XWindowAttributes attr;
588 hWnd = getHwnd(pWMInfo, iWindow);
592 /* If window isn't override-redirect */
593 XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr);
594 if (!attr.override_redirect) {
597 /* Get the X windows window name */
598 GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName);
601 /* Convert from UTF-8 to wide char */
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);
609 /* Set the Windows window name */
610 SetWindowTextW(hWnd, pwszWideWindowName);
612 free(pwszWideWindowName);
619 * Updates the icon of a HWND according to its X icon properties
623 UpdateIcon(WMInfoPtr pWMInfo, Window iWindow)
626 HICON hIconNew = NULL;
627 XWindowAttributes attr;
629 hWnd = getHwnd(pWMInfo, iWindow);
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;
639 if (XGetClassHint(pWMInfo->pDisplay, iWindow, &class_hint)) {
640 XFetchName(pWMInfo->pDisplay, iWindow, &window_name);
643 (HICON) winOverrideIcon(class_hint.res_name,
644 class_hint.res_class, window_name);
646 if (class_hint.res_name)
647 XFree(class_hint.res_name);
648 if (class_hint.res_class)
649 XFree(class_hint.res_class);
655 winUpdateIcon(hWnd, pWMInfo->pDisplay, iWindow, hIconNew);
659 * Updates the style of a HWND according to its X style properties
663 UpdateStyle(WMInfoPtr pWMInfo, Window iWindow)
666 HWND zstyle = HWND_NOTOPMOST;
669 hWnd = getHwnd(pWMInfo, iWindow);
673 /* Determine the Window style, which determines borders and clipping region... */
674 winApplyHints(pWMInfo->pDisplay, iWindow, hWnd, &zstyle);
675 winUpdateWindowPosition(hWnd, &zstyle);
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);
684 Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
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.
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.
692 winShowWindowOnTaskbar(hWnd,
693 (GetWindowLongPtr(hWnd, GWL_EXSTYLE) &
694 WS_EX_APPWINDOW) ? TRUE : FALSE);
699 * Fix up any differences between the X11 and Win32 window stacks
700 * starting at the window passed in
703 PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction)
706 DWORD myWinProcID, winProcID;
708 WINDOWPLACEMENT wndPlace;
710 hWnd = getHwnd(pWMInfo, iWindow);
714 GetWindowThreadProcessId(hWnd, &myWinProcID);
715 hWnd = GetNextWindow(hWnd, direction);
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);
726 if (direction == GW_HWNDPREV)
727 XRaiseWindow(pWMInfo->pDisplay, xWindow);
729 XLowerWindow(pWMInfo->pDisplay, xWindow);
733 hWnd = GetNextWindow(hWnd, direction);
736 #endif /* PreserveWin32Stack */
739 * winMultiWindowWMProc
743 winMultiWindowWMProc(void *pArg)
745 WMProcArgPtr pProcArg = (WMProcArgPtr) pArg;
746 WMInfoPtr pWMInfo = pProcArg->pWMInfo;
748 /* Initialize the Window Manager */
749 winInitMultiWindowWM(pWMInfo, pProcArg);
751 #if CYGMULTIWINDOW_DEBUG
752 ErrorF("winMultiWindowWMProc ()\n");
755 /* Loop until we explicitly break out */
759 if (g_fAnotherWMRunning) { /* Another Window manager exists. */
764 /* Pop a message off of our queue */
765 pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo);
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");
773 #if CYGMULTIWINDOW_DEBUG
774 ErrorF("winMultiWindowWMProc - %d ms MSG: %d ID: %d\n",
775 GetTickCount(), (int) pNode->msg.msg, (int) pNode->msg.dwID);
778 /* Branch on the message type */
779 switch (pNode->msg.msg) {
782 ErrorF("\tWM_WM_MOVE\n");
786 ErrorF("\tWM_WM_SIZE\n");
791 #if CYGMULTIWINDOW_DEBUG
792 ErrorF("\tWM_WM_RAISE\n");
794 /* Raise the window */
795 XRaiseWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
797 PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV);
802 #if CYGMULTIWINDOW_DEBUG
803 ErrorF("\tWM_WM_LOWER\n");
806 /* Lower the window */
807 XLowerWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
811 #if CYGMULTIWINDOW_DEBUG
812 ErrorF("\tWM_WM_MAP\n");
814 /* Put a note as to the HWND associated with this Window */
815 XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
818 (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
819 UpdateName(pWMInfo, pNode->msg.iWindow);
820 UpdateIcon(pWMInfo, pNode->msg.iWindow);
824 #if CYGMULTIWINDOW_DEBUG
825 ErrorF("\tWM_WM_MAP2\n");
827 XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
830 (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
834 #if CYGMULTIWINDOW_DEBUG
835 ErrorF("\tWM_WM_MAP3\n");
837 /* Put a note as to the HWND associated with this Window */
838 XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
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);
850 GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP);
852 winReshapeMultiWindow(pWin);
853 winUpdateRgnMultiWindow(pWin);
860 #if CYGMULTIWINDOW_DEBUG
861 ErrorF("\tWM_WM_UNMAP\n");
864 /* Unmap the window */
865 XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
869 #if CYGMULTIWINDOW_DEBUG
870 ErrorF("\tWM_WM_KILL\n");
874 if (IsWmProtocolAvailable(pWMInfo->pDisplay,
876 pWMInfo->atmWmDelete))
877 SendXMessage(pWMInfo->pDisplay,
879 pWMInfo->atmWmProtos, pWMInfo->atmWmDelete);
881 XKillClient(pWMInfo->pDisplay, pNode->msg.iWindow);
886 #if CYGMULTIWINDOW_DEBUG
887 ErrorF("\tWM_WM_ACTIVATE\n");
889 /* Set the input focus */
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
896 -- independently, the WM_TAKE_FOCUS protocol determines whether
897 the WM should send a WM_TAKE_FOCUS ClientMessage.
900 Bool neverFocus = FALSE;
901 XWMHints *hints = XGetWMHints(pWMInfo->pDisplay, pNode->msg.iWindow);
904 if (hints->flags & InputHint)
905 neverFocus = !hints->input;
910 XSetInputFocus(pWMInfo->pDisplay,
912 RevertToPointerRoot, CurrentTime);
914 if (IsWmProtocolAvailable(pWMInfo->pDisplay,
916 pWMInfo->atmWmTakeFocus))
917 SendXMessage(pWMInfo->pDisplay,
919 pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus);
924 case WM_WM_NAME_EVENT:
925 UpdateName(pWMInfo, pNode->msg.iWindow);
928 case WM_WM_ICON_EVENT:
929 UpdateIcon(pWMInfo, pNode->msg.iWindow);
932 case WM_WM_HINTS_EVENT:
934 XWindowAttributes attr;
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)
941 UpdateStyle(pWMInfo, pNode->msg.iWindow);
945 case WM_WM_CHANGE_STATE:
946 /* Minimize the window in Windows */
947 winMinimizeWindow(pNode->msg.iWindow);
951 ErrorF("winMultiWindowWMProc - Unknown Message. Exiting.\n");
956 /* Free the retrieved message */
959 /* Flush any pending events on our display */
960 XFlush(pWMInfo->pDisplay);
963 /* Free the condition variable */
964 pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty);
966 /* Free the mutex variable */
967 pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex);
969 /* Free the passed-in argument */
972 #if CYGMULTIWINDOW_DEBUG
973 ErrorF("-winMultiWindowWMProc ()\n");
979 * X message procedure
983 winMultiWindowXMsgProc(void *pArg)
986 XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg;
987 char pszDisplay[512];
994 Atom atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
998 winDebug("winMultiWindowXMsgProc - Hello\n");
1000 /* Check that argument pointer is not invalid */
1001 if (pProcArg == NULL) {
1002 ErrorF("winMultiWindowXMsgProc - pProcArg is NULL. Exiting.\n");
1006 ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
1008 /* Grab the server started mutex - pause until we get it */
1009 iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
1011 ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d. "
1012 "Exiting.\n", iReturn);
1016 ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
1018 /* Allow multiple threads to access Xlib */
1019 if (XInitThreads() == 0) {
1020 ErrorF("winMultiWindowXMsgProc - XInitThreads () failed. Exiting.\n");
1024 /* See if X supports the current locale */
1025 if (XSupportsLocale() == False) {
1026 ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n");
1029 /* Release the server started mutex */
1030 pthread_mutex_unlock(pProcArg->ppmServerStarted);
1032 ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
1034 /* Install our error handler */
1035 XSetErrorHandler(winMultiWindowXMsgProcErrorHandler);
1036 g_winMultiWindowXMsgProcThread = pthread_self();
1037 g_winMultiWindowXMsgProcOldIOErrorHandler =
1038 XSetIOErrorHandler(winMultiWindowXMsgProcIOErrorHandler);
1040 /* Set jump point for IO Error exits */
1041 iReturn = setjmp(g_jmpXMsgProcEntry);
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",
1050 else if (iReturn == WIN_JMP_ERROR_IO) {
1051 ErrorF("winInitMultiWindowXMsgProc - Caught IO Error. Exiting.\n");
1055 /* Setup the display connection string x */
1056 snprintf(pszDisplay,
1057 512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen);
1059 /* Print the display connection string */
1060 ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay);
1062 /* Use our generated cookie for authentication */
1063 winSetAuthorization();
1065 /* Initialize retry count */
1068 /* Open the X display */
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);
1076 sleep(WIN_CONNECT_DELAY);
1082 while (pProcArg->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
1084 /* Make sure that the display opened */
1085 if (pProcArg->pDisplay == NULL) {
1086 ErrorF("winMultiWindowXMsgProc - Failed opening the display. "
1091 ErrorF("winMultiWindowXMsgProc - XOpenDisplay () returned and "
1092 "successfully opened the display.\n");
1094 /* Check if another window manager is already running */
1095 g_fAnotherWMRunning =
1096 CheckAnotherWindowManager(pProcArg->pDisplay, pProcArg->dwScreen,
1097 pProcArg->pWMInfo->fAllowOtherWM);
1099 if (g_fAnotherWMRunning && !pProcArg->pWMInfo->fAllowOtherWM) {
1100 ErrorF("winMultiWindowXMsgProc - "
1101 "another window manager is running. Exiting.\n");
1105 /* Set up the supported icon sizes */
1106 xis = XAllocIconSize();
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),
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);
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.
1131 Since this is on in the default Solaris 10 install,
1132 workaround this by making sure it does exist...
1134 XInternAtom(pProcArg->pDisplay, "WM_STATE", 0);
1136 /* Loop until we explicitly break out */
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);
1150 if (g_fAnotherWMRunning) {
1151 g_fAnotherWMRunning = FALSE;
1152 SendMessage(pProcArg->hwndScreen, WM_MANAGE, 0, 0);
1159 /* Fetch next event */
1160 XNextEvent(pProcArg->pDisplay, &event);
1162 /* Branch on event type */
1163 if (event.type == CreateNotify) {
1164 XWindowAttributes attr;
1166 XSelectInput(pProcArg->pDisplay,
1167 event.xcreatewindow.window, PropertyChangeMask);
1169 /* Get the window attributes */
1170 XGetWindowAttributes(pProcArg->pDisplay,
1171 event.xcreatewindow.window, &attr);
1173 if (!attr.override_redirect)
1174 XSetWindowBorderWidth(pProcArg->pDisplay,
1175 event.xcreatewindow.window, 0);
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.
1182 We don't actually need to reparent, as the frame is
1183 a native window, not an X window
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)
1190 See sourceware bugzilla #9848
1193 XWindowAttributes attr;
1197 unsigned int nchildren;
1199 if (XGetWindowAttributes(event.xmap.display,
1202 XQueryTree(event.xmap.display,
1204 &root, &parent, &children, &nchildren)) {
1209 It's a top-level window if the parent window is a root window
1210 Only non-override_redirect windows can get reparented
1212 if ((attr.root == parent) && !event.xmap.override_redirect) {
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;
1222 XSendEvent(event.xmap.display,
1224 True, StructureNotifyMask, &event_send);
1228 else if (event.type == ConfigureNotify) {
1229 if (!event.xconfigure.send_event) {
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)
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)
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
1241 XEvent event_send = event;
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);
1250 else if (event.type == PropertyNotify) {
1251 if (event.xproperty.atom == atmWmName) {
1252 memset(&msg, 0, sizeof(msg));
1254 msg.msg = WM_WM_NAME_EVENT;
1255 msg.iWindow = event.xproperty.window;
1257 /* Other fields ignored */
1258 winSendMessageToWM(pProcArg->pWMInfo, &msg);
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())
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;
1274 /* Other fields ignored */
1275 winSendMessageToWM(pProcArg->pWMInfo, &msg);
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;
1285 /* Other fields ignored */
1286 winSendMessageToWM(pProcArg->pWMInfo, &msg);
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");
1295 memset(&msg, 0, sizeof(msg));
1297 msg.msg = WM_WM_CHANGE_STATE;
1298 msg.iWindow = event.xclient.window;
1300 winSendMessageToWM(pProcArg->pWMInfo, &msg);
1304 XCloseDisplay(pProcArg->pDisplay);
1310 * winInitWM - Entry point for the X server to spawn
1311 * the Window Manager thread. Called from
1312 * winscrinit.c/winFinishScreenInitFB ().
1316 winInitWM(void **ppWMInfo,
1317 pthread_t * ptWMProc,
1318 pthread_t * ptXMsgProc,
1319 pthread_mutex_t * ppmServerStarted,
1320 int dwScreen, HWND hwndScreen, BOOL allowOtherWM)
1322 WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
1323 WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
1324 XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec));
1326 /* Bail if the input parameters are bad */
1327 if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) {
1328 ErrorF("winInitWM - malloc failed.\n");
1335 /* Zero the allocated memory */
1336 ZeroMemory(pArg, sizeof(WMProcArgRec));
1337 ZeroMemory(pWMInfo, sizeof(WMInfoRec));
1338 ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec));
1340 /* Set a return pointer to the Window Manager info structure */
1341 *ppWMInfo = pWMInfo;
1342 pWMInfo->fAllowOtherWM = allowOtherWM;
1344 /* Setup the argument structure for the thread function */
1345 pArg->dwScreen = dwScreen;
1346 pArg->pWMInfo = pWMInfo;
1347 pArg->ppmServerStarted = ppmServerStarted;
1349 /* Intialize the message queue */
1350 if (!InitQueue(&pWMInfo->wmMsgQueue)) {
1351 ErrorF("winInitWM - InitQueue () failed.\n");
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");
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");
1374 winDebug("winInitWM - Returning.\n");
1381 * Window manager thread - setup
1385 winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
1388 char pszDisplay[512];
1391 winDebug("winInitMultiWindowWM - Hello\n");
1393 /* Check that argument pointer is not invalid */
1394 if (pProcArg == NULL) {
1395 ErrorF("winInitMultiWindowWM - pProcArg is NULL. Exiting.\n");
1399 ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
1401 /* Grab our garbage mutex to satisfy pthread_cond_wait */
1402 iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
1404 ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d. "
1405 "Exiting.\n", iReturn);
1409 ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
1411 /* Allow multiple threads to access Xlib */
1412 if (XInitThreads() == 0) {
1413 ErrorF("winInitMultiWindowWM - XInitThreads () failed. Exiting.\n");
1417 /* See if X supports the current locale */
1418 if (XSupportsLocale() == False) {
1419 ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n");
1422 /* Release the server started mutex */
1423 pthread_mutex_unlock(pProcArg->ppmServerStarted);
1425 ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
1427 /* Install our error handler */
1428 XSetErrorHandler(winMultiWindowWMErrorHandler);
1429 g_winMultiWindowWMThread = pthread_self();
1430 g_winMultiWindowWMOldIOErrorHandler =
1431 XSetIOErrorHandler(winMultiWindowWMIOErrorHandler);
1433 /* Set jump point for IO Error exits */
1434 iReturn = setjmp(g_jmpWMEntry);
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",
1443 else if (iReturn == WIN_JMP_ERROR_IO) {
1444 ErrorF("winInitMultiWindowWM - Caught IO Error. Exiting.\n");
1448 /* Setup the display connection string x */
1449 snprintf(pszDisplay,
1450 512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen);
1452 /* Print the display connection string */
1453 ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay);
1455 /* Use our generated cookie for authentication */
1456 winSetAuthorization();
1458 /* Open the X display */
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);
1466 sleep(WIN_CONNECT_DELAY);
1472 while (pWMInfo->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
1474 /* Make sure that the display opened */
1475 if (pWMInfo->pDisplay == NULL) {
1476 ErrorF("winInitMultiWindowWM - Failed opening the display. "
1481 ErrorF("winInitMultiWindowWM - XOpenDisplay () returned and "
1482 "successfully opened the display.\n");
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);
1492 pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay,
1493 WINDOWSWM_NATIVE_HWND, False);
1496 Cursor cursor = XCreateFontCursor(pWMInfo->pDisplay, XC_left_ptr);
1499 XDefineCursor(pWMInfo->pDisplay,
1500 DefaultRootWindow(pWMInfo->pDisplay), cursor);
1501 XFreeCursor(pWMInfo->pDisplay, cursor);
1507 * winSendMessageToWM - Send a message from the X thread to the WM thread
1511 winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg)
1515 #if CYGMULTIWINDOW_DEBUG
1516 ErrorF("winSendMessageToWM ()\n");
1519 pNode = malloc(sizeof(WMMsgNodeRec));
1520 if (pNode != NULL) {
1521 memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec));
1522 PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode);
1527 * Window manager error handler
1531 winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr)
1533 char pszErrorMsg[100];
1535 if (pErr->request_code == X_ChangeWindowAttributes
1536 && pErr->error_code == BadAccess) {
1537 ErrorF("winMultiWindowWMErrorHandler - ChangeWindowAttributes "
1542 XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
1543 ErrorF("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg);
1549 * Window manager IO error handler
1553 winMultiWindowWMIOErrorHandler(Display * pDisplay)
1555 ErrorF("winMultiWindowWMIOErrorHandler!\n");
1557 if (pthread_equal(pthread_self(), g_winMultiWindowWMThread)) {
1561 /* Restart at the main entry point */
1562 longjmp(g_jmpWMEntry, WIN_JMP_ERROR_IO);
1565 if (g_winMultiWindowWMOldIOErrorHandler)
1566 g_winMultiWindowWMOldIOErrorHandler(pDisplay);
1572 * X message procedure error handler
1576 winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr)
1578 char pszErrorMsg[100];
1580 XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
1581 #if CYGMULTIWINDOW_DEBUG
1582 ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg);
1589 * X message procedure IO error handler
1593 winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay)
1595 ErrorF("winMultiWindowXMsgProcIOErrorHandler!\n");
1597 if (pthread_equal(pthread_self(), g_winMultiWindowXMsgProcThread)) {
1598 /* Restart at the main entry point */
1599 longjmp(g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO);
1602 if (g_winMultiWindowXMsgProcOldIOErrorHandler)
1603 g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay);
1609 * Catch RedirectError to detect other window manager running
1613 winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr)
1615 redirectError = TRUE;
1620 * Check if another window manager is running
1624 CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen,
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...
1631 redirectError = FALSE;
1632 XSetErrorHandler(winRedirectErrorHandler);
1633 XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen),
1634 ResizeRedirectMask | SubstructureRedirectMask |
1637 XSetErrorHandler(winMultiWindowXMsgProcErrorHandler);
1640 Side effect: select the events we are actually interested in...
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...
1645 XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen),
1646 SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask :
1649 return redirectError;
1653 * Notify the MWM thread we're exiting and not to reconnect
1657 winDeinitMultiWindowWM(void)
1659 ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
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)
1677 winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle)
1679 static Atom windowState, motif_wm_hints, windowType;
1680 static Atom hiddenState, fullscreenState, belowState, aboveState,
1682 static Atom dockWindow;
1683 static int generation;
1684 Atom type, *pAtom = NULL;
1686 unsigned long hint = 0, maxmin = 0, nitems = 0, left = 0;
1687 unsigned long style, exStyle;
1688 MwmHints *mwm_hint = NULL;
1692 if (!IsWindow(hWnd))
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);
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);
1707 XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False);
1710 if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L,
1711 MAXINT, False, XA_ATOM, &type, &format,
1713 (unsigned char **) &pAtom) == Success) {
1717 for (i = 0; i < nitems; i++) {
1718 if (pAtom[i] == skiptaskbarState)
1719 hint |= HINT_SKIPTASKBAR;
1720 if (pAtom[i] == hiddenState)
1722 else if (pAtom[i] == fullscreenState)
1724 if (pAtom[i] == belowState)
1725 *zstyle = HWND_BOTTOM;
1726 else if (pAtom[i] == aboveState)
1727 *zstyle = HWND_TOPMOST;
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;
1759 MwmDecorAll means all decorations *except* those specified by other flag
1760 bits that are set. Not yet implemented.
1770 if (XGetWindowProperty(pDisplay, iWindow, windowType, 0L,
1771 1L, False, XA_ATOM, &type, &format,
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;
1785 XSizeHints *normal_hint = XAllocSizeHints();
1789 (XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied) ==
1791 if (normal_hint->flags & PMaxSize) {
1792 /* Not maximizable if a maximum size is specified */
1793 hint |= HINT_NOMAXIMIZE;
1795 if (normal_hint->flags & PMinSize) {
1797 If both minimum size and maximum size are specified and are the same,
1798 don't bother with a resizing frame
1800 if ((normal_hint->min_width == normal_hint->max_width)
1801 && (normal_hint->min_height == normal_hint->max_height))
1802 hint = (hint & ~HINT_SIZEBOX);
1810 Override hint settings from above with settings from config file and set
1811 application id for grouping.
1814 XClassHint class_hint = { 0, 0 };
1815 char *window_name = 0;
1816 char *application_id = 0;
1818 if (XGetClassHint(pDisplay, iWindow, &class_hint)) {
1819 XFetchName(pDisplay, iWindow, &window_name);
1822 winOverrideStyle(class_hint.res_name, class_hint.res_class,
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);
1832 asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
1833 APPLICATION_ID_UNKNOWN);
1835 winSetAppUserModelID(hWnd, application_id);
1837 if (class_hint.res_name)
1838 XFree(class_hint.res_name);
1839 if (class_hint.res_class)
1840 XFree(class_hint.res_class);
1842 free(application_id);
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;
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);
1865 if (style & STYLE_NOTITLE)
1867 (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) |
1869 else if (style & STYLE_OUTLINE)
1871 (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) |
1873 else if (style & STYLE_NOFRAME)
1875 (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) |
1878 /* Now apply styles to window */
1879 style = GetWindowLongPtr(hWnd, GWL_STYLE);
1881 return; /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
1883 style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */
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;
1890 style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) |
1891 ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) |
1892 ((hint & HINT_CAPTION) ? WS_CAPTION : 0);
1894 if (hint & HINT_NOMAXIMIZE)
1895 style = style & ~WS_MAXIMIZEBOX;
1897 if (hint & HINT_NOMINIMIZE)
1898 style = style & ~WS_MINIMIZEBOX;
1900 if (hint & HINT_NOSYSMENU)
1901 style = style & ~WS_SYSMENU;
1903 if (hint & HINT_SKIPTASKBAR)
1904 style = style & ~WS_MINIMIZEBOX; /* window will become lost if minimized */
1906 SetWindowLongPtr(hWnd, GWL_STYLE, style);
1908 exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
1909 if (hint & HINT_SKIPTASKBAR)
1910 exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW;
1912 exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW;
1913 SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
1916 ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
1917 iWindow, hint, style, exStyle);
1921 winUpdateWindowPosition(HWND hWnd, HWND * zstyle)
1923 int iX, iY, iWidth, iHeight;
1926 WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP);
1927 DrawablePtr pDraw = NULL;
1931 pDraw = &pWin->drawable;
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);
1939 /* Get the height and width of the X window */
1940 iWidth = pWin->drawable.width;
1941 iHeight = pWin->drawable.height;
1943 /* Setup a rectangle with the X window position and size */
1944 SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
1946 winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
1947 rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
1949 AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE,
1950 GetWindowLongPtr(hWnd, GWL_EXSTYLE));
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;
1959 if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) {
1960 iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top;
1962 rcNew.bottom += iDy;
1965 winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
1966 rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
1968 /* Position the Windows window */
1969 SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top,
1970 rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0);