diff options
Diffstat (limited to 'sway/tree/view.c')
-rw-r--r-- | sway/tree/view.c | 363 |
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 | ||
231 | static bool gaps_to_edge(struct sway_view *view) { | 232 | static 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 | ||
236 | void view_autoconfigure(struct sway_view *view) { | 237 | void 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 | ||
353 | void view_set_activated(struct sway_view *view, bool activated) { | 355 | void 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 | ||
363 | void view_request_activate(struct sway_view *view) { | 365 | void 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) { | |||
401 | void view_update_csd_from_client(struct sway_view *view, bool enabled) { | 403 | void 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, | |||
465 | static void view_init_subsurfaces(struct sway_view *view, | 467 | static void view_init_subsurfaces(struct sway_view *view, |
466 | struct wlr_surface *surface); | 468 | struct wlr_surface *surface); |
467 | 469 | ||
470 | static void view_child_init_subsurfaces(struct sway_view_child *view_child, | ||
471 | struct wlr_surface *surface); | ||
472 | |||
468 | static void view_handle_surface_new_subsurface(struct wl_listener *listener, | 473 | static 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 | ||
640 | static void handle_foreign_fullscreen_request( | 651 | static 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 | ||
667 | static void handle_foreign_close_request( | 691 | static 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 | ||
863 | void view_update_size(struct sway_view *view, int width, int height) { | 885 | void 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)) { | 892 | void 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 | ||
878 | static const struct sway_view_child_impl subsurface_impl; | 902 | static const struct sway_view_child_impl subsurface_impl; |
879 | 903 | ||
880 | static void subsurface_get_root_coords(struct sway_view_child *child, | 904 | static 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 | ||
906 | static void subsurface_destroy(struct sway_view_child *child) { | 919 | static 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 | ||
916 | static const struct sway_view_child_impl subsurface_impl = { | 929 | static 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 | ||
984 | static 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 | |||
971 | static void view_child_damage(struct sway_view_child *child, bool whole) { | 994 | static 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 | ||
982 | static void view_child_handle_surface_commit(struct wl_listener *listener, | 1007 | static 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, | |||
1004 | static void view_init_subsurfaces(struct sway_view *view, | 1029 | static 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 | ||
1042 | static 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 | |||
1012 | static void view_child_handle_surface_map(struct wl_listener *listener, | 1055 | static 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 | ||
1070 | void view_child_destroy(struct sway_view_child *child) { | 1113 | void 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 | ||