diff options
Diffstat (limited to 'sway/desktop/xwayland.c')
-rw-r--r-- | sway/desktop/xwayland.c | 268 |
1 files changed, 180 insertions, 88 deletions
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 7c5dde53..270cf08f 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -1,21 +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> |
9 | #include <xcb/xcb_icccm.h> | 10 | #include <xcb/xcb_icccm.h> |
10 | #include "log.h" | 11 | #include "log.h" |
11 | #include "sway/desktop.h" | ||
12 | #include "sway/desktop/transaction.h" | 12 | #include "sway/desktop/transaction.h" |
13 | #include "sway/input/cursor.h" | 13 | #include "sway/input/cursor.h" |
14 | #include "sway/input/input-manager.h" | 14 | #include "sway/input/input-manager.h" |
15 | #include "sway/input/seat.h" | 15 | #include "sway/input/seat.h" |
16 | #include "sway/output.h" | 16 | #include "sway/output.h" |
17 | #include "sway/scene_descriptor.h" | ||
17 | #include "sway/tree/arrange.h" | 18 | #include "sway/tree/arrange.h" |
18 | #include "sway/tree/container.h" | 19 | #include "sway/tree/container.h" |
20 | #include "sway/server.h" | ||
19 | #include "sway/tree/view.h" | 21 | #include "sway/tree/view.h" |
20 | #include "sway/tree/workspace.h" | 22 | #include "sway/tree/workspace.h" |
21 | 23 | ||
@@ -43,29 +45,12 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener, | |||
43 | ev->width, ev->height); | 45 | ev->width, ev->height); |
44 | } | 46 | } |
45 | 47 | ||
46 | static void unmanaged_handle_commit(struct wl_listener *listener, void *data) { | ||
47 | struct sway_xwayland_unmanaged *surface = | ||
48 | wl_container_of(listener, surface, commit); | ||
49 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | ||
50 | |||
51 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, | ||
52 | false); | ||
53 | } | ||
54 | |||
55 | 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) { |
56 | struct sway_xwayland_unmanaged *surface = | 49 | struct sway_xwayland_unmanaged *surface = |
57 | wl_container_of(listener, surface, set_geometry); | 50 | wl_container_of(listener, surface, set_geometry); |
58 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 51 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
59 | 52 | ||
60 | if (xsurface->x != surface->lx || xsurface->y != surface->ly) { | 53 | wlr_scene_node_set_position(&surface->surface_scene->buffer->node, xsurface->x, xsurface->y); |
61 | // Surface has moved | ||
62 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, | ||
63 | true); | ||
64 | surface->lx = xsurface->x; | ||
65 | surface->ly = xsurface->y; | ||
66 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, | ||
67 | true); | ||
68 | } | ||
69 | } | 54 | } |
70 | 55 | ||
71 | static void unmanaged_handle_map(struct wl_listener *listener, void *data) { | 56 | static void unmanaged_handle_map(struct wl_listener *listener, void *data) { |
@@ -73,17 +58,18 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { | |||
73 | wl_container_of(listener, surface, map); | 58 | wl_container_of(listener, surface, map); |
74 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 59 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
75 | 60 | ||
76 | wl_list_insert(root->xwayland_unmanaged.prev, &surface->link); | 61 | surface->surface_scene = wlr_scene_surface_create(root->layers.unmanaged, |
62 | xsurface->surface); | ||
77 | 63 | ||
78 | wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry); | 64 | if (surface->surface_scene) { |
79 | surface->set_geometry.notify = unmanaged_handle_set_geometry; | 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); | ||
80 | 69 | ||
81 | wl_signal_add(&xsurface->surface->events.commit, &surface->commit); | 70 | wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry); |
82 | surface->commit.notify = unmanaged_handle_commit; | 71 | surface->set_geometry.notify = unmanaged_handle_set_geometry; |
83 | 72 | } | |
84 | surface->lx = xsurface->x; | ||
85 | surface->ly = xsurface->y; | ||
86 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); | ||
87 | 73 | ||
88 | if (wlr_xwayland_or_surface_wants_focus(xsurface)) { | 74 | if (wlr_xwayland_or_surface_wants_focus(xsurface)) { |
89 | struct sway_seat *seat = input_manager_current_seat(); | 75 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -97,10 +83,13 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
97 | struct sway_xwayland_unmanaged *surface = | 83 | struct sway_xwayland_unmanaged *surface = |
98 | wl_container_of(listener, surface, unmap); | 84 | wl_container_of(listener, surface, unmap); |
99 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 85 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
100 | desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true); | 86 | |
101 | wl_list_remove(&surface->link); | 87 | if (surface->surface_scene) { |
102 | wl_list_remove(&surface->set_geometry.link); | 88 | wl_list_remove(&surface->set_geometry.link); |
103 | wl_list_remove(&surface->commit.link); | 89 | |
90 | wlr_scene_node_destroy(&surface->surface_scene->buffer->node); | ||
91 | surface->surface_scene = NULL; | ||
92 | } | ||
104 | 93 | ||
105 | struct sway_seat *seat = input_manager_current_seat(); | 94 | struct sway_seat *seat = input_manager_current_seat(); |
106 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { | 95 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { |
@@ -123,8 +112,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
123 | } | 112 | } |
124 | 113 | ||
125 | static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { | 114 | static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { |
126 | struct wlr_xwayland_surface *xsurface = data; | 115 | struct sway_xwayland_unmanaged *surface = |
127 | if (!xsurface->mapped) { | 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) { | ||
128 | return; | 119 | return; |
129 | } | 120 | } |
130 | struct sway_seat *seat = input_manager_current_seat(); | 121 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -136,12 +127,29 @@ static void unmanaged_handle_request_activate(struct wl_listener *listener, void | |||
136 | seat_set_focus_surface(seat, xsurface->surface, false); | 127 | seat_set_focus_surface(seat, xsurface->surface, false); |
137 | } | 128 | } |
138 | 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 | |||
139 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { | 147 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { |
140 | struct sway_xwayland_unmanaged *surface = | 148 | struct sway_xwayland_unmanaged *surface = |
141 | wl_container_of(listener, surface, destroy); | 149 | wl_container_of(listener, surface, destroy); |
142 | wl_list_remove(&surface->request_configure.link); | 150 | wl_list_remove(&surface->request_configure.link); |
143 | wl_list_remove(&surface->map.link); | 151 | wl_list_remove(&surface->associate.link); |
144 | wl_list_remove(&surface->unmap.link); | 152 | wl_list_remove(&surface->dissociate.link); |
145 | wl_list_remove(&surface->destroy.link); | 153 | wl_list_remove(&surface->destroy.link); |
146 | wl_list_remove(&surface->override_redirect.link); | 154 | wl_list_remove(&surface->override_redirect.link); |
147 | wl_list_remove(&surface->request_activate.link); | 155 | wl_list_remove(&surface->request_activate.link); |
@@ -149,6 +157,7 @@ static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { | |||
149 | } | 157 | } |
150 | 158 | ||
151 | 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); | ||
152 | 161 | ||
153 | 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); |
154 | 163 | ||
@@ -157,14 +166,22 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi | |||
157 | wl_container_of(listener, surface, override_redirect); | 166 | wl_container_of(listener, surface, override_redirect); |
158 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 167 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
159 | 168 | ||
160 | bool mapped = xsurface->mapped; | 169 | bool associated = xsurface->surface != NULL; |
170 | bool mapped = associated && xsurface->surface->mapped; | ||
161 | if (mapped) { | 171 | if (mapped) { |
162 | unmanaged_handle_unmap(&surface->unmap, NULL); | 172 | unmanaged_handle_unmap(&surface->unmap, NULL); |
163 | } | 173 | } |
174 | if (associated) { | ||
175 | unmanaged_handle_dissociate(&surface->dissociate, NULL); | ||
176 | } | ||
164 | 177 | ||
165 | unmanaged_handle_destroy(&surface->destroy, NULL); | 178 | unmanaged_handle_destroy(&surface->destroy, NULL); |
166 | xsurface->data = NULL; | 179 | xsurface->data = NULL; |
180 | |||
167 | 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 | } | ||
168 | if (mapped) { | 185 | if (mapped) { |
169 | handle_map(&xwayland_view->map, xsurface); | 186 | handle_map(&xwayland_view->map, xsurface); |
170 | } | 187 | } |
@@ -184,10 +201,10 @@ static struct sway_xwayland_unmanaged *create_unmanaged( | |||
184 | wl_signal_add(&xsurface->events.request_configure, | 201 | wl_signal_add(&xsurface->events.request_configure, |
185 | &surface->request_configure); | 202 | &surface->request_configure); |
186 | surface->request_configure.notify = unmanaged_handle_request_configure; | 203 | surface->request_configure.notify = unmanaged_handle_request_configure; |
187 | wl_signal_add(&xsurface->events.map, &surface->map); | 204 | wl_signal_add(&xsurface->events.associate, &surface->associate); |
188 | surface->map.notify = unmanaged_handle_map; | 205 | surface->associate.notify = unmanaged_handle_associate; |
189 | wl_signal_add(&xsurface->events.unmap, &surface->unmap); | 206 | wl_signal_add(&xsurface->events.dissociate, &surface->dissociate); |
190 | surface->unmap.notify = unmanaged_handle_unmap; | 207 | surface->dissociate.notify = unmanaged_handle_dissociate; |
191 | wl_signal_add(&xsurface->events.destroy, &surface->destroy); | 208 | wl_signal_add(&xsurface->events.destroy, &surface->destroy); |
192 | surface->destroy.notify = unmanaged_handle_destroy; | 209 | surface->destroy.notify = unmanaged_handle_destroy; |
193 | wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); | 210 | wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); |
@@ -396,17 +413,6 @@ static const struct sway_view_impl view_impl = { | |||
396 | .destroy = destroy, | 413 | .destroy = destroy, |
397 | }; | 414 | }; |
398 | 415 | ||
399 | static void get_geometry(struct sway_view *view, struct wlr_box *box) { | ||
400 | box->x = box->y = 0; | ||
401 | if (view->surface) { | ||
402 | box->width = view->surface->current.width; | ||
403 | box->height = view->surface->current.height; | ||
404 | } else { | ||
405 | box->width = 0; | ||
406 | box->height = 0; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | static void handle_commit(struct wl_listener *listener, void *data) { | 416 | static void handle_commit(struct wl_listener *listener, void *data) { |
411 | struct sway_xwayland_view *xwayland_view = | 417 | struct sway_xwayland_view *xwayland_view = |
412 | wl_container_of(listener, xwayland_view, commit); | 418 | wl_container_of(listener, xwayland_view, commit); |
@@ -414,34 +420,38 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
414 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 420 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
415 | struct wlr_surface_state *state = &xsurface->surface->current; | 421 | struct wlr_surface_state *state = &xsurface->surface->current; |
416 | 422 | ||
417 | struct wlr_box new_geo; | 423 | struct wlr_box new_geo = {0}; |
418 | get_geometry(view, &new_geo); | 424 | new_geo.width = state->width; |
425 | new_geo.height = state->height; | ||
426 | |||
419 | bool new_size = new_geo.width != view->geometry.width || | 427 | bool new_size = new_geo.width != view->geometry.width || |
420 | new_geo.height != view->geometry.height || | 428 | new_geo.height != view->geometry.height; |
421 | new_geo.x != view->geometry.x || | ||
422 | new_geo.y != view->geometry.y; | ||
423 | 429 | ||
424 | if (new_size) { | 430 | if (new_size) { |
425 | // The client changed its surface size in this commit. For floating | 431 | // The client changed its surface size in this commit. For floating |
426 | // containers, we resize the container to match. For tiling containers, | 432 | // containers, we resize the container to match. For tiling containers, |
427 | // we only recenter the surface. | 433 | // we only recenter the surface. |
428 | desktop_damage_view(view); | ||
429 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | 434 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); |
430 | if (container_is_floating(view->container)) { | 435 | if (container_is_floating(view->container)) { |
431 | view_update_size(view); | 436 | view_update_size(view); |
432 | transaction_commit_dirty_client(); | 437 | transaction_commit_dirty_client(); |
433 | } else { | ||
434 | view_center_surface(view); | ||
435 | } | 438 | } |
436 | desktop_damage_view(view); | 439 | |
440 | view_center_and_clip_surface(view); | ||
437 | } | 441 | } |
438 | 442 | ||
439 | if (view->container->node.instruction) { | 443 | if (view->container->node.instruction) { |
440 | transaction_notify_view_ready_by_geometry(view, | 444 | bool successful = transaction_notify_view_ready_by_geometry(view, |
441 | xsurface->x, xsurface->y, state->width, state->height); | 445 | xsurface->x, xsurface->y, state->width, state->height); |
442 | } | ||
443 | 446 | ||
444 | 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 | } | ||
445 | } | 455 | } |
446 | 456 | ||
447 | static void handle_destroy(struct wl_listener *listener, void *data) { | 457 | static void handle_destroy(struct wl_listener *listener, void *data) { |
@@ -466,11 +476,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
466 | wl_list_remove(&xwayland_view->set_title.link); | 476 | wl_list_remove(&xwayland_view->set_title.link); |
467 | wl_list_remove(&xwayland_view->set_class.link); | 477 | wl_list_remove(&xwayland_view->set_class.link); |
468 | 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); | ||
469 | wl_list_remove(&xwayland_view->set_window_type.link); | 480 | wl_list_remove(&xwayland_view->set_window_type.link); |
470 | wl_list_remove(&xwayland_view->set_hints.link); | 481 | wl_list_remove(&xwayland_view->set_hints.link); |
471 | wl_list_remove(&xwayland_view->set_decorations.link); | 482 | wl_list_remove(&xwayland_view->set_decorations.link); |
472 | wl_list_remove(&xwayland_view->map.link); | 483 | wl_list_remove(&xwayland_view->associate.link); |
473 | wl_list_remove(&xwayland_view->unmap.link); | 484 | wl_list_remove(&xwayland_view->dissociate.link); |
474 | wl_list_remove(&xwayland_view->override_redirect.link); | 485 | wl_list_remove(&xwayland_view->override_redirect.link); |
475 | view_begin_destroy(&xwayland_view->view); | 486 | view_begin_destroy(&xwayland_view->view); |
476 | } | 487 | } |
@@ -484,16 +495,28 @@ static void handle_unmap(struct wl_listener *listener, void *data) { | |||
484 | return; | 495 | return; |
485 | } | 496 | } |
486 | 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 | |||
487 | view_unmap(view); | 506 | view_unmap(view); |
507 | } | ||
488 | 508 | ||
489 | 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; | ||
490 | } | 513 | } |
491 | 514 | ||
492 | static void handle_map(struct wl_listener *listener, void *data) { | 515 | static void handle_map(struct wl_listener *listener, void *data) { |
493 | struct sway_xwayland_view *xwayland_view = | 516 | struct sway_xwayland_view *xwayland_view = |
494 | wl_container_of(listener, xwayland_view, map); | 517 | wl_container_of(listener, xwayland_view, map); |
495 | struct wlr_xwayland_surface *xsurface = data; | ||
496 | 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; | ||
497 | 520 | ||
498 | view->natural_width = xsurface->width; | 521 | view->natural_width = xsurface->width; |
499 | view->natural_height = xsurface->height; | 522 | view->natural_height = xsurface->height; |
@@ -506,23 +529,42 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
506 | // Put it back into the tree | 529 | // Put it back into the tree |
507 | view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false); | 530 | view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false); |
508 | 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 | |||
509 | transaction_commit_dirty(); | 541 | transaction_commit_dirty(); |
510 | } | 542 | } |
511 | 543 | ||
544 | static void handle_dissociate(struct wl_listener *listener, void *data); | ||
545 | |||
512 | static void handle_override_redirect(struct wl_listener *listener, void *data) { | 546 | static void handle_override_redirect(struct wl_listener *listener, void *data) { |
513 | struct sway_xwayland_view *xwayland_view = | 547 | struct sway_xwayland_view *xwayland_view = |
514 | wl_container_of(listener, xwayland_view, override_redirect); | 548 | wl_container_of(listener, xwayland_view, override_redirect); |
515 | struct wlr_xwayland_surface *xsurface = data; | ||
516 | 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; | ||
517 | 551 | ||
518 | bool mapped = xsurface->mapped; | 552 | bool associated = xsurface->surface != NULL; |
553 | bool mapped = associated && xsurface->surface->mapped; | ||
519 | if (mapped) { | 554 | if (mapped) { |
520 | handle_unmap(&xwayland_view->unmap, NULL); | 555 | handle_unmap(&xwayland_view->unmap, NULL); |
521 | } | 556 | } |
557 | if (associated) { | ||
558 | handle_dissociate(&xwayland_view->dissociate, NULL); | ||
559 | } | ||
522 | 560 | ||
523 | handle_destroy(&xwayland_view->destroy, view); | 561 | handle_destroy(&xwayland_view->destroy, view); |
524 | xsurface->data = NULL; | 562 | xsurface->data = NULL; |
563 | |||
525 | 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 | } | ||
526 | if (mapped) { | 568 | if (mapped) { |
527 | unmanaged_handle_map(&unmanaged->map, xsurface); | 569 | unmanaged_handle_map(&unmanaged->map, xsurface); |
528 | } | 570 | } |
@@ -534,7 +576,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { | |||
534 | struct wlr_xwayland_surface_configure_event *ev = data; | 576 | struct wlr_xwayland_surface_configure_event *ev = data; |
535 | struct sway_view *view = &xwayland_view->view; | 577 | struct sway_view *view = &xwayland_view->view; |
536 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 578 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
537 | if (!xsurface->mapped) { | 579 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
538 | wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, | 580 | wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, |
539 | ev->width, ev->height); | 581 | ev->width, ev->height); |
540 | return; | 582 | return; |
@@ -563,7 +605,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
563 | wl_container_of(listener, xwayland_view, request_fullscreen); | 605 | wl_container_of(listener, xwayland_view, request_fullscreen); |
564 | struct sway_view *view = &xwayland_view->view; | 606 | struct sway_view *view = &xwayland_view->view; |
565 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 607 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
566 | if (!xsurface->mapped) { | 608 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
567 | return; | 609 | return; |
568 | } | 610 | } |
569 | container_set_fullscreen(view->container, xsurface->fullscreen); | 611 | container_set_fullscreen(view->container, xsurface->fullscreen); |
@@ -577,7 +619,7 @@ static void handle_request_minimize(struct wl_listener *listener, void *data) { | |||
577 | wl_container_of(listener, xwayland_view, request_minimize); | 619 | wl_container_of(listener, xwayland_view, request_minimize); |
578 | struct sway_view *view = &xwayland_view->view; | 620 | struct sway_view *view = &xwayland_view->view; |
579 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 621 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
580 | if (!xsurface->mapped) { | 622 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
581 | return; | 623 | return; |
582 | } | 624 | } |
583 | 625 | ||
@@ -592,7 +634,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { | |||
592 | wl_container_of(listener, xwayland_view, request_move); | 634 | wl_container_of(listener, xwayland_view, request_move); |
593 | struct sway_view *view = &xwayland_view->view; | 635 | struct sway_view *view = &xwayland_view->view; |
594 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 636 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
595 | if (!xsurface->mapped) { | 637 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
596 | return; | 638 | return; |
597 | } | 639 | } |
598 | if (!container_is_floating(view->container) || | 640 | if (!container_is_floating(view->container) || |
@@ -608,7 +650,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { | |||
608 | wl_container_of(listener, xwayland_view, request_resize); | 650 | wl_container_of(listener, xwayland_view, request_resize); |
609 | struct sway_view *view = &xwayland_view->view; | 651 | struct sway_view *view = &xwayland_view->view; |
610 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 652 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
611 | if (!xsurface->mapped) { | 653 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
612 | return; | 654 | return; |
613 | } | 655 | } |
614 | if (!container_is_floating(view->container)) { | 656 | if (!container_is_floating(view->container)) { |
@@ -624,10 +666,10 @@ static void handle_request_activate(struct wl_listener *listener, void *data) { | |||
624 | wl_container_of(listener, xwayland_view, request_activate); | 666 | wl_container_of(listener, xwayland_view, request_activate); |
625 | struct sway_view *view = &xwayland_view->view; | 667 | struct sway_view *view = &xwayland_view->view; |
626 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 668 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
627 | if (!xsurface->mapped) { | 669 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
628 | return; | 670 | return; |
629 | } | 671 | } |
630 | view_request_activate(view); | 672 | view_request_activate(view, NULL); |
631 | 673 | ||
632 | transaction_commit_dirty(); | 674 | transaction_commit_dirty(); |
633 | } | 675 | } |
@@ -637,7 +679,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) { | |||
637 | wl_container_of(listener, xwayland_view, set_title); | 679 | wl_container_of(listener, xwayland_view, set_title); |
638 | struct sway_view *view = &xwayland_view->view; | 680 | struct sway_view *view = &xwayland_view->view; |
639 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 681 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
640 | if (!xsurface->mapped) { | 682 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
641 | return; | 683 | return; |
642 | } | 684 | } |
643 | view_update_title(view, false); | 685 | view_update_title(view, false); |
@@ -649,7 +691,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) { | |||
649 | wl_container_of(listener, xwayland_view, set_class); | 691 | wl_container_of(listener, xwayland_view, set_class); |
650 | struct sway_view *view = &xwayland_view->view; | 692 | struct sway_view *view = &xwayland_view->view; |
651 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 693 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
652 | if (!xsurface->mapped) { | 694 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
653 | return; | 695 | return; |
654 | } | 696 | } |
655 | view_execute_criteria(view); | 697 | view_execute_criteria(view); |
@@ -660,18 +702,43 @@ static void handle_set_role(struct wl_listener *listener, void *data) { | |||
660 | wl_container_of(listener, xwayland_view, set_role); | 702 | wl_container_of(listener, xwayland_view, set_role); |
661 | struct sway_view *view = &xwayland_view->view; | 703 | struct sway_view *view = &xwayland_view->view; |
662 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 704 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
663 | if (!xsurface->mapped) { | 705 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
664 | return; | 706 | return; |
665 | } | 707 | } |
666 | view_execute_criteria(view); | 708 | view_execute_criteria(view); |
667 | } | 709 | } |
668 | 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 | |||
669 | 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) { |
670 | struct sway_xwayland_view *xwayland_view = | 737 | struct sway_xwayland_view *xwayland_view = |
671 | wl_container_of(listener, xwayland_view, set_window_type); | 738 | wl_container_of(listener, xwayland_view, set_window_type); |
672 | struct sway_view *view = &xwayland_view->view; | 739 | struct sway_view *view = &xwayland_view->view; |
673 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 740 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
674 | if (!xsurface->mapped) { | 741 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
675 | return; | 742 | return; |
676 | } | 743 | } |
677 | view_execute_criteria(view); | 744 | view_execute_criteria(view); |
@@ -682,7 +749,7 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { | |||
682 | wl_container_of(listener, xwayland_view, set_hints); | 749 | wl_container_of(listener, xwayland_view, set_hints); |
683 | struct sway_view *view = &xwayland_view->view; | 750 | struct sway_view *view = &xwayland_view->view; |
684 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 751 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
685 | if (!xsurface->mapped) { | 752 | if (xsurface->surface == NULL || !xsurface->surface->mapped) { |
686 | return; | 753 | return; |
687 | } | 754 | } |
688 | const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); | 755 | const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); |
@@ -697,6 +764,24 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { | |||
697 | } | 764 | } |
698 | } | 765 | } |
699 | 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 | |||
700 | struct sway_view *view_from_wlr_xwayland_surface( | 785 | struct sway_view *view_from_wlr_xwayland_surface( |
701 | struct wlr_xwayland_surface *xsurface) { | 786 | struct wlr_xwayland_surface *xsurface) { |
702 | return xsurface->data; | 787 | return xsurface->data; |
@@ -712,7 +797,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu | |||
712 | return NULL; | 797 | return NULL; |
713 | } | 798 | } |
714 | 799 | ||
715 | 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 | } | ||
716 | xwayland_view->view.wlr_xwayland_surface = xsurface; | 804 | xwayland_view->view.wlr_xwayland_surface = xsurface; |
717 | 805 | ||
718 | wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); | 806 | wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); |
@@ -751,6 +839,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu | |||
751 | wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role); | 839 | wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role); |
752 | xwayland_view->set_role.notify = handle_set_role; | 840 | xwayland_view->set_role.notify = handle_set_role; |
753 | 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 | |||
754 | wl_signal_add(&xsurface->events.set_window_type, | 846 | wl_signal_add(&xsurface->events.set_window_type, |
755 | &xwayland_view->set_window_type); | 847 | &xwayland_view->set_window_type); |
756 | xwayland_view->set_window_type.notify = handle_set_window_type; | 848 | xwayland_view->set_window_type.notify = handle_set_window_type; |
@@ -762,11 +854,11 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu | |||
762 | &xwayland_view->set_decorations); | 854 | &xwayland_view->set_decorations); |
763 | xwayland_view->set_decorations.notify = handle_set_decorations; | 855 | xwayland_view->set_decorations.notify = handle_set_decorations; |
764 | 856 | ||
765 | wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); | 857 | wl_signal_add(&xsurface->events.associate, &xwayland_view->associate); |
766 | xwayland_view->unmap.notify = handle_unmap; | 858 | xwayland_view->associate.notify = handle_associate; |
767 | 859 | ||
768 | wl_signal_add(&xsurface->events.map, &xwayland_view->map); | 860 | wl_signal_add(&xsurface->events.dissociate, &xwayland_view->dissociate); |
769 | xwayland_view->map.notify = handle_map; | 861 | xwayland_view->dissociate.notify = handle_dissociate; |
770 | 862 | ||
771 | wl_signal_add(&xsurface->events.set_override_redirect, | 863 | wl_signal_add(&xsurface->events.set_override_redirect, |
772 | &xwayland_view->override_redirect); | 864 | &xwayland_view->override_redirect); |