diff options
Diffstat (limited to 'sway/desktop/xwayland.c')
-rw-r--r-- | sway/desktop/xwayland.c | 297 |
1 files changed, 206 insertions, 91 deletions
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 66cb3b02..270cf08f 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -1,20 +1,23 @@ | |||
1 | #define _POSIX_C_SOURCE 199309L | ||
2 | #include <float.h> | 1 | #include <float.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
5 | #include <wayland-server-core.h> | 4 | #include <wayland-server-core.h> |
6 | #include <wlr/types/wlr_output_layout.h> | 5 | #include <wlr/types/wlr_output_layout.h> |
7 | #include <wlr/types/wlr_output.h> | 6 | #include <wlr/types/wlr_output.h> |
7 | #include <wlr/types/wlr_xdg_activation_v1.h> | ||
8 | #include <wlr/types/wlr_scene.h> | ||
8 | #include <wlr/xwayland.h> | 9 | #include <wlr/xwayland.h> |
10 | #include <xcb/xcb_icccm.h> | ||
9 | #include "log.h" | 11 | #include "log.h" |
10 | #include "sway/desktop.h" | ||
11 | #include "sway/desktop/transaction.h" | 12 | #include "sway/desktop/transaction.h" |
12 | #include "sway/input/cursor.h" | 13 | #include "sway/input/cursor.h" |
13 | #include "sway/input/input-manager.h" | 14 | #include "sway/input/input-manager.h" |
14 | #include "sway/input/seat.h" | 15 | #include "sway/input/seat.h" |
15 | #include "sway/output.h" | 16 | #include "sway/output.h" |
17 | #include "sway/scene_descriptor.h" | ||
16 | #include "sway/tree/arrange.h" | 18 | #include "sway/tree/arrange.h" |
17 | #include "sway/tree/container.h" | 19 | #include "sway/tree/container.h" |
20 | #include "sway/server.h" | ||
18 | #include "sway/tree/view.h" | 21 | #include "sway/tree/view.h" |
19 | #include "sway/tree/workspace.h" | 22 | #include "sway/tree/workspace.h" |
20 | 23 | ||
@@ -42,29 +45,12 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener, | |||
42 | ev->width, ev->height); | 45 | ev->width, ev->height); |
43 | } | 46 | } |
44 | 47 | ||
45 | static void unmanaged_handle_commit(struct wl_listener *listener, void *data) { | ||
46 | struct sway_xwayland_unmanaged *surface = | ||
47 | wl_container_of(listener, surface, commit); | ||
48 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | ||
49 | |||
50 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, | ||
51 | false); | ||
52 | } | ||
53 | |||
54 | static void unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) { | 48 | static void unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) { |
55 | struct sway_xwayland_unmanaged *surface = | 49 | struct sway_xwayland_unmanaged *surface = |
56 | wl_container_of(listener, surface, set_geometry); | 50 | wl_container_of(listener, surface, set_geometry); |
57 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 51 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
58 | 52 | ||
59 | if (xsurface->x != surface->lx || xsurface->y != surface->ly) { | 53 | wlr_scene_node_set_position(&surface->surface_scene->buffer->node, xsurface->x, xsurface->y); |
60 | // Surface has moved | ||
61 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, | ||
62 | true); | ||
63 | surface->lx = xsurface->x; | ||
64 | surface->ly = xsurface->y; | ||
65 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, | ||
66 | true); | ||
67 | } | ||
68 | } | 54 | } |
69 | 55 | ||
70 | static void unmanaged_handle_map(struct wl_listener *listener, void *data) { | 56 | static void unmanaged_handle_map(struct wl_listener *listener, void *data) { |
@@ -72,17 +58,18 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { | |||
72 | wl_container_of(listener, surface, map); | 58 | wl_container_of(listener, surface, map); |
73 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 59 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
74 | 60 | ||
75 | wl_list_insert(root->xwayland_unmanaged.prev, &surface->link); | 61 | surface->surface_scene = wlr_scene_surface_create(root->layers.unmanaged, |
76 | 62 | xsurface->surface); | |
77 | wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry); | ||
78 | surface->set_geometry.notify = unmanaged_handle_set_geometry; | ||
79 | 63 | ||
80 | wl_signal_add(&xsurface->surface->events.commit, &surface->commit); | 64 | if (surface->surface_scene) { |
81 | surface->commit.notify = unmanaged_handle_commit; | 65 | scene_descriptor_assign(&surface->surface_scene->buffer->node, |
66 | SWAY_SCENE_DESC_XWAYLAND_UNMANAGED, surface); | ||
67 | wlr_scene_node_set_position(&surface->surface_scene->buffer->node, | ||
68 | xsurface->x, xsurface->y); | ||
82 | 69 | ||
83 | surface->lx = xsurface->x; | 70 | wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry); |
84 | surface->ly = xsurface->y; | 71 | surface->set_geometry.notify = unmanaged_handle_set_geometry; |
85 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); | 72 | } |
86 | 73 | ||
87 | if (wlr_xwayland_or_surface_wants_focus(xsurface)) { | 74 | if (wlr_xwayland_or_surface_wants_focus(xsurface)) { |
88 | struct sway_seat *seat = input_manager_current_seat(); | 75 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -96,10 +83,13 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
96 | struct sway_xwayland_unmanaged *surface = | 83 | struct sway_xwayland_unmanaged *surface = |
97 | wl_container_of(listener, surface, unmap); | 84 | wl_container_of(listener, surface, unmap); |
98 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 85 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
99 | desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true); | 86 | |
100 | wl_list_remove(&surface->link); | 87 | if (surface->surface_scene) { |
101 | wl_list_remove(&surface->set_geometry.link); | 88 | wl_list_remove(&surface->set_geometry.link); |
102 | wl_list_remove(&surface->commit.link); | 89 | |
90 | wlr_scene_node_destroy(&surface->surface_scene->buffer->node); | ||
91 | surface->surface_scene = NULL; | ||
92 | } | ||
103 | 93 | ||
104 | struct sway_seat *seat = input_manager_current_seat(); | 94 | struct sway_seat *seat = input_manager_current_seat(); |
105 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { | 95 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { |
@@ -121,18 +111,53 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
121 | } | 111 | } |
122 | } | 112 | } |
123 | 113 | ||
114 | static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { | ||
115 | struct sway_xwayland_unmanaged *surface = | ||
116 | wl_container_of(listener, surface, request_activate); | ||
117 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | ||
118 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { | ||
119 | return; | ||
120 | } | ||
121 | struct sway_seat *seat = input_manager_current_seat(); | ||
122 | struct sway_container *focus = seat_get_focused_container(seat); | ||
123 | if (focus && focus->view && focus->view->pid != xsurface->pid) { | ||
124 | return; | ||
125 | } | ||
126 | |||
127 | seat_set_focus_surface(seat, xsurface->surface, false); | ||
128 | } | ||
129 | |||
130 | static void unmanaged_handle_associate(struct wl_listener *listener, void *data) { | ||
131 | struct sway_xwayland_unmanaged *surface = | ||
132 | wl_container_of(listener, surface, associate); | ||
133 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | ||
134 | wl_signal_add(&xsurface->surface->events.map, &surface->map); | ||
135 | surface->map.notify = unmanaged_handle_map; | ||
136 | wl_signal_add(&xsurface->surface->events.unmap, &surface->unmap); | ||
137 | surface->unmap.notify = unmanaged_handle_unmap; | ||
138 | } | ||
139 | |||
140 | static void unmanaged_handle_dissociate(struct wl_listener *listener, void *data) { | ||
141 | struct sway_xwayland_unmanaged *surface = | ||
142 | wl_container_of(listener, surface, dissociate); | ||
143 | wl_list_remove(&surface->map.link); | ||
144 | wl_list_remove(&surface->unmap.link); | ||
145 | } | ||
146 | |||
124 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { | 147 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { |
125 | struct sway_xwayland_unmanaged *surface = | 148 | struct sway_xwayland_unmanaged *surface = |
126 | wl_container_of(listener, surface, destroy); | 149 | wl_container_of(listener, surface, destroy); |
127 | wl_list_remove(&surface->request_configure.link); | 150 | wl_list_remove(&surface->request_configure.link); |
128 | wl_list_remove(&surface->map.link); | 151 | wl_list_remove(&surface->associate.link); |
129 | wl_list_remove(&surface->unmap.link); | 152 | wl_list_remove(&surface->dissociate.link); |
130 | wl_list_remove(&surface->destroy.link); | 153 | wl_list_remove(&surface->destroy.link); |
131 | wl_list_remove(&surface->override_redirect.link); | 154 | wl_list_remove(&surface->override_redirect.link); |
155 | wl_list_remove(&surface->request_activate.link); | ||
132 | free(surface); | 156 | free(surface); |
133 | } | 157 | } |
134 | 158 | ||
135 | static void handle_map(struct wl_listener *listener, void *data); | 159 | static void handle_map(struct wl_listener *listener, void *data); |
160 | static void handle_associate(struct wl_listener *listener, void *data); | ||
136 | 161 | ||
137 | struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsurface); | 162 | struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsurface); |
138 | 163 | ||
@@ -141,14 +166,22 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi | |||
141 | wl_container_of(listener, surface, override_redirect); | 166 | wl_container_of(listener, surface, override_redirect); |
142 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 167 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
143 | 168 | ||
144 | bool mapped = xsurface->mapped; | 169 | bool associated = xsurface->surface != NULL; |
170 | bool mapped = associated && xsurface->surface->mapped; | ||
145 | if (mapped) { | 171 | if (mapped) { |
146 | unmanaged_handle_unmap(&surface->unmap, NULL); | 172 | unmanaged_handle_unmap(&surface->unmap, NULL); |
147 | } | 173 | } |
174 | if (associated) { | ||
175 | unmanaged_handle_dissociate(&surface->dissociate, NULL); | ||
176 | } | ||
148 | 177 | ||
149 | unmanaged_handle_destroy(&surface->destroy, NULL); | 178 | unmanaged_handle_destroy(&surface->destroy, NULL); |
150 | xsurface->data = NULL; | 179 | xsurface->data = NULL; |
180 | |||
151 | struct sway_xwayland_view *xwayland_view = create_xwayland_view(xsurface); | 181 | struct sway_xwayland_view *xwayland_view = create_xwayland_view(xsurface); |
182 | if (associated) { | ||
183 | handle_associate(&xwayland_view->associate, NULL); | ||
184 | } | ||
152 | if (mapped) { | 185 | if (mapped) { |
153 | handle_map(&xwayland_view->map, xsurface); | 186 | handle_map(&xwayland_view->map, xsurface); |
154 | } | 187 | } |
@@ -168,14 +201,16 @@ static struct sway_xwayland_unmanaged *create_unmanaged( | |||
168 | wl_signal_add(&xsurface->events.request_configure, | 201 | wl_signal_add(&xsurface->events.request_configure, |
169 | &surface->request_configure); | 202 | &surface->request_configure); |
170 | surface->request_configure.notify = unmanaged_handle_request_configure; | 203 | surface->request_configure.notify = unmanaged_handle_request_configure; |
171 | wl_signal_add(&xsurface->events.map, &surface->map); | 204 | wl_signal_add(&xsurface->events.associate, &surface->associate); |
172 | surface->map.notify = unmanaged_handle_map; | 205 | surface->associate.notify = unmanaged_handle_associate; |
173 | wl_signal_add(&xsurface->events.unmap, &surface->unmap); | 206 | wl_signal_add(&xsurface->events.dissociate, &surface->dissociate); |
174 | surface->unmap.notify = unmanaged_handle_unmap; | 207 | surface->dissociate.notify = unmanaged_handle_dissociate; |
175 | wl_signal_add(&xsurface->events.destroy, &surface->destroy); | 208 | wl_signal_add(&xsurface->events.destroy, &surface->destroy); |
176 | surface->destroy.notify = unmanaged_handle_destroy; | 209 | surface->destroy.notify = unmanaged_handle_destroy; |
177 | wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); | 210 | wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); |
178 | surface->override_redirect.notify = unmanaged_handle_override_redirect; | 211 | surface->override_redirect.notify = unmanaged_handle_override_redirect; |
212 | wl_signal_add(&xsurface->events.request_activate, &surface->request_activate); | ||
213 | surface->request_activate.notify = unmanaged_handle_request_activate; | ||
179 | 214 | ||
180 | return surface; | 215 | return surface; |
181 | } | 216 | } |
@@ -254,6 +289,7 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
254 | } | 289 | } |
255 | 290 | ||
256 | wlr_xwayland_surface_activate(surface, activated); | 291 | wlr_xwayland_surface_activate(surface, activated); |
292 | wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE); | ||
257 | } | 293 | } |
258 | 294 | ||
259 | static void set_tiled(struct sway_view *view, bool tiled) { | 295 | static void set_tiled(struct sway_view *view, bool tiled) { |
@@ -293,7 +329,7 @@ static bool wants_floating(struct sway_view *view) { | |||
293 | } | 329 | } |
294 | } | 330 | } |
295 | 331 | ||
296 | struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; | 332 | xcb_size_hints_t *size_hints = surface->size_hints; |
297 | if (size_hints != NULL && | 333 | if (size_hints != NULL && |
298 | size_hints->min_width > 0 && size_hints->min_height > 0 && | 334 | size_hints->min_width > 0 && size_hints->min_height > 0 && |
299 | (size_hints->max_width == size_hints->min_width || | 335 | (size_hints->max_width == size_hints->min_width || |
@@ -347,7 +383,7 @@ static void destroy(struct sway_view *view) { | |||
347 | static void get_constraints(struct sway_view *view, double *min_width, | 383 | static void get_constraints(struct sway_view *view, double *min_width, |
348 | double *max_width, double *min_height, double *max_height) { | 384 | double *max_width, double *min_height, double *max_height) { |
349 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; | 385 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; |
350 | struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; | 386 | xcb_size_hints_t *size_hints = surface->size_hints; |
351 | 387 | ||
352 | if (size_hints == NULL) { | 388 | if (size_hints == NULL) { |
353 | *min_width = DBL_MIN; | 389 | *min_width = DBL_MIN; |
@@ -377,17 +413,6 @@ static const struct sway_view_impl view_impl = { | |||
377 | .destroy = destroy, | 413 | .destroy = destroy, |
378 | }; | 414 | }; |
379 | 415 | ||
380 | static void get_geometry(struct sway_view *view, struct wlr_box *box) { | ||
381 | box->x = box->y = 0; | ||
382 | if (view->surface) { | ||
383 | box->width = view->surface->current.width; | ||
384 | box->height = view->surface->current.height; | ||
385 | } else { | ||
386 | box->width = 0; | ||
387 | box->height = 0; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | static void handle_commit(struct wl_listener *listener, void *data) { | 416 | static void handle_commit(struct wl_listener *listener, void *data) { |
392 | struct sway_xwayland_view *xwayland_view = | 417 | struct sway_xwayland_view *xwayland_view = |
393 | wl_container_of(listener, xwayland_view, commit); | 418 | wl_container_of(listener, xwayland_view, commit); |
@@ -395,34 +420,38 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
395 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 420 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
396 | struct wlr_surface_state *state = &xsurface->surface->current; | 421 | struct wlr_surface_state *state = &xsurface->surface->current; |
397 | 422 | ||
398 | struct wlr_box new_geo; | 423 | struct wlr_box new_geo = {0}; |
399 | get_geometry(view, &new_geo); | 424 | new_geo.width = state->width; |
425 | new_geo.height = state->height; | ||
426 | |||
400 | bool new_size = new_geo.width != view->geometry.width || | 427 | bool new_size = new_geo.width != view->geometry.width || |
401 | new_geo.height != view->geometry.height || | 428 | new_geo.height != view->geometry.height; |
402 | new_geo.x != view->geometry.x || | ||
403 | new_geo.y != view->geometry.y; | ||
404 | 429 | ||
405 | if (new_size) { | 430 | if (new_size) { |
406 | // The client changed its surface size in this commit. For floating | 431 | // The client changed its surface size in this commit. For floating |
407 | // containers, we resize the container to match. For tiling containers, | 432 | // containers, we resize the container to match. For tiling containers, |
408 | // we only recenter the surface. | 433 | // we only recenter the surface. |
409 | desktop_damage_view(view); | ||
410 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | 434 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); |
411 | if (container_is_floating(view->container)) { | 435 | if (container_is_floating(view->container)) { |
412 | view_update_size(view); | 436 | view_update_size(view); |
413 | transaction_commit_dirty_client(); | 437 | transaction_commit_dirty_client(); |
414 | } else { | ||
415 | view_center_surface(view); | ||
416 | } | 438 | } |
417 | desktop_damage_view(view); | 439 | |
440 | view_center_and_clip_surface(view); | ||
418 | } | 441 | } |
419 | 442 | ||
420 | if (view->container->node.instruction) { | 443 | if (view->container->node.instruction) { |
421 | transaction_notify_view_ready_by_geometry(view, | 444 | bool successful = transaction_notify_view_ready_by_geometry(view, |
422 | xsurface->x, xsurface->y, state->width, state->height); | 445 | xsurface->x, xsurface->y, state->width, state->height); |
423 | } | ||
424 | 446 | ||
425 | view_damage_from(view); | 447 | // If we saved the view and this commit isn't what we're looking for |
448 | // that means the user will never actually see the buffers submitted to | ||
449 | // us here. Just send frame done events to these surfaces so they can | ||
450 | // commit another time for us. | ||
451 | if (view->saved_surface_tree && !successful) { | ||
452 | view_send_frame_done(view); | ||
453 | } | ||
454 | } | ||
426 | } | 455 | } |
427 | 456 | ||
428 | static void handle_destroy(struct wl_listener *listener, void *data) { | 457 | static void handle_destroy(struct wl_listener *listener, void *data) { |
@@ -435,6 +464,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
435 | wl_list_remove(&xwayland_view->commit.link); | 464 | wl_list_remove(&xwayland_view->commit.link); |
436 | } | 465 | } |
437 | 466 | ||
467 | xwayland_view->view.wlr_xwayland_surface = NULL; | ||
468 | |||
438 | wl_list_remove(&xwayland_view->destroy.link); | 469 | wl_list_remove(&xwayland_view->destroy.link); |
439 | wl_list_remove(&xwayland_view->request_configure.link); | 470 | wl_list_remove(&xwayland_view->request_configure.link); |
440 | wl_list_remove(&xwayland_view->request_fullscreen.link); | 471 | wl_list_remove(&xwayland_view->request_fullscreen.link); |
@@ -445,11 +476,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
445 | wl_list_remove(&xwayland_view->set_title.link); | 476 | wl_list_remove(&xwayland_view->set_title.link); |
446 | wl_list_remove(&xwayland_view->set_class.link); | 477 | wl_list_remove(&xwayland_view->set_class.link); |
447 | wl_list_remove(&xwayland_view->set_role.link); | 478 | wl_list_remove(&xwayland_view->set_role.link); |
479 | wl_list_remove(&xwayland_view->set_startup_id.link); | ||
448 | wl_list_remove(&xwayland_view->set_window_type.link); | 480 | wl_list_remove(&xwayland_view->set_window_type.link); |
449 | wl_list_remove(&xwayland_view->set_hints.link); | 481 | wl_list_remove(&xwayland_view->set_hints.link); |
450 | wl_list_remove(&xwayland_view->set_decorations.link); | 482 | wl_list_remove(&xwayland_view->set_decorations.link); |
451 | wl_list_remove(&xwayland_view->map.link); | 483 | wl_list_remove(&xwayland_view->associate.link); |
452 | wl_list_remove(&xwayland_view->unmap.link); | 484 | wl_list_remove(&xwayland_view->dissociate.link); |
453 | wl_list_remove(&xwayland_view->override_redirect.link); | 485 | wl_list_remove(&xwayland_view->override_redirect.link); |
454 | view_begin_destroy(&xwayland_view->view); | 486 | view_begin_destroy(&xwayland_view->view); |
455 | } | 487 | } |
@@ -463,16 +495,28 @@ static void handle_unmap(struct wl_listener *listener, void *data) { | |||
463 | return; | 495 | return; |
464 | } | 496 | } |
465 | 497 | ||
498 | wl_list_remove(&xwayland_view->commit.link); | ||
499 | wl_list_remove(&xwayland_view->surface_tree_destroy.link); | ||
500 | |||
501 | if (xwayland_view->surface_tree) { | ||
502 | wlr_scene_node_destroy(&xwayland_view->surface_tree->node); | ||
503 | xwayland_view->surface_tree = NULL; | ||
504 | } | ||
505 | |||
466 | view_unmap(view); | 506 | view_unmap(view); |
507 | } | ||
467 | 508 | ||
468 | wl_list_remove(&xwayland_view->commit.link); | 509 | static void handle_surface_tree_destroy(struct wl_listener *listener, void *data) { |
510 | struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, | ||
511 | surface_tree_destroy); | ||
512 | xwayland_view->surface_tree = NULL; | ||
469 | } | 513 | } |
470 | 514 | ||
471 | static void handle_map(struct wl_listener *listener, void *data) { | 515 | static void handle_map(struct wl_listener *listener, void *data) { |
472 | struct sway_xwayland_view *xwayland_view = | 516 | struct sway_xwayland_view *xwayland_view = |
473 | wl_container_of(listener, xwayland_view, map); | 517 | wl_container_of(listener, xwayland_view, map); |
474 | struct wlr_xwayland_surface *xsurface = data; | ||
475 | struct sway_view *view = &xwayland_view->view; | 518 | struct sway_view *view = &xwayland_view->view; |
519 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
476 | 520 | ||
477 | view->natural_width = xsurface->width; | 521 | view->natural_width = xsurface->width; |
478 | view->natural_height = xsurface->height; | 522 | view->natural_height = xsurface->height; |
@@ -485,23 +529,42 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
485 | // Put it back into the tree | 529 | // Put it back into the tree |
486 | view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false); | 530 | view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false); |
487 | 531 | ||
532 | xwayland_view->surface_tree = wlr_scene_subsurface_tree_create( | ||
533 | xwayland_view->view.content_tree, xsurface->surface); | ||
534 | |||
535 | if (xwayland_view->surface_tree) { | ||
536 | xwayland_view->surface_tree_destroy.notify = handle_surface_tree_destroy; | ||
537 | wl_signal_add(&xwayland_view->surface_tree->node.events.destroy, | ||
538 | &xwayland_view->surface_tree_destroy); | ||
539 | } | ||
540 | |||
488 | transaction_commit_dirty(); | 541 | transaction_commit_dirty(); |
489 | } | 542 | } |
490 | 543 | ||
544 | static void handle_dissociate(struct wl_listener *listener, void *data); | ||
545 | |||
491 | static void handle_override_redirect(struct wl_listener *listener, void *data) { | 546 | static void handle_override_redirect(struct wl_listener *listener, void *data) { |
492 | struct sway_xwayland_view *xwayland_view = | 547 | struct sway_xwayland_view *xwayland_view = |
493 | wl_container_of(listener, xwayland_view, override_redirect); | 548 | wl_container_of(listener, xwayland_view, override_redirect); |
494 | struct wlr_xwayland_surface *xsurface = data; | ||
495 | struct sway_view *view = &xwayland_view->view; | 549 | struct sway_view *view = &xwayland_view->view; |
550 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
496 | 551 | ||
497 | bool mapped = xsurface->mapped; | 552 | bool associated = xsurface->surface != NULL; |
553 | bool mapped = associated && xsurface->surface->mapped; | ||
498 | if (mapped) { | 554 | if (mapped) { |
499 | handle_unmap(&xwayland_view->unmap, NULL); | 555 | handle_unmap(&xwayland_view->unmap, NULL); |
500 | } | 556 | } |
557 | if (associated) { | ||
558 | handle_dissociate(&xwayland_view->dissociate, NULL); | ||
559 | } | ||
501 | 560 | ||
502 | handle_destroy(&xwayland_view->destroy, view); | 561 | handle_destroy(&xwayland_view->destroy, view); |
503 | xsurface->data = NULL; | 562 | xsurface->data = NULL; |
563 | |||
504 | struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface); | 564 | struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface); |
565 | if (associated) { | ||
566 | unmanaged_handle_associate(&unmanaged->associate, NULL); | ||
567 | } | ||
505 | if (mapped) { | 568 | if (mapped) { |
506 | unmanaged_handle_map(&unmanaged->map, xsurface); | 569 | unmanaged_handle_map(&unmanaged->map, xsurface); |
507 | } | 570 | } |
@@ -513,7 +576,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { | |||
513 | struct wlr_xwayland_surface_configure_event *ev = data; | 576 | struct wlr_xwayland_surface_configure_event *ev = data; |
514 | struct sway_view *view = &xwayland_view->view; | 577 | struct sway_view *view = &xwayland_view->view; |
515 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 578 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
516 | if (!xsurface->mapped) { | 579 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
517 | wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, | 580 | wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, |
518 | ev->width, ev->height); | 581 | ev->width, ev->height); |
519 | return; | 582 | return; |
@@ -542,7 +605,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
542 | wl_container_of(listener, xwayland_view, request_fullscreen); | 605 | wl_container_of(listener, xwayland_view, request_fullscreen); |
543 | struct sway_view *view = &xwayland_view->view; | 606 | struct sway_view *view = &xwayland_view->view; |
544 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 607 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
545 | if (!xsurface->mapped) { | 608 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
546 | return; | 609 | return; |
547 | } | 610 | } |
548 | container_set_fullscreen(view->container, xsurface->fullscreen); | 611 | container_set_fullscreen(view->container, xsurface->fullscreen); |
@@ -556,7 +619,7 @@ static void handle_request_minimize(struct wl_listener *listener, void *data) { | |||
556 | wl_container_of(listener, xwayland_view, request_minimize); | 619 | wl_container_of(listener, xwayland_view, request_minimize); |
557 | struct sway_view *view = &xwayland_view->view; | 620 | struct sway_view *view = &xwayland_view->view; |
558 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 621 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
559 | if (!xsurface->mapped) { | 622 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
560 | return; | 623 | return; |
561 | } | 624 | } |
562 | 625 | ||
@@ -571,10 +634,11 @@ static void handle_request_move(struct wl_listener *listener, void *data) { | |||
571 | wl_container_of(listener, xwayland_view, request_move); | 634 | wl_container_of(listener, xwayland_view, request_move); |
572 | struct sway_view *view = &xwayland_view->view; | 635 | struct sway_view *view = &xwayland_view->view; |
573 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 636 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
574 | if (!xsurface->mapped) { | 637 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
575 | return; | 638 | return; |
576 | } | 639 | } |
577 | if (!container_is_floating(view->container)) { | 640 | if (!container_is_floating(view->container) || |
641 | view->container->pending.fullscreen_mode) { | ||
578 | return; | 642 | return; |
579 | } | 643 | } |
580 | struct sway_seat *seat = input_manager_current_seat(); | 644 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -586,7 +650,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { | |||
586 | wl_container_of(listener, xwayland_view, request_resize); | 650 | wl_container_of(listener, xwayland_view, request_resize); |
587 | struct sway_view *view = &xwayland_view->view; | 651 | struct sway_view *view = &xwayland_view->view; |
588 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 652 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
589 | if (!xsurface->mapped) { | 653 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
590 | return; | 654 | return; |
591 | } | 655 | } |
592 | if (!container_is_floating(view->container)) { | 656 | if (!container_is_floating(view->container)) { |
@@ -602,10 +666,10 @@ static void handle_request_activate(struct wl_listener *listener, void *data) { | |||
602 | wl_container_of(listener, xwayland_view, request_activate); | 666 | wl_container_of(listener, xwayland_view, request_activate); |
603 | struct sway_view *view = &xwayland_view->view; | 667 | struct sway_view *view = &xwayland_view->view; |
604 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 668 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
605 | if (!xsurface->mapped) { | 669 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
606 | return; | 670 | return; |
607 | } | 671 | } |
608 | view_request_activate(view); | 672 | view_request_activate(view, NULL); |
609 | 673 | ||
610 | transaction_commit_dirty(); | 674 | transaction_commit_dirty(); |
611 | } | 675 | } |
@@ -615,7 +679,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) { | |||
615 | wl_container_of(listener, xwayland_view, set_title); | 679 | wl_container_of(listener, xwayland_view, set_title); |
616 | struct sway_view *view = &xwayland_view->view; | 680 | struct sway_view *view = &xwayland_view->view; |
617 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 681 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
618 | if (!xsurface->mapped) { | 682 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
619 | return; | 683 | return; |
620 | } | 684 | } |
621 | view_update_title(view, false); | 685 | view_update_title(view, false); |
@@ -627,7 +691,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) { | |||
627 | wl_container_of(listener, xwayland_view, set_class); | 691 | wl_container_of(listener, xwayland_view, set_class); |
628 | struct sway_view *view = &xwayland_view->view; | 692 | struct sway_view *view = &xwayland_view->view; |
629 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 693 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
630 | if (!xsurface->mapped) { | 694 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
631 | return; | 695 | return; |
632 | } | 696 | } |
633 | view_execute_criteria(view); | 697 | view_execute_criteria(view); |
@@ -638,18 +702,43 @@ static void handle_set_role(struct wl_listener *listener, void *data) { | |||
638 | wl_container_of(listener, xwayland_view, set_role); | 702 | wl_container_of(listener, xwayland_view, set_role); |
639 | struct sway_view *view = &xwayland_view->view; | 703 | struct sway_view *view = &xwayland_view->view; |
640 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 704 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
641 | if (!xsurface->mapped) { | 705 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
642 | return; | 706 | return; |
643 | } | 707 | } |
644 | view_execute_criteria(view); | 708 | view_execute_criteria(view); |
645 | } | 709 | } |
646 | 710 | ||
711 | static void handle_set_startup_id(struct wl_listener *listener, void *data) { | ||
712 | struct sway_xwayland_view *xwayland_view = | ||
713 | wl_container_of(listener, xwayland_view, set_startup_id); | ||
714 | struct sway_view *view = &xwayland_view->view; | ||
715 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
716 | if (xsurface->startup_id == NULL) { | ||
717 | return; | ||
718 | } | ||
719 | |||
720 | struct wlr_xdg_activation_token_v1 *token = | ||
721 | wlr_xdg_activation_v1_find_token( | ||
722 | server.xdg_activation_v1, xsurface->startup_id); | ||
723 | if (token == NULL) { | ||
724 | // Tried to activate with an unknown or expired token | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | struct launcher_ctx *ctx = token->data; | ||
729 | if (token->data == NULL) { | ||
730 | // TODO: support external launchers in X | ||
731 | return; | ||
732 | } | ||
733 | view_assign_ctx(view, ctx); | ||
734 | } | ||
735 | |||
647 | static void handle_set_window_type(struct wl_listener *listener, void *data) { | 736 | static void handle_set_window_type(struct wl_listener *listener, void *data) { |
648 | struct sway_xwayland_view *xwayland_view = | 737 | struct sway_xwayland_view *xwayland_view = |
649 | wl_container_of(listener, xwayland_view, set_window_type); | 738 | wl_container_of(listener, xwayland_view, set_window_type); |
650 | struct sway_view *view = &xwayland_view->view; | 739 | struct sway_view *view = &xwayland_view->view; |
651 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 740 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
652 | if (!xsurface->mapped) { | 741 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
653 | return; | 742 | return; |
654 | } | 743 | } |
655 | view_execute_criteria(view); | 744 | view_execute_criteria(view); |
@@ -660,20 +749,39 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { | |||
660 | wl_container_of(listener, xwayland_view, set_hints); | 749 | wl_container_of(listener, xwayland_view, set_hints); |
661 | struct sway_view *view = &xwayland_view->view; | 750 | struct sway_view *view = &xwayland_view->view; |
662 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 751 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
663 | if (!xsurface->mapped) { | 752 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
664 | return; | 753 | return; |
665 | } | 754 | } |
666 | if (!xsurface->hints_urgency && view->urgent_timer) { | 755 | const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); |
756 | if (!hints_urgency && view->urgent_timer) { | ||
667 | // The view is in the timeout period. We'll ignore the request to | 757 | // The view is in the timeout period. We'll ignore the request to |
668 | // unset urgency so that the view remains urgent until the timer clears | 758 | // unset urgency so that the view remains urgent until the timer clears |
669 | // it. | 759 | // it. |
670 | return; | 760 | return; |
671 | } | 761 | } |
672 | if (view->allow_request_urgent) { | 762 | if (view->allow_request_urgent) { |
673 | view_set_urgent(view, (bool)xsurface->hints_urgency); | 763 | view_set_urgent(view, hints_urgency); |
674 | } | 764 | } |
675 | } | 765 | } |
676 | 766 | ||
767 | static void handle_associate(struct wl_listener *listener, void *data) { | ||
768 | struct sway_xwayland_view *xwayland_view = | ||
769 | wl_container_of(listener, xwayland_view, associate); | ||
770 | struct wlr_xwayland_surface *xsurface = | ||
771 | xwayland_view->view.wlr_xwayland_surface; | ||
772 | wl_signal_add(&xsurface->surface->events.unmap, &xwayland_view->unmap); | ||
773 | xwayland_view->unmap.notify = handle_unmap; | ||
774 | wl_signal_add(&xsurface->surface->events.map, &xwayland_view->map); | ||
775 | xwayland_view->map.notify = handle_map; | ||
776 | } | ||
777 | |||
778 | static void handle_dissociate(struct wl_listener *listener, void *data) { | ||
779 | struct sway_xwayland_view *xwayland_view = | ||
780 | wl_container_of(listener, xwayland_view, dissociate); | ||
781 | wl_list_remove(&xwayland_view->map.link); | ||
782 | wl_list_remove(&xwayland_view->unmap.link); | ||
783 | } | ||
784 | |||
677 | struct sway_view *view_from_wlr_xwayland_surface( | 785 | struct sway_view *view_from_wlr_xwayland_surface( |
678 | struct wlr_xwayland_surface *xsurface) { | 786 | struct wlr_xwayland_surface *xsurface) { |
679 | return xsurface->data; | 787 | return xsurface->data; |
@@ -689,7 +797,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu | |||
689 | return NULL; | 797 | return NULL; |
690 | } | 798 | } |
691 | 799 | ||
692 | view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl); | 800 | if (!view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl)) { |
801 | free(xwayland_view); | ||
802 | return NULL; | ||
803 | } | ||
693 | xwayland_view->view.wlr_xwayland_surface = xsurface; | 804 | xwayland_view->view.wlr_xwayland_surface = xsurface; |
694 | 805 | ||
695 | wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); | 806 | wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); |
@@ -728,6 +839,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu | |||
728 | wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role); | 839 | wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role); |
729 | xwayland_view->set_role.notify = handle_set_role; | 840 | xwayland_view->set_role.notify = handle_set_role; |
730 | 841 | ||
842 | wl_signal_add(&xsurface->events.set_startup_id, | ||
843 | &xwayland_view->set_startup_id); | ||
844 | xwayland_view->set_startup_id.notify = handle_set_startup_id; | ||
845 | |||
731 | wl_signal_add(&xsurface->events.set_window_type, | 846 | wl_signal_add(&xsurface->events.set_window_type, |
732 | &xwayland_view->set_window_type); | 847 | &xwayland_view->set_window_type); |
733 | xwayland_view->set_window_type.notify = handle_set_window_type; | 848 | xwayland_view->set_window_type.notify = handle_set_window_type; |
@@ -739,11 +854,11 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu | |||
739 | &xwayland_view->set_decorations); | 854 | &xwayland_view->set_decorations); |
740 | xwayland_view->set_decorations.notify = handle_set_decorations; | 855 | xwayland_view->set_decorations.notify = handle_set_decorations; |
741 | 856 | ||
742 | wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); | 857 | wl_signal_add(&xsurface->events.associate, &xwayland_view->associate); |
743 | xwayland_view->unmap.notify = handle_unmap; | 858 | xwayland_view->associate.notify = handle_associate; |
744 | 859 | ||
745 | wl_signal_add(&xsurface->events.map, &xwayland_view->map); | 860 | wl_signal_add(&xsurface->events.dissociate, &xwayland_view->dissociate); |
746 | xwayland_view->map.notify = handle_map; | 861 | xwayland_view->dissociate.notify = handle_dissociate; |
747 | 862 | ||
748 | wl_signal_add(&xsurface->events.set_override_redirect, | 863 | wl_signal_add(&xsurface->events.set_override_redirect, |
749 | &xwayland_view->override_redirect); | 864 | &xwayland_view->override_redirect); |