aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Ankit Pandey <anpandey@protonmail.com>2022-12-11 16:44:48 -0800
committerLibravatar Ronan Pigott <ronan@rjp.ie>2023-03-14 23:26:42 -0700
commit90c2d631e2dc4c7633bb8fcd92f300a4a2dffb86 (patch)
tree218db72a61c8e7b55cf39d241e51ee0780636670
parentman: add warning for hide_cursor configuration (diff)
downloadsway-90c2d631e2dc4c7633bb8fcd92f300a4a2dffb86.tar.gz
sway-90c2d631e2dc4c7633bb8fcd92f300a4a2dffb86.tar.zst
sway-90c2d631e2dc4c7633bb8fcd92f300a4a2dffb86.zip
root: Try to preserve relative positions of floating containers
This makes the behavior of floating containers more consistent with i3. The coordinates of the container are scaled when the size of the workspace it is on changes or when the container is moved between workspaces on different outputs. For scratchpad containers, add a new state that preserves the dimensions of the last output the window appeared on. This is necessary because after a container is hidden in the scratchpad, we expect it to be in the same relative position on the output when it reappears. We can't just use the container's attached workspace because that workspace's dimensions might have been changed or the workspace as a whole could have been destroyed.
-rw-r--r--include/sway/tree/container.h8
-rw-r--r--sway/commands/move.c12
-rw-r--r--sway/tree/arrange.c14
-rw-r--r--sway/tree/container.c22
-rw-r--r--sway/tree/root.c27
5 files changed, 68 insertions, 15 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 751612e2..fe3ee8a8 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -113,6 +113,11 @@ struct sway_container {
113 // Hidden scratchpad containers have a NULL parent. 113 // Hidden scratchpad containers have a NULL parent.
114 bool scratchpad; 114 bool scratchpad;
115 115
116 // Stores last output size and position for adjusting coordinates of
117 // scratchpad windows.
118 // Unused for non-scratchpad windows.
119 struct wlr_box transform;
120
116 float alpha; 121 float alpha;
117 122
118 struct wlr_texture *title_focused; 123 struct wlr_texture *title_focused;
@@ -196,6 +201,9 @@ size_t container_titlebar_height(void);
196void floating_calculate_constraints(int *min_width, int *max_width, 201void floating_calculate_constraints(int *min_width, int *max_width,
197 int *min_height, int *max_height); 202 int *min_height, int *max_height);
198 203
204void floating_fix_coordinates(struct sway_container *con,
205 struct wlr_box *old, struct wlr_box *new);
206
199void container_floating_resize_and_center(struct sway_container *con); 207void container_floating_resize_and_center(struct sway_container *con);
200 208
201void container_floating_set_default_size(struct sway_container *con); 209void container_floating_set_default_size(struct sway_container *con);
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 7bd1fe3e..9e40a3b4 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -206,9 +206,17 @@ static void container_move_to_workspace(struct sway_container *container,
206 container_detach(container); 206 container_detach(container);
207 workspace_add_floating(workspace, container); 207 workspace_add_floating(workspace, container);
208 container_handle_fullscreen_reparent(container); 208 container_handle_fullscreen_reparent(container);
209 // If changing output, center it within the workspace 209 // If changing output, adjust the coordinates of the window.
210 if (old_output != workspace->output && !container->pending.fullscreen_mode) { 210 if (old_output != workspace->output && !container->pending.fullscreen_mode) {
211 container_floating_move_to_center(container); 211 struct wlr_box workspace_box, old_workspace_box;
212 workspace_get_box(workspace, &workspace_box);
213 workspace_get_box(old_workspace, &old_workspace_box);
214 floating_fix_coordinates(container, &old_workspace_box, &workspace_box);
215 if (container->scratchpad && workspace->output) {
216 struct wlr_box output_box;
217 output_get_box(workspace->output, &output_box);
218 container->transform = workspace_box;
219 }
212 } 220 }
213 } else { 221 } else {
214 container_detach(container); 222 container_detach(container);
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 9c1a11e5..af925d05 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -264,6 +264,9 @@ void arrange_workspace(struct sway_workspace *workspace) {
264 area->width, area->height, area->x, area->y); 264 area->width, area->height, area->x, area->y);
265 265
266 bool first_arrange = workspace->width == 0 && workspace->height == 0; 266 bool first_arrange = workspace->width == 0 && workspace->height == 0;
267 struct wlr_box prev_box;
268 workspace_get_box(workspace, &prev_box);
269
267 double prev_x = workspace->x - workspace->current_gaps.left; 270 double prev_x = workspace->x - workspace->current_gaps.left;
268 double prev_y = workspace->y - workspace->current_gaps.top; 271 double prev_y = workspace->y - workspace->current_gaps.top;
269 workspace->width = area->width; 272 workspace->width = area->width;
@@ -277,13 +280,14 @@ void arrange_workspace(struct sway_workspace *workspace) {
277 if (!first_arrange && (diff_x != 0 || diff_y != 0)) { 280 if (!first_arrange && (diff_x != 0 || diff_y != 0)) {
278 for (int i = 0; i < workspace->floating->length; ++i) { 281 for (int i = 0; i < workspace->floating->length; ++i) {
279 struct sway_container *floater = workspace->floating->items[i]; 282 struct sway_container *floater = workspace->floating->items[i];
280 container_floating_translate(floater, diff_x, diff_y);
281 double center_x = floater->pending.x + floater->pending.width / 2;
282 double center_y = floater->pending.y + floater->pending.height / 2;
283 struct wlr_box workspace_box; 283 struct wlr_box workspace_box;
284 workspace_get_box(workspace, &workspace_box); 284 workspace_get_box(workspace, &workspace_box);
285 if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { 285 floating_fix_coordinates(floater, &prev_box, &workspace_box);
286 container_floating_move_to_center(floater); 286 // Set transformation for scratchpad windows.
287 if (floater->scratchpad) {
288 struct wlr_box output_box;
289 output_get_box(output, &output_box);
290 floater->transform = output_box;
287 } 291 }
288 } 292 }
289 } 293 }
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 8222a506..d2c4ffc4 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -712,6 +712,21 @@ void floating_calculate_constraints(int *min_width, int *max_width,
712 712
713} 713}
714 714
715void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, struct wlr_box *new) {
716 if (!old->width || !old->height) {
717 // Fall back to centering on the workspace.
718 container_floating_move_to_center(con);
719 } else {
720 int rel_x = con->pending.x - old->x + (con->pending.width / 2);
721 int rel_y = con->pending.y - old->y + (con->pending.height / 2);
722
723 con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->pending.width / 2);
724 con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->pending.height / 2);
725
726 sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y);
727 }
728}
729
715static void floating_natural_resize(struct sway_container *con) { 730static void floating_natural_resize(struct sway_container *con) {
716 int min_width, max_width, min_height, max_height; 731 int min_width, max_width, min_height, max_height;
717 floating_calculate_constraints(&min_width, &max_width, 732 floating_calculate_constraints(&min_width, &max_width,
@@ -1025,6 +1040,13 @@ void container_floating_move_to(struct sway_container *con,
1025 workspace_add_floating(new_workspace, con); 1040 workspace_add_floating(new_workspace, con);
1026 arrange_workspace(old_workspace); 1041 arrange_workspace(old_workspace);
1027 arrange_workspace(new_workspace); 1042 arrange_workspace(new_workspace);
1043 // If the moved container was a visible scratchpad container, then
1044 // update its transform.
1045 if (con->scratchpad) {
1046 struct wlr_box output_box;
1047 output_get_box(new_output, &output_box);
1048 con->transform = output_box;
1049 }
1028 workspace_detect_urgent(old_workspace); 1050 workspace_detect_urgent(old_workspace);
1029 workspace_detect_urgent(new_workspace); 1051 workspace_detect_urgent(new_workspace);
1030 } 1052 }
diff --git a/sway/tree/root.c b/sway/tree/root.c
index 95129a88..233358d2 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -56,6 +56,16 @@ void root_destroy(struct sway_root *root) {
56 free(root); 56 free(root);
57} 57}
58 58
59static void set_container_transform(struct sway_workspace *ws,
60 struct sway_container *con) {
61 struct sway_output *output = ws->output;
62 struct wlr_box box = {0};
63 if (output) {
64 output_get_box(output, &box);
65 }
66 con->transform = box;
67}
68
59void root_scratchpad_add_container(struct sway_container *con, struct sway_workspace *ws) { 69void root_scratchpad_add_container(struct sway_container *con, struct sway_workspace *ws) {
60 if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) { 70 if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
61 return; 71 return;
@@ -64,6 +74,8 @@ void root_scratchpad_add_container(struct sway_container *con, struct sway_works
64 struct sway_container *parent = con->pending.parent; 74 struct sway_container *parent = con->pending.parent;
65 struct sway_workspace *workspace = con->pending.workspace; 75 struct sway_workspace *workspace = con->pending.workspace;
66 76
77 set_container_transform(workspace, con);
78
67 // Clear the fullscreen mode when sending to the scratchpad 79 // Clear the fullscreen mode when sending to the scratchpad
68 if (con->pending.fullscreen_mode != FULLSCREEN_NONE) { 80 if (con->pending.fullscreen_mode != FULLSCREEN_NONE) {
69 container_fullscreen_disable(con); 81 container_fullscreen_disable(con);
@@ -142,15 +154,12 @@ void root_scratchpad_show(struct sway_container *con) {
142 } 154 }
143 workspace_add_floating(new_ws, con); 155 workspace_add_floating(new_ws, con);
144 156
145 // Make sure the container's center point overlaps this workspace 157 if (new_ws->output) {
146 double center_lx = con->pending.x + con->pending.width / 2; 158 struct wlr_box output_box;
147 double center_ly = con->pending.y + con->pending.height / 2; 159 output_get_box(new_ws->output, &output_box);
148 160 floating_fix_coordinates(con, &con->transform, &output_box);
149 struct wlr_box workspace_box;
150 workspace_get_box(new_ws, &workspace_box);
151 if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
152 container_floating_resize_and_center(con);
153 } 161 }
162 set_container_transform(new_ws, con);
154 163
155 arrange_workspace(new_ws); 164 arrange_workspace(new_ws);
156 seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node)); 165 seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node));
@@ -173,6 +182,8 @@ void root_scratchpad_hide(struct sway_container *con) {
173 return; 182 return;
174 } 183 }
175 184
185 set_container_transform(con->pending.workspace, con);
186
176 disable_fullscreen(con, NULL); 187 disable_fullscreen(con, NULL);
177 container_for_each_child(con, disable_fullscreen, NULL); 188 container_for_each_child(con, disable_fullscreen, NULL);
178 container_detach(con); 189 container_detach(con);