aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands/border.c7
-rw-r--r--sway/commands/floating.c3
-rw-r--r--sway/commands/fullscreen.c4
-rw-r--r--sway/commands/gaps.c18
-rw-r--r--sway/commands/layout.c2
-rw-r--r--sway/commands/move.c41
-rw-r--r--sway/commands/reload.c2
-rw-r--r--sway/commands/resize.c2
-rw-r--r--sway/commands/smart_gaps.c5
-rw-r--r--sway/commands/split.c2
-rw-r--r--sway/commands/swap.c12
-rw-r--r--sway/config.c4
-rw-r--r--sway/desktop/desktop.c3
-rw-r--r--sway/desktop/layer_shell.c2
-rw-r--r--sway/desktop/output.c100
-rw-r--r--sway/desktop/transaction.c232
-rw-r--r--sway/desktop/xdg_shell.c45
-rw-r--r--sway/desktop/xdg_shell_v6.c48
-rw-r--r--sway/desktop/xwayland.c37
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/arrange.c326
-rw-r--r--sway/tree/container.c21
-rw-r--r--sway/tree/layout.c74
-rw-r--r--sway/tree/output.c5
-rw-r--r--sway/tree/view.c111
-rw-r--r--sway/tree/workspace.c2
26 files changed, 710 insertions, 399 deletions
diff --git a/sway/commands/border.c b/sway/commands/border.c
index 0b059562..6db85395 100644
--- a/sway/commands/border.c
+++ b/sway/commands/border.c
@@ -3,6 +3,7 @@
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/input/cursor.h" 4#include "sway/input/cursor.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "sway/tree/arrange.h"
6#include "sway/tree/container.h" 7#include "sway/tree/container.h"
7#include "sway/tree/view.h" 8#include "sway/tree/view.h"
8 9
@@ -38,13 +39,11 @@ struct cmd_results *cmd_border(int argc, char **argv) {
38 } 39 }
39 40
40 if (container_is_floating(view->swayc)) { 41 if (container_is_floating(view->swayc)) {
41 container_damage_whole(view->swayc);
42 container_set_geometry_from_floating_view(view->swayc); 42 container_set_geometry_from_floating_view(view->swayc);
43 container_damage_whole(view->swayc);
44 } else {
45 view_autoconfigure(view);
46 } 43 }
47 44
45 arrange_and_commit(view->swayc);
46
48 struct sway_seat *seat = input_manager_current_seat(input_manager); 47 struct sway_seat *seat = input_manager_current_seat(input_manager);
49 if (seat->cursor) { 48 if (seat->cursor) {
50 cursor_send_pointer_motion(seat->cursor, 0, false); 49 cursor_send_pointer_motion(seat->cursor, 0, false);
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index 46b761da..e6003521 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -36,5 +36,8 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
36 36
37 container_set_floating(container, wants_floating); 37 container_set_floating(container, wants_floating);
38 38
39 struct sway_container *workspace = container_parent(container, C_WORKSPACE);
40 arrange_and_commit(workspace);
41
39 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 42 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
40} 43}
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index ec9ec276..1a4d8b41 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -1,6 +1,7 @@
1#include "log.h" 1#include "log.h"
2#include "sway/commands.h" 2#include "sway/commands.h"
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/tree/arrange.h"
4#include "sway/tree/container.h" 5#include "sway/tree/container.h"
5#include "sway/tree/view.h" 6#include "sway/tree/view.h"
6#include "sway/tree/layout.h" 7#include "sway/tree/layout.h"
@@ -32,5 +33,8 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
32 33
33 view_set_fullscreen(view, wants_fullscreen); 34 view_set_fullscreen(view, wants_fullscreen);
34 35
36 struct sway_container *workspace = container_parent(container, C_WORKSPACE);
37 arrange_and_commit(workspace->parent);
38
35 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 39 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
36} 40}
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c
index aacb792b..801fb179 100644
--- a/sway/commands/gaps.c
+++ b/sway/commands/gaps.c
@@ -31,21 +31,19 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
31 31
32 if (strcmp(argv[1], "on") == 0) { 32 if (strcmp(argv[1], "on") == 0) {
33 config->edge_gaps = true; 33 config->edge_gaps = true;
34 arrange_root();
35 } else if (strcmp(argv[1], "off") == 0) { 34 } else if (strcmp(argv[1], "off") == 0) {
36 config->edge_gaps = false; 35 config->edge_gaps = false;
37 arrange_root();
38 } else if (strcmp(argv[1], "toggle") == 0) { 36 } else if (strcmp(argv[1], "toggle") == 0) {
39 if (!config->active) { 37 if (!config->active) {
40 return cmd_results_new(CMD_INVALID, "gaps", 38 return cmd_results_new(CMD_INVALID, "gaps",
41 "Cannot toggle gaps while not running."); 39 "Cannot toggle gaps while not running.");
42 } 40 }
43 config->edge_gaps = !config->edge_gaps; 41 config->edge_gaps = !config->edge_gaps;
44 arrange_root();
45 } else { 42 } else {
46 return cmd_results_new(CMD_INVALID, "gaps", 43 return cmd_results_new(CMD_INVALID, "gaps",
47 "gaps edge_gaps on|off|toggle"); 44 "gaps edge_gaps on|off|toggle");
48 } 45 }
46 arrange_and_commit(&root_container);
49 } else { 47 } else {
50 int amount_idx = 0; // the current index in argv 48 int amount_idx = 0; // the current index in argv
51 enum gaps_op op = GAPS_OP_SET; 49 enum gaps_op op = GAPS_OP_SET;
@@ -120,13 +118,13 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
120 "gaps inner|outer <amount>"); 118 "gaps inner|outer <amount>");
121 } 119 }
122 return cmd_results_new(CMD_INVALID, "gaps", 120 return cmd_results_new(CMD_INVALID, "gaps",
123 "gaps inner|outer all|workspace|current set|plus|minus <amount>"); 121 "gaps inner|outer all|workspace|current set|plus|minus <amount>");
124 } 122 }
125 123
126 if (amount_idx == 0) { // gaps <amount> 124 if (amount_idx == 0) { // gaps <amount>
127 config->gaps_inner = val; 125 config->gaps_inner = val;
128 config->gaps_outer = val; 126 config->gaps_outer = val;
129 arrange_root(); 127 arrange_and_commit(&root_container);
130 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 128 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
131 } 129 }
132 // Other variants. The middle-length variant (gaps inner|outer <amount>) 130 // Other variants. The middle-length variant (gaps inner|outer <amount>)
@@ -150,14 +148,14 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
150 break; 148 break;
151 } 149 }
152 } 150 }
153 151
154 if (scope == GAPS_SCOPE_ALL) { 152 if (scope == GAPS_SCOPE_ALL) {
155 if (inner) { 153 if (inner) {
156 config->gaps_inner = total; 154 config->gaps_inner = total;
157 } else { 155 } else {
158 config->gaps_outer = total; 156 config->gaps_outer = total;
159 } 157 }
160 arrange_root(); 158 arrange_and_commit(&root_container);
161 } else { 159 } else {
162 struct sway_container *c = 160 struct sway_container *c =
163 config->handler_context.current_container; 161 config->handler_context.current_container;
@@ -171,11 +169,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
171 c->gaps_outer = total; 169 c->gaps_outer = total;
172 } 170 }
173 171
174 if (c->parent) { 172 arrange_and_commit(c->parent ? c->parent : &root_container);
175 arrange_children_of(c->parent);
176 } else {
177 arrange_root();
178 }
179 } 173 }
180 } 174 }
181 175
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index a009e38f..9945fa5c 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -49,7 +49,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
49 } 49 }
50 50
51 container_notify_subtree_changed(parent); 51 container_notify_subtree_changed(parent);
52 arrange_children_of(parent); 52 arrange_and_commit(parent);
53 53
54 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 54 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
55} 55}
diff --git a/sway/commands/move.c b/sway/commands/move.c
index dc9a6f6f..2c9fb77a 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -5,8 +5,10 @@
5#include <wlr/types/wlr_output_layout.h> 5#include <wlr/types/wlr_output_layout.h>
6#include <wlr/util/log.h> 6#include <wlr/util/log.h>
7#include "sway/commands.h" 7#include "sway/commands.h"
8#include "sway/desktop/transaction.h"
8#include "sway/input/seat.h" 9#include "sway/input/seat.h"
9#include "sway/output.h" 10#include "sway/output.h"
11#include "sway/tree/arrange.h"
10#include "sway/tree/container.h" 12#include "sway/tree/container.h"
11#include "sway/tree/layout.h" 13#include "sway/tree/layout.h"
12#include "sway/tree/workspace.h" 14#include "sway/tree/workspace.h"
@@ -96,6 +98,12 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
96 seat_set_focus(config->handler_context.seat, focus); 98 seat_set_focus(config->handler_context.seat, focus);
97 container_reap_empty(old_parent); 99 container_reap_empty(old_parent);
98 container_reap_empty(destination->parent); 100 container_reap_empty(destination->parent);
101
102 struct sway_transaction *txn = transaction_create();
103 arrange_windows(old_parent, txn);
104 arrange_windows(destination->parent, txn);
105 transaction_commit(txn);
106
99 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 107 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
100 } else if (strcasecmp(argv[1], "to") == 0 108 } else if (strcasecmp(argv[1], "to") == 0
101 && strcasecmp(argv[2], "output") == 0) { 109 && strcasecmp(argv[2], "output") == 0) {
@@ -125,6 +133,12 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
125 seat_set_focus(config->handler_context.seat, old_parent); 133 seat_set_focus(config->handler_context.seat, old_parent);
126 container_reap_empty(old_parent); 134 container_reap_empty(old_parent);
127 container_reap_empty(focus->parent); 135 container_reap_empty(focus->parent);
136
137 struct sway_transaction *txn = transaction_create();
138 arrange_windows(old_parent, txn);
139 arrange_windows(focus->parent, txn);
140 transaction_commit(txn);
141
128 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 142 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
129 } 143 }
130 return cmd_results_new(CMD_INVALID, "move", expected_syntax); 144 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
@@ -152,9 +166,28 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current,
152 current = container_parent(current, C_WORKSPACE); 166 current = container_parent(current, C_WORKSPACE);
153 } 167 }
154 container_move_to(current, destination); 168 container_move_to(current, destination);
169
170 struct sway_transaction *txn = transaction_create();
171 arrange_windows(source, txn);
172 arrange_windows(destination, txn);
173 transaction_commit(txn);
174
155 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 175 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
156} 176}
157 177
178static void move_in_direction(struct sway_container *container,
179 enum wlr_direction direction, int move_amt) {
180 struct sway_container *old_parent = container->parent;
181 container_move(container, direction, move_amt);
182
183 struct sway_transaction *txn = transaction_create();
184 arrange_windows(old_parent, txn);
185 if (container->parent != old_parent) {
186 arrange_windows(container->parent, txn);
187 }
188 transaction_commit(txn);
189}
190
158struct cmd_results *cmd_move(int argc, char **argv) { 191struct cmd_results *cmd_move(int argc, char **argv) {
159 struct cmd_results *error = NULL; 192 struct cmd_results *error = NULL;
160 int move_amt = 10; 193 int move_amt = 10;
@@ -173,13 +206,13 @@ struct cmd_results *cmd_move(int argc, char **argv) {
173 } 206 }
174 207
175 if (strcasecmp(argv[0], "left") == 0) { 208 if (strcasecmp(argv[0], "left") == 0) {
176 container_move(current, MOVE_LEFT, move_amt); 209 move_in_direction(current, MOVE_LEFT, move_amt);
177 } else if (strcasecmp(argv[0], "right") == 0) { 210 } else if (strcasecmp(argv[0], "right") == 0) {
178 container_move(current, MOVE_RIGHT, move_amt); 211 move_in_direction(current, MOVE_RIGHT, move_amt);
179 } else if (strcasecmp(argv[0], "up") == 0) { 212 } else if (strcasecmp(argv[0], "up") == 0) {
180 container_move(current, MOVE_UP, move_amt); 213 move_in_direction(current, MOVE_UP, move_amt);
181 } else if (strcasecmp(argv[0], "down") == 0) { 214 } else if (strcasecmp(argv[0], "down") == 0) {
182 container_move(current, MOVE_DOWN, move_amt); 215 move_in_direction(current, MOVE_DOWN, move_amt);
183 } else if (strcasecmp(argv[0], "container") == 0 216 } else if (strcasecmp(argv[0], "container") == 0
184 || strcasecmp(argv[0], "window") == 0) { 217 || strcasecmp(argv[0], "window") == 0) {
185 return cmd_move_container(current, argc, argv); 218 return cmd_move_container(current, argc, argv);
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 092dd46f..9fc213c4 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -12,6 +12,6 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
12 } 12 }
13 13
14 load_swaybars(); 14 load_swaybars();
15 arrange_root(); 15 arrange_and_commit(&root_container);
16 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 16 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
17} 17}
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 29637953..6357343e 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -182,7 +182,7 @@ static void resize_tiled(int amount, enum resize_axis axis) {
182 } 182 }
183 } 183 }
184 184
185 arrange_children_of(parent->parent); 185 arrange_and_commit(parent->parent);
186} 186}
187 187
188static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { 188static void resize(int amount, enum resize_axis axis, enum resize_unit unit) {
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c
index 38700d65..f687e78e 100644
--- a/sway/commands/smart_gaps.c
+++ b/sway/commands/smart_gaps.c
@@ -16,13 +16,14 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
16 16
17 if (strcmp(argv[0], "on") == 0) { 17 if (strcmp(argv[0], "on") == 0) {
18 config->smart_gaps = true; 18 config->smart_gaps = true;
19 arrange_root();
20 } else if (strcmp(argv[0], "off") == 0) { 19 } else if (strcmp(argv[0], "off") == 0) {
21 config->smart_gaps = false; 20 config->smart_gaps = false;
22 arrange_root();
23 } else { 21 } else {
24 return cmd_results_new(CMD_INVALID, "smart_gaps", 22 return cmd_results_new(CMD_INVALID, "smart_gaps",
25 "Expected 'smart_gaps <on|off>' "); 23 "Expected 'smart_gaps <on|off>' ");
26 } 24 }
25
26 arrange_and_commit(&root_container);
27
27 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
28} 29}
diff --git a/sway/commands/split.c b/sway/commands/split.c
index 57e42a5a..7ea14953 100644
--- a/sway/commands/split.c
+++ b/sway/commands/split.c
@@ -16,7 +16,7 @@ static struct cmd_results *do_split(int layout) {
16 } 16 }
17 struct sway_container *parent = container_split(con, layout); 17 struct sway_container *parent = container_split(con, layout);
18 container_create_notify(parent); 18 container_create_notify(parent);
19 arrange_children_of(parent); 19 arrange_and_commit(parent);
20 20
21 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 21 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
22} 22}
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index e8dfc57f..e052058f 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -1,6 +1,8 @@
1#include <strings.h> 1#include <strings.h>
2#include <wlr/util/log.h> 2#include <wlr/util/log.h>
3#include "sway/commands.h" 3#include "sway/commands.h"
4#include "sway/desktop/transaction.h"
5#include "sway/tree/arrange.h"
4#include "sway/tree/layout.h" 6#include "sway/tree/layout.h"
5#include "sway/tree/view.h" 7#include "sway/tree/view.h"
6#include "stringop.h" 8#include "stringop.h"
@@ -76,5 +78,15 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
76 } 78 }
77 79
78 container_swap(current, other); 80 container_swap(current, other);
81
82 struct sway_transaction *txn = transaction_create();
83 arrange_windows(current->parent, txn);
84
85 if (other->parent != current->parent) {
86 arrange_windows(other->parent, txn);
87 }
88
89 transaction_commit(txn);
90
79 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 91 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
80} 92}
diff --git a/sway/config.c b/sway/config.c
index 949c5cd3..12a02163 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -531,7 +531,7 @@ static int detect_brace_on_following_line(FILE *file, char *line,
531 } while (peeked && strlen(peeked) == 0); 531 } while (peeked && strlen(peeked) == 0);
532 532
533 if (peeked && strlen(peeked) == 1 && peeked[0] == '{') { 533 if (peeked && strlen(peeked) == 1 && peeked[0] == '{') {
534 fseek(file, position, SEEK_SET); 534 fseek(file, position, SEEK_SET);
535 } else { 535 } else {
536 lines = 0; 536 lines = 0;
537 } 537 }
@@ -735,6 +735,6 @@ void config_update_font_height(bool recalculate) {
735 } 735 }
736 736
737 if (config->font_height != prev_max_height) { 737 if (config->font_height != prev_max_height) {
738 arrange_root(); 738 arrange_and_commit(&root_container);
739 } 739 }
740} 740}
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c
index 66f33151..e495790c 100644
--- a/sway/desktop/desktop.c
+++ b/sway/desktop/desktop.c
@@ -7,7 +7,8 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
7 for (int i = 0; i < root_container.children->length; ++i) { 7 for (int i = 0; i < root_container.children->length; ++i) {
8 struct sway_container *cont = root_container.children->items[i]; 8 struct sway_container *cont = root_container.children->items[i];
9 if (cont->type == C_OUTPUT) { 9 if (cont->type == C_OUTPUT) {
10 output_damage_surface(cont->sway_output, lx - cont->x, ly - cont->y, 10 output_damage_surface(cont->sway_output,
11 lx - cont->current.swayc_x, ly - cont->current.swayc_y,
11 surface, whole); 12 surface, whole);
12 } 13 }
13 } 14 }
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 3accdefb..fe5fc316 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -176,7 +176,7 @@ void arrange_layers(struct sway_output *output) {
176 sizeof(struct wlr_box)) != 0) { 176 sizeof(struct wlr_box)) != 0) {
177 wlr_log(L_DEBUG, "Usable area changed, rearranging output"); 177 wlr_log(L_DEBUG, "Usable area changed, rearranging output");
178 memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); 178 memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
179 arrange_output(output->swayc); 179 arrange_and_commit(output->swayc);
180 } 180 }
181 181
182 // Arrange non-exlusive surfaces from top->bottom 182 // Arrange non-exlusive surfaces from top->bottom
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index d4115be8..37528cac 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -69,6 +69,7 @@ struct render_data {
69 struct root_geometry root_geo; 69 struct root_geometry root_geo;
70 struct sway_output *output; 70 struct sway_output *output;
71 pixman_region32_t *damage; 71 pixman_region32_t *damage;
72 struct sway_view *view;
72 float alpha; 73 float alpha;
73}; 74};
74 75
@@ -108,6 +109,38 @@ static bool get_surface_box(struct root_geometry *geo,
108 return wlr_box_intersection(&output_box, &rotated_box, &intersection); 109 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
109} 110}
110 111
112static bool get_view_box(struct root_geometry *geo,
113 struct sway_output *output, struct sway_view *view, int sx, int sy,
114 struct wlr_box *surface_box) {
115 int sw = view->width;
116 int sh = view->height;
117
118 double _sx = sx, _sy = sy;
119 rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
120 geo->rotation);
121
122 struct wlr_box box = {
123 .x = geo->x + _sx,
124 .y = geo->y + _sy,
125 .width = sw,
126 .height = sh,
127 };
128 if (surface_box != NULL) {
129 memcpy(surface_box, &box, sizeof(struct wlr_box));
130 }
131
132 struct wlr_box rotated_box;
133 wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
134
135 struct wlr_box output_box = {
136 .width = output->swayc->width,
137 .height = output->swayc->height,
138 };
139
140 struct wlr_box intersection;
141 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
142}
143
111static void surface_for_each_surface(struct wlr_surface *surface, 144static void surface_for_each_surface(struct wlr_surface *surface,
112 double ox, double oy, struct root_geometry *geo, 145 double ox, double oy, struct root_geometry *geo,
113 wlr_surface_iterator_func_t iterator, void *user_data) { 146 wlr_surface_iterator_func_t iterator, void *user_data) {
@@ -240,14 +273,26 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
240 pixman_region32_t *output_damage = data->damage; 273 pixman_region32_t *output_damage = data->damage;
241 float alpha = data->alpha; 274 float alpha = data->alpha;
242 275
243 struct wlr_texture *texture = wlr_surface_get_texture(surface); 276 struct wlr_texture *texture = NULL;
244 if (texture == NULL) { 277 struct wlr_box box;
245 return; 278 bool intersects;
279
280 // If this is the main surface of a view, render the saved_texture instead
281 // if it exists. It exists when we are mid-transaction.
282 if (data->view && data->view->saved_texture &&
283 data->view->surface == surface) {
284 texture = data->view->saved_texture;
285 intersects = get_view_box(&data->root_geo, data->output, data->view,
286 sx, sy, &box);
287 } else {
288 texture = wlr_surface_get_texture(surface);
289 if (texture == NULL) {
290 return;
291 }
292 intersects = get_surface_box(&data->root_geo, data->output, surface,
293 sx, sy, &box);
246 } 294 }
247 295
248 struct wlr_box box;
249 bool intersects = get_surface_box(&data->root_geo, data->output, surface,
250 sx, sy, &box);
251 if (!intersects) { 296 if (!intersects) {
252 return; 297 return;
253 } 298 }
@@ -341,6 +386,7 @@ static void render_view_surfaces(struct sway_view *view,
341 struct render_data data = { 386 struct render_data data = {
342 .output = output, 387 .output = output,
343 .damage = damage, 388 .damage = damage,
389 .view = view,
344 .alpha = alpha, 390 .alpha = alpha,
345 }; 391 };
346 output_view_for_each_surface( 392 output_view_for_each_surface(
@@ -754,9 +800,10 @@ static void render_container_stacked(struct sway_output *output,
754 marks_texture = view ? view->marks_unfocused : NULL; 800 marks_texture = view ? view->marks_unfocused : NULL;
755 } 801 }
756 802
757 int y = con->y + container_titlebar_height() * i; 803 int y = con->current.swayc_y + container_titlebar_height() * i;
758 render_titlebar(output, damage, child, child->x, y, child->width, 804 render_titlebar(output, damage, child, child->current.swayc_x, y,
759 colors, title_texture, marks_texture); 805 child->current.swayc_width, colors,
806 title_texture, marks_texture);
760 807
761 if (child == current) { 808 if (child == current) {
762 current_colors = colors; 809 current_colors = colors;
@@ -775,7 +822,7 @@ static void render_container_stacked(struct sway_output *output,
775static void render_container(struct sway_output *output, 822static void render_container(struct sway_output *output,
776 pixman_region32_t *damage, struct sway_container *con, 823 pixman_region32_t *damage, struct sway_container *con,
777 bool parent_focused) { 824 bool parent_focused) {
778 switch (con->layout) { 825 switch (con->current.layout) {
779 case L_NONE: 826 case L_NONE:
780 case L_HORIZ: 827 case L_HORIZ:
781 case L_VERT: 828 case L_VERT:
@@ -812,9 +859,10 @@ static void render_floating_container(struct sway_output *soutput,
812 marks_texture = view->marks_unfocused; 859 marks_texture = view->marks_unfocused;
813 } 860 }
814 861
815 if (con->sway_view->border == B_NORMAL) { 862 if (con->current.border == B_NORMAL) {
816 render_titlebar(soutput, damage, con, con->x, con->y, con->width, 863 render_titlebar(soutput, damage, con, con->current.swayc_x,
817 colors, title_texture, marks_texture); 864 con->current.swayc_y, con->current.swayc_width, colors,
865 title_texture, marks_texture);
818 } else { 866 } else {
819 render_top_border(soutput, damage, con, colors); 867 render_top_border(soutput, damage, con, colors);
820 } 868 }
@@ -1168,6 +1216,16 @@ void output_damage_from_view(struct sway_output *output,
1168 output_damage_view(output, view, false); 1216 output_damage_view(output, view, false);
1169} 1217}
1170 1218
1219// Expecting an unscaled box in layout coordinates
1220void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
1221 struct wlr_box box;
1222 memcpy(&box, _box, sizeof(struct wlr_box));
1223 box.x -= output->swayc->current.swayc_x;
1224 box.y -= output->swayc->current.swayc_y;
1225 scale_box(&box, output->wlr_output->scale);
1226 wlr_output_damage_add_box(output->damage, &box);
1227}
1228
1171static void output_damage_whole_container_iterator(struct sway_container *con, 1229static void output_damage_whole_container_iterator(struct sway_container *con,
1172 void *data) { 1230 void *data) {
1173 struct sway_output *output = data; 1231 struct sway_output *output = data;
@@ -1182,10 +1240,10 @@ static void output_damage_whole_container_iterator(struct sway_container *con,
1182void output_damage_whole_container(struct sway_output *output, 1240void output_damage_whole_container(struct sway_output *output,
1183 struct sway_container *con) { 1241 struct sway_container *con) {
1184 struct wlr_box box = { 1242 struct wlr_box box = {
1185 .x = con->x - output->wlr_output->lx, 1243 .x = con->current.swayc_x - output->wlr_output->lx,
1186 .y = con->y - output->wlr_output->ly, 1244 .y = con->current.swayc_y - output->wlr_output->ly,
1187 .width = con->width, 1245 .width = con->current.swayc_width,
1188 .height = con->height, 1246 .height = con->current.swayc_height,
1189 }; 1247 };
1190 scale_box(&box, output->wlr_output->scale); 1248 scale_box(&box, output->wlr_output->scale);
1191 wlr_output_damage_add_box(output->damage, &box); 1249 wlr_output_damage_add_box(output->damage, &box);
@@ -1212,13 +1270,13 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
1212static void handle_mode(struct wl_listener *listener, void *data) { 1270static void handle_mode(struct wl_listener *listener, void *data) {
1213 struct sway_output *output = wl_container_of(listener, output, mode); 1271 struct sway_output *output = wl_container_of(listener, output, mode);
1214 arrange_layers(output); 1272 arrange_layers(output);
1215 arrange_output(output->swayc); 1273 arrange_and_commit(output->swayc);
1216} 1274}
1217 1275
1218static void handle_transform(struct wl_listener *listener, void *data) { 1276static void handle_transform(struct wl_listener *listener, void *data) {
1219 struct sway_output *output = wl_container_of(listener, output, transform); 1277 struct sway_output *output = wl_container_of(listener, output, transform);
1220 arrange_layers(output); 1278 arrange_layers(output);
1221 arrange_output(output->swayc); 1279 arrange_and_commit(output->swayc);
1222} 1280}
1223 1281
1224static void handle_scale_iterator(struct sway_container *view, void *data) { 1282static void handle_scale_iterator(struct sway_container *view, void *data) {
@@ -1228,8 +1286,8 @@ static void handle_scale_iterator(struct sway_container *view, void *data) {
1228static void handle_scale(struct wl_listener *listener, void *data) { 1286static void handle_scale(struct wl_listener *listener, void *data) {
1229 struct sway_output *output = wl_container_of(listener, output, scale); 1287 struct sway_output *output = wl_container_of(listener, output, scale);
1230 arrange_layers(output); 1288 arrange_layers(output);
1231 arrange_output(output->swayc);
1232 container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL); 1289 container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL);
1290 arrange_and_commit(output->swayc);
1233} 1291}
1234 1292
1235void handle_new_output(struct wl_listener *listener, void *data) { 1293void handle_new_output(struct wl_listener *listener, void *data) {
@@ -1293,5 +1351,5 @@ void output_enable(struct sway_output *output) {
1293 output->damage_destroy.notify = damage_handle_destroy; 1351 output->damage_destroy.notify = damage_handle_destroy;
1294 1352
1295 arrange_layers(output); 1353 arrange_layers(output);
1296 arrange_root(); 1354 arrange_and_commit(&root_container);
1297} 1355}
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
new file mode 100644
index 00000000..07bfbf7a
--- /dev/null
+++ b/sway/desktop/transaction.c
@@ -0,0 +1,232 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdbool.h>
3#include <stdlib.h>
4#include <string.h>
5#include <wlr/types/wlr_linux_dmabuf.h>
6#include "sway/debug.h"
7#include "sway/desktop/transaction.h"
8#include "sway/output.h"
9#include "sway/tree/container.h"
10#include "sway/tree/view.h"
11#include "list.h"
12#include "log.h"
13
14/**
15 * How long we should wait for views to respond to the configure before giving
16 * up and applying the transaction anyway.
17 */
18#define TIMEOUT_MS 200
19
20struct sway_transaction {
21 struct wl_event_source *timer;
22 list_t *instructions; // struct sway_transaction_instruction *
23 list_t *damage; // struct wlr_box *
24 size_t num_waiting;
25};
26
27struct sway_transaction_instruction {
28 struct sway_transaction *transaction;
29 struct sway_container *container;
30 struct sway_container_state state;
31 uint32_t serial;
32};
33
34struct sway_transaction *transaction_create() {
35 struct sway_transaction *transaction =
36 calloc(1, sizeof(struct sway_transaction));
37 transaction->instructions = create_list();
38 transaction->damage = create_list();
39 return transaction;
40}
41
42static void transaction_destroy(struct sway_transaction *transaction) {
43 int i;
44 // Free instructions
45 for (i = 0; i < transaction->instructions->length; ++i) {
46 struct sway_transaction_instruction *instruction =
47 transaction->instructions->items[i];
48 if (instruction->container->type == C_VIEW) {
49 struct sway_view *view = instruction->container->sway_view;
50 for (int j = 0; j < view->instructions->length; ++j) {
51 if (view->instructions->items[j] == instruction) {
52 list_del(view->instructions, j);
53 break;
54 }
55 }
56 }
57 free(instruction);
58 }
59 list_free(transaction->instructions);
60
61 // Free damage
62 for (i = 0; i < transaction->damage->length; ++i) {
63 struct wlr_box *box = transaction->damage->items[i];
64 free(box);
65 }
66 list_free(transaction->damage);
67
68 free(transaction);
69}
70
71void transaction_add_container(struct sway_transaction *transaction,
72 struct sway_container *container) {
73 struct sway_transaction_instruction *instruction =
74 calloc(1, sizeof(struct sway_transaction_instruction));
75 instruction->transaction = transaction;
76 instruction->container = container;
77
78 // Copy the container's main (pending) properties into the instruction state
79 struct sway_container_state *state = &instruction->state;
80 state->layout = container->layout;
81 state->swayc_x = container->x;
82 state->swayc_y = container->y;
83 state->swayc_width = container->width;
84 state->swayc_height = container->height;
85 state->has_gaps = container->has_gaps;
86 state->current_gaps = container->current_gaps;
87 state->gaps_inner = container->gaps_inner;
88 state->gaps_outer = container->gaps_outer;
89
90 if (container->type == C_VIEW) {
91 struct sway_view *view = container->sway_view;
92 state->view_x = view->x;
93 state->view_y = view->y;
94 state->view_width = view->width;
95 state->view_height = view->height;
96 state->is_fullscreen = view->is_fullscreen;
97 state->border = view->border;
98 state->border_thickness = view->border_thickness;
99 state->border_top = view->border_top;
100 state->border_left = view->border_left;
101 state->border_right = view->border_right;
102 state->border_bottom = view->border_bottom;
103 }
104
105 list_add(transaction->instructions, instruction);
106}
107
108void transaction_add_damage(struct sway_transaction *transaction,
109 struct wlr_box *_box) {
110 struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
111 memcpy(box, _box, sizeof(struct wlr_box));
112 list_add(transaction->damage, box);
113}
114
115static void save_view_texture(struct sway_view *view) {
116 wlr_texture_destroy(view->saved_texture);
117 view->saved_texture = NULL;
118
119 // TODO: Copy the texture and store it in view->saved_texture.
120}
121
122static void remove_saved_view_texture(struct sway_view *view) {
123 wlr_texture_destroy(view->saved_texture);
124 view->saved_texture = NULL;
125}
126
127/**
128 * Apply a transaction to the "current" state of the tree.
129 *
130 * This is mostly copying stuff from the pending state into the main swayc
131 * properties, but also includes reparenting and deleting containers.
132 */
133static void transaction_apply(struct sway_transaction *transaction) {
134 int i;
135 for (i = 0; i < transaction->instructions->length; ++i) {
136 struct sway_transaction_instruction *instruction =
137 transaction->instructions->items[i];
138 struct sway_container *container = instruction->container;
139
140 memcpy(&instruction->container->current, &instruction->state,
141 sizeof(struct sway_container_state));
142
143 if (container->type == C_VIEW) {
144 remove_saved_view_texture(container->sway_view);
145 }
146 }
147
148 // Damage
149 for (i = 0; i < transaction->damage->length; ++i) {
150 struct wlr_box *box = transaction->damage->items[i];
151 for (int j = 0; j < root_container.children->length; ++j) {
152 struct sway_container *output = root_container.children->items[j];
153 output_damage_box(output->sway_output, box);
154 }
155 }
156
157 update_debug_tree();
158}
159
160static int handle_timeout(void *data) {
161 struct sway_transaction *transaction = data;
162 wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting), applying anyway",
163 transaction, transaction->num_waiting);
164 transaction_apply(transaction);
165 transaction_destroy(transaction);
166 return 0;
167}
168
169void transaction_commit(struct sway_transaction *transaction) {
170 wlr_log(L_DEBUG, "Transaction %p committing with %i instructions",
171 transaction, transaction->instructions->length);
172 transaction->num_waiting = 0;
173 for (int i = 0; i < transaction->instructions->length; ++i) {
174 struct sway_transaction_instruction *instruction =
175 transaction->instructions->items[i];
176 struct sway_container *con = instruction->container;
177 if (con->type == C_VIEW &&
178 (con->current.view_width != instruction->state.view_width ||
179 con->current.view_height != instruction->state.view_height)) {
180 instruction->serial = view_configure(con->sway_view,
181 instruction->state.view_x,
182 instruction->state.view_y,
183 instruction->state.view_width,
184 instruction->state.view_height);
185 if (instruction->serial) {
186 save_view_texture(con->sway_view);
187 list_add(con->sway_view->instructions, instruction);
188 ++transaction->num_waiting;
189 }
190 }
191 }
192 if (!transaction->num_waiting) {
193 // This can happen if the transaction only contains xwayland views
194 wlr_log(L_DEBUG, "Transaction %p has nothing to wait for, applying",
195 transaction);
196 transaction_apply(transaction);
197 transaction_destroy(transaction);
198 return;
199 }
200
201 // Set up a timer which the views must respond within
202 transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
203 handle_timeout, transaction);
204 wl_event_source_timer_update(transaction->timer, TIMEOUT_MS);
205}
206
207void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) {
208 // Find the instruction
209 struct sway_transaction_instruction *instruction = NULL;
210 for (int i = 0; i < view->instructions->length; ++i) {
211 struct sway_transaction_instruction *tmp_instruction =
212 view->instructions->items[i];
213 if (tmp_instruction->serial == serial) {
214 instruction = tmp_instruction;
215 list_del(view->instructions, i);
216 break;
217 }
218 }
219 if (!instruction) {
220 // This can happen if the view acknowledges the configure after the
221 // transaction has timed out and applied.
222 return;
223 }
224 // If all views are ready, apply the transaction
225 struct sway_transaction *transaction = instruction->transaction;
226 if (--transaction->num_waiting == 0) {
227 wlr_log(L_DEBUG, "Transaction %p is ready, applying", transaction);
228 wl_event_source_timer_update(transaction->timer, 0);
229 transaction_apply(transaction);
230 transaction_destroy(transaction);
231 }
232}
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index d2b8822c..d22c967c 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -8,6 +8,7 @@
8#include "sway/input/input-manager.h" 8#include "sway/input/input-manager.h"
9#include "sway/input/seat.h" 9#include "sway/input/seat.h"
10#include "sway/server.h" 10#include "sway/server.h"
11#include "sway/tree/arrange.h"
11#include "sway/tree/container.h" 12#include "sway/tree/container.h"
12#include "sway/tree/layout.h" 13#include "sway/tree/layout.h"
13#include "sway/tree/view.h" 14#include "sway/tree/view.h"
@@ -87,18 +88,14 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p
87 } 88 }
88} 89}
89 90
90static void configure(struct sway_view *view, double lx, double ly, int width, 91static uint32_t configure(struct sway_view *view, double lx, double ly,
91 int height) { 92 int width, int height) {
92 struct sway_xdg_shell_view *xdg_shell_view = 93 struct sway_xdg_shell_view *xdg_shell_view =
93 xdg_shell_view_from_view(view); 94 xdg_shell_view_from_view(view);
94 if (xdg_shell_view == NULL) { 95 if (xdg_shell_view == NULL) {
95 return; 96 return 0;
96 } 97 }
97 98 return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
98 xdg_shell_view->pending_width = width;
99 xdg_shell_view->pending_height = height;
100 wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
101 view_update_position(view, lx, ly);
102} 99}
103 100
104static void set_activated(struct sway_view *view, bool activated) { 101static void set_activated(struct sway_view *view, bool activated) {
@@ -174,18 +171,12 @@ static void handle_commit(struct wl_listener *listener, void *data) {
174 struct sway_xdg_shell_view *xdg_shell_view = 171 struct sway_xdg_shell_view *xdg_shell_view =
175 wl_container_of(listener, xdg_shell_view, commit); 172 wl_container_of(listener, xdg_shell_view, commit);
176 struct sway_view *view = &xdg_shell_view->view; 173 struct sway_view *view = &xdg_shell_view->view;
177 if (view->swayc && container_is_floating(view->swayc)) { 174 struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
178 int width = view->wlr_xdg_surface->geometry.width; 175
179 int height = view->wlr_xdg_surface->geometry.height; 176 if (view->instructions->length) {
180 if (!width && !height) { 177 transaction_notify_view_ready(view, xdg_surface->configure_serial);
181 width = view->wlr_xdg_surface->surface->current->width;
182 height = view->wlr_xdg_surface->surface->current->height;
183 }
184 view_update_size(view, width, height);
185 } else {
186 view_update_size(view, xdg_shell_view->pending_width,
187 xdg_shell_view->pending_height);
188 } 178 }
179
189 view_update_title(view, false); 180 view_update_title(view, false);
190 view_damage_from(view); 181 view_damage_from(view);
191} 182}
@@ -219,8 +210,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
219 view->natural_width = view->wlr_xdg_surface->surface->current->width; 210 view->natural_width = view->wlr_xdg_surface->surface->current->width;
220 view->natural_height = view->wlr_xdg_surface->surface->current->height; 211 view->natural_height = view->wlr_xdg_surface->surface->current->height;
221 } 212 }
213
222 view_map(view, view->wlr_xdg_surface->surface); 214 view_map(view, view->wlr_xdg_surface->surface);
223 215
216 if (xdg_surface->toplevel->client_pending.fullscreen) {
217 view_set_fullscreen(view, true);
218 }
219 arrange_and_commit(view->swayc->parent);
220
224 xdg_shell_view->commit.notify = handle_commit; 221 xdg_shell_view->commit.notify = handle_commit;
225 wl_signal_add(&xdg_surface->surface->events.commit, 222 wl_signal_add(&xdg_surface->surface->events.commit,
226 &xdg_shell_view->commit); 223 &xdg_shell_view->commit);
@@ -228,10 +225,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
228 xdg_shell_view->new_popup.notify = handle_new_popup; 225 xdg_shell_view->new_popup.notify = handle_new_popup;
229 wl_signal_add(&xdg_surface->events.new_popup, 226 wl_signal_add(&xdg_surface->events.new_popup,
230 &xdg_shell_view->new_popup); 227 &xdg_shell_view->new_popup);
231
232 if (xdg_surface->toplevel->client_pending.fullscreen) {
233 view_set_fullscreen(view, true);
234 }
235} 228}
236 229
237static void handle_destroy(struct wl_listener *listener, void *data) { 230static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -246,6 +239,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
246 struct wlr_xdg_toplevel_set_fullscreen_event *e = data; 239 struct wlr_xdg_toplevel_set_fullscreen_event *e = data;
247 struct wlr_xdg_surface *xdg_surface = 240 struct wlr_xdg_surface *xdg_surface =
248 xdg_shell_view->view.wlr_xdg_surface; 241 xdg_shell_view->view.wlr_xdg_surface;
242 struct sway_view *view = &xdg_shell_view->view;
249 243
250 if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL, 244 if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL,
251 "xdg_shell requested fullscreen of surface with role %i", 245 "xdg_shell requested fullscreen of surface with role %i",
@@ -256,7 +250,10 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
256 return; 250 return;
257 } 251 }
258 252
259 view_set_fullscreen(&xdg_shell_view->view, e->fullscreen); 253 view_set_fullscreen(view, e->fullscreen);
254
255 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
256 arrange_and_commit(ws);
260} 257}
261 258
262void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { 259void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 6ffe334a..7ec9e6cb 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -3,9 +3,10 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <wayland-server.h> 4#include <wayland-server.h>
5#include <wlr/types/wlr_xdg_shell_v6.h> 5#include <wlr/types/wlr_xdg_shell_v6.h>
6#include "sway/server.h"
7#include "sway/tree/arrange.h"
6#include "sway/tree/container.h" 8#include "sway/tree/container.h"
7#include "sway/tree/layout.h" 9#include "sway/tree/layout.h"
8#include "sway/server.h"
9#include "sway/tree/view.h" 10#include "sway/tree/view.h"
10#include "sway/input/seat.h" 11#include "sway/input/seat.h"
11#include "sway/input/input-manager.h" 12#include "sway/input/input-manager.h"
@@ -86,18 +87,15 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p
86 } 87 }
87} 88}
88 89
89static void configure(struct sway_view *view, double lx, double ly, int width, 90static uint32_t configure(struct sway_view *view, double lx, double ly,
90 int height) { 91 int width, int height) {
91 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 92 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
92 xdg_shell_v6_view_from_view(view); 93 xdg_shell_v6_view_from_view(view);
93 if (xdg_shell_v6_view == NULL) { 94 if (xdg_shell_v6_view == NULL) {
94 return; 95 return 0;
95 } 96 }
96 97 return wlr_xdg_toplevel_v6_set_size(
97 xdg_shell_v6_view->pending_width = width; 98 view->wlr_xdg_surface_v6, width, height);
98 xdg_shell_v6_view->pending_height = height;
99 wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
100 view_update_position(view, lx, ly);
101} 99}
102 100
103static void set_activated(struct sway_view *view, bool activated) { 101static void set_activated(struct sway_view *view, bool activated) {
@@ -173,18 +171,12 @@ static void handle_commit(struct wl_listener *listener, void *data) {
173 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 171 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
174 wl_container_of(listener, xdg_shell_v6_view, commit); 172 wl_container_of(listener, xdg_shell_v6_view, commit);
175 struct sway_view *view = &xdg_shell_v6_view->view; 173 struct sway_view *view = &xdg_shell_v6_view->view;
176 if (view->swayc && container_is_floating(view->swayc)) { 174 struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6;
177 int width = view->wlr_xdg_surface_v6->geometry.width; 175
178 int height = view->wlr_xdg_surface_v6->geometry.height; 176 if (view->instructions->length) {
179 if (!width && !height) { 177 transaction_notify_view_ready(view, xdg_surface_v6->configure_serial);
180 width = view->wlr_xdg_surface_v6->surface->current->width;
181 height = view->wlr_xdg_surface_v6->surface->current->height;
182 }
183 view_update_size(view, width, height);
184 } else {
185 view_update_size(view, xdg_shell_v6_view->pending_width,
186 xdg_shell_v6_view->pending_height);
187 } 178 }
179
188 view_update_title(view, false); 180 view_update_title(view, false);
189 view_damage_from(view); 181 view_damage_from(view);
190} 182}
@@ -218,8 +210,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
218 view->natural_width = view->wlr_xdg_surface_v6->surface->current->width; 210 view->natural_width = view->wlr_xdg_surface_v6->surface->current->width;
219 view->natural_height = view->wlr_xdg_surface_v6->surface->current->height; 211 view->natural_height = view->wlr_xdg_surface_v6->surface->current->height;
220 } 212 }
213
221 view_map(view, view->wlr_xdg_surface_v6->surface); 214 view_map(view, view->wlr_xdg_surface_v6->surface);
222 215
216 if (xdg_surface->toplevel->client_pending.fullscreen) {
217 view_set_fullscreen(view, true);
218 }
219 arrange_and_commit(view->swayc->parent);
220
223 xdg_shell_v6_view->commit.notify = handle_commit; 221 xdg_shell_v6_view->commit.notify = handle_commit;
224 wl_signal_add(&xdg_surface->surface->events.commit, 222 wl_signal_add(&xdg_surface->surface->events.commit,
225 &xdg_shell_v6_view->commit); 223 &xdg_shell_v6_view->commit);
@@ -227,10 +225,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
227 xdg_shell_v6_view->new_popup.notify = handle_new_popup; 225 xdg_shell_v6_view->new_popup.notify = handle_new_popup;
228 wl_signal_add(&xdg_surface->events.new_popup, 226 wl_signal_add(&xdg_surface->events.new_popup,
229 &xdg_shell_v6_view->new_popup); 227 &xdg_shell_v6_view->new_popup);
230
231 if (xdg_surface->toplevel->client_pending.fullscreen) {
232 view_set_fullscreen(view, true);
233 }
234} 228}
235 229
236static void handle_destroy(struct wl_listener *listener, void *data) { 230static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -245,6 +239,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
245 struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data; 239 struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data;
246 struct wlr_xdg_surface_v6 *xdg_surface = 240 struct wlr_xdg_surface_v6 *xdg_surface =
247 xdg_shell_v6_view->view.wlr_xdg_surface_v6; 241 xdg_shell_v6_view->view.wlr_xdg_surface_v6;
242 struct sway_view *view = &xdg_shell_v6_view->view;
248 243
249 if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, 244 if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL,
250 "xdg_shell_v6 requested fullscreen of surface with role %i", 245 "xdg_shell_v6 requested fullscreen of surface with role %i",
@@ -255,7 +250,10 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
255 return; 250 return;
256 } 251 }
257 252
258 view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen); 253 view_set_fullscreen(view, e->fullscreen);
254
255 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
256 arrange_and_commit(ws);
259} 257}
260 258
261void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { 259void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 6447b711..70929d48 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -11,6 +11,7 @@
11#include "sway/input/seat.h" 11#include "sway/input/seat.h"
12#include "sway/output.h" 12#include "sway/output.h"
13#include "sway/server.h" 13#include "sway/server.h"
14#include "sway/tree/arrange.h"
14#include "sway/tree/container.h" 15#include "sway/tree/container.h"
15#include "sway/tree/layout.h" 16#include "sway/tree/layout.h"
16#include "sway/tree/view.h" 17#include "sway/tree/view.h"
@@ -167,19 +168,18 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
167 } 168 }
168} 169}
169 170
170static void configure(struct sway_view *view, double lx, double ly, int width, 171static uint32_t configure(struct sway_view *view, double lx, double ly, int width,
171 int height) { 172 int height) {
172 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); 173 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
173 if (xwayland_view == NULL) { 174 if (xwayland_view == NULL) {
174 return; 175 return 0;
175 } 176 }
176 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 177 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
177 178
178 xwayland_view->pending_lx = lx;
179 xwayland_view->pending_ly = ly;
180 xwayland_view->pending_width = width;
181 xwayland_view->pending_height = height;
182 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); 179 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height);
180
181 // xwayland doesn't give us a serial for the configure
182 return 0;
183} 183}
184 184
185static void set_activated(struct sway_view *view, bool activated) { 185static void set_activated(struct sway_view *view, bool activated) {
@@ -250,15 +250,19 @@ static void handle_commit(struct wl_listener *listener, void *data) {
250 wl_container_of(listener, xwayland_view, commit); 250 wl_container_of(listener, xwayland_view, commit);
251 struct sway_view *view = &xwayland_view->view; 251 struct sway_view *view = &xwayland_view->view;
252 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 252 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
253 if (view->swayc && container_is_floating(view->swayc)) { 253
254 view_update_size(view, xsurface->width, xsurface->height); 254 // Don't allow xwayland views to do resize or reposition themselves if
255 } else { 255 // they're involved in a transaction. Once the transaction has finished
256 view_update_size(view, xwayland_view->pending_width, 256 // they'll apply the next time a commit happens.
257 xwayland_view->pending_height); 257 if (view->instructions->length) {
258 if (view->swayc && container_is_floating(view->swayc)) {
259 view_update_size(view, xsurface->width, xsurface->height);
260 } else {
261 view_update_size(view, view->swayc->width, view->swayc->height);
262 }
263 view_update_position(view, view->x, view->y);
264 view_damage_from(view);
258 } 265 }
259 view_update_position(view,
260 xwayland_view->pending_lx, xwayland_view->pending_ly);
261 view_damage_from(view);
262} 266}
263 267
264static void handle_unmap(struct wl_listener *listener, void *data) { 268static void handle_unmap(struct wl_listener *listener, void *data) {
@@ -289,6 +293,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
289 if (xsurface->fullscreen) { 293 if (xsurface->fullscreen) {
290 view_set_fullscreen(view, true); 294 view_set_fullscreen(view, true);
291 } 295 }
296 arrange_and_commit(view->swayc);
292} 297}
293 298
294static void handle_destroy(struct wl_listener *listener, void *data) { 299static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -309,7 +314,8 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
309 return; 314 return;
310 } 315 }
311 // TODO: Let floating views do whatever 316 // TODO: Let floating views do whatever
312 configure(view, view->swayc->x, view->swayc->y, view->width, view->height); 317 configure(view, view->swayc->current.view_x, view->swayc->current.view_y,
318 view->swayc->current.view_width, view->swayc->current.view_height);
313} 319}
314 320
315static void handle_request_fullscreen(struct wl_listener *listener, void *data) { 321static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
@@ -321,6 +327,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
321 return; 327 return;
322 } 328 }
323 view_set_fullscreen(view, xsurface->fullscreen); 329 view_set_fullscreen(view, xsurface->fullscreen);
330 arrange_and_commit(view->swayc);
324} 331}
325 332
326static void handle_set_title(struct wl_listener *listener, void *data) { 333static void handle_set_title(struct wl_listener *listener, void *data) {
diff --git a/sway/meson.build b/sway/meson.build
index 0da67ed7..c461b0ff 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -12,6 +12,7 @@ sway_sources = files(
12 'desktop/desktop.c', 12 'desktop/desktop.c',
13 'desktop/layer_shell.c', 13 'desktop/layer_shell.c',
14 'desktop/output.c', 14 'desktop/output.c',
15 'desktop/transaction.c',
15 'desktop/xdg_shell_v6.c', 16 'desktop/xdg_shell_v6.c',
16 'desktop/xdg_shell.c', 17 'desktop/xdg_shell.c',
17 'desktop/xwayland.c', 18 'desktop/xwayland.c',
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 53c95820..ac99c5df 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -5,7 +5,6 @@
5#include <string.h> 5#include <string.h>
6#include <wlr/types/wlr_output.h> 6#include <wlr/types/wlr_output.h>
7#include <wlr/types/wlr_output_layout.h> 7#include <wlr/types/wlr_output_layout.h>
8#include "sway/debug.h"
9#include "sway/tree/arrange.h" 8#include "sway/tree/arrange.h"
10#include "sway/tree/container.h" 9#include "sway/tree/container.h"
11#include "sway/tree/layout.h" 10#include "sway/tree/layout.h"
@@ -17,116 +16,6 @@
17 16
18struct sway_container root_container; 17struct sway_container root_container;
19 18
20void arrange_root() {
21 if (config->reloading) {
22 return;
23 }
24 struct wlr_output_layout *output_layout =
25 root_container.sway_root->output_layout;
26 const struct wlr_box *layout_box =
27 wlr_output_layout_get_box(output_layout, NULL);
28 root_container.x = layout_box->x;
29 root_container.y = layout_box->y;
30 root_container.width = layout_box->width;
31 root_container.height = layout_box->height;
32 for (int i = 0; i < root_container.children->length; ++i) {
33 struct sway_container *output = root_container.children->items[i];
34 arrange_output(output);
35 }
36}
37
38void arrange_output(struct sway_container *output) {
39 if (config->reloading) {
40 return;
41 }
42 if (!sway_assert(output->type == C_OUTPUT,
43 "called arrange_output() on non-output container")) {
44 return;
45 }
46
47 const struct wlr_box *output_box = wlr_output_layout_get_box(
48 root_container.sway_root->output_layout,
49 output->sway_output->wlr_output);
50 output->x = output_box->x;
51 output->y = output_box->y;
52 output->width = output_box->width;
53 output->height = output_box->height;
54 wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
55 output->name, output->x, output->y);
56
57 for (int i = 0; i < output->children->length; ++i) {
58 struct sway_container *workspace = output->children->items[i];
59 arrange_workspace(workspace);
60 }
61 container_damage_whole(output);
62}
63
64void arrange_workspace(struct sway_container *workspace) {
65 if (config->reloading) {
66 return;
67 }
68 if (!sway_assert(workspace->type == C_WORKSPACE,
69 "called arrange_workspace() on non-workspace container")) {
70 return;
71 }
72
73 struct sway_container *output = workspace->parent;
74 struct wlr_box *area = &output->sway_output->usable_area;
75 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
76 area->width, area->height, area->x, area->y);
77
78 remove_gaps(workspace);
79
80 workspace->width = area->width;
81 workspace->height = area->height;
82 workspace->x = output->x + area->x;
83 workspace->y = output->y + area->y;
84
85 add_gaps(workspace);
86
87 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
88 workspace->name, workspace->x, workspace->y);
89 arrange_children_of(workspace);
90}
91
92void remove_gaps(struct sway_container *c) {
93 if (c->current_gaps == 0) {
94 wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c);
95 return;
96 }
97
98 c->width += c->current_gaps * 2;
99 c->height += c->current_gaps * 2;
100 c->x -= c->current_gaps;
101 c->y -= c->current_gaps;
102
103 c->current_gaps = 0;
104
105 wlr_log(L_DEBUG, "Removing gaps %p", c);
106}
107
108void add_gaps(struct sway_container *c) {
109 if (c->current_gaps > 0 || c->type == C_CONTAINER) {
110 wlr_log(L_DEBUG, "Not adding gaps: %p", c);
111 return;
112 }
113
114 if (c->type == C_WORKSPACE &&
115 !(config->edge_gaps || (config->smart_gaps && c->children->length > 1))) {
116 return;
117 }
118
119 double gaps = c->has_gaps ? c->gaps_inner : config->gaps_inner;
120
121 c->x += gaps;
122 c->y += gaps;
123 c->width -= 2 * gaps;
124 c->height -= 2 * gaps;
125 c->current_gaps = gaps;
126
127 wlr_log(L_DEBUG, "Adding gaps: %p", c);
128}
129
130static void apply_horiz_layout(struct sway_container *parent) { 19static void apply_horiz_layout(struct sway_container *parent) {
131 size_t num_children = parent->children->length; 20 size_t num_children = parent->children->length;
132 if (!num_children) { 21 if (!num_children) {
@@ -136,8 +25,8 @@ static void apply_horiz_layout(struct sway_container *parent) {
136 if (parent->parent->layout == L_TABBED) { 25 if (parent->parent->layout == L_TABBED) {
137 parent_offset = container_titlebar_height(); 26 parent_offset = container_titlebar_height();
138 } else if (parent->parent->layout == L_STACKED) { 27 } else if (parent->parent->layout == L_STACKED) {
139 parent_offset = 28 parent_offset = container_titlebar_height() *
140 container_titlebar_height() * parent->parent->children->length; 29 parent->parent->children->length;
141 } 30 }
142 size_t parent_height = parent->height - parent_offset; 31 size_t parent_height = parent->height - parent_offset;
143 32
@@ -145,7 +34,6 @@ static void apply_horiz_layout(struct sway_container *parent) {
145 double total_width = 0; 34 double total_width = 0;
146 for (size_t i = 0; i < num_children; ++i) { 35 for (size_t i = 0; i < num_children; ++i) {
147 struct sway_container *child = parent->children->items[i]; 36 struct sway_container *child = parent->children->items[i];
148
149 if (child->width <= 0) { 37 if (child->width <= 0) {
150 if (num_children > 1) { 38 if (num_children > 1) {
151 child->width = parent->width / (num_children - 1); 39 child->width = parent->width / (num_children - 1);
@@ -161,25 +49,21 @@ static void apply_horiz_layout(struct sway_container *parent) {
161 // Resize windows 49 // Resize windows
162 wlr_log(L_DEBUG, "Arranging %p horizontally", parent); 50 wlr_log(L_DEBUG, "Arranging %p horizontally", parent);
163 double child_x = parent->x; 51 double child_x = parent->x;
164 struct sway_container *child;
165 for (size_t i = 0; i < num_children; ++i) { 52 for (size_t i = 0; i < num_children; ++i) {
166 child = parent->children->items[i]; 53 struct sway_container *child = parent->children->items[i];
167 wlr_log(L_DEBUG, 54 wlr_log(L_DEBUG,
168 "Calculating arrangement for %p:%d (will scale %f by %f)", 55 "Calculating arrangement for %p:%d (will scale %f by %f)",
169 child, child->type, child->width, scale); 56 child, child->type, child->width, scale);
170 child->x = child_x; 57 child->x = child_x;
171 child->y = parent->y + parent_offset; 58 child->y = parent->y + parent_offset;
59 child->width = floor(child->width * scale);
172 child->height = parent_height; 60 child->height = parent_height;
61 child_x += child->width;
173 62
63 // Make last child use remaining width of parent
174 if (i == num_children - 1) { 64 if (i == num_children - 1) {
175 // Make last child use remaining width of parent
176 child->width = parent->x + parent->width - child->x; 65 child->width = parent->x + parent->width - child->x;
177 } else {
178 child->width = floor(child->width * scale);
179 } 66 }
180
181 child_x += child->width;
182
183 add_gaps(child); 67 add_gaps(child);
184 } 68 }
185} 69}
@@ -202,7 +86,6 @@ static void apply_vert_layout(struct sway_container *parent) {
202 double total_height = 0; 86 double total_height = 0;
203 for (size_t i = 0; i < num_children; ++i) { 87 for (size_t i = 0; i < num_children; ++i) {
204 struct sway_container *child = parent->children->items[i]; 88 struct sway_container *child = parent->children->items[i];
205
206 if (child->height <= 0) { 89 if (child->height <= 0) {
207 if (num_children > 1) { 90 if (num_children > 1) {
208 child->height = parent_height / (num_children - 1); 91 child->height = parent_height / (num_children - 1);
@@ -218,25 +101,22 @@ static void apply_vert_layout(struct sway_container *parent) {
218 // Resize 101 // Resize
219 wlr_log(L_DEBUG, "Arranging %p vertically", parent); 102 wlr_log(L_DEBUG, "Arranging %p vertically", parent);
220 double child_y = parent->y + parent_offset; 103 double child_y = parent->y + parent_offset;
221 struct sway_container *child;
222 for (size_t i = 0; i < num_children; ++i) { 104 for (size_t i = 0; i < num_children; ++i) {
223 child = parent->children->items[i]; 105 struct sway_container *child = parent->children->items[i];
224 wlr_log(L_DEBUG, 106 wlr_log(L_DEBUG,
225 "Calculating arrangement for %p:%d (will scale %f by %f)", 107 "Calculating arrangement for %p:%d (will scale %f by %f)",
226 child, child->type, child->height, scale); 108 child, child->type, child->height, scale);
227 child->x = parent->x; 109 child->x = parent->x;
228 child->y = child_y; 110 child->y = child_y;
229 child->width = parent->width; 111 child->width = parent->width;
112 child->height = floor(child->height * scale);
113 child_y += child->height;
230 114
115 // Make last child use remaining height of parent
231 if (i == num_children - 1) { 116 if (i == num_children - 1) {
232 // Make last child use remaining height of parent 117 child->height =
233 child->height = parent->y + parent_offset + parent_height - child->y; 118 parent->y + parent_offset + parent_height - child->y;
234 } else {
235 child->height = floor(child->height * scale);
236 } 119 }
237
238 child_y += child->height;
239
240 add_gaps(child); 120 add_gaps(child);
241 } 121 }
242} 122}
@@ -264,26 +144,27 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
264 } 144 }
265} 145}
266 146
267void arrange_children_of(struct sway_container *parent) { 147static void arrange_children_of(struct sway_container *parent,
268 if (config->reloading) { 148 struct sway_transaction *transaction);
269 return;
270 }
271 if (!sway_assert(parent->type == C_WORKSPACE || parent->type == C_CONTAINER,
272 "container is a %s", container_type_to_str(parent->type))) {
273 return;
274 }
275 149
276 struct sway_container *workspace = parent; 150static void arrange_floating(struct sway_container *floating,
277 if (workspace->type != C_WORKSPACE) { 151 struct sway_transaction *transaction) {
278 workspace = container_parent(workspace, C_WORKSPACE); 152 for (int i = 0; i < floating->children->length; ++i) {
153 struct sway_container *floater = floating->children->items[i];
154 if (floater->type == C_VIEW) {
155 view_autoconfigure(floater->sway_view);
156 } else {
157 arrange_children_of(floater, transaction);
158 }
159 transaction_add_container(transaction, floater);
279 } 160 }
161}
280 162
281 if (workspace->sway_workspace->fullscreen) { 163static void arrange_children_of(struct sway_container *parent,
282 // Just arrange the fullscreen view and jump out 164 struct sway_transaction *transaction) {
283 view_autoconfigure(workspace->sway_workspace->fullscreen); 165 if (config->reloading) {
284 return; 166 return;
285 } 167 }
286
287 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, 168 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent,
288 parent->name, parent->width, parent->height, parent->x, parent->y); 169 parent->name, parent->width, parent->height, parent->x, parent->y);
289 170
@@ -299,13 +180,15 @@ void arrange_children_of(struct sway_container *parent) {
299 case L_STACKED: 180 case L_STACKED:
300 apply_tabbed_or_stacked_layout(parent); 181 apply_tabbed_or_stacked_layout(parent);
301 break; 182 break;
302 default: 183 case L_NONE:
303 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
304 apply_horiz_layout(parent); 184 apply_horiz_layout(parent);
305 break; 185 break;
186 case L_FLOATING:
187 arrange_floating(parent, transaction);
188 break;
306 } 189 }
307 190
308 // Apply x, y, width and height to children and recurse if needed 191 // Recurse into child containers
309 for (int i = 0; i < parent->children->length; ++i) { 192 for (int i = 0; i < parent->children->length; ++i) {
310 struct sway_container *child = parent->children->items[i]; 193 struct sway_container *child = parent->children->items[i];
311 if (parent->has_gaps && !child->has_gaps) { 194 if (parent->has_gaps && !child->has_gaps) {
@@ -316,21 +199,140 @@ void arrange_children_of(struct sway_container *parent) {
316 if (child->type == C_VIEW) { 199 if (child->type == C_VIEW) {
317 view_autoconfigure(child->sway_view); 200 view_autoconfigure(child->sway_view);
318 } else { 201 } else {
319 arrange_children_of(child); 202 arrange_children_of(child, transaction);
320 } 203 }
204 transaction_add_container(transaction, child);
321 } 205 }
206}
322 207
323 // If container is a workspace, process floating containers too 208static void arrange_workspace(struct sway_container *workspace,
324 if (parent->type == C_WORKSPACE) { 209 struct sway_transaction *transaction) {
325 struct sway_workspace *ws = workspace->sway_workspace; 210 if (config->reloading) {
326 for (int i = 0; i < ws->floating->children->length; ++i) { 211 return;
327 struct sway_container *child = ws->floating->children->items[i];
328 if (child->type != C_VIEW) {
329 arrange_children_of(child);
330 }
331 }
332 } 212 }
213 struct sway_container *output = workspace->parent;
214 struct wlr_box *area = &output->sway_output->usable_area;
215 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
216 area->width, area->height, area->x, area->y);
217 remove_gaps(workspace);
218 workspace->width = area->width;
219 workspace->height = area->height;
220 workspace->x = output->x + area->x;
221 workspace->y = output->y + area->y;
222 add_gaps(workspace);
223 transaction_add_container(transaction, workspace);
224 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
225 workspace->x, workspace->y);
226 arrange_floating(workspace->sway_workspace->floating, transaction);
227 arrange_children_of(workspace, transaction);
228}
333 229
334 container_damage_whole(parent); 230static void arrange_output(struct sway_container *output,
335 update_debug_tree(); 231 struct sway_transaction *transaction) {
232 if (config->reloading) {
233 return;
234 }
235 const struct wlr_box *output_box = wlr_output_layout_get_box(
236 root_container.sway_root->output_layout,
237 output->sway_output->wlr_output);
238 output->x = output_box->x;
239 output->y = output_box->y;
240 output->width = output_box->width;
241 output->height = output_box->height;
242 transaction_add_container(transaction, output);
243 wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
244 output->name, output->x, output->y);
245 for (int i = 0; i < output->children->length; ++i) {
246 struct sway_container *workspace = output->children->items[i];
247 arrange_workspace(workspace, transaction);
248 }
249}
250
251static void arrange_root(struct sway_transaction *transaction) {
252 if (config->reloading) {
253 return;
254 }
255 struct wlr_output_layout *output_layout =
256 root_container.sway_root->output_layout;
257 const struct wlr_box *layout_box =
258 wlr_output_layout_get_box(output_layout, NULL);
259 root_container.x = layout_box->x;
260 root_container.y = layout_box->y;
261 root_container.width = layout_box->width;
262 root_container.height = layout_box->height;
263 transaction_add_container(transaction, &root_container);
264 for (int i = 0; i < root_container.children->length; ++i) {
265 struct sway_container *output = root_container.children->items[i];
266 arrange_output(output, transaction);
267 }
268}
269
270void arrange_windows(struct sway_container *container,
271 struct sway_transaction *transaction) {
272 switch (container->type) {
273 case C_ROOT:
274 arrange_root(transaction);
275 break;
276 case C_OUTPUT:
277 arrange_output(container, transaction);
278 break;
279 case C_WORKSPACE:
280 arrange_workspace(container, transaction);
281 break;
282 case C_CONTAINER:
283 arrange_children_of(container, transaction);
284 transaction_add_container(transaction, container);
285 break;
286 case C_VIEW:
287 view_autoconfigure(container->sway_view);
288 transaction_add_container(transaction, container);
289 break;
290 case C_TYPES:
291 break;
292 }
293 transaction_add_damage(transaction, container_get_box(container));
294}
295
296void arrange_and_commit(struct sway_container *container) {
297 struct sway_transaction *transaction = transaction_create();
298 arrange_windows(container, transaction);
299 transaction_commit(transaction);
300}
301
302void remove_gaps(struct sway_container *c) {
303 if (c->current_gaps == 0) {
304 wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c);
305 return;
306 }
307
308 c->width += c->current_gaps * 2;
309 c->height += c->current_gaps * 2;
310 c->x -= c->current_gaps;
311 c->y -= c->current_gaps;
312
313 c->current_gaps = 0;
314
315 wlr_log(L_DEBUG, "Removing gaps %p", c);
316}
317
318void add_gaps(struct sway_container *c) {
319 if (c->current_gaps > 0 || c->type == C_CONTAINER) {
320 wlr_log(L_DEBUG, "Not adding gaps: %p", c);
321 return;
322 }
323
324 if (c->type == C_WORKSPACE &&
325 !(config->edge_gaps || (config->smart_gaps && c->children->length > 1))) {
326 return;
327 }
328
329 double gaps = c->has_gaps ? c->gaps_inner : config->gaps_inner;
330
331 c->x += gaps;
332 c->y += gaps;
333 c->width -= 2 * gaps;
334 c->height -= 2 * gaps;
335 c->current_gaps = gaps;
336
337 wlr_log(L_DEBUG, "Adding gaps: %p", c);
336} 338}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index af55a54e..f8620b72 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -116,6 +116,7 @@ struct sway_container *container_create(enum sway_container_type type) {
116 116
117 if (type != C_VIEW) { 117 if (type != C_VIEW) {
118 c->children = create_list(); 118 c->children = create_list();
119 //c->pending.children = create_list();
119 } 120 }
120 121
121 wl_signal_init(&c->events.destroy); 122 wl_signal_init(&c->events.destroy);
@@ -167,6 +168,7 @@ static void _container_destroy(struct sway_container *cont) {
167 wlr_texture_destroy(cont->title_urgent); 168 wlr_texture_destroy(cont->title_urgent);
168 169
169 list_free(cont->children); 170 list_free(cont->children);
171 //list_free(cont->pending.children);
170 cont->children = NULL; 172 cont->children = NULL;
171 free(cont); 173 free(cont);
172} 174}
@@ -207,6 +209,7 @@ static struct sway_container *container_workspace_destroy(
207 container_move_to(floating->children->items[i], 209 container_move_to(floating->children->items[i],
208 new_workspace->sway_workspace->floating); 210 new_workspace->sway_workspace->floating);
209 } 211 }
212 arrange_and_commit(new_workspace);
210 } 213 }
211 214
212 struct sway_workspace *sway_workspace = workspace->sway_workspace; 215 struct sway_workspace *sway_workspace = workspace->sway_workspace;
@@ -267,10 +270,10 @@ static struct sway_container *container_output_destroy(
267 } 270 }
268 271
269 container_sort_workspaces(new_output); 272 container_sort_workspaces(new_output);
270 arrange_output(new_output);
271 } 273 }
272 } 274 }
273 } 275 }
276 arrange_and_commit(&root_container);
274 277
275 wl_list_remove(&output->sway_output->mode.link); 278 wl_list_remove(&output->sway_output->mode.link);
276 wl_list_remove(&output->sway_output->transform.link); 279 wl_list_remove(&output->sway_output->transform.link);
@@ -927,13 +930,12 @@ void container_set_floating(struct sway_container *container, bool enable) {
927 930
928 struct sway_container *workspace = container_parent(container, C_WORKSPACE); 931 struct sway_container *workspace = container_parent(container, C_WORKSPACE);
929 struct sway_seat *seat = input_manager_current_seat(input_manager); 932 struct sway_seat *seat = input_manager_current_seat(input_manager);
930 container_damage_whole(container);
931 933
932 if (enable) { 934 if (enable) {
933 container_remove_child(container); 935 container_remove_child(container);
934 container_add_child(workspace->sway_workspace->floating, container); 936 container_add_child(workspace->sway_workspace->floating, container);
935 if (container->type == C_VIEW) { 937 if (container->type == C_VIEW) {
936 view_autoconfigure(container->sway_view); 938 view_init_floating(container->sway_view);
937 } 939 }
938 seat_set_focus(seat, seat_get_focus_inactive(seat, container)); 940 seat_set_focus(seat, seat_get_focus_inactive(seat, container));
939 container_reap_empty_recursive(workspace); 941 container_reap_empty_recursive(workspace);
@@ -946,8 +948,8 @@ void container_set_floating(struct sway_container *container, bool enable) {
946 container->is_sticky = false; 948 container->is_sticky = false;
947 container_reap_empty_recursive(workspace->sway_workspace->floating); 949 container_reap_empty_recursive(workspace->sway_workspace->floating);
948 } 950 }
949 arrange_workspace(workspace); 951
950 container_damage_whole(container); 952 ipc_event_window(container, "floating");
951} 953}
952 954
953void container_set_geometry_from_floating_view(struct sway_container *con) { 955void container_set_geometry_from_floating_view(struct sway_container *con) {
@@ -976,3 +978,12 @@ bool container_is_floating(struct sway_container *container) {
976 } 978 }
977 return container->parent == workspace->sway_workspace->floating; 979 return container->parent == workspace->sway_workspace->floating;
978} 980}
981
982struct wlr_box *container_get_box(struct sway_container *container) {
983 struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
984 box->x = container->x;
985 box->y = container->y;
986 box->width = container->width;
987 box->height = container->height;
988 return box;
989}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index d1ad044d..3724361d 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -22,7 +22,7 @@ struct sway_container root_container;
22 22
23static void output_layout_handle_change(struct wl_listener *listener, 23static void output_layout_handle_change(struct wl_listener *listener,
24 void *data) { 24 void *data) {
25 arrange_root(); 25 arrange_and_commit(&root_container);
26} 26}
27 27
28void layout_init(void) { 28void layout_init(void) {
@@ -57,18 +57,17 @@ static int index_child(const struct sway_container *child) {
57 return -1; 57 return -1;
58} 58}
59 59
60static void container_handle_fullscreen_reparent(struct sway_container *viewcon, 60static void container_handle_fullscreen_reparent(struct sway_container *con,
61 struct sway_container *old_parent) { 61 struct sway_container *old_parent) {
62 if (viewcon->type != C_VIEW || !viewcon->sway_view->is_fullscreen) { 62 if (con->type != C_VIEW || !con->sway_view->is_fullscreen) {
63 return; 63 return;
64 } 64 }
65 struct sway_view *view = viewcon->sway_view; 65 struct sway_view *view = con->sway_view;
66 struct sway_container *old_workspace = old_parent; 66 struct sway_container *old_workspace = old_parent;
67 if (old_workspace && old_workspace->type != C_WORKSPACE) { 67 if (old_workspace && old_workspace->type != C_WORKSPACE) {
68 old_workspace = container_parent(old_workspace, C_WORKSPACE); 68 old_workspace = container_parent(old_workspace, C_WORKSPACE);
69 } 69 }
70 struct sway_container *new_workspace = container_parent(view->swayc, 70 struct sway_container *new_workspace = container_parent(con, C_WORKSPACE);
71 C_WORKSPACE);
72 if (old_workspace == new_workspace) { 71 if (old_workspace == new_workspace) {
73 return; 72 return;
74 } 73 }
@@ -79,15 +78,19 @@ static void container_handle_fullscreen_reparent(struct sway_container *viewcon,
79 78
80 // Mark the new workspace as fullscreen 79 // Mark the new workspace as fullscreen
81 if (new_workspace->sway_workspace->fullscreen) { 80 if (new_workspace->sway_workspace->fullscreen) {
82 view_set_fullscreen_raw( 81 view_set_fullscreen(new_workspace->sway_workspace->fullscreen, false);
83 new_workspace->sway_workspace->fullscreen, false);
84 } 82 }
85 new_workspace->sway_workspace->fullscreen = view; 83 new_workspace->sway_workspace->fullscreen = view;
86 // Resize view to new output dimensions 84 // Resize view to new output dimensions
87 struct sway_container *output = new_workspace->parent; 85 struct sway_container *output = new_workspace->parent;
88 view_configure(view, 0, 0, output->width, output->height); 86 view->x = output->x;
89 view->swayc->width = output->width; 87 view->y = output->y;
90 view->swayc->height = output->height; 88 view->width = output->width;
89 view->height = output->height;
90 con->x = output->x;
91 con->y = output->y;
92 con->width = output->width;
93 con->height = output->height;
91} 94}
92 95
93void container_insert_child(struct sway_container *parent, 96void container_insert_child(struct sway_container *parent,
@@ -189,18 +192,7 @@ void container_move_to(struct sway_container *container,
189 } 192 }
190 container_notify_subtree_changed(old_parent); 193 container_notify_subtree_changed(old_parent);
191 container_notify_subtree_changed(new_parent); 194 container_notify_subtree_changed(new_parent);
192 if (old_parent) { 195
193 if (old_parent->type == C_OUTPUT) {
194 arrange_output(old_parent);
195 } else {
196 arrange_children_of(old_parent);
197 }
198 }
199 if (new_parent->type == C_OUTPUT) {
200 arrange_output(new_parent);
201 } else {
202 arrange_children_of(new_parent);
203 }
204 // If view was moved to a fullscreen workspace, refocus the fullscreen view 196 // If view was moved to a fullscreen workspace, refocus the fullscreen view
205 struct sway_container *new_workspace = container; 197 struct sway_container *new_workspace = container;
206 if (new_workspace->type != C_WORKSPACE) { 198 if (new_workspace->type != C_WORKSPACE) {
@@ -215,7 +207,8 @@ void container_move_to(struct sway_container *container,
215 if (focus_ws->type != C_WORKSPACE) { 207 if (focus_ws->type != C_WORKSPACE) {
216 focus_ws = container_parent(focus_ws, C_WORKSPACE); 208 focus_ws = container_parent(focus_ws, C_WORKSPACE);
217 } 209 }
218 seat_set_focus(seat, new_workspace->sway_workspace->fullscreen->swayc); 210 seat_set_focus(seat,
211 new_workspace->sway_workspace->fullscreen->swayc);
219 if (focus_ws != new_workspace) { 212 if (focus_ws != new_workspace) {
220 seat_set_focus(seat, focus); 213 seat_set_focus(seat, focus);
221 } 214 }
@@ -309,7 +302,6 @@ static void workspace_rejigger(struct sway_container *ws,
309 container_reap_empty_recursive(original_parent); 302 container_reap_empty_recursive(original_parent);
310 wl_signal_emit(&child->events.reparent, original_parent); 303 wl_signal_emit(&child->events.reparent, original_parent);
311 container_create_notify(new_parent); 304 container_create_notify(new_parent);
312 arrange_workspace(ws);
313} 305}
314 306
315static void move_out_of_tabs_stacks(struct sway_container *container, 307static void move_out_of_tabs_stacks(struct sway_container *container,
@@ -320,11 +312,6 @@ static void move_out_of_tabs_stacks(struct sway_container *container,
320 wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id); 312 wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id);
321 current->parent->layout = move_dir == 313 current->parent->layout = move_dir ==
322 MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; 314 MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
323 if (current->parent->type == C_WORKSPACE) {
324 arrange_workspace(current->parent);
325 } else {
326 arrange_children_of(current->parent);
327 }
328 return; 315 return;
329 } 316 }
330 317
@@ -340,11 +327,6 @@ static void move_out_of_tabs_stacks(struct sway_container *container,
340 container_flatten(new_parent->parent); 327 container_flatten(new_parent->parent);
341 } 328 }
342 container_create_notify(new_parent); 329 container_create_notify(new_parent);
343 if (is_workspace) {
344 arrange_workspace(new_parent->parent);
345 } else {
346 arrange_children_of(new_parent);
347 }
348 container_notify_subtree_changed(new_parent); 330 container_notify_subtree_changed(new_parent);
349} 331}
350 332
@@ -368,10 +350,7 @@ void container_move(struct sway_container *container,
368 350
369 struct sway_container *new_parent = container_flatten(parent); 351 struct sway_container *new_parent = container_flatten(parent);
370 if (new_parent != parent) { 352 if (new_parent != parent) {
371 // Special case: we were the last one in this container, so flatten it 353 // Special case: we were the last one in this container, so leave
372 // and leave
373 arrange_children_of(new_parent);
374 update_debug_tree();
375 return; 354 return;
376 } 355 }
377 356
@@ -453,12 +432,9 @@ void container_move(struct sway_container *container,
453 wlr_log(L_DEBUG, "Hit limit, " 432 wlr_log(L_DEBUG, "Hit limit, "
454 "promoting descendant to sibling"); 433 "promoting descendant to sibling");
455 // Special case 434 // Special case
456 struct sway_container *old_parent = container->parent;
457 container_insert_child(current->parent, container, 435 container_insert_child(current->parent, container,
458 index + (offs < 0 ? 0 : 1)); 436 index + (offs < 0 ? 0 : 1));
459 container->width = container->height = 0; 437 container->width = container->height = 0;
460 arrange_children_of(current->parent);
461 arrange_children_of(old_parent);
462 return; 438 return;
463 } 439 }
464 } else { 440 } else {
@@ -492,14 +468,11 @@ void container_move(struct sway_container *container,
492 wlr_log(L_DEBUG, "Swapping siblings"); 468 wlr_log(L_DEBUG, "Swapping siblings");
493 sibling->parent->children->items[index + offs] = container; 469 sibling->parent->children->items[index + offs] = container;
494 sibling->parent->children->items[index] = sibling; 470 sibling->parent->children->items[index] = sibling;
495 arrange_children_of(sibling->parent);
496 } else { 471 } else {
497 wlr_log(L_DEBUG, "Promoting to sibling of cousin"); 472 wlr_log(L_DEBUG, "Promoting to sibling of cousin");
498 container_insert_child(sibling->parent, container, 473 container_insert_child(sibling->parent, container,
499 index_child(sibling) + (offs > 0 ? 0 : 1)); 474 index_child(sibling) + (offs > 0 ? 0 : 1));
500 container->width = container->height = 0; 475 container->width = container->height = 0;
501 arrange_children_of(sibling->parent);
502 arrange_children_of(old_parent);
503 } 476 }
504 sibling = NULL; 477 sibling = NULL;
505 break; 478 break;
@@ -513,8 +486,6 @@ void container_move(struct sway_container *container,
513 "(move dir: %d)", limit, move_dir); 486 "(move dir: %d)", limit, move_dir);
514 container_insert_child(sibling, container, limit); 487 container_insert_child(sibling, container, limit);
515 container->width = container->height = 0; 488 container->width = container->height = 0;
516 arrange_children_of(sibling);
517 arrange_children_of(old_parent);
518 sibling = NULL; 489 sibling = NULL;
519 } else { 490 } else {
520 wlr_log(L_DEBUG, "Reparenting container (perpendicular)"); 491 wlr_log(L_DEBUG, "Reparenting container (perpendicular)");
@@ -538,8 +509,6 @@ void container_move(struct sway_container *container,
538 container_add_child(sibling, container); 509 container_add_child(sibling, container);
539 } 510 }
540 container->width = container->height = 0; 511 container->width = container->height = 0;
541 arrange_children_of(sibling);
542 arrange_children_of(old_parent);
543 sibling = NULL; 512 sibling = NULL;
544 } 513 }
545 break; 514 break;
@@ -864,7 +833,6 @@ struct sway_container *container_split(struct sway_container *child,
864 // Special case: this just behaves like splitt 833 // Special case: this just behaves like splitt
865 child->prev_layout = child->layout; 834 child->prev_layout = child->layout;
866 child->layout = layout; 835 child->layout = layout;
867 arrange_children_of(child);
868 return child; 836 return child;
869 } 837 }
870 838
@@ -882,7 +850,7 @@ struct sway_container *container_split(struct sway_container *child,
882 850
883 struct sway_seat *seat = input_manager_get_default_seat(input_manager); 851 struct sway_seat *seat = input_manager_get_default_seat(input_manager);
884 bool set_focus = (seat_get_focus(seat) == child); 852 bool set_focus = (seat_get_focus(seat) == child);
885 853
886 add_gaps(cont); 854 add_gaps(cont);
887 855
888 if (child->type == C_WORKSPACE) { 856 if (child->type == C_WORKSPACE) {
@@ -912,7 +880,6 @@ struct sway_container *container_split(struct sway_container *child,
912 } 880 }
913 881
914 container_notify_subtree_changed(cont); 882 container_notify_subtree_changed(cont);
915 arrange_children_of(cont);
916 return cont; 883 return cont;
917} 884}
918 885
@@ -1050,9 +1017,6 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
1050 prev_workspace_name = stored_prev_name; 1017 prev_workspace_name = stored_prev_name;
1051 } 1018 }
1052 1019
1053 arrange_children_of(con1->parent);
1054 arrange_children_of(con2->parent);
1055
1056 if (fs1 && con2->type == C_VIEW) { 1020 if (fs1 && con2->type == C_VIEW) {
1057 view_set_fullscreen(con2->sway_view, true); 1021 view_set_fullscreen(con2->sway_view, true);
1058 } 1022 }
diff --git a/sway/tree/output.c b/sway/tree/output.c
index ed7e941e..8af319d5 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -26,12 +26,10 @@ static void restore_workspaces(struct sway_container *output) {
26 j--; 26 j--;
27 } 27 }
28 } 28 }
29
30 arrange_output(other);
31 } 29 }
32 30
33 container_sort_workspaces(output); 31 container_sort_workspaces(output);
34 arrange_output(output); 32 arrange_and_commit(&root_container);
35} 33}
36 34
37struct sway_container *output_create( 35struct sway_container *output_create(
@@ -68,6 +66,7 @@ struct sway_container *output_create(
68 66
69 struct sway_container *output = container_create(C_OUTPUT); 67 struct sway_container *output = container_create(C_OUTPUT);
70 output->sway_output = sway_output; 68 output->sway_output = sway_output;
69 sway_output->swayc = output;
71 output->name = strdup(name); 70 output->name = strdup(name);
72 if (output->name == NULL) { 71 if (output->name == NULL) {
73 container_destroy(output); 72 container_destroy(output);
diff --git a/sway/tree/view.c b/sway/tree/view.c
index c9c82405..658a94e8 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -25,6 +25,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
25 view->impl = impl; 25 view->impl = impl;
26 view->executed_criteria = create_list(); 26 view->executed_criteria = create_list();
27 view->marks = create_list(); 27 view->marks = create_list();
28 view->instructions = create_list();
28 wl_signal_init(&view->events.unmap); 29 wl_signal_init(&view->events.unmap);
29} 30}
30 31
@@ -37,6 +38,11 @@ void view_destroy(struct sway_view *view) {
37 view_unmap(view); 38 view_unmap(view);
38 } 39 }
39 40
41 if (!sway_assert(view->instructions->length == 0,
42 "Tried to destroy view with pending instructions")) {
43 return;
44 }
45
40 list_free(view->executed_criteria); 46 list_free(view->executed_criteria);
41 47
42 for (int i = 0; i < view->marks->length; ++i) { 48 for (int i = 0; i < view->marks->length; ++i) {
@@ -44,6 +50,8 @@ void view_destroy(struct sway_view *view) {
44 } 50 }
45 list_free(view->marks); 51 list_free(view->marks);
46 52
53 list_free(view->instructions);
54
47 wlr_texture_destroy(view->marks_focused); 55 wlr_texture_destroy(view->marks_focused);
48 wlr_texture_destroy(view->marks_focused_inactive); 56 wlr_texture_destroy(view->marks_focused_inactive);
49 wlr_texture_destroy(view->marks_unfocused); 57 wlr_texture_destroy(view->marks_unfocused);
@@ -119,29 +127,30 @@ const char *view_get_shell(struct sway_view *view) {
119 return "unknown"; 127 return "unknown";
120} 128}
121 129
122void view_configure(struct sway_view *view, double lx, double ly, int width, 130uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
123 int height) { 131 int height) {
124 if (view->impl->configure) { 132 if (view->impl->configure) {
125 view->impl->configure(view, lx, ly, width, height); 133 return view->impl->configure(view, lx, ly, width, height);
126 } 134 }
135 return 0;
127} 136}
128 137
129static void view_autoconfigure_floating(struct sway_view *view) { 138void view_init_floating(struct sway_view *view) {
130 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); 139 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
131 int max_width = ws->width * 0.6666; 140 int max_width = ws->width * 0.6666;
132 int max_height = ws->height * 0.6666; 141 int max_height = ws->height * 0.6666;
133 int width = 142 view->width =
134 view->natural_width > max_width ? max_width : view->natural_width; 143 view->natural_width > max_width ? max_width : view->natural_width;
135 int height = 144 view->height =
136 view->natural_height > max_height ? max_height : view->natural_height; 145 view->natural_height > max_height ? max_height : view->natural_height;
137 int lx = ws->x + (ws->width - width) / 2; 146 view->x = ws->x + (ws->width - view->width) / 2;
138 int ly = ws->y + (ws->height - height) / 2; 147 view->y = ws->y + (ws->height - view->height) / 2;
139 148
140 // If the view's border is B_NONE then these properties are ignored. 149 // If the view's border is B_NONE then these properties are ignored.
141 view->border_top = view->border_bottom = true; 150 view->border_top = view->border_bottom = true;
142 view->border_left = view->border_right = true; 151 view->border_left = view->border_right = true;
143 152
144 view_configure(view, lx, ly, width, height); 153 container_set_geometry_from_floating_view(view->swayc);
145} 154}
146 155
147void view_autoconfigure(struct sway_view *view) { 156void view_autoconfigure(struct sway_view *view) {
@@ -153,12 +162,14 @@ void view_autoconfigure(struct sway_view *view) {
153 struct sway_container *output = container_parent(view->swayc, C_OUTPUT); 162 struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
154 163
155 if (view->is_fullscreen) { 164 if (view->is_fullscreen) {
156 view_configure(view, output->x, output->y, output->width, output->height); 165 view->x = output->x;
166 view->y = output->y;
167 view->width = output->width;
168 view->height = output->height;
157 return; 169 return;
158 } 170 }
159 171
160 if (container_is_floating(view->swayc)) { 172 if (container_is_floating(view->swayc)) {
161 view_autoconfigure_floating(view);
162 return; 173 return;
163 } 174 }
164 175
@@ -178,20 +189,22 @@ void view_autoconfigure(struct sway_view *view) {
178 } 189 }
179 } 190 }
180 191
192 struct sway_container *con = view->swayc;
193
181 view->border_top = view->border_bottom = true; 194 view->border_top = view->border_bottom = true;
182 view->border_left = view->border_right = true; 195 view->border_left = view->border_right = true;
183 if (config->hide_edge_borders == E_BOTH 196 if (config->hide_edge_borders == E_BOTH
184 || config->hide_edge_borders == E_VERTICAL 197 || config->hide_edge_borders == E_VERTICAL
185 || (config->hide_edge_borders == E_SMART && !other_views)) { 198 || (config->hide_edge_borders == E_SMART && !other_views)) {
186 view->border_left = view->swayc->x != ws->x; 199 view->border_left = con->x != ws->x;
187 int right_x = view->swayc->x + view->swayc->width; 200 int right_x = con->x + con->width;
188 view->border_right = right_x != ws->x + ws->width; 201 view->border_right = right_x != ws->x + ws->width;
189 } 202 }
190 if (config->hide_edge_borders == E_BOTH 203 if (config->hide_edge_borders == E_BOTH
191 || config->hide_edge_borders == E_HORIZONTAL 204 || config->hide_edge_borders == E_HORIZONTAL
192 || (config->hide_edge_borders == E_SMART && !other_views)) { 205 || (config->hide_edge_borders == E_SMART && !other_views)) {
193 view->border_top = view->swayc->y != ws->y; 206 view->border_top = con->y != ws->y;
194 int bottom_y = view->swayc->y + view->swayc->height; 207 int bottom_y = con->y + con->height;
195 view->border_bottom = bottom_y != ws->y + ws->height; 208 view->border_bottom = bottom_y != ws->y + ws->height;
196 } 209 }
197 210
@@ -202,45 +215,44 @@ void view_autoconfigure(struct sway_view *view) {
202 // In a tabbed or stacked container, the swayc's y is the top of the title 215 // In a tabbed or stacked container, the swayc's y is the top of the title
203 // area. We have to offset the surface y by the height of the title bar, and 216 // area. We have to offset the surface y by the height of the title bar, and
204 // disable any top border because we'll always have the title bar. 217 // disable any top border because we'll always have the title bar.
205 if (view->swayc->parent->layout == L_TABBED) { 218 if (con->parent->layout == L_TABBED) {
206 y_offset = container_titlebar_height(); 219 y_offset = container_titlebar_height();
207 view->border_top = false; 220 view->border_top = false;
208 } else if (view->swayc->parent->layout == L_STACKED) { 221 } else if (con->parent->layout == L_STACKED) {
209 y_offset = container_titlebar_height() 222 y_offset = container_titlebar_height() * con->parent->children->length;
210 * view->swayc->parent->children->length;
211 view->border_top = false; 223 view->border_top = false;
212 } 224 }
213 225
214 switch (view->border) { 226 switch (view->border) {
215 case B_NONE: 227 case B_NONE:
216 x = view->swayc->x; 228 x = con->x;
217 y = view->swayc->y + y_offset; 229 y = con->y + y_offset;
218 width = view->swayc->width; 230 width = con->width;
219 height = view->swayc->height - y_offset; 231 height = con->height - y_offset;
220 break; 232 break;
221 case B_PIXEL: 233 case B_PIXEL:
222 x = view->swayc->x + view->border_thickness * view->border_left; 234 x = con->x + view->border_thickness * view->border_left;
223 y = view->swayc->y + view->border_thickness * view->border_top + y_offset; 235 y = con->y + view->border_thickness * view->border_top + y_offset;
224 width = view->swayc->width 236 width = con->width
225 - view->border_thickness * view->border_left 237 - view->border_thickness * view->border_left
226 - view->border_thickness * view->border_right; 238 - view->border_thickness * view->border_right;
227 height = view->swayc->height - y_offset 239 height = con->height - y_offset
228 - view->border_thickness * view->border_top 240 - view->border_thickness * view->border_top
229 - view->border_thickness * view->border_bottom; 241 - view->border_thickness * view->border_bottom;
230 break; 242 break;
231 case B_NORMAL: 243 case B_NORMAL:
232 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border 244 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
233 x = view->swayc->x + view->border_thickness * view->border_left; 245 x = con->x + view->border_thickness * view->border_left;
234 width = view->swayc->width 246 width = con->width
235 - view->border_thickness * view->border_left 247 - view->border_thickness * view->border_left
236 - view->border_thickness * view->border_right; 248 - view->border_thickness * view->border_right;
237 if (y_offset) { 249 if (y_offset) {
238 y = view->swayc->y + y_offset; 250 y = con->y + y_offset;
239 height = view->swayc->height - y_offset 251 height = con->height - y_offset
240 - view->border_thickness * view->border_bottom; 252 - view->border_thickness * view->border_bottom;
241 } else { 253 } else {
242 y = view->swayc->y + container_titlebar_height(); 254 y = con->y + container_titlebar_height();
243 height = view->swayc->height - container_titlebar_height() 255 height = con->height - container_titlebar_height()
244 - view->border_thickness * view->border_bottom; 256 - view->border_thickness * view->border_bottom;
245 } 257 }
246 break; 258 break;
@@ -248,7 +260,8 @@ void view_autoconfigure(struct sway_view *view) {
248 260
249 view->x = x; 261 view->x = x;
250 view->y = y; 262 view->y = y;
251 view_configure(view, x, y, width, height); 263 view->width = width;
264 view->height = height;
252} 265}
253 266
254void view_set_activated(struct sway_view *view, bool activated) { 267void view_set_activated(struct sway_view *view, bool activated) {
@@ -257,8 +270,7 @@ void view_set_activated(struct sway_view *view, bool activated) {
257 } 270 }
258} 271}
259 272
260// Set fullscreen, but without IPC events or arranging windows. 273void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
261void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) {
262 if (view->is_fullscreen == fullscreen) { 274 if (view->is_fullscreen == fullscreen) {
263 return; 275 return;
264 } 276 }
@@ -304,27 +316,17 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) {
304 } else { 316 } else {
305 workspace->sway_workspace->fullscreen = NULL; 317 workspace->sway_workspace->fullscreen = NULL;
306 if (container_is_floating(view->swayc)) { 318 if (container_is_floating(view->swayc)) {
307 view_configure(view, view->saved_x, view->saved_y, 319 view->x = view->saved_x;
308 view->saved_width, view->saved_height); 320 view->y = view->saved_y;
321 view->width = view->saved_width;
322 view->height = view->saved_height;
323 container_set_geometry_from_floating_view(view->swayc);
309 } else { 324 } else {
310 view->swayc->width = view->swayc->saved_width; 325 view->swayc->width = view->swayc->saved_width;
311 view->swayc->height = view->swayc->saved_height; 326 view->swayc->height = view->swayc->saved_height;
312 view_autoconfigure(view);
313 } 327 }
314 } 328 }
315}
316 329
317void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
318 if (view->is_fullscreen == fullscreen) {
319 return;
320 }
321
322 view_set_fullscreen_raw(view, fullscreen);
323
324 struct sway_container *workspace =
325 container_parent(view->swayc, C_WORKSPACE);
326 arrange_workspace(workspace);
327 output_damage_whole(workspace->parent->sway_output);
328 ipc_event_window(view->swayc, "fullscreen_mode"); 330 ipc_event_window(view->swayc, "fullscreen_mode");
329} 331}
330 332
@@ -507,8 +509,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
507 509
508 if (view->impl->wants_floating && view->impl->wants_floating(view)) { 510 if (view->impl->wants_floating && view->impl->wants_floating(view)) {
509 container_set_floating(view->swayc, true); 511 container_set_floating(view->swayc, true);
510 } else {
511 arrange_children_of(cont->parent);
512 } 512 }
513 513
514 input_manager_set_focus(input_manager, cont); 514 input_manager_set_focus(input_manager, cont);
@@ -520,7 +520,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
520 container_notify_subtree_changed(view->swayc->parent); 520 container_notify_subtree_changed(view->swayc->parent);
521 view_execute_criteria(view); 521 view_execute_criteria(view);
522 522
523 container_damage_whole(cont);
524 view_handle_container_reparent(&view->container_reparent, NULL); 523 view_handle_container_reparent(&view->container_reparent, NULL);
525} 524}
526 525
@@ -551,11 +550,7 @@ void view_unmap(struct sway_view *view) {
551 view->title_format = NULL; 550 view->title_format = NULL;
552 } 551 }
553 552
554 if (parent->type == C_OUTPUT) { 553 arrange_and_commit(parent);
555 arrange_output(parent);
556 } else {
557 arrange_children_of(parent);
558 }
559} 554}
560 555
561void view_update_position(struct sway_view *view, double lx, double ly) { 556void view_update_position(struct sway_view *view, double lx, double ly) {
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 9ba210fd..ead752ad 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -425,7 +425,7 @@ bool workspace_switch(struct sway_container *workspace) {
425 } 425 }
426 seat_set_focus(seat, next); 426 seat_set_focus(seat, next);
427 struct sway_container *output = container_parent(workspace, C_OUTPUT); 427 struct sway_container *output = container_parent(workspace, C_OUTPUT);
428 arrange_output(output); 428 arrange_and_commit(output);
429 return true; 429 return true;
430} 430}
431 431