Skip to content

Make scrolling layout work on multi-monitor setups - #1682

Open
inayayousfi wants to merge 11 commits into
LGUG2Z:masterfrom
inayayousfi:make-scrolling-layout-usable-with-multiple-monitors
Open

inayayousfi wants to merge 11 commits into
LGUG2Z:masterfrom
inayayousfi:make-scrolling-layout-usable-with-multiple-monitors

Conversation

@inayayousfi

@inayayousfi inayayousfi commented Mar 21, 2026

Copy link
Copy Markdown

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

LGUG2Z commented Mar 21, 2026

Copy link
Copy Markdown
Owner

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.
@inayayousfi

inayayousfi commented Mar 21, 2026

Copy link
Copy Markdown
Author

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.
@inayayousfi

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

@inayayousfi

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

amnweb commented Mar 24, 2026

Copy link
Copy Markdown

@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

@inayayousfi

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

amnweb commented Mar 24, 2026

Copy link
Copy Markdown

@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

@inayayousfi

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

amnweb commented Mar 24, 2026

Copy link
Copy Markdown

@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
@inayayousfi

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?

@inayayousfi

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

CtByte commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

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.

@inayayousfi

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.

@inayayousfi

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
@inayayousfi

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

initiateit commented Apr 2, 2026

Copy link
Copy Markdown

@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 :)

@inayayousfi

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"
    }
}

@inayayousfi

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!

@inayayousfi

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

initiateit added a commit to initiateit/komorebi that referenced this pull request Apr 18, 2026
- Replace non-existent set_position_from() with set_position()
- Remove reference to missing previous_layouts variable
- Monocle code now works with current upstream/master API
- Note: Smooth animations from PR LGUG2Z#1682 not included (not in upstream/master yet)
@LGUG2Z
LGUG2Z force-pushed the master branch 2 times, most recently from d99b4b5 to a3b2e28 Compare May 5, 2026 02:09
@utaysi

utaysi commented Jun 10, 2026

Copy link
Copy Markdown

Just wanted to add a data point in support of this PR. I'm on v0.1.41 with a dual-monitor setup and set the Scrolling layout via the static config, which bypasses the single-monitor guard in change-layout. The result is that scrolled-out columns on my left monitor get positioned past its right edge and render on top of the other display.

Relevant config

Monitors: two 1920x1080 side by side — main at (0,0), secondary to its right at (1920,0).

"layout_defaults": {
  "Scrolling": {
    "layout_options": {
      "scrolling": { "columns": 2 }
    }
  }
},
"monitors": [
  { "workspaces": [{ "name": "I", "layout": "Scrolling" }] },
  { "workspaces": [{ "name": "I", "layout": "Scrolling" }] }
]

With 3+ windows on the main (left) monitor, the third column is placed at x ≈ 1967, i.e. on the secondary display, instead of being hidden.

The scrolling layout is fantastic otherwise, proper multi-monitor support would make it my daily driver. Happy to test builds of this branch on my setup if that helps. Thanks for working on this!

@initiateit

Copy link
Copy Markdown

@utaysi - did you resize any of the windows? The only time I get this effect is when I have resized a window horizontally.

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

6 participants