Commit Graph
100 Commits
Author SHA1 Message Date
alex-ds13 0e8ed8aa40 feat(wm): apply wallpapers per monitor 2025-04-04 11:08:45 -07:00
alex-ds13 fa2ccad5bf fix(wm): skip serde on WorkspaceGlobals 2025-04-04 11:08:45 -07:00
alex-ds13 58730b81b4 feat(gui): add floating and locked border colours 2025-04-01 05:53:33 -07:00
alex-ds13 274ae43e8f feat(wm): add unfocused_locked to border_colours
This commit adds the `unfocused_locked` color to the border_colours so
that users that don't use themes can still customize this color like
they do the others.
2025-04-01 05:53:26 -07:00
alex-ds13 8fd18048a4 remove(wm): remove workspace_reconciliator 2025-03-31 15:23:33 -07:00
alex-ds13 5809735024 refactor(wm): refactor alt-tab reconciliation
This commit changes the way the alt-tab reconciliation is done.

It no longer uses the `workspace_reconciliator` with the sending of
notifications.

Instead there is a simple function that checks if the shown/uncloaked
window is already handled by komorebi and if it is it will check if it
is on an unfocused workspace and/or if it is an unfocused window of a
stacked container, returning the monitor/workspace index pair of said
window.

If we get this pair then we perform the reconciliation immediately by
focusing the monitor, workspace, container and window indices
corresponding to that window.
2025-03-31 15:23:14 -07:00
alex-ds13 96fdbbd1fb fix(client): re-export FloatingLayerBehaviour 2025-03-31 15:23:10 -07:00
alex-ds13 e4226ce623 feat(wm): show float windows in order on layer toggle
This commit raises and lowers all the floating windows so that they show
up with the smaller windows on top and the bigger windows on the bottom
when we toggle between layers.
2025-03-26 15:48:35 -07:00
alex-ds13 4bfd7febb4 feat(wm): focus floats depending on direction
This commit tries to focus the floating windows depending on the
direction used. It takes into account the top left corner of each window
and uses that to look for the closest top left corner in the direction
provided.

If there are no windows found in that direction, it then checks if it
can focus across monitor.
2025-03-26 15:48:15 -07:00
alex-ds13 5cc688dc6b feat(wm): track focused floating window
This commit changes the `floating_windows` from a `Vec<Window>` to a
`Ring<Window>` which allows us to keep track of the focused floating
window.

This combined with the existing layer switch allows us to know when we
should focus the focused container or the focused floating window.
2025-03-26 15:48:07 -07:00
alex-ds13 30fbc1ae73 feat(client): reexport win32_display_data
This commit reexports the `win32_display_data` crate so that any 3rd
party app that needs it can get it through the `komorebi-client` without
having to keep manually synchronizing it with the version used by komorebi.
2025-03-22 19:35:23 -07:00
alex-ds13 24791f0ce5 fix(wm): change when floating windows are centered
This commit changes the behaviour of when floating windows are centered
by making them only center when we are on a `WorkspaceLayer::Floating`
and the window doesn't match a `floating_windows` rule and the workspace
is not a floating workspace.
2025-03-20 18:34:35 -07:00
alex-ds13 9f16894a09 fix(wm): correct workspace restore + remove workarounds
This commit removes some workarounds on the `update_focused_workspace`
function that were there to fix issues related to some bugs on the
`workspace.restore()` function.

This commit fixes the bugs on the `restore` function instead. The
`update_focused_workspace` function should be used only to update a
workspace layout.
2025-03-17 18:17:30 -07:00
alex-ds13 df9ae931cc feat(wm): toggle float override with floating layer
This commit ensures that when the user switches to the flooating layer
any new spawned window will be spawned floating as if the float override
was set.

This results in a workflow which makes it easier to spawn floating
windows on the fly.

This effectively reverts commit ff2aa5e51a.
2025-03-17 18:16:16 -07:00
alex-ds13 be2af9fdcb fix(borders): update monitor_idx on all borders
This fixes the issue where borders moved to other monitors would
sometimes be removed by their initial monitor because this data wasn't
being updated.

This effectively reverts commit 5919f88b38.
2025-03-17 18:15:27 -07:00
alex-ds13 c083484ef0 fix(wm): correctly focus workspace on eager-focus 2025-03-17 18:12:51 -07:00
alex-ds13 17cbdc8663 docs(mkdocs): add multi monitor common-workflows section 2025-03-14 16:51:02 -07:00
alex-ds13 a4de2ee841 fix(wm): use preferred id when caching monitors
Use the preferred id set by the user as the key when caching monitors.
This way if a user is having issues with the device_id on their system
they can use the serial_number_id on display_index_preferences.

If instead a user is having issues with the serial_number_id they can
make sure to use the device_id on display_index_preferences. Komorebi
will use the preferred one as a key when caching the monitors.

This PR also includes a change of the DISPLAY_INDEX_PREFERENCES from a
Mutex to RwLock.

I believe the RwLock is better since it allows multiple readers at the
same time, while the mutex blocks on all calls even if you just want to
read or compare some value.

For display index preferences (same thing applies to other existing
mutexes) most times we access it is a read-only access. We only ever
change it when applying a config or when a command is used to change it.

Every other use is a read-only use so it doesn't make sense to block on
those situations
2025-03-13 09:12:15 -07:00
alex-ds13 60e1834b43 fix(wm): correct float window move/resize
This commit fixes an issue where the move/resize functions for floating
windows weren't properly taking into account the coordinates of
secondary monitors and were only working correctly on the main monitor
where top/left was 0/0.
2025-03-11 17:58:05 -07:00
alex-ds13 54323c4c6a fix(wm): update layer on cross monitor moves 2025-03-11 15:19:27 -07:00
alex-ds13 ea9752d5e1 fix(wm): focus correct window if monocled stack
Previously if we had a stack on a monocle container and tried to cycle
stack or move the window within the stack or even using the focus stack
window from a bar it would focus the wrong window and temporarely show
that wrong window. This commit fixes this.
2025-03-10 08:23:49 -07:00
alex-ds13 70a61376a8 fix(borders): ignore borders on all stack window updates 2025-03-04 08:20:35 -08:00
alex-ds13 0776ca1565 feat(border): cache borders on all workspaces
This commit refactors the `border_manager` with the following changes:

