diff options
Diffstat (limited to 'hw/xwin/winmultiwindowwm.c')
-rw-r--r-- | hw/xwin/winmultiwindowwm.c | 731 |
1 files changed, 509 insertions, 222 deletions
diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index 6599dfba8..860df9ac9 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -30,10 +30,24 @@ * Colin Harrison */ +#ifndef WINVER +#define WINVER 0x0500 +#endif + /* X headers */ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + +/* + * Including any server header might define the macro _XSERVER64 on 64 bit machines. + * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen. + * So let's undef that macro if necessary. + */ +#ifdef _XSERVER64 +#undef _XSERVER64 +#endif + #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -48,20 +62,19 @@ #include <X11/X.h> #include <X11/Xatom.h> #include <X11/Xlib.h> -#include <X11/Xlocale.h> #include <X11/Xproto.h> #include <X11/Xutil.h> #include <X11/cursorfont.h> +#include <X11/extensions/Xcomposite.h> #include <X11/Xwindows.h> /* Local headers */ #include "winwindow.h" #include "winprefs.h" #include "window.h" -#include "pixmapstr.h" -#include "windowstr.h" #include "winglobals.h" #include "windisplay.h" +#include "winmultiwindowicons.h" #ifdef XWIN_MULTIWINDOWEXTWM #include <X11/extensions/windowswmstr.h> @@ -78,6 +91,9 @@ extern void winDebug(const char *format, ...); extern void winReshapeMultiWindow(WindowPtr pWin); extern void winUpdateRgnMultiWindow(WindowPtr pWin); +extern void winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew); +extern void winSetAuthorization(void); +extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle); #ifndef CYGDEBUG #define CYGDEBUG NO @@ -115,11 +131,22 @@ typedef struct _WMMsgQueueRec { typedef struct _WMInfo { Display *pDisplay; WMMsgQueueRec wmMsgQueue; + Atom atmUTF8String; Atom atmWmProtos; Atom atmWmDelete; Atom atmWmTakeFocus; Atom atmPrivMap; + Atom atmNetWmName; + Atom atmCurrentDesktop; + Atom atmNumberDesktops; + Atom atmDesktopNames; + Atom atmWmState; + Atom atmNetWmState; + Atom atmHiddenState; + Atom atmVertMaxState; + Atom atmHorzMaxState; Bool fAllowOtherWM; + Bool fCompositeWM; } WMInfoRec, *WMInfoPtr; typedef struct _WMProcArgRec { @@ -149,7 +176,7 @@ static Bool InitQueue(WMMsgQueuePtr pQueue); static void - GetWindowName(Display * pDpy, Window iWin, char **ppWindowName); + GetWindowName(Display * pDpy, Window iWin, char **ppWindowName, Atom atmNetWmName); static int SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData); @@ -173,6 +200,9 @@ static int static int winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay); +static void +winMultiWindowThreadExit(void *arg); + static int winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr); @@ -190,10 +220,10 @@ CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, Bool fAllowOtherWM); static void - winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle); + winApplyUrgency(Display * pDisplay, Window iWindow, HWND hWnd); -void - winUpdateWindowPosition(HWND hWnd, HWND * zstyle); +static void + winApplyHints(WMInfoPtr pWMInfo, Window iWindow, HWND hWnd, HWND * zstyle, Bool onCreate); /* * Local globals @@ -210,6 +240,64 @@ static Bool redirectError = FALSE; static Bool g_fAnotherWMRunning = FALSE; /* + * Translate msg id to text, for debug purposes + */ + +static const char * +MessageName(winWMMessagePtr msg) +{ + switch (msg->msg) + { + case WM_WM_MOVE: + return "WM_WM_MOVE"; + break; + case WM_WM_SIZE: + return "WM_WM_SIZE"; + break; + case WM_WM_RAISE: + return "WM_WM_RAISE"; + break; + case WM_WM_LOWER: + return "WM_WM_LOWER"; + break; + case WM_WM_UNMAP: + return "WM_WM_UNMAP"; + break; + case WM_WM_KILL: + return "WM_WM_KILL"; + break; + case WM_WM_ACTIVATE: + return "WM_WM_ACTIVATE"; + break; + case WM_WM_NAME_EVENT: + return "WM_WM_NAME_EVENT"; + break; + case WM_WM_ICON_EVENT: + return "WM_WM_ICON_EVENT"; + break; + case WM_WM_CHANGE_STATE: + return "WM_WM_CHANGE_STATE"; + break; + case WM_WM_MAP: + return "WM_WM_MAP"; + break; + case WM_WM_MAP_UNMANAGED: + return "WM_WM_MAP_UNMANAGED"; + break; + case WM_WM_MAP_MANAGED: + return "WM_WM_MAP_MANAGED"; + break; + case WM_WM_HINTS_EVENT: + return "WM_WM_HINTS_EVENT"; + break; + default: + return "Unknown Message"; + break; + } +} + + +/* * PushMessage - Push a message onto the queue */ @@ -231,44 +319,6 @@ PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode) pQueue->pHead = pNode; } -#if 0 - switch (pNode->msg.msg) { - case WM_WM_MOVE: - ErrorF("\tWM_WM_MOVE\n"); - break; - case WM_WM_SIZE: - ErrorF("\tWM_WM_SIZE\n"); - break; - case WM_WM_RAISE: - ErrorF("\tWM_WM_RAISE\n"); - break; - case WM_WM_LOWER: - ErrorF("\tWM_WM_LOWER\n"); - break; - case WM_WM_MAP: - ErrorF("\tWM_WM_MAP\n"); - break; - case WM_WM_MAP2: - ErrorF("\tWM_WM_MAP2\n"); - break; - case WM_WM_MAP3: - ErrorF("\tWM_WM_MAP3\n"); - break; - case WM_WM_UNMAP: - ErrorF("\tWM_WM_UNMAP\n"); - break; - case WM_WM_KILL: - ErrorF("\tWM_WM_KILL\n"); - break; - case WM_WM_ACTIVATE: - ErrorF("\tWM_WM_ACTIVATE\n"); - break; - default: - ErrorF("\tUnknown Message.\n"); - break; - } -#endif - /* Increase the count of elements in the queue by one */ ++(pQueue->nQueueSize); @@ -432,14 +482,10 @@ Xutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp) */ static void -GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) +GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName, Atom atmNetWmName) { int nResult; - XTextProperty xtpWindowName; - XTextProperty xtpClientMachine; - char *pszWindowName; - char *pszClientMachine; - char hostname[HOST_NAME_MAX + 1]; + char *pszWindowName = NULL; #if CYGMULTIWINDOW_DEBUG ErrorF("GetWindowName\n"); @@ -448,35 +494,75 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) /* Intialize ppWindowName to NULL */ *ppWindowName = NULL; - /* Try to get window name */ - nResult = XGetWMName(pDisplay, iWin, &xtpWindowName); - if (!nResult || !xtpWindowName.value || !xtpWindowName.nitems) { + /* Try to get window name from _NET_WM_NAME */ + { + char *utf8WindowName; + Atom type; + int format; + unsigned long nitems, after; + + nResult = XGetWindowProperty(pDisplay, iWin, atmNetWmName, + 0, INT_MAX, False, + AnyPropertyType, &type, &format, + &nitems, &after, + (unsigned char **)&utf8WindowName); + if ((nResult == Success) && (type != None)) + { + pszWindowName = strdup(utf8WindowName); + XFree(utf8WindowName); + } + } + + /* Otherwise, try to get window name from WM_NAME */ + if (!pszWindowName) + { + XTextProperty xtpWindowName; + + nResult = XGetWMName(pDisplay, iWin, &xtpWindowName); + if (!nResult || !xtpWindowName.value || !xtpWindowName.nitems) { #if CYGMULTIWINDOW_DEBUG - ErrorF("GetWindowName - XGetWMName failed. No name.\n"); + ErrorF("GetWindowName - XGetWMName failed. No name.\n"); #endif - return; - } + return; + } + + pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName); + XFree(xtpWindowName.value); + } - pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName); - XFree(xtpWindowName.value); + /* return the window name, unless... */ + *ppWindowName = pszWindowName; if (g_fHostInTitle) { + XTextProperty xtpClientMachine; + /* Try to get client machine name */ nResult = XGetWMClientMachine(pDisplay, iWin, &xtpClientMachine); if (nResult && xtpClientMachine.value && xtpClientMachine.nitems) { + char *pszClientMachine; + char *pszClientHostname; + char *dot; + char hostname[HOST_NAME_MAX + 1]; + pszClientMachine = Xutf8TextPropertyToString(pDisplay, &xtpClientMachine); XFree(xtpClientMachine.value); + /* If client machine name looks like a FQDN, find the hostname */ + pszClientHostname = strdup(pszClientMachine); + dot = strchr(pszClientHostname, '.'); + if (dot) + *dot = '\0'; + /* - If we have a client machine name - and it's not the local host name + If we have a client machine hostname + and it's not the local hostname and it's not already in the window title... */ - if (strlen(pszClientMachine) && + if (strlen(pszClientHostname) && !gethostname(hostname, HOST_NAME_MAX + 1) && - strcmp(hostname, pszClientMachine) && - (strstr(pszWindowName, pszClientMachine) == 0)) { + strcmp(hostname, pszClientHostname) && + (strstr(pszWindowName, pszClientHostname) == 0)) { /* ... add '@<clientmachine>' to end of window name */ *ppWindowName = malloc(strlen(pszWindowName) + @@ -486,15 +572,12 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) strcat(*ppWindowName, pszClientMachine); free(pszWindowName); - free(pszClientMachine); - - return; } + + free(pszClientMachine); + free(pszClientHostname); } } - - /* otherwise just return the window name */ - *ppWindowName = pszWindowName; } /* @@ -528,6 +611,7 @@ SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData) XEvent e; /* Prepare the X event structure */ + memset(&e, 0, sizeof(e)); e.type = ClientMessage; e.xclient.window = iWin; e.xclient.message_type = atmType; @@ -596,7 +680,7 @@ UpdateName(WMInfoPtr pWMInfo, Window iWindow) char *pszWindowName; /* Get the X windows window name */ - GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName); + GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName, pWMInfo->atmNetWmName); if (pszWindowName) { /* Convert from UTF-8 to wide char */ @@ -661,7 +745,7 @@ UpdateIcon(WMInfoPtr pWMInfo, Window iWindow) */ static void -UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) +UpdateStyle(WMInfoPtr pWMInfo, Window iWindow, Bool onCreate) { HWND hWnd; HWND zstyle = HWND_NOTOPMOST; @@ -672,7 +756,7 @@ UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) return; /* Determine the Window style, which determines borders and clipping region... */ - winApplyHints(pWMInfo->pDisplay, iWindow, hWnd, &zstyle); + winApplyHints(pWMInfo, iWindow, hWnd, &zstyle, onCreate); winUpdateWindowPosition(hWnd, &zstyle); /* Apply the updated window style, without changing it's show or activation state */ @@ -693,6 +777,151 @@ UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) winShowWindowOnTaskbar(hWnd, (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) ? TRUE : FALSE); + + /* Check urgency hint */ + winApplyUrgency(pWMInfo->pDisplay, iWindow, hWnd); +} + +/* + * Updates the state of a HWND + */ + +static void +UpdateState(WMInfoPtr pWMInfo, Window iWindow, int state) +{ + HWND hWnd; + int current_state = -1; + + winDebug("UpdateState: iWindow 0x%08x %d\n", (int)iWindow, state); + + hWnd = getHwnd(pWMInfo, iWindow); + if (hWnd) + { + // Keep track of the Window state, do nothing if it's not changing + current_state = (intptr_t)GetProp(hWnd, WIN_STATE_PROP); + + if (current_state == state) + return; + + SetProp(hWnd, WIN_STATE_PROP, (HANDLE)(intptr_t)state); + + switch (state) + { + case IconicState: + ShowWindow(hWnd, SW_SHOWMINNOACTIVE); + break; + + case ZoomState: + // ZoomState should only come internally, not from a client + // There doesn't seem to be a SW_SHOWMAXNOACTIVE, but Window should + // already displayed correctly. + break; + + case NormalState: + ShowWindow(hWnd, SW_SHOWNA); + break; + + case WithdrawnState: + ShowWindow(hWnd, SW_HIDE); + break; + } + } + + // Update WM_STATE property + { + // ZoomState is obsolete in ICCCM, so map it to NormalState + int icccm_state = state; + int icccm_current_state = current_state; + + if (icccm_state == ZoomState) + icccm_state = NormalState; + + if (icccm_current_state == ZoomState) + icccm_current_state = NormalState; + + // Don't change property unnecessarily + // + // (Note that we do not take notice of WM_STATE PropertyNotify, only + // WM_CHANGE_STATE ClientMessage, so this should not cause the state to + // change itself) + if (icccm_current_state != icccm_state) + { + struct + { + CARD32 state; + XID icon; + } wmstate; + + wmstate.state = icccm_state; + wmstate.icon = None; + + XChangeProperty(pWMInfo->pDisplay, iWindow, pWMInfo->atmWmState, + pWMInfo->atmWmState, 32, PropModeReplace, + (unsigned char *) &wmstate, + sizeof(wmstate)/sizeof(int)); + } + } + + // Update _NET_WM_STATE property + if (state == WithdrawnState) { + XDeleteProperty(pWMInfo->pDisplay, iWindow, pWMInfo->atmNetWmState); + } + else { + Atom type, *pAtom = NULL; + int format; + unsigned long nitems = 0, left; + + XGetWindowProperty(pWMInfo->pDisplay, iWindow, + pWMInfo->atmNetWmState, 0L, + MAXINT, False, XA_ATOM, &type, &format, + &nitems, &left, + (unsigned char **) &pAtom); + { + unsigned long i, o = 0; + Atom netwmstate[nitems + 2]; + Bool changed = FALSE; + + // Make a copy with _NET_WM_HIDDEN, _NET_WM_MAXIMIZED_{VERT,HORZ} + // removed + for (i = 0; i < nitems; i++) { + if ((pAtom[i] != pWMInfo->atmHiddenState) && + (pAtom[i] != pWMInfo->atmVertMaxState) && + (pAtom[i] != pWMInfo->atmHorzMaxState)) + netwmstate[o++] = pAtom[i]; + } + XFree(pAtom); + + // if iconized, add _NET_WM_HIDDEN + if (state == IconicState) { + netwmstate[o++] = pWMInfo->atmHiddenState; + } + + // if maximized, add _NET_WM_MAXIMIZED_{VERT,HORZ} + if (state == ZoomState) { + netwmstate[o++] = pWMInfo->atmVertMaxState; + netwmstate[o++] = pWMInfo->atmHorzMaxState; + } + + // Don't change property unnecessarily + if (nitems != o) + changed = TRUE; + else + for (i = 0; i < nitems; i++) + { + if (pAtom[i] != netwmstate[i]) + { + changed = TRUE; + break; + } + } + + if (changed) + XChangeProperty(pWMInfo->pDisplay, iWindow, + pWMInfo->atmNetWmState, XA_ATOM, 32, + PropModeReplace, (unsigned char *) &netwmstate, + o); + } + } } #if 0 @@ -746,6 +975,8 @@ winMultiWindowWMProc(void *pArg) WMProcArgPtr pProcArg = (WMProcArgPtr) pArg; WMInfoPtr pWMInfo = pProcArg->pWMInfo; + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); + /* Initialize the Window Manager */ winInitMultiWindowWM(pWMInfo, pProcArg); @@ -772,26 +1003,21 @@ winMultiWindowWMProc(void *pArg) } #if CYGMULTIWINDOW_DEBUG - ErrorF("winMultiWindowWMProc - %d ms MSG: %d ID: %d\n", - GetTickCount(), (int) pNode->msg.msg, (int) pNode->msg.dwID); + ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n", + MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID); #endif /* Branch on the message type */ switch (pNode->msg.msg) { #if 0 case WM_WM_MOVE: - ErrorF("\tWM_WM_MOVE\n"); break; case WM_WM_SIZE: - ErrorF("\tWM_WM_SIZE\n"); break; #endif case WM_WM_RAISE: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_RAISE\n"); -#endif /* Raise the window */ XRaiseWindow(pWMInfo->pDisplay, pNode->msg.iWindow); #if 0 @@ -800,18 +1026,12 @@ winMultiWindowWMProc(void *pArg) break; case WM_WM_LOWER: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_LOWER\n"); -#endif /* Lower the window */ XLowerWindow(pWMInfo->pDisplay, pNode->msg.iWindow); break; case WM_WM_MAP: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_MAP\n"); -#endif /* Put a note as to the HWND associated with this Window */ XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, 32, @@ -821,28 +1041,22 @@ winMultiWindowWMProc(void *pArg) UpdateIcon(pWMInfo, pNode->msg.iWindow); break; - case WM_WM_MAP2: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_MAP2\n"); -#endif + case WM_WM_MAP_UNMANAGED: XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); break; - case WM_WM_MAP3: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_MAP3\n"); -#endif + case WM_WM_MAP_MANAGED: /* Put a note as to the HWND associated with this Window */ XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); UpdateName(pWMInfo, pNode->msg.iWindow); + UpdateStyle(pWMInfo, pNode->msg.iWindow, TRUE); UpdateIcon(pWMInfo, pNode->msg.iWindow); - UpdateStyle(pWMInfo, pNode->msg.iWindow); /* Reshape */ @@ -858,18 +1072,12 @@ winMultiWindowWMProc(void *pArg) break; case WM_WM_UNMAP: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_UNMAP\n"); -#endif /* Unmap the window */ XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow); break; case WM_WM_KILL: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_KILL\n"); -#endif { /* --- */ if (IsWmProtocolAvailable(pWMInfo->pDisplay, @@ -884,9 +1092,6 @@ winMultiWindowWMProc(void *pArg) break; case WM_WM_ACTIVATE: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_ACTIVATE\n"); -#endif /* Set the input focus */ /* @@ -939,13 +1144,12 @@ winMultiWindowWMProc(void *pArg) if (attr.override_redirect) break; - UpdateStyle(pWMInfo, pNode->msg.iWindow); + UpdateStyle(pWMInfo, pNode->msg.iWindow, FALSE); } break; case WM_WM_CHANGE_STATE: - /* Minimize the window in Windows */ - winMinimizeWindow(pNode->msg.iWindow); + UpdateState(pWMInfo, pNode->msg.iWindow, pNode->msg.dwID); break; default: @@ -973,6 +1177,9 @@ winMultiWindowWMProc(void *pArg) #if CYGMULTIWINDOW_DEBUG ErrorF("-winMultiWindowWMProc ()\n"); #endif + + pthread_cleanup_pop(0); + return NULL; } @@ -989,6 +1196,7 @@ winMultiWindowXMsgProc(void *pArg) int iRetries; XEvent event; Atom atmWmName; + Atom atmNetWmName; Atom atmWmHints; Atom atmWmChange; Atom atmNetWmIcon; @@ -996,6 +1204,8 @@ winMultiWindowXMsgProc(void *pArg) int iReturn; XIconSize *xis; + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); + winDebug("winMultiWindowXMsgProc - Hello\n"); /* Check that argument pointer is not invalid */ @@ -1004,7 +1214,7 @@ winMultiWindowXMsgProc(void *pArg) pthread_exit(NULL); } - ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); + winDebug("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); /* Grab the server started mutex - pause until we get it */ iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); @@ -1014,23 +1224,12 @@ winMultiWindowXMsgProc(void *pArg) pthread_exit(NULL); } - ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); - - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winMultiWindowXMsgProc - XInitThreads () failed. Exiting.\n"); - pthread_exit(NULL); - } - - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n"); - } + winDebug("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); /* Release the server started mutex */ pthread_mutex_unlock(pProcArg->ppmServerStarted); - ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); + winDebug("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); /* Install our error handler */ XSetErrorHandler(winMultiWindowXMsgProcErrorHandler); @@ -1109,12 +1308,13 @@ winMultiWindowXMsgProc(void *pArg) xis->max_width = xis->max_height = 48; xis->width_inc = xis->height_inc = 16; XSetIconSizes(pProcArg->pDisplay, - RootWindow(pProcArg->pDisplay, pProcArg->dwScreen), + XRootWindow(pProcArg->pDisplay, pProcArg->dwScreen), xis, 1); XFree(xis); } atmWmName = XInternAtom(pProcArg->pDisplay, "WM_NAME", False); + atmNetWmName = XInternAtom(pProcArg->pDisplay, "_NET_WM_NAME", False); atmWmHints = XInternAtom(pProcArg->pDisplay, "WM_HINTS", False); atmWmChange = XInternAtom(pProcArg->pDisplay, "WM_CHANGE_STATE", False); atmNetWmIcon = XInternAtom(pProcArg->pDisplay, "_NET_WM_ICON", False); @@ -1124,14 +1324,36 @@ winMultiWindowXMsgProc(void *pArg) atmNormalHints = XInternAtom(pProcArg->pDisplay, "WM_NORMAL_HINTS", False); /* - iiimxcf had a bug until 2009-04-27, assuming that the - WM_STATE atom exists, causing clients to fail with - a BadAtom X error if it doesn't. - - Since this is on in the default Solaris 10 install, - workaround this by making sure it does exist... + Enable Composite extension and redirect subwindows of the root window */ - XInternAtom(pProcArg->pDisplay, "WM_STATE", 0); + if (pProcArg->pWMInfo->fCompositeWM) + { + int composite_event_base, composite_error_base; + if (XCompositeQueryExtension(pProcArg->pDisplay, + &composite_event_base, + &composite_error_base)) + { + XCompositeRedirectSubwindows(pProcArg->pDisplay, + XRootWindow(pProcArg->pDisplay, + pProcArg->dwScreen), + CompositeRedirectAutomatic); + + /* + We use automatic updating of the root window for two + reasons: + + 1) redirected window contents are mirrored to the root + window so that the root window draws correctly when shown. + + 2) updating the root window causes damage against the + shadow framebuffer, which ultimately causes WM_PAINT to be + sent to the affected window(s) to cause the damage regions + to be redrawn. + */ + + ErrorF("Using Composite redirection\n"); + } + } /* Loop until we explicitly break out */ while (1) { @@ -1225,6 +1447,13 @@ winMultiWindowXMsgProc(void *pArg) } } } + else if (event.type == UnmapNotify) { + msg.msg = WM_WM_CHANGE_STATE; + msg.iWindow = event.xunmap.window; + msg.dwID = WithdrawnState; + + winSendMessageToWM(pProcArg->pWMInfo, &msg); + } else if (event.type == ConfigureNotify) { if (!event.xconfigure.send_event) { /* @@ -1248,7 +1477,12 @@ winMultiWindowXMsgProc(void *pArg) } } else if (event.type == PropertyNotify) { - if (event.xproperty.atom == atmWmName) { + char *atomName = + XGetAtomName(pProcArg->pDisplay, event.xproperty.atom); + winDebug("winMultiWindowXMsgProc: PropertyNotify %s\n", atomName); + XFree(atomName); + if ((event.xproperty.atom == atmWmName) || + (event.xproperty.atom == atmNetWmName)) { memset(&msg, 0, sizeof(msg)); msg.msg = WM_WM_NAME_EVENT; @@ -1296,13 +1530,14 @@ winMultiWindowXMsgProc(void *pArg) msg.msg = WM_WM_CHANGE_STATE; msg.iWindow = event.xclient.window; + msg.dwID = event.xclient.data.l[0]; winSendMessageToWM(pProcArg->pWMInfo, &msg); } } XCloseDisplay(pProcArg->pDisplay); - pthread_exit(NULL); + pthread_cleanup_pop(0); return NULL; } @@ -1317,7 +1552,7 @@ winInitWM(void **ppWMInfo, pthread_t * ptWMProc, pthread_t * ptXMsgProc, pthread_mutex_t * ppmServerStarted, - int dwScreen, HWND hwndScreen, BOOL allowOtherWM) + int dwScreen, HWND hwndScreen, BOOL allowOtherWM, BOOL compositeWM) { WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec)); WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec)); @@ -1340,6 +1575,7 @@ winInitWM(void **ppWMInfo, /* Set a return pointer to the Window Manager info structure */ *ppWMInfo = pWMInfo; pWMInfo->fAllowOtherWM = allowOtherWM; + pWMInfo->fCompositeWM = compositeWM; /* Setup the argument structure for the thread function */ pArg->dwScreen = dwScreen; @@ -1387,6 +1623,8 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) int iRetries = 0; char pszDisplay[512]; int iReturn; + int data; + const char buf[] = "Desktop"; winDebug("winInitMultiWindowWM - Hello\n"); @@ -1396,7 +1634,7 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pthread_exit(NULL); } - ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); + winDebug("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); /* Grab our garbage mutex to satisfy pthread_cond_wait */ iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); @@ -1406,23 +1644,12 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pthread_exit(NULL); } - ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); - - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winInitMultiWindowWM - XInitThreads () failed. Exiting.\n"); - pthread_exit(NULL); - } - - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n"); - } + winDebug("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); /* Release the server started mutex */ pthread_mutex_unlock(pProcArg->ppmServerStarted); - ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); + winDebug("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); /* Install our error handler */ XSetErrorHandler(winMultiWindowWMErrorHandler); @@ -1481,22 +1708,59 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) "successfully opened the display.\n"); /* Create some atoms */ + pWMInfo->atmUTF8String = XInternAtom(pWMInfo->pDisplay, + "UTF8_STRING", False); pWMInfo->atmWmProtos = XInternAtom(pWMInfo->pDisplay, "WM_PROTOCOLS", False); pWMInfo->atmWmDelete = XInternAtom(pWMInfo->pDisplay, "WM_DELETE_WINDOW", False); pWMInfo->atmWmTakeFocus = XInternAtom(pWMInfo->pDisplay, "WM_TAKE_FOCUS", False); - pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay, WINDOWSWM_NATIVE_HWND, False); + pWMInfo->atmNetWmName = XInternAtom(pWMInfo->pDisplay, + "_NET_WM_NAME", False); + pWMInfo->atmCurrentDesktop = XInternAtom(pWMInfo->pDisplay, + "_NET_CURRENT_DESKTOP", False); + pWMInfo->atmNumberDesktops = XInternAtom(pWMInfo->pDisplay, + "_NET_NUMBER_OF_DESKTOPS", False); + pWMInfo->atmDesktopNames = XInternAtom(pWMInfo->pDisplay, + "_NET_DESKTOP_NAMES", False); + pWMInfo->atmWmState = XInternAtom(pWMInfo->pDisplay, + "WM_STATE", False); + pWMInfo->atmNetWmState = XInternAtom(pWMInfo->pDisplay, + "_NET_WM_STATE", False); + pWMInfo->atmHiddenState = XInternAtom(pWMInfo->pDisplay, + "_NET_WM_STATE_HIDDEN", False); + pWMInfo->atmVertMaxState = XInternAtom(pWMInfo->pDisplay, + "_NET_WM_STATE_MAXIMIZED_VERT", False); + pWMInfo->atmHorzMaxState = XInternAtom(pWMInfo->pDisplay, + "_NET_WM_STATE_MAXIMIZED_HORZ", False); + + /* + Set root window properties for describing multiple desktops to describe + the one desktop we have + */ + data = 0; + XChangeProperty(pWMInfo->pDisplay, XDefaultRootWindow(pWMInfo->pDisplay), + pWMInfo->atmCurrentDesktop, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &data, 1); + + data = 1; + XChangeProperty(pWMInfo->pDisplay, XDefaultRootWindow(pWMInfo->pDisplay), + pWMInfo->atmNumberDesktops, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &data, 1); + + XChangeProperty(pWMInfo->pDisplay, XDefaultRootWindow(pWMInfo->pDisplay), + pWMInfo->atmDesktopNames, pWMInfo->atmUTF8String, 8, + PropModeReplace, (unsigned char *) buf, strlen(buf)); if (1) { Cursor cursor = XCreateFontCursor(pWMInfo->pDisplay, XC_left_ptr); if (cursor) { XDefineCursor(pWMInfo->pDisplay, - DefaultRootWindow(pWMInfo->pDisplay), cursor); + XDefaultRootWindow(pWMInfo->pDisplay), cursor); XFreeCursor(pWMInfo->pDisplay, cursor); } } @@ -1512,7 +1776,7 @@ winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) WMMsgNodePtr pNode; #if CYGMULTIWINDOW_DEBUG - ErrorF("winSendMessageToWM ()\n"); + ErrorF("winSendMessageToWM %s\n", MessageName(pMsg)); #endif pNode = malloc(sizeof(WMMsgNodeRec)); @@ -1577,9 +1841,7 @@ winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr) char pszErrorMsg[100]; XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); -#if CYGMULTIWINDOW_DEBUG ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg); -#endif return 0; } @@ -1605,6 +1867,17 @@ winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay) } /* + * winMultiWindowThreadExit - Thread exit handler + */ + +static void +winMultiWindowThreadExit(void *arg) +{ + /* multiwindow client thread has exited, stop server as well */ + raise(SIGTERM); +} + +/* * Catch RedirectError to detect other window manager running */ @@ -1629,7 +1902,7 @@ CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, */ redirectError = FALSE; XSetErrorHandler(winRedirectErrorHandler); - XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), + XSelectInput(pDisplay, XRootWindow(pDisplay, dwScreen), ResizeRedirectMask | SubstructureRedirectMask | ButtonPressMask); XSync(pDisplay, 0); @@ -1641,7 +1914,7 @@ CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, If other WMs are not allowed, also select one of the events which only one client at a time is allowed to select, so other window managers won't start... */ - XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), + XSelectInput(pDisplay, XRootWindow(pDisplay, dwScreen), SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask : 0)); XSync(pDisplay, 0); @@ -1659,6 +1932,40 @@ winDeinitMultiWindowWM(void) g_shutdown = TRUE; } +static void +winApplyUrgency(Display * pDisplay, Window iWindow, HWND hWnd) +{ + XWMHints *hints = XGetWMHints(pDisplay, iWindow); + + if (hints) { + FLASHWINFO fwi; + + fwi.cbSize = sizeof(FLASHWINFO); + fwi.hwnd = hWnd; + + winDebug("winApplyUrgency: window 0x%08x has urgency hint %s\n", + iWindow, (hints->flags & XUrgencyHint) ? "on" : "off"); + + if (hints->flags & XUrgencyHint) { + DWORD count = 3; + + SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &count, 0); + fwi.dwFlags = FLASHW_TRAY; + fwi.uCount = count; + fwi.dwTimeout = 0; + } + else { + fwi.dwFlags = FLASHW_STOP; + fwi.uCount = 0; + fwi.dwTimeout = 0; + } + + FlashWindowEx(&fwi); + + XFree(hints); + } +} + /* Windows window styles */ #define HINT_NOFRAME (1L<<0) #define HINT_BORDER (1L<<1) @@ -1673,18 +1980,18 @@ winDeinitMultiWindowWM(void) #define HINT_MIN (1L<<1) static void -winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) +winApplyHints(WMInfoPtr pWMInfo, Window iWindow, HWND hWnd, HWND * zstyle, Bool onCreate) { - static Atom windowState, motif_wm_hints, windowType; - static Atom hiddenState, fullscreenState, belowState, aboveState, - skiptaskbarState; - static Atom dockWindow; + static Atom motif_wm_hints, windowType; + static Atom fullscreenState, belowState, aboveState, skiptaskbarState; + static Atom dockWindow, splashWindow; static int generation; Atom type, *pAtom = NULL; int format; unsigned long hint = 0, maxmin = 0, nitems = 0, left = 0; unsigned long style, exStyle; MwmHints *mwm_hint = NULL; + Display *pDisplay = pWMInfo->pDisplay; if (!hWnd) return; @@ -1693,30 +2000,32 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) if (generation != serverGeneration) { generation = serverGeneration; - windowState = XInternAtom(pDisplay, "_NET_WM_STATE", False); motif_wm_hints = XInternAtom(pDisplay, "_MOTIF_WM_HINTS", False); windowType = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE", False); - hiddenState = XInternAtom(pDisplay, "_NET_WM_STATE_HIDDEN", False); fullscreenState = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", False); belowState = XInternAtom(pDisplay, "_NET_WM_STATE_BELOW", False); aboveState = XInternAtom(pDisplay, "_NET_WM_STATE_ABOVE", False); dockWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_DOCK", False); + splashWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_SPLASH", False); skiptaskbarState = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False); } - if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L, + if (XGetWindowProperty(pDisplay, iWindow, pWMInfo->atmNetWmState, 0L, MAXINT, False, XA_ATOM, &type, &format, &nitems, &left, (unsigned char **) &pAtom) == Success) { + Bool verMax = FALSE; + Bool horMax = FALSE; + if (pAtom ) { unsigned long i; for (i = 0; i < nitems; i++) { if (pAtom[i] == skiptaskbarState) hint |= HINT_SKIPTASKBAR; - if (pAtom[i] == hiddenState) + if (pAtom[i] == pWMInfo->atmHiddenState) maxmin |= HINT_MIN; else if (pAtom[i] == fullscreenState) maxmin |= HINT_MAX; @@ -1724,8 +2033,15 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) *zstyle = HWND_BOTTOM; else if (pAtom[i] == aboveState) *zstyle = HWND_TOPMOST; + if (pAtom[i] == pWMInfo->atmVertMaxState) + verMax = TRUE; + if (pAtom[i] == pWMInfo->atmHorzMaxState) + horMax = TRUE; } + if (verMax && horMax) + maxmin |= HINT_MAX; + XFree(pAtom); } } @@ -1738,7 +2054,7 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) if (mwm_hint && nitems == PropMwmHintsElements && (mwm_hint->flags & MwmHintsDecorations)) { if (!mwm_hint->decorations) - hint |= HINT_NOFRAME; + hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); else if (!(mwm_hint->decorations & MwmDecorAll)) { if (mwm_hint->decorations & MwmDecorBorder) hint |= HINT_BORDER; @@ -1772,7 +2088,11 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) (unsigned char **) &pAtom) == Success) { if (pAtom && nitems == 1) { if (*pAtom == dockWindow) { - hint = (hint & ~HINT_NOFRAME) | HINT_SIZEBOX; /* Xming puts a sizebox on dock windows */ + hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX; /* Xming puts a sizebox on dock windows */ + *zstyle = HWND_TOPMOST; + } + else if (*pAtom == splashWindow) { + hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); *zstyle = HWND_TOPMOST; } } @@ -1785,11 +2105,17 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) long supplied; if (normal_hint && - (XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied) == - Success)) { + XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied)) { if (normal_hint->flags & PMaxSize) { - /* Not maximizable if a maximum size is specified */ - hint |= HINT_NOMAXIMIZE; + /* Ensure default style is used if no other styling */ + if (!(hint & ~HINT_SKIPTASKBAR)) + hint |= HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION; + + /* Not maximizable if a maximum size is specified, and that size + is smaller (in either dimension) than the screen size */ + if ((normal_hint->max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN)) + || (normal_hint->max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN))) + hint |= HINT_NOMAXIMIZE; if (normal_hint->flags & PMinSize) { /* @@ -1841,6 +2167,13 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) free(application_id); if (window_name) XFree(window_name); + + /* + It only makes sense to apply minimize/maximize override when the + window is mapped, as otherwise the state can't be changed. + */ + if (!onCreate) + style &= ~(STYLE_MAXIMIZE | STYLE_MINIMIZE); } else { style = STYLE_NONE; @@ -1874,6 +2207,9 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) | HINT_NOFRAME; + if (style & STYLE_SKIPTASKBAR) + hint |= HINT_SKIPTASKBAR; + /* Now apply styles to window */ style = GetWindowLongPtr(hWnd, GWL_STYLE); if (!style) @@ -1881,6 +2217,11 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */ + if (GetParent(hWnd)) + style |= WS_SYSMENU; + else + style |= WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; + if (!(hint & ~HINT_SKIPTASKBAR)) /* No hints, default */ style = style | WS_CAPTION | WS_SIZEBOX; else if (hint & HINT_NOFRAME) /* No frame, no decorations */ @@ -1915,57 +2256,3 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n", iWindow, hint, style, exStyle); } - -void -winUpdateWindowPosition(HWND hWnd, HWND * zstyle) -{ - int iX, iY, iWidth, iHeight; - int iDx, iDy; - RECT rcNew; - WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP); - DrawablePtr pDraw = NULL; - - if (!pWin) - return; - pDraw = &pWin->drawable; - if (!pDraw) - return; - - /* Get the X and Y location of the X window */ - iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); - iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); - - /* Get the height and width of the X window */ - iWidth = pWin->drawable.width; - iHeight = pWin->drawable.height; - - /* Setup a rectangle with the X window position and size */ - SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight); - - winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n", - rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); - - AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, - GetWindowLongPtr(hWnd, GWL_EXSTYLE)); - - /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */ - if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) { - iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left; - rcNew.left += iDx; - rcNew.right += iDx; - } - - if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) { - iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top; - rcNew.top += iDy; - rcNew.bottom += iDy; - } - - winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n", - rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); - - /* Position the Windows window */ - SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top, - rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0); - -} |