Skip to content

Make scrolling layout work on multi-monitor setups#1682

Open
ZiedYousfi wants to merge 11 commits intoLGUG2Z:masterfrom
ZiedYousfi:make-scrolling-layout-usable-with-multiple-monitors
Open

Make scrolling layout work on multi-monitor setups#1682
ZiedYousfi wants to merge 11 commits intoLGUG2Z:masterfrom
ZiedYousfi:make-scrolling-layout-usable-with-multiple-monitors

Conversation

@ZiedYousfi
Copy link
Copy Markdown

@ZiedYousfi ZiedYousfi commented Mar 21, 2026

I'm trying to fix that problem because of how dumb it is but from what I seen in the codebase and the way windows handle the API this needs "hacks"

To fix this issue, I am trying to instead of just moving horizontally the windows by literally scrolling, we hide windows that shouldn't be visible in invisible virtual space.

Closes #1643

Prevent scrolling columns that fall fully outside a workspace's work area from being shown on adjacent displays. This keeps managed tiled windows tied to their assigned monitor while leaving floating and unmanaged windows alone.
Keep scrolling layout state logical while rendering non-visible columns beyond the virtual desktop so they do not appear on neighboring monitors. Remove the single-monitor scrolling guardrails so the parking workaround can be exercised on multi-monitor setups.
Use each window's current rect when parking offscreen scrolling columns so apps do not receive an unnecessary resize. This keeps the multi-monitor scrolling workaround focused on position changes only.
@LGUG2Z
Copy link
Copy Markdown
Owner

LGUG2Z commented Mar 21, 2026

Thanks for trying to tackle this ongoing issue!

I have just been running with this briefly and on a single monitor, the thing I notice is that when I focus to the left, and a window is supposed to be revealed, that window animates in from the right side of the screen which is quite jarring (however, if I do the same thing focusing to the right to reveal a window, this works as expected)

Park offscreen scrolling windows on the same side as their logical layout so reveal animations stay directional. This keeps the multi-monitor workaround lightweight while avoiding windows animating back in from the wrong edge.
@ZiedYousfi
Copy link
Copy Markdown
Author

ZiedYousfi commented Mar 21, 2026

Yes sorry I forgot to do that. I don't have an animation right now in my set up and it's getting pretty late for me right now. If you mind testing it, it would be cool but I can do it tomorrow if you don't have the time and thank you for the review.

Oh and also I have multi-monitor on my daily driver so I'll use it tomorrow to test if it all works properly

…tting

Add comment suggesting that skipping movement animations when parking windows could become a user setting in the future.
@ZiedYousfi
Copy link
Copy Markdown
Author

Also now that I think about it this virtual space approach gives us the ability to give like Niri a way to like visualize all of them and how they are disposed on the scrolling list and even enable vertical scrolling.

And one thing I need to test too is how it adapts to plugging in and unplugging monitors

@ZiedYousfi
Copy link
Copy Markdown
Author

Okay, if the push from master didn't break anything, I fixed all the bugs and tested it as much as I could and I think it's now ready for review.

@amnweb
Copy link
Copy Markdown

amnweb commented Mar 24, 2026

@ZiedYousfi There are some bugs where the window moves from the last monitor to the first one. I slowed down the animation to show you exactly what the problem is

2026-03-24.02-55-20.mp4

@ZiedYousfi
Copy link
Copy Markdown
Author

@amnweb Just to be sure the problem is when it goes from right to left ? If so what what action did you do (with whkd or ahk) ?

@amnweb
Copy link
Copy Markdown

amnweb commented Mar 24, 2026

@amnweb Just to be sure the problem is when it goes from right to left ? If so what what action did you do (with whkd or ahk) ?

komorebic move left, komorebic move right

@ZiedYousfi
Copy link
Copy Markdown
Author

@amnweb I might look dumb, but I don't understand what is the specific problem you're talking about.

@amnweb
Copy link
Copy Markdown

amnweb commented Mar 24, 2026

@amnweb I might look dumb, but I don't understand what is the specific problem you're talking about.

A window is flying over all my screens when scrolling. I moving window on one screen and it comes from another one :p

image

- Add logic for smoother window reveal when scrolling containers in/out across multiple monitors
- Refactor position setting to support transitions from offscreen and parked windows
- Add tests for reveal rect calculation at monitor edges
@ZiedYousfi
Copy link
Copy Markdown
Author

Okay, thank you a lot for your patience with me. This is honestly the best I could do because of how we go around the problem of scrolling going into the other monitor. The limit is still here so I've added the same kind of work around and from my testing it works now as expected.

@initiateit
Copy link
Copy Markdown

What is the method to navigate between parked and visible windows? ie focus-window or move-window?

@ZiedYousfi
Copy link
Copy Markdown
Author

What is the method to navigate between parked and visible windows? ie focus-window or move-window?

It's focus window. Technically it's all the same thing as the scrolling layout on one screen.

@CtByte
Copy link
Copy Markdown
Contributor

CtByte commented Mar 27, 2026

I finally had time to test it out and I think it works better with animations than my approach.
It makes my PR obsolete so I will close it :)

@initiateit
Copy link
Copy Markdown

What is the method to navigate between parked and visible windows? ie focus-window or move-window?

It's focus window. Technically it's all the same thing as the scrolling layout on one screen.

Can you show me what komorebi.json you are using?

I get bleeding of windows into adjacent monitor when you resize them and insert windows after.

@ZiedYousfi
Copy link
Copy Markdown
Author

