[BUG]: Multiple monitors layout mix up #493

Closed
opened 2026-01-05 14:51:06 +01:00 by adam · 6 comments
Owner

Originally created by @alexgorbatchev on GitHub (Oct 14, 2024).

Summary

I'm experiencing repeated monitor ID issue. I have 3 monitors arranged in this configuration:

-----  -----
| 1 |  |   |
-----  | 2 |
-----  |   |
| 0 |  |   |
-----  -----

The monitor-information always returns this for me:

$ komorebic monitor-information
{
  "GBT3204-5&1818b9c1&0&UID4355": {
    "left": 0,
    "top": 0,
    "right": 3840,
    "bottom": 2160
  },
  "GSM7750-5&1818b9c1&0&UID4353": {
    "left": 0,
    "top": -2160,
    "right": 3840,
    "bottom": 2160
  },
  "DELA0AA-5&1818b9c1&0&UID4352": {
    "left": 3840,
    "top": -1711,
    "right": 1440,
    "bottom": 3440
  }
}

My config has the following:

  "display_index_preferences": {
    "0": "GBT3204-5&1818b9c1&0&UID4355",
    "1": "GSM7750-5&1818b9c1&0&UID4353",
    "2": "DELA0AA-5&1818b9c1&0&UID4352"
  },
  "monitors": [
    {
      "workspaces": [{ "name": "a", "layout": "BSP" }]
    },
    {
      "workspaces": [{ "name": "b", "layout": "Columns" }]
    },
    {
      "workspaces": [{ "name": "c", "layout": "Rows" }]
    }
  ]

I found that after Windows sleep, monitors[1] and monitors[2] get swapped. I would say this happens pretty much every time, or nearly as frequent. My solution is to swap the values in the .json file manually every time. So essentially I keep rotating b and c to fix the issue.

At this point I've probably done it a few dozen times.

Version Information

OS Name:                   Microsoft Windows 11 Pro
OS Version:                10.0.22631 N/A Build 22631
komorebic 0.1.28
tag:v0.1.28
commit_hash:0cdce8fc
build_time:2024-07-15 16:06:31 +00:00
build_env:rustc 1.79.0 (129f3b996 2024-06-10),stable-x86_64-pc-windows-msvc

Komorebi Configuration

{
  "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.28/schema.json",
  "app_specific_configuration_path": "$Env:USERPROFILE/applications.yaml",
  "window_hiding_behaviour": "Cloak",
  "cross_monitor_move_behaviour": "Insert",
  "default_workspace_padding": 10,
  "default_container_padding": 10,
  "border": true,
  "border_width": 8,
  "border_offset": -1,
  "border_colours": {
    "single": "#42a5f5",
    "stack": "#00a542",
    "monocle": "#ff3399",
    "unfocused": "#808080"
  },
  "stackbar": {
    "height": 40,
    "mode": "OnStack",
    "label": "Title",
    "tabs": {
      "width": 300,
      "focused_text": "#00a542",
      "unfocused_text": "#b3b3b3",
      "background": "#141414"
    }
  },
  "display_index_preferences": {
    "0": "GBT3204-5&1818b9c1&0&UID4355",
    "1": "GSM7750-5&1818b9c1&0&UID4353",
    "2": "DELA0AA-5&1818b9c1&0&UID4352"
  },
  "monitors": [
    {
      "workspaces": [{ "name": "a", "layout": "BSP" }]
    },
    {
      "workspaces": [{ "name": "b", "layout": "Columns" }]
    },
    {
      "workspaces": [{ "name": "c", "layout": "Rows" }]
    }
  ]
}

Hotkey Configuration

.shell powershell

# Reload whkd configuration
# alt + o                 : taskkill /f /im whkd.exe && start /b whkd # if shell is cmd
alt + o                 : taskkill /f /im whkd.exe && Start-Process whkd -WindowStyle hidden # if shell is pwsh / powershell
alt + shift + o         : komorebic reload-configuration

