From ea4931e83d26c53c2d6dd8530377f7fff5650994 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Wed, 9 Dec 2020 14:20:09 -0500 Subject: [PATCH 1/2] vmside: Rename wm_state to net_wm_state. The internal variable "wm_state" is used to store the X atom "_NET_WM_STATE". Rename this variable to "net_wm_state" to avoid confusion, because "WM_STATE" is something different from "_NET_WM_STATE" and we need to handle both. --- gui-agent/vmside.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index c13ff694..2fa72e29 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -89,7 +89,7 @@ struct _global_handles { Atom tray_opcode; /* Atom: _NET_SYSTEM_TRAY_MESSAGE_OPCODE */ Atom xembed_info; /* Atom: _XEMBED_INFO */ Atom utf8_string_atom; /* Atom: UTF8_STRING */ - Atom wm_state; /* Atom: _NET_WM_STATE */ + Atom net_wm_state; /* Atom: _NET_WM_STATE */ Atom wm_state_fullscreen; /* Atom: _NET_WM_STATE_FULLSCREEN */ Atom wm_state_demands_attention; /* Atom: _NET_WM_STATE_DEMANDS_ATTENTION */ Atom wm_take_focus; /* Atom: WM_TAKE_FOCUS */ @@ -783,7 +783,7 @@ static void send_window_state(Ghandles * g, XID window) struct msg_window_flags flags; /* FIXME: only first 10 elements are parsed */ - ret = XGetWindowProperty(g->display, window, g->wm_state, 0, 10, + ret = XGetWindowProperty(g->display, window, g->net_wm_state, 0, 10, False, XA_ATOM, &act_type, &act_fmt, &nitems, &bytesleft, (unsigned char**)&state_list); if (ret != Success) return; @@ -838,7 +838,7 @@ static void process_xevent_unmap(Ghandles * g, XID window) hdr.window = window; hdr.untrusted_len = 0; write_struct(g->vchan, hdr); - XDeleteProperty(g->display, window, g->wm_state); + XDeleteProperty(g->display, window, g->net_wm_state); } static void process_xevent_destroy(Ghandles * g, XID window) @@ -1249,7 +1249,7 @@ static void process_xevent_message(Ghandles * g, XClientMessageEvent * ev) fprintf(stderr, "unhandled tray opcode: %ld\n", ev->data.l[1]); } - } else if (ev->message_type == g->wm_state) { + } else if (ev->message_type == g->net_wm_state) { struct msg_hdr hdr; struct msg_window_flags msg; @@ -1552,7 +1552,7 @@ static void mkghandles(Ghandles * g) g->tray_opcode = XInternAtom(g->display, "_NET_SYSTEM_TRAY_OPCODE", False); g->xembed_info = XInternAtom(g->display, "_XEMBED_INFO", False); - g->wm_state = XInternAtom(g->display, "_NET_WM_STATE", False); + g->net_wm_state = XInternAtom(g->display, "_NET_WM_STATE", False); g->wm_state_fullscreen = XInternAtom(g->display, "_NET_WM_STATE_FULLSCREEN", False); g->wm_state_demands_attention = XInternAtom(g->display, "_NET_WM_STATE_DEMANDS_ATTENTION", False); g->wm_take_focus = XInternAtom(g->display, "WM_TAKE_FOCUS", False); @@ -2082,7 +2082,7 @@ static void handle_window_flags(Ghandles *g, XID winid) read_data(g->vchan, (char *) &msg_flags, sizeof(msg_flags)); /* FIXME: only first 10 elements are parsed */ - ret = XGetWindowProperty(g->display, winid, g->wm_state, 0, 10, + ret = XGetWindowProperty(g->display, winid, g->net_wm_state, 0, 10, False, XA_ATOM, &act_type, &act_fmt, &nitems, &bytesleft, (unsigned char**)&state_list); if (ret != Success) return; @@ -2115,7 +2115,7 @@ static void handle_window_flags(Ghandles *g, XID winid) if (!changed) return; - XChangeProperty(g->display, winid, g->wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)new_state_list, j); + XChangeProperty(g->display, winid, g->net_wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)new_state_list, j); } static void handle_message(Ghandles * g) From 585fa4511165bd97c39e26e84472a278197ce5f9 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Wed, 9 Dec 2020 14:39:19 -0500 Subject: [PATCH 2/2] vmside: Implement the WM_STATE property. The WM_STATE property is defined by ICCCM, and should be set by the window manager to indicate the current state of a client window. It is used for two primary purposes: - A client can examine the property to determine whether the client's own window is conceptually "visible" (NormalState) or "hidden" (IconicState). - A client can look for this property on other clients' windows, in order to distinguish application windows (which have the WM_STATE property) from windows created by the window manager. One notable program that makes use of the latter feature is Mozilla Firefox, which allows WebRTC sites to perform "screen sharing" - but in order to share a single window rather than the whole screen, that other window must have the WM_STATE property. We want to set this property when a client window is mapped, and unset it when the window is unmapped (withdrawn). In Qubes, we pretend that the window is always in normal state, regardless of whether it's currently minimized/iconified/shaded in dom0. Note that this property shouldn't be set for override-redirect windows, since those are beyond the window manager's purview. --- gui-agent/vmside.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 2fa72e29..7b2d3357 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -89,6 +89,7 @@ struct _global_handles { Atom tray_opcode; /* Atom: _NET_SYSTEM_TRAY_MESSAGE_OPCODE */ Atom xembed_info; /* Atom: _XEMBED_INFO */ Atom utf8_string_atom; /* Atom: UTF8_STRING */ + Atom wm_state; /* Atom: WM_STATE */ Atom net_wm_state; /* Atom: _NET_WM_STATE */ Atom wm_state_fullscreen; /* Atom: _NET_WM_STATE_FULLSCREEN */ Atom wm_state_demands_attention; /* Atom: _NET_WM_STATE_DEMANDS_ATTENTION */ @@ -802,6 +803,7 @@ static void send_window_state(Ghandles * g, XID window) static void process_xevent_map(Ghandles * g, XID window) { XWindowAttributes attr; + long new_wm_state[2]; struct msg_hdr hdr; struct msg_map_info map_info; Window transient; @@ -825,6 +827,13 @@ static void process_xevent_map(Ghandles * g, XID window) write_message(g->vchan, hdr, map_info); send_wmname(g, window); // process_xevent_damage(g, window, 0, 0, attr.width, attr.height); + + if (!attr.override_redirect) { + /* WM_STATE is always set to normal */ + new_wm_state[0] = NormalState; /* state */ + new_wm_state[1] = None; /* icon */ + XChangeProperty(g->display, window, g->wm_state, g->wm_state, 32, PropModeReplace, (unsigned char *)new_wm_state, 2); + } } static void process_xevent_unmap(Ghandles * g, XID window) @@ -838,6 +847,7 @@ static void process_xevent_unmap(Ghandles * g, XID window) hdr.window = window; hdr.untrusted_len = 0; write_struct(g->vchan, hdr); + XDeleteProperty(g->display, window, g->wm_state); XDeleteProperty(g->display, window, g->net_wm_state); } @@ -1552,6 +1562,7 @@ static void mkghandles(Ghandles * g) g->tray_opcode = XInternAtom(g->display, "_NET_SYSTEM_TRAY_OPCODE", False); g->xembed_info = XInternAtom(g->display, "_XEMBED_INFO", False); + g->wm_state = XInternAtom(g->display, "WM_STATE", False); g->net_wm_state = XInternAtom(g->display, "_NET_WM_STATE", False); g->wm_state_fullscreen = XInternAtom(g->display, "_NET_WM_STATE_FULLSCREEN", False); g->wm_state_demands_attention = XInternAtom(g->display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);