diff options
Diffstat (limited to 'hw/xwin/winmultiwindowwm.c')
-rw-r--r-- | hw/xwin/winmultiwindowwm.c | 644 |
1 files changed, 501 insertions, 143 deletions
diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index df7e6d3d5..f3ccfb2fc 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> @@ -49,6 +63,7 @@ #include <xcb/xcb_icccm.h> #include <xcb/xcb_ewmh.h> #include <xcb/xcb_aux.h> +#include <xcb/composite.h> #include <X11/Xwindows.h> @@ -57,8 +72,6 @@ #include "winwindow.h" #include "winprefs.h" #include "window.h" -#include "pixmapstr.h" -#include "windowstr.h" #include "winglobals.h" #include "windisplay.h" #include "winmultiwindowicons.h" @@ -75,6 +88,7 @@ extern void winDebug(const char *format, ...); extern void winReshapeMultiWindow(WindowPtr pWin); extern void winUpdateRgnMultiWindow(WindowPtr pWin); extern xcb_auth_info_t *winGetXcbAuthInfo(void); +extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle); #ifndef CYGDEBUG #define CYGDEBUG NO @@ -90,6 +104,9 @@ extern xcb_auth_info_t *winGetXcbAuthInfo(void); #define WIN_MSG_QUEUE_FNAME "/dev/windows" #endif +#define HINT_MAX (1L<<0) +#define HINT_MIN (1L<<1) + /* * Local structures */ @@ -115,7 +132,12 @@ typedef struct _WMInfo { xcb_atom_t atmPrivMap; xcb_atom_t atmUtf8String; xcb_atom_t atmNetWmName; + xcb_atom_t atmCurrentDesktop; + xcb_atom_t atmNumberDesktops; + xcb_atom_t atmDesktopNames; + xcb_atom_t atmWmState; xcb_ewmh_connection_t ewmh; + Bool fCompositeWM; } WMInfoRec, *WMInfoPtr; typedef struct _WMProcArgRec { @@ -158,6 +180,9 @@ static void *winMultiWindowWMProc(void *pArg); static void *winMultiWindowXMsgProc(void *pArg); static void +winMultiWindowThreadExit(void *arg); + +static void winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg); #if 0 @@ -169,10 +194,10 @@ static Bool CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen); static void - winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle); + winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle, unsigned long *maxmin); -void - winUpdateWindowPosition(HWND hWnd, HWND * zstyle); +static void + winApplyUrgency(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd); /* * Local globals @@ -219,15 +244,18 @@ MessageName(winWMMessagePtr msg) case WM_WM_CHANGE_STATE: return "WM_WM_CHANGE_STATE"; break; - case WM_WM_MAP2: - return "WM_WM_MAP2"; + case WM_WM_MAP_UNMANAGED: + return "WM_WM_MAP_UNMANAGED"; break; - case WM_WM_MAP3: - return "WM_WM_MAP3"; + case WM_WM_MAP_MANAGED: + return "WM_WM_MAP_MANAGED"; break; case WM_WM_HINTS_EVENT: return "WM_WM_HINTS_EVENT"; break; + case WM_WM_CREATE: + return "WM_WM_CREATE"; + break; default: return "Unknown Message"; break; @@ -538,8 +566,10 @@ getHwnd(WMInfoPtr pWMInfo, xcb_window_t iWindow) } /* Some sanity checks */ - if (!hWnd) + if (!hWnd) { + winDebug("getHwnd: no HWND\n"); return NULL; + } if (!IsWindow(hWnd)) return NULL; @@ -677,7 +707,7 @@ UpdateIcon(WMInfoPtr pWMInfo, xcb_window_t iWindow) */ static void -UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow) +UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow, unsigned long *maxmin) { HWND hWnd; HWND zstyle = HWND_NOTOPMOST; @@ -687,8 +717,12 @@ UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow) if (!hWnd) return; + /* If window isn't override-redirect */ + if (IsOverrideRedirect(pWMInfo->conn, iWindow)) + return; + /* Determine the Window style, which determines borders and clipping region... */ - winApplyHints(pWMInfo, iWindow, hWnd, &zstyle); + winApplyHints(pWMInfo, iWindow, hWnd, &zstyle, maxmin); winUpdateWindowPosition(hWnd, &zstyle); /* Apply the updated window style, without changing it's show or activation state */ @@ -709,25 +743,155 @@ UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow) winShowWindowOnTaskbar(hWnd, (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) ? TRUE : FALSE); + + /* Check urgency hint */ + winApplyUrgency(pWMInfo, iWindow, hWnd); } /* * Updates the state of a HWND - * (only minimization supported at the moment) */ static void -UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow) +UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow, int state) { HWND hWnd; + int current_state = -1; - winDebug("UpdateState: iWindow 0x%08x\n", (int)iWindow); + winDebug("UpdateState: iWindow 0x%08x %d\n", (int)iWindow, state); hWnd = getHwnd(pWMInfo, iWindow); - if (!hWnd) - return; + 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 XCB_ICCCM_WM_STATE_ICONIC: + ShowWindow(hWnd, SW_SHOWMINNOACTIVE); + break; + +#define XCB_ICCCM_WM_STATE_ZOOM 2 + case XCB_ICCCM_WM_STATE_ZOOM: + // There doesn't seem to be a SW_SHOWMAXNOACTIVE. Hopefully + // always activating a maximized window isn't so bad... + ShowWindow(hWnd, SW_SHOWMAXIMIZED); + break; + + case XCB_ICCCM_WM_STATE_NORMAL: + ShowWindow(hWnd, SW_SHOWNOACTIVATE); + break; + + case XCB_ICCCM_WM_STATE_WITHDRAWN: + 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 == XCB_ICCCM_WM_STATE_ZOOM) + icccm_state = XCB_ICCCM_WM_STATE_NORMAL; + + if (icccm_current_state == XCB_ICCCM_WM_STATE_ZOOM) + icccm_current_state = XCB_ICCCM_WM_STATE_NORMAL; + + // 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; + + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + iWindow, pWMInfo->atmWmState, + pWMInfo->atmWmState, 32, + sizeof(wmstate)/sizeof(int), + (unsigned char *) &wmstate); + } + } + + // Update _NET_WM_STATE property + if (state == XCB_ICCCM_WM_STATE_WITHDRAWN) { + xcb_delete_property(pWMInfo->conn, iWindow, pWMInfo->ewmh._NET_WM_STATE); + } + else { + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + + cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, + pWMInfo->ewmh._NET_WM_STATE, + XCB_ATOM_ATOM, + 0, INT_MAX); + reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL); + if (reply) { + int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); + xcb_atom_t *pAtom = xcb_get_property_value(reply); + unsigned long i, o = 0; + xcb_atom_t 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->ewmh._NET_WM_STATE_HIDDEN) && + (pAtom[i] != pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) && + (pAtom[i] != pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ)) + netwmstate[o++] = pAtom[i]; + } + free(reply); + + // if iconized, add _NET_WM_HIDDEN + if (state == XCB_ICCCM_WM_STATE_ICONIC) { + netwmstate[o++] = pWMInfo->ewmh._NET_WM_STATE_HIDDEN; + } - ShowWindow(hWnd, SW_MINIMIZE); + // if maximized, add _NET_WM_MAXIMIZED_{VERT,HORZ} + if (state == XCB_ICCCM_WM_STATE_ZOOM) { + netwmstate[o++] = pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT; + netwmstate[o++] = pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ; + } + + // 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) + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + iWindow, + pWMInfo->ewmh._NET_WM_STATE, + XCB_ATOM_ATOM, 32, + o, (unsigned char *) &netwmstate); + } + } } #if 0 @@ -781,6 +945,8 @@ winMultiWindowWMProc(void *pArg) WMProcArgPtr pProcArg = (WMProcArgPtr) pArg; WMInfoPtr pWMInfo = pProcArg->pWMInfo; + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); + /* Initialize the Window Manager */ winInitMultiWindowWM(pWMInfo, pProcArg); @@ -802,12 +968,69 @@ winMultiWindowWMProc(void *pArg) } #if CYGMULTIWINDOW_DEBUG - ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n", - MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID); + ErrorF("winMultiWindowWMProc - MSG: %s (%d) Window: %08x ID: %d\n", + MessageName(&(pNode->msg)), (int)pNode->msg.msg, pNode->msg.iWindow, (int)pNode->msg.dwID); #endif /* Branch on the message type */ switch (pNode->msg.msg) { + case WM_WM_CREATE: + { + unsigned long maxmin = 0; +#if CYGMULTIWINDOW_DEBUG + ErrorF("\tWM_WM_CREATE\n"); +#endif + + /* Put a note as to the HWND associated with this Window */ + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + pNode->msg.iWindow, pWMInfo->atmPrivMap, + XCB_ATOM_INTEGER, 32, + sizeof(HWND)/4, &(pNode->msg.hwndWindow)); + + + /* Determine the Window style, which determines borders and clipping region... */ + UpdateStyle(pWMInfo, pNode->msg.iWindow, &maxmin); + + /* Make sure it gets the proper system menu for a WS_POPUP, too */ + GetSystemMenu(pNode->msg.hwndWindow, TRUE); + +#define WM_INIT_SYS_MENU (WM_USER + 1001) + /* Cause any .XWinrc menus to be added in main WNDPROC */ + PostMessage(pNode->msg.hwndWindow, WM_INIT_SYS_MENU, 0, 0); + + /* Display the window without activating it */ + { + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + + cookie = xcb_get_window_attributes(pWMInfo->conn, pNode->msg.iWindow); + reply = xcb_get_window_attributes_reply(pWMInfo->conn, cookie, NULL); + + if (reply) { + if (reply->_class != InputOnly) + ShowWindow(pNode->msg.hwndWindow, SW_SHOWNA); + free(reply); + } + } + + /* Send first paint message */ + UpdateWindow(pNode->msg.hwndWindow); + + /* Establish initial state */ + UpdateState(pWMInfo, pNode->msg.iWindow, XCB_ICCCM_WM_STATE_NORMAL); + + /* + It only makes sense to apply minimize/maximize override as the + initial state, otherwise that state can't be changed. + */ + if (maxmin & HINT_MAX) + SendMessage(pNode->msg.hwndWindow, WM_SYSCOMMAND, SC_MAXIMIZE, 0); + else if (maxmin & HINT_MIN) + SendMessage(pNode->msg.hwndWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0); + } + + break; + #if 0 case WM_WM_MOVE: break; @@ -838,26 +1061,16 @@ winMultiWindowWMProc(void *pArg) } break; - case WM_WM_MAP2: - /* Put a note as to the HWND associated with this Window */ - xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, - pNode->msg.iWindow, pWMInfo->atmPrivMap, - XCB_ATOM_INTEGER, 32, - sizeof(HWND)/4, &(pNode->msg.hwndWindow)); - + case WM_WM_MAP_UNMANAGED: break; - case WM_WM_MAP3: - /* Put a note as to the HWND associated with this Window */ - xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, - pNode->msg.iWindow, pWMInfo->atmPrivMap, - XCB_ATOM_INTEGER, 32, - sizeof(HWND)/4, &(pNode->msg.hwndWindow)); + case WM_WM_MAP_MANAGED: + { + unsigned long maxmin = 0; UpdateName(pWMInfo, pNode->msg.iWindow); + UpdateStyle(pWMInfo, pNode->msg.iWindow, &maxmin); UpdateIcon(pWMInfo, pNode->msg.iWindow); - UpdateStyle(pWMInfo, pNode->msg.iWindow); - /* Reshape */ { @@ -868,8 +1081,9 @@ winMultiWindowWMProc(void *pArg) winUpdateRgnMultiWindow(pWin); } } + } - break; + break; case WM_WM_UNMAP: @@ -938,16 +1152,18 @@ winMultiWindowWMProc(void *pArg) case WM_WM_HINTS_EVENT: { + unsigned long maxmin = 0; + /* Don't do anything if this is an override-redirect window */ if (IsOverrideRedirect(pWMInfo->conn, pNode->msg.iWindow)) break; - UpdateStyle(pWMInfo, pNode->msg.iWindow); + UpdateStyle(pWMInfo, pNode->msg.iWindow, &maxmin); } break; case WM_WM_CHANGE_STATE: - UpdateState(pWMInfo, pNode->msg.iWindow); + UpdateState(pWMInfo, pNode->msg.iWindow, pNode->msg.dwID); break; default: @@ -968,10 +1184,10 @@ winMultiWindowWMProc(void *pArg) if (event) { if ((event->response_type & ~0x80) == 0) { xcb_generic_error_t *err = (xcb_generic_error_t *)event; - ErrorF("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, " - "Major opcode: %i, Minor opcode: %i\n", - err->error_code, err->resource_id, - err->major_code, err->minor_code); + winDebug("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, " + "Major opcode: %i, Minor opcode: %i\n", + err->error_code, err->resource_id, + err->major_code, err->minor_code); } } } @@ -981,6 +1197,7 @@ winMultiWindowWMProc(void *pArg) int e = xcb_connection_has_error(pWMInfo->conn); if (e) { ErrorF("winMultiWindowWMProc - Fatal error %d on xcb connection\n", e); + pthread_exit(NULL); break; } } @@ -998,6 +1215,9 @@ winMultiWindowWMProc(void *pArg) #if CYGMULTIWINDOW_DEBUG ErrorF("-winMultiWindowWMProc ()\n"); #endif + + pthread_cleanup_pop(0); + return NULL; } @@ -1036,6 +1256,10 @@ winMultiWindowXMsgProc(void *pArg) xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints; int iReturn; xcb_auth_info_t *auth_info; + xcb_screen_t *root_screen; + xcb_window_t root_window_id; + + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); winDebug("winMultiWindowXMsgProc - Hello\n"); @@ -1108,11 +1332,11 @@ winMultiWindowXMsgProc(void *pArg) pthread_exit(NULL); } - { - /* Get root window id */ - xcb_screen_t *root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen); - xcb_window_t root_window_id = root_screen->root; + /* Get root window id */ + root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen); + root_window_id = root_screen->root; + { /* Set WM_ICON_SIZE property indicating desired icon sizes */ typedef struct { uint32_t min_width, min_height; @@ -1141,14 +1365,39 @@ winMultiWindowXMsgProc(void *pArg) atmNormalHints = intern_atom(pProcArg->conn, "WM_NORMAL_HINTS"); /* - 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 */ - intern_atom(pProcArg->conn, "WM_STATE"); + if (pProcArg->pWMInfo->fCompositeWM) { + const char *extension_name = "Composite"; + xcb_query_extension_cookie_t cookie; + xcb_query_extension_reply_t *reply; + + cookie = xcb_query_extension(pProcArg->conn, strlen(extension_name), extension_name); + reply = xcb_query_extension_reply(pProcArg->conn, cookie, NULL); + + if (reply && (reply->present)) { + xcb_composite_redirect_subwindows(pProcArg->conn, + root_window_id, + XCB_COMPOSITE_REDIRECT_AUTOMATIC); + + /* + 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"); + + free(reply); + } + } /* Loop until we explicitly break out */ while (1) { @@ -1164,6 +1413,7 @@ winMultiWindowXMsgProc(void *pArg) if (!event) { // returns NULL on I/O error int e = xcb_connection_has_error(pProcArg->conn); ErrorF("winMultiWindowXMsgProc - Fatal error %d on xcb connection\n", e); + pthread_exit(NULL); break; } @@ -1175,10 +1425,10 @@ winMultiWindowXMsgProc(void *pArg) /* Branch on event type */ if (type == 0) { xcb_generic_error_t *err = (xcb_generic_error_t *)event; - ErrorF("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, " - "Major opcode: %i, Minor opcode: %i\n", - err->error_code, err->resource_id, - err->major_code, err->minor_code); + winDebug("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, " + "Major opcode: %i, Minor opcode: %i\n", + err->error_code, err->resource_id, + err->major_code, err->minor_code); } else if (type == XCB_CREATE_NOTIFY) { xcb_create_notify_event_t *notify = (xcb_create_notify_event_t *)event; @@ -1247,6 +1497,16 @@ winMultiWindowXMsgProc(void *pArg) } } } + else if (type == XCB_UNMAP_NOTIFY) { + xcb_unmap_notify_event_t *notify = (xcb_unmap_notify_event_t *)event; + + memset(&msg, 0, sizeof(msg)); + msg.msg = WM_WM_CHANGE_STATE; + msg.iWindow = notify->window; + msg.dwID = XCB_ICCCM_WM_STATE_WITHDRAWN; + + winSendMessageToWM(pProcArg->pWMInfo, &msg); + } else if (type == XCB_CONFIGURE_NOTIFY) { if (!send_event) { /* @@ -1273,6 +1533,15 @@ winMultiWindowXMsgProc(void *pArg) else if (type == XCB_PROPERTY_NOTIFY) { xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)event; + xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(pProcArg->conn, notify->atom); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(pProcArg->conn, cookie, NULL); + if (reply) { + winDebug("winMultiWindowXMsgProc: PropertyNotify %.*s\n", + xcb_get_atom_name_name_length(reply), + xcb_get_atom_name_name(reply)); + free(reply); + } + if ((notify->atom == atmWmName) || (notify->atom == atmNetWmName)) { memset(&msg, 0, sizeof(msg)); @@ -1315,18 +1584,60 @@ winMultiWindowXMsgProc(void *pArg) } else if (type == XCB_CLIENT_MESSAGE) { xcb_client_message_event_t *client_msg = (xcb_client_message_event_t *)event; + winDebug("winMultiWindowXMsgProc: ClientMessage: type %d window 0x%08x data[0] %d\n", client_msg->type, client_msg->window, client_msg->data.data32[0]); if (client_msg->type == atmWmChange && client_msg->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) { ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n"); memset(&msg, 0, sizeof(msg)); - msg.msg = WM_WM_CHANGE_STATE; msg.iWindow = client_msg->window; + msg.dwID = client_msg->data.data32[0]; winSendMessageToWM(pProcArg->pWMInfo, &msg); } + else if (client_msg->type == pProcArg->pWMInfo->ewmh._NET_WM_STATE) { + int action = client_msg->data.data32[0]; + int state = -1; + + if (action == XCB_EWMH_WM_STATE_ADD) { + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ)) + state = XCB_ICCCM_WM_STATE_ZOOM; + + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT)) + state = XCB_ICCCM_WM_STATE_ZOOM; + + if (client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_HIDDEN) + state = XCB_ICCCM_WM_STATE_ICONIC; + } + else if (action == XCB_EWMH_WM_STATE_REMOVE) { + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ)) + state = XCB_ICCCM_WM_STATE_NORMAL; + + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT)) + state = XCB_ICCCM_WM_STATE_NORMAL; + + if (client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_HIDDEN) + state = XCB_ICCCM_WM_STATE_NORMAL; + } + else { + ErrorF("winMultiWindowXMsgProc: ClientMEssage _NET_WM_STATE unsupported action %d\n", action); + } + + if (state != -1) { + memset(&msg, 0, sizeof(msg)); + msg.msg = WM_WM_CHANGE_STATE; + msg.iWindow = client_msg->window; + msg.dwID = state; + + winSendMessageToWM(pProcArg->pWMInfo, &msg); + } + } } /* Free the event */ @@ -1334,7 +1645,7 @@ winMultiWindowXMsgProc(void *pArg) } xcb_disconnect(pProcArg->conn); - pthread_exit(NULL); + pthread_cleanup_pop(0); return NULL; } @@ -1349,7 +1660,7 @@ winInitWM(void **ppWMInfo, pthread_t * ptWMProc, pthread_t * ptXMsgProc, pthread_mutex_t * ppmServerStarted, - int dwScreen, HWND hwndScreen) + int dwScreen, HWND hwndScreen, Bool compositeWM) { WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec)); WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec)); @@ -1371,6 +1682,7 @@ winInitWM(void **ppWMInfo, /* Set a return pointer to the Window Manager info structure */ *ppWMInfo = pWMInfo; + pWMInfo->fCompositeWM = compositeWM; /* Setup the argument structure for the thread function */ pArg->dwScreen = dwScreen; @@ -1419,6 +1731,8 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) char pszDisplay[512]; int iReturn; xcb_auth_info_t *auth_info; + xcb_screen_t *root_screen; + xcb_window_t root_window_id; winDebug("winInitMultiWindowWM - Hello\n"); @@ -1488,6 +1802,10 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pWMInfo->atmPrivMap = intern_atom(pWMInfo->conn, WINDOWSWM_NATIVE_HWND); pWMInfo->atmUtf8String = intern_atom(pWMInfo->conn, "UTF8_STRING"); pWMInfo->atmNetWmName = intern_atom(pWMInfo->conn, "_NET_WM_NAME"); + pWMInfo->atmCurrentDesktop = intern_atom(pWMInfo->conn, "_NET_CURRENT_DESKTOP"); + pWMInfo->atmNumberDesktops = intern_atom(pWMInfo->conn, "_NET_NUMBER_OF_DESKTOPS"); + pWMInfo->atmDesktopNames = intern_atom(pWMInfo->conn, "__NET_DESKTOP_NAMES"); + pWMInfo->atmWmState = intern_atom(pWMInfo->conn, "WM_STATE"); /* Initialization for the xcb_ewmh and EWMH atoms */ { @@ -1512,6 +1830,8 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pWMInfo->ewmh._NET_WM_STATE_ABOVE, pWMInfo->ewmh._NET_WM_STATE_BELOW, pWMInfo->ewmh._NET_WM_STATE_SKIP_TASKBAR, + pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT, + pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ, }; xcb_ewmh_set_supported(&pWMInfo->ewmh, pProcArg->dwScreen, @@ -1522,6 +1842,32 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) } } + /* Get root window id */ + root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen); + root_window_id = root_screen->root; + + /* + Set root window properties for describing multiple desktops to describe + the one desktop we have + */ + { + int data; + const char buf[] = "Desktop"; + + data = 0; + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id, + pWMInfo->atmCurrentDesktop, XCB_ATOM_CARDINAL, 32, + 1, &data); + data = 1; + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id, + pWMInfo->atmNumberDesktops, XCB_ATOM_CARDINAL, 32, + 1, &data); + + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id, + pWMInfo->atmDesktopNames, pWMInfo->atmUtf8String, 8, + strlen(buf), (unsigned char *) buf); + } + /* Set the root window cursor to left_ptr (this controls the cursor an application gets over it's windows when it doesn't set one) @@ -1535,9 +1881,6 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) uint32_t mask = XCB_CW_CURSOR; uint32_t value_list = cursor; - xcb_screen_t *root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen); - xcb_window_t window = root_screen->root; - static const uint16_t fgred = 0, fggreen = 0, fgblue = 0; static const uint16_t bgred = 0xFFFF, bggreen = 0xFFFF, bgblue = 0xFFFF; @@ -1547,7 +1890,7 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) shape, shape + 1, fgred, fggreen, fgblue, bgred, bggreen, bgblue); - xcb_change_window_attributes(pWMInfo->conn, window, mask, &value_list); + xcb_change_window_attributes(pWMInfo->conn, root_window_id, mask, &value_list); xcb_free_cursor(pWMInfo->conn, cursor); xcb_close_font(pWMInfo->conn, font); @@ -1564,7 +1907,7 @@ winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) WMMsgNodePtr pNode; #if CYGMULTIWINDOW_DEBUG - ErrorF("winSendMessageToWM %s\n", MessageName(pMsg)); + ErrorF("winSendMessageToWM %s %08x %d\n", MessageName(pMsg), pMsg->iWindow, pMsg->dwID); #endif pNode = malloc(sizeof(WMMsgNodeRec)); @@ -1575,6 +1918,17 @@ winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) } /* + * winMultiWindowThreadExit - Thread exit handler + */ + +static void +winMultiWindowThreadExit(void *arg) +{ + /* multiwindow client thread has exited, stop server as well */ + raise(SIGTERM); +} + +/* * Check if another window manager is running */ @@ -1633,6 +1987,40 @@ winDeinitMultiWindowWM(void) g_shutdown = TRUE; } +static void +winApplyUrgency(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd) +{ + xcb_get_property_cookie_t cookie; + xcb_icccm_wm_hints_t hints; + + cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, iWindow); + if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints, NULL)) { + FLASHWINFO fwi; + + fwi.cbSize = sizeof(FLASHWINFO); + fwi.hwnd = hWnd; + + winDebug("winApplyUrgency: window 0x%08x has urgency hint %s\n", iWindow, + (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) ? "on" : "off"); + + if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) { + 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); + } +} + /* Windows window styles */ #define HINT_NOFRAME (1L<<0) #define HINT_BORDER (1L<<1) @@ -1642,12 +2030,9 @@ winDeinitMultiWindowWM(void) #define HINT_NOMINIMIZE (1L<<5) #define HINT_NOSYSMENU (1L<<6) #define HINT_SKIPTASKBAR (1L<<7) -/* These two are used on their own */ -#define HINT_MAX (1L<<0) -#define HINT_MIN (1L<<1) static void -winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) +winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle, unsigned long *maxmin) { xcb_connection_t *conn = pWMInfo->conn; @@ -1657,9 +2042,11 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) static xcb_atom_t splashType; static int generation; - unsigned long hint = 0, maxmin = 0; + unsigned long hint = HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION; unsigned long style, exStyle; + *maxmin = 0; + if (!hWnd) return; if (!IsWindow(hWnd)) @@ -1684,20 +2071,29 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) int i; int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); xcb_atom_t *pAtom = xcb_get_property_value(reply); + Bool verMax = FALSE; + Bool horMax = FALSE; for (i = 0; i < nitems; i++) { if (pAtom[i] == skiptaskbarState) hint |= HINT_SKIPTASKBAR; if (pAtom[i] == hiddenState) - maxmin |= HINT_MIN; + *maxmin |= HINT_MIN; else if (pAtom[i] == fullscreenState) - maxmin |= HINT_MAX; + *maxmin |= HINT_MAX; if (pAtom[i] == belowState) *zstyle = HWND_BOTTOM; else if (pAtom[i] == aboveState) *zstyle = HWND_TOPMOST; + if (pAtom[i] == pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) + verMax = TRUE; + if (pAtom[i] == pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ) + horMax = TRUE; } + if (verMax && horMax) + *maxmin |= HINT_MAX; + free(reply); } } @@ -1710,15 +2106,17 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) MwmHints *mwm_hint = xcb_get_property_value(reply); if (mwm_hint && (nitems >= PropMwmHintsElements) && (mwm_hint->flags & MwmHintsDecorations)) { - if (!mwm_hint->decorations) + if (!mwm_hint->decorations) { + hint &= ~(HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION); hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); + } else if (!(mwm_hint->decorations & MwmDecorAll)) { - if (mwm_hint->decorations & MwmDecorBorder) - hint |= HINT_BORDER; - if (mwm_hint->decorations & MwmDecorHandle) - hint |= HINT_SIZEBOX; - if (mwm_hint->decorations & MwmDecorTitle) - hint |= HINT_CAPTION; + if (!(mwm_hint->decorations & MwmDecorBorder)) + hint &= ~HINT_BORDER; + if (!(mwm_hint->decorations & MwmDecorHandle)) + hint &= ~HINT_SIZEBOX; + if (!(mwm_hint->decorations & MwmDecorTitle)) + hint &= ~HINT_CAPTION; if (!(mwm_hint->decorations & MwmDecorMenu)) hint |= HINT_NOSYSMENU; if (!(mwm_hint->decorations & MwmDecorMinimize)) @@ -1744,11 +2142,13 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) if (xcb_ewmh_get_wm_window_type_reply(&pWMInfo->ewmh, cookie, &type, NULL)) { for (i = 0; i < type.atoms_len; i++) { if (type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK) { - hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX; + hint &= ~(HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION | HINT_NOFRAME); + hint |= (HINT_SKIPTASKBAR | HINT_SIZEBOX); *zstyle = HWND_TOPMOST; } else if ((type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH) || (type.atoms[i] == splashType)) { + hint &= ~(HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION); hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); *zstyle = HWND_TOPMOST; } @@ -1762,22 +2162,31 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) cookie = xcb_icccm_get_wm_normal_hints(conn, iWindow); if (xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &size_hints, NULL)) { - if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { + /* Notwithstanding MwmDecorHandle, if we have a border, and + WM_NORMAL_HINTS indicates the window should be resizeable, let + the window have a resizing border. This is necessary for windows + with gtk3+ 3.14 csd. */ + if (hint & HINT_BORDER) + hint |= HINT_SIZEBOX; + if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { /* Not maximizable if a maximum size is specified, and that size is smaller (in either dimension) than the screen size */ if ((size_hints.max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN)) || (size_hints.max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN))) hint |= HINT_NOMAXIMIZE; + if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { /* If both minimum size and maximum size are specified and are the same, don't bother with a resizing frame */ if ((size_hints.min_width == size_hints.max_width) - && (size_hints.min_height == size_hints.max_height)) + && (size_hints.min_height == size_hints.max_height)) { + hint |= HINT_NOMAXIMIZE; hint = (hint & ~HINT_SIZEBOX); + } } } } @@ -1819,17 +2228,12 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) if (style & STYLE_TOPMOST) *zstyle = HWND_TOPMOST; else if (style & STYLE_MAXIMIZE) - maxmin = (hint & ~HINT_MIN) | HINT_MAX; + *maxmin = (hint & ~HINT_MIN) | HINT_MAX; else if (style & STYLE_MINIMIZE) - maxmin = (hint & ~HINT_MAX) | HINT_MIN; + *maxmin = (hint & ~HINT_MAX) | HINT_MIN; else if (style & STYLE_BOTTOM) *zstyle = HWND_BOTTOM; - if (maxmin & HINT_MAX) - SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); - else if (maxmin & HINT_MIN) - SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); - if (style & STYLE_NOTITLE) hint = (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) | @@ -1843,6 +2247,9 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t 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) @@ -1850,6 +2257,11 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t 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 */ @@ -1884,57 +2296,3 @@ winApplyHints(WMInfoPtr pWMInfo, xcb_window_t 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); - -} |