# App shortcuts - these require shell to be pwsh / powershell
# The apps will be focused if open, or launched if not open
# alt + f                 : if ($wshell.AppActivate('Firefox') -eq $False) { start firefox }
# alt + b                 : if ($wshell.AppActivate('Chrome') -eq $False) { start chrome }

alt + m                 : komorebic minimize
# Focus windows
alt + h                 : komorebic focus left
alt + j                 : komorebic focus down
alt + k                 : komorebic focus up
alt + l                 : komorebic focus right
alt + shift + oem_4     : komorebic cycle-focus previous # oem_4 is [
alt + shift + oem_6     : komorebic cycle-focus next # oem_6 is ]

# Move windows
alt + shift + h         : komorebic move left
alt + shift + j         : komorebic move down
alt + shift + k         : komorebic move up
alt + shift + l         : komorebic move right
alt + shift + return    : komorebic promote

# Stack windows
alt + left              : komorebic stack left
alt + down              : komorebic stack down
alt + up                : komorebic stack up
alt + right             : komorebic stack right
alt + oem_1             : komorebic unstack # oem_1 is ;
alt + oem_4             : komorebic cycle-stack previous # oem_4 is [
alt + oem_6             : komorebic cycle-stack next # oem_6 is ]

# Resize
alt + oem_plus          : komorebic resize-axis horizontal increase
alt + oem_minus         : komorebic resize-axis horizontal decrease
alt + shift + oem_plus  : komorebic resize-axis vertical increase
alt + shift + oem_minus : komorebic resize-axis vertical decrease

# Manipulate windows
alt + t                 : komorebic toggle-float
alt + shift + f         : komorebic toggle-monocle

# Window manager options
alt + shift + r         : komorebic retile
alt + shift + p         : komorebic toggle-pause

# Layouts
alt + x                 : komorebic flip-layout horizontal
alt + y                 : komorebic flip-layout vertical

# Workspaces
alt + 1                 : komorebic focus-workspace 0
alt + 2                 : komorebic focus-workspace 1
alt + 3                 : komorebic focus-workspace 2

# Move windows across workspaces
alt + shift + 1         : komorebic move-to-workspace 0
alt + shift + 2         : komorebic move-to-workspace 1
alt + shift + 3         : komorebic move-to-workspace 2

Output of komorebic check

No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\alex

Looking for configuration files in C:\Users\alex

Found komorebi.json; this file can be passed to the start command with the --config flag