{
  "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/master/schema.json",
  
  "app_specific_configuration_path": "$Env:KOMOREBI_CONFIG_HOME/applications.json",
  
  "window_hiding_behaviour": "Cloak",
  "cross_monitor_move_behaviour": "Insert",
  "cross_boundary_behaviour": "Monitor",

  "mouse_follows_focus": false,

  "default_workspace_padding": 0,
  "default_container_padding": 4,

  "border": true,
  "border_width": 4,
  "border_style": "System",
  "border_colours": {
    "single": "#ff4ead",
    "stack": "#ff85c8",
    "monocle": "#a78bfa",
    "floating": "#60a5fa",
    "unfocused": "#1a1a1a"
  },

  "monitors": [
    {
      "workspaces": [
        { "name": "1", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "2", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "3", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "4", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "5", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "6", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "7", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "8", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "9", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "10", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } }
      ]
    },
    {
      "workspaces": [
        { "name": "1", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "2", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "3", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "4", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "5", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "6", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "7", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "8", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "9", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "10", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } }
      ]
    },
    {
      "workspaces": [
        { "name": "1", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "2", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "3", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "4", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "5", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "6", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "7", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "8", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "9", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } },
        { "name": "10", "layout": "Scrolling", "layout_options": { "scrolling": { "columns": 2 } } }
      ]
    }
  ],

  "floating_applications": [
    { "kind": "Title", "id": "Picture-in-Picture", "matching_strategy": "Regex" },
    { "kind": "Title", "id": "Helper", "matching_strategy": "Contains" }
  ]
}

@initiateit
Copy link
Copy Markdown

@ZiedYousfi Thanks for that! My observations are as follows:

If you resize any window in the scrolling layout, it ends up breaking by forcing the scrolling layout's overflow into the adjacent monitor. I think the issue is the layout tries to tile all windows and resize to them to fit. Part of the mantra of Niri scrolling is to never resize other windows based on resizing the current window. Here's a video with various scenarios when resizing:

Watch this video
https://www.youtube.com/watch?v=RfYcP4jz1qI

I have tried (and am still trying) to get a solution, but its very tricky.

It would help if we had a set goal as to what we want? If you take resizing out and rely on monocle mode to pick out the window you want to work on - then nothing really needs to be done.

@ZiedYousfi
Copy link
Copy Markdown
Author

@initiateit Okay I see the problem thank you so much for finding this out. I've got some ideas to fix it but honestly I think this goes out of the scope of implementation and bugs and more into preference side. So I would very much appreciate if @LGUG2Z could tell what do they want the default to be? What should be supported? And how this whole idea would work (because we go very much out of the tiling idea and the architecture of the codebase is not really gilded towards scrolling which I learned through this PR that it's way different from usual tiling managers) So if they could give me some directions on what they want to do so that I don't have to spend time implementing things that would be thrown away, it would be very much appreciated.

- Keep adjacent containers visible instead of parking the focused one
offscreen
- Add tests for left- and right-shifting scrolling layouts
@ZiedYousfi
Copy link
Copy Markdown
Author

@initiateit Could you test it again please

- Translate visible layouts from the focused anchor
- Keep gaps intact while clamping windows to the work area
- Add regression coverage for multi-monitor scrolling
@initiateit
Copy link
Copy Markdown

initiateit commented Apr 2, 2026

@ZiedYousfi I didnt have any luck mate, I can make a video if you like but I think its not worth your time. I have been trying myself and its out of my reach in terms of rust.

I can live with columns and just monocle whenever i need larger focus.

Appreciate your work all the same :)

@ZiedYousfi
Copy link
Copy Markdown
Author

No I don't want to give up after the time I've given to it lmaoo. Could you give me your config so that I can try it on my computer pls?

@initiateit
Copy link
Copy Markdown

@ZiedYousfi don't say I didnt warn ya buddy!

My standard config:

{
    "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/master/schema.json",
    "app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
    "window_hiding_behaviour": "Cloak",
    "cross_monitor_move_behaviour": "Insert",
    "mouse_follows_focus": false,
    "default_workspace_padding": 10,
    "default_container_padding": 10,
    "border": true,
    "border_width": 5,
    "border_style": "System",
    "border_offset": -1,
    "border_colours": {
        "single": {
            "r": 54,
            "g": 200,
            "b": 255
        },
        "stack": {
            "r": 94,
            "g": 215,
            "b": 90
        }
    },
    "monitors": [
        {
            "workspaces": [
                {
                    "name": "Monitor 2, Workspace 1",
                    "layout": "Scrolling",
                     "layout_options": {
                        "scrolling": {
                             "columns": 3
          }
                }
                },
                {
                    "name": "Monitor 2, Workspace 2",
                    "layout": "BSP"
                },
                {
                    "name": "Monitor 2, Workspace 3",
                    "layout": "HorizontalStack"
                }
            ]
        },
        {
            "workspaces": [
                {
                    "name": "Monitor 1, Workspace 1",
                    "layout": "BSP",
                    "layout_options": {
                    }
                },
                {
                    "name": "Monitor 1, Workspace 2",
                    "layout": "VerticalStack"
                },
                {
                    "name": "Monitor 1, Workspace 3",
                    "layout": "HorizontalStack"
                }
            ]
        }
    ],
    "display_index_preferences": {
        "0": "2KJDQ43",
        "1": "1CJDQ43"
    }
}

@ZiedYousfi
Copy link
Copy Markdown
Author

I can't reproduce it...

@initiateit
Copy link
Copy Markdown

@ZiedYousfi if you have time, post a video on how it works for you? It would be a good thing if it is my system and config that is the issue!

@ZiedYousfi
Copy link
Copy Markdown
Author

2026-04-04_16-26-55.mp4

I speak a lot in the video so if you could look at it with sound I would gladly appreciate it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: komorebic change-layout scrolling does nothing in a multiple monitor setup

5 participants