From cda66e9a263d8467b6d1857808305d5e9f7bc3cd Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 18 Jun 2018 22:49:28 +0100 Subject: Automatically float xwayland windows --- sway/desktop/xwayland.c | 83 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 10 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 6447b711..2c3848cd 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -15,6 +15,14 @@ #include "sway/tree/layout.h" #include "sway/tree/view.h" +static const char *atom_map[ATOM_LAST] = { + "_NET_WM_WINDOW_TYPE_DIALOG", + "_NET_WM_WINDOW_TYPE_UTILITY", + "_NET_WM_WINDOW_TYPE_TOOLBAR", + "_NET_WM_WINDOW_TYPE_SPLASH", + "_NET_WM_STATE_MODAL", +}; + static void unmanaged_handle_request_configure(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = @@ -61,7 +69,8 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { if (!wlr_xwayland_surface_is_unmanaged(xsurface)) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct wlr_xwayland *xwayland = seat->input->server->xwayland; + struct wlr_xwayland *xwayland = + seat->input->server->xwayland.wlr_xwayland; wlr_xwayland_set_seat(xwayland, seat->wlr_seat); seat_set_focus_surface(seat, xsurface->surface); } @@ -199,15 +208,32 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { } static bool wants_floating(struct sway_view *view) { - // TODO: - // We want to return true if the window type contains any of these: - // NET_WM_WINDOW_TYPE_DIALOG - // NET_WM_WINDOW_TYPE_UTILITY - // NET_WM_WINDOW_TYPE_TOOLBAR - // NET_WM_WINDOW_TYPE_SPLASH - // - // We also want to return true if the NET_WM_STATE is MODAL. - // wlroots doesn't appear to provide all this information at the moment. + if (xwayland_view_from_view(view) == NULL) { + return false; + } + struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; + struct sway_xwayland *xwayland = &server.xwayland; + + // TODO: return true if the NET_WM_STATE is MODAL + + for (size_t i = 0; i < surface->window_type_len; ++i) { + xcb_atom_t type = surface->window_type[i]; + if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_DIALOG] || + type == xwayland->atoms[NET_WM_WINDOW_TYPE_UTILITY] || + type == xwayland->atoms[NET_WM_WINDOW_TYPE_TOOLBAR] || + type == xwayland->atoms[NET_WM_WINDOW_TYPE_SPLASH]) { + return true; + } + } + + struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; + if (size_hints != NULL && + size_hints->min_width != 0 && size_hints->min_height != 0 && + size_hints->max_width == size_hints->min_width && + size_hints->max_height == size_hints->min_height) { + return true; + } + return false; } @@ -411,3 +437,40 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { wl_signal_add(&xsurface->events.map, &xwayland_view->map); xwayland_view->map.notify = handle_map; } + +void handle_xwayland_ready(struct wl_listener *listener, void *data) { + struct sway_server *server = + wl_container_of(listener, server, xwayland_ready); + struct sway_xwayland *xwayland = &server->xwayland; + + xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL); + int err = xcb_connection_has_error(xcb_conn); + if (err) { + wlr_log(L_ERROR, "XCB connect failed: %d", err); + return; + } + + xcb_intern_atom_cookie_t cookies[ATOM_LAST]; + for (size_t i = 0; i < ATOM_LAST; i++) { + cookies[i] = + xcb_intern_atom(xcb_conn, 0, strlen(atom_map[i]), atom_map[i]); + } + for (size_t i = 0; i < ATOM_LAST; i++) { + xcb_generic_error_t *error = NULL; + xcb_intern_atom_reply_t *reply = + xcb_intern_atom_reply(xcb_conn, cookies[i], &error); + if (reply != NULL && error == NULL) { + xwayland->atoms[i] = reply->atom; + } + free(reply); + + if (error != NULL) { + wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d", + atom_map[i], error->error_code); + free(error); + break; + } + } + + xcb_disconnect(xcb_conn); +} -- cgit v1.2.3 From eeb38d65cbf5c8452c449b9f5e003bd255ca6a53 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 24 Jun 2018 19:21:02 +0100 Subject: xwayland: accept configure requests from floating views --- sway/desktop/xwayland.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 2c3848cd..eb39dc4b 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -334,8 +334,12 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { ev->width, ev->height); return; } - // TODO: Let floating views do whatever - configure(view, view->swayc->x, view->swayc->y, view->width, view->height); + if (container_is_floating(view->swayc)) { + configure(view, view->swayc->x, view->swayc->y, ev->width, ev->height); + } else { + configure(view, view->swayc->x, view->swayc->y, + view->width, view->height); + } } static void handle_request_fullscreen(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From c9be0145576433e71f8b7732f7ff5ddee0d36076 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 26 Jun 2018 11:59:06 +0900 Subject: xdg_shell: make view floating if a parent has been set Prompts e.g. authentication request from firefox-wayland ought to be floating. This is a bit coarse but just fixed size is not enough, here is what firefox does: [1285461.363] -> xdg_wm_base@18.get_xdg_surface(new id xdg_surface@68, wl_surface@71) [1285461.508] -> xdg_surface@68.get_toplevel(new id xdg_toplevel@67) [1285461.571] -> xdg_toplevel@67.set_parent(xdg_toplevel@37) [1285461.630] -> xdg_toplevel@67.set_title("Authentication Required") [1285461.736] -> xdg_toplevel@67.set_app_id("firefox") ... [1285476.549] xdg_toplevel@67.configure(0, 0, array) ... [1285502.080] -> xdg_toplevel@67.set_min_size(299, 187) [1285502.140] -> xdg_toplevel@67.set_max_size(1920, 32767) This can also be observed with e.g. the open window of gedit (gedit->open->other documents) --- sway/desktop/xdg_shell.c | 9 +++++---- sway/desktop/xdg_shell_v6.c | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index d2b8822c..8457c06b 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -120,11 +120,12 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { } static bool wants_floating(struct sway_view *view) { - struct wlr_xdg_toplevel_state *state = - &view->wlr_xdg_surface->toplevel->current; - return state->min_width != 0 && state->min_height != 0 + struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel; + struct wlr_xdg_toplevel_state *state = &toplevel->current; + return (state->min_width != 0 && state->min_height != 0 && state->min_width == state->max_width - && state->min_height == state->max_height; + && state->min_height == state->max_height) + || toplevel->parent; } static void for_each_surface(struct sway_view *view, diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 6ffe334a..eb1cef26 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -119,11 +119,13 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { } static bool wants_floating(struct sway_view *view) { - struct wlr_xdg_toplevel_v6_state *state = - &view->wlr_xdg_surface_v6->toplevel->current; - return state->min_width != 0 && state->min_height != 0 + struct wlr_xdg_toplevel_v6 *toplevel = + view->wlr_xdg_surface_v6->toplevel; + struct wlr_xdg_toplevel_v6_state *state = &toplevel->current; + return (state->min_width != 0 && state->min_height != 0 && state->min_width == state->max_width - && state->min_height == state->max_height; + && state->min_height == state->max_height) + || toplevel->parent; } static void for_each_surface(struct sway_view *view, -- cgit v1.2.3 From 08800c8ee22f2aad8c00117756c15169d6e543b1 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 26 Jun 2018 21:16:42 +0900 Subject: layer_shell: cleanup output link on output destroy Fixes this kind of use-after-free: ==1795==ERROR: AddressSanitizer: heap-use-after-free on address 0x612000191ef0 at pc 0x00000048c388 bp 0x7ffe308f0410 sp 0x7ffe308f0400 WRITE of size 8 at 0x612000191ef0 thread T0 #0 0x48c387 in wl_list_remove ../common/list.c:157 #1 0x42196b in handle_destroy ../sway/desktop/layer_shell.c:275 #2 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29 #3 0x7f55cc22cf68 in layer_surface_destroy ../types/wlr_layer_shell.c:182 #4 0x7f55cc22d084 in layer_surface_resource_destroy ../types/wlr_layer_shell.c:196 #5 0x7f55cc4ca025 in destroy_resource src/wayland-server.c:688 #6 0x7f55cc4ca091 in wl_resource_destroy src/wayland-server.c:705 #7 0x7f55cc22c3a2 in resource_handle_destroy ../types/wlr_layer_shell.c:18 #8 0x7f55c8ef103d in ffi_call_unix64 (/lib64/libffi.so.6+0x603d) #9 0x7f55c8ef09fe in ffi_call (/lib64/libffi.so.6+0x59fe) #10 0x7f55cc4cdf2c (/lib64/libwayland-server.so.0+0xbf2c) #11 0x7f55cc4ca3de in wl_client_connection_data src/wayland-server.c:420 #12 0x7f55cc4cbf01 in wl_event_loop_dispatch src/event-loop.c:641 #13 0x7f55cc4ca601 in wl_display_run src/wayland-server.c:1260 #14 0x40bb1e in server_run ../sway/server.c:141 #15 0x40ab2f in main ../sway/main.c:432 #16 0x7f55cb97318a in __libc_start_main ../csu/libc-start.c:308 #17 0x408d29 in _start (/opt/wayland/bin/sway+0x408d29) 0x612000191ef0 is located 48 bytes inside of 312-byte region [0x612000191ec0,0x612000191ff8) freed by thread T0 here: #0 0x7f55ce3bb880 in __interceptor_free (/lib64/libasan.so.5+0xee880) #1 0x42f1db in handle_destroy ../sway/desktop/output.c:1275 #2 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29 #3 0x7f55cc23b4c2 in wlr_output_destroy ../types/wlr_output.c:284 #4 0x7f55cc1ddc20 in xdg_toplevel_handle_close ../backend/wayland/output.c:235 #5 0x7f55c8ef103d in ffi_call_unix64 (/lib64/libffi.so.6+0x603d) previously allocated by thread T0 here: #0 0x7f55ce3bbe50 in calloc (/lib64/libasan.so.5+0xeee50) #1 0x42f401 in handle_new_output ../sway/desktop/output.c:1308 #2 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29 #3 0x7f55cc1d6cbf in new_output_reemit ../backend/multi/backend.c:113 #4 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29 #5 0x7f55cc1deac7 in wlr_wl_output_create ../backend/wayland/output.c:327 #6 0x7f55cc1db353 in backend_start ../backend/wayland/backend.c:55 #7 0x7f55cc1bad55 in wlr_backend_start ../backend/backend.c:35 #8 0x7f55cc1d67a0 in multi_backend_start ../backend/multi/backend.c:24 #9 0x7f55cc1bad55 in wlr_backend_start ../backend/backend.c:35 #10 0x40ba8a in server_run ../sway/server.c:136 #11 0x40ab2f in main ../sway/main.c:432 #12 0x7f55cb97318a in __libc_start_main ../csu/libc-start.c:308 --- sway/desktop/layer_shell.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 3accdefb..94dc22e7 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -219,6 +219,8 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { struct sway_layer_surface *sway_layer = wl_container_of(listener, sway_layer, output_destroy); wl_list_remove(&sway_layer->output_destroy.link); + wl_list_remove(&sway_layer->link); + wl_list_init(&sway_layer->link); sway_layer->layer_surface->output = NULL; wlr_layer_surface_close(sway_layer->layer_surface); } -- cgit v1.2.3 From 6856866a612c9f0708a42cbe6d9627173d9e3569 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 26 Jun 2018 21:19:38 +0900 Subject: layer_shell: order destroying before sway_output Both sway_output and sway_layer_shell listen to wlr's output destroy event, but sway_layer_shell needs to access into sway_output's data strucure and needs to be destroyed first. Resolve this by making sway_layer_shell listen to a new event that happens at start of sway_output's destroy handler --- include/sway/output.h | 4 ++++ sway/desktop/layer_shell.c | 7 +++---- sway/desktop/output.c | 3 +++ 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'sway/desktop') diff --git a/include/sway/output.h b/include/sway/output.h index 70f746dc..8180ce3d 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -32,6 +32,10 @@ struct sway_output { struct wl_list link; pid_t bg_pid; + + struct { + struct wl_signal destroy; + } events; }; void output_damage_whole(struct sway_output *output); diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 94dc22e7..b57d1ee6 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -352,10 +352,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { wl_signal_add(&layer_surface->surface->events.commit, &sway_layer->surface_commit); - sway_layer->output_destroy.notify = handle_output_destroy; - wl_signal_add(&layer_surface->output->events.destroy, - &sway_layer->output_destroy); - sway_layer->destroy.notify = handle_destroy; wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); sway_layer->map.notify = handle_map; @@ -368,6 +364,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { layer_surface->data = sway_layer; struct sway_output *output = layer_surface->output->data; + sway_layer->output_destroy.notify = handle_output_destroy; + wl_signal_add(&output->events.destroy, &sway_layer->output_destroy); + wl_list_insert(&output->layers[layer_surface->layer], &sway_layer->link); // Temporarily set the layer's current state to client_pending diff --git a/sway/desktop/output.c b/sway/desktop/output.c index d4115be8..f0f1603a 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -1199,6 +1199,8 @@ static void damage_handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, destroy); + wl_signal_emit(&output->events.destroy, output); + if (output->swayc) { container_destroy(output->swayc); } @@ -1277,6 +1279,7 @@ void output_enable(struct sway_output *output) { for (size_t i = 0; i < len; ++i) { wl_list_init(&output->layers[i]); } + wl_signal_init(&output->events.destroy); input_manager_configure_xcursor(input_manager); -- cgit v1.2.3 From c4b900c1e04ec45b481a3f05870d8b4a6c49e386 Mon Sep 17 00:00:00 2001 From: Armin Preiml Date: Wed, 27 Jun 2018 17:48:36 +0200 Subject: fix accidently removing borders on XCB_CONFIGURE_REQUEST The view was configured with the container coordinates. Although they were right on the first configure, they changed after a XCB_CONFIGURE_REQUEST, when the border was already drawn. --- sway/desktop/xwayland.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index eb39dc4b..df5f6698 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -335,9 +335,9 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { return; } if (container_is_floating(view->swayc)) { - configure(view, view->swayc->x, view->swayc->y, ev->width, ev->height); + configure(view, view->x, view->y, ev->width, ev->height); } else { - configure(view, view->swayc->x, view->swayc->y, + configure(view, view->x, view->y, view->width, view->height); } } -- cgit v1.2.3