Found C:\Users\alex\.config\whkdrc; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag
Originally created by @alexgorbatchev on GitHub (Oct 14, 2024). ### Summary I'm experiencing repeated monitor ID issue. I have 3 monitors arranged in this configuration: ``` ----- ----- | 1 | | | ----- | 2 | ----- | | | 0 | | | ----- ----- ``` The `monitor-information` always returns this for me: ``` $ komorebic monitor-information { "GBT3204-5&1818b9c1&0&UID4355": { "left": 0, "top": 0, "right": 3840, "bottom": 2160 }, "GSM7750-5&1818b9c1&0&UID4353": { "left": 0, "top": -2160, "right": 3840, "bottom": 2160 }, "DELA0AA-5&1818b9c1&0&UID4352": { "left": 3840, "top": -1711, "right": 1440, "bottom": 3440 } } ``` My config has the following: ``` "display_index_preferences": { "0": "GBT3204-5&1818b9c1&0&UID4355", "1": "GSM7750-5&1818b9c1&0&UID4353", "2": "DELA0AA-5&1818b9c1&0&UID4352" }, "monitors": [ { "workspaces": [{ "name": "a", "layout": "BSP" }] }, { "workspaces": [{ "name": "b", "layout": "Columns" }] }, { "workspaces": [{ "name": "c", "layout": "Rows" }] } ] ``` I found that after Windows sleep, `monitors[1]` and `monitors[2]` get swapped. I would say this happens pretty much every time, or nearly as frequent. My solution is to swap the values in the `.json` file manually every time. So essentially I keep rotating `b` and `c` to fix the issue. At this point I've probably done it a few dozen times. ### Version Information ``` OS Name: Microsoft Windows 11 Pro OS Version: 10.0.22631 N/A Build 22631 ``` ``` komorebic 0.1.28 tag:v0.1.28 commit_hash:0cdce8fc build_time:2024-07-15 16:06:31 +00:00 build_env:rustc 1.79.0 (129f3b996 2024-06-10),stable-x86_64-pc-windows-msvc ``` ### Komorebi Configuration ```json { "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.28/schema.json", "app_specific_configuration_path": "$Env:USERPROFILE/applications.yaml", "window_hiding_behaviour": "Cloak", "cross_monitor_move_behaviour": "Insert", "default_workspace_padding": 10, "default_container_padding": 10, "border": true, "border_width": 8, "border_offset": -1, "border_colours": { "single": "#42a5f5", "stack": "#00a542", "monocle": "#ff3399", "unfocused": "#808080" }, "stackbar": { "height": 40, "mode": "OnStack", "label": "Title", "tabs": { "width": 300, "focused_text": "#00a542", "unfocused_text": "#b3b3b3", "background": "#141414" } }, "display_index_preferences": { "0": "GBT3204-5&1818b9c1&0&UID4355", "1": "GSM7750-5&1818b9c1&0&UID4353", "2": "DELA0AA-5&1818b9c1&0&UID4352" }, "monitors": [ { "workspaces": [{ "name": "a", "layout": "BSP" }] }, { "workspaces": [{ "name": "b", "layout": "Columns" }] }, { "workspaces": [{ "name": "c", "layout": "Rows" }] } ] } ``` ### Hotkey Configuration ``` .shell powershell # Reload whkd configuration # alt + o : taskkill /f /im whkd.exe && start /b whkd # if shell is cmd alt + o : taskkill /f /im whkd.exe && Start-Process whkd -WindowStyle hidden # if shell is pwsh / powershell alt + shift + o : komorebic reload-configuration # App shortcuts - these require shell to be pwsh / powershell # The apps will be focused if open, or launched if not open # alt + f : if ($wshell.AppActivate('Firefox') -eq $False) { start firefox } # alt + b : if ($wshell.AppActivate('Chrome') -eq $False) { start chrome } alt + m : komorebic minimize # Focus windows alt + h : komorebic focus left alt + j : komorebic focus down alt + k : komorebic focus up alt + l : komorebic focus right alt + shift + oem_4 : komorebic cycle-focus previous # oem_4 is [ alt + shift + oem_6 : komorebic cycle-focus next # oem_6 is ] # Move windows alt + shift + h : komorebic move left alt + shift + j : komorebic move down alt + shift + k : komorebic move up alt + shift + l : komorebic move right alt + shift + return : komorebic promote # Stack windows alt + left : komorebic stack left alt + down : komorebic stack down alt + up : komorebic stack up alt + right : komorebic stack right alt + oem_1 : komorebic unstack # oem_1 is ; alt + oem_4 : komorebic cycle-stack previous # oem_4 is [ alt + oem_6 : komorebic cycle-stack next # oem_6 is ] # Resize alt + oem_plus : komorebic resize-axis horizontal increase alt + oem_minus : komorebic resize-axis horizontal decrease alt + shift + oem_plus : komorebic resize-axis vertical increase alt + shift + oem_minus : komorebic resize-axis vertical decrease # Manipulate windows alt + t : komorebic toggle-float alt + shift + f : komorebic toggle-monocle # Window manager options alt + shift + r : komorebic retile alt + shift + p : komorebic toggle-pause # Layouts alt + x : komorebic flip-layout horizontal alt + y : komorebic flip-layout vertical # Workspaces alt + 1 : komorebic focus-workspace 0 alt + 2 : komorebic focus-workspace 1 alt + 3 : komorebic focus-workspace 2 # Move windows across workspaces alt + shift + 1 : komorebic move-to-workspace 0 alt + shift + 2 : komorebic move-to-workspace 1 alt + shift + 3 : komorebic move-to-workspace 2 ``` ### Output of komorebic check ``` No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\alex Looking for configuration files in C:\Users\alex Found komorebi.json; this file can be passed to the start command with the --config flag Found C:\Users\alex\.config\whkdrc; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag ```
adam added the bug label 2026-01-05 14:51:06 +01:00
adam closed this issue 2026-01-05 14:51:06 +01:00
Author
Owner

