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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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...).
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.
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.
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.
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.
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`.
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).
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`.
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.
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.
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!
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).
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.
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.
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.
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`).
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`.
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.
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.
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.
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.
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.
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.
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`.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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`.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.