diff options
Diffstat (limited to 'xwayland/xwm.c')
| -rw-r--r-- | xwayland/xwm.c | 129 | 
1 files changed, 105 insertions, 24 deletions
| diff --git a/xwayland/xwm.c b/xwayland/xwm.c index bee3a005..9c803543 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -24,6 +24,7 @@ const char *atom_map[ATOM_LAST] = {  	"WM_HINTS",  	"WM_NORMAL_HINTS",  	"WM_SIZE_HINTS", +	"WM_WINDOW_ROLE",  	"_MOTIF_WM_HINTS",  	"UTF8_STRING",  	"WM_S0", @@ -39,6 +40,7 @@ const char *atom_map[ATOM_LAST] = {  	"_NET_WM_MOVERESIZE",  	"_NET_WM_NAME",  	"_NET_SUPPORTING_WM_CHECK", +	"_NET_WM_STATE_MODAL",  	"_NET_WM_STATE_FULLSCREEN",  	"_NET_WM_STATE_MAXIMIZED_VERT",  	"_NET_WM_STATE_MAXIMIZED_HORZ", @@ -147,13 +149,17 @@ static struct wlr_xwayland_surface *xwayland_surface_create(  	wl_signal_init(&surface->events.request_resize);  	wl_signal_init(&surface->events.request_maximize);  	wl_signal_init(&surface->events.request_fullscreen); +	wl_signal_init(&surface->events.request_activate);  	wl_signal_init(&surface->events.map);  	wl_signal_init(&surface->events.unmap);  	wl_signal_init(&surface->events.set_class); +	wl_signal_init(&surface->events.set_role);  	wl_signal_init(&surface->events.set_title);  	wl_signal_init(&surface->events.set_parent);  	wl_signal_init(&surface->events.set_pid);  	wl_signal_init(&surface->events.set_window_type); +	wl_signal_init(&surface->events.set_hints); +	wl_signal_init(&surface->events.set_override_redirect);  	wl_signal_init(&surface->events.ping_timeout);  	xcb_get_geometry_reply_t *geometry_reply = @@ -240,8 +246,7 @@ static void xwm_send_focus_window(struct wlr_xwm *xwm,  		XCB_CONFIG_WINDOW_STACK_MODE, values);  } - -void xwm_surface_activate(struct wlr_xwm *xwm, +static void xwm_surface_activate(struct wlr_xwm *xwm,  		struct wlr_xwayland_surface *xsurface) {  	if (xwm->focus_surface == xsurface ||  			(xsurface && xsurface->override_redirect)) { @@ -267,6 +272,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) {  	int i;  	i = 0; +	if (xsurface->modal) { +		property[i++] = xwm->atoms[_NET_WM_STATE_MODAL]; +	}  	if (xsurface->fullscreen) {  		property[i++] = xwm->atoms[_NET_WM_STATE_FULLSCREEN];  	} @@ -321,6 +329,7 @@ static void xwayland_surface_destroy(  	free(xsurface->title);  	free(xsurface->class);  	free(xsurface->instance); +	free(xsurface->role);  	free(xsurface->window_type);  	free(xsurface->protocols);  	free(xsurface->hints); @@ -359,6 +368,28 @@ static void read_surface_class(struct wlr_xwm *xwm,  	wlr_signal_emit_safe(&surface->events.set_class, surface);  } +static void read_surface_role(struct wlr_xwm *xwm, +		struct wlr_xwayland_surface *xsurface, +		xcb_get_property_reply_t *reply) { +	if (reply->type != XCB_ATOM_STRING && +			reply->type != xwm->atoms[UTF8_STRING]) { +		return; +	} + +	size_t len = xcb_get_property_value_length(reply); +	char *role = xcb_get_property_value(reply); + +	free(xsurface->role); +	if (len > 0) { +		xsurface->role = strndup(role, len); +	} else { +		xsurface->role = NULL; +	} + +	wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", xsurface->role); +	wlr_signal_emit_safe(&xsurface->events.set_role, xsurface); +} +  static void read_surface_title(struct wlr_xwm *xwm,  		struct wlr_xwayland_surface *xsurface,  		xcb_get_property_reply_t *reply) { @@ -492,6 +523,7 @@ static void read_surface_hints(struct wlr_xwm *xwm,  	xsurface->hints_urgency = xcb_icccm_wm_hints_get_urgency(&hints);  	wlr_log(WLR_DEBUG, "WM_HINTS (%d)", reply->value_len); +	wlr_signal_emit_safe(&xsurface->events.set_hints, xsurface);  }  #else  static void read_surface_hints(struct wlr_xwm *xwm, @@ -573,7 +605,9 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm,  	xsurface->fullscreen = 0;  	xcb_atom_t *atom = xcb_get_property_value(reply);  	for (uint32_t i = 0; i < reply->value_len; i++) { -		if (atom[i] == xwm->atoms[_NET_WM_STATE_FULLSCREEN]) { +		if (atom[i] == xwm->atoms[_NET_WM_STATE_MODAL]) { +			xsurface->modal = true; +		} else if (atom[i] == xwm->atoms[_NET_WM_STATE_FULLSCREEN]) {  			xsurface->fullscreen = true;  		} else if (atom[i] == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT]) {  			xsurface->maximized_vert = true; @@ -629,6 +663,8 @@ static void read_surface_property(struct wlr_xwm *xwm,  		read_surface_normal_hints(xwm, xsurface, reply);  	} else if (property == xwm->atoms[MOTIF_WM_HINTS]) {  		read_surface_motif_hints(xwm, xsurface, reply); +	} else if (property == xwm->atoms[WM_WINDOW_ROLE]) { +		read_surface_role(xwm, xsurface, reply);  	} else {  		char *prop_name = xwm_get_atom_name(xwm, property);  		wlr_log(WLR_DEBUG, "unhandled X11 property %u (%s) for window %u", @@ -652,9 +688,27 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) {  	}  } +static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface) { +	assert(wlr_surface->role == &xwayland_surface_role); +	struct wlr_xwayland_surface *surface = wlr_surface->role_data; +	if (surface == NULL) { +		return; +	} + +	if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && +			wlr_surface->pending.buffer_resource == NULL) { +		// This is a NULL commit +		if (surface->mapped) { +			wlr_signal_emit_safe(&surface->events.unmap, surface); +			surface->mapped = false; +		} +	} +} +  static const struct wlr_surface_role xwayland_surface_role = {  	.name = "wlr_xwayland_surface",  	.commit = xwayland_surface_role_commit, +	.precommit = xwayland_surface_role_precommit,  };  static void handle_surface_destroy(struct wl_listener *listener, void *data) { @@ -764,9 +818,7 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm,  static void xwm_handle_configure_notify(struct wlr_xwm *xwm,  		xcb_configure_notify_event_t *ev) { -	struct wlr_xwayland_surface *xsurface = -		lookup_surface(xwm, ev->window); - +	struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window);  	if (!xsurface) {  		return;  	} @@ -775,6 +827,11 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm,  	xsurface->y = ev->y;  	xsurface->width = ev->width;  	xsurface->height = ev->height; + +	if (xsurface->override_redirect != ev->override_redirect) { +		xsurface->override_redirect = ev->override_redirect; +		wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); +	}  }  #define ICCCM_WITHDRAWN_STATE	0 @@ -814,6 +871,15 @@ static void xwm_handle_map_request(struct wlr_xwm *xwm,  static void xwm_handle_map_notify(struct wlr_xwm *xwm,  		xcb_map_notify_event_t *ev) {  	wlr_log(WLR_DEBUG, "XCB_MAP_NOTIFY (%u)", ev->window); +	struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); +	if (!xsurface) { +		return; +	} + +	if (xsurface->override_redirect != ev->override_redirect) { +		xsurface->override_redirect = ev->override_redirect; +		wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); +	}  }  static void xwm_handle_unmap_notify(struct wlr_xwm *xwm, @@ -996,7 +1062,10 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm,  	for (size_t i = 0; i < 2; ++i) {  		uint32_t property = client_message->data.data32[1 + i]; -		if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && +		if (property == xwm->atoms[_NET_WM_STATE_MODAL] && +				update_state(action, &xsurface->modal)) { +			xsurface_set_net_wm_state(xsurface); +		} else if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] &&  				update_state(action, &xsurface->fullscreen)) {  			xsurface_set_net_wm_state(xsurface);  		} else if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT] && @@ -1055,6 +1124,15 @@ static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm,  	}  } +static void xwm_handle_net_active_window_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; +	} +	wlr_signal_emit_safe(&surface->events.request_activate, surface); +} +  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); @@ -1067,6 +1145,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm,  		xwm_handle_net_wm_moveresize_message(xwm, ev);  	} else if (ev->type == xwm->atoms[WM_PROTOCOLS]) {  		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 (!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, @@ -1598,6 +1678,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {  		xwm->atoms[NET_WM_STATE],  		xwm->atoms[_NET_ACTIVE_WINDOW],  		xwm->atoms[_NET_WM_MOVERESIZE], +		xwm->atoms[_NET_WM_STATE_MODAL],  		xwm->atoms[_NET_WM_STATE_FULLSCREEN],  		xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT],  		xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ], @@ -1659,8 +1740,22 @@ bool xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms,  	return false;  } -bool wlr_xwayland_surface_is_unmanaged( +void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { +	xcb_client_message_data_t data = { 0 }; +	data.data32[0] = surface->xwm->atoms[_NET_WM_PING]; +	data.data32[1] = XCB_CURRENT_TIME; +	data.data32[2] = surface->window_id; + +	xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); + +	wl_event_source_timer_update(surface->ping_timer, +		surface->xwm->ping_timeout); +	surface->pinging = true; +} + +bool wlr_xwayland_or_surface_wants_focus(  		const struct wlr_xwayland_surface *surface) { +	bool ret = true;  	static enum atom_name needles[] = {  		NET_WM_WINDOW_TYPE_COMBO,  		NET_WM_WINDOW_TYPE_DND, @@ -1672,26 +1767,12 @@ bool wlr_xwayland_surface_is_unmanaged(  		NET_WM_WINDOW_TYPE_TOOLTIP,  		NET_WM_WINDOW_TYPE_UTILITY,  	}; -  	for (size_t i = 0; i < sizeof(needles) / sizeof(needles[0]); ++i) {  		if (xwm_atoms_contains(surface->xwm, surface->window_type,  				surface->window_type_len, needles[i])) { -			return true; +			ret = false;  		}  	} -	return false; -} - -void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { -	xcb_client_message_data_t data = { 0 }; -	data.data32[0] = surface->xwm->atoms[_NET_WM_PING]; -	data.data32[1] = XCB_CURRENT_TIME; -	data.data32[2] = surface->window_id; - -	xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); - -	wl_event_source_timer_update(surface->ping_timer, -		surface->xwm->ping_timeout); -	surface->pinging = true; +	return ret;  } | 