@LGUG2Z commented on GitHub (Oct 14, 2024):

{
  "GBT3204-5&1818b9c1&0&UID4355": {
    "left": 0,
    "top": 0,
    "right": 3840,
    "bottom": 2160
  },
  "GSM7750-5&1818b9c1&0&UID4353": {
    "left": 0,
    "top": -2160,
    "right": 3840,
    "bottom": 2160
  },
  "DELA0AA-5&1818b9c1&0&UID4352": {
    "left": 3840,
    "top": -1711,
    "right": 1440,
    "bottom": 3440
  }
}

This is an unordered map, so the order these values are printed in don't have any special meaning.

Assuming that this is the desired index layout:

-----  -----
| 1 |  |   |
-----  | 2 |
-----  |   |
| 0 |  |   |
-----  -----

You probably need to set display_index_preferences like this:

  "display_index_preferences": {
    "0": "GSM7750-5&1818b9c1&0&UID4353",
    "1": "GBT3204-5&1818b9c1&0&UID4355",
    "2": "DELA0AA-5&1818b9c1&0&UID4352"
  },
@LGUG2Z commented on GitHub (Oct 14, 2024): ```json { "GBT3204-5&1818b9c1&0&UID4355": { "left": 0, "top": 0, "right": 3840, "bottom": 2160 }, "GSM7750-5&1818b9c1&0&UID4353": { "left": 0, "top": -2160, "right": 3840, "bottom": 2160 }, "DELA0AA-5&1818b9c1&0&UID4352": { "left": 3840, "top": -1711, "right": 1440, "bottom": 3440 } } ``` This is an unordered map, so the order these values are printed in don't have any special meaning. Assuming that this is the desired index layout: ``` ----- ----- | 1 | | | ----- | 2 | ----- | | | 0 | | | ----- ----- ``` You probably need to set `display_index_preferences` like this: ```json "display_index_preferences": { "0": "GSM7750-5&1818b9c1&0&UID4353", "1": "GBT3204-5&1818b9c1&0&UID4355", "2": "DELA0AA-5&1818b9c1&0&UID4352" }, ```
Author
Owner

@alexgorbatchev commented on GitHub (Oct 15, 2024):

Thank you for you help, unfortunately I already have display_index_preferences in my config referenced above and so I believe the problem is elsewhere.

@alexgorbatchev commented on GitHub (Oct 15, 2024): Thank you for you help, unfortunately I already have `display_index_preferences` in my config referenced above and so I believe the problem is elsewhere.
Author
Owner

@LGUG2Z commented on GitHub (Oct 15, 2024):

You should try replacing the value in your config with the value I have given- I made a change to the ordering based on the diagram you drew.

@LGUG2Z commented on GitHub (Oct 15, 2024): You should try replacing the value in your config with the value I have given- I made a change to the ordering based on the diagram you drew.
Author
Owner

@alex-ds13 commented on GitHub (Oct 17, 2024):

You probably need to set display_index_preferences like this:

  "display_index_preferences": {
    "0": "GSM7750-5&1818b9c1&0&UID4353",
    "1": "GBT3204-5&1818b9c1&0&UID4355",
    "2": "DELA0AA-5&1818b9c1&0&UID4352"
  },

I don't think this is the case because usually the main monitor (index 0) is the one with top/left at 0,0, which here is "GBT3204", then monitor "GSM775" has negative top which means it is above the previous one (the y axis is positive towards the bottom...) and monitor "DELA0AA" also has negative top but has positive left which means it is to the right of main monitor but starts higher that main monitor. Which means that the OP's order should've been right from the start...

