From bd387da62d78f25027f1f80d25d85970fd09c235 Mon Sep 17 00:00:00 2001 From: Tobias Langendorf Date: Sat, 18 Jul 2020 21:37:02 +0200 Subject: [PATCH] xwm: add support for xwayland minimize --- include/wlr/xwayland.h | 10 ++++++ include/xwayland/xwm.h | 2 ++ xwayland/xwm.c | 70 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 03201718..26a14aea 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -173,6 +173,7 @@ struct wlr_xwayland_surface { bool modal; bool fullscreen; bool maximized_vert, maximized_horz; + bool minimized; bool has_alpha; @@ -181,6 +182,7 @@ struct wlr_xwayland_surface { struct wl_signal request_configure; struct wl_signal request_move; struct wl_signal request_resize; + struct wl_signal request_minimize; struct wl_signal request_maximize; struct wl_signal request_fullscreen; struct wl_signal request_activate; @@ -221,6 +223,11 @@ struct wlr_xwayland_resize_event { uint32_t edges; }; +struct wlr_xwayland_minimize_event { + struct wlr_xwayland_surface *surface; + bool minimize; +}; + struct wlr_xwayland_server *wlr_xwayland_server_create( struct wl_display *display, struct wlr_xwayland_server_options *options); void wlr_xwayland_server_destroy(struct wlr_xwayland_server *server); @@ -250,6 +257,9 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *surface, void wlr_xwayland_surface_close(struct wlr_xwayland_surface *surface); +void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface, + bool minimized); + void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface, bool maximized); diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 2569092f..1085cb14 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -44,7 +44,9 @@ enum atom_name { NET_WM_STATE_FULLSCREEN, NET_WM_STATE_MAXIMIZED_VERT, NET_WM_STATE_MAXIMIZED_HORZ, + NET_WM_STATE_HIDDEN, NET_WM_PING, + WM_CHANGE_STATE, WM_STATE, CLIPBOARD, PRIMARY, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 28e329f3..a3fb61b4 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -42,7 +42,9 @@ const char *atom_map[ATOM_LAST] = { [NET_WM_STATE_FULLSCREEN] = "_NET_WM_STATE_FULLSCREEN", [NET_WM_STATE_MAXIMIZED_VERT] = "_NET_WM_STATE_MAXIMIZED_VERT", [NET_WM_STATE_MAXIMIZED_HORZ] = "_NET_WM_STATE_MAXIMIZED_HORZ", + [NET_WM_STATE_HIDDEN] = "_NET_WM_STATE_HIDDEN", [NET_WM_PING] = "_NET_WM_PING", + [WM_CHANGE_STATE] = "WM_CHANGE_STATE", [WM_STATE] = "WM_STATE", [CLIPBOARD] = "CLIPBOARD", [PRIMARY] = "PRIMARY", @@ -146,6 +148,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.request_configure); wl_signal_init(&surface->events.request_move); wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.request_maximize); wl_signal_init(&surface->events.request_fullscreen); wl_signal_init(&surface->events.request_activate); @@ -290,7 +293,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[4]; + uint32_t property[5]; int i; i = 0; @@ -306,6 +309,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->maximized_horz) { property[i++] = xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ]; } + if (xsurface->minimized) { + property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; + } xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, @@ -664,6 +670,8 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm, xsurface->maximized_vert = true; } else if (atom[i] == xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ]) { xsurface->maximized_horz = true; + } else if (atom[i] == xwm->atoms[NET_WM_STATE_HIDDEN]) { + xsurface->minimized = true; } } } @@ -1126,6 +1134,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, bool fullscreen = xsurface->fullscreen; bool maximized = xsurface_is_maximized(xsurface); + bool minimized = xsurface->minimized; uint32_t action = client_message->data.data32[0]; for (size_t i = 0; i < 2; ++i) { @@ -1143,6 +1152,9 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, } else if (property == xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ] && update_state(action, &xsurface->maximized_horz)) { xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[NET_WM_STATE_HIDDEN] && + update_state(action, &xsurface->minimized)) { + xsurface_set_net_wm_state(xsurface); } } // client_message->data.data32[3] is the source indication @@ -1165,6 +1177,19 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.request_maximize, xsurface); } + + if (minimized != xsurface->minimized) { + if (xsurface->minimized) { + xsurface->saved_width = xsurface->width; + xsurface->saved_height = xsurface->height; + } + + struct wlr_xwayland_minimize_event minimize_event = { + .surface = xsurface, + .minimize = xsurface->minimized, + }; + wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); + } } static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, @@ -1202,6 +1227,32 @@ static void xwm_handle_net_active_window_message(struct wlr_xwm *xwm, wlr_signal_emit_safe(&surface->events.request_activate, surface); } +static void xwm_handle_wm_change_state_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); + uint32_t detail = ev->data.data32[0]; + + if (xsurface == NULL) { + return; + } + + bool minimize; + if (detail == ICCCM_ICONIC_STATE) { + minimize = true; + } else if (detail == ICCCM_NORMAL_STATE) { + minimize = false; + } else { + wlr_log(WLR_DEBUG, "unhandled wm_change_state event %u", detail); + return; + } + + struct wlr_xwayland_minimize_event minimize_event = { + .surface = xsurface, + .minimize = minimize, + }; + wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); +} + static void xwm_handle_client_message(struct wlr_xwm *xwm, xcb_client_message_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_CLIENT_MESSAGE (%u)", ev->window); @@ -1216,6 +1267,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_wm_protocols_message(xwm, ev); } else if (ev->type == xwm->atoms[NET_ACTIVE_WINDOW]) { xwm_handle_net_active_window_message(xwm, ev); + } else if (ev->type == xwm->atoms[WM_CHANGE_STATE]) { + xwm_handle_wm_change_state_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, @@ -1768,6 +1821,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { xwm->atoms[NET_WM_STATE_FULLSCREEN], xwm->atoms[NET_WM_STATE_MAXIMIZED_VERT], xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ], + xwm->atoms[NET_WM_STATE_HIDDEN], xwm->atoms[NET_CLIENT_LIST], }; xcb_change_property(xwm->xcb_conn, @@ -1799,6 +1853,20 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { return xwm; } +void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface, + bool minimized) { + surface->minimized = minimized; + + if (minimized) { + xsurface_set_wm_state(surface, ICCCM_ICONIC_STATE); + } else { + xsurface_set_wm_state(surface, ICCCM_NORMAL_STATE); + } + + xsurface_set_net_wm_state(surface); + xcb_flush(surface->xwm->xcb_conn); +} + void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface, bool maximized) { surface->maximized_horz = maximized;