- Rework the way the borders are created and their pointer is sent to
  the window message handler. Now we also store the same pointer as a
  `Box<Border>` on the `border_manager`'s `BORDER_STATE`. This means
  that the borders we have are exactly the same ones that the border
  window itself is accessing so we can now store the border's info
  inside the `Border` struct and all of it will be accessible by the
  border window as well. This makes it so the "ACTUAL" border struct is
  the one created on the thread of the `Border::create()` function and
  when that thread finishes (after the border window closes) it will
  handle the drop of the border itself. However this means we need to be
  careful with our own stored `Box<Border>` since it will point to the
  same memory we can't let the compiler dropped them as usual or
  otherwise it would create heap corruption errors. So this commit
  creates a special function called `destroy_border()` to actually close
  the window border without dropping the border, since it will be later
  dropped by the thread that created it.

- Remove `BORDERS_MONITORS`, `FOCUS_STATE` and `RENDER_TARGETS` arc
  mutexes, since now this info is stored on the border itself.

- Change the `BORDER_STATE` to now map an id (container or window) to a
  `Box<Border>`.

- Change the `WINDOWS_BORDERS` to now map a window hwnd to a border id.

- Create new struct `BorderInfo` which as the border window hwnd and the
  border kind. This struct is what is now returned by the function
  `window_border()` which checks if some window as a border attached to
  it and if it does it returns this info. There is no need to clone the
  entire border. If in the future we need more info we can just add it
  to this struct.

- Change the way we clear the `BORDER_STATE`. Like mentioned before we
  need to be sure we don't drop the `Box<Border>` when removing it, so
  now we use the `.drain` function to remove all the borders as an
  iterator and we call the `destroy_border()` on each border we are
  removing.

- We now check if a border's `tracking_hwnd` has changed and if it does
  we simply update it instead of destroying the border and create a new
  one.

- Create function `delete_border` so that we can remove a border
  properly from outside the `border_manager`.

- Create function `hide_border` which spawns a new thread that searches
  if a window hwnd has a border attached to it and if it does it hides
  said border window. This function is called on every `window.hide()`.

- Create function `show_border` which spawns a new thread that searches
  if a window hwnd has a border attached to it and if it does it restores
  said border window. This function is called on every `window.restore()`.

- This commit also changes the previous `window.hide()` and
  `window.restore()` functions to be named:
  - `window.hide_with_border(hide_border: bool)`: this is the same
    function as before but adds a check at the end in case `hide_border`
    is true it calls `border_manager::hide_border()`. A new function was
    created with the same name as before `window.hide()` which by
    default calls this new function with `hide_border = true`.
  - `window.restore_with_border(restore_border: bool)`: this is the same
    function as before but adds a check at the end in case `hide_border`
    is true it calls `border_manager::hide_border()`. A new function was
    created with the same name as before `window.hide()` which by
    default calls this new function with `hide_border = true`.

- This commit creates a new function on `Container` called
  `load_focused_window_ignore_borders()` which performs the same as
  `load_focused_window()` but it ignores the borders when hiding and
  restoring the windows. This function, along with the
  `hide_with_border(false)` and `restore_with_border(false)` are used on
  all functions related to changing focus on a stack since if we let the
  borders be hidden and restored when cycling or changing focus on a
  stack the border would flicker slightly, this prevents that. Ignore
  borders when clicking on the stackbar as well.
  (P.S. there might still be other places that I forgot to use these new
  functions, but if that is the case then what will happen is a simple
  flicker of the stack border...)

- The `remove_window` from `Workspace` needs to call the
  `border_manager::delete_border()` so that wew make sure we remove that
  windows's border window as well if it exists. This is essential when
  enforcing workspace rules, otherwise the border would be left behind.

- Lastly, but not least, now that we hide the borders windows along with
  their tracking window, we no longer remove the borders when swapping
  workspaces or when toggling monocle, etc. Instead we keep all borders
  of all workspaces cached and simply hide them. They are only removed
  when their tracking window is closed or cloaked on a stack (since on a
  stack we only keep one border for all the entire stack container).
  This means that when changing between workspaces we no longer see the
  borders showing up delayed after the windows show up. Now both the
  window and it's border show up as if they are one and the same.
2025-03-03 21:15:45 -08:00
alex-ds13 724b0b7692 fix(border): update border when moving from admin windows 2025-03-03 21:13:37 -08:00
alex-ds13 b26910aa58 fix(wm): allow stacking in all dirs, improve stack border rendering
Previously the stacking logic would sometimes change the focused
container without actually changing focus to said container.

This resulted in the stack showing up with an unfocused border even
though we had focus on one windows belonging to the stack (just not the
right one).

Also before it wasn't possible to stack windows on some directions
when we were already on a stack.

This commit fixes both issues.
2025-02-26 19:23:40 -08:00
alex-ds13 487c217497 fix(borders): address memory leaks
This commit fixes multiple issues with the borders which were resulting
in multiple borders being created and not completely destroyed which
meant that the amount of borders in memory kept increasing indefinitely
the more we used komorebi. To do so this commit does the following:

- Clear all the maps on `destroy_all_borders`.

- Create function `remove_border` which should always be used when we
  want to remove a border since this function destroys the border window
  and removes all its related data and clones from all the maps.

- Create function `remove_borders` which should always be used when we
  want to remove multiple borders or filter the current existing
  borders. It takes in a `condition` function that takes a ref to the
  border's container id and a ref to the border and should return a
  bool. This function is then applied to each existing border and if it
  evaluates to true it will call `remove_border` on it.

- Apply these new functions on all the code that was previously manually
  removing borders.

- When a container is a stack, we now check it's unfocused windows, in
  case they had borders attached to them we remove them, otherwise these
  borders would persist and be drawn below other borders.

- We now check if a container's border was previously tracking a different
  window, if it was we destroy that border and remove it's hwnd from the
  `FOCUS_STATE` and then we check if its `tracking_hwnd` still points to
  the same border and remove it if it does (if it doesn't that means
  that a new border was already attached to that window so we don't
  remove it).

  We don't call `remove_border` here since we don't want to actually
  remove the border but instead we replace it with a new one tracking
  the correct window. (I've tried updating the `tracking_hwnd` instead
  of destroying the border and creating a new one but that didn't work
  since it still kept tracking the previous window...).
2025-02-26 19:22:22 -08:00
alex-ds13 4031fbf033 feat(wm): move all windows on ws layer toggle
This commit makes it so when you toggle between workspace layers it
moves all windows of that layer to the top of the z-order.

