mirror of
https://github.com/swaywm/sway.git
synced 2024-12-01 10:56:36 +00:00
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.
This commit is contained in:
parent
ebeed7e303
commit
90c2d631e2
|
@ -113,6 +113,11 @@ struct sway_container {
|
||||||
// Hidden scratchpad containers have a NULL parent.
|
// Hidden scratchpad containers have a NULL parent.
|
||||||
bool scratchpad;
|
bool scratchpad;
|
||||||
|
|
||||||
|
// Stores last output size and position for adjusting coordinates of
|
||||||
|
// scratchpad windows.
|
||||||
|
// Unused for non-scratchpad windows.
|
||||||
|
struct wlr_box transform;
|
||||||
|
|
||||||
float alpha;
|
float alpha;
|
||||||
|
|
||||||
struct wlr_texture *title_focused;
|
struct wlr_texture *title_focused;
|
||||||
|
@ -196,6 +201,9 @@ size_t container_titlebar_height(void);
|
||||||
void floating_calculate_constraints(int *min_width, int *max_width,
|
void floating_calculate_constraints(int *min_width, int *max_width,
|
||||||
int *min_height, int *max_height);
|
int *min_height, int *max_height);
|
||||||
|
|
||||||
|
void floating_fix_coordinates(struct sway_container *con,
|
||||||
|
struct wlr_box *old, struct wlr_box *new);
|
||||||
|
|
||||||
void container_floating_resize_and_center(struct sway_container *con);
|
void container_floating_resize_and_center(struct sway_container *con);
|
||||||
|
|
||||||
void container_floating_set_default_size(struct sway_container *con);
|
void container_floating_set_default_size(struct sway_container *con);
|
||||||
|
|
|
@ -206,9 +206,17 @@ static void container_move_to_workspace(struct sway_container *container,
|
||||||
container_detach(container);
|
container_detach(container);
|
||||||
workspace_add_floating(workspace, container);
|
workspace_add_floating(workspace, container);
|
||||||
container_handle_fullscreen_reparent(container);
|
container_handle_fullscreen_reparent(container);
|
||||||
// If changing output, center it within the workspace
|
// If changing output, adjust the coordinates of the window.
|
||||||
if (old_output != workspace->output && !container->pending.fullscreen_mode) {
|
if (old_output != workspace->output && !container->pending.fullscreen_mode) {
|
||||||
container_floating_move_to_center(container);
|
struct wlr_box workspace_box, old_workspace_box;
|
||||||
|
workspace_get_box(workspace, &workspace_box);
|
||||||
|
workspace_get_box(old_workspace, &old_workspace_box);
|
||||||
|
floating_fix_coordinates(container, &old_workspace_box, &workspace_box);
|
||||||
|
if (container->scratchpad && workspace->output) {
|
||||||
|
struct wlr_box output_box;
|
||||||
|
output_get_box(workspace->output, &output_box);
|
||||||
|
container->transform = workspace_box;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
container_detach(container);
|
container_detach(container);
|
||||||
|
|
|
@ -264,6 +264,9 @@ void arrange_workspace(struct sway_workspace *workspace) {
|
||||||
area->width, area->height, area->x, area->y);
|
area->width, area->height, area->x, area->y);
|
||||||
|
|
||||||
bool first_arrange = workspace->width == 0 && workspace->height == 0;
|
bool first_arrange = workspace->width == 0 && workspace->height == 0;
|
||||||
|
struct wlr_box prev_box;
|
||||||
|
workspace_get_box(workspace, &prev_box);
|
||||||
|
|
||||||
double prev_x = workspace->x - workspace->current_gaps.left;
|
double prev_x = workspace->x - workspace->current_gaps.left;
|
||||||
double prev_y = workspace->y - workspace->current_gaps.top;
|
double prev_y = workspace->y - workspace->current_gaps.top;
|
||||||
workspace->width = area->width;
|
workspace->width = area->width;
|
||||||
|
@ -277,13 +280,14 @@ void arrange_workspace(struct sway_workspace *workspace) {
|
||||||
if (!first_arrange && (diff_x != 0 || diff_y != 0)) {
|
if (!first_arrange && (diff_x != 0 || diff_y != 0)) {
|
||||||
for (int i = 0; i < workspace->floating->length; ++i) {
|
for (int i = 0; i < workspace->floating->length; ++i) {
|
||||||
struct sway_container *floater = workspace->floating->items[i];
|
struct sway_container *floater = workspace->floating->items[i];
|
||||||
container_floating_translate(floater, diff_x, diff_y);
|
|
||||||
double center_x = floater->pending.x + floater->pending.width / 2;
|
|
||||||
double center_y = floater->pending.y + floater->pending.height / 2;
|
|
||||||
struct wlr_box workspace_box;
|
struct wlr_box workspace_box;
|
||||||
workspace_get_box(workspace, &workspace_box);
|
workspace_get_box(workspace, &workspace_box);
|
||||||
if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) {
|
floating_fix_coordinates(floater, &prev_box, &workspace_box);
|
||||||
container_floating_move_to_center(floater);
|
// Set transformation for scratchpad windows.
|
||||||
|
if (floater->scratchpad) {
|
||||||
|
struct wlr_box output_box;
|
||||||
|
output_get_box(output, &output_box);
|
||||||
|
floater->transform = output_box;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -712,6 +712,21 @@ void floating_calculate_constraints(int *min_width, int *max_width,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, struct wlr_box *new) {
|
||||||
|
if (!old->width || !old->height) {
|
||||||
|
// Fall back to centering on the workspace.
|
||||||
|
container_floating_move_to_center(con);
|
||||||
|
} else {
|
||||||
|
int rel_x = con->pending.x - old->x + (con->pending.width / 2);
|
||||||
|
int rel_y = con->pending.y - old->y + (con->pending.height / 2);
|
||||||
|
|
||||||
|
con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->pending.width / 2);
|
||||||
|
con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->pending.height / 2);
|
||||||
|
|
||||||
|
sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void floating_natural_resize(struct sway_container *con) {
|
static void floating_natural_resize(struct sway_container *con) {
|
||||||
int min_width, max_width, min_height, max_height;
|
int min_width, max_width, min_height, max_height;
|
||||||
floating_calculate_constraints(&min_width, &max_width,
|
floating_calculate_constraints(&min_width, &max_width,
|
||||||
|
@ -1025,6 +1040,13 @@ void container_floating_move_to(struct sway_container *con,
|
||||||
workspace_add_floating(new_workspace, con);
|
workspace_add_floating(new_workspace, con);
|
||||||
arrange_workspace(old_workspace);
|
arrange_workspace(old_workspace);
|
||||||
arrange_workspace(new_workspace);
|
arrange_workspace(new_workspace);
|
||||||
|
// If the moved container was a visible scratchpad container, then
|
||||||
|
// update its transform.
|
||||||
|
if (con->scratchpad) {
|
||||||
|
struct wlr_box output_box;
|
||||||
|
output_get_box(new_output, &output_box);
|
||||||
|
con->transform = output_box;
|
||||||
|
}
|
||||||
workspace_detect_urgent(old_workspace);
|
workspace_detect_urgent(old_workspace);
|
||||||
workspace_detect_urgent(new_workspace);
|
workspace_detect_urgent(new_workspace);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,16 @@ void root_destroy(struct sway_root *root) {
|
||||||
free(root);
|
free(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_container_transform(struct sway_workspace *ws,
|
||||||
|
struct sway_container *con) {
|
||||||
|
struct sway_output *output = ws->output;
|
||||||
|
struct wlr_box box = {0};
|
||||||
|
if (output) {
|
||||||
|
output_get_box(output, &box);
|
||||||
|
}
|
||||||
|
con->transform = box;
|
||||||
|
}
|
||||||
|
|
||||||
void root_scratchpad_add_container(struct sway_container *con, struct sway_workspace *ws) {
|
void root_scratchpad_add_container(struct sway_container *con, struct sway_workspace *ws) {
|
||||||
if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
|
if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
|
||||||
return;
|
return;
|
||||||
|
@ -64,6 +74,8 @@ void root_scratchpad_add_container(struct sway_container *con, struct sway_works
|
||||||
struct sway_container *parent = con->pending.parent;
|
struct sway_container *parent = con->pending.parent;
|
||||||
struct sway_workspace *workspace = con->pending.workspace;
|
struct sway_workspace *workspace = con->pending.workspace;
|
||||||
|
|
||||||
|
set_container_transform(workspace, con);
|
||||||
|
|
||||||
// Clear the fullscreen mode when sending to the scratchpad
|
// Clear the fullscreen mode when sending to the scratchpad
|
||||||
if (con->pending.fullscreen_mode != FULLSCREEN_NONE) {
|
if (con->pending.fullscreen_mode != FULLSCREEN_NONE) {
|
||||||
container_fullscreen_disable(con);
|
container_fullscreen_disable(con);
|
||||||
|
@ -142,15 +154,12 @@ void root_scratchpad_show(struct sway_container *con) {
|
||||||
}
|
}
|
||||||
workspace_add_floating(new_ws, con);
|
workspace_add_floating(new_ws, con);
|
||||||
|
|
||||||
// Make sure the container's center point overlaps this workspace
|
if (new_ws->output) {
|
||||||
double center_lx = con->pending.x + con->pending.width / 2;
|
struct wlr_box output_box;
|
||||||
double center_ly = con->pending.y + con->pending.height / 2;
|
output_get_box(new_ws->output, &output_box);
|
||||||
|
floating_fix_coordinates(con, &con->transform, &output_box);
|
||||||
struct wlr_box workspace_box;
|
|
||||||
workspace_get_box(new_ws, &workspace_box);
|
|
||||||
if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
|
|
||||||
container_floating_resize_and_center(con);
|
|
||||||
}
|
}
|
||||||
|
set_container_transform(new_ws, con);
|
||||||
|
|
||||||
arrange_workspace(new_ws);
|
arrange_workspace(new_ws);
|
||||||
seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node));
|
seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node));
|
||||||
|
@ -173,6 +182,8 @@ void root_scratchpad_hide(struct sway_container *con) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_container_transform(con->pending.workspace, con);
|
||||||
|
|
||||||
disable_fullscreen(con, NULL);
|
disable_fullscreen(con, NULL);
|
||||||
container_for_each_child(con, disable_fullscreen, NULL);
|
container_for_each_child(con, disable_fullscreen, NULL);
|
||||||
container_detach(con);
|
container_detach(con);
|
||||||
|
|
Loading…
Reference in a new issue