Skip to content

Commit

Permalink
xwm: Add support for minimize actions
Browse files Browse the repository at this point in the history
This fixes minimize buttons for several xwayland CSD clients such as steam and chrome.
Fixes swaywm#2251.
  • Loading branch information
soreau committed Jul 19, 2020
1 parent 751a21d commit 1d21c9c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
5 changes: 5 additions & 0 deletions include/wlr/xwayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ struct wlr_xwayland_surface {
bool modal;
bool fullscreen;
bool maximized_vert, maximized_horz;
bool minimized;

bool has_alpha;

Expand All @@ -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;
Expand Down Expand Up @@ -250,6 +252,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);

Expand Down
2 changes: 2 additions & 0 deletions include/xwayland/xwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
59 changes: 58 additions & 1 deletion xwayland/xwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -1165,6 +1177,14 @@ 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;
}
wlr_signal_emit_safe(&xsurface->events.request_minimize, xsurface);
}
}

static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm,
Expand Down Expand Up @@ -1202,6 +1222,26 @@ 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 *surface = lookup_surface(xwm, ev->window);
if (surface == NULL) {
return;
}
uint32_t detail = ev->data.data32[0];

if (surface == NULL) {
return;
} else if (detail == ICCCM_ICONIC_STATE || detail == ICCCM_NORMAL_STATE) {
xsurface_set_wm_state(surface, detail);
xsurface_set_net_wm_state(surface);
surface->minimized = detail == ICCCM_ICONIC_STATE ? true : false;
wlr_signal_emit_safe(&surface->events.request_minimize, surface);
} else {
wlr_log(WLR_DEBUG, "unhandled wm_change_state event %u", detail);
}
}

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);
Expand All @@ -1216,6 +1256,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,
Expand Down Expand Up @@ -1768,6 +1810,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,
Expand Down Expand Up @@ -1799,6 +1842,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;
Expand Down

0 comments on commit 1d21c9c

Please sign in to comment.