So if you move to `Floating` layer, then all floating windows are moved
to the top, and if you go back to the `Tiling` layer, all tiled
containers are moved to the top.
2025-02-26 19:21:33 -08:00
alex-ds13 20817b094d fix(wm): prevent floating focus change event infinite loops
This commit stops the `FocusChange` event from focusing a floating
window when it is the one emitting said `FocusChange` event, since it's
not needed and is the cause of some flicker bugs reported!

If that floating window was the one emitting the `FocusChange` event
then it means it is already the foreground window, and there is no
reason for us to focus the window again (since that will create an
infinite loop of events).

When the window emitting this event is not floating we don't try to
focus the window, we simply set the focus index for the container of
that window and the focused index for the window of that container.

Except in one case, which is if the workspace has a monocle container,
then it does focus a window, it focuses the monocle window to make sure
the monocle keeps showing in front of everything and doesn't let
anything come in front of it.
2025-02-23 20:16:32 -08:00
alex-ds13 394709e356 fix(reaper): avoid deadlocks at startup
Previously the reaper at startup would lock it's own `HWNDS_CACHE` and
then try to lock the WM to get its `known_hwnds`.

However if there was an event in the meantime, process_event would lock
the WM first and then it would try to lock the reaper's `HWNDS_CACHE` to
update it.  This would deadlock since that would be locked by the reaper
waiting for the WM lock to be released.

This commit now makes it so we pass the `known_hwnds` to the reaper as
an argument at startup and it also rearranges the order of loading the
listeners.

Now komorebi first loads all the manager-type listeners, and only
afterwards does it load the commands and events listeners.

After some testing this seems to be the best order that doesn't cause
any issues at all!

There were some other issues that I've noticed before when starting
komorebi while having other 3rd parties trying to subscribe to it (like
komorebi-bar and YASB), which would make those subscribers lock the
`process_command` thread. This doesn't seem to be happening on my tests
anymore with this new order.
2025-02-23 20:10:29 -08:00
alex-ds13 990a339d4e fix(bar): apply work area offset on monitor reconnect
This commit makes sure the bar applies the the `work_area_offset`
correctly after a monitor reconnects; if it is the first time a monitor
is connecting, the cached offset won't exist yet.
2025-02-23 15:25:19 -08:00
alex-ds13 f0222dd4ab fix(wm): properly load monitor on first connect
This commit fixes an issue where if you started komorebi without a
monitor connected, and then connected it later, it wasn't properly
loading the data returned from `win32-display-data`.
2025-02-23 15:24:15 -08:00
alex-ds13 2bbc269b9f feat(wm): add padding per monitor
This commit adds the ability to set container and workspace padding per
monitor.

To do so (and to simplify any future need of changing some value per
monitor), and have it pass through to each workspace a new field was added
to `Workspace` called `globals` which has a new struct called
`WorkspaceGlobals`.

`WorkspaceGlobals` includes any global values that might be needed by
the workspace.

This field is updated by the monitor for all its workspaces whenever the
config is loaded or reloaded. It is also updated on `RetileAll` and on
the function `update_focused_workspace`.

This should make sure that every time a workspace needs to use it's
`update` function, it has all the `globals` up to date!

This also means that now the `update` function from workspaces doesn't
take any argument at all, reducing all the need to get all the
`work_area`, `work_area_offset`, `window_based_work_area_offset` or
`window_based_work_area_offset_limit` simplifying the callers of this
function quite a bit.

Lastly this commit has also (sort of accidentaly) fixed an existing bug
with the `move_workspace_to_monitor` function.

This was previous removing the workspace from a monitor, but wasn't
changing it's `focused_workspace_idx`, meaning that komorebi would get
all messed up after that command. For example, the `border_manager`
would get stuck and the komorebi-bar would crash.

Now, the `remove_focused_workspace` function also focuses the previous
workspace (which in turn will create a new workspace in case the removed
workspace was the last workspace).
2025-02-23 09:52:33 -08:00
alex-ds13 13ee42276d fix(wm): hide/restore floating windows on monocle toggle 2025-02-23 06:51:42 -08:00
alex-ds13 3641ce6b42 fix(wm): take layer into account on ws restore
Previously if a workspace had any floating windows it would always focus
the first one when restoring. Now it only focus the floating window if
the workspace layer is `Floating`.
2025-02-23 06:51:14 -08:00
alex-ds13 3d327c407c perf(reaper): switch to channel notifications
This commit changes the way the reaper works.

First this commit changed the `known_hwnds` held by the `WindowManager`
to be a HashMap of window handles (isize) to a pair of monitor_idx,
workspace_idx (usize, usize).

This commit then changes the reaper to have a cache of hwnds which is
updated by the `WindowManager` when they change. The reaper has a thread
that is continuously checking this cache to see if there is any window
handle that no longer exists. When it finds them, the thread sends a
notification to a channel which is then received by the reaper on
another thread that actually does the work on the `WindowManager` by
removing said windows.

This means that the reaper no longer tries to access and lock the
`WindowManager` every second like it used to, but instead it only does
it when it actually needs, when a window actually needs to be reaped.
This means that we can make the thread that checks for orphan windows
run much more frequently since it won't influence the rest of komorebi.

Since now the `known_hwnds` have the monitor/workspace index pair of the
window, we can simply get that info from the map and immediately access
that monitor/workspace or use that index info.
2025-02-22 12:29:27 -08:00
alex-ds13 e5fb5390a8 feat(wm): strip unncessary info from state 2025-02-22 12:28:30 -08:00
alex-ds13 6a8e362c21 refactor(wm): make workspace fields public 2025-02-22 12:28:23 -08:00
alex-ds13 1edeb44203 fix(wm): include workspace rules on cached monitor
The `WorkspaceConfig` stored on `Workspace` was changed to not be
serialized, however it needs to be serialized and deserialized when
caching a monitor (after a disconnect), so that when it reconnects it is
able to read all the workspace rules, which include:

- initial_workspace_rules
- workspace_rules
- window_container_behaviour_rules
- layout_rules
- custom_layout_rules

This commit changes the serde skip to only skip if is is `None`.

This means that the `komorebic state` command will have all this
information as well and it will send it when notifying subscribers too,
which isn't good at all, so we need to find another way of excluding it
from the state.
2025-02-22 12:27:55 -08:00
alex-ds13 c095f8ae9f fix(bar): improve handle monitor lifecycle handling
This commit introduces a few changes to the bar so that it can handle
the monitor disconnect/reconnect properly and so that it can map the bar
config to the correct monitor.

