diff options
author | Alexander Orzechowski <alex@ozal.ski> | 2023-12-06 14:28:59 -0500 |
---|---|---|
committer | Kirill Primak <vyivel@eclair.cafe> | 2024-01-18 18:36:54 +0300 |
commit | b38ed8b4792928dca3e1580e8160792ea41e25c4 (patch) | |
tree | b080710c7a3f37de868ff4d5d96e6971f7105675 | |
parent | transaction: ready signals will return success bools (diff) | |
download | sway-b38ed8b4792928dca3e1580e8160792ea41e25c4.tar.gz sway-b38ed8b4792928dca3e1580e8160792ea41e25c4.tar.zst sway-b38ed8b4792928dca3e1580e8160792ea41e25c4.zip |
scene_graph: Port xdg_shell
-rw-r--r-- | include/sway/scene_descriptor.h | 1 | ||||
-rw-r--r-- | include/sway/tree/view.h | 46 | ||||
-rw-r--r-- | sway/desktop/output.c | 8 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 113 | ||||
-rw-r--r-- | sway/input/cursor.c | 13 | ||||
-rw-r--r-- | sway/tree/view.c | 272 |
6 files changed, 81 insertions, 372 deletions
diff --git a/include/sway/scene_descriptor.h b/include/sway/scene_descriptor.h index 970adaa5..43991f77 100644 --- a/include/sway/scene_descriptor.h +++ b/include/sway/scene_descriptor.h | |||
@@ -16,6 +16,7 @@ enum sway_scene_descriptor_type { | |||
16 | SWAY_SCENE_DESC_CONTAINER, | 16 | SWAY_SCENE_DESC_CONTAINER, |
17 | SWAY_SCENE_DESC_VIEW, | 17 | SWAY_SCENE_DESC_VIEW, |
18 | SWAY_SCENE_DESC_LAYER_SHELL, | 18 | SWAY_SCENE_DESC_LAYER_SHELL, |
19 | SWAY_SCENE_DESC_POPUP, | ||
19 | SWAY_SCENE_DESC_DRAG_ICON, | 20 | SWAY_SCENE_DESC_DRAG_ICON, |
20 | }; | 21 | }; |
21 | 22 | ||
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 4aaed9e3..467d912f 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -123,8 +123,6 @@ struct sway_view { | |||
123 | struct wl_signal unmap; | 123 | struct wl_signal unmap; |
124 | } events; | 124 | } events; |
125 | 125 | ||
126 | struct wl_listener surface_new_subsurface; | ||
127 | |||
128 | int max_render_time; // In milliseconds | 126 | int max_render_time; // In milliseconds |
129 | 127 | ||
130 | enum seat_config_shortcuts_inhibit shortcuts_inhibit; | 128 | enum seat_config_shortcuts_inhibit shortcuts_inhibit; |
@@ -191,43 +189,12 @@ struct sway_xwayland_unmanaged { | |||
191 | struct wl_listener override_redirect; | 189 | struct wl_listener override_redirect; |
192 | }; | 190 | }; |
193 | #endif | 191 | #endif |
194 | struct sway_view_child; | ||
195 | |||
196 | struct sway_view_child_impl { | ||
197 | void (*get_view_coords)(struct sway_view_child *child, int *sx, int *sy); | ||
198 | void (*destroy)(struct sway_view_child *child); | ||
199 | }; | ||
200 | |||
201 | /** | ||
202 | * A view child is a surface in the view tree, such as a subsurface or a popup. | ||
203 | */ | ||
204 | struct sway_view_child { | ||
205 | const struct sway_view_child_impl *impl; | ||
206 | struct wl_list link; | ||
207 | |||
208 | struct sway_view *view; | ||
209 | struct sway_view_child *parent; | ||
210 | struct wl_list children; // sway_view_child::link | ||
211 | struct wlr_surface *surface; | ||
212 | bool mapped; | ||
213 | |||
214 | struct wl_listener surface_commit; | ||
215 | struct wl_listener surface_new_subsurface; | ||
216 | struct wl_listener surface_map; | ||
217 | struct wl_listener surface_unmap; | ||
218 | struct wl_listener surface_destroy; | ||
219 | struct wl_listener view_unmap; | ||
220 | }; | ||
221 | |||
222 | struct sway_subsurface { | ||
223 | struct sway_view_child child; | ||
224 | |||
225 | struct wl_listener destroy; | ||
226 | }; | ||
227 | 192 | ||
228 | struct sway_xdg_popup { | 193 | struct sway_xdg_popup { |
229 | struct sway_view_child child; | 194 | struct sway_view *view; |
230 | 195 | ||
196 | struct wlr_scene_tree *scene_tree; | ||
197 | struct wlr_scene_tree *xdg_surface_tree; | ||
231 | struct wlr_xdg_popup *wlr_xdg_popup; | 198 | struct wlr_xdg_popup *wlr_xdg_popup; |
232 | 199 | ||
233 | struct wl_listener surface_commit; | 200 | struct wl_listener surface_commit; |
@@ -339,13 +306,6 @@ void view_unmap(struct sway_view *view); | |||
339 | void view_update_size(struct sway_view *view); | 306 | void view_update_size(struct sway_view *view); |
340 | void view_center_surface(struct sway_view *view); | 307 | void view_center_surface(struct sway_view *view); |
341 | 308 | ||
342 | void view_child_init(struct sway_view_child *child, | ||
343 | const struct sway_view_child_impl *impl, struct sway_view *view, | ||
344 | struct wlr_surface *surface); | ||
345 | |||
346 | void view_child_destroy(struct sway_view_child *child); | ||
347 | |||
348 | |||
349 | struct sway_view *view_from_wlr_xdg_surface( | 309 | struct sway_view *view_from_wlr_xdg_surface( |
350 | struct wlr_xdg_surface *xdg_surface); | 310 | struct wlr_xdg_surface *xdg_surface); |
351 | #if HAVE_XWAYLAND | 311 | #if HAVE_XWAYLAND |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 942bc780..a5184484 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -289,8 +289,14 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, | |||
289 | } | 289 | } |
290 | 290 | ||
291 | struct wlr_scene_node *current = &buffer->node; | 291 | struct wlr_scene_node *current = &buffer->node; |
292 | |||
293 | while (true) { | 292 | while (true) { |
293 | struct sway_view *view = scene_descriptor_try_get(current, | ||
294 | SWAY_SCENE_DESC_VIEW); | ||
295 | if (view) { | ||
296 | view_max_render_time = view->max_render_time; | ||
297 | break; | ||
298 | } | ||
299 | |||
294 | if (!current->parent) { | 300 | if (!current->parent) { |
295 | break; | 301 | break; |
296 | } | 302 | } |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 11c112be..fed820cf 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -7,7 +7,7 @@ | |||
7 | #include <wlr/util/edges.h> | 7 | #include <wlr/util/edges.h> |
8 | #include "log.h" | 8 | #include "log.h" |
9 | #include "sway/decoration.h" | 9 | #include "sway/decoration.h" |
10 | #include "sway/desktop.h" | 10 | #include "sway/scene_descriptor.h" |
11 | #include "sway/desktop/transaction.h" | 11 | #include "sway/desktop/transaction.h" |
12 | #include "sway/input/cursor.h" | 12 | #include "sway/input/cursor.h" |
13 | #include "sway/input/input-manager.h" | 13 | #include "sway/input/input-manager.h" |
@@ -19,41 +19,29 @@ | |||
19 | #include "sway/tree/workspace.h" | 19 | #include "sway/tree/workspace.h" |
20 | #include "sway/xdg_decoration.h" | 20 | #include "sway/xdg_decoration.h" |
21 | 21 | ||
22 | static const struct sway_view_child_impl popup_impl; | 22 | static struct sway_xdg_popup *popup_create( |
23 | 23 | struct wlr_xdg_popup *wlr_popup, struct sway_view *view, | |
24 | static void popup_get_view_coords(struct sway_view_child *child, | 24 | struct wlr_scene_tree *parent); |
25 | int *sx, int *sy) { | ||
26 | struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; | ||
27 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; | ||
28 | 25 | ||
29 | wlr_xdg_popup_get_toplevel_coords(wlr_popup, | 26 | static void popup_handle_new_popup(struct wl_listener *listener, void *data) { |
30 | wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x, | 27 | struct sway_xdg_popup *popup = |
31 | wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y, | 28 | wl_container_of(listener, popup, new_popup); |
32 | sx, sy); | 29 | struct wlr_xdg_popup *wlr_popup = data; |
30 | popup_create(wlr_popup, popup->view, popup->xdg_surface_tree); | ||
33 | } | 31 | } |
34 | 32 | ||
35 | static void popup_destroy(struct sway_view_child *child) { | 33 | static void popup_handle_destroy(struct wl_listener *listener, void *data) { |
36 | if (!sway_assert(child->impl == &popup_impl, | 34 | struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); |
37 | "Expected an xdg_shell popup")) { | 35 | |
38 | return; | ||
39 | } | ||
40 | struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; | ||
41 | wl_list_remove(&popup->surface_commit.link); | ||
42 | wl_list_remove(&popup->new_popup.link); | 36 | wl_list_remove(&popup->new_popup.link); |
43 | wl_list_remove(&popup->destroy.link); | 37 | wl_list_remove(&popup->destroy.link); |
38 | wl_list_remove(&popup->surface_commit.link); | ||
39 | wlr_scene_node_destroy(&popup->scene_tree->node); | ||
44 | free(popup); | 40 | free(popup); |
45 | } | 41 | } |
46 | 42 | ||
47 | static const struct sway_view_child_impl popup_impl = { | ||
48 | .get_view_coords = popup_get_view_coords, | ||
49 | .destroy = popup_destroy, | ||
50 | }; | ||
51 | |||
52 | static struct sway_xdg_popup *popup_create( | ||
53 | struct wlr_xdg_popup *wlr_popup, struct sway_view *view); | ||
54 | |||
55 | static void popup_unconstrain(struct sway_xdg_popup *popup) { | 43 | static void popup_unconstrain(struct sway_xdg_popup *popup) { |
56 | struct sway_view *view = popup->child.view; | 44 | struct sway_view *view = popup->view; |
57 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; | 45 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; |
58 | 46 | ||
59 | struct sway_workspace *workspace = view->container->pending.workspace; | 47 | struct sway_workspace *workspace = view->container->pending.workspace; |
@@ -83,29 +71,44 @@ static void popup_handle_surface_commit(struct wl_listener *listener, void *data | |||
83 | } | 71 | } |
84 | } | 72 | } |
85 | 73 | ||
86 | static void popup_handle_new_popup(struct wl_listener *listener, void *data) { | 74 | static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, |
87 | struct sway_xdg_popup *popup = | 75 | struct sway_view *view, struct wlr_scene_tree *parent) { |
88 | wl_container_of(listener, popup, new_popup); | ||
89 | struct wlr_xdg_popup *wlr_popup = data; | ||
90 | popup_create(wlr_popup, popup->child.view); | ||
91 | } | ||
92 | |||
93 | static void popup_handle_destroy(struct wl_listener *listener, void *data) { | ||
94 | struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); | ||
95 | view_child_destroy(&popup->child); | ||
96 | } | ||
97 | |||
98 | static struct sway_xdg_popup *popup_create( | ||
99 | struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { | ||
100 | struct wlr_xdg_surface *xdg_surface = wlr_popup->base; | 76 | struct wlr_xdg_surface *xdg_surface = wlr_popup->base; |
101 | 77 | ||
102 | struct sway_xdg_popup *popup = | 78 | struct sway_xdg_popup *popup = calloc(1, sizeof(struct sway_xdg_popup)); |
103 | calloc(1, sizeof(struct sway_xdg_popup)); | 79 | if (!popup) { |
104 | if (popup == NULL) { | ||
105 | return NULL; | 80 | return NULL; |
106 | } | 81 | } |
107 | view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); | 82 | |
108 | popup->wlr_xdg_popup = wlr_popup; | 83 | popup->wlr_xdg_popup = wlr_popup; |
84 | popup->view = view; | ||
85 | |||
86 | popup->scene_tree = wlr_scene_tree_create(parent); | ||
87 | if (!popup->scene_tree) { | ||
88 | free(popup); | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | popup->xdg_surface_tree = wlr_scene_xdg_surface_create( | ||
93 | popup->scene_tree, xdg_surface); | ||
94 | if (!popup->xdg_surface_tree) { | ||
95 | wlr_scene_node_destroy(&popup->scene_tree->node); | ||
96 | free(popup); | ||
97 | return NULL; | ||
98 | } | ||
99 | |||
100 | if (!scene_descriptor_assign(&popup->scene_tree->node, | ||
101 | SWAY_SCENE_DESC_POPUP, popup)) { | ||
102 | sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor"); | ||
103 | wlr_scene_node_destroy(&popup->scene_tree->node); | ||
104 | free(popup); | ||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | popup->wlr_xdg_popup = xdg_surface->popup; | ||
109 | struct sway_xdg_shell_view *shell_view = | ||
110 | wl_container_of(view, shell_view, view); | ||
111 | xdg_surface->data = shell_view; | ||
109 | 112 | ||
110 | wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit); | 113 | wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit); |
111 | popup->surface_commit.notify = popup_handle_surface_commit; | 114 | popup->surface_commit.notify = popup_handle_surface_commit; |
@@ -114,9 +117,6 @@ static struct sway_xdg_popup *popup_create( | |||
114 | wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); | 117 | wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); |
115 | popup->destroy.notify = popup_handle_destroy; | 118 | popup->destroy.notify = popup_handle_destroy; |
116 | 119 | ||
117 | wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); | ||
118 | wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); | ||
119 | |||
120 | return popup; | 120 | return popup; |
121 | } | 121 | } |
122 | 122 | ||
@@ -317,7 +317,6 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
317 | // The client changed its surface size in this commit. For floating | 317 | // The client changed its surface size in this commit. For floating |
318 | // containers, we resize the container to match. For tiling containers, | 318 | // containers, we resize the container to match. For tiling containers, |
319 | // we only recenter the surface. | 319 | // we only recenter the surface. |
320 | desktop_damage_view(view); | ||
321 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | 320 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); |
322 | if (container_is_floating(view->container)) { | 321 | if (container_is_floating(view->container)) { |
323 | view_update_size(view); | 322 | view_update_size(view); |
@@ -330,15 +329,12 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
330 | } else { | 329 | } else { |
331 | view_center_surface(view); | 330 | view_center_surface(view); |
332 | } | 331 | } |
333 | desktop_damage_view(view); | ||
334 | } | 332 | } |
335 | 333 | ||
336 | if (view->container->node.instruction) { | 334 | if (view->container->node.instruction) { |
337 | transaction_notify_view_ready_by_serial(view, | 335 | transaction_notify_view_ready_by_serial(view, |
338 | xdg_surface->current.configure_serial); | 336 | xdg_surface->current.configure_serial); |
339 | } | 337 | } |
340 | |||
341 | view_damage_from(view); | ||
342 | } | 338 | } |
343 | 339 | ||
344 | static void handle_set_title(struct wl_listener *listener, void *data) { | 340 | static void handle_set_title(struct wl_listener *listener, void *data) { |
@@ -360,7 +356,16 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { | |||
360 | struct sway_xdg_shell_view *xdg_shell_view = | 356 | struct sway_xdg_shell_view *xdg_shell_view = |
361 | wl_container_of(listener, xdg_shell_view, new_popup); | 357 | wl_container_of(listener, xdg_shell_view, new_popup); |
362 | struct wlr_xdg_popup *wlr_popup = data; | 358 | struct wlr_xdg_popup *wlr_popup = data; |
363 | popup_create(wlr_popup, &xdg_shell_view->view); | 359 | |
360 | struct sway_xdg_popup *popup = popup_create(wlr_popup, | ||
361 | &xdg_shell_view->view, root->layers.popup); | ||
362 | if (!popup) { | ||
363 | return; | ||
364 | } | ||
365 | |||
366 | int lx, ly; | ||
367 | wlr_scene_node_coords(&popup->view->content_tree->node, &lx, &ly); | ||
368 | wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly); | ||
364 | } | 369 | } |
365 | 370 | ||
366 | static void handle_request_maximize(struct wl_listener *listener, void *data) { | 371 | static void handle_request_maximize(struct wl_listener *listener, void *data) { |
@@ -567,5 +572,7 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { | |||
567 | xdg_shell_view->destroy.notify = handle_destroy; | 572 | xdg_shell_view->destroy.notify = handle_destroy; |
568 | wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy); | 573 | wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy); |
569 | 574 | ||
575 | wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); | ||
576 | |||
570 | xdg_toplevel->base->data = xdg_shell_view; | 577 | xdg_toplevel->base->data = xdg_shell_view; |
571 | } | 578 | } |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 30df76f4..fd8f50d4 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -80,6 +80,7 @@ struct sway_node *node_at_coords( | |||
80 | while (true) { | 80 | while (true) { |
81 | struct sway_container *con = scene_descriptor_try_get(current, | 81 | struct sway_container *con = scene_descriptor_try_get(current, |
82 | SWAY_SCENE_DESC_CONTAINER); | 82 | SWAY_SCENE_DESC_CONTAINER); |
83 | |||
83 | if (!con) { | 84 | if (!con) { |
84 | struct sway_view *view = scene_descriptor_try_get(current, | 85 | struct sway_view *view = scene_descriptor_try_get(current, |
85 | SWAY_SCENE_DESC_VIEW); | 86 | SWAY_SCENE_DESC_VIEW); |
@@ -88,12 +89,18 @@ struct sway_node *node_at_coords( | |||
88 | } | 89 | } |
89 | } | 90 | } |
90 | 91 | ||
91 | if (con) { | 92 | if (!con) { |
92 | if (!con->view || con->view->surface) { | 93 | struct sway_xdg_popup *popup = |
93 | return &con->node; | 94 | scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP); |
95 | if (popup) { | ||
96 | con = popup->view->container; | ||
94 | } | 97 | } |
95 | } | 98 | } |
96 | 99 | ||
100 | if (con && (!con->view || con->view->surface)) { | ||
101 | return &con->node; | ||
102 | } | ||
103 | |||
97 | if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) { | 104 | if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) { |
98 | // We don't want to feed through the current workspace on | 105 | // We don't want to feed through the current workspace on |
99 | // layer shells | 106 | // layer shells |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 7af2fd3f..ee25faf1 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -488,24 +488,6 @@ void view_for_each_popup_surface(struct sway_view *view, | |||
488 | view->impl->for_each_popup_surface(view, iterator, user_data); | 488 | view->impl->for_each_popup_surface(view, iterator, user_data); |
489 | } | 489 | } |
490 | } | 490 | } |
491 | |||
492 | static void view_subsurface_create(struct sway_view *view, | ||
493 | struct wlr_subsurface *subsurface); | ||
494 | |||
495 | static void view_init_subsurfaces(struct sway_view *view, | ||
496 | struct wlr_surface *surface); | ||
497 | |||
498 | static void view_child_init_subsurfaces(struct sway_view_child *view_child, | ||
499 | struct wlr_surface *surface); | ||
500 | |||
501 | static void view_handle_surface_new_subsurface(struct wl_listener *listener, | ||
502 | void *data) { | ||
503 | struct sway_view *view = | ||
504 | wl_container_of(listener, view, surface_new_subsurface); | ||
505 | struct wlr_subsurface *subsurface = data; | ||
506 | view_subsurface_create(view, subsurface); | ||
507 | } | ||
508 | |||
509 | static bool view_has_executed_criteria(struct sway_view *view, | 491 | static bool view_has_executed_criteria(struct sway_view *view, |
510 | struct criteria *criteria) { | 492 | struct criteria *criteria) { |
511 | for (int i = 0; i < view->executed_criteria->length; ++i) { | 493 | for (int i = 0; i < view->executed_criteria->length; ++i) { |
@@ -826,11 +808,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
826 | } | 808 | } |
827 | ipc_event_window(view->container, "new"); | 809 | ipc_event_window(view->container, "new"); |
828 | 810 | ||
829 | view_init_subsurfaces(view, wlr_surface); | ||
830 | wl_signal_add(&wlr_surface->events.new_subsurface, | ||
831 | &view->surface_new_subsurface); | ||
832 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; | ||
833 | |||
834 | if (decoration) { | 811 | if (decoration) { |
835 | view_update_csd_from_client(view, decoration); | 812 | view_update_csd_from_client(view, decoration); |
836 | } | 813 | } |
@@ -897,8 +874,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
897 | void view_unmap(struct sway_view *view) { | 874 | void view_unmap(struct sway_view *view) { |
898 | wl_signal_emit_mutable(&view->events.unmap, view); | 875 | wl_signal_emit_mutable(&view->events.unmap, view); |
899 | 876 | ||
900 | wl_list_remove(&view->surface_new_subsurface.link); | ||
901 | |||
902 | view->executed_criteria->length = 0; | 877 | view->executed_criteria->length = 0; |
903 | 878 | ||
904 | if (view->urgent_timer) { | 879 | if (view->urgent_timer) { |
@@ -962,253 +937,6 @@ void view_center_surface(struct sway_view *view) { | |||
962 | (con->current.content_height - view->geometry.height) / 2); | 937 | (con->current.content_height - view->geometry.height) / 2); |
963 | } | 938 | } |
964 | 939 | ||
965 | static const struct sway_view_child_impl subsurface_impl; | ||
966 | |||
967 | static void subsurface_get_view_coords(struct sway_view_child *child, | ||
968 | int *sx, int *sy) { | ||
969 | struct wlr_surface *surface = child->surface; | ||
970 | if (child->parent && child->parent->impl && | ||
971 | child->parent->impl->get_view_coords) { | ||
972 | child->parent->impl->get_view_coords(child->parent, sx, sy); | ||
973 | } else { | ||
974 | *sx = *sy = 0; | ||
975 | } | ||
976 | struct wlr_subsurface *subsurface = | ||
977 | wlr_subsurface_try_from_wlr_surface(surface); | ||
978 | *sx += subsurface->current.x; | ||
979 | *sy += subsurface->current.y; | ||
980 | } | ||
981 | |||
982 | static void subsurface_destroy(struct sway_view_child *child) { | ||
983 | if (!sway_assert(child->impl == &subsurface_impl, | ||
984 | "Expected a subsurface")) { | ||
985 | return; | ||
986 | } | ||
987 | struct sway_subsurface *subsurface = (struct sway_subsurface *)child; | ||
988 | wl_list_remove(&subsurface->destroy.link); | ||
989 | free(subsurface); | ||
990 | } | ||
991 | |||
992 | static const struct sway_view_child_impl subsurface_impl = { | ||
993 | .get_view_coords = subsurface_get_view_coords, | ||
994 | .destroy = subsurface_destroy, | ||
995 | }; | ||
996 | |||
997 | static void subsurface_handle_destroy(struct wl_listener *listener, | ||
998 | void *data) { | ||
999 | struct sway_subsurface *subsurface = | ||
1000 | wl_container_of(listener, subsurface, destroy); | ||
1001 | struct sway_view_child *child = &subsurface->child; | ||
1002 | view_child_destroy(child); | ||
1003 | } | ||
1004 | |||
1005 | static void view_child_damage(struct sway_view_child *child, bool whole); | ||
1006 | |||
1007 | static void view_subsurface_create(struct sway_view *view, | ||
1008 | struct wlr_subsurface *wlr_subsurface) { | ||
1009 | struct sway_subsurface *subsurface = | ||
1010 | calloc(1, sizeof(struct sway_subsurface)); | ||
1011 | if (subsurface == NULL) { | ||
1012 | sway_log(SWAY_ERROR, "Allocation failed"); | ||
1013 | return; | ||
1014 | } | ||
1015 | view_child_init(&subsurface->child, &subsurface_impl, view, | ||
1016 | wlr_subsurface->surface); | ||
1017 | |||
1018 | wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); | ||
1019 | subsurface->destroy.notify = subsurface_handle_destroy; | ||
1020 | |||
1021 | subsurface->child.mapped = true; | ||
1022 | |||
1023 | view_child_damage(&subsurface->child, true); | ||
1024 | } | ||
1025 | |||
1026 | static void view_child_subsurface_create(struct sway_view_child *child, | ||
1027 | struct wlr_subsurface *wlr_subsurface) { | ||
1028 | struct sway_subsurface *subsurface = | ||
1029 | calloc(1, sizeof(struct sway_subsurface)); | ||
1030 | if (subsurface == NULL) { | ||
1031 | sway_log(SWAY_ERROR, "Allocation failed"); | ||
1032 | return; | ||
1033 | } | ||
1034 | subsurface->child.parent = child; | ||
1035 | wl_list_insert(&child->children, &subsurface->child.link); | ||
1036 | view_child_init(&subsurface->child, &subsurface_impl, child->view, | ||
1037 | wlr_subsurface->surface); | ||
1038 | |||
1039 | wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); | ||
1040 | subsurface->destroy.notify = subsurface_handle_destroy; | ||
1041 | |||
1042 | subsurface->child.mapped = true; | ||
1043 | |||
1044 | view_child_damage(&subsurface->child, true); | ||
1045 | } | ||
1046 | |||
1047 | static bool view_child_is_mapped(struct sway_view_child *child) { | ||
1048 | while (child) { | ||
1049 | if (!child->mapped) { | ||
1050 | return false; | ||
1051 | } | ||
1052 | child = child->parent; | ||
1053 | } | ||
1054 | return true; | ||
1055 | } | ||
1056 | |||
1057 | static void view_child_damage(struct sway_view_child *child, bool whole) { | ||
1058 | if (!child || !view_child_is_mapped(child) || !child->view || !child->view->container) { | ||
1059 | return; | ||
1060 | } | ||
1061 | int sx, sy; | ||
1062 | child->impl->get_view_coords(child, &sx, &sy); | ||
1063 | desktop_damage_surface(child->surface, | ||
1064 | child->view->container->pending.content_x - | ||
1065 | child->view->geometry.x + sx, | ||
1066 | child->view->container->pending.content_y - | ||
1067 | child->view->geometry.y + sy, whole); | ||
1068 | } | ||
1069 | |||
1070 | static void view_child_handle_surface_commit(struct wl_listener *listener, | ||
1071 | void *data) { | ||
1072 | struct sway_view_child *child = | ||
1073 | wl_container_of(listener, child, surface_commit); | ||
1074 | view_child_damage(child, false); | ||
1075 | } | ||
1076 | |||
1077 | static void view_child_handle_surface_new_subsurface( | ||
1078 | struct wl_listener *listener, void *data) { | ||
1079 | struct sway_view_child *child = | ||
1080 | wl_container_of(listener, child, surface_new_subsurface); | ||
1081 | struct wlr_subsurface *subsurface = data; | ||
1082 | view_child_subsurface_create(child, subsurface); | ||
1083 | } | ||
1084 | |||
1085 | static void view_child_handle_surface_destroy(struct wl_listener *listener, | ||
1086 | void *data) { | ||
1087 | struct sway_view_child *child = | ||
1088 | wl_container_of(listener, child, surface_destroy); | ||
1089 | view_child_destroy(child); | ||
1090 | } | ||
1091 | |||
1092 | static void view_init_subsurfaces(struct sway_view *view, | ||
1093 | struct wlr_surface *surface) { | ||
1094 | struct wlr_subsurface *subsurface; | ||
1095 | wl_list_for_each(subsurface, &surface->current.subsurfaces_below, | ||
1096 | current.link) { | ||
1097 | view_subsurface_create(view, subsurface); | ||
1098 | } | ||
1099 | wl_list_for_each(subsurface, &surface->current.subsurfaces_above, | ||
1100 | current.link) { | ||
1101 | view_subsurface_create(view, subsurface); | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | static void view_child_init_subsurfaces(struct sway_view_child *view_child, | ||
1106 | struct wlr_surface *surface) { | ||
1107 | struct wlr_subsurface *subsurface; | ||
1108 | wl_list_for_each(subsurface, &surface->current.subsurfaces_below, | ||
1109 | current.link) { | ||
1110 | view_child_subsurface_create(view_child, subsurface); | ||
1111 | } | ||
1112 | wl_list_for_each(subsurface, &surface->current.subsurfaces_above, | ||
1113 | current.link) { | ||
1114 | view_child_subsurface_create(view_child, subsurface); | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | static void view_child_handle_surface_map(struct wl_listener *listener, | ||
1119 | void *data) { | ||
1120 | struct sway_view_child *child = | ||
1121 | wl_container_of(listener, child, surface_map); | ||
1122 | child->mapped = true; | ||
1123 | view_child_damage(child, true); | ||
1124 | } | ||
1125 | |||
1126 | static void view_child_handle_surface_unmap(struct wl_listener *listener, | ||
1127 | void *data) { | ||
1128 | struct sway_view_child *child = | ||
1129 | wl_container_of(listener, child, surface_unmap); | ||
1130 | view_child_damage(child, true); | ||
1131 | child->mapped = false; | ||
1132 | } | ||
1133 | |||
1134 | static void view_child_handle_view_unmap(struct wl_listener *listener, | ||
1135 | void *data) { | ||
1136 | struct sway_view_child *child = | ||
1137 | wl_container_of(listener, child, view_unmap); | ||
1138 | view_child_damage(child, true); | ||
1139 | child->mapped = false; | ||
1140 | } | ||
1141 | |||
1142 | void view_child_init(struct sway_view_child *child, | ||
1143 | const struct sway_view_child_impl *impl, struct sway_view *view, | ||
1144 | struct wlr_surface *surface) { | ||
1145 | child->impl = impl; | ||
1146 | child->view = view; | ||
1147 | child->surface = surface; | ||
1148 | wl_list_init(&child->children); | ||
1149 | |||
1150 | wl_signal_add(&surface->events.commit, &child->surface_commit); | ||
1151 | child->surface_commit.notify = view_child_handle_surface_commit; | ||
1152 | wl_signal_add(&surface->events.new_subsurface, | ||
1153 | &child->surface_new_subsurface); | ||
1154 | child->surface_new_subsurface.notify = | ||
1155 | view_child_handle_surface_new_subsurface; | ||
1156 | wl_signal_add(&surface->events.destroy, &child->surface_destroy); | ||
1157 | child->surface_destroy.notify = view_child_handle_surface_destroy; | ||
1158 | |||
1159 | // Not all child views have a map/unmap event | ||
1160 | child->surface_map.notify = view_child_handle_surface_map; | ||
1161 | wl_list_init(&child->surface_map.link); | ||
1162 | child->surface_unmap.notify = view_child_handle_surface_unmap; | ||
1163 | wl_list_init(&child->surface_unmap.link); | ||
1164 | |||
1165 | wl_signal_add(&view->events.unmap, &child->view_unmap); | ||
1166 | child->view_unmap.notify = view_child_handle_view_unmap; | ||
1167 | |||
1168 | struct sway_container *container = child->view->container; | ||
1169 | if (container != NULL) { | ||
1170 | struct sway_workspace *workspace = container->pending.workspace; | ||
1171 | if (workspace) { | ||
1172 | surface_enter_output(child->surface, workspace->output); | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | view_child_init_subsurfaces(child, surface); | ||
1177 | } | ||
1178 | |||
1179 | void view_child_destroy(struct sway_view_child *child) { | ||
1180 | if (view_child_is_mapped(child) && child->view->container != NULL) { | ||
1181 | view_child_damage(child, true); | ||
1182 | } | ||
1183 | |||
1184 | if (child->parent != NULL) { | ||
1185 | wl_list_remove(&child->link); | ||
1186 | child->parent = NULL; | ||
1187 | } | ||
1188 | |||
1189 | struct sway_view_child *subchild, *tmpchild; | ||
1190 | wl_list_for_each_safe(subchild, tmpchild, &child->children, link) { | ||
1191 | wl_list_remove(&subchild->link); | ||
1192 | subchild->parent = NULL; | ||
1193 | // The subchild lost its parent link, so it cannot see that the parent | ||
1194 | // is unmapped. Unmap it directly. | ||
1195 | subchild->mapped = false; | ||
1196 | } | ||
1197 | |||
1198 | wl_list_remove(&child->surface_commit.link); | ||
1199 | wl_list_remove(&child->surface_destroy.link); | ||
1200 | wl_list_remove(&child->surface_map.link); | ||
1201 | wl_list_remove(&child->surface_unmap.link); | ||
1202 | wl_list_remove(&child->view_unmap.link); | ||
1203 | wl_list_remove(&child->surface_new_subsurface.link); | ||
1204 | |||
1205 | if (child->impl && child->impl->destroy) { | ||
1206 | child->impl->destroy(child); | ||
1207 | } else { | ||
1208 | free(child); | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { | 940 | struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { |
1213 | struct wlr_xdg_surface *xdg_surface; | 941 | struct wlr_xdg_surface *xdg_surface; |
1214 | if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) { | 942 | if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) { |