summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorJon Turney <jon.turney@dronecode.org.uk>2015-05-21 14:17:23 +0100
committerJon Turney <jon.turney@dronecode.org.uk>2018-05-13 18:21:59 +0100
commitc42959f36637bd7af84cf0fba3b760c52d86e279 (patch)
tree9a92ea21feabf816fe2260e035fecd05266a2c37 /hw
parent84753daccb6303e5fad3fb37249a76cc0fb681d3 (diff)
Update WM_STATE, _NET_WM_STATE when window state changes
This avoids a problem seen with evolution, which updates it WM_HINTS to change icon when new mail it received. If started maximized, this maximization is re-applied with every WM_HINTS change, even if it has been minimized. v2: Fix broken Qt menus Qt won't map unmapped windows which have an incorrect WM_STATE of NormalState. So update WM_STATE when window is unmapped as well.
Diffstat (limited to 'hw')
-rw-r--r--hw/xwin/winmultiwindowwm.c173
1 files changed, 136 insertions, 37 deletions
diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c
index cc5109119..3137ede90 100644
--- a/hw/xwin/winmultiwindowwm.c
+++ b/hw/xwin/winmultiwindowwm.c
@@ -133,6 +133,7 @@ typedef struct _WMInfo {
xcb_atom_t atmCurrentDesktop;
xcb_atom_t atmNumberDesktops;
xcb_atom_t atmDesktopNames;
+ xcb_atom_t atmWmState;
xcb_ewmh_connection_t ewmh;
} WMInfoRec, *WMInfoPtr;
@@ -745,45 +746,142 @@ static void
UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow, int state)
{
HWND hWnd;
- int current_state;
+ int current_state = -1;
winDebug("UpdateState: iWindow 0x%08x %d\n", (int)iWindow, state);
hWnd = getHwnd(pWMInfo, iWindow);
- if (!hWnd)
- return;
-
- // Keep track of the Window state, do nothing if it's not changing
- current_state = (intptr_t)GetProp(hWnd, WIN_STATE_PROP);
+ 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;
+ if (current_state == state)
+ return;
- SetProp(hWnd, WIN_STATE_PROP, (HANDLE)(intptr_t)state);
+ SetProp(hWnd, WIN_STATE_PROP, (HANDLE)(intptr_t)state);
- switch (state)
- {
- case XCB_ICCCM_WM_STATE_ICONIC:
- ShowWindow(hWnd, SW_SHOWMINNOACTIVE);
- break;
+ 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:
- // 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 XCB_ICCCM_WM_STATE_ZOOM:
+ // 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 XCB_ICCCM_WM_STATE_NORMAL:
+ ShowWindow(hWnd, SW_SHOWNA);
+ break;
+
+ case XCB_ICCCM_WM_STATE_WITHDRAWN:
+ ShowWindow(hWnd, SW_HIDE);
+ break;
+ }
+ }
- case XCB_ICCCM_WM_STATE_NORMAL:
- ShowWindow(hWnd, SW_SHOWNA);
- 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);
+ }
+ }
- case XCB_ICCCM_WM_STATE_WITHDRAWN:
- ShowWindow(hWnd, SW_HIDE);
- break;
- }
+ // 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;
+ }
+
+ // 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;
+ }
- // XXX: should also set WM_STATE, _NET_WM_STATE property
+ // 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
@@ -1204,16 +1302,6 @@ winMultiWindowXMsgProc(void *pArg)
atmWindowType = intern_atom(pProcArg->conn, "_NET_WM_WINDOW_TYPE");
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...
- */
- intern_atom(pProcArg->conn, "WM_STATE");
-
/* Loop until we explicitly break out */
while (1) {
xcb_generic_event_t *event;
@@ -1312,6 +1400,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) {
/*
@@ -1567,6 +1665,7 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
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 */
{