Previously if you had 3 monitor configs setup on `komorebi.json` with
the `display_index_preferences` set like this:

```
"display_index_preferences": [
    "0": "MONITOR_A",
    "1": "MONITOR_B",
    "2": "MONITOR_C",
]
```

But if you only had connected monitors A and C you would have to
manually change the bar configurations monitor index because now monitor
A would have index 0, but monitor C would have index 1 instead of 2.

Now with this commit this is no longer needed. Now the monitor index
setup on the bar configuration **MUST BE** the index you've used on
`display_index_preferences` for that monitor.

So in the case above you would setup the bar configurations using the
indices 0, 1 and 2 for monitors A, B and C respectively.

As for the changes introduced on this commit they are the following:

- `Komobar.monitor_index` is now an `Option`. When it is `None` it
  either means that the bar is starting and has not yet received the
  first `State` from komorebi or that the bar is disabled.

- `Komobar.config` is no longer an `Arc`. There was no need for that and
  it was creating more issues and difficulties. It was mainly used to
  pass the config as an `Arc` to `apply_config` function, but then this
  function would actually clone the config itself (not just the `Arc`).

  Also this function was passing a `self.config.clone()` most of the
  times except once when it received a new config from a hotreload. Now,
  on hotreload it first sets `self.config` to the new config and then
  calls `apply_config` which now uses its own `self.config` everywhere.

- We only change the `work_area_offset` when the bar is not disabled.

- We update the global `MONITOR` size/coordinates when we receive a
  `DisplayConnectionChange` from komorebi.

- We also check if the monitor size/coordinates have changed from the
  currently stored ones on every komorebi notification since sometimes
  the `DisplayConnectionChange` would be emitted while the state still
  had the previous size/coordinates.

  This makes sure we always capture a change of size/coordinates, store
  the new values, and update the bar.

- The previously mentioned update of the `MONITOR` coordinates also
  updates the `config.position.start` since that value is being
  overriden on `main.rs` in case the user hasn't set it so we need to
  override it again with the new monitor coordinates.

  This might mean that users of the old config system might have their
  start position changed, but if we didn't do this the bar wouldn't even
  show on the screen for them when a monitor disconnected/reconnected.

  This is another case for users to start moving into the new config
  system, since with that system the bar will still show up with the
  correct margins!
2025-02-20 19:57:36 -08:00
alex-ds13 c455ad1386 feat(wm): register more monitor reconcilator events
This commits adds a few more events that can trigger a
`DisplayConnectionChange` event.

Some of these events are redundant and after a display is
disconnected/reconnected it emits multiple `DisplayConnectionChange`
events.

However, when trying to remove them to have just one it stopped behaving
as it should, as if it was missing the update, while having them
duplicated it works properly.

Therefore it appears to be better to keep them for now, since the
duplicated events will exit early as soon as they see that the monitor
counts match (on the first event the counts don't match so it
adds/removes the monitor and the following events see that the counts
match).
2025-02-20 19:55:24 -08:00
alex-ds13 ce99290027 chore(deps): update win32-display-data rev 2025-02-20 19:55:19 -08:00
alex-ds13 60bc83d407 fix(wm): increase monitor_reconciliator channel bound
When there is a monitor disconnect/reconnect, usually it produces
multiple monitor events along with it, like the monitor resolution
change and the work area change. With the bound set to 1 it would
sometimes result in missed events.

This commit increases the bound to 20 to prevent this from happening.
2025-02-20 19:54:55 -08:00
alex-ds13 9c8a639282 fix(wm): check for monitor changes on system resume 2025-02-20 19:54:34 -08:00
alex-ds13 b7ebd3fe63 fix(bar): check monitor connection on all notifications 2025-02-20 19:54:27 -08:00
alex-ds13 ec8519d75a fix(wm): don't panic if state isn't up to date
This commit makes sure that if the state on file isn't up to date with
the expected `State` struct (maybe after an update) it doesn't panic
komorebi entirely, instead it ignores the state and continues with a
clean state.
2025-02-20 19:54:17 -08:00
alex-ds13 c62405bfaa fix(bar): restore + reposition on monitor reconnect 2025-02-20 19:54:05 -08:00
alex-ds13 0126465de4 fix(wm): cache monitor state instead of config
This commit changes the MONITOR_CACHE to hold an actual monitor with its
state instead of the config.

This allows us to keep the state of a disconnected monitor, so that when
the monitor reconnects we still have access to all its workspaces and
windows as they were before.

While the monitor is disconnected, all the windows from that monitor are
not considered as handled by komorebi and so they're free to be handled
at any point; if for example the user uses `alt+tab` or presses the
taskbar icon of one of these windows, that window will produce a `Show`
event and will become handled by the currently focused workspace of the
focused monitor.

When the disconnected monitor reconnects it checks all windows and once
it notices that this specific window is now being shown on another
monitor/workspace, it ignores it.
2025-02-20 19:52:38 -08:00
alex-ds13 1cd28652aa feat(wm): keep track of known_hwnds on wm 2025-02-20 19:52:15 -08:00
alex-ds13 a1ab1c5724 fix(wm): update usr idx map when there are no index preferences 2025-02-20 19:52:00 -08:00
alex-ds13 be932078e0 refactor(wm): make monitor fields public 2025-02-20 19:51:49 -08:00
alex-ds13 302e96c172 fix(bar): handle monitor disconnect/reconnect
This commit allows a bar to be disabled when it's monitor is
disconnected and re-enabled when said monitor reconnects.

This commit also uses the new `monitor_usr_idx_map` to properly map the
monitor index given by the users on config to the actual monitor index
on the `WindowManager` - in case some middle monitor gets disconnected
the index of the monitors to the "right" of that one will be lowered by
1.

This should allow for the following in cases with monitor A, B and C: if
monitor B disconnects, its bar will be disabled and monitor C will
properly change its monitor index internally to 1 so it still gets the
infos from monitor C (which now will have index 1 on the
`WindowManager`).
2025-02-20 19:49:47 -08:00
alex-ds13 c05eab9044 feat(wm): add monitor_usr_idx_map to wm
This commit creates a new field on the `WindowManager` called
`monitor_usr_idx_map` which contains a map of user intended index for
monitors to their actual monitors' index.

It will be rebuilt on `load_monitor_information` by taking into account
the `display_index_preferences`.
2025-02-20 19:49:21 -08:00
alex-ds13 ff986fba67 fix(wm): remove ws rules from disconnected monitors
This commit makes sure that any workspace_rules that tried to move a
window to a monitor that has been disconnected are removed.