Also this appears to only be happening after sleep, which means before the order was correct.

@alexgorbatchev Have you tried checking the windows screen settings when the swap happens to make sure that it isn't Windows itself swapping the screens? Also try running the komorebic monitor-info again after the swap to see if there are any changes... From what I see, if the monitors kept the same id komorebi should see that it already had them and keep them just the same as before going to sleep...

@alex-ds13 commented on GitHub (Oct 17, 2024): > You probably need to set `display_index_preferences` like this: > > ```json > "display_index_preferences": { > "0": "GSM7750-5&1818b9c1&0&UID4353", > "1": "GBT3204-5&1818b9c1&0&UID4355", > "2": "DELA0AA-5&1818b9c1&0&UID4352" > }, > ``` I don't think this is the case because usually the main monitor (index 0) is the one with `top`/`left` at `0,0`, which here is "GBT3204", then monitor "GSM775" has negative `top` which means it is above the previous one (the `y` axis is positive towards the bottom...) and monitor "DELA0AA" also has negative `top` but has positive `left` which means it is to the right of main monitor but starts higher that main monitor. Which means that the OP's order should've been right from the start... Also this appears to only be happening after sleep, which means before the order was correct. @alexgorbatchev Have you tried checking the windows screen settings when the swap happens to make sure that it isn't Windows itself swapping the screens? Also try running the `komorebic monitor-info` again after the swap to see if there are any changes... From what I see, if the monitors kept the same id komorebi should see that it already had them and keep them just the same as before going to sleep...
Author
Owner

@alex-ds13 commented on GitHub (Oct 18, 2024):

@LGUG2Z I think I've found a bug in the way that the monitors are currently being rearranged when there are index preferences. It is on this code here.

Try putting the following example on a rust playground:

extern crate rand;
use rand::Rng;

fn main() {
    let mut monitors = Vec::new();
    //let mut indices = vec![0,1,2];
    let mut indices = vec![0,1,2,3];
    println!("{indices:#?}");
    random_shuffle(&mut indices);
    println!("{indices:#?}");
    //indices.insert(0, 3);
    //println!("{indices:#?}");
    for i in indices {
        if monitors.is_empty() {
            monitors.push(format!("M{i}"));
        } else {
            while i > monitors.len() {
                monitors.push(String::from("PLACEHOLDER"));
            }

            monitors.insert(i, format!("M{i}"));
        }
    }
    println!("{monitors:#?}");
    monitors.retain(|m| m != "PLACEHOLDER");
    println!("{monitors:#?}");
}

fn random_shuffle<T>(vec: &mut Vec<T>) {
    let mut rng = rand::thread_rng();
    for i in (0..vec.len()).rev() {
        let j = rng.gen_range(0..=i);
        vec.swap(i, j);
    }
}

If you uncomment the line let mut indices = vec![0,1,2]; and comment the line below it (simulating a system with 3 monitors) this always seems to work unless the exact combination after the shuffle is [2, 1, 0] which then the result is wrong. But if you use it as is (simulating a system with 4 monitors) it will get a wrong result a lot of times! If you use the commented line let mut indices = vec![0,1,2]; and then uncomment the line //indices.insert(0, 3); which makes the last index always be at the start then it will fail almost every time (unless your are lucky enough to get [3,0,1,2]).

I believe this is what might be causing the issues reported here and on other related issues...

