diff options
-rw-r--r-- | include/wlr/xwayland.h | 5 | ||||
-rw-r--r-- | xwayland/xwm.c | 55 | ||||
-rw-r--r-- | xwayland/xwm.h | 1 |
3 files changed, 60 insertions, 1 deletions
diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index bb85017e..43133567 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -50,6 +50,9 @@ struct wlr_xwayland_surface { xcb_atom_t *window_type; size_t window_type_len; + xcb_atom_t *protocols; + size_t protocols_len; + struct { struct wl_signal destroy; @@ -79,5 +82,7 @@ void wlr_xwayland_surface_activate(struct wlr_xwayland *wlr_xwayland, struct wlr_xwayland_surface *surface); void wlr_xwayland_surface_configure(struct wlr_xwayland *wlr_xwayland, struct wlr_xwayland_surface *surface); +void wlr_xwayland_surface_close(struct wlr_xwayland *wlr_xwayland, + struct wlr_xwayland_surface *surface); #endif diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a84b19a5..d7816bcd 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -10,6 +10,7 @@ const char *atom_map[ATOM_LAST] = { "WL_SURFACE_ID", + "WM_DELETE_WINDOW", "WM_PROTOCOLS", "UTF8_STRING", "WM_S0", @@ -243,6 +244,27 @@ static void read_surface_window_type(struct wlr_xwm *xwm, wl_signal_emit(&surface->events.set_window_type, surface); } +static void read_surface_protocols(struct wlr_xwm *xwm, + struct wlr_xwayland_surface *surface, xcb_get_property_reply_t *reply) { + if (reply->type != XCB_ATOM_ATOM) { + return; + } + + xcb_atom_t *atoms = xcb_get_property_value(reply); + size_t atoms_len = reply->value_len; + size_t atoms_size = sizeof(xcb_atom_t) * atoms_len; + + free(surface->protocols); + surface->protocols = malloc(atoms_size); + if (surface->protocols == NULL) { + return; + } + memcpy(surface->protocols, atoms, atoms_size); + surface->protocols_len = atoms_len; + + wlr_log(L_DEBUG, "WM_PROTOCOLS (%zu)", atoms_len); +} + static void read_surface_property(struct wlr_xwm *xwm, struct wlr_xwayland_surface *surface, xcb_atom_t property) { xcb_get_property_cookie_t cookie = xcb_get_property(xwm->xcb_conn, 0, @@ -264,6 +286,8 @@ static void read_surface_property(struct wlr_xwm *xwm, read_surface_pid(xwm, surface, reply); } else if (property == xwm->atoms[NET_WM_WINDOW_TYPE]) { read_surface_window_type(xwm, surface, reply); + } else if (property == xwm->atoms[WM_PROTOCOLS]) { + read_surface_protocols(xwm, surface, reply); } else if (property == xwm->atoms[NET_WM_STATE]) { read_surface_state(xwm, surface, reply); } else { @@ -284,7 +308,7 @@ static void map_shell_surface(struct wlr_xwm *xwm, XCB_ATOM_WM_CLASS, XCB_ATOM_WM_NAME, XCB_ATOM_WM_TRANSIENT_FOR, - //xwm->atoms[WM_PROTOCOLS], + xwm->atoms[WM_PROTOCOLS], xwm->atoms[NET_WM_STATE], xwm->atoms[NET_WM_WINDOW_TYPE], xwm->atoms[NET_WM_NAME], @@ -596,6 +620,35 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland *wlr_xwayland, xcb_configure_window(xwm->xcb_conn, surface->window_id, mask, values); } +void wlr_xwayland_surface_close(struct wlr_xwayland *wlr_xwayland, + struct wlr_xwayland_surface *surface) { + struct wlr_xwm *xwm = wlr_xwayland->xwm; + + bool supports_delete = false; + for (size_t i = 0; i < surface->protocols_len; i++) { + if (surface->protocols[i] == xwm->atoms[WM_DELETE_WINDOW]) { + supports_delete = true; + break; + } + } + + if (supports_delete) { + xcb_client_message_event_t ev = {0}; + ev.response_type = XCB_CLIENT_MESSAGE; + ev.window = surface->window_id; + ev.format = 32; + ev.sequence = 0; + ev.type = xwm->atoms[WM_PROTOCOLS]; + ev.data.data32[0] = xwm->atoms[WM_DELETE_WINDOW]; + ev.data.data32[1] = XCB_CURRENT_TIME; + XCB_CALL(xwm, xcb_send_event_checked(xwm->xcb_conn, 0, + surface->window_id, XCB_EVENT_MASK_NO_EVENT, (char *)&ev)); + } else { + XCB_CALL(xwm, xcb_kill_client_checked(xwm->xcb_conn, + surface->window_id)); + } +} + void xwm_destroy(struct wlr_xwm *xwm) { if (!xwm) { return; diff --git a/xwayland/xwm.h b/xwayland/xwm.h index 0d753832..d1998e48 100644 --- a/xwayland/xwm.h +++ b/xwayland/xwm.h @@ -47,6 +47,7 @@ enum atom_name { WL_SURFACE_ID, + WM_DELETE_WINDOW, WM_PROTOCOLS, UTF8_STRING, WM_S0, |