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.c764
1 files changed, 309 insertions, 455 deletions
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 7afcdf31..d6984178 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -6,6 +6,7 @@
6#include <wlr/types/wlr_buffer.h> 6#include <wlr/types/wlr_buffer.h>
7#include <wlr/types/wlr_output_layout.h> 7#include <wlr/types/wlr_output_layout.h>
8#include <wlr/types/wlr_server_decoration.h> 8#include <wlr/types/wlr_server_decoration.h>
9#include <wlr/types/wlr_subcompositor.h>
9#include <wlr/types/wlr_xdg_decoration_v1.h> 10#include <wlr/types/wlr_xdg_decoration_v1.h>
10#include "config.h" 11#include "config.h"
11#if HAVE_XWAYLAND 12#if HAVE_XWAYLAND
@@ -15,14 +16,16 @@
15#include "log.h" 16#include "log.h"
16#include "sway/criteria.h" 17#include "sway/criteria.h"
17#include "sway/commands.h" 18#include "sway/commands.h"
18#include "sway/desktop.h"
19#include "sway/desktop/transaction.h" 19#include "sway/desktop/transaction.h"
20#include "sway/desktop/idle_inhibit_v1.h" 20#include "sway/desktop/idle_inhibit_v1.h"
21#include "sway/desktop/launcher.h"
21#include "sway/input/cursor.h" 22#include "sway/input/cursor.h"
22#include "sway/ipc-server.h" 23#include "sway/ipc-server.h"
23#include "sway/output.h" 24#include "sway/output.h"
24#include "sway/input/seat.h" 25#include "sway/input/seat.h"
26#include "sway/scene_descriptor.h"
25#include "sway/server.h" 27#include "sway/server.h"
28#include "sway/sway_text_node.h"
26#include "sway/tree/arrange.h" 29#include "sway/tree/arrange.h"
27#include "sway/tree/container.h" 30#include "sway/tree/container.h"
28#include "sway/tree/view.h" 31#include "sway/tree/view.h"
@@ -32,15 +35,29 @@
32#include "pango.h" 35#include "pango.h"
33#include "stringop.h" 36#include "stringop.h"
34 37
35void view_init(struct sway_view *view, enum sway_view_type type, 38bool view_init(struct sway_view *view, enum sway_view_type type,
36 const struct sway_view_impl *impl) { 39 const struct sway_view_impl *impl) {
40 bool failed = false;
41 view->scene_tree = alloc_scene_tree(root->staging, &failed);
42 view->content_tree = alloc_scene_tree(view->scene_tree, &failed);
43
44 if (!failed && !scene_descriptor_assign(&view->scene_tree->node,
45 SWAY_SCENE_DESC_VIEW, view)) {
46 failed = true;
47 }
48
49 if (failed) {
50 wlr_scene_node_destroy(&view->scene_tree->node);
51 return false;
52 }
53
37 view->type = type; 54 view->type = type;
38 view->impl = impl; 55 view->impl = impl;
39 view->executed_criteria = create_list(); 56 view->executed_criteria = create_list();
40 wl_list_init(&view->saved_buffers);
41 view->allow_request_urgent = true; 57 view->allow_request_urgent = true;
42 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; 58 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
43 wl_signal_init(&view->events.unmap); 59 wl_signal_init(&view->events.unmap);
60 return true;
44} 61}
45 62
46void view_destroy(struct sway_view *view) { 63void view_destroy(struct sway_view *view) {
@@ -56,11 +73,11 @@ void view_destroy(struct sway_view *view) {
56 "(might have a pending transaction?)")) { 73 "(might have a pending transaction?)")) {
57 return; 74 return;
58 } 75 }
59 if (!wl_list_empty(&view->saved_buffers)) { 76 wl_list_remove(&view->events.unmap.listener_list);
60 view_remove_saved_buffer(view);
61 }
62 list_free(view->executed_criteria); 77 list_free(view->executed_criteria);
63 78
79 view_assign_ctx(view, NULL);
80 wlr_scene_node_destroy(&view->scene_tree->node);
64 free(view->title_format); 81 free(view->title_format);
65 82
66 if (view->impl->destroy) { 83 if (view->impl->destroy) {
@@ -206,7 +223,7 @@ bool view_ancestor_is_only_visible(struct sway_view *view) {
206 } else { 223 } else {
207 only_visible = true; 224 only_visible = true;
208 } 225 }
209 con = con->parent; 226 con = con->pending.parent;
210 } 227 }
211 return only_visible; 228 return only_visible;
212} 229}
@@ -222,72 +239,73 @@ static bool view_is_only_visible(struct sway_view *view) {
222 } 239 }
223 } 240 }
224 241
225 con = con->parent; 242 con = con->pending.parent;
226 } 243 }
227 244
228 return true; 245 return true;
229} 246}
230 247
231static bool gaps_to_edge(struct sway_view *view) { 248static bool gaps_to_edge(struct sway_view *view) {
232 struct side_gaps gaps = view->container->workspace->current_gaps; 249 struct side_gaps gaps = view->container->pending.workspace->current_gaps;
233 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0; 250 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0;
234} 251}
235 252
236void view_autoconfigure(struct sway_view *view) { 253void view_autoconfigure(struct sway_view *view) {
237 struct sway_container *con = view->container; 254 struct sway_container *con = view->container;
238 struct sway_workspace *ws = con->workspace; 255 struct sway_workspace *ws = con->pending.workspace;
239 256
240 if (container_is_scratchpad_hidden(con) && 257 if (container_is_scratchpad_hidden(con) &&
241 con->fullscreen_mode != FULLSCREEN_GLOBAL) { 258 con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
242 return; 259 return;
243 } 260 }
244 struct sway_output *output = ws ? ws->output : NULL; 261 struct sway_output *output = ws ? ws->output : NULL;
245 262
246 if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { 263 if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
247 con->content_x = output->lx; 264 con->pending.content_x = output->lx;
248 con->content_y = output->ly; 265 con->pending.content_y = output->ly;
249 con->content_width = output->width; 266 con->pending.content_width = output->width;
250 con->content_height = output->height; 267 con->pending.content_height = output->height;
251 return; 268 return;
252 } else if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { 269 } else if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
253 con->content_x = root->x; 270 con->pending.content_x = root->x;
254 con->content_y = root->y; 271 con->pending.content_y = root->y;
255 con->content_width = root->width; 272 con->pending.content_width = root->width;
256 con->content_height = root->height; 273 con->pending.content_height = root->height;
257 return; 274 return;
258 } 275 }
259 276
260 con->border_top = con->border_bottom = true; 277 con->pending.border_top = con->pending.border_bottom = true;
261 con->border_left = con->border_right = true; 278 con->pending.border_left = con->pending.border_right = true;
262 double y_offset = 0; 279 double y_offset = 0;
263 280
264 if (!container_is_floating(con) && ws) { 281 if (!container_is_floating_or_child(con) && ws) {
265 if (config->hide_edge_borders == E_BOTH 282 if (config->hide_edge_borders == E_BOTH
266 || config->hide_edge_borders == E_VERTICAL) { 283 || config->hide_edge_borders == E_VERTICAL) {
267 con->border_left = con->x != ws->x; 284 con->pending.border_left = con->pending.x != ws->x;
268 int right_x = con->x + con->width; 285 int right_x = con->pending.x + con->pending.width;
269 con->border_right = right_x != ws->x + ws->width; 286 con->pending.border_right = right_x != ws->x + ws->width;
270 } 287 }
271 288
272 if (config->hide_edge_borders == E_BOTH 289 if (config->hide_edge_borders == E_BOTH
273 || config->hide_edge_borders == E_HORIZONTAL) { 290 || config->hide_edge_borders == E_HORIZONTAL) {
274 con->border_top = con->y != ws->y; 291 con->pending.border_top = con->pending.y != ws->y;
275 int bottom_y = con->y + con->height; 292 int bottom_y = con->pending.y + con->pending.height;
276 con->border_bottom = bottom_y != ws->y + ws->height; 293 con->pending.border_bottom = bottom_y != ws->y + ws->height;
277 } 294 }
278 295
279 bool smart = config->hide_edge_borders_smart == ESMART_ON || 296 bool smart = config->hide_edge_borders_smart == ESMART_ON ||
280 (config->hide_edge_borders_smart == ESMART_NO_GAPS && 297 (config->hide_edge_borders_smart == ESMART_NO_GAPS &&
281 !gaps_to_edge(view)); 298 !gaps_to_edge(view));
282 if (smart) { 299 if (smart) {
283 bool show_border = container_is_floating_or_child(con) || 300 bool show_border = !view_is_only_visible(view);
284 !view_is_only_visible(view); 301 con->pending.border_left &= show_border;
285 con->border_left &= show_border; 302 con->pending.border_right &= show_border;
286 con->border_right &= show_border; 303 con->pending.border_top &= show_border;
287 con->border_top &= show_border; 304 con->pending.border_bottom &= show_border;
288 con->border_bottom &= show_border;
289 } 305 }
306 }
290 307
308 if (!container_is_floating(con)) {
291 // In a tabbed or stacked container, the container's y is the top of the 309 // 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, 310 // 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. 311 // bar, and disable any top border because we'll always have the title bar.
@@ -298,56 +316,56 @@ void view_autoconfigure(struct sway_view *view) {
298 enum sway_container_layout layout = container_parent_layout(con); 316 enum sway_container_layout layout = container_parent_layout(con);
299 if (layout == L_TABBED) { 317 if (layout == L_TABBED) {
300 y_offset = container_titlebar_height(); 318 y_offset = container_titlebar_height();
301 con->border_top = false; 319 con->pending.border_top = false;
302 } else if (layout == L_STACKED) { 320 } else if (layout == L_STACKED) {
303 y_offset = container_titlebar_height() * siblings->length; 321 y_offset = container_titlebar_height() * siblings->length;
304 con->border_top = false; 322 con->pending.border_top = false;
305 } 323 }
306 } 324 }
307 } 325 }
308 326
309 double x, y, width, height; 327 double x, y, width, height;
310 switch (con->border) { 328 switch (con->pending.border) {
311 default: 329 default:
312 case B_CSD: 330 case B_CSD:
313 case B_NONE: 331 case B_NONE:
314 x = con->x; 332 x = con->pending.x;
315 y = con->y + y_offset; 333 y = con->pending.y + y_offset;
316 width = con->width; 334 width = con->pending.width;
317 height = con->height - y_offset; 335 height = con->pending.height - y_offset;
318 break; 336 break;
319 case B_PIXEL: 337 case B_PIXEL:
320 x = con->x + con->border_thickness * con->border_left; 338 x = con->pending.x + con->pending.border_thickness * con->pending.border_left;
321 y = con->y + con->border_thickness * con->border_top + y_offset; 339 y = con->pending.y + con->pending.border_thickness * con->pending.border_top + y_offset;
322 width = con->width 340 width = con->pending.width
323 - con->border_thickness * con->border_left 341 - con->pending.border_thickness * con->pending.border_left
324 - con->border_thickness * con->border_right; 342 - con->pending.border_thickness * con->pending.border_right;
325 height = con->height - y_offset 343 height = con->pending.height - y_offset
326 - con->border_thickness * con->border_top 344 - con->pending.border_thickness * con->pending.border_top
327 - con->border_thickness * con->border_bottom; 345 - con->pending.border_thickness * con->pending.border_bottom;
328 break; 346 break;
329 case B_NORMAL: 347 case B_NORMAL:
330 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border 348 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
331 x = con->x + con->border_thickness * con->border_left; 349 x = con->pending.x + con->pending.border_thickness * con->pending.border_left;
332 width = con->width 350 width = con->pending.width
333 - con->border_thickness * con->border_left 351 - con->pending.border_thickness * con->pending.border_left
334 - con->border_thickness * con->border_right; 352 - con->pending.border_thickness * con->pending.border_right;
335 if (y_offset) { 353 if (y_offset) {
336 y = con->y + y_offset; 354 y = con->pending.y + y_offset;
337 height = con->height - y_offset 355 height = con->pending.height - y_offset
338 - con->border_thickness * con->border_bottom; 356 - con->pending.border_thickness * con->pending.border_bottom;
339 } else { 357 } else {
340 y = con->y + container_titlebar_height(); 358 y = con->pending.y + container_titlebar_height();
341 height = con->height - container_titlebar_height() 359 height = con->pending.height - container_titlebar_height()
342 - con->border_thickness * con->border_bottom; 360 - con->pending.border_thickness * con->pending.border_bottom;
343 } 361 }
344 break; 362 break;
345 } 363 }
346 364
347 con->content_x = x; 365 con->pending.content_x = x;
348 con->content_y = y; 366 con->pending.content_y = y;
349 con->content_width = width; 367 con->pending.content_width = width;
350 con->content_height = height; 368 con->pending.content_height = height;
351} 369}
352 370
353void view_set_activated(struct sway_view *view, bool activated) { 371void view_set_activated(struct sway_view *view, bool activated) {
@@ -360,17 +378,17 @@ void view_set_activated(struct sway_view *view, bool activated) {
360 } 378 }
361} 379}
362 380
363void view_request_activate(struct sway_view *view) { 381void view_request_activate(struct sway_view *view, struct sway_seat *seat) {
364 struct sway_workspace *ws = view->container->workspace; 382 struct sway_workspace *ws = view->container->pending.workspace;
365 if (!ws) { // hidden scratchpad container 383 if (!seat) {
366 return; 384 seat = input_manager_current_seat();
367 } 385 }
368 struct sway_seat *seat = input_manager_current_seat();
369 386
370 switch (config->focus_on_window_activation) { 387 switch (config->focus_on_window_activation) {
371 case FOWA_SMART: 388 case FOWA_SMART:
372 if (workspace_is_visible(ws)) { 389 if (ws && workspace_is_visible(ws)) {
373 seat_set_focus_container(seat, view->container); 390 seat_set_focus_container(seat, view->container);
391 container_raise_floating(view->container);
374 } else { 392 } else {
375 view_set_urgent(view, true); 393 view_set_urgent(view, true);
376 } 394 }
@@ -379,11 +397,17 @@ void view_request_activate(struct sway_view *view) {
379 view_set_urgent(view, true); 397 view_set_urgent(view, true);
380 break; 398 break;
381 case FOWA_FOCUS: 399 case FOWA_FOCUS:
382 seat_set_focus_container(seat, view->container); 400 if (container_is_scratchpad_hidden_or_child(view->container)) {
401 root_scratchpad_show(view->container);
402 } else {
403 seat_set_focus_container(seat, view->container);
404 container_raise_floating(view->container);
405 }
383 break; 406 break;
384 case FOWA_NONE: 407 case FOWA_NONE:
385 break; 408 break;
386 } 409 }
410 transaction_commit_dirty();
387} 411}
388 412
389void view_set_csd_from_server(struct sway_view *view, bool enabled) { 413void view_set_csd_from_server(struct sway_view *view, bool enabled) {
@@ -401,13 +425,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) { 425void view_update_csd_from_client(struct sway_view *view, bool enabled) {
402 sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled); 426 sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled);
403 struct sway_container *con = view->container; 427 struct sway_container *con = view->container;
404 if (enabled && con && con->border != B_CSD) { 428 if (enabled && con && con->pending.border != B_CSD) {
405 con->saved_border = con->border; 429 con->saved_border = con->pending.border;
406 if (container_is_floating(con)) { 430 if (container_is_floating(con)) {
407 con->border = B_CSD; 431 con->pending.border = B_CSD;
408 } 432 }
409 } else if (!enabled && con && con->border == B_CSD) { 433 } else if (!enabled && con && con->pending.border == B_CSD) {
410 con->border = con->saved_border; 434 con->pending.border = con->saved_border;
411 } 435 }
412 view->using_csd = enabled; 436 view->using_csd = enabled;
413} 437}
@@ -430,49 +454,6 @@ void view_close_popups(struct sway_view *view) {
430 } 454 }
431} 455}
432 456
433void view_damage_from(struct sway_view *view) {
434 for (int i = 0; i < root->outputs->length; ++i) {
435 struct sway_output *output = root->outputs->items[i];
436 output_damage_from_view(output, view);
437 }
438}
439
440void view_for_each_surface(struct sway_view *view,
441 wlr_surface_iterator_func_t iterator, void *user_data) {
442 if (!view->surface) {
443 return;
444 }
445 if (view->impl->for_each_surface) {
446 view->impl->for_each_surface(view, iterator, user_data);
447 } else {
448 wlr_surface_for_each_surface(view->surface, iterator, user_data);
449 }
450}
451
452void view_for_each_popup_surface(struct sway_view *view,
453 wlr_surface_iterator_func_t iterator, void *user_data) {
454 if (!view->surface) {
455 return;
456 }
457 if (view->impl->for_each_popup_surface) {
458 view->impl->for_each_popup_surface(view, iterator, user_data);
459 }
460}
461
462static void view_subsurface_create(struct sway_view *view,
463 struct wlr_subsurface *subsurface);
464
465static void view_init_subsurfaces(struct sway_view *view,
466 struct wlr_surface *surface);
467
468static void view_handle_surface_new_subsurface(struct wl_listener *listener,
469 void *data) {
470 struct sway_view *view =
471 wl_container_of(listener, view, surface_new_subsurface);
472 struct wlr_subsurface *subsurface = data;
473 view_subsurface_create(view, subsurface);
474}
475
476static bool view_has_executed_criteria(struct sway_view *view, 457static bool view_has_executed_criteria(struct sway_view *view,
477 struct criteria *criteria) { 458 struct criteria *criteria) {
478 for (int i = 0; i < view->executed_criteria->length; ++i) { 459 for (int i = 0; i < view->executed_criteria->length; ++i) {
@@ -514,7 +495,7 @@ static void view_populate_pid(struct sway_view *view) {
514#if HAVE_XWAYLAND 495#if HAVE_XWAYLAND
515 case SWAY_VIEW_XWAYLAND:; 496 case SWAY_VIEW_XWAYLAND:;
516 struct wlr_xwayland_surface *surf = 497 struct wlr_xwayland_surface *surf =
517 wlr_xwayland_surface_from_wlr_surface(view->surface); 498 wlr_xwayland_surface_try_from_wlr_surface(view->surface);
518 pid = surf->pid; 499 pid = surf->pid;
519 break; 500 break;
520#endif 501#endif
@@ -527,6 +508,20 @@ static void view_populate_pid(struct sway_view *view) {
527 view->pid = pid; 508 view->pid = pid;
528} 509}
529 510
511void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx) {
512 if (view->ctx) {
513 // This ctx has been replaced
514 launcher_ctx_destroy(view->ctx);
515 view->ctx = NULL;
516 }
517 if (ctx == NULL) {
518 return;
519 }
520 launcher_ctx_consume(ctx);
521
522 view->ctx = ctx;
523}
524
530static struct sway_workspace *select_workspace(struct sway_view *view) { 525static struct sway_workspace *select_workspace(struct sway_view *view) {
531 struct sway_seat *seat = input_manager_current_seat(); 526 struct sway_seat *seat = input_manager_current_seat();
532 527
@@ -562,13 +557,14 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
562 } 557 }
563 list_free(criterias); 558 list_free(criterias);
564 if (ws) { 559 if (ws) {
565 root_remove_workspace_pid(view->pid); 560 view_assign_ctx(view, NULL);
566 return ws; 561 return ws;
567 } 562 }
568 563
569 // Check if there's a PID mapping 564 // Check if there's a PID mapping
570 ws = root_workspace_for_pid(view->pid); 565 ws = view->ctx ? launcher_ctx_get_workspace(view->ctx) : NULL;
571 if (ws) { 566 if (ws) {
567 view_assign_ctx(view, NULL);
572 return ws; 568 return ws;
573 } 569 }
574 570
@@ -577,7 +573,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
577 if (node && node->type == N_WORKSPACE) { 573 if (node && node->type == N_WORKSPACE) {
578 return node->sway_workspace; 574 return node->sway_workspace;
579 } else if (node && node->type == N_CONTAINER) { 575 } else if (node && node->type == N_CONTAINER) {
580 return node->sway_container->workspace; 576 return node->sway_container->pending.workspace;
581 } 577 }
582 578
583 // When there's no outputs connected, the above should match a workspace on 579 // When there's no outputs connected, the above should match a workspace on
@@ -590,12 +586,17 @@ static bool should_focus(struct sway_view *view) {
590 struct sway_seat *seat = input_manager_current_seat(); 586 struct sway_seat *seat = input_manager_current_seat();
591 struct sway_container *prev_con = seat_get_focused_container(seat); 587 struct sway_container *prev_con = seat_get_focused_container(seat);
592 struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); 588 struct sway_workspace *prev_ws = seat_get_focused_workspace(seat);
593 struct sway_workspace *map_ws = view->container->workspace; 589 struct sway_workspace *map_ws = view->container->pending.workspace;
594 590
595 if (view->container->fullscreen_mode == FULLSCREEN_GLOBAL) { 591 if (view->container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
596 return true; 592 return true;
597 } 593 }
598 594
595 // View opened "under" fullscreen view should not be given focus.
596 if (root->fullscreen_global || !map_ws || map_ws->fullscreen) {
597 return false;
598 }
599
599 // Views can only take focus if they are mapped into the active workspace 600 // Views can only take focus if they are mapped into the active workspace
600 if (prev_ws != map_ws) { 601 if (prev_ws != map_ws) {
601 return false; 602 return false;
@@ -603,9 +604,9 @@ static bool should_focus(struct sway_view *view) {
603 604
604 // If the view is the only one in the focused workspace, it'll get focus 605 // If the view is the only one in the focused workspace, it'll get focus
605 // regardless of any no_focus criteria. 606 // regardless of any no_focus criteria.
606 if (!view->container->parent && !prev_con) { 607 if (!view->container->pending.parent && !prev_con) {
607 size_t num_children = view->container->workspace->tiling->length + 608 size_t num_children = view->container->pending.workspace->tiling->length +
608 view->container->workspace->floating->length; 609 view->container->pending.workspace->floating->length;
609 if (num_children == 1) { 610 if (num_children == 1) {
610 return true; 611 return true;
611 } 612 }
@@ -635,6 +636,7 @@ static void handle_foreign_activate_request(
635 break; 636 break;
636 } 637 }
637 } 638 }
639 transaction_commit_dirty();
638} 640}
639 641
640static void handle_foreign_fullscreen_request( 642static void handle_foreign_fullscreen_request(
@@ -645,9 +647,21 @@ static void handle_foreign_fullscreen_request(
645 647
646 // Match fullscreen command behavior for scratchpad hidden views 648 // Match fullscreen command behavior for scratchpad hidden views
647 struct sway_container *container = view->container; 649 struct sway_container *container = view->container;
648 if (!container->workspace) { 650 if (!container->pending.workspace) {
649 while (container->parent) { 651 while (container->pending.parent) {
650 container = container->parent; 652 container = container->pending.parent;
653 }
654 }
655
656 if (event->fullscreen && event->output && event->output->data) {
657 struct sway_output *output = event->output->data;
658 struct sway_workspace *ws = output_get_active_workspace(output);
659 if (ws && !container_is_scratchpad_hidden(view->container)) {
660 if (container_is_floating(view->container)) {
661 workspace_add_floating(ws, view->container);
662 } else {
663 workspace_add_tiling(ws, view->container);
664 }
651 } 665 }
652 } 666 }
653 667
@@ -656,12 +670,13 @@ static void handle_foreign_fullscreen_request(
656 if (event->fullscreen) { 670 if (event->fullscreen) {
657 arrange_root(); 671 arrange_root();
658 } else { 672 } else {
659 if (container->parent) { 673 if (container->pending.parent) {
660 arrange_container(container->parent); 674 arrange_container(container->pending.parent);
661 } else if (container->workspace) { 675 } else if (container->pending.workspace) {
662 arrange_workspace(container->workspace); 676 arrange_workspace(container->pending.workspace);
663 } 677 }
664 } 678 }
679 transaction_commit_dirty();
665} 680}
666 681
667static void handle_foreign_close_request( 682static void handle_foreign_close_request(
@@ -692,6 +707,13 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
692 view_populate_pid(view); 707 view_populate_pid(view);
693 view->container = container_create(view); 708 view->container = container_create(view);
694 709
710 if (view->ctx == NULL) {
711 struct launcher_ctx *ctx = launcher_ctx_find_pid(view->pid);
712 if (ctx != NULL) {
713 view_assign_ctx(view, ctx);
714 }
715 }
716
695 // If there is a request to be opened fullscreen on a specific output, try 717 // If there is a request to be opened fullscreen on a specific output, try
696 // to honor that request. Otherwise, fallback to assigns, pid mappings, 718 // to honor that request. Otherwise, fallback to assigns, pid mappings,
697 // focused workspace, etc 719 // focused workspace, etc
@@ -705,10 +727,29 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
705 } 727 }
706 728
707 struct sway_seat *seat = input_manager_current_seat(); 729 struct sway_seat *seat = input_manager_current_seat();
708 struct sway_node *node = ws ? seat_get_focus_inactive(seat, &ws->node) 730 struct sway_node *node =
709 : seat_get_focus_inactive(seat, &root->node); 731 seat_get_focus_inactive(seat, ws ? &ws->node : &root->node);
710 struct sway_container *target_sibling = node->type == N_CONTAINER ? 732 struct sway_container *target_sibling = NULL;
711 node->sway_container : NULL; 733 if (node && node->type == N_CONTAINER) {
734 if (container_is_floating(node->sway_container)) {
735 // If we're about to launch the view into the floating container, then
736 // launch it as a tiled view instead.
737 if (ws) {
738 target_sibling = seat_get_focus_inactive_tiling(seat, ws);
739 if (target_sibling) {
740 struct sway_container *con =
741 seat_get_focus_inactive_view(seat, &target_sibling->node);
742 if (con) {
743 target_sibling = con;
744 }
745 }
746 } else {
747 ws = seat_get_last_known_workspace(seat);
748 }
749 } else {
750 target_sibling = node->sway_container;
751 }
752 }
712 753
713 view->foreign_toplevel = 754 view->foreign_toplevel =
714 wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); 755 wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager);
@@ -725,13 +766,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
725 wl_signal_add(&view->foreign_toplevel->events.destroy, 766 wl_signal_add(&view->foreign_toplevel->events.destroy,
726 &view->foreign_destroy); 767 &view->foreign_destroy);
727 768
728 // If we're about to launch the view into the floating container, then
729 // launch it as a tiled view in the root of the workspace instead.
730 if (target_sibling && container_is_floating(target_sibling)) {
731 target_sibling = NULL;
732 ws = seat_get_last_known_workspace(seat);
733 }
734
735 struct sway_container *container = view->container; 769 struct sway_container *container = view->container;
736 if (target_sibling) { 770 if (target_sibling) {
737 container_add_sibling(target_sibling, container, 1); 771 container_add_sibling(target_sibling, container, 1);
@@ -740,30 +774,25 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
740 } 774 }
741 ipc_event_window(view->container, "new"); 775 ipc_event_window(view->container, "new");
742 776
743 view_init_subsurfaces(view, wlr_surface);
744 wl_signal_add(&wlr_surface->events.new_subsurface,
745 &view->surface_new_subsurface);
746 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface;
747
748 if (decoration) { 777 if (decoration) {
749 view_update_csd_from_client(view, decoration); 778 view_update_csd_from_client(view, decoration);
750 } 779 }
751 780
752 if (view->impl->wants_floating && view->impl->wants_floating(view)) { 781 if (view->impl->wants_floating && view->impl->wants_floating(view)) {
753 view->container->border = config->floating_border; 782 view->container->pending.border = config->floating_border;
754 view->container->border_thickness = config->floating_border_thickness; 783 view->container->pending.border_thickness = config->floating_border_thickness;
755 container_set_floating(view->container, true); 784 container_set_floating(view->container, true);
756 } else { 785 } else {
757 view->container->border = config->border; 786 view->container->pending.border = config->border;
758 view->container->border_thickness = config->border_thickness; 787 view->container->pending.border_thickness = config->border_thickness;
759 view_set_tiled(view, true); 788 view_set_tiled(view, true);
760 } 789 }
761 790
762 if (config->popup_during_fullscreen == POPUP_LEAVE && 791 if (config->popup_during_fullscreen == POPUP_LEAVE &&
763 container->workspace && 792 container->pending.workspace &&
764 container->workspace->fullscreen && 793 container->pending.workspace->fullscreen &&
765 container->workspace->fullscreen->view) { 794 container->pending.workspace->fullscreen->view) {
766 struct sway_container *fs = container->workspace->fullscreen; 795 struct sway_container *fs = container->pending.workspace->fullscreen;
767 if (view_is_transient_for(view, fs->view)) { 796 if (view_is_transient_for(view, fs->view)) {
768 container_set_fullscreen(fs, false); 797 container_set_fullscreen(fs, false);
769 } 798 }
@@ -774,12 +803,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
774 803
775 if (fullscreen) { 804 if (fullscreen) {
776 container_set_fullscreen(view->container, true); 805 container_set_fullscreen(view->container, true);
777 arrange_workspace(view->container->workspace); 806 arrange_workspace(view->container->pending.workspace);
778 } else { 807 } else {
779 if (container->parent) { 808 if (container->pending.parent) {
780 arrange_container(container->parent); 809 arrange_container(container->pending.parent);
781 } else if (container->workspace) { 810 } else if (container->pending.workspace) {
782 arrange_workspace(container->workspace); 811 arrange_workspace(container->pending.workspace);
783 } 812 }
784 } 813 }
785 814
@@ -788,11 +817,10 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
788 bool set_focus = should_focus(view); 817 bool set_focus = should_focus(view);
789 818
790#if HAVE_XWAYLAND 819#if HAVE_XWAYLAND
791 if (wlr_surface_is_xwayland_surface(wlr_surface)) { 820 struct wlr_xwayland_surface *xsurface;
792 struct wlr_xwayland_surface *xsurface = 821 if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) {
793 wlr_xwayland_surface_from_wlr_surface(wlr_surface); 822 set_focus &= wlr_xwayland_icccm_input_model(xsurface) !=
794 set_focus = (wlr_xwayland_icccm_input_model(xsurface) != 823 WLR_ICCCM_INPUT_MODEL_NONE;
795 WLR_ICCCM_INPUT_MODEL_NONE) && set_focus;
796 } 824 }
797#endif 825#endif
798 826
@@ -803,18 +831,16 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
803 const char *app_id; 831 const char *app_id;
804 const char *class; 832 const char *class;
805 if ((app_id = view_get_app_id(view)) != NULL) { 833 if ((app_id = view_get_app_id(view)) != NULL) {
806 wlr_foreign_toplevel_handle_v1_set_app_id( 834 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) { 835 } else if ((class = view_get_class(view)) != NULL) {
809 wlr_foreign_toplevel_handle_v1_set_app_id( 836 wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, class);
810 view->foreign_toplevel, class);
811 } 837 }
812} 838}
813 839
814void view_unmap(struct sway_view *view) { 840void view_unmap(struct sway_view *view) {
815 wl_signal_emit(&view->events.unmap, view); 841 wl_signal_emit_mutable(&view->events.unmap, view);
816 842
817 wl_list_remove(&view->surface_new_subsurface.link); 843 view->executed_criteria->length = 0;
818 844
819 if (view->urgent_timer) { 845 if (view->urgent_timer) {
820 wl_event_source_remove(view->urgent_timer); 846 wl_event_source_remove(view->urgent_timer);
@@ -826,8 +852,8 @@ void view_unmap(struct sway_view *view) {
826 view->foreign_toplevel = NULL; 852 view->foreign_toplevel = NULL;
827 } 853 }
828 854
829 struct sway_container *parent = view->container->parent; 855 struct sway_container *parent = view->container->pending.parent;
830 struct sway_workspace *ws = view->container->workspace; 856 struct sway_workspace *ws = view->container->pending.workspace;
831 container_begin_destroy(view->container); 857 container_begin_destroy(view->container);
832 if (parent) { 858 if (parent) {
833 container_reap_empty(parent); 859 container_reap_empty(parent);
@@ -860,262 +886,54 @@ void view_unmap(struct sway_view *view) {
860 view->surface = NULL; 886 view->surface = NULL;
861} 887}
862 888
863void view_update_size(struct sway_view *view, int width, int height) { 889void view_update_size(struct sway_view *view) {
864 struct sway_container *con = view->container; 890 struct sway_container *con = view->container;
865 891 con->pending.content_width = view->geometry.width;
866 if (container_is_floating(con)) { 892 con->pending.content_height = view->geometry.height;
867 con->content_width = width; 893 container_set_geometry_from_content(con);
868 con->content_height = height;
869 container_set_geometry_from_content(con);
870 } else {
871 con->surface_x = con->content_x + (con->content_width - width) / 2;
872 con->surface_y = con->content_y + (con->content_height - height) / 2;
873 con->surface_x = fmax(con->surface_x, con->content_x);
874 con->surface_y = fmax(con->surface_y, con->content_y);
875 }
876} 894}
877 895
878static const struct sway_view_child_impl subsurface_impl; 896void view_center_and_clip_surface(struct sway_view *view) {
897 struct sway_container *con = view->container;
879 898
880static void subsurface_get_root_coords(struct sway_view_child *child, 899 if (container_is_floating(con)) {
881 int *root_sx, int *root_sy) { 900 // We always center the current coordinates rather than the next, as the
882 struct wlr_surface *surface = child->surface; 901 // geometry immediately affects the currently active rendering.
883 *root_sx = -child->view->geometry.x; 902 int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2);
884 *root_sy = -child->view->geometry.y; 903 int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2);
885 904
886 if (child->parent && child->parent->impl && 905 wlr_scene_node_set_position(&view->content_tree->node, x, y);
887 child->parent->impl->get_root_coords) {
888 int sx, sy;
889 child->parent->impl->get_root_coords(child->parent, &sx, &sy);
890 *root_sx += sx;
891 *root_sy += sy;
892 } else { 906 } else {
893 while (surface && wlr_surface_is_subsurface(surface)) { 907 wlr_scene_node_set_position(&view->content_tree->node, 0, 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 }
904}
905
906static void subsurface_destroy(struct sway_view_child *child) {
907 if (!sway_assert(child->impl == &subsurface_impl,
908 "Expected a subsurface")) {
909 return;
910 }
911 struct sway_subsurface *subsurface = (struct sway_subsurface *)child;
912 wl_list_remove(&subsurface->destroy.link);
913 free(subsurface);
914}
915
916static const struct sway_view_child_impl subsurface_impl = {
917 .get_root_coords = subsurface_get_root_coords,
918 .destroy = subsurface_destroy,
919};
920
921static void subsurface_handle_destroy(struct wl_listener *listener,
922 void *data) {
923 struct sway_subsurface *subsurface =
924 wl_container_of(listener, subsurface, destroy);
925 struct sway_view_child *child = &subsurface->child;
926 view_child_destroy(child);
927}
928
929static void view_child_damage(struct sway_view_child *child, bool whole);
930
931static void view_subsurface_create(struct sway_view *view,
932 struct wlr_subsurface *wlr_subsurface) {
933 struct sway_subsurface *subsurface =
934 calloc(1, sizeof(struct sway_subsurface));
935 if (subsurface == NULL) {
936 sway_log(SWAY_ERROR, "Allocation failed");
937 return;
938 }
939 view_child_init(&subsurface->child, &subsurface_impl, view,
940 wlr_subsurface->surface);
941
942 wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
943 subsurface->destroy.notify = subsurface_handle_destroy;
944
945 subsurface->child.mapped = true;
946
947 view_child_damage(&subsurface->child, true);
948}
949
950static void view_child_subsurface_create(struct sway_view_child *child,
951 struct wlr_subsurface *wlr_subsurface) {
952 struct sway_subsurface *subsurface =
953 calloc(1, sizeof(struct sway_subsurface));
954 if (subsurface == NULL) {
955 sway_log(SWAY_ERROR, "Allocation failed");
956 return;
957 }
958 subsurface->child.parent = child;
959 wl_list_insert(&child->children, &subsurface->child.link);
960 view_child_init(&subsurface->child, &subsurface_impl, child->view,
961 wlr_subsurface->surface);
962
963 wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
964 subsurface->destroy.notify = subsurface_handle_destroy;
965
966 subsurface->child.mapped = true;
967
968 view_child_damage(&subsurface->child, true);
969}
970
971static void view_child_damage(struct sway_view_child *child, bool whole) {
972 if (!child || !child->mapped || !child->view || !child->view->container) {
973 return;
974 } 908 }
975 int sx, sy;
976 child->impl->get_root_coords(child, &sx, &sy);
977 desktop_damage_surface(child->surface,
978 child->view->container->content_x + sx,
979 child->view->container->content_y + sy, whole);
980}
981
982static void view_child_handle_surface_commit(struct wl_listener *listener,
983 void *data) {
984 struct sway_view_child *child =
985 wl_container_of(listener, child, surface_commit);
986 view_child_damage(child, false);
987}
988 909
989static void view_child_handle_surface_new_subsurface( 910 // only make sure to clip the content if there is content to clip
990 struct wl_listener *listener, void *data) { 911 if (!wl_list_empty(&con->view->content_tree->children)) {
991 struct sway_view_child *child = 912 wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &(struct wlr_box){
992 wl_container_of(listener, child, surface_new_subsurface); 913 .x = con->view->geometry.x,
993 struct wlr_subsurface *subsurface = data; 914 .y = con->view->geometry.y,
994 view_child_subsurface_create(child, subsurface); 915 .width = con->current.content_width,
995} 916 .height = con->current.content_height,
996 917 });
997static void view_child_handle_surface_destroy(struct wl_listener *listener,
998 void *data) {
999 struct sway_view_child *child =
1000 wl_container_of(listener, child, surface_destroy);
1001 view_child_destroy(child);
1002}
1003
1004static void view_init_subsurfaces(struct sway_view *view,
1005 struct wlr_surface *surface) {
1006 struct wlr_subsurface *subsurface;
1007 wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
1008 view_subsurface_create(view, subsurface);
1009 }
1010}
1011
1012static void view_child_handle_surface_map(struct wl_listener *listener,
1013 void *data) {
1014 struct sway_view_child *child =
1015 wl_container_of(listener, child, surface_map);
1016 child->mapped = true;
1017 view_child_damage(child, true);
1018}
1019
1020static void view_child_handle_surface_unmap(struct wl_listener *listener,
1021 void *data) {
1022 struct sway_view_child *child =
1023 wl_container_of(listener, child, surface_unmap);
1024 view_child_damage(child, true);
1025 child->mapped = false;
1026}
1027
1028static void view_child_handle_view_unmap(struct wl_listener *listener,
1029 void *data) {
1030 struct sway_view_child *child =
1031 wl_container_of(listener, child, view_unmap);
1032 view_child_damage(child, true);
1033 child->mapped = false;
1034}
1035
1036void view_child_init(struct sway_view_child *child,
1037 const struct sway_view_child_impl *impl, struct sway_view *view,
1038 struct wlr_surface *surface) {
1039 child->impl = impl;
1040 child->view = view;
1041 child->surface = surface;
1042 wl_list_init(&child->children);
1043
1044 wl_signal_add(&surface->events.commit, &child->surface_commit);
1045 child->surface_commit.notify = view_child_handle_surface_commit;
1046 wl_signal_add(&surface->events.new_subsurface,
1047 &child->surface_new_subsurface);
1048 child->surface_new_subsurface.notify =
1049 view_child_handle_surface_new_subsurface;
1050 wl_signal_add(&surface->events.destroy, &child->surface_destroy);
1051 child->surface_destroy.notify = view_child_handle_surface_destroy;
1052
1053 // Not all child views have a map/unmap event
1054 child->surface_map.notify = view_child_handle_surface_map;
1055 wl_list_init(&child->surface_map.link);
1056 child->surface_unmap.notify = view_child_handle_surface_unmap;
1057 wl_list_init(&child->surface_unmap.link);
1058
1059 wl_signal_add(&view->events.unmap, &child->view_unmap);
1060 child->view_unmap.notify = view_child_handle_view_unmap;
1061
1062 struct sway_workspace *workspace = child->view->container->workspace;
1063 if (workspace) {
1064 wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
1065 }
1066
1067 view_init_subsurfaces(child->view, surface);
1068}
1069
1070void view_child_destroy(struct sway_view_child *child) {
1071 if (child->mapped && child->view->container != NULL) {
1072 view_child_damage(child, true);
1073 }
1074
1075 if (child->parent != NULL) {
1076 wl_list_remove(&child->link);
1077 child->parent = NULL;
1078 }
1079
1080 struct sway_view_child *subchild, *tmpchild;
1081 wl_list_for_each_safe(subchild, tmpchild, &child->children, link) {
1082 wl_list_remove(&subchild->link);
1083 subchild->parent = NULL;
1084 }
1085
1086 wl_list_remove(&child->surface_commit.link);
1087 wl_list_remove(&child->surface_destroy.link);
1088 wl_list_remove(&child->surface_map.link);
1089 wl_list_remove(&child->surface_unmap.link);
1090 wl_list_remove(&child->view_unmap.link);
1091 wl_list_remove(&child->surface_new_subsurface.link);
1092
1093 if (child->impl && child->impl->destroy) {
1094 child->impl->destroy(child);
1095 } else {
1096 free(child);
1097 } 918 }
1098} 919}
1099 920
1100struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { 921struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
1101 if (wlr_surface_is_xdg_surface(wlr_surface)) { 922 struct wlr_xdg_surface *xdg_surface;
1102 struct wlr_xdg_surface *xdg_surface = 923 if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) {
1103 wlr_xdg_surface_from_wlr_surface(wlr_surface);
1104 return view_from_wlr_xdg_surface(xdg_surface); 924 return view_from_wlr_xdg_surface(xdg_surface);
1105 } 925 }
1106#if HAVE_XWAYLAND 926#if HAVE_XWAYLAND
1107 if (wlr_surface_is_xwayland_surface(wlr_surface)) { 927 struct wlr_xwayland_surface *xsurface;
1108 struct wlr_xwayland_surface *xsurface = 928 if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) {
1109 wlr_xwayland_surface_from_wlr_surface(wlr_surface);
1110 return view_from_wlr_xwayland_surface(xsurface); 929 return view_from_wlr_xwayland_surface(xsurface);
1111 } 930 }
1112#endif 931#endif
1113 if (wlr_surface_is_subsurface(wlr_surface)) { 932 struct wlr_subsurface *subsurface;
1114 struct wlr_subsurface *subsurface = 933 if ((subsurface = wlr_subsurface_try_from_wlr_surface(wlr_surface))) {
1115 wlr_subsurface_from_wlr_surface(wlr_surface);
1116 return view_from_wlr_surface(subsurface->parent); 934 return view_from_wlr_surface(subsurface->parent);
1117 } 935 }
1118 if (wlr_surface_is_layer_surface(wlr_surface)) { 936 if (wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface) != NULL) {
1119 return NULL; 937 return NULL;
1120 } 938 }
1121 939
@@ -1211,25 +1029,31 @@ void view_update_title(struct sway_view *view, bool force) {
1211 1029
1212 free(view->container->title); 1030 free(view->container->title);
1213 free(view->container->formatted_title); 1031 free(view->container->formatted_title);
1214 if (title) { 1032
1215 size_t len = parse_title_format(view, NULL); 1033 size_t len = parse_title_format(view, NULL);
1034
1035 if (len) {
1216 char *buffer = calloc(len + 1, sizeof(char)); 1036 char *buffer = calloc(len + 1, sizeof(char));
1217 if (!sway_assert(buffer, "Unable to allocate title string")) { 1037 if (!sway_assert(buffer, "Unable to allocate title string")) {
1218 return; 1038 return;
1219 } 1039 }
1220 parse_title_format(view, buffer);
1221 1040
1222 view->container->title = strdup(title); 1041 parse_title_format(view, buffer);
1223 view->container->formatted_title = buffer; 1042 view->container->formatted_title = buffer;
1224 } else { 1043 } else {
1225 view->container->title = NULL;
1226 view->container->formatted_title = NULL; 1044 view->container->formatted_title = NULL;
1227 } 1045 }
1228 container_calculate_title_height(view->container); 1046
1229 config_update_font_height(false); 1047 view->container->title = title ? strdup(title) : NULL;
1230 1048
1231 // Update title after the global font height is updated 1049 // Update title after the global font height is updated
1232 container_update_title_textures(view->container); 1050 if (view->container->title_bar.title_text && len) {
1051 sway_text_node_set_text(view->container->title_bar.title_text,
1052 view->container->formatted_title);
1053 container_arrange_title_bar(view->container);
1054 } else {
1055 container_update_title_bar(view->container);
1056 }
1233 1057
1234 ipc_event_window(view->container, "title"); 1058 ipc_event_window(view->container, "title");
1235 1059
@@ -1242,15 +1066,15 @@ bool view_is_visible(struct sway_view *view) {
1242 if (view->container->node.destroying) { 1066 if (view->container->node.destroying) {
1243 return false; 1067 return false;
1244 } 1068 }
1245 struct sway_workspace *workspace = view->container->workspace; 1069 struct sway_workspace *workspace = view->container->pending.workspace;
1246 if (!workspace && view->container->fullscreen_mode != FULLSCREEN_GLOBAL) { 1070 if (!workspace && view->container->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
1247 bool fs_global_descendant = false; 1071 bool fs_global_descendant = false;
1248 struct sway_container *parent = view->container->parent; 1072 struct sway_container *parent = view->container->pending.parent;
1249 while (parent) { 1073 while (parent) {
1250 if (parent->fullscreen_mode == FULLSCREEN_GLOBAL) { 1074 if (parent->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
1251 fs_global_descendant = true; 1075 fs_global_descendant = true;
1252 } 1076 }
1253 parent = parent->parent; 1077 parent = parent->pending.parent;
1254 } 1078 }
1255 if (!fs_global_descendant) { 1079 if (!fs_global_descendant) {
1256 return false; 1080 return false;
@@ -1268,13 +1092,13 @@ bool view_is_visible(struct sway_view *view) {
1268 enum sway_container_layout layout = container_parent_layout(con); 1092 enum sway_container_layout layout = container_parent_layout(con);
1269 if ((layout == L_TABBED || layout == L_STACKED) 1093 if ((layout == L_TABBED || layout == L_STACKED)
1270 && !container_is_floating(con)) { 1094 && !container_is_floating(con)) {
1271 struct sway_node *parent = con->parent ? 1095 struct sway_node *parent = con->pending.parent ?
1272 &con->parent->node : &con->workspace->node; 1096 &con->pending.parent->node : &con->pending.workspace->node;
1273 if (seat_get_active_tiling_child(seat, parent) != &con->node) { 1097 if (seat_get_active_tiling_child(seat, parent) != &con->node) {
1274 return false; 1098 return false;
1275 } 1099 }
1276 } 1100 }
1277 con = con->parent; 1101 con = con->pending.parent;
1278 } 1102 }
1279 // Check view isn't hidden by another fullscreen view 1103 // Check view isn't hidden by another fullscreen view
1280 struct sway_container *fs = root->fullscreen_global ? 1104 struct sway_container *fs = root->fullscreen_global ?
@@ -1296,6 +1120,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
1296 return; 1120 return;
1297 } 1121 }
1298 clock_gettime(CLOCK_MONOTONIC, &view->urgent); 1122 clock_gettime(CLOCK_MONOTONIC, &view->urgent);
1123 container_update_itself_and_parents(view->container);
1299 } else { 1124 } else {
1300 view->urgent = (struct timespec){ 0 }; 1125 view->urgent = (struct timespec){ 0 };
1301 if (view->urgent_timer) { 1126 if (view->urgent_timer) {
@@ -1303,12 +1128,11 @@ void view_set_urgent(struct sway_view *view, bool enable) {
1303 view->urgent_timer = NULL; 1128 view->urgent_timer = NULL;
1304 } 1129 }
1305 } 1130 }
1306 container_damage_whole(view->container);
1307 1131
1308 ipc_event_window(view->container, "urgent"); 1132 ipc_event_window(view->container, "urgent");
1309 1133
1310 if (!container_is_scratchpad_hidden(view->container)) { 1134 if (!container_is_scratchpad_hidden(view->container)) {
1311 workspace_detect_urgent(view->container->workspace); 1135 workspace_detect_urgent(view->container->pending.workspace);
1312 } 1136 }
1313} 1137}
1314 1138
@@ -1317,40 +1141,54 @@ bool view_is_urgent(struct sway_view *view) {
1317} 1141}
1318 1142
1319void view_remove_saved_buffer(struct sway_view *view) { 1143void view_remove_saved_buffer(struct sway_view *view) {
1320 if (!sway_assert(!wl_list_empty(&view->saved_buffers), "Expected a saved buffer")) { 1144 if (!sway_assert(view->saved_surface_tree, "Expected a saved buffer")) {
1321 return; 1145 return;
1322 } 1146 }
1323 struct sway_saved_buffer *saved_buf, *tmp; 1147
1324 wl_list_for_each_safe(saved_buf, tmp, &view->saved_buffers, link) { 1148 wlr_scene_node_destroy(&view->saved_surface_tree->node);
1325 wlr_buffer_unlock(&saved_buf->buffer->base); 1149 view->saved_surface_tree = NULL;
1326 wl_list_remove(&saved_buf->link); 1150 wlr_scene_node_set_enabled(&view->content_tree->node, true);
1327 free(saved_buf);
1328 }
1329} 1151}
1330 1152
1331static void view_save_buffer_iterator(struct wlr_surface *surface, 1153static void view_save_buffer_iterator(struct wlr_scene_buffer *buffer,
1332 int sx, int sy, void *data) { 1154 int sx, int sy, void *data) {
1333 struct sway_view *view = data; 1155 struct wlr_scene_tree *tree = data;
1334 1156
1335 if (surface && wlr_surface_has_buffer(surface)) { 1157 struct wlr_scene_buffer *sbuf = wlr_scene_buffer_create(tree, NULL);
1336 wlr_buffer_lock(&surface->buffer->base); 1158 if (!sbuf) {
1337 struct sway_saved_buffer *saved_buffer = calloc(1, sizeof(struct sway_saved_buffer)); 1159 sway_log(SWAY_ERROR, "Could not allocate a scene buffer when saving a surface");
1338 saved_buffer->buffer = surface->buffer; 1160 return;
1339 saved_buffer->width = surface->current.width;
1340 saved_buffer->height = surface->current.height;
1341 saved_buffer->x = sx;
1342 saved_buffer->y = sy;
1343 saved_buffer->transform = surface->current.transform;
1344 wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box);
1345 wl_list_insert(&view->saved_buffers, &saved_buffer->link);
1346 } 1161 }
1162
1163 wlr_scene_buffer_set_dest_size(sbuf,
1164 buffer->dst_width, buffer->dst_height);
1165 wlr_scene_buffer_set_opaque_region(sbuf, &buffer->opaque_region);
1166 wlr_scene_buffer_set_source_box(sbuf, &buffer->src_box);
1167 wlr_scene_node_set_position(&sbuf->node, sx, sy);
1168 wlr_scene_buffer_set_transform(sbuf, buffer->transform);
1169 wlr_scene_buffer_set_buffer(sbuf, buffer->buffer);
1347} 1170}
1348 1171
1349void view_save_buffer(struct sway_view *view) { 1172void view_save_buffer(struct sway_view *view) {
1350 if (!sway_assert(wl_list_empty(&view->saved_buffers), "Didn't expect saved buffer")) { 1173 if (!sway_assert(!view->saved_surface_tree, "Didn't expect saved buffer")) {
1351 view_remove_saved_buffer(view); 1174 view_remove_saved_buffer(view);
1352 } 1175 }
1353 view_for_each_surface(view, view_save_buffer_iterator, view); 1176
1177 view->saved_surface_tree = wlr_scene_tree_create(view->scene_tree);
1178 if (!view->saved_surface_tree) {
1179 sway_log(SWAY_ERROR, "Could not allocate a scene tree node when saving a surface");
1180 return;
1181 }
1182
1183 // Enable and disable the saved surface tree like so to atomitaclly update
1184 // the tree. This will prevent over damaging or other weirdness.
1185 wlr_scene_node_set_enabled(&view->saved_surface_tree->node, false);
1186
1187 wlr_scene_node_for_each_buffer(&view->content_tree->node,
1188 view_save_buffer_iterator, view->saved_surface_tree);
1189
1190 wlr_scene_node_set_enabled(&view->content_tree->node, false);
1191 wlr_scene_node_set_enabled(&view->saved_surface_tree->node, true);
1354} 1192}
1355 1193
1356bool view_is_transient_for(struct sway_view *child, 1194bool view_is_transient_for(struct sway_view *child,
@@ -1358,3 +1196,19 @@ bool view_is_transient_for(struct sway_view *child,
1358 return child->impl->is_transient_for && 1196 return child->impl->is_transient_for &&
1359 child->impl->is_transient_for(child, ancestor); 1197 child->impl->is_transient_for(child, ancestor);
1360} 1198}
1199
1200static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
1201 int x, int y, void *data) {
1202 struct timespec *when = data;
1203 wl_signal_emit_mutable(&scene_buffer->events.frame_done, when);
1204}
1205
1206void view_send_frame_done(struct sway_view *view) {
1207 struct timespec when;
1208 clock_gettime(CLOCK_MONOTONIC, &when);
1209
1210 struct wlr_scene_node *node;
1211 wl_list_for_each(node, &view->content_tree->children, link) {
1212 wlr_scene_node_for_each_buffer(node, send_frame_done_iterator, &when);
1213 }
1214}