aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/view.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/view.c')
-rw-r--r--sway/tree/view.c363
1 files changed, 208 insertions, 155 deletions
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 7afcdf31..b2f70d70 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -56,6 +56,7 @@ void view_destroy(struct sway_view *view) {
56 "(might have a pending transaction?)")) { 56 "(might have a pending transaction?)")) {
57 return; 57 return;
58 } 58 }
59 wl_list_remove(&view->events.unmap.listener_list);
59 if (!wl_list_empty(&view->saved_buffers)) { 60 if (!wl_list_empty(&view->saved_buffers)) {
60 view_remove_saved_buffer(view); 61 view_remove_saved_buffer(view);
61 } 62 }
@@ -206,7 +207,7 @@ bool view_ancestor_is_only_visible(struct sway_view *view) {
206 } else { 207 } else {
207 only_visible = true; 208 only_visible = true;
208 } 209 }
209 con = con->parent; 210 con = con->pending.parent;
210 } 211 }
211 return only_visible; 212 return only_visible;
212} 213}
@@ -222,72 +223,73 @@ static bool view_is_only_visible(struct sway_view *view) {
222 } 223 }
223 } 224 }
224 225
225 con = con->parent; 226 con = con->pending.parent;
226 } 227 }
227 228
228 return true; 229 return true;
229} 230}
230 231
231static bool gaps_to_edge(struct sway_view *view) { 232static bool gaps_to_edge(struct sway_view *view) {
232 struct side_gaps gaps = view->container->workspace->current_gaps; 233 struct side_gaps gaps = view->container->pending.workspace->current_gaps;
233 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0; 234 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0;
234} 235}
235 236
236void view_autoconfigure(struct sway_view *view) { 237void view_autoconfigure(struct sway_view *view) {
237 struct sway_container *con = view->container; 238 struct sway_container *con = view->container;
238 struct sway_workspace *ws = con->workspace; 239 struct sway_workspace *ws = con->pending.workspace;
239 240
240 if (container_is_scratchpad_hidden(con) && 241 if (container_is_scratchpad_hidden(con) &&
241 con->fullscreen_mode != FULLSCREEN_GLOBAL) { 242 con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
242 return; 243 return;
243 } 244 }
244 struct sway_output *output = ws ? ws->output : NULL; 245 struct sway_output *output = ws ? ws->output : NULL;
245 246
246 if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { 247 if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
247 con->content_x = output->lx; 248 con->pending.content_x = output->lx;
248 con->content_y = output->ly; 249 con->pending.content_y = output->ly;
249 con->content_width = output->width; 250 con->pending.content_width = output->width;
250 con->content_height = output->height; 251 con->pending.content_height = output->height;
251 return; 252 return;
252 } else if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { 253 } else if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
253 con->content_x = root->x; 254 con->pending.content_x = root->x;
254 con->content_y = root->y; 255 con->pending.content_y = root->y;
255 con->content_width = root->width; 256 con->pending.content_width = root->width;
256 con->content_height = root->height; 257 con->pending.content_height = root->height;
257 return; 258 return;
258 } 259 }
259 260
260 con->border_top = con->border_bottom = true; 261 con->pending.border_top = con->pending.border_bottom = true;
261 con->border_left = con->border_right = true; 262 con->pending.border_left = con->pending.border_right = true;
262 double y_offset = 0; 263 double y_offset = 0;
263 264
264 if (!container_is_floating(con) && ws) { 265 if (!container_is_floating_or_child(con) && ws) {
265 if (config->hide_edge_borders == E_BOTH 266 if (config->hide_edge_borders == E_BOTH
266 || config->hide_edge_borders == E_VERTICAL) { 267 || config->hide_edge_borders == E_VERTICAL) {
267 con->border_left = con->x != ws->x; 268 con->pending.border_left = con->pending.x != ws->x;
268 int right_x = con->x + con->width; 269 int right_x = con->pending.x + con->pending.width;
269 con->border_right = right_x != ws->x + ws->width; 270 con->pending.border_right = right_x != ws->x + ws->width;
270 } 271 }
271 272
272 if (config->hide_edge_borders == E_BOTH 273 if (config->hide_edge_borders == E_BOTH
273 || config->hide_edge_borders == E_HORIZONTAL) { 274 || config->hide_edge_borders == E_HORIZONTAL) {
274 con->border_top = con->y != ws->y; 275 con->pending.border_top = con->pending.y != ws->y;
275 int bottom_y = con->y + con->height; 276 int bottom_y = con->pending.y + con->pending.height;
276 con->border_bottom = bottom_y != ws->y + ws->height; 277 con->pending.border_bottom = bottom_y != ws->y + ws->height;
277 } 278 }
278 279
279 bool smart = config->hide_edge_borders_smart == ESMART_ON || 280 bool smart = config->hide_edge_borders_smart == ESMART_ON ||
280 (config->hide_edge_borders_smart == ESMART_NO_GAPS && 281 (config->hide_edge_borders_smart == ESMART_NO_GAPS &&
281 !gaps_to_edge(view)); 282 !gaps_to_edge(view));
282 if (smart) { 283 if (smart) {
283 bool show_border = container_is_floating_or_child(con) || 284 bool show_border = !view_is_only_visible(view);
284 !view_is_only_visible(view); 285 con->pending.border_left &= show_border;
285 con->border_left &= show_border; 286 con->pending.border_right &= show_border;
286 con->border_right &= show_border; 287 con->pending.border_top &= show_border;
287 con->border_top &= show_border; 288 con->pending.border_bottom &= show_border;
288 con->border_bottom &= show_border;
289 } 289 }
290 }
290 291
292 if (!container_is_floating(con)) {
291 // In a tabbed or stacked container, the container's y is the top of the 293 // In a tabbed or stacked container, the container's y is the top of the
292 // title area. We have to offset the surface y by the height of the title, 294 // title area. We have to offset the surface y by the height of the title,
293 // bar, and disable any top border because we'll always have the title bar. 295 // bar, and disable any top border because we'll always have the title bar.
@@ -298,56 +300,56 @@ void view_autoconfigure(struct sway_view *view) {
298 enum sway_container_layout layout = container_parent_layout(con); 300 enum sway_container_layout layout = container_parent_layout(con);
299 if (layout == L_TABBED) { 301 if (layout == L_TABBED) {
300 y_offset = container_titlebar_height(); 302 y_offset = container_titlebar_height();
301 con->border_top = false; 303 con->pending.border_top = false;
302 } else if (layout == L_STACKED) { 304 } else if (layout == L_STACKED) {
303 y_offset = container_titlebar_height() * siblings->length; 305 y_offset = container_titlebar_height() * siblings->length;
304 con->border_top = false; 306 con->pending.border_top = false;
305 } 307 }
306 } 308 }
307 } 309 }
308 310
309 double x, y, width, height; 311 double x, y, width, height;
310 switch (con->border) { 312 switch (con->pending.border) {
311 default: 313 default:
312 case B_CSD: 314 case B_CSD:
313 case B_NONE: 315 case B_NONE:
314 x = con->x; 316 x = con->pending.x;
315 y = con->y + y_offset; 317 y = con->pending.y + y_offset;
316 width = con->width; 318 width = con->pending.width;
317 height = con->height - y_offset; 319 height = con->pending.height - y_offset;
318 break; 320 break;
319 case B_PIXEL: 321 case B_PIXEL:
320 x = con->x + con->border_thickness * con->border_left; 322 x = con->pending.x + con->pending.border_thickness * con->pending.border_left;
321 y = con->y + con->border_thickness * con->border_top + y_offset; 323 y = con->pending.y + con->pending.border_thickness * con->pending.border_top + y_offset;
322 width = con->width 324 width = con->pending.width
323 - con->border_thickness * con->border_left 325 - con->pending.border_thickness * con->pending.border_left
324 - con->border_thickness * con->border_right; 326 - con->pending.border_thickness * con->pending.border_right;
325 height = con->height - y_offset 327 height = con->pending.height - y_offset
326 - con->border_thickness * con->border_top 328 - con->pending.border_thickness * con->pending.border_top
327 - con->border_thickness * con->border_bottom; 329 - con->pending.border_thickness * con->pending.border_bottom;
328 break; 330 break;
329 case B_NORMAL: 331 case B_NORMAL:
330 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border 332 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
331 x = con->x + con->border_thickness * con->border_left; 333 x = con->pending.x + con->pending.border_thickness * con->pending.border_left;
332 width = con->width 334 width = con->pending.width
333 - con->border_thickness * con->border_left 335 - con->pending.border_thickness * con->pending.border_left
334 - con->border_thickness * con->border_right; 336 - con->pending.border_thickness * con->pending.border_right;
335 if (y_offset) { 337 if (y_offset) {
336 y = con->y + y_offset; 338 y = con->pending.y + y_offset;
337 height = con->height - y_offset 339 height = con->pending.height - y_offset
338 - con->border_thickness * con->border_bottom; 340 - con->pending.border_thickness * con->pending.border_bottom;
339 } else { 341 } else {
340 y = con->y + container_titlebar_height(); 342 y = con->pending.y + container_titlebar_height();
341 height = con->height - container_titlebar_height() 343 height = con->pending.height - container_titlebar_height()
342 - con->border_thickness * con->border_bottom; 344 - con->pending.border_thickness * con->pending.border_bottom;
343 } 345 }
344 break; 346 break;
345 } 347 }
346 348
347 con->content_x = x; 349 con->pending.content_x = x;
348 con->content_y = y; 350 con->pending.content_y = y;
349 con->content_width = width; 351 con->pending.content_width = width;
350 con->content_height = height; 352 con->pending.content_height = height;
351} 353}
352 354
353void view_set_activated(struct sway_view *view, bool activated) { 355void view_set_activated(struct sway_view *view, bool activated) {
@@ -361,7 +363,7 @@ void view_set_activated(struct sway_view *view, bool activated) {
361} 363}
362 364
363void view_request_activate(struct sway_view *view) { 365void view_request_activate(struct sway_view *view) {
364 struct sway_workspace *ws = view->container->workspace; 366 struct sway_workspace *ws = view->container->pending.workspace;
365 if (!ws) { // hidden scratchpad container 367 if (!ws) { // hidden scratchpad container
366 return; 368 return;
367 } 369 }
@@ -401,13 +403,13 @@ void view_set_csd_from_server(struct sway_view *view, bool enabled) {
401void view_update_csd_from_client(struct sway_view *view, bool enabled) { 403void view_update_csd_from_client(struct sway_view *view, bool enabled) {
402 sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled); 404 sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled);
403 struct sway_container *con = view->container; 405 struct sway_container *con = view->container;
404 if (enabled && con && con->border != B_CSD) { 406 if (enabled && con && con->pending.border != B_CSD) {
405 con->saved_border = con->border; 407 con->saved_border = con->pending.border;
406 if (container_is_floating(con)) { 408 if (container_is_floating(con)) {
407 con->border = B_CSD; 409 con->pending.border = B_CSD;
408 } 410 }
409 } else if (!enabled && con && con->border == B_CSD) { 411 } else if (!enabled && con && con->pending.border == B_CSD) {
410 con->border = con->saved_border; 412 con->pending.border = con->saved_border;
411 } 413 }
412 view->using_csd = enabled; 414 view->using_csd = enabled;
413} 415}
@@ -465,6 +467,9 @@ static void view_subsurface_create(struct sway_view *view,
465static void view_init_subsurfaces(struct sway_view *view, 467static void view_init_subsurfaces(struct sway_view *view,
466 struct wlr_surface *surface); 468 struct wlr_surface *surface);
467 469
470static void view_child_init_subsurfaces(struct sway_view_child *view_child,
471 struct wlr_surface *surface);
472
468static void view_handle_surface_new_subsurface(struct wl_listener *listener, 473static void view_handle_surface_new_subsurface(struct wl_listener *listener,
469 void *data) { 474 void *data) {
470 struct sway_view *view = 475 struct sway_view *view =
@@ -577,7 +582,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
577 if (node && node->type == N_WORKSPACE) { 582 if (node && node->type == N_WORKSPACE) {
578 return node->sway_workspace; 583 return node->sway_workspace;
579 } else if (node && node->type == N_CONTAINER) { 584 } else if (node && node->type == N_CONTAINER) {
580 return node->sway_container->workspace; 585 return node->sway_container->pending.workspace;
581 } 586 }
582 587
583 // When there's no outputs connected, the above should match a workspace on 588 // When there's no outputs connected, the above should match a workspace on
@@ -590,12 +595,17 @@ static bool should_focus(struct sway_view *view) {
590 struct sway_seat *seat = input_manager_current_seat(); 595 struct sway_seat *seat = input_manager_current_seat();
591 struct sway_container *prev_con = seat_get_focused_container(seat); 596 struct sway_container *prev_con = seat_get_focused_container(seat);
592 struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); 597 struct sway_workspace *prev_ws = seat_get_focused_workspace(seat);
593 struct sway_workspace *map_ws = view->container->workspace; 598 struct sway_workspace *map_ws = view->container->pending.workspace;
594 599
595 if (view->container->fullscreen_mode == FULLSCREEN_GLOBAL) { 600 if (view->container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
596 return true; 601 return true;
597 } 602 }
598 603
604 // View opened "under" fullscreen view should not be given focus.
605 if (root->fullscreen_global || !map_ws || map_ws->fullscreen) {
606 return false;
607 }
608
599 // Views can only take focus if they are mapped into the active workspace 609 // Views can only take focus if they are mapped into the active workspace
600 if (prev_ws != map_ws) { 610 if (prev_ws != map_ws) {
601 return false; 611 return false;
@@ -603,9 +613,9 @@ static bool should_focus(struct sway_view *view) {
603 613
604 // If the view is the only one in the focused workspace, it'll get focus 614 // If the view is the only one in the focused workspace, it'll get focus
605 // regardless of any no_focus criteria. 615 // regardless of any no_focus criteria.
606 if (!view->container->parent && !prev_con) { 616 if (!view->container->pending.parent && !prev_con) {
607 size_t num_children = view->container->workspace->tiling->length + 617 size_t num_children = view->container->pending.workspace->tiling->length +
608 view->container->workspace->floating->length; 618 view->container->pending.workspace->floating->length;
609 if (num_children == 1) { 619 if (num_children == 1) {
610 return true; 620 return true;
611 } 621 }
@@ -635,6 +645,7 @@ static void handle_foreign_activate_request(
635 break; 645 break;
636 } 646 }
637 } 647 }
648 transaction_commit_dirty();
638} 649}
639 650
640static void handle_foreign_fullscreen_request( 651static void handle_foreign_fullscreen_request(
@@ -645,9 +656,21 @@ static void handle_foreign_fullscreen_request(
645 656
646 // Match fullscreen command behavior for scratchpad hidden views 657 // Match fullscreen command behavior for scratchpad hidden views
647 struct sway_container *container = view->container; 658 struct sway_container *container = view->container;
648 if (!container->workspace) { 659 if (!container->pending.workspace) {
649 while (container->parent) { 660 while (container->pending.parent) {
650 container = container->parent; 661 container = container->pending.parent;
662 }
663 }
664
665 if (event->fullscreen && event->output && event->output->data) {
666 struct sway_output *output = event->output->data;
667 struct sway_workspace *ws = output_get_active_workspace(output);
668 if (ws && !container_is_scratchpad_hidden(view->container)) {
669 if (container_is_floating(view->container)) {
670 workspace_add_floating(ws, view->container);
671 } else {
672 workspace_add_tiling(ws, view->container);
673 }
651 } 674 }
652 } 675 }
653 676
@@ -656,12 +679,13 @@ static void handle_foreign_fullscreen_request(
656 if (event->fullscreen) { 679 if (event->fullscreen) {
657 arrange_root(); 680 arrange_root();
658 } else { 681 } else {
659 if (container->parent) { 682 if (container->pending.parent) {
660 arrange_container(container->parent); 683 arrange_container(container->pending.parent);
661 } else if (container->workspace) { 684 } else if (container->pending.workspace) {
662 arrange_workspace(container->workspace); 685 arrange_workspace(container->pending.workspace);
663 } 686 }
664 } 687 }
688 transaction_commit_dirty();
665} 689}
666 690
667static void handle_foreign_close_request( 691static void handle_foreign_close_request(
@@ -742,7 +766,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
742 766
743 view_init_subsurfaces(view, wlr_surface); 767 view_init_subsurfaces(view, wlr_surface);
744 wl_signal_add(&wlr_surface->events.new_subsurface, 768 wl_signal_add(&wlr_surface->events.new_subsurface,
745 &view->surface_new_subsurface); 769 &view->surface_new_subsurface);
746 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; 770 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface;
747 771
748 if (decoration) { 772 if (decoration) {
@@ -750,20 +774,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
750 } 774 }
751 775
752 if (view->impl->wants_floating && view->impl->wants_floating(view)) { 776 if (view->impl->wants_floating && view->impl->wants_floating(view)) {
753 view->container->border = config->floating_border; 777 view->container->pending.border = config->floating_border;
754 view->container->border_thickness = config->floating_border_thickness; 778 view->container->pending.border_thickness = config->floating_border_thickness;
755 container_set_floating(view->container, true); 779 container_set_floating(view->container, true);
756 } else { 780 } else {
757 view->container->border = config->border; 781 view->container->pending.border = config->border;
758 view->container->border_thickness = config->border_thickness; 782 view->container->pending.border_thickness = config->border_thickness;
759 view_set_tiled(view, true); 783 view_set_tiled(view, true);
760 } 784 }
761 785
762 if (config->popup_during_fullscreen == POPUP_LEAVE && 786 if (config->popup_during_fullscreen == POPUP_LEAVE &&
763 container->workspace && 787 container->pending.workspace &&
764 container->workspace->fullscreen && 788 container->pending.workspace->fullscreen &&
765 container->workspace->fullscreen->view) { 789 container->pending.workspace->fullscreen->view) {
766 struct sway_container *fs = container->workspace->fullscreen; 790 struct sway_container *fs = container->pending.workspace->fullscreen;
767 if (view_is_transient_for(view, fs->view)) { 791 if (view_is_transient_for(view, fs->view)) {
768 container_set_fullscreen(fs, false); 792 container_set_fullscreen(fs, false);
769 } 793 }
@@ -774,12 +798,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
774 798
775 if (fullscreen) { 799 if (fullscreen) {
776 container_set_fullscreen(view->container, true); 800 container_set_fullscreen(view->container, true);
777 arrange_workspace(view->container->workspace); 801 arrange_workspace(view->container->pending.workspace);
778 } else { 802 } else {
779 if (container->parent) { 803 if (container->pending.parent) {
780 arrange_container(container->parent); 804 arrange_container(container->pending.parent);
781 } else if (container->workspace) { 805 } else if (container->pending.workspace) {
782 arrange_workspace(container->workspace); 806 arrange_workspace(container->pending.workspace);
783 } 807 }
784 } 808 }
785 809
@@ -790,9 +814,9 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
790#if HAVE_XWAYLAND 814#if HAVE_XWAYLAND
791 if (wlr_surface_is_xwayland_surface(wlr_surface)) { 815 if (wlr_surface_is_xwayland_surface(wlr_surface)) {
792 struct wlr_xwayland_surface *xsurface = 816 struct wlr_xwayland_surface *xsurface =
793 wlr_xwayland_surface_from_wlr_surface(wlr_surface); 817 wlr_xwayland_surface_from_wlr_surface(wlr_surface);
794 set_focus = (wlr_xwayland_icccm_input_model(xsurface) != 818 set_focus &= wlr_xwayland_icccm_input_model(xsurface) !=
795 WLR_ICCCM_INPUT_MODEL_NONE) && set_focus; 819 WLR_ICCCM_INPUT_MODEL_NONE;
796 } 820 }
797#endif 821#endif
798 822
@@ -803,11 +827,9 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
803 const char *app_id; 827 const char *app_id;
804 const char *class; 828 const char *class;
805 if ((app_id = view_get_app_id(view)) != NULL) { 829 if ((app_id = view_get_app_id(view)) != NULL) {
806 wlr_foreign_toplevel_handle_v1_set_app_id( 830 wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id);
807 view->foreign_toplevel, app_id);
808 } else if ((class = view_get_class(view)) != NULL) { 831 } else if ((class = view_get_class(view)) != NULL) {
809 wlr_foreign_toplevel_handle_v1_set_app_id( 832 wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, class);
810 view->foreign_toplevel, class);
811 } 833 }
812} 834}
813 835
@@ -826,8 +848,8 @@ void view_unmap(struct sway_view *view) {
826 view->foreign_toplevel = NULL; 848 view->foreign_toplevel = NULL;
827 } 849 }
828 850
829 struct sway_container *parent = view->container->parent; 851 struct sway_container *parent = view->container->pending.parent;
830 struct sway_workspace *ws = view->container->workspace; 852 struct sway_workspace *ws = view->container->pending.workspace;
831 container_begin_destroy(view->container); 853 container_begin_destroy(view->container);
832 if (parent) { 854 if (parent) {
833 container_reap_empty(parent); 855 container_reap_empty(parent);
@@ -860,47 +882,38 @@ void view_unmap(struct sway_view *view) {
860 view->surface = NULL; 882 view->surface = NULL;
861} 883}
862 884
863void view_update_size(struct sway_view *view, int width, int height) { 885void view_update_size(struct sway_view *view) {
864 struct sway_container *con = view->container; 886 struct sway_container *con = view->container;
887 con->pending.content_width = view->geometry.width;
888 con->pending.content_height = view->geometry.height;
889 container_set_geometry_from_content(con);
890}
865 891
866 if (container_is_floating(con)) { 892void view_center_surface(struct sway_view *view) {
867 con->content_width = width; 893 struct sway_container *con = view->container;
868 con->content_height = height; 894 // We always center the current coordinates rather than the next, as the
869 container_set_geometry_from_content(con); 895 // geometry immediately affects the currently active rendering.
870 } else { 896 con->surface_x = fmax(con->current.content_x, con->current.content_x +
871 con->surface_x = con->content_x + (con->content_width - width) / 2; 897 (con->current.content_width - view->geometry.width) / 2);
872 con->surface_y = con->content_y + (con->content_height - height) / 2; 898 con->surface_y = fmax(con->current.content_y, con->current.content_y +
873 con->surface_x = fmax(con->surface_x, con->content_x); 899 (con->current.content_height - view->geometry.height) / 2);
874 con->surface_y = fmax(con->surface_y, con->content_y);
875 }
876} 900}
877 901
878static const struct sway_view_child_impl subsurface_impl; 902static const struct sway_view_child_impl subsurface_impl;
879 903
880static void subsurface_get_root_coords(struct sway_view_child *child, 904static void subsurface_get_view_coords(struct sway_view_child *child,
881 int *root_sx, int *root_sy) { 905 int *sx, int *sy) {
882 struct wlr_surface *surface = child->surface; 906 struct wlr_surface *surface = child->surface;
883 *root_sx = -child->view->geometry.x;
884 *root_sy = -child->view->geometry.y;
885
886 if (child->parent && child->parent->impl && 907 if (child->parent && child->parent->impl &&
887 child->parent->impl->get_root_coords) { 908 child->parent->impl->get_view_coords) {
888 int sx, sy; 909 child->parent->impl->get_view_coords(child->parent, sx, sy);
889 child->parent->impl->get_root_coords(child->parent, &sx, &sy);
890 *root_sx += sx;
891 *root_sy += sy;
892 } else { 910 } else {
893 while (surface && wlr_surface_is_subsurface(surface)) { 911 *sx = *sy = 0;
894 struct wlr_subsurface *subsurface =
895 wlr_subsurface_from_wlr_surface(surface);
896 if (subsurface == NULL) {
897 break;
898 }
899 *root_sx += subsurface->current.x;
900 *root_sy += subsurface->current.y;
901 surface = subsurface->parent;
902 }
903 } 912 }
913 struct wlr_subsurface *subsurface =
914 wlr_subsurface_from_wlr_surface(surface);
915 *sx += subsurface->current.x;
916 *sy += subsurface->current.y;
904} 917}
905 918
906static void subsurface_destroy(struct sway_view_child *child) { 919static void subsurface_destroy(struct sway_view_child *child) {
@@ -914,7 +927,7 @@ static void subsurface_destroy(struct sway_view_child *child) {
914} 927}
915 928
916static const struct sway_view_child_impl subsurface_impl = { 929static const struct sway_view_child_impl subsurface_impl = {
917 .get_root_coords = subsurface_get_root_coords, 930 .get_view_coords = subsurface_get_view_coords,
918 .destroy = subsurface_destroy, 931 .destroy = subsurface_destroy,
919}; 932};
920 933
@@ -968,15 +981,27 @@ static void view_child_subsurface_create(struct sway_view_child *child,
968 view_child_damage(&subsurface->child, true); 981 view_child_damage(&subsurface->child, true);
969} 982}
970 983
984static bool view_child_is_mapped(struct sway_view_child *child) {
985 while (child) {
986 if (!child->mapped) {
987 return false;
988 }
989 child = child->parent;
990 }
991 return true;
992}
993
971static void view_child_damage(struct sway_view_child *child, bool whole) { 994static void view_child_damage(struct sway_view_child *child, bool whole) {
972 if (!child || !child->mapped || !child->view || !child->view->container) { 995 if (!child || !view_child_is_mapped(child) || !child->view || !child->view->container) {
973 return; 996 return;
974 } 997 }
975 int sx, sy; 998 int sx, sy;
976 child->impl->get_root_coords(child, &sx, &sy); 999 child->impl->get_view_coords(child, &sx, &sy);
977 desktop_damage_surface(child->surface, 1000 desktop_damage_surface(child->surface,
978 child->view->container->content_x + sx, 1001 child->view->container->pending.content_x -
979 child->view->container->content_y + sy, whole); 1002 child->view->geometry.x + sx,
1003 child->view->container->pending.content_y -
1004 child->view->geometry.y + sy, whole);
980} 1005}
981 1006
982static void view_child_handle_surface_commit(struct wl_listener *listener, 1007static void view_child_handle_surface_commit(struct wl_listener *listener,
@@ -1004,11 +1029,29 @@ static void view_child_handle_surface_destroy(struct wl_listener *listener,
1004static void view_init_subsurfaces(struct sway_view *view, 1029static void view_init_subsurfaces(struct sway_view *view,
1005 struct wlr_surface *surface) { 1030 struct wlr_surface *surface) {
1006 struct wlr_subsurface *subsurface; 1031 struct wlr_subsurface *subsurface;
1007 wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { 1032 wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
1033 current.link) {
1034 view_subsurface_create(view, subsurface);
1035 }
1036 wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
1037 current.link) {
1008 view_subsurface_create(view, subsurface); 1038 view_subsurface_create(view, subsurface);
1009 } 1039 }
1010} 1040}
1011 1041
1042static void view_child_init_subsurfaces(struct sway_view_child *view_child,
1043 struct wlr_surface *surface) {
1044 struct wlr_subsurface *subsurface;
1045 wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
1046 current.link) {
1047 view_child_subsurface_create(view_child, subsurface);
1048 }
1049 wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
1050 current.link) {
1051 view_child_subsurface_create(view_child, subsurface);
1052 }
1053}
1054
1012static void view_child_handle_surface_map(struct wl_listener *listener, 1055static void view_child_handle_surface_map(struct wl_listener *listener,
1013 void *data) { 1056 void *data) {
1014 struct sway_view_child *child = 1057 struct sway_view_child *child =
@@ -1059,16 +1102,16 @@ void view_child_init(struct sway_view_child *child,
1059 wl_signal_add(&view->events.unmap, &child->view_unmap); 1102 wl_signal_add(&view->events.unmap, &child->view_unmap);
1060 child->view_unmap.notify = view_child_handle_view_unmap; 1103 child->view_unmap.notify = view_child_handle_view_unmap;
1061 1104
1062 struct sway_workspace *workspace = child->view->container->workspace; 1105 struct sway_workspace *workspace = child->view->container->pending.workspace;
1063 if (workspace) { 1106 if (workspace) {
1064 wlr_surface_send_enter(child->surface, workspace->output->wlr_output); 1107 wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
1065 } 1108 }
1066 1109
1067 view_init_subsurfaces(child->view, surface); 1110 view_child_init_subsurfaces(child, surface);
1068} 1111}
1069 1112
1070void view_child_destroy(struct sway_view_child *child) { 1113void view_child_destroy(struct sway_view_child *child) {
1071 if (child->mapped && child->view->container != NULL) { 1114 if (view_child_is_mapped(child) && child->view->container != NULL) {
1072 view_child_damage(child, true); 1115 view_child_damage(child, true);
1073 } 1116 }
1074 1117
@@ -1081,6 +1124,9 @@ void view_child_destroy(struct sway_view_child *child) {
1081 wl_list_for_each_safe(subchild, tmpchild, &child->children, link) { 1124 wl_list_for_each_safe(subchild, tmpchild, &child->children, link) {
1082 wl_list_remove(&subchild->link); 1125 wl_list_remove(&subchild->link);
1083 subchild->parent = NULL; 1126 subchild->parent = NULL;
1127 // The subchild lost its parent link, so it cannot see that the parent
1128 // is unmapped. Unmap it directly.
1129 subchild->mapped = false;
1084 } 1130 }
1085 1131
1086 wl_list_remove(&child->surface_commit.link); 1132 wl_list_remove(&child->surface_commit.link);
@@ -1101,18 +1147,27 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
1101 if (wlr_surface_is_xdg_surface(wlr_surface)) { 1147 if (wlr_surface_is_xdg_surface(wlr_surface)) {
1102 struct wlr_xdg_surface *xdg_surface = 1148 struct wlr_xdg_surface *xdg_surface =
1103 wlr_xdg_surface_from_wlr_surface(wlr_surface); 1149 wlr_xdg_surface_from_wlr_surface(wlr_surface);
1150 if (xdg_surface == NULL) {
1151 return NULL;
1152 }
1104 return view_from_wlr_xdg_surface(xdg_surface); 1153 return view_from_wlr_xdg_surface(xdg_surface);
1105 } 1154 }
1106#if HAVE_XWAYLAND 1155#if HAVE_XWAYLAND
1107 if (wlr_surface_is_xwayland_surface(wlr_surface)) { 1156 if (wlr_surface_is_xwayland_surface(wlr_surface)) {
1108 struct wlr_xwayland_surface *xsurface = 1157 struct wlr_xwayland_surface *xsurface =
1109 wlr_xwayland_surface_from_wlr_surface(wlr_surface); 1158 wlr_xwayland_surface_from_wlr_surface(wlr_surface);
1159 if (xsurface == NULL) {
1160 return NULL;
1161 }
1110 return view_from_wlr_xwayland_surface(xsurface); 1162 return view_from_wlr_xwayland_surface(xsurface);
1111 } 1163 }
1112#endif 1164#endif
1113 if (wlr_surface_is_subsurface(wlr_surface)) { 1165 if (wlr_surface_is_subsurface(wlr_surface)) {
1114 struct wlr_subsurface *subsurface = 1166 struct wlr_subsurface *subsurface =
1115 wlr_subsurface_from_wlr_surface(wlr_surface); 1167 wlr_subsurface_from_wlr_surface(wlr_surface);
1168 if (subsurface == NULL) {
1169 return NULL;
1170 }
1116 return view_from_wlr_surface(subsurface->parent); 1171 return view_from_wlr_surface(subsurface->parent);
1117 } 1172 }
1118 if (wlr_surface_is_layer_surface(wlr_surface)) { 1173 if (wlr_surface_is_layer_surface(wlr_surface)) {
@@ -1225,8 +1280,6 @@ void view_update_title(struct sway_view *view, bool force) {
1225 view->container->title = NULL; 1280 view->container->title = NULL;
1226 view->container->formatted_title = NULL; 1281 view->container->formatted_title = NULL;
1227 } 1282 }
1228 container_calculate_title_height(view->container);
1229 config_update_font_height(false);
1230 1283
1231 // Update title after the global font height is updated 1284 // Update title after the global font height is updated
1232 container_update_title_textures(view->container); 1285 container_update_title_textures(view->container);
@@ -1242,15 +1295,15 @@ bool view_is_visible(struct sway_view *view) {
1242 if (view->container->node.destroying) { 1295 if (view->container->node.destroying) {
1243 return false; 1296 return false;
1244 } 1297 }
1245 struct sway_workspace *workspace = view->container->workspace; 1298 struct sway_workspace *workspace = view->container->pending.workspace;
1246 if (!workspace && view->container->fullscreen_mode != FULLSCREEN_GLOBAL) { 1299 if (!workspace && view->container->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
1247 bool fs_global_descendant = false; 1300 bool fs_global_descendant = false;
1248 struct sway_container *parent = view->container->parent; 1301 struct sway_container *parent = view->container->pending.parent;
1249 while (parent) { 1302 while (parent) {
1250 if (parent->fullscreen_mode == FULLSCREEN_GLOBAL) { 1303 if (parent->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
1251 fs_global_descendant = true; 1304 fs_global_descendant = true;
1252 } 1305 }
1253 parent = parent->parent; 1306 parent = parent->pending.parent;
1254 } 1307 }
1255 if (!fs_global_descendant) { 1308 if (!fs_global_descendant) {
1256 return false; 1309 return false;
@@ -1268,13 +1321,13 @@ bool view_is_visible(struct sway_view *view) {
1268 enum sway_container_layout layout = container_parent_layout(con); 1321 enum sway_container_layout layout = container_parent_layout(con);
1269 if ((layout == L_TABBED || layout == L_STACKED) 1322 if ((layout == L_TABBED || layout == L_STACKED)
1270 && !container_is_floating(con)) { 1323 && !container_is_floating(con)) {
1271 struct sway_node *parent = con->parent ? 1324 struct sway_node *parent = con->pending.parent ?
1272 &con->parent->node : &con->workspace->node; 1325 &con->pending.parent->node : &con->pending.workspace->node;
1273 if (seat_get_active_tiling_child(seat, parent) != &con->node) { 1326 if (seat_get_active_tiling_child(seat, parent) != &con->node) {
1274 return false; 1327 return false;
1275 } 1328 }
1276 } 1329 }
1277 con = con->parent; 1330 con = con->pending.parent;
1278 } 1331 }
1279 // Check view isn't hidden by another fullscreen view 1332 // Check view isn't hidden by another fullscreen view
1280 struct sway_container *fs = root->fullscreen_global ? 1333 struct sway_container *fs = root->fullscreen_global ?
@@ -1308,7 +1361,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
1308 ipc_event_window(view->container, "urgent"); 1361 ipc_event_window(view->container, "urgent");
1309 1362
1310 if (!container_is_scratchpad_hidden(view->container)) { 1363 if (!container_is_scratchpad_hidden(view->container)) {
1311 workspace_detect_urgent(view->container->workspace); 1364 workspace_detect_urgent(view->container->pending.workspace);
1312 } 1365 }
1313} 1366}
1314 1367
@@ -1338,11 +1391,11 @@ static void view_save_buffer_iterator(struct wlr_surface *surface,
1338 saved_buffer->buffer = surface->buffer; 1391 saved_buffer->buffer = surface->buffer;
1339 saved_buffer->width = surface->current.width; 1392 saved_buffer->width = surface->current.width;
1340 saved_buffer->height = surface->current.height; 1393 saved_buffer->height = surface->current.height;
1341 saved_buffer->x = sx; 1394 saved_buffer->x = view->container->surface_x + sx;
1342 saved_buffer->y = sy; 1395 saved_buffer->y = view->container->surface_y + sy;
1343 saved_buffer->transform = surface->current.transform; 1396 saved_buffer->transform = surface->current.transform;
1344 wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box); 1397 wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box);
1345 wl_list_insert(&view->saved_buffers, &saved_buffer->link); 1398 wl_list_insert(view->saved_buffers.prev, &saved_buffer->link);
1346 } 1399 }
1347} 1400}
1348 1401