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"
64 #ifdef XWIN_MULTIWINDOWEXTWM
65 #include <X11/extensions/windowswmstr.h>
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"
72 extern void winDebug(const char *format
, ...);
73 extern void winReshapeMultiWindow(WindowPtr pWin
);
74 extern void winUpdateRgnMultiWindow(WindowPtr pWin
);
84 #define WIN_CONNECT_RETRIES 5
85 #define WIN_CONNECT_DELAY 5
87 #define WIN_MSG_QUEUE_FNAME "/dev/windows"
89 #define WIN_JMP_OKAY 0
90 #define WIN_JMP_ERROR_IO 2
96 typedef struct _WMMsgNodeRec
{
98 struct _WMMsgNodeRec
*pNext
;
99 } WMMsgNodeRec
, *WMMsgNodePtr
;
101 typedef struct _WMMsgQueueRec
{
102 struct _WMMsgNodeRec
*pHead
;
103 struct _WMMsgNodeRec
*pTail
;
104 pthread_mutex_t pmMutex
;
105 pthread_cond_t pcNotEmpty
;
107 } WMMsgQueueRec
, *WMMsgQueuePtr
;
109 typedef struct _WMInfo
{
111 WMMsgQueueRec wmMsgQueue
;
116 } WMInfoRec
, *WMInfoPtr
;
118 typedef struct _WMProcArgRec
{
121 pthread_mutex_t
*ppmServerStarted
;
122 } WMProcArgRec
, *WMProcArgPtr
;
124 typedef struct _XMsgProcArgRec
{
128 pthread_mutex_t
*ppmServerStarted
;
130 } XMsgProcArgRec
, *XMsgProcArgPtr
;
133 * Prototypes for local functions
137 PushMessage(WMMsgQueuePtr pQueue
, WMMsgNodePtr pNode
);
139 static WMMsgNodePtr
PopMessage(WMMsgQueuePtr pQueue
, WMInfoPtr pWMInfo
);
142 InitQueue(WMMsgQueuePtr pQueue
);
145 GetWindowName(Display
* pDpy
, Window iWin
, char **ppWindowName
);
148 SendXMessage(Display
* pDisplay
, Window iWin
, Atom atmType
, long nData
);
151 UpdateName(WMInfoPtr pWMInfo
, Window iWindow
);
153 static void *winMultiWindowWMProc(void *pArg
);
156 winMultiWindowWMErrorHandler(Display
* pDisplay
, XErrorEvent
* pErr
);
159 winMultiWindowWMIOErrorHandler(Display
* pDisplay
);
161 static void *winMultiWindowXMsgProc(void *pArg
);
164 winMultiWindowXMsgProcErrorHandler(Display
* pDisplay
, XErrorEvent
* pErr
);
167 winMultiWindowXMsgProcIOErrorHandler(Display
* pDisplay
);
170 winRedirectErrorHandler(Display
* pDisplay
, XErrorEvent
* pErr
);
173 winInitMultiWindowWM(WMInfoPtr pWMInfo
, WMProcArgPtr pProcArg
);
177 PreserveWin32Stack(WMInfoPtr pWMInfo
, Window iWindow
, UINT direction
);
182 CheckAnotherWindowManager(Display
* pDisplay
, DWORD dwScreen
,
186 winApplyHints(Display
* pDisplay
, Window iWindow
, HWND hWnd
, HWND
* zstyle
);
189 winUpdateWindowPosition(HWND hWnd
, HWND
* zstyle
);
195 static jmp_buf g_jmpWMEntry
;
196 static XIOErrorHandler g_winMultiWindowWMOldIOErrorHandler
;
197 static pthread_t g_winMultiWindowWMThread
;
198 static jmp_buf g_jmpXMsgProcEntry
;
199 static XIOErrorHandler g_winMultiWindowXMsgProcOldIOErrorHandler
;
200 static pthread_t g_winMultiWindowXMsgProcThread
;
201 static Bool g_shutdown
= FALSE
;
202 static Bool redirectError
= FALSE
;
203 static Bool g_fAnotherWMRunning
= FALSE
;
206 * PushMessage - Push a message onto the queue
210 PushMessage(WMMsgQueuePtr pQueue
, WMMsgNodePtr pNode
)
213 /* Lock the queue mutex */
214 pthread_mutex_lock(&pQueue
->pmMutex
);
218 if (pQueue
->pTail
!= NULL
) {
219 pQueue
->pTail
->pNext
= pNode
;
221 pQueue
->pTail
= pNode
;
223 if (pQueue
->pHead
== NULL
) {
224 pQueue
->pHead
= pNode
;
228 switch (pNode
->msg
.msg
) {
230 ErrorF("\tWM_WM_MOVE\n");
233 ErrorF("\tWM_WM_SIZE\n");
236 ErrorF("\tWM_WM_RAISE\n");
239 ErrorF("\tWM_WM_LOWER\n");
242 ErrorF("\tWM_WM_MAP\n");
245 ErrorF("\tWM_WM_MAP2\n");
248 ErrorF("\tWM_WM_MAP3\n");
251 ErrorF("\tWM_WM_UNMAP\n");
254 ErrorF("\tWM_WM_KILL\n");
257 ErrorF("\tWM_WM_ACTIVATE\n");
260 ErrorF("\tUnknown Message.\n");
265 /* Increase the count of elements in the queue by one */
266 ++(pQueue
->nQueueSize
);
268 /* Release the queue mutex */
269 pthread_mutex_unlock(&pQueue
->pmMutex
);
271 /* Signal that the queue is not empty */
272 pthread_cond_signal(&pQueue
->pcNotEmpty
);
275 #if CYGMULTIWINDOW_DEBUG
277 * QueueSize - Return the size of the queue
281 QueueSize(WMMsgQueuePtr pQueue
)
286 /* Loop through all elements in the queue */
287 for (pNode
= pQueue
->pHead
; pNode
!= NULL
; pNode
= pNode
->pNext
)
295 * PopMessage - Pop a message from the queue
299 PopMessage(WMMsgQueuePtr pQueue
, WMInfoPtr pWMInfo
)
303 /* Lock the queue mutex */
304 pthread_mutex_lock(&pQueue
->pmMutex
);
307 while (pQueue
->pHead
== NULL
) {
308 pthread_cond_wait(&pQueue
->pcNotEmpty
, &pQueue
->pmMutex
);
311 pNode
= pQueue
->pHead
;
312 if (pQueue
->pHead
!= NULL
) {
313 pQueue
->pHead
= pQueue
->pHead
->pNext
;
316 if (pQueue
->pTail
== pNode
) {
317 pQueue
->pTail
= NULL
;
320 /* Drop the number of elements in the queue by one */
321 --(pQueue
->nQueueSize
);
323 #if CYGMULTIWINDOW_DEBUG
324 ErrorF("Queue Size %d %d\n", pQueue
->nQueueSize
, QueueSize(pQueue
));
327 /* Release the queue mutex */
328 pthread_mutex_unlock(&pQueue
->pmMutex
);
339 HaveMessage(WMMsgQueuePtr pQueue
, UINT msg
, Window iWindow
)
343 for (pNode
= pQueue
->pHead
; pNode
!= NULL
; pNode
= pNode
->pNext
) {
344 if (pNode
->msg
.msg
== msg
&& pNode
->msg
.iWindow
== iWindow
)
353 * InitQueue - Initialize the Window Manager message queue
358 InitQueue(WMMsgQueuePtr pQueue
)
360 /* Check if the pQueue pointer is NULL */
361 if (pQueue
== NULL
) {
362 ErrorF("InitQueue - pQueue is NULL. Exiting.\n");
366 /* Set the head and tail to NULL */
367 pQueue
->pHead
= NULL
;
368 pQueue
->pTail
= NULL
;
370 /* There are no elements initially */
371 pQueue
->nQueueSize
= 0;
373 #if CYGMULTIWINDOW_DEBUG
374 winDebug("InitQueue - Queue Size %d %d\n", pQueue
->nQueueSize
,
378 winDebug("InitQueue - Calling pthread_mutex_init\n");
380 /* Create synchronization objects */
381 pthread_mutex_init(&pQueue
->pmMutex
, NULL
);
383 winDebug("InitQueue - pthread_mutex_init returned\n");
384 winDebug("InitQueue - Calling pthread_cond_init\n");
386 pthread_cond_init(&pQueue
->pcNotEmpty
, NULL
);
388 winDebug("InitQueue - pthread_cond_init returned\n");
395 Xutf8TextPropertyToString(Display
* pDisplay
, XTextProperty
* xtp
)
401 if (Xutf8TextPropertyToTextList(pDisplay
, xtp
, &ppList
, &nNum
) >= Success
&&
402 nNum
> 0 && *ppList
) {
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
]);
413 XFreeStringList(ppList
);
416 pszReturnData
= (char *) malloc(1);
417 pszReturnData
[0] = '\0';
420 return pszReturnData
;
424 * GetWindowName - Retrieve the title of an X Window
428 GetWindowName(Display
* pDisplay
, Window iWin
, char **ppWindowName
)
431 XTextProperty xtpWindowName
;
434 #if CYGMULTIWINDOW_DEBUG
435 ErrorF("GetWindowName\n");
438 /* Intialize ppWindowName to NULL */
439 *ppWindowName
= NULL
;
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");
450 pszWindowName
= Xutf8TextPropertyToString(pDisplay
, &xtpWindowName
);
451 XFree(xtpWindowName
.value
);
452 *ppWindowName
= pszWindowName
;
456 * Send a message to the X server from the WM thread
460 SendXMessage(Display
* pDisplay
, Window iWin
, Atom atmType
, long nData
)
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
;
472 /* Send the event to X */
473 return XSendEvent(pDisplay
, iWin
, False
, NoEventMask
, &e
);
477 * See if we can get the stored HWND for this window...
480 getHwnd(WMInfoPtr pWMInfo
, Window iWindow
)
484 unsigned long items
, remain
;
485 HWND
*retHwnd
, hWnd
= NULL
;
487 if (XGetWindowProperty(pWMInfo
->pDisplay
,
497 &remain
, (unsigned char **) &retHwnd
) == Success
) {
504 /* Some sanity checks */
514 * Updates the name of a HWND according to its X WM_NAME property
518 UpdateName(WMInfoPtr pWMInfo
, Window iWindow
)
521 XWindowAttributes attr
;
523 hWnd
= getHwnd(pWMInfo
, iWindow
);
527 /* If window isn't override-redirect */
528 XGetWindowAttributes(pWMInfo
->pDisplay
, iWindow
, &attr
);
529 if (!attr
.override_redirect
) {
532 /* Get the X windows window name */
533 GetWindowName(pWMInfo
->pDisplay
, iWindow
, &pszWindowName
);
536 /* Convert from UTF-8 to wide char */
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
);
544 /* Set the Windows window name */
545 SetWindowTextW(hWnd
, pwszWideWindowName
);
547 free(pwszWideWindowName
);
554 * Updates the icon of a HWND according to its X icon properties
558 UpdateIcon(WMInfoPtr pWMInfo
, Window iWindow
)
561 HICON hIconNew
= NULL
;
562 XWindowAttributes attr
;
564 hWnd
= getHwnd(pWMInfo
, iWindow
);
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;
574 if (XGetClassHint(pWMInfo
->pDisplay
, iWindow
, &class_hint
)) {
575 XFetchName(pWMInfo
->pDisplay
, iWindow
, &window_name
);
578 (HICON
) winOverrideIcon(class_hint
.res_name
,
579 class_hint
.res_class
, window_name
);
581 if (class_hint
.res_name
)
582 XFree(class_hint
.res_name
);
583 if (class_hint
.res_class
)
584 XFree(class_hint
.res_class
);
590 winUpdateIcon(hWnd
, pWMInfo
->pDisplay
, iWindow
, hIconNew
);
594 * Updates the style of a HWND according to its X style properties
598 UpdateStyle(WMInfoPtr pWMInfo
, Window iWindow
)
601 HWND zstyle
= HWND_NOTOPMOST
;
604 hWnd
= getHwnd(pWMInfo
, iWindow
);
608 /* Determine the Window style, which determines borders and clipping region... */
609 winApplyHints(pWMInfo
->pDisplay
, iWindow
, hWnd
, &zstyle
);
610 winUpdateWindowPosition(hWnd
, &zstyle
);
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
);
619 Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
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.
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.
627 winShowWindowOnTaskbar(hWnd
,
628 (GetWindowLongPtr(hWnd
, GWL_EXSTYLE
) &
629 WS_EX_APPWINDOW
) ? TRUE
: FALSE
);
634 * Fix up any differences between the X11 and Win32 window stacks
635 * starting at the window passed in
638 PreserveWin32Stack(WMInfoPtr pWMInfo
, Window iWindow
, UINT direction
)
641 DWORD myWinProcID
, winProcID
;
643 WINDOWPLACEMENT wndPlace
;
645 hWnd
= getHwnd(pWMInfo
, iWindow
);
649 GetWindowThreadProcessId(hWnd
, &myWinProcID
);
650 hWnd
= GetNextWindow(hWnd
, direction
);
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
);
661 if (direction
== GW_HWNDPREV
)
662 XRaiseWindow(pWMInfo
->pDisplay
, xWindow
);
664 XLowerWindow(pWMInfo
->pDisplay
, xWindow
);
668 hWnd
= GetNextWindow(hWnd
, direction
);
671 #endif /* PreserveWin32Stack */
674 * winMultiWindowWMProc
678 winMultiWindowWMProc(void *pArg
)
680 WMProcArgPtr pProcArg
= (WMProcArgPtr
) pArg
;
681 WMInfoPtr pWMInfo
= pProcArg
->pWMInfo
;
683 /* Initialize the Window Manager */
684 winInitMultiWindowWM(pWMInfo
, pProcArg
);
686 #if CYGMULTIWINDOW_DEBUG
687 ErrorF("winMultiWindowWMProc ()\n");
690 /* Loop until we explicitly break out */
694 if (g_fAnotherWMRunning
) { /* Another Window manager exists. */
699 /* Pop a message off of our queue */
700 pNode
= PopMessage(&pWMInfo
->wmMsgQueue
, pWMInfo
);
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");
708 #if CYGMULTIWINDOW_DEBUG
709 ErrorF("winMultiWindowWMProc - %d ms MSG: %d ID: %d\n",
710 GetTickCount(), (int) pNode
->msg
.msg
, (int) pNode
->msg
.dwID
);
713 /* Branch on the message type */
714 switch (pNode
->msg
.msg
) {
717 ErrorF("\tWM_WM_MOVE\n");
721 ErrorF("\tWM_WM_SIZE\n");
726 #if CYGMULTIWINDOW_DEBUG
727 ErrorF("\tWM_WM_RAISE\n");
729 /* Raise the window */
730 XRaiseWindow(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
);
732 PreserveWin32Stack(pWMInfo
, pNode
->msg
.iWindow
, GW_HWNDPREV
);
737 #if CYGMULTIWINDOW_DEBUG
738 ErrorF("\tWM_WM_LOWER\n");
741 /* Lower the window */
742 XLowerWindow(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
);
746 #if CYGMULTIWINDOW_DEBUG
747 ErrorF("\tWM_WM_MAP\n");
749 /* Put a note as to the HWND associated with this Window */
750 XChangeProperty(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
, pWMInfo
->atmPrivMap
, XA_INTEGER
,
753 (unsigned char *) &(pNode
->msg
.hwndWindow
), sizeof(HWND
)/4);
754 UpdateName(pWMInfo
, pNode
->msg
.iWindow
);
755 UpdateIcon(pWMInfo
, pNode
->msg
.iWindow
);
759 #if CYGMULTIWINDOW_DEBUG
760 ErrorF("\tWM_WM_MAP2\n");
762 XChangeProperty(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
, pWMInfo
->atmPrivMap
, XA_INTEGER
,
765 (unsigned char *) &(pNode
->msg
.hwndWindow
), sizeof(HWND
)/4);
769 #if CYGMULTIWINDOW_DEBUG
770 ErrorF("\tWM_WM_MAP3\n");
772 /* Put a note as to the HWND associated with this Window */
773 XChangeProperty(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
, pWMInfo
->atmPrivMap
, XA_INTEGER
,
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
);
785 GetProp(pNode
->msg
.hwndWindow
, WIN_WINDOW_PROP
);
787 winReshapeMultiWindow(pWin
);
788 winUpdateRgnMultiWindow(pWin
);
795 #if CYGMULTIWINDOW_DEBUG
796 ErrorF("\tWM_WM_UNMAP\n");
799 /* Unmap the window */
800 XUnmapWindow(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
);
804 #if CYGMULTIWINDOW_DEBUG
805 ErrorF("\tWM_WM_KILL\n");
812 if (XGetWMProtocols(pWMInfo
->pDisplay
,
813 pNode
->msg
.iWindow
, &protocols
, &n
)) {
814 for (i
= 0; i
< n
; ++i
)
815 if (protocols
[i
] == pWMInfo
->atmWmDelete
)
823 SendXMessage(pWMInfo
->pDisplay
,
825 pWMInfo
->atmWmProtos
, pWMInfo
->atmWmDelete
);
827 XKillClient(pWMInfo
->pDisplay
, pNode
->msg
.iWindow
);
832 #if CYGMULTIWINDOW_DEBUG
833 ErrorF("\tWM_WM_ACTIVATE\n");
836 /* Set the input focus */
837 XSetInputFocus(pWMInfo
->pDisplay
,
839 RevertToPointerRoot
, CurrentTime
);
842 case WM_WM_NAME_EVENT
:
843 UpdateName(pWMInfo
, pNode
->msg
.iWindow
);
846 case WM_WM_ICON_EVENT
:
847 UpdateIcon(pWMInfo
, pNode
->msg
.iWindow
);
850 case WM_WM_HINTS_EVENT
:
852 XWindowAttributes attr
;
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
)
859 UpdateStyle(pWMInfo
, pNode
->msg
.iWindow
);
863 case WM_WM_CHANGE_STATE
:
864 /* Minimize the window in Windows */
865 winMinimizeWindow(pNode
->msg
.iWindow
);
869 ErrorF("winMultiWindowWMProc - Unknown Message. Exiting.\n");
874 /* Free the retrieved message */
877 /* Flush any pending events on our display */
878 XFlush(pWMInfo
->pDisplay
);
881 /* Free the condition variable */
882 pthread_cond_destroy(&pWMInfo
->wmMsgQueue
.pcNotEmpty
);
884 /* Free the mutex variable */
885 pthread_mutex_destroy(&pWMInfo
->wmMsgQueue
.pmMutex
);
887 /* Free the passed-in argument */
890 #if CYGMULTIWINDOW_DEBUG
891 ErrorF("-winMultiWindowWMProc ()\n");
897 * X message procedure
901 winMultiWindowXMsgProc(void *pArg
)
904 XMsgProcArgPtr pProcArg
= (XMsgProcArgPtr
) pArg
;
905 char pszDisplay
[512];
912 Atom atmWindowState
, atmMotifWmHints
, atmWindowType
, atmNormalHints
;
916 winDebug("winMultiWindowXMsgProc - Hello\n");
918 /* Check that argument pointer is not invalid */
919 if (pProcArg
== NULL
) {
920 ErrorF("winMultiWindowXMsgProc - pProcArg is NULL. Exiting.\n");
924 ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
926 /* Grab the server started mutex - pause until we get it */
927 iReturn
= pthread_mutex_lock(pProcArg
->ppmServerStarted
);
929 ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d. "
930 "Exiting.\n", iReturn
);
934 ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
936 /* Allow multiple threads to access Xlib */
937 if (XInitThreads() == 0) {
938 ErrorF("winMultiWindowXMsgProc - XInitThreads () failed. Exiting.\n");
942 /* See if X supports the current locale */
943 if (XSupportsLocale() == False
) {
944 ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n");
947 /* Release the server started mutex */
948 pthread_mutex_unlock(pProcArg
->ppmServerStarted
);
950 ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
952 /* Install our error handler */
953 XSetErrorHandler(winMultiWindowXMsgProcErrorHandler
);
954 g_winMultiWindowXMsgProcThread
= pthread_self();
955 g_winMultiWindowXMsgProcOldIOErrorHandler
=
956 XSetIOErrorHandler(winMultiWindowXMsgProcIOErrorHandler
);
958 /* Set jump point for IO Error exits */
959 iReturn
= setjmp(g_jmpXMsgProcEntry
);
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",
968 else if (iReturn
== WIN_JMP_ERROR_IO
) {
969 ErrorF("winInitMultiWindowXMsgProc - Caught IO Error. Exiting.\n");
973 /* Setup the display connection string x */
975 512, "127.0.0.1:%s.%d", display
, (int) pProcArg
->dwScreen
);
977 /* Print the display connection string */
978 ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay
);
980 /* Use our generated cookie for authentication */
981 winSetAuthorization();
983 /* Initialize retry count */
986 /* Open the X display */
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
);
994 sleep(WIN_CONNECT_DELAY
);
1000 while (pProcArg
->pDisplay
== NULL
&& iRetries
< WIN_CONNECT_RETRIES
);
1002 /* Make sure that the display opened */
1003 if (pProcArg
->pDisplay
== NULL
) {
1004 ErrorF("winMultiWindowXMsgProc - Failed opening the display. "
1009 ErrorF("winMultiWindowXMsgProc - XOpenDisplay () returned and "
1010 "successfully opened the display.\n");
1012 /* Check if another window manager is already running */
1013 g_fAnotherWMRunning
=
1014 CheckAnotherWindowManager(pProcArg
->pDisplay
, pProcArg
->dwScreen
,
1015 pProcArg
->pWMInfo
->fAllowOtherWM
);
1017 if (g_fAnotherWMRunning
&& !pProcArg
->pWMInfo
->fAllowOtherWM
) {
1018 ErrorF("winMultiWindowXMsgProc - "
1019 "another window manager is running. Exiting.\n");
1023 /* Set up the supported icon sizes */
1024 xis
= XAllocIconSize();
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
),
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
);
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.
1049 Since this is on in the default Solaris 10 install,
1050 workaround this by making sure it does exist...
1052 XInternAtom(pProcArg
->pDisplay
, "WM_STATE", 0);
1054 /* Loop until we explicitly break out */
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);
1068 if (g_fAnotherWMRunning
) {
1069 g_fAnotherWMRunning
= FALSE
;
1070 SendMessage(pProcArg
->hwndScreen
, WM_MANAGE
, 0, 0);
1077 /* Fetch next event */
1078 XNextEvent(pProcArg
->pDisplay
, &event
);
1080 /* Branch on event type */
1081 if (event
.type
== CreateNotify
) {
1082 XWindowAttributes attr
;
1084 XSelectInput(pProcArg
->pDisplay
,
1085 event
.xcreatewindow
.window
, PropertyChangeMask
);
1087 /* Get the window attributes */
1088 XGetWindowAttributes(pProcArg
->pDisplay
,
1089 event
.xcreatewindow
.window
, &attr
);
1091 if (!attr
.override_redirect
)
1092 XSetWindowBorderWidth(pProcArg
->pDisplay
,
1093 event
.xcreatewindow
.window
, 0);
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.
1100 We don't actually need to reparent, as the frame is
1101 a native window, not an X window
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)
1108 See sourceware bugzilla #9848
1111 XWindowAttributes attr
;
1115 unsigned int nchildren
;
1117 if (XGetWindowAttributes(event
.xmap
.display
,
1120 XQueryTree(event
.xmap
.display
,
1122 &root
, &parent
, &children
, &nchildren
)) {
1127 It's a top-level window if the parent window is a root window
1128 Only non-override_redirect windows can get reparented
1130 if ((attr
.root
== parent
) && !event
.xmap
.override_redirect
) {
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
;
1140 XSendEvent(event
.xmap
.display
,
1142 True
, StructureNotifyMask
, &event_send
);
1146 else if (event
.type
== ConfigureNotify
) {
1147 if (!event
.xconfigure
.send_event
) {
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)
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)
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
1159 XEvent event_send
= event
;
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
);
1168 else if (event
.type
== PropertyNotify
) {
1169 if (event
.xproperty
.atom
== atmWmName
) {
1170 memset(&msg
, 0, sizeof(msg
));
1172 msg
.msg
= WM_WM_NAME_EVENT
;
1173 msg
.iWindow
= event
.xproperty
.window
;
1175 /* Other fields ignored */
1176 winSendMessageToWM(pProcArg
->pWMInfo
, &msg
);
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())
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
;
1192 /* Other fields ignored */
1193 winSendMessageToWM(pProcArg
->pWMInfo
, &msg
);
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
;
1203 /* Other fields ignored */
1204 winSendMessageToWM(pProcArg
->pWMInfo
, &msg
);
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");
1213 memset(&msg
, 0, sizeof(msg
));
1215 msg
.msg
= WM_WM_CHANGE_STATE
;
1216 msg
.iWindow
= event
.xclient
.window
;
1218 winSendMessageToWM(pProcArg
->pWMInfo
, &msg
);
1222 XCloseDisplay(pProcArg
->pDisplay
);
1228 * winInitWM - Entry point for the X server to spawn
1229 * the Window Manager thread. Called from
1230 * winscrinit.c/winFinishScreenInitFB ().
1234 winInitWM(void **ppWMInfo
,
1235 pthread_t
* ptWMProc
,
1236 pthread_t
* ptXMsgProc
,
1237 pthread_mutex_t
* ppmServerStarted
,
1238 int dwScreen
, HWND hwndScreen
, BOOL allowOtherWM
)
1240 WMProcArgPtr pArg
= (WMProcArgPtr
) malloc(sizeof(WMProcArgRec
));
1241 WMInfoPtr pWMInfo
= (WMInfoPtr
) malloc(sizeof(WMInfoRec
));
1242 XMsgProcArgPtr pXMsgArg
= (XMsgProcArgPtr
) malloc(sizeof(XMsgProcArgRec
));
1244 /* Bail if the input parameters are bad */
1245 if (pArg
== NULL
|| pWMInfo
== NULL
|| pXMsgArg
== NULL
) {
1246 ErrorF("winInitWM - malloc failed.\n");
1253 /* Zero the allocated memory */
1254 ZeroMemory(pArg
, sizeof(WMProcArgRec
));
1255 ZeroMemory(pWMInfo
, sizeof(WMInfoRec
));
1256 ZeroMemory(pXMsgArg
, sizeof(XMsgProcArgRec
));
1258 /* Set a return pointer to the Window Manager info structure */
1259 *ppWMInfo
= pWMInfo
;
1260 pWMInfo
->fAllowOtherWM
= allowOtherWM
;
1262 /* Setup the argument structure for the thread function */
1263 pArg
->dwScreen
= dwScreen
;
1264 pArg
->pWMInfo
= pWMInfo
;
1265 pArg
->ppmServerStarted
= ppmServerStarted
;
1267 /* Intialize the message queue */
1268 if (!InitQueue(&pWMInfo
->wmMsgQueue
)) {
1269 ErrorF("winInitWM - InitQueue () failed.\n");
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");
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");
1292 winDebug("winInitWM - Returning.\n");
1299 * Window manager thread - setup
1303 winInitMultiWindowWM(WMInfoPtr pWMInfo
, WMProcArgPtr pProcArg
)
1306 char pszDisplay
[512];
1309 winDebug("winInitMultiWindowWM - Hello\n");
1311 /* Check that argument pointer is not invalid */
1312 if (pProcArg
== NULL
) {
1313 ErrorF("winInitMultiWindowWM - pProcArg is NULL. Exiting.\n");
1317 ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
1319 /* Grab our garbage mutex to satisfy pthread_cond_wait */
1320 iReturn
= pthread_mutex_lock(pProcArg
->ppmServerStarted
);
1322 ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d. "
1323 "Exiting.\n", iReturn
);
1327 ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
1329 /* Allow multiple threads to access Xlib */
1330 if (XInitThreads() == 0) {
1331 ErrorF("winInitMultiWindowWM - XInitThreads () failed. Exiting.\n");
1335 /* See if X supports the current locale */
1336 if (XSupportsLocale() == False
) {
1337 ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n");
1340 /* Release the server started mutex */
1341 pthread_mutex_unlock(pProcArg
->ppmServerStarted
);
1343 ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
1345 /* Install our error handler */
1346 XSetErrorHandler(winMultiWindowWMErrorHandler
);
1347 g_winMultiWindowWMThread
= pthread_self();
1348 g_winMultiWindowWMOldIOErrorHandler
=
1349 XSetIOErrorHandler(winMultiWindowWMIOErrorHandler
);
1351 /* Set jump point for IO Error exits */
1352 iReturn
= setjmp(g_jmpWMEntry
);
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",
1361 else if (iReturn
== WIN_JMP_ERROR_IO
) {
1362 ErrorF("winInitMultiWindowWM - Caught IO Error. Exiting.\n");
1366 /* Setup the display connection string x */
1367 snprintf(pszDisplay
,
1368 512, "127.0.0.1:%s.%d", display
, (int) pProcArg
->dwScreen
);
1370 /* Print the display connection string */
1371 ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay
);
1373 /* Use our generated cookie for authentication */
1374 winSetAuthorization();
1376 /* Open the X display */
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
);
1384 sleep(WIN_CONNECT_DELAY
);
1390 while (pWMInfo
->pDisplay
== NULL
&& iRetries
< WIN_CONNECT_RETRIES
);
1392 /* Make sure that the display opened */
1393 if (pWMInfo
->pDisplay
== NULL
) {
1394 ErrorF("winInitMultiWindowWM - Failed opening the display. "
1399 ErrorF("winInitMultiWindowWM - XOpenDisplay () returned and "
1400 "successfully opened the display.\n");
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
);
1408 pWMInfo
->atmPrivMap
= XInternAtom(pWMInfo
->pDisplay
,
1409 WINDOWSWM_NATIVE_HWND
, False
);
1412 Cursor cursor
= XCreateFontCursor(pWMInfo
->pDisplay
, XC_left_ptr
);
1415 XDefineCursor(pWMInfo
->pDisplay
,
1416 DefaultRootWindow(pWMInfo
->pDisplay
), cursor
);
1417 XFreeCursor(pWMInfo
->pDisplay
, cursor
);
1423 * winSendMessageToWM - Send a message from the X thread to the WM thread
1427 winSendMessageToWM(void *pWMInfo
, winWMMessagePtr pMsg
)
1431 #if CYGMULTIWINDOW_DEBUG
1432 ErrorF("winSendMessageToWM ()\n");
1435 pNode
= (WMMsgNodePtr
) malloc(sizeof(WMMsgNodeRec
));
1436 if (pNode
!= NULL
) {
1437 memcpy(&pNode
->msg
, pMsg
, sizeof(winWMMessageRec
));
1438 PushMessage(&((WMInfoPtr
) pWMInfo
)->wmMsgQueue
, pNode
);
1443 * Window manager error handler
1447 winMultiWindowWMErrorHandler(Display
* pDisplay
, XErrorEvent
* pErr
)
1449 char pszErrorMsg
[100];
1451 if (pErr
->request_code
== X_ChangeWindowAttributes
1452 && pErr
->error_code
== BadAccess
) {
1453 ErrorF("winMultiWindowWMErrorHandler - ChangeWindowAttributes "
1458 XGetErrorText(pDisplay
, pErr
->error_code
, pszErrorMsg
, sizeof(pszErrorMsg
));
1459 ErrorF("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg
);
1465 * Window manager IO error handler
1469 winMultiWindowWMIOErrorHandler(Display
* pDisplay
)
1471 ErrorF("winMultiWindowWMIOErrorHandler!\n");
1473 if (pthread_equal(pthread_self(), g_winMultiWindowWMThread
)) {
1477 /* Restart at the main entry point */
1478 longjmp(g_jmpWMEntry
, WIN_JMP_ERROR_IO
);
1481 if (g_winMultiWindowWMOldIOErrorHandler
)
1482 g_winMultiWindowWMOldIOErrorHandler(pDisplay
);
1488 * X message procedure error handler
1492 winMultiWindowXMsgProcErrorHandler(Display
* pDisplay
, XErrorEvent
* pErr
)
1494 char pszErrorMsg
[100];
1496 XGetErrorText(pDisplay
, pErr
->error_code
, pszErrorMsg
, sizeof(pszErrorMsg
));
1497 #if CYGMULTIWINDOW_DEBUG
1498 ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg
);
1505 * X message procedure IO error handler
1509 winMultiWindowXMsgProcIOErrorHandler(Display
* pDisplay
)
1511 ErrorF("winMultiWindowXMsgProcIOErrorHandler!\n");
1513 if (pthread_equal(pthread_self(), g_winMultiWindowXMsgProcThread
)) {
1514 /* Restart at the main entry point */
1515 longjmp(g_jmpXMsgProcEntry
, WIN_JMP_ERROR_IO
);
1518 if (g_winMultiWindowXMsgProcOldIOErrorHandler
)
1519 g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay
);
1525 * Catch RedirectError to detect other window manager running
1529 winRedirectErrorHandler(Display
* pDisplay
, XErrorEvent
* pErr
)
1531 redirectError
= TRUE
;
1536 * Check if another window manager is running
1540 CheckAnotherWindowManager(Display
* pDisplay
, DWORD dwScreen
,
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...
1547 redirectError
= FALSE
;
1548 XSetErrorHandler(winRedirectErrorHandler
);
1549 XSelectInput(pDisplay
, RootWindow(pDisplay
, dwScreen
),
1550 ResizeRedirectMask
| SubstructureRedirectMask
|
1553 XSetErrorHandler(winMultiWindowXMsgProcErrorHandler
);
1556 Side effect: select the events we are actually interested in...
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...
1561 XSelectInput(pDisplay
, RootWindow(pDisplay
, dwScreen
),
1562 SubstructureNotifyMask
| (!fAllowOtherWM
? ButtonPressMask
:
1565 return redirectError
;
1569 * Notify the MWM thread we're exiting and not to reconnect
1573 winDeinitMultiWindowWM(void)
1575 ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
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)
1593 winApplyHints(Display
* pDisplay
, Window iWindow
, HWND hWnd
, HWND
* zstyle
)
1595 static Atom windowState
, motif_wm_hints
, windowType
;
1596 static Atom hiddenState
, fullscreenState
, belowState
, aboveState
,
1598 static Atom dockWindow
;
1599 static int generation
;
1600 Atom type
, *pAtom
= NULL
;
1602 unsigned long hint
= 0, maxmin
= 0, nitems
= 0, left
= 0;
1603 unsigned long style
, exStyle
;
1604 MwmHints
*mwm_hint
= NULL
;
1608 if (!IsWindow(hWnd
))
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
);
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
);
1623 XInternAtom(pDisplay
, "_NET_WM_STATE_SKIP_TASKBAR", False
);
1626 if (XGetWindowProperty(pDisplay
, iWindow
, windowState
, 0L,
1627 MAXINT
, False
, XA_ATOM
, &type
, &format
,
1629 (unsigned char **) &pAtom
) == Success
) {
1633 for (i
= 0; i
< nitems
; i
++) {
1634 if (pAtom
[i
] == skiptaskbarState
)
1635 hint
|= HINT_SKIPTASKBAR
;
1636 if (pAtom
[i
] == hiddenState
)
1638 else if (pAtom
[i
] == fullscreenState
)
1640 if (pAtom
[i
] == belowState
)
1641 *zstyle
= HWND_BOTTOM
;
1642 else if (pAtom
[i
] == aboveState
)
1643 *zstyle
= HWND_TOPMOST
;
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
;
1675 MwmDecorAll means all decorations *except* those specified by other flag
1676 bits that are set. Not yet implemented.
1686 if (XGetWindowProperty(pDisplay
, iWindow
, windowType
, 0L,
1687 1L, False
, XA_ATOM
, &type
, &format
,
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
;
1701 XSizeHints
*normal_hint
= XAllocSizeHints();
1705 (XGetWMNormalHints(pDisplay
, iWindow
, normal_hint
, &supplied
) ==
1707 if (normal_hint
->flags
& PMaxSize
) {
1708 /* Not maximizable if a maximum size is specified */
1709 hint
|= HINT_NOMAXIMIZE
;
1711 if (normal_hint
->flags
& PMinSize
) {
1713 If both minimum size and maximum size are specified and are the same,
1714 don't bother with a resizing frame
1716 if ((normal_hint
->min_width
== normal_hint
->max_width
)
1717 && (normal_hint
->min_height
== normal_hint
->max_height
))
1718 hint
= (hint
& ~HINT_SIZEBOX
);
1726 Override hint settings from above with settings from config file and set
1727 application id for grouping.
1730 XClassHint class_hint
= { 0, 0 };
1731 char *window_name
= 0;
1732 char *application_id
= 0;
1734 if (XGetClassHint(pDisplay
, iWindow
, &class_hint
)) {
1735 XFetchName(pDisplay
, iWindow
, &window_name
);
1738 winOverrideStyle(class_hint
.res_name
, class_hint
.res_class
,
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
);
1748 asprintf(&application_id
, APPLICATION_ID_FORMAT
, XVENDORNAME
,
1749 APPLICATION_ID_UNKNOWN
);
1751 winSetAppUserModelID(hWnd
, application_id
);
1753 if (class_hint
.res_name
)
1754 XFree(class_hint
.res_name
);
1755 if (class_hint
.res_class
)
1756 XFree(class_hint
.res_class
);
1758 free(application_id
);
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
;
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);
1781 if (style
& STYLE_NOTITLE
)
1783 (hint
& ~HINT_NOFRAME
& ~HINT_BORDER
& ~HINT_CAPTION
) |
1785 else if (style
& STYLE_OUTLINE
)
1787 (hint
& ~HINT_NOFRAME
& ~HINT_SIZEBOX
& ~HINT_CAPTION
) |
1789 else if (style
& STYLE_NOFRAME
)
1791 (hint
& ~HINT_BORDER
& ~HINT_CAPTION
& ~HINT_SIZEBOX
) |
1794 /* Now apply styles to window */
1795 style
= GetWindowLongPtr(hWnd
, GWL_STYLE
);
1797 return; /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
1799 style
&= ~WS_CAPTION
& ~WS_SIZEBOX
; /* Just in case */
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
;
1806 style
= style
| ((hint
& HINT_BORDER
) ? WS_BORDER
: 0) |
1807 ((hint
& HINT_SIZEBOX
) ? WS_SIZEBOX
: 0) |
1808 ((hint
& HINT_CAPTION
) ? WS_CAPTION
: 0);
1810 if (hint
& HINT_NOMAXIMIZE
)
1811 style
= style
& ~WS_MAXIMIZEBOX
;
1813 if (hint
& HINT_NOMINIMIZE
)
1814 style
= style
& ~WS_MINIMIZEBOX
;
1816 if (hint
& HINT_NOSYSMENU
)
1817 style
= style
& ~WS_SYSMENU
;
1819 if (hint
& HINT_SKIPTASKBAR
)
1820 style
= style
& ~WS_MINIMIZEBOX
; /* window will become lost if minimized */
1822 SetWindowLongPtr(hWnd
, GWL_STYLE
, style
);
1824 exStyle
= GetWindowLongPtr(hWnd
, GWL_EXSTYLE
);
1825 if (hint
& HINT_SKIPTASKBAR
)
1826 exStyle
= (exStyle
& ~WS_EX_APPWINDOW
) | WS_EX_TOOLWINDOW
;
1828 exStyle
= (exStyle
& ~WS_EX_TOOLWINDOW
) | WS_EX_APPWINDOW
;
1829 SetWindowLongPtr(hWnd
, GWL_EXSTYLE
, exStyle
);
1832 ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
1833 iWindow
, hint
, style
, exStyle
);
1837 winUpdateWindowPosition(HWND hWnd
, HWND
* zstyle
)
1839 int iX
, iY
, iWidth
, iHeight
;
1842 WindowPtr pWin
= GetProp(hWnd
, WIN_WINDOW_PROP
);
1843 DrawablePtr pDraw
= NULL
;
1847 pDraw
= &pWin
->drawable
;
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
);
1855 /* Get the height and width of the X window */
1856 iWidth
= pWin
->drawable
.width
;
1857 iHeight
= pWin
->drawable
.height
;
1859 /* Setup a rectangle with the X window position and size */
1860 SetRect(&rcNew
, iX
, iY
, iX
+ iWidth
, iY
+ iHeight
);
1862 winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
1863 rcNew
.left
, rcNew
.top
, rcNew
.right
, rcNew
.bottom
);
1865 AdjustWindowRectEx(&rcNew
, GetWindowLongPtr(hWnd
, GWL_STYLE
), FALSE
,
1866 GetWindowLongPtr(hWnd
, GWL_EXSTYLE
));
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
;
1875 if (rcNew
.top
< GetSystemMetrics(SM_YVIRTUALSCREEN
)) {
1876 iDy
= GetSystemMetrics(SM_YVIRTUALSCREEN
) - rcNew
.top
;
1878 rcNew
.bottom
+= iDy
;
1881 winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
1882 rcNew
.left
, rcNew
.top
, rcNew
.right
, rcNew
.bottom
);
1884 /* Position the Windows window */
1885 SetWindowPos(hWnd
, *zstyle
, rcNew
.left
, rcNew
.top
,
1886 rcNew
.right
- rcNew
.left
, rcNew
.bottom
- rcNew
.top
, 0);