If the monitor is later reconnected the workspace_rules should be added
from the cached config.
2025-02-20 19:48:56 -08:00
alex-ds13 e408410c58 fix(wm): handle serial id on load_monitor_information 2025-02-20 19:48:38 -08:00
alex-ds13 3ade81444a feat(wm): support both serial numbers and device ids
This commit makes use of both `serial_number_id` and `device_id` with
the first taking priority on all monitor reconciliator code, monitor
cache and on postload and reload.

This allows using the serial numbers on the `display_index_preferences`
config, while keeping compatibility with the use of `device_id`.

Using `device_id` should be discouraged since that value can
change on restart while serial number doesn't appear to do so.
2025-02-20 19:47:25 -08:00
alex-ds13 c9e98c3cdb fix(wm): serde skip annotation for workspace_config 2025-02-20 19:46:36 -08:00
alex-ds13 b42fcbe509 fix(wm): restore orphaned containers
When a monitor was disconnected the containers from the removed monitor
were being moved to the primary monitor.

However they weren't restored so containers that were on an unfocused
workspace of the removed monitor would have been cloak and were getting
added to the main monitor still cloaked creating ghost tiles. This
commit fixes that.
2025-02-20 19:46:21 -08:00
alex-ds13 d8636d651d fix(wm): don't store empty layout_rules on monitor cache 2025-02-20 19:46:14 -08:00
alex-ds13 9ad32e40cf fix(wm): cache monitor configs for unloaded monitors
If we have display_index_preferences that set a specific config index
for a specific display device, but that device isn't loaded yet, now we
store that config with the corresponding `device_id` on the monitor
cache.

Now when the display is connected it can load the correct config from
the cache.
2025-02-20 19:45:31 -08:00
alex-ds13 c91cb9f061 fix(wm): improve display_index_preferences selection
This commit reworks the way the `postload` and the `reload` functions
apply the monitor configs to the monitors.

Previously it was looping through the monitor configs and applying them
to the monitor with the index corresponding to the config's index.

However this isn't correct, since the user might set the preferred
indices for 3 monitors (like monitor A, B and C), with the preferred
index set to 0 for A, 1 for B and 2 for C, but if only monitors A and C
are connected then komorebi would apply config 0 to A and config 1 to C,
which is wrong it should be 2 for C.

This commit changes the way the configs are applied on those functions.
Now it loops through the existing monitors (already in order), then
checks if the monitor has a preferred config index, if it does it uses
that one, if it doesn't then it uses the first monitor config that isn't
a preferred index for some other monitor and that hasn't been used yet.

For the situation above it means that it would still apply config 2 to
monitor C. And in case there aren't any display_index_preferences set it
will still apply the configs in order.
2025-02-20 19:44:11 -08:00
alex-ds13 52340a1487 refactor(wm): store config on workspace
Store the `WorkspaceConfig` on the `Workspace` itself so that when we
want to cache the workspace as `WorkspaceConfig` on the monitor cache it
properly saves things like the workspace rules and the custom layout and
custom layout rules.
2025-02-20 19:43:53 -08:00
alex-ds13 4f7a8f10c0 fix(wm): properly store tile state when caching ws
Previously, when caching a workspace config for a monitor it would
simply store the `DefaultLayout` on `layout` even if the original
workspace config had the `layout` as `None`, which makes komorebi create
a workspace with the `layout` as default `BSP` and the `tile` set to
`false`.

This resulted in floating workspaces would becoming tiling `BSP`
workspaces after a monitor disconnect and reconnect.

This commit fixes this by turning the `layout` to `None` when `tile` is
`false`.
2025-02-20 19:42:33 -08:00
alex-ds13 86bbcac5ae feat(client): add more re-exports for integrations
This commit is a squashed commit of all the individual commits that made
up PR #1267 - adding various derives and re-exports aimed at improving
the komorebi integration surface for third party applications.
2025-02-07 15:53:38 -08:00
alex-ds13 7f3b932693 fix(wm): sort layout and behaviour rules
This commit makes sure the `layout-rules` and
`window_container_behaviour_rules` are sorted when setting them from the
config. So that the behaviour on workspace update is correct.
2025-01-27 14:15:02 -08:00
alex-ds13 4a8362336f feat(bar): update bar on display connection change
Use the new `MonitorNotification` to reapply the config and recalculate
the position on `MonitorNotification::DisplayConnectionChange`.
2025-01-24 11:48:29 -08:00
alex-ds13 5c3c3659b5 feat(wm): notify subscribers of monitor events
This commit allows notifying the subscribers of any monitor events like
display connection change or work area change.
2025-01-24 11:48:29 -08:00
alex-ds13 39621c14db fix(wm): stop wrongfully removing layout-flip
This commit removes the code on the workspace `update` on `layout-rules`
where it was setting the `layout-flip` to `None` if the layout was
different from `BSP`. This appears to be some old code when the
layout-flip would only apply to the `BSP` layout. However now it appears
to apply to all layouts so this code shouldn't exist. This commit also
changes the docs from the `FlipLayout` command to remove the statement
that only applied to `BSP` since it is no longer true.
2025-01-23 07:46:30 -08:00
alex-ds13 d7fcbb7d00 fix(bar): pass reconnect event to bar
This commit changes the `rx_gui` from receiving just a notification from
komorebi to now receive a new type `KomorebiEvent` which can be either a
`KomorebiEvent::Notification(komorebi_client::Notification)` or a
`KomorebiEvent::Reconnect`.

The `Reconnect` is sent after losing connection with komorebi and then
reconnecting again.

Now on the bar `update` we check for this `rx_gui` if we get a
notification we pass that to the
`KomorebiNotificationState::handle_notification` function just like
before (except now it takes a notification directly instead of taking
the `rx_gui` and checking for some message on the channel).

If instead we get a `Reconnect` we send a `MonitorWorkAreaOffset` socket
message to komorebi to update the work area offset.
2025-01-22 19:03:38 -08:00
alex-ds13 3e1fc6123a fix(bar): simplify komorebi-bar config
This interactively rebased commit is comprised of the subsequent
individual commits listed further below.

At a high level:

- work_area_offset is now automatically calculated by default
- monitor can now take an index in addition to the previous object
- position can largely be replaced by margin and padding for bars that
  are positioned at the top of the screen
