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