Skip to content

Commit 90c2d63

Browse files
anpandeyrpigott
authored andcommitted
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.
1 parent ebeed7e commit 90c2d63

File tree

5 files changed

+68
-15
lines changed

5 files changed

+68
-15
lines changed

include/sway/tree/container.h

+8
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ struct sway_container {
113113
// Hidden scratchpad containers have a NULL parent.
114114
bool scratchpad;
115115

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+
116121
float alpha;
117122

118123
struct wlr_texture *title_focused;
@@ -196,6 +201,9 @@ size_t container_titlebar_height(void);
196201
void floating_calculate_constraints(int *min_width, int *max_width,
197202
int *min_height, int *max_height);
198203

204+
void floating_fix_coordinates(struct sway_container *con,
205+
struct wlr_box *old, struct wlr_box *new);
206+
199207
void container_floating_resize_and_center(struct sway_container *con);
200208

201209
void container_floating_set_default_size(struct sway_container *con);

sway/commands/move.c

+10-2
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,17 @@ static void container_move_to_workspace(struct sway_container *container,
206206
container_detach(container);
207207
workspace_add_floating(workspace, container);
208208
container_handle_fullscreen_reparent(container);
209-
// If changing output, center it within the workspace
209+
// If changing output, adjust the coordinates of the window.
210210
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+
}
212220
}
213221
} else {
214222
container_detach(container);

sway/tree/arrange.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ void arrange_workspace(struct sway_workspace *workspace) {
264264
area->width, area->height, area->x, area->y);
265265

266266
bool first_arrange = workspace->width == 0 && workspace->height == 0;
267+
struct wlr_box prev_box;
268+
workspace_get_box(workspace, &prev_box);
269+
267270
double prev_x = workspace->x - workspace->current_gaps.left;
268271
double prev_y = workspace->y - workspace->current_gaps.top;
269272
workspace->width = area->width;
@@ -277,13 +280,14 @@ void arrange_workspace(struct sway_workspace *workspace) {
277280
if (!first_arrange && (diff_x != 0 || diff_y != 0)) {
278281
for (int i = 0; i < workspace->floating->length; ++i) {
279282
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;
283283
struct wlr_box workspace_box;
284284
workspace_get_box(workspace, &workspace_box);
285-
if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) {
286-
container_floating_move_to_center(floater);
285+
floating_fix_coordinates(floater, &prev_box, &workspace_box);
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;
287291
}
288292
}
289293
}

sway/tree/container.c

+22
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,21 @@ void floating_calculate_constraints(int *min_width, int *max_width,
712712

713713
}
714714

715+
void 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+
715730
static void floating_natural_resize(struct sway_container *con) {
716731
int min_width, max_width, min_height, max_height;
717732
floating_calculate_constraints(&min_width, &max_width,
@@ -1025,6 +1040,13 @@ void container_floating_move_to(struct sway_container *con,
10251040
workspace_add_floating(new_workspace, con);
10261041
arrange_workspace(old_workspace);
10271042
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+
}
10281050
workspace_detect_urgent(old_workspace);
10291051
workspace_detect_urgent(new_workspace);
10301052
}

sway/tree/root.c

+19-8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ void root_destroy(struct sway_root *root) {
5656
free(root);
5757
}
5858

59+
static 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+
5969
void root_scratchpad_add_container(struct sway_container *con, struct sway_workspace *ws) {
6070
if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
6171
return;
@@ -64,6 +74,8 @@ void root_scratchpad_add_container(struct sway_container *con, struct sway_works
6474
struct sway_container *parent = con->pending.parent;
6575
struct sway_workspace *workspace = con->pending.workspace;
6676

77+
set_container_transform(workspace, con);
78+
6779
// Clear the fullscreen mode when sending to the scratchpad
6880
if (con->pending.fullscreen_mode != FULLSCREEN_NONE) {
6981
container_fullscreen_disable(con);
@@ -142,15 +154,12 @@ void root_scratchpad_show(struct sway_container *con) {
142154
}
143155
workspace_add_floating(new_ws, con);
144156

145-
// Make sure the container's center point overlaps this workspace
146-
double center_lx = con->pending.x + con->pending.width / 2;
147-
double center_ly = con->pending.y + con->pending.height / 2;
148-
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);
157+
if (new_ws->output) {
158+
struct wlr_box output_box;
159+
output_get_box(new_ws->output, &output_box);
160+
floating_fix_coordinates(con, &con->transform, &output_box);
153161
}
162+
set_container_transform(new_ws, con);
154163

155164
arrange_workspace(new_ws);
156165
seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node));
@@ -173,6 +182,8 @@ void root_scratchpad_hide(struct sway_container *con) {
173182
return;
174183
}
175184

185+
set_container_transform(con->pending.workspace, con);
186+
176187
disable_fullscreen(con, NULL);
177188
container_for_each_child(con, disable_fullscreen, NULL);
178189
container_detach(con);

0 commit comments

Comments
 (0)