- frame can now largely be replaced by margin and padding for bars that
  are positioned at the top of the screen
- height is now a more intuitive configuration option for setting the
  height of the bar

Detailed explainations and examples are included in the body of PR #1224
on GitHub: https://github.com/LGUG2Z/komorebi/pull/1224

fix(bar): add simplified config for bar

This commit creates a few new config options for the bar that should
make it a lot simpler for new users to configure the bar.

- Remove the need for `position`: if a position is given the bar will
  still use it with priority over the new config. Instead of position
  you can now use the following:
  - `height`: defines the height of the bar (50 by default)
  - `horizontal_margin`: defines the left and right offset of the bar, it
  is the same as setting a `position.start.x` and then remove the same
  amount on `position.end.x`.
  - `vertical_margin`: defines the top and bottom offset of the bar, it is
  the same as setting a `position.start.y` and then add a correct amount
  on the `work_area_offset`.

- Remove the need for `frame`: some new configs were added that take
  priority over the old `frame`. These are:
  - `horizontal_padding`: defines the left and right padding of the bar.
    Similar to `frame.inner_margin.x`.
  - `vertical_padding`: defines the top and bottom padding of the bar.
    Similar to `frame.inner_margin.y`.

- Remove the need for `work_area_offset`: if a `work_area_offset` is
  given then it will take priority, if not, then it will calculate the
  necessary `work_area_offset` using the bar height, position and
  horizontal and vertical margins.

feat(bar): set margin/padding as one or two values

This commit changes the `horizontal_margin`, `vertical_margin`,
`horizontal_padding` and `vertical_padding` to now take a
`SpacingAxisConfig` which can take a single value or two values.

For example, you can set the vertical margin of the bar to add some
spacing above and below like this:

```json
"vertical_margin": 10
```

Which will add a spacing of 10 above and below the bar. Or you can set
it like this:

```json
"vertical_margin": [10, 0]
```

Which will add a spacing of 10 above the bar but no spacing below. You
can even set something like this:

```json
"vertical_margin": [0, -10]
```

To make no spacing above and a negative spacing below to make it so the
tiled windows show right next to the bar. This will basically be
removing the workspace and container padding between the tiled windows
and the bar.

fix(bar): use a right_to_left layout on right side

This commit changes the right area with the right widgets to have a
different layout that is still right_to_left as previously but behaves
much better in regards to its height.

fix(bar): use default bar height

When there is no `work_area_offset` and no `height` on the config it was
using the `BAR_HEIGHT` as default, however the automatica
work_area_offset calculation wasn't being done properly. Now it is!

feat(bar): monitor can be `MonitorConfig` or index

This commit allows the `"monitor":` config to take a `MonitorConfig`
object like it used to or simply a number (index).

docs(schema): update all json schemas

fix(bar): update example bar config

fix(bar): correct work_area_offset on secondary monitors

feat(bar): add multiple options for margin/padding

This commit removes the previous `horizontal_margin`, `vertical_margin`,
`horizontal_padding` and `vertical_padding`, replacing them all with
just `margin` and `padding`.

These new options can be set either with a single value that sets that
spacing on all sides, with an object specifying each individual side or
with an object specifying some "vertical" and/or "horizontal" spacing
which can have a single value, resulting on a symmetric spacing for that
specific axis or two values to define each side of the axis individually.
2025-01-22 18:57:32 -08:00
alex-ds13 96f7eb1d31 fix(bar): apply position on start
For some reason, when calling the `window.set_position` when creating
the Komobar or even when applying the config on the first frame the
actual EGUI's window size wasn't changing. This commit adds a new field
to `Komobar` called `size_rect` so that we can store the expected size
rect of the window according to the config, so that we don't have to be
calculating it all the time. This field is updated on `apply_config`.

Now on `update` of the bar we check if the current size using the EGUI
Context is the expected `size_rect`, if it is we do nothing, if it is
not we update the bar position. This makes sure that on start the bar
will resize to the users config correctly! Now the resize of the bar
only happens here.

This commit also adds the `hwnd` field to `Komobar` so that we don't
have to be calling `process_hwnd()` all the time.
2025-01-07 16:39:38 -08:00
alex-ds13 692da90890 feat(wm): allow reapplying initial workspace rules
This commit adds the following new socket messages and commands:
- `EnforceWorkspaceRules`: resets the `already_moved_window_handles` and
  calls `enforce_workspace_rules` so that all workspace rules, including
  initial workspace rules are applied again
- `enforce-workspace-rules`: cli command which sends the
  EnforceWorkspaceRules socket message
2024-12-26 14:16:25 -08:00
alex-ds13 4babf336ec fix(bar): prevent komorebi connection from staling
Sometimes the bar would randomly stop receiving notifications from
komorebi and would stop updating the `Komorebi` widget.

This feels to me that the reason is the same one that used to happen on
the `process_commands` from `komorebi` where the socket would get stuck
reading an empty connection.

This commit adds a read timeout to the socket to prevent that from
happening and hopefully it should stop those situations where the bar
would stop receiving notifications.
2024-12-26 14:16:13 -08:00
alex-ds13 d93b6fa1b3 fix(bar): update widgets background color properly
Previously when changing between themes with different backgrounds the
widget's background color was not updating because they take the bg
color from the `RenderConfig` which was only being updated on
`apply_config`, now we also pass the `RenderConfig` to the `apply_theme`
function and update it's `background_color` there as well.
2024-12-21 08:53:01 -08:00
alex-ds13 5ab5ec4f3a fix(bar): apply theme on first frame
On some computers the context colors were being reset on the very first
frame. So now we try to apply the theme on the first frame and
afterwards we only do it again when there is a config change or a theme
socket message.
2024-12-19 16:39:35 -08:00
alex-ds13 ad08585faf fix(bar): use layout on Area to prevent shaking
There were some cases were the bar was showing some shaking, turns out
that using `ui.with_layout` instead of `ui.horizontal_centered` removes
this shaking, so this commit makes that change and uses the
`right_to_left` layout on the right widgets again, meaning that we need
to reverse them again.
2024-12-19 16:39:35 -08:00
alex-ds13 eb8a988841 fix(bar): fix background color clobbering 2024-12-19 16:39:35 -08:00
alex-ds13 0e2a55b300 fix(bar): apply roundings on komorebi.json change
Group roundings were getting lost when applying the theme after a
`komorebi.json` change/save trigger. Now we reapply these groupings on
the `apply_theme` to make sure they are always correct.
2024-12-19 16:39:35 -08:00
alex-ds13 eda91dcd1d fix(bar): use bg color before applying transparency 2024-12-19 16:39:35 -08:00
alex-ds13 0c6317a27b fix(bar): use correct transparency_alpha
Previously when reading the `theme` from `komorebi.json` it was also
getting the transparency_alpha from the `StaticConfig`, this is wrong,
it should use the alpha from the bar config. This commit fixes that.
2024-12-19 16:39:35 -08:00
alex-ds13 5c81a8c9e2 fix(bar): apply work_area_offset on config change 2024-12-19 16:39:35 -08:00
alex-ds13 a4128b7276 fix(bar): handle komorebi theme change properly
Previously if we changed/set the theme on `komorebi.json` it would apply
that theme to the bar without taking into account the transparency
alpha, also after removing the `theme` from `komorebi.json` file it
wasn't applying the theme from the bar config. This commit fixes these
issues.
2024-12-19 16:39:35 -08:00
alex-ds13 73a4df884c fix(bar): use the frame.inner_margin config 2024-12-19 16:39:35 -08:00
alex-ds13 32a234317c fix(bar): actually save the config on apply_config 2024-12-19 16:39:35 -08:00
alex-ds13 0dc6780da6 fix(bar): normalize areas of widgets
This commit changes the way each of the 3 parts of potential widgets
(left, center and right) is created so that they are all done on the
same way and look the same. It is using `Area` with different anchors
for each part which makes the widgets actually center vertically
properly.

