swaywm / sway

i3-compatible Wayland compositor
https://swaywm.org
MIT License
14.5k stars 1.11k forks source link

Scratchpad doesn't remember window size when moving to another monitor #6561

Open Zeioth opened 3 years ago

Zeioth commented 3 years ago

How to reproduce:

This issue only seem to happen in multi monitor setups. If you always work in the same monitor, it does't happen.

https://x0.at/R4rM.png https://x0.at/Dls8.png

boredland commented 3 years ago

What are the screen resolutions of the different monitors? Are they identical or different?

Zeioth commented 3 years ago

5 monitors, all of them UHD (3840 x 2160).

My config, if relevant:

output $screen2 mode 3840x2160@70.981Hz pos 0 0 scale 1
output $screen3 mode 3840x2160@70.981Hz pos 3840 0 scale 1
output $screen4 mode 3840x2160@70.981Hz pos 0 -2160 scale 1
output $screen5 mode 3840x2160@70.981Hz pos -3840 -2160 scale 1
output $screen6 mode 3840x2160@70.981Hz pos 3840 -2160 scale 1
boredland commented 3 years ago

So this is different from the problem I experienced in the past, I think, when switching from a high-res display to a lower-res one.

PolyMeilex commented 2 years ago

It's the same for me, but for me they get huge, rather than super small. I have two FHD monitors

  1. Send a window to the scratchpad.
  2. Move the cursor to another monitor
  3. Bring back the window from scratchpad.
  4. The size of the window changed, and is now approximately the size of the monitor (FHD)

It does not happen in i3 btw

Shfty commented 2 years ago

I'm also seeing this on my 3-monitor setup - a central 2560x1440 monitor flanked by a pair of 1920x1200 ones.

In my case, restoring a foot terminal from the scratchpad on a different monitor causes it to briefly appear at its original size (i.e. the size it was hidden at), then shrink down to 69 columns x 24 rows.

I note that the window doesn't move during this process - when appearing at the original size, it's center-aligned as if it's already 69x24, after which the resize occurs.

It's also not specific to foot - the same behavior occurs when running st via xwayland.

paulodiovani commented 2 years ago

I handle this issue by resizing the window after showing scratchpad. E.g.

bindsym Ctrl+Escape exec swaymsg 'scratchpad show' \
  && sleep .1 \
  && swaymsg 'resize set 100ppt 40ppt, move position 0 0'

The sleep .1 is necessary due to the time the window takes to render, otherwise, it could try resizing the underlying window, if any. It is not pretty, as the window will flick before resizing/moving, due to the latency of using exec swaymsg instead of calling from sway process. I supposed it can be made better with use of sway-ipc, but it solves my issue for now.

I currently use this for my dropdown terminal. Full config: https://github.com/paulodiovani/dot-files/blob/feature/sway/home/user/.config/sway/config.d/50-dropdownterminal

anpandey commented 1 year ago

This happens because sway resets the window back to the default floating size and position if it finds that the center of the container doesn't overlap with the current workspace. On the other hand, i3 uses floating_fix_coordinates to adjust the coordinates of floating windows moved between workspaces of possibly different sizes.

Here's a hackish way of saving coordinates across outputs in sway, which works well enough for me. This still resets the window if e.g. the output the window is on is disconnected.

diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 05761150..f2674dc7 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -196,6 +196,8 @@ size_t container_titlebar_height(void);
 void floating_calculate_constraints(int *min_width, int *max_width,
        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_set_default_size(struct sway_container *con);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 79e04ec0..a34f752f 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -731,6 +731,22 @@ static void floating_natural_resize(struct sway_container *con) {
    }
 }

+void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, struct wlr_box *new) {
+   int rel_x = con->current.x - old->x + (con->current.width / 2);
+   int rel_y = con->current.y - old->y + (con->current.height / 2);
+
+   sway_log(SWAY_DEBUG, "old = (%d, %d), %d x %d",
+            old->x, old->y, old->width, old->height);
+   sway_log(SWAY_DEBUG, "new = (%d, %d), %d x %d",
+            new->x, new->y, new->width, new->height);
+
+   con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->current.width / 2);
+   con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->current.height / 2);
+
+   sway_log(SWAY_DEBUG, "fixed container coords to (%.2f, %.2f)",
+            con->pending.x, con->pending.y);
+}
+
 void container_floating_resize_and_center(struct sway_container *con) {
    struct sway_workspace *ws = con->pending.workspace;
    if (!ws) {
diff --git a/sway/tree/root.c b/sway/tree/root.c
index 73f3993c..a58584f9 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -140,6 +140,15 @@ void root_scratchpad_show(struct sway_container *con) {
    }
    workspace_add_floating(new_ws, con);

+   // Try to fix the coords of the container.
+   if (new_ws->output) {
+       struct wlr_box new_output_box, closest_box;
+       struct sway_output *closest = container_floating_find_output(con);
+       output_get_box(new_ws->output, &new_output_box);
+       output_get_box(closest, &closest_box);
+       floating_fix_coordinates(con, &closest_box, &new_output_box);
+   }
+
    // Make sure the container's center point overlaps this workspace
    double center_lx = con->pending.x + con->pending.width / 2;
    double center_ly = con->pending.y + con->pending.height / 2;

It would be nice if we could replicate i3's behavior in adjusting coordinates for all floating window movements. I think that would require storing some additional state for scratchpad windows (where the previous workspace is unknown).