diff options
Diffstat (limited to 'xwayland')
| -rw-r--r-- | xwayland/xwm.c | 97 | 
1 files changed, 70 insertions, 27 deletions
diff --git a/xwayland/xwm.c b/xwayland/xwm.c index fb5879e3..845b98cc 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -85,6 +85,7 @@ const char *const atom_map[ATOM_LAST] = {  	[DND_ACTION_ASK] = "XdndActionAsk",  	[DND_ACTION_PRIVATE] = "XdndActionPrivate",  	[NET_CLIENT_LIST] = "_NET_CLIENT_LIST", +	[NET_CLIENT_LIST_STACKING] = "_NET_CLIENT_LIST_STACKING",  };  static const struct wlr_surface_role xwayland_surface_role; @@ -147,6 +148,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create(  	surface->height = height;  	surface->override_redirect = override_redirect;  	wl_list_init(&surface->children); +	wl_list_init(&surface->stack_link);  	wl_list_init(&surface->parent_link);  	wl_signal_init(&surface->events.destroy);  	wl_signal_init(&surface->events.request_configure); @@ -223,6 +225,10 @@ static void xwm_send_wm_message(struct wlr_xwayland_surface *surface,  }  static void xwm_set_net_client_list(struct wlr_xwm *xwm) { +	// FIXME: _NET_CLIENT_LIST is expected to be ordered by map time, but the +	// order of surfaces in `xwm->surfaces` is by creation time. The order of +	// windows _NET_CLIENT_LIST exposed by wlroots is wrong. +  	size_t mapped_surfaces = 0;  	struct wlr_xwayland_surface *surface;  	wl_list_for_each(surface, &xwm->surfaces, link) { @@ -244,6 +250,24 @@ static void xwm_set_net_client_list(struct wlr_xwm *xwm) {  			XCB_ATOM_WINDOW, 32, mapped_surfaces, windows);  } +static void xwm_set_net_client_list_stacking(struct wlr_xwm *xwm) { +	size_t num_surfaces = wl_list_length(&xwm->surfaces_in_stack_order); +	xcb_window_t windows[num_surfaces + 1]; + +	// We store surfaces in top-to-bottom order because this is easier to reason +	// about, but _NET_CLIENT_LIST_STACKING is supposed to be in bottom-to-top +	// order, so iterate backwards through the list. +	size_t i = 0; +	struct wlr_xwayland_surface *xsurface; +	wl_list_for_each(xsurface, &xwm->surfaces_in_stack_order, stack_link) { +		windows[i++] = xsurface->window_id; +	} + +	xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, xwm->screen->root, +			xwm->atoms[NET_CLIENT_LIST_STACKING], XCB_ATOM_WINDOW, 32, num_surfaces, +			windows); +} +  static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface);  static void xwm_set_focus_window(struct wlr_xwm *xwm, @@ -285,11 +309,7 @@ static void xwm_set_focus_window(struct wlr_xwm *xwm,  		xwm->last_focus_seq = cookie.sequence;  	} -	uint32_t values[1]; -	values[0] = XCB_STACK_MODE_ABOVE; -	xcb_configure_window(xwm->xcb_conn, xsurface->window_id, -		XCB_CONFIG_WINDOW_STACK_MODE, values); - +	wlr_xwayland_surface_restack(xsurface, NULL, XCB_STACK_MODE_ABOVE);  	xsurface_set_net_wm_state(xsurface);  } @@ -358,6 +378,7 @@ static void xwayland_surface_destroy(  	}  	wl_list_remove(&xsurface->link); +	wl_list_remove(&xsurface->stack_link);  	wl_list_remove(&xsurface->parent_link);  	struct wlr_xwayland_surface *child, *next; @@ -964,6 +985,47 @@ static void xsurface_set_wm_state(struct wlr_xwayland_surface *xsurface,  		sizeof(property) / sizeof(property[0]), property);  } +void wlr_xwayland_surface_restack(struct wlr_xwayland_surface *xsurface, +		struct wlr_xwayland_surface *sibling, enum xcb_stack_mode_t mode) { +	struct wlr_xwm *xwm = xsurface->xwm; +	uint32_t values[2]; +	size_t idx = 0; +	uint32_t flags = XCB_CONFIG_WINDOW_STACK_MODE; + +	if (sibling != NULL) { +		values[idx++] = sibling->window_id; +		flags |= XCB_CONFIG_WINDOW_SIBLING; +	} +	values[idx++] = mode; + +	xcb_configure_window(xwm->xcb_conn, xsurface->window_id, flags, values); + +	wl_list_remove(&xsurface->stack_link); + +	struct wl_list *node; +	if (mode == XCB_STACK_MODE_ABOVE) { +		if (sibling) { +			node = &sibling->stack_link; +		} else { +			node = xwm->surfaces_in_stack_order.prev; +		} +	} else if (mode == XCB_STACK_MODE_BELOW) { +		if (sibling) { +			node = sibling->stack_link.prev; +		} else { +			node = &xwm->surfaces_in_stack_order; +		} +	} else { +		// Not implementing XCB_STACK_MODE_TOP_IF | XCB_STACK_MODE_BOTTOM_IF | +		// XCB_STACK_MODE_OPPOSITE. +		abort(); +	} + +	wl_list_insert(node, &xsurface->stack_link); +	xwm_set_net_client_list_stacking(xwm); +	xcb_flush(xwm->xcb_conn); +} +  static void xwm_handle_map_request(struct wlr_xwm *xwm,  		xcb_map_request_event_t *ev) {  	struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); @@ -974,11 +1036,7 @@ static void xwm_handle_map_request(struct wlr_xwm *xwm,  	xsurface_set_wm_state(xsurface, XCB_ICCCM_WM_STATE_NORMAL);  	xsurface_set_net_wm_state(xsurface); -	uint32_t values[1]; -	values[0] = XCB_STACK_MODE_BELOW; -	xcb_configure_window(xwm->xcb_conn, ev->window, -			XCB_CONFIG_WINDOW_STACK_MODE, values); - +	wlr_xwayland_surface_restack(xsurface, NULL, XCB_STACK_MODE_BELOW);  	xcb_map_window(xwm->xcb_conn, ev->window);  } @@ -1531,23 +1589,6 @@ void wlr_xwayland_surface_activate(struct wlr_xwayland_surface *xsurface,  	}  } -void wlr_xwayland_surface_restack(struct wlr_xwayland_surface *surface, -		struct wlr_xwayland_surface *sibling, enum xcb_stack_mode_t mode) { -	struct wlr_xwm *xwm = surface->xwm; -	uint32_t values[2]; -	size_t idx = 0; -	uint32_t flags = XCB_CONFIG_WINDOW_STACK_MODE; - -	if (sibling != NULL) { -		values[idx++] = sibling->window_id; -		flags |= XCB_CONFIG_WINDOW_SIBLING; -	} -	values[idx++] = mode; - -	xcb_configure_window(xwm->xcb_conn, surface->window_id, flags, values); -	xcb_flush(xwm->xcb_conn); -} -  void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,  		int16_t x, int16_t y, uint16_t width, uint16_t height) {  	xsurface->x = x; @@ -1878,6 +1919,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {  	xwm->xwayland = xwayland;  	wl_list_init(&xwm->surfaces); +	wl_list_init(&xwm->surfaces_in_stack_order);  	wl_list_init(&xwm->unpaired_surfaces);  	xwm->ping_timeout = 10000; @@ -1937,6 +1979,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {  		xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ],  		xwm->atoms[NET_WM_STATE_HIDDEN],  		xwm->atoms[NET_CLIENT_LIST], +		xwm->atoms[NET_CLIENT_LIST_STACKING],  	};  	xcb_change_property(xwm->xcb_conn,  		XCB_PROP_MODE_REPLACE,  | 