This created an issue with the `Bar` grouping. To fix it we've made the
`Bar` grouping change the outer panel frame instead of creating an
actual group. This has the side effect (or maybe feature!) of losing the
background of the outer frame. Meaning this outer frame will now have
the look of the `Bar` grouping only. Currently it is using a fixed outer
margin but this can be changed in the future to a config option.
2024-12-19 16:39:35 -08:00
alex-ds13 f089d3e59b feat(wm): allow stopping without restoring windows
This commit creates a new `SocketMessage` called `StopIgnoreRestore`
which makes komorebi stop without calling `window.restore()` on all
windows. This way every maximized window will stay maximized once you
start komorebi again and it is able to use the previous `State`.

If it fails to restore the previous state you might have to call
`komorebic restore-windows` in case you had hidden windows, for example
when when using the `window_hiding_behaviour` as `Hide`, or you can
simply unminimize them if you were using `Cloak` or `Minimize`.
2024-12-18 08:19:21 -08:00
alex-ds13 d393f8fe77 feat(bar): add two new display format types
This commit adds two new `DisplayFormat` types:
- `TextAndIconOnSelected`: which displays icon and text for the selected
  element and the other elements only have text.
- `IconAndTextOnSelected`: which displays icon and text for the selected
  element and the other elements only have icon.
2024-12-17 16:00:08 -08:00
alex-ds13 c3769e7881 feat(bar): optional workspaces on Komorebi widget
This commit makes the `workspaces` on `Komorebi` widget optional. This
way it allows adding the `workspaces` on one Alignment and the
`focused_window` on another one, for example.
2024-12-17 14:43:59 -08:00
alex-ds13 804faef229 fix(wm): focus and update after apply state
This commit makes sure we focus the previously focused workspace on all
monitors, load it and update it and in the end focus the actual focused
monitor and workspace pair calling `update_focused_workspace` to make
sure it updates the workspace and gives focus to the focused window.
2024-12-17 11:51:55 -08:00
alex-ds13 10539a4bab fix(bar): prevent the bar from changing mff value
This commit makes use of the new `send_batch` function to batch all the
messages in one go when pressing the button to move between workspaces
or when moving between stacked windows.

Since we are creating this messages in one go we won't be mistakenly
changing the value of mff for the user.

It also only batches the mff messages when the mff value it's true, if
it is already false there is no need to be sending those extra messages.
2024-12-14 08:59:46 -08:00
alex-ds13 9463c75f12 feat(client): create send_batch helper
This commit adds a helper function `send_batch` to komorebi-client that
allows sending multiple messages in a batch.

3rd party users of this library could already do this themselves but it
is nice to have this helper to simplify it.
2024-12-14 08:59:29 -08:00
alex-ds13 26f90cc9ee fix(borders): floating window z-order handling
This commit makes it so a floating window only has the floating border
when it is focused, if not it has the `Unfocused` border. It also makes
the 'focused_container' have the `Unfocused` border when it is not the
foreground window, for example when we have a floating window focused
instead.

