diff options
Diffstat (limited to 'sway/desktop/transaction.c')
-rw-r--r-- | sway/desktop/transaction.c | 500 |
1 files changed, 441 insertions, 59 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index f5a3a053..042141ab 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -1,11 +1,10 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | 1 | #include <stdbool.h> |
3 | #include <stdlib.h> | 2 | #include <stdlib.h> |
4 | #include <string.h> | 3 | #include <string.h> |
5 | #include <time.h> | 4 | #include <time.h> |
6 | #include <wlr/types/wlr_buffer.h> | 5 | #include <wlr/types/wlr_buffer.h> |
7 | #include "sway/config.h" | 6 | #include "sway/config.h" |
8 | #include "sway/desktop.h" | 7 | #include "sway/scene_descriptor.h" |
9 | #include "sway/desktop/idle_inhibit_v1.h" | 8 | #include "sway/desktop/idle_inhibit_v1.h" |
10 | #include "sway/desktop/transaction.h" | 9 | #include "sway/desktop/transaction.h" |
11 | #include "sway/input/cursor.h" | 10 | #include "sway/input/cursor.h" |
@@ -214,39 +213,20 @@ static void transaction_add_node(struct sway_transaction *transaction, | |||
214 | 213 | ||
215 | static void apply_output_state(struct sway_output *output, | 214 | static void apply_output_state(struct sway_output *output, |
216 | struct sway_output_state *state) { | 215 | struct sway_output_state *state) { |
217 | output_damage_whole(output); | ||
218 | list_free(output->current.workspaces); | 216 | list_free(output->current.workspaces); |
219 | memcpy(&output->current, state, sizeof(struct sway_output_state)); | 217 | memcpy(&output->current, state, sizeof(struct sway_output_state)); |
220 | output_damage_whole(output); | ||
221 | } | 218 | } |
222 | 219 | ||
223 | static void apply_workspace_state(struct sway_workspace *ws, | 220 | static void apply_workspace_state(struct sway_workspace *ws, |
224 | struct sway_workspace_state *state) { | 221 | struct sway_workspace_state *state) { |
225 | output_damage_whole(ws->current.output); | ||
226 | list_free(ws->current.floating); | 222 | list_free(ws->current.floating); |
227 | list_free(ws->current.tiling); | 223 | list_free(ws->current.tiling); |
228 | memcpy(&ws->current, state, sizeof(struct sway_workspace_state)); | 224 | memcpy(&ws->current, state, sizeof(struct sway_workspace_state)); |
229 | output_damage_whole(ws->current.output); | ||
230 | } | 225 | } |
231 | 226 | ||
232 | static void apply_container_state(struct sway_container *container, | 227 | static void apply_container_state(struct sway_container *container, |
233 | struct sway_container_state *state) { | 228 | struct sway_container_state *state) { |
234 | struct sway_view *view = container->view; | 229 | struct sway_view *view = container->view; |
235 | // Damage the old location | ||
236 | desktop_damage_whole_container(container); | ||
237 | if (view && !wl_list_empty(&view->saved_buffers)) { | ||
238 | struct sway_saved_buffer *saved_buf; | ||
239 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { | ||
240 | struct wlr_box box = { | ||
241 | .x = saved_buf->x - view->saved_geometry.x, | ||
242 | .y = saved_buf->y - view->saved_geometry.y, | ||
243 | .width = saved_buf->width, | ||
244 | .height = saved_buf->height, | ||
245 | }; | ||
246 | desktop_damage_box(&box); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | // There are separate children lists for each instruction state, the | 230 | // There are separate children lists for each instruction state, the |
251 | // container's current state and the container's pending state | 231 | // container's current state and the container's pending state |
252 | // (ie. con->children). The list itself needs to be freed here. | 232 | // (ie. con->children). The list itself needs to be freed here. |
@@ -256,35 +236,443 @@ static void apply_container_state(struct sway_container *container, | |||
256 | 236 | ||
257 | memcpy(&container->current, state, sizeof(struct sway_container_state)); | 237 | memcpy(&container->current, state, sizeof(struct sway_container_state)); |
258 | 238 | ||
259 | if (view && !wl_list_empty(&view->saved_buffers)) { | 239 | if (view) { |
260 | if (!container->node.destroying || container->node.ntxnrefs == 1) { | 240 | if (view->saved_surface_tree) { |
261 | view_remove_saved_buffer(view); | 241 | if (!container->node.destroying || container->node.ntxnrefs == 1) { |
242 | view_remove_saved_buffer(view); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | // If the view hasn't responded to the configure, center it within | ||
247 | // the container. This is important for fullscreen views which | ||
248 | // refuse to resize to the size of the output. | ||
249 | if (view->surface) { | ||
250 | view_center_and_clip_surface(view); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | |||
255 | static void arrange_title_bar(struct sway_container *con, | ||
256 | int x, int y, int width, int height) { | ||
257 | container_update(con); | ||
258 | |||
259 | bool has_title_bar = height > 0; | ||
260 | wlr_scene_node_set_enabled(&con->title_bar.tree->node, has_title_bar); | ||
261 | if (!has_title_bar) { | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | wlr_scene_node_set_position(&con->title_bar.tree->node, x, y); | ||
266 | |||
267 | con->title_width = width; | ||
268 | container_arrange_title_bar(con); | ||
269 | } | ||
270 | |||
271 | static void disable_container(struct sway_container *con) { | ||
272 | if (con->view) { | ||
273 | wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree); | ||
274 | } else { | ||
275 | for (int i = 0; i < con->current.children->length; i++) { | ||
276 | struct sway_container *child = con->current.children->items[i]; | ||
277 | |||
278 | wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree); | ||
279 | |||
280 | disable_container(child); | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void arrange_container(struct sway_container *con, | ||
286 | int width, int height, bool title_bar, int gaps); | ||
287 | |||
288 | static void arrange_children(enum sway_container_layout layout, list_t *children, | ||
289 | struct sway_container *active, struct wlr_scene_tree *content, | ||
290 | int width, int height, int gaps) { | ||
291 | int title_bar_height = container_titlebar_height(); | ||
292 | |||
293 | if (layout == L_TABBED) { | ||
294 | struct sway_container *first = children->length == 1 ? | ||
295 | ((struct sway_container *)children->items[0]) : NULL; | ||
296 | if (config->hide_lone_tab && first && first->view && | ||
297 | first->current.border != B_NORMAL) { | ||
298 | title_bar_height = 0; | ||
299 | } | ||
300 | |||
301 | double w = (double) width / children->length; | ||
302 | int title_offset = 0; | ||
303 | for (int i = 0; i < children->length; i++) { | ||
304 | struct sway_container *child = children->items[i]; | ||
305 | bool activated = child == active; | ||
306 | int next_title_offset = round(w * i + w); | ||
307 | |||
308 | arrange_title_bar(child, title_offset, -title_bar_height, | ||
309 | next_title_offset - title_offset, title_bar_height); | ||
310 | wlr_scene_node_set_enabled(&child->border.tree->node, activated); | ||
311 | wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height); | ||
312 | wlr_scene_node_reparent(&child->scene_tree->node, content); | ||
313 | |||
314 | if (activated) { | ||
315 | arrange_container(child, width, height - title_bar_height, | ||
316 | false, 0); | ||
317 | } else { | ||
318 | disable_container(child); | ||
319 | } | ||
320 | |||
321 | title_offset = next_title_offset; | ||
322 | } | ||
323 | } else if (layout == L_STACKED) { | ||
324 | struct sway_container *first = children->length == 1 ? | ||
325 | ((struct sway_container *)children->items[0]) : NULL; | ||
326 | if (config->hide_lone_tab && first && first->view && | ||
327 | first->current.border != B_NORMAL) { | ||
328 | title_bar_height = 0; | ||
329 | } | ||
330 | |||
331 | int title_height = title_bar_height * children->length; | ||
332 | |||
333 | int y = 0; | ||
334 | for (int i = 0; i < children->length; i++) { | ||
335 | struct sway_container *child = children->items[i]; | ||
336 | bool activated = child == active; | ||
337 | |||
338 | arrange_title_bar(child, 0, y - title_height, width, title_bar_height); | ||
339 | wlr_scene_node_set_enabled(&child->border.tree->node, activated); | ||
340 | wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height); | ||
341 | wlr_scene_node_reparent(&child->scene_tree->node, content); | ||
342 | |||
343 | if (activated) { | ||
344 | arrange_container(child, width, height - title_height, | ||
345 | false, 0); | ||
346 | } else { | ||
347 | disable_container(child); | ||
348 | } | ||
349 | |||
350 | y += title_bar_height; | ||
351 | } | ||
352 | } else if (layout == L_VERT) { | ||
353 | int off = 0; | ||
354 | for (int i = 0; i < children->length; i++) { | ||
355 | struct sway_container *child = children->items[i]; | ||
356 | int cheight = child->current.height; | ||
357 | |||
358 | wlr_scene_node_set_enabled(&child->border.tree->node, true); | ||
359 | wlr_scene_node_set_position(&child->scene_tree->node, 0, off); | ||
360 | wlr_scene_node_reparent(&child->scene_tree->node, content); | ||
361 | arrange_container(child, width, cheight, true, gaps); | ||
362 | off += cheight + gaps; | ||
363 | } | ||
364 | } else if (layout == L_HORIZ) { | ||
365 | int off = 0; | ||
366 | for (int i = 0; i < children->length; i++) { | ||
367 | struct sway_container *child = children->items[i]; | ||
368 | int cwidth = child->current.width; | ||
369 | |||
370 | wlr_scene_node_set_enabled(&child->border.tree->node, true); | ||
371 | wlr_scene_node_set_position(&child->scene_tree->node, off, 0); | ||
372 | wlr_scene_node_reparent(&child->scene_tree->node, content); | ||
373 | arrange_container(child, cwidth, height, true, gaps); | ||
374 | off += cwidth + gaps; | ||
375 | } | ||
376 | } else { | ||
377 | sway_assert(false, "unreachable"); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static void arrange_container(struct sway_container *con, | ||
382 | int width, int height, bool title_bar, int gaps) { | ||
383 | // this container might have previously been in the scratchpad, | ||
384 | // make sure it's enabled for viewing | ||
385 | wlr_scene_node_set_enabled(&con->scene_tree->node, true); | ||
386 | |||
387 | if (con->output_handler) { | ||
388 | wlr_scene_buffer_set_dest_size(con->output_handler, width, height); | ||
389 | } | ||
390 | |||
391 | if (con->view) { | ||
392 | int border_top = container_titlebar_height(); | ||
393 | int border_width = con->current.border_thickness; | ||
394 | |||
395 | if (title_bar && con->current.border != B_NORMAL) { | ||
396 | wlr_scene_node_set_enabled(&con->title_bar.tree->node, false); | ||
397 | wlr_scene_node_set_enabled(&con->border.top->node, true); | ||
398 | } else { | ||
399 | wlr_scene_node_set_enabled(&con->border.top->node, false); | ||
400 | } | ||
401 | |||
402 | if (con->current.border == B_NORMAL) { | ||
403 | if (title_bar) { | ||
404 | arrange_title_bar(con, 0, 0, width, border_top); | ||
405 | } else { | ||
406 | border_top = 0; | ||
407 | // should be handled by the parent container | ||
408 | } | ||
409 | } else if (con->current.border == B_PIXEL) { | ||
410 | container_update(con); | ||
411 | border_top = title_bar && con->current.border_top ? border_width : 0; | ||
412 | } else if (con->current.border == B_NONE) { | ||
413 | container_update(con); | ||
414 | border_top = 0; | ||
415 | border_width = 0; | ||
416 | } else if (con->current.border == B_CSD) { | ||
417 | border_top = 0; | ||
418 | border_width = 0; | ||
419 | } else { | ||
420 | sway_assert(false, "unreachable"); | ||
421 | } | ||
422 | |||
423 | int border_bottom = con->current.border_bottom ? border_width : 0; | ||
424 | int border_left = con->current.border_left ? border_width : 0; | ||
425 | int border_right = con->current.border_right ? border_width : 0; | ||
426 | |||
427 | wlr_scene_rect_set_size(con->border.top, width, border_top); | ||
428 | wlr_scene_rect_set_size(con->border.bottom, width, border_bottom); | ||
429 | wlr_scene_rect_set_size(con->border.left, | ||
430 | border_left, height - border_top - border_bottom); | ||
431 | wlr_scene_rect_set_size(con->border.right, | ||
432 | border_right, height - border_top - border_bottom); | ||
433 | |||
434 | wlr_scene_node_set_position(&con->border.top->node, 0, 0); | ||
435 | wlr_scene_node_set_position(&con->border.bottom->node, | ||
436 | 0, height - border_bottom); | ||
437 | wlr_scene_node_set_position(&con->border.left->node, | ||
438 | 0, border_top); | ||
439 | wlr_scene_node_set_position(&con->border.right->node, | ||
440 | width - border_right, border_top); | ||
441 | |||
442 | // make sure to reparent, it's possible that the client just came out of | ||
443 | // fullscreen mode where the parent of the surface is not the container | ||
444 | wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree); | ||
445 | wlr_scene_node_set_position(&con->view->scene_tree->node, | ||
446 | border_left, border_top); | ||
447 | } else { | ||
448 | // make sure to disable the title bar if the parent is not managing it | ||
449 | if (title_bar) { | ||
450 | wlr_scene_node_set_enabled(&con->title_bar.tree->node, false); | ||
451 | } | ||
452 | |||
453 | arrange_children(con->current.layout, con->current.children, | ||
454 | con->current.focused_inactive_child, con->content_tree, | ||
455 | width, height, gaps); | ||
456 | } | ||
457 | } | ||
458 | |||
459 | static int container_get_gaps(struct sway_container *con) { | ||
460 | struct sway_workspace *ws = con->current.workspace; | ||
461 | struct sway_container *temp = con; | ||
462 | while (temp) { | ||
463 | enum sway_container_layout layout; | ||
464 | if (temp->current.parent) { | ||
465 | layout = temp->current.parent->current.layout; | ||
466 | } else { | ||
467 | layout = ws->current.layout; | ||
468 | } | ||
469 | if (layout == L_TABBED || layout == L_STACKED) { | ||
470 | return 0; | ||
471 | } | ||
472 | temp = temp->pending.parent; | ||
473 | } | ||
474 | return ws->gaps_inner; | ||
475 | } | ||
476 | |||
477 | static void arrange_fullscreen(struct wlr_scene_tree *tree, | ||
478 | struct sway_container *fs, struct sway_workspace *ws, | ||
479 | int width, int height) { | ||
480 | struct wlr_scene_node *fs_node; | ||
481 | if (fs->view) { | ||
482 | fs_node = &fs->view->scene_tree->node; | ||
483 | |||
484 | // if we only care about the view, disable any decorations | ||
485 | wlr_scene_node_set_enabled(&fs->scene_tree->node, false); | ||
486 | } else { | ||
487 | fs_node = &fs->scene_tree->node; | ||
488 | arrange_container(fs, width, height, true, container_get_gaps(fs)); | ||
489 | } | ||
490 | |||
491 | wlr_scene_node_reparent(fs_node, tree); | ||
492 | wlr_scene_node_lower_to_bottom(fs_node); | ||
493 | wlr_scene_node_set_position(fs_node, 0, 0); | ||
494 | } | ||
495 | |||
496 | static void arrange_workspace_floating(struct sway_workspace *ws) { | ||
497 | for (int i = 0; i < ws->current.floating->length; i++) { | ||
498 | struct sway_container *floater = ws->current.floating->items[i]; | ||
499 | struct wlr_scene_tree *layer = root->layers.floating; | ||
500 | |||
501 | if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { | ||
502 | continue; | ||
503 | } | ||
504 | |||
505 | if (root->fullscreen_global) { | ||
506 | if (container_is_transient_for(floater, root->fullscreen_global)) { | ||
507 | layer = root->layers.fullscreen_global; | ||
508 | } | ||
509 | } else { | ||
510 | for (int i = 0; i < root->outputs->length; i++) { | ||
511 | struct sway_output *output = root->outputs->items[i]; | ||
512 | struct sway_workspace *active = output->current.active_workspace; | ||
513 | |||
514 | if (active && active->fullscreen && | ||
515 | container_is_transient_for(floater, active->fullscreen)) { | ||
516 | layer = root->layers.fullscreen; | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | |||
521 | wlr_scene_node_reparent(&floater->scene_tree->node, layer); | ||
522 | wlr_scene_node_set_position(&floater->scene_tree->node, | ||
523 | floater->current.x, floater->current.y); | ||
524 | wlr_scene_node_set_enabled(&floater->scene_tree->node, true); | ||
525 | |||
526 | arrange_container(floater, floater->current.width, floater->current.height, | ||
527 | true, ws->gaps_inner); | ||
528 | } | ||
529 | } | ||
530 | |||
531 | static void arrange_workspace_tiling(struct sway_workspace *ws, | ||
532 | int width, int height) { | ||
533 | arrange_children(ws->current.layout, ws->current.tiling, | ||
534 | ws->current.focused_inactive_child, ws->layers.tiling, | ||
535 | width, height, ws->gaps_inner); | ||
536 | } | ||
537 | |||
538 | static void disable_workspace(struct sway_workspace *ws) { | ||
539 | // if any containers were just moved to a disabled workspace it will | ||
540 | // have the parent of the old workspace. Move the workspace so that it won't | ||
541 | // be shown. | ||
542 | for (int i = 0; i < ws->current.tiling->length; i++) { | ||
543 | struct sway_container *child = ws->current.tiling->items[i]; | ||
544 | |||
545 | wlr_scene_node_reparent(&child->scene_tree->node, ws->layers.tiling); | ||
546 | disable_container(child); | ||
547 | } | ||
548 | |||
549 | for (int i = 0; i < ws->current.floating->length; i++) { | ||
550 | struct sway_container *floater = ws->current.floating->items[i]; | ||
551 | wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating); | ||
552 | disable_container(floater); | ||
553 | wlr_scene_node_set_enabled(&floater->scene_tree->node, false); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void arrange_output(struct sway_output *output, int width, int height) { | ||
558 | for (int i = 0; i < output->current.workspaces->length; i++) { | ||
559 | struct sway_workspace *child = output->current.workspaces->items[i]; | ||
560 | |||
561 | bool activated = output->current.active_workspace == child; | ||
562 | |||
563 | wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling); | ||
564 | wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen); | ||
565 | |||
566 | for (int i = 0; i < child->current.floating->length; i++) { | ||
567 | struct sway_container *floater = child->current.floating->items[i]; | ||
568 | wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating); | ||
569 | wlr_scene_node_set_enabled(&floater->scene_tree->node, activated); | ||
570 | } | ||
571 | |||
572 | if (activated) { | ||
573 | struct sway_container *fs = child->current.fullscreen; | ||
574 | wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs); | ||
575 | wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs); | ||
576 | |||
577 | arrange_workspace_floating(child); | ||
578 | |||
579 | wlr_scene_node_set_enabled(&output->layers.shell_background->node, !fs); | ||
580 | wlr_scene_node_set_enabled(&output->layers.shell_bottom->node, !fs); | ||
581 | wlr_scene_node_set_enabled(&output->layers.fullscreen->node, fs); | ||
582 | |||
583 | if (fs) { | ||
584 | wlr_scene_rect_set_size(output->fullscreen_background, width, height); | ||
585 | |||
586 | arrange_fullscreen(child->layers.fullscreen, fs, child, | ||
587 | width, height); | ||
588 | } else { | ||
589 | struct wlr_box *area = &output->usable_area; | ||
590 | struct side_gaps *gaps = &child->current_gaps; | ||
591 | |||
592 | wlr_scene_node_set_position(&child->layers.tiling->node, | ||
593 | gaps->left + area->x, gaps->top + area->y); | ||
594 | |||
595 | arrange_workspace_tiling(child, | ||
596 | area->width - gaps->left - gaps->right, | ||
597 | area->height - gaps->top - gaps->bottom); | ||
598 | } | ||
599 | } else { | ||
600 | wlr_scene_node_set_enabled(&child->layers.tiling->node, false); | ||
601 | wlr_scene_node_set_enabled(&child->layers.fullscreen->node, false); | ||
602 | |||
603 | disable_workspace(child); | ||
262 | } | 604 | } |
263 | } | 605 | } |
606 | } | ||
264 | 607 | ||
265 | // If the view hasn't responded to the configure, center it within | 608 | void arrange_popups(struct wlr_scene_tree *popups) { |
266 | // the container. This is important for fullscreen views which | 609 | struct wlr_scene_node *node; |
267 | // refuse to resize to the size of the output. | 610 | wl_list_for_each(node, &popups->children, link) { |
268 | if (view && view->surface) { | 611 | struct sway_popup_desc *popup = scene_descriptor_try_get(node, |
269 | view_center_surface(view); | 612 | SWAY_SCENE_DESC_POPUP); |
613 | |||
614 | int lx, ly; | ||
615 | wlr_scene_node_coords(popup->relative, &lx, &ly); | ||
616 | wlr_scene_node_set_position(node, lx, ly); | ||
270 | } | 617 | } |
618 | } | ||
619 | |||
620 | static void arrange_root(struct sway_root *root) { | ||
621 | struct sway_container *fs = root->fullscreen_global; | ||
622 | |||
623 | wlr_scene_node_set_enabled(&root->layers.shell_background->node, !fs); | ||
624 | wlr_scene_node_set_enabled(&root->layers.shell_bottom->node, !fs); | ||
625 | wlr_scene_node_set_enabled(&root->layers.tiling->node, !fs); | ||
626 | wlr_scene_node_set_enabled(&root->layers.floating->node, !fs); | ||
627 | wlr_scene_node_set_enabled(&root->layers.shell_top->node, !fs); | ||
628 | wlr_scene_node_set_enabled(&root->layers.fullscreen->node, !fs); | ||
271 | 629 | ||
272 | // Damage the new location | 630 | // hide all contents in the scratchpad |
273 | desktop_damage_whole_container(container); | 631 | for (int i = 0; i < root->scratchpad->length; i++) { |
274 | if (view && view->surface) { | 632 | struct sway_container *con = root->scratchpad->items[i]; |
275 | struct wlr_surface *surface = view->surface; | 633 | |
276 | struct wlr_box box = { | 634 | wlr_scene_node_set_enabled(&con->scene_tree->node, false); |
277 | .x = container->current.content_x - view->geometry.x, | ||
278 | .y = container->current.content_y - view->geometry.y, | ||
279 | .width = surface->current.width, | ||
280 | .height = surface->current.height, | ||
281 | }; | ||
282 | desktop_damage_box(&box); | ||
283 | } | 635 | } |
284 | 636 | ||
285 | if (!container->node.destroying) { | 637 | if (fs) { |
286 | container_discover_outputs(container); | 638 | for (int i = 0; i < root->outputs->length; i++) { |
639 | struct sway_output *output = root->outputs->items[i]; | ||
640 | struct sway_workspace *ws = output->current.active_workspace; | ||
641 | |||
642 | if (ws) { | ||
643 | arrange_workspace_floating(ws); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | arrange_fullscreen(root->layers.fullscreen_global, fs, NULL, | ||
648 | root->width, root->height); | ||
649 | } else { | ||
650 | for (int i = 0; i < root->outputs->length; i++) { | ||
651 | struct sway_output *output = root->outputs->items[i]; | ||
652 | |||
653 | wlr_scene_output_set_position(output->scene_output, output->lx, output->ly); | ||
654 | |||
655 | wlr_scene_node_reparent(&output->layers.shell_background->node, root->layers.shell_background); | ||
656 | wlr_scene_node_reparent(&output->layers.shell_bottom->node, root->layers.shell_bottom); | ||
657 | wlr_scene_node_reparent(&output->layers.tiling->node, root->layers.tiling); | ||
658 | wlr_scene_node_reparent(&output->layers.shell_top->node, root->layers.shell_top); | ||
659 | wlr_scene_node_reparent(&output->layers.shell_overlay->node, root->layers.shell_overlay); | ||
660 | wlr_scene_node_reparent(&output->layers.fullscreen->node, root->layers.fullscreen); | ||
661 | wlr_scene_node_reparent(&output->layers.session_lock->node, root->layers.session_lock); | ||
662 | |||
663 | wlr_scene_node_set_position(&output->layers.shell_background->node, output->lx, output->ly); | ||
664 | wlr_scene_node_set_position(&output->layers.shell_bottom->node, output->lx, output->ly); | ||
665 | wlr_scene_node_set_position(&output->layers.tiling->node, output->lx, output->ly); | ||
666 | wlr_scene_node_set_position(&output->layers.fullscreen->node, output->lx, output->ly); | ||
667 | wlr_scene_node_set_position(&output->layers.shell_top->node, output->lx, output->ly); | ||
668 | wlr_scene_node_set_position(&output->layers.shell_overlay->node, output->lx, output->ly); | ||
669 | wlr_scene_node_set_position(&output->layers.session_lock->node, output->lx, output->ly); | ||
670 | |||
671 | arrange_output(output, output->width, output->height); | ||
672 | } | ||
287 | } | 673 | } |
674 | |||
675 | arrange_popups(root->layers.popup); | ||
288 | } | 676 | } |
289 | 677 | ||
290 | /** | 678 | /** |
@@ -326,8 +714,6 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
326 | 714 | ||
327 | node->instruction = NULL; | 715 | node->instruction = NULL; |
328 | } | 716 | } |
329 | |||
330 | cursor_rebase_all(); | ||
331 | } | 717 | } |
332 | 718 | ||
333 | static void transaction_commit_pending(void); | 719 | static void transaction_commit_pending(void); |
@@ -340,11 +726,13 @@ static void transaction_progress(void) { | |||
340 | return; | 726 | return; |
341 | } | 727 | } |
342 | transaction_apply(server.queued_transaction); | 728 | transaction_apply(server.queued_transaction); |
729 | arrange_root(root); | ||
730 | cursor_rebase_all(); | ||
343 | transaction_destroy(server.queued_transaction); | 731 | transaction_destroy(server.queued_transaction); |
344 | server.queued_transaction = NULL; | 732 | server.queued_transaction = NULL; |
345 | 733 | ||
346 | if (!server.pending_transaction) { | 734 | if (!server.pending_transaction) { |
347 | sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); | 735 | sway_idle_inhibit_v1_check_active(); |
348 | return; | 736 | return; |
349 | } | 737 | } |
350 | 738 | ||
@@ -415,21 +803,11 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
415 | ++transaction->num_waiting; | 803 | ++transaction->num_waiting; |
416 | } | 804 | } |
417 | 805 | ||
418 | // From here on we are rendering a saved buffer of the view, which | 806 | view_send_frame_done(node->sway_container->view); |
419 | // means we can send a frame done event to make the client redraw it | ||
420 | // as soon as possible. Additionally, this is required if a view is | ||
421 | // mapping and its default geometry doesn't intersect an output. | ||
422 | struct timespec now; | ||
423 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
424 | wlr_surface_send_frame_done( | ||
425 | node->sway_container->view->surface, &now); | ||
426 | } | 807 | } |
427 | if (!hidden && node_is_view(node) && | 808 | if (!hidden && node_is_view(node) && |
428 | wl_list_empty(&node->sway_container->view->saved_buffers)) { | 809 | !node->sway_container->view->saved_surface_tree) { |
429 | view_save_buffer(node->sway_container->view); | 810 | view_save_buffer(node->sway_container->view); |
430 | memcpy(&node->sway_container->view->saved_geometry, | ||
431 | &node->sway_container->view->geometry, | ||
432 | sizeof(struct wlr_box)); | ||
433 | } | 811 | } |
434 | node->instruction = instruction; | 812 | node->instruction = instruction; |
435 | } | 813 | } |
@@ -499,16 +877,18 @@ static void set_instruction_ready( | |||
499 | transaction_progress(); | 877 | transaction_progress(); |
500 | } | 878 | } |
501 | 879 | ||
502 | void transaction_notify_view_ready_by_serial(struct sway_view *view, | 880 | bool transaction_notify_view_ready_by_serial(struct sway_view *view, |
503 | uint32_t serial) { | 881 | uint32_t serial) { |
504 | struct sway_transaction_instruction *instruction = | 882 | struct sway_transaction_instruction *instruction = |
505 | view->container->node.instruction; | 883 | view->container->node.instruction; |
506 | if (instruction != NULL && instruction->serial == serial) { | 884 | if (instruction != NULL && instruction->serial == serial) { |
507 | set_instruction_ready(instruction); | 885 | set_instruction_ready(instruction); |
886 | return true; | ||
508 | } | 887 | } |
888 | return false; | ||
509 | } | 889 | } |
510 | 890 | ||
511 | void transaction_notify_view_ready_by_geometry(struct sway_view *view, | 891 | bool transaction_notify_view_ready_by_geometry(struct sway_view *view, |
512 | double x, double y, int width, int height) { | 892 | double x, double y, int width, int height) { |
513 | struct sway_transaction_instruction *instruction = | 893 | struct sway_transaction_instruction *instruction = |
514 | view->container->node.instruction; | 894 | view->container->node.instruction; |
@@ -518,7 +898,9 @@ void transaction_notify_view_ready_by_geometry(struct sway_view *view, | |||
518 | instruction->container_state.content_width == width && | 898 | instruction->container_state.content_width == width && |
519 | instruction->container_state.content_height == height) { | 899 | instruction->container_state.content_height == height) { |
520 | set_instruction_ready(instruction); | 900 | set_instruction_ready(instruction); |
901 | return true; | ||
521 | } | 902 | } |
903 | return false; | ||
522 | } | 904 | } |
523 | 905 | ||
524 | static void _transaction_commit_dirty(bool server_request) { | 906 | static void _transaction_commit_dirty(bool server_request) { |