@alex-ds13 commented on GitHub (Oct 18, 2024): @LGUG2Z I think I've found a bug in the way that the monitors are currently being rearranged when there are index preferences. It is on this [code here](https://github.com/LGUG2Z/komorebi/blob/master/komorebi/src/windows_api.rs#L303). Try putting the following example on a rust playground: ```rust extern crate rand; use rand::Rng; fn main() { let mut monitors = Vec::new(); //let mut indices = vec![0,1,2]; let mut indices = vec![0,1,2,3]; println!("{indices:#?}"); random_shuffle(&mut indices); println!("{indices:#?}"); //indices.insert(0, 3); //println!("{indices:#?}"); for i in indices { if monitors.is_empty() { monitors.push(format!("M{i}")); } else { while i > monitors.len() { monitors.push(String::from("PLACEHOLDER")); } monitors.insert(i, format!("M{i}")); } } println!("{monitors:#?}"); monitors.retain(|m| m != "PLACEHOLDER"); println!("{monitors:#?}"); } fn random_shuffle<T>(vec: &mut Vec<T>) { let mut rng = rand::thread_rng(); for i in (0..vec.len()).rev() { let j = rng.gen_range(0..=i); vec.swap(i, j); } } ``` If you uncomment the line `let mut indices = vec![0,1,2];` and comment the line below it (simulating a system with 3 monitors) this always seems to work unless the exact combination after the shuffle is `[2, 1, 0]` which then the result is wrong. But if you use it as is (simulating a system with 4 monitors) it will get a wrong result a lot of times! If you use the commented line `let mut indices = vec![0,1,2];` and then uncomment the line `//indices.insert(0, 3);` which makes the last index always be at the start then it will fail almost every time (*unless your are lucky enough to get `[3,0,1,2]`*). I believe this is what might be causing the issues reported here and on other related issues...
Author
Owner

@alex-ds13 commented on GitHub (Oct 18, 2024):

Doing something like this instead should fix it:

extern crate rand;
use rand::Rng;

fn main() {
    let mut monitors = Vec::new();
    let mut indices = vec![0,1,2,3,4,5,6,7,8];
    //let mut indices = vec![0,1,2,3];
    println!("{indices:#?}");
    random_shuffle(&mut indices);
    //println!("{indices:#?}");
    indices.insert(0, 9);
    println!("{indices:#?}");
    for i in indices {
        while i >= monitors.len() {
            monitors.push(String::from("PLACEHOLDER"));
        }
        if monitors.get(i).unwrap() == "PLACEHOLDER" {
            monitors.remove(i);
            monitors.insert(i, format!("M{i}"));
        } else {
            monitors.insert(i, format!("M{i}"));
        }
    }
    println!("{monitors:#?}");
    monitors.retain(|m| m != "PLACEHOLDER");
    println!("{monitors:#?}");
}

fn random_shuffle<T>(vec: &mut Vec<T>) {
    let mut rng = rand::thread_rng();
    for i in (0..vec.len()).rev() {
        let j = rng.gen_range(0..=i);
        vec.swap(i, j);
    }
}

I've used indices all the way through 9, like there were 9 monitors to increase the probability of having bad scenarios that would give wrong result.

@alex-ds13 commented on GitHub (Oct 18, 2024): Doing something like this instead should fix it: ```rust extern crate rand; use rand::Rng; fn main() { let mut monitors = Vec::new(); let mut indices = vec![0,1,2,3,4,5,6,7,8]; //let mut indices = vec![0,1,2,3]; println!("{indices:#?}"); random_shuffle(&mut indices); //println!("{indices:#?}"); indices.insert(0, 9); println!("{indices:#?}"); for i in indices { while i >= monitors.len() { monitors.push(String::from("PLACEHOLDER")); } if monitors.get(i).unwrap() == "PLACEHOLDER" { monitors.remove(i); monitors.insert(i, format!("M{i}")); } else { monitors.insert(i, format!("M{i}")); } } println!("{monitors:#?}"); monitors.retain(|m| m != "PLACEHOLDER"); println!("{monitors:#?}"); } fn random_shuffle<T>(vec: &mut Vec<T>) { let mut rng = rand::thread_rng(); for i in (0..vec.len()).rev() { let j = rng.gen_range(0..=i); vec.swap(i, j); } } ``` I've used indices all the way through 9, like there were 9 monitors to increase the probability of having bad scenarios that would give wrong result.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/komorebi#493