This commit also changes the border's `window_kind` so that the stored
borders actually have that value so we can check it later (This value
wasn't being updated).

This commit also makes it so we properly invalidate the borders in the
situations discussed above (for example when changing focus to/from a
floating window we need the floating window border to update its ZOrder
as well as the previously focused window).

Lastly this commit, changes the `WM_PAINT` code part of the border so
that it now sets the position of border so that the border's ZOrder
updates to it's tracking window ZOrder.
2024-12-09 14:53:14 -08:00
alex-ds13 192af6751b fix(border): stop removing borders on wrong monitors 2024-12-09 07:57:53 -08:00
alex-ds13 8743cdd292 fix(wm): cross-monitor ops for floating windows
This commit fixes an issue where when trying to move floating windows or
windows on a floating workspace across boundaries to another monitor
using the `move_container_in_direction` it wouldn't move the floating
windows physically, although it moved them internally on komorebi,
resulting in weird and wrong behavior.

This commit creates a new method on `Monitor` to
`add_container_with_direction` which takes a move direction and then
uses the same logic that was previously on the
`move_container_in_direction` function.

It changes the `move_container_to_monitor` function to take an optional
move direction which if it is some will have this function call the new
method `add_container_with_direction` instead of just `add_container`.

Lastly the `move_container_in_direction` function now when it realizes
the move will be across monitors simply calls the
`move_container_to_monitor` with the direction that was initially given
to it.

These changes require that all callers of `move_container_to_monitor`
add an direction option, instead of passing `None` on all of them, a new
helper function was created, named `direction_from_monitor_idx` which
calculates the direction a move will have from the currently focused
monitor and the target monitor return `None` if they are the same or
returning `Some(direction)` if not. This way now all commands that call
a move across monitor will use the logic to check from the direction if
it should add the container on front or end.

With these changes now all the code related to moving a window across
monitors using a command should be on one place only making sure that in
the future any change required only needs to be done on one place,
instead of having to do it on `move_container_to_monitor` and
`move_container_in_direction` as before!

This commit is an interactive squashed rebase of the following commits
from PR #1154:

8f4bc101bc
fix(wm): move floats in direction across monitors

This commit fixes an issue where when trying to move floating windows or
windows on a floating workspace across boundaries to another monitor
using the `move_container_in_direction` it wouldn't move the floating
windows physically, although it moved them internally on komorebi,
resulting in weird and wrong behavior.

This commit creates a new method on `Monitor` to
`add_container_with_direction` which takes a move direction and then
uses the same logic that was previously on the
`move_container_in_direction` function.

It changes the `move_container_to_monitor` function to take an optional
move direction which if it is some will have this function call the new
method `add_container_with_direction` instead of just `add_container`.
Lastly the `move_container_in_direction` function now when it realizes
the move will be across monitors simply calls the
`move_container_to_monitor` with the direction that was initially given
to it.

These changes require that all callers of `move_container_to_monitor`
add an direction option, instead of passing `None` on all of them, a new
helper function was created, named `direction_from_monitor_idx` which
calculates the direction a move will have from the currently focused
monitor and the target monitor return `None` if they are the same or
returning `Some(direction)` if not. This way now all commands that call
a move across monitor will use the logic to check from the direction if
it should add the container on front or end.

3b20e4b2fe
refactor(wm): use helper function on move to workspace

Use the same `add_container_with_direction` function on
`move_container_to_workspace` as it is being used on
`move_container_to_monitor` or `move_container_in_direction`.

This way we bring parity between all methods and make it easier to
change the way a container is added on a monitor workspace when taking
the move direction into consideration.
2024-11-30 10:57:15 -08:00
alex-ds13 01367f59e2 fix(client): add write-timeout to prevent blocking 2024-11-29 08:11:36 -08:00
alex-ds13 e6ddccc5f6 fix(wm): move ops on floating workspaces
83f222fe84
* fix(wm): correctly define moves across monitors

Moves within the same workspace were being considered as moves across
monitors when the workspace was floating (not tiled).

This commit fixes this by changing the way we first define if a move was
across monitor or not.

We now search for the moved window on all workspaces and check if its
monitor index is different from the target monitor index (the monitor
where the move ended).

a02694348e
* fix(wm): ignore moves/resizes on floating workspaces

This commit makes sure that moves or resizes within a floating workspace
(i.e. not tiled) will be ignored, unless the move is across monitors.
We don't care about the positions or sizes of windows within a floating
workspace!

4bf24f81e0
* fix(wm): avoid workspace load on cross monitor moves

This commit replaces the `window_manager.focus_workspace` call with a
`monitor.focus_workspace` which doesn't load the workspace. There is no
need to load the workspace when moving windows across monitors since
those workspaces will already be loaded, we simply need to update them.
Loading the workspace would cause some issues as well, like when moving
a window to a floating workspace which already contained a window that
matched some `floating_windows` rules was always putting the
"floating_window" on top of the window we just moved with a bunch of
focus flickering. This is fixed with this commit.

cb53f463ae
* fix(wm): avoid workspace load on command move across monitor

If the move happens between the already focused workspaces of two
monitors we shouldn't load the workspace, since it is already loaded and
it will cause changes on focused windows, which might result on the
window we just moved not being focused.
2024-11-29 02:57:32 -08:00
alex-ds13 6f00c527a4 fix(wm): cross-monitor max floating window moves
When moving maximized floating windows across monitors they were
magically disappearing!

The window would be on the correct place, with the correct coordinates
and size, its styles wouldn't change it would still have the `VISIBLE`
style, however the window was invisible.

If we used the system move to try to move it sometimes we would be able
to see a bar on the top of the monitor and if we moved the window with
the keyboard on the direction of another monitor then the window would
start showing up on that monitor... So it was visible on that monitor
but not on the one we just moved it into.

After some investigation I decided to atribute that behavior to magic,
since I couldn't find any other plausible explanation, if someone knows
about this please tell me, I too would like to learn the ways of this
dark mysteries from the deep of the Windows OS.

On a serious note, this commit creates a workaround for this by simply
unmaximazing the window first (it's not restore, it doesn't change the
size) then it moves the window (if animations are enabled it proceeds to
wait for the animation to finish...), then it maximizes the window
again.
2024-11-26 14:34:57 -08:00
alex-ds13 3ad4090df8 fix(wm): resize float windows moved across monitors
Previously when moving floating windows across monitors we would keep
the size of the window as it was. For most cases this would be ok.

However for users with monitors with completely different sizes this
could result on a window that would fill across monitors when moving
from the bigger monitor to the smaller monitor.

This commit, attempts to resize the windows proportionally to the
monitors' sizes.

There is currently a slight issue with some apps (so far I've only
noticed it on 'Wezterm'...) where if the DPIs across monitors are
different they don't seem to fully get the OS DPI change completely, but
it seems that setting the `Wezterm` compatibility high DPI scaling
override to "System" on the app's executable properties, fixes the
issue.

Since this is only 1 app (so far...) and only when the scales between
monitors are different I decided to commit this anyway.

This will do more good than harm, since in the cases it was misbehaving
with 'Wezterm' the result would be a wrongly resized window that is
still completely visible on the target monitor anyway and the override
fix seems to be good so far.
2024-11-26 14:34:17 -08:00
alex-ds13 3615451f41 fix(wm): disallow focusing other windows when there is a maximized_window 2024-11-21 12:06:54 -08:00
alex-ds13 6893f39dd9 fix(wm): focus maximized windows when moving focus across monitors
There was an issue where if you changed focus across monitors and the
target monitor had a maximized window it would focus one of the
containers beneath it instead. And if there were no containers it
wouldn't focus anything, but instead keep focus on the previous monitor.
This commit fixes that issue.
2024-11-21 12:06:54 -08:00
alex-ds13 7f0b54c35e fix(wm): add read timeout to command socket
After investigating further the issue where commands would randomly stop
working, we've noticed that the issue seems to be that somehow the
listening thread gets stuck reading the unix socket, as in it
continuously tries to read a socket on a connection that is not sending
anything anymore. The result would be that komorebi would no longer be
able to receive commands until it was restarted.

This fix adds a read timeout of 1s and it spawns a new thread to handle
the stream reading and process of cmds. So in case this happens again,
that specific processing thread will only be stuck for 1s but the rest
of komorebi will never get stuck and should keep working normally.
2024-11-11 06:22:42 -08:00