Compare commits

...

40 Commits

Author SHA1 Message Date
LGUG2Z
3281c61113 wip 2025-05-07 09:33:20 -07:00
LGUG2Z
70f561e6ac feat(shortcuts): add helper written in egui
This commit adds a simple egui helper application which shows a list of
shortcuts defined in a user's whkdrc file. Parsing AHK files is not
supported.

In addition to listing out shortcuts defined in the whkdrc file, the top
line allows users to add filter a filter to narrow down the list of
commands and key bindings to the ones they are interested in.

A new komorebic command "toggle-shortcuts" has been introduced which
will first attempt to kill "komorebi-shortcuts.exe", and then exit if
the kill signal was successful (ie. a process was closed), or proceed to
open "komorebi-shortcuts.exe" if the kill signal was not successful (ie.
no process was closed, so we should open one).

"komorebi-shortcuts.exe" has been added as a floating application in
lib.rs to allow for users to use the "komorebic move" command to
manipulate its position via their existing keyboard bindings.
2025-05-07 08:52:08 -07:00
LGUG2Z
4ea835fa59 feat(wm): toggle monocle off on monitor container moves
This commit ensures that if a user sends one of the various messages
which ultimately call move_container_to_monitor, if the target workspace
on the target monitor currently has a monocle container, it will be
toggled off to allow space for the container being moved to be rendered.
2025-05-07 08:19:22 -07:00
LGUG2Z
09137af305 feat(wm): toggle monocle off on ws container moves
This commit ensures that if a user sends one of the various messages
which ultimately call move_container_to_workspace, if the target
workspace currently has a monocle container, it will be toggled off to
allow space for the container being moved to be rendered.
2025-05-06 17:03:57 -07:00
LGUG2Z
ee89b344df chore(deps): update dependencies.json 2025-05-04 11:38:03 -07:00
LGUG2Z
46d5ea4a1d refactor(wm): log errors when allow_set_foreground_window fails
This startup Win32 API call can sporadically fail, so this commit adds
some retry logic and logging of errors every time it fails. If it
crosses the retry threshold, the application will exit (because you
can't really have a tiling window manager running that doesn't let you
set the foreground window).
2025-05-02 17:49:29 -07:00
LGUG2Z
82c2241601 fix(wm): don't reap ws windows when using hide instead of cloak
This commit ensures that workspace windows that are hidden when the user
is using HidingBehaviour::Hide will not be unintentionally reaped by a
hard-coded workaround for Microsoft Office's continuing
enshittification.

HidingBehaviour::Hide has also been marked in the docs as an EOL
feature, and some dead code that was ultimately migrated to reaper.rs
has been cleaned up.

fix #1426
2025-05-02 17:29:41 -07:00
dependabot[bot]
c28773b96a chore(deps): bump miette from 7.5.0 to 7.6.0
Bumps [miette](https://github.com/zkat/miette) from 7.5.0 to 7.6.0.
- [Release notes](https://github.com/zkat/miette/releases)
- [Changelog](https://github.com/zkat/miette/blob/main/CHANGELOG.md)
- [Commits](https://github.com/zkat/miette/commits/miette-derive-v7.6.0)

---
updated-dependencies:
- dependency-name: miette
  dependency-version: 7.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-29 08:27:05 -07:00
LGUG2Z
577364a556 feat(bar): hide when leaving komorebi's virtual desktop
This commit adds a new VirtualDesktopNotification which is used to
notify subscribers when the user leaves and enters the virtual desktop
associated with komorebi.

komorebi-bar consumes these notifications to minmize and restore the bar
appropriately depending on the currently focused virtual desktop.

re #1420
2025-04-28 14:33:39 -07:00
LGUG2Z
17cd0308cb feat(bar): improve path handling on apps widget
This commit improves path handling for commands and icons in the new
Application widget by making use of PathExt::replace_env when loading
the user-specified ApplicationsConfig.

Crucially for scoop users, this means that user-agnostic references to
scoop apps can now be made like this:

```
$Env:USERPROFILE/scoop/apps/zed-nightly/current/zed.exe
```

When attempting to look up an icon for a command, we now split the
command on ".exe", and if this is a complete path to a file, we try to
use it to extract an icon, otherwise we try to resolve a complete path
using "which" before doing the same.
2025-04-27 11:47:19 -07:00
Alisher Galiev
10424b696f feat(bar): add applications widget
This pull request introduces a new Applications widget that displays a
user-defined list of application launchers in the UI. Each app entry
supports an icon, a label, and executes its configured command on click.

The design of this widget is inspired by the Applications Widget of YASB
Reborn. I personally missed this functionality and aimed to bring a
similar experience to komorebi-bar.

Further information is in the text of PR #1415
2025-04-27 11:45:06 -07:00
LGUG2Z
6e7d8fb922 fix(animation): avoid redundant async window pos calls
As pointed out by @alex-ds13, animations run on a separate thread and so
unresponsive apps will not block komorebi.
2025-04-25 17:53:57 -07:00
LGUG2Z
917cd9b7db fix(borders): destroy all if a different vd is detected
This commit ensures that all borders will destroyed if komorebi detects
that the user has switched to a Windows Virtual Desktop different from
the one it was launched on and associated with.

There is still some work to be done to forcibly redraw the borders when
a navigation back to the VD associated with komorebi is detected, but
that requires tracking the state of the current VD ID outside of the
process_event handler somewhere.

re #1420
2025-04-24 21:41:21 -07:00
LGUG2Z
bdbd665b21 refactor(wm): add window handling sync/async enum
This commit adds a dedicated WindowHandlingBehaviour enum with Sync and
Async variants, and reverts a change to the render fn in window.rs to
use move_window instead of position_window if the
WindowHandlingBehaviour variant is Sync.
2025-04-24 18:50:54 -07:00
Kuukunen
f3f2098451 feat(wm): add configuration option for async window handling
Add configuration option for enabling/disabling the asynchronous window
handling. The feature might cause unforeseen issues, so by default it is
off. It can be enabled with setting the option async_window_handling to
true.
2025-04-24 18:50:21 -07:00
Kuukunen
4ca2e8388b fix(wm): fix unresponsiveness by using asynchronous window handling
Unresponsive windows might cause Komorebi to hang because functions like
SetWindowPos wait for the target window's WindowProc.

I changed most SetWindowPos calls to use the SWP_ASYNCWINDOWPOS flag,
which should avoid hanging, and I changed the one
WindowsApi::move_window call to use position_window instead. I also
changed the ShowWindow to ShowWindowAsync.

The only issue I noticed was that it caused the stackbar to disappear
(and/or flicker), probably because the window is modified right after
moving it, so I disabled the async position_window for that.
2025-04-24 18:50:21 -07:00
thearturca
31752e422a feat(animation): cubic-bezier for styles
This commit adds ability to use cubic-bezier as an animation style,
which allows users to customize the smoothness of animations.
2025-04-24 17:42:04 -07:00
Jerry Kingsbury
5e308b9131 test(wm): add window handle to move based on workspace rules test
Created a simple test for the
add_window_handle_to_move_based_on_workspace_rules function.

The test creates mock data representing window and the movement details.

The test will call the function with an empty vector to hold the
workspace rules and then check that the workspace rules are in the
vector.
2025-04-22 18:03:42 -07:00
Jerry Kingsbury
1bf53b89af test(wm): ensure named workspace for monitor test
Created a test for the ensure_named_workspace_for_monitor function.

The test creates two monitors and holds a list of workspace names.

When calling the ensure_named_workspace_for_monitor_function the test
checks to ensure that the the the monitor contains the length of the
list workspaces and that the workspaces uses the name in the list.

The test adds more names to the list and repeats the check on the other
monitor.
2025-04-22 18:03:13 -07:00
Jerry Kingsbury
11690c6004 test(wm): test toggle_monocle and toggle_maximize
Created tests for the toggle_monocle and toggle_maximize functions. The
test are simialar to the maximize and unmaximize test and the monocle on
and off test.
2025-04-22 18:02:59 -07:00
Jerry Kingsbury
3457dfc04c test(wm): monocle on and off test
Created a test for the monocle_on and monocle_off functions.

The test checks to ensure that the focused workspace container becomes a
monocle container when calling the monocle_on function.

The test will also ensure that the container is moved to the workspace's
container ring when the monocle_off function is called.
2025-04-22 18:02:23 -07:00
Jerry Kingsbury
af1c9b5aa9 test(wm): test maximize and unmaximize window
Created a test for maximizing and unmaximizing a window.

The test ensures that the when calling maximize_window, the focused
window is added to the maximized_window list.

When calling unmaximized window, the checks to ensure that None is
returned to ensure that the maximized window is removed from the list.

The test switches to a different window and performs the same checks.
2025-04-22 18:01:55 -07:00
dependabot[bot]
22fac5a9fb chore(deps): bump netdev from 0.33.0 to 0.34.0
Bumps [netdev](https://github.com/shellrow/netdev) from 0.33.0 to 0.34.0.
- [Release notes](https://github.com/shellrow/netdev/releases)
- [Commits](https://github.com/shellrow/netdev/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: netdev
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-21 17:16:48 -07:00
LGUG2Z
7a3990f106 chore(deps): cargo update 2025-04-20 10:39:28 -07:00
alex-ds13
74e93e5524 fix(wm): ensure default CrossBoundaryBehaviour consistency
This commit fixes the default for `CrossBoundaryBehaviour` which was set
to `Monitor` when loading a user configuration but was set to
`Workspace` if starting from fresh without a user config.

The docs also stated that this value was `Monitor` by default.
2025-04-20 10:26:01 -07:00
alex-ds13
86e78570d6 fix(wm): reset global configs to default on removal 2025-04-20 10:26:01 -07:00
alex-ds13
3ee3aac806 feat(wm): float placement configs
This commit adds a few more options to combine with the
`FloatingLayerBehaviour` which determine placement in different
situations:

- `"toggle_float_placement"`: the placement to be used by a floating
  window when it is forced to float with the `toggle-float` command.
- `"floating_layer_placement"`: the placement to be used by a floating
  window when it is spawned on the floating layer and the user has the
  floating layer behaviour set to float.
- `"floating_override_placement"`: the placement to be used by a window
  that is spawned when float override is active.
- `"float_rule_placement"`: the placement to be used by a window that
  matches a 'floating_applications' rule.

Each `Placement` can be one of the following types:

- "None": windows are spawned wherever Windows positions them with
  whatever size they had. Komorebi does not change its size or position.
- "Center": windows are centered without changing their size.
- "CenterAndResize": windows are centered and resized according to the
defined aspect ratio.

By default the placements are as follows:
- `"toggle_float_placement"`: `"CenterAndResize"`
- `"floating_layer_placement"`: `"Center"`
- `"floating_override_placement"`: `"None"`
- `"float_rule_placement"`: `"None"`

This commit also adds the `floating_layer_behaviour` as a global config.
2025-04-20 10:25:57 -07:00
alex-ds13
c408c1149c fix(wm): fix eager focus on hidden stacked window
When using the eager focus command to focus a window that was hidden on
a stack on an unfocused workspace it would load the workspace focus the
correct window but keep it cloaked with the previously focused window
showing. This would happen because we were focusing the workspace before
focusing the window which would create two window focus events, the
first one for the previously focused window and the second one for the
target window we wanted. The problem was that when the first event was
handled it would again refocus that window and cloak the target window
again so when the target window focus event came it would ignore it
since the `should_manage` function would return `false` because the
window was cloaked and had all its window styles as `None`, unless we
had transparency enabled, in that case it would override it and create a
focus loop.

This commit fixes this by not loading the newly focused workspace
immediately. Instead we first focus the workspace if it is needed
without loading it and mark it as needing to be loaded. Then we focus
the correct target window and only then do we load the workspace. This
way the workspace loads with the correct window already focused.

This is the same approach that is currently being done on the
`perform_reconciliation` function when there is an alt-tab.
2025-04-17 07:57:45 -07:00
LGUG2Z
a8b02f40fd chore(dev): begin 0.1.37-dev 2025-04-13 09:38:12 -07:00
LGUG2Z
6608e5a5bb docs(schema): update schema.json 2025-04-13 09:37:13 -07:00
LGUG2Z
8ef1bcf26e chore(release): v0.1.36 2025-04-12 10:52:31 -07:00
LGUG2Z
d146f35c25 chore(deps): cargo update 2025-04-12 10:52:31 -07:00
dependabot[bot]
fc07ba3dd9 chore(deps): bump crossbeam-channel from 0.5.14 to 0.5.15
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.14 to 0.5.15.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.14...crossbeam-channel-0.5.15)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-version: 0.5.15
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-10 09:54:12 -07:00
LGUG2Z
3a8a61119d fix(config): update monitor wallpaper on reload 2025-04-09 16:09:17 -07:00
LGUG2Z
d24beb60b1 feat(config): add per-monitor floating layer behaviour opt
This commit adds an option to set the floating layer behaviour for all
workspaces on a monitor.

Overrides set on an individual workspace level will take precedence over
the option set at the monitor level.
2025-04-09 09:42:46 -07:00
Jerry Kingsbury
7daf3242e2 test(wm): add float and lock toggle tests
Created a test for the toggle_lock function. The test creates a
workspace with multiple containers and checks to see whether the
container was added or removed from the locked containers list when
calling the toggle_lock function.

Created a test for the float_window function. The test checks to ensure
that when calling the float_window function, the window is added to the
floating_windows list and removed from the containers window list. The
test will also check the count and ensure the expected window was added.
2025-04-09 08:55:10 -07:00
LGUG2Z
b6e261aef6 fix(bar): avoid retile messages on ws switch
This commit removes RetileWithResizeDimensions messages from the batches
that are sent to komorebi when changing workspace.

I'm not really sure why this was added in the first place, but removing
it doesn't seem to impact layouts on workspace switch, and more
important, by removing this message I'm no longer able to reproduce the
sudden exits of komorebi.exe under sustained workspace switching calls
made via the bar.
2025-04-08 17:20:02 -07:00
LGUG2Z
d40c304324 fix(borders): avoid deadlock on state hashmaps
This commit addresses a deadlock on WINDOW_BORDERS which can occur under
load, particularly when switching workspaces.

When switching workspaces using the komorebi-bar,
RetileWithResizeDimensions is also called, which calls
border_manager::destroy_all_borders.

At the same time, border_manager::window_border is called when hiding
borders from the previous workspace. Both of these functions try to take
locks on WINDOWS_BORDERS and BORDER_STATE.

border_manager::window_border is called in a new thread by hide_border,
so if this has not finished with the lock by the time
destroy_all_borders requests it, we get stuck in a deadlock.

The changes in this commit ensure that the BORDER_STATE lock is dropped
as early as possible in destroy_all_borders, and that we are not holding
the WINDOWS_BORDERS lock in window_border while trying to get the
BORDER_STATE lock to look up BorderInfo.

The logs which show the initial deadlock being detected:

2025-04-08T22:49:37.641888Z  WARN komorebi::process_command: could not acquire window manager lock, not processing message: FocusWorkspaceNumber
2025-04-08T22:49:38.294952Z  WARN komorebi::process_command: could not acquire window manager lock, not processing message: FocusWorkspaceNumber
2025-04-08T22:49:39.225645Z ERROR komorebi: 1 deadlocks detected
2025-04-08T22:49:39.225826Z ERROR komorebi: deadlock #0
2025-04-08T22:49:39.225950Z ERROR komorebi: thread id: 9896
2025-04-08T22:49:39.226072Z ERROR komorebi:    0:     0x7ff68fd33dec - backtrace::backtrace::dbghelp64::trace
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\dbghelp64.rs:99
                           backtrace::backtrace::trace_unsynchronized<backtrace::capture::impl$1::create::closure_env$0>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:66
   1:     0x7ff68fd33c87 - backtrace::backtrace::trace<backtrace::capture::impl$1::create::closure_env$0>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:53
   2:     0x7ff68fd3c03e - backtrace::capture::Backtrace::create
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:193
   3:     0x7ff68fd3bfae - backtrace::capture::Backtrace::new
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:158
   4:     0x7ff68f937b54 - parking_lot_core::parking_lot::deadlock_impl::on_unpark
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1211
   5:     0x7ff68f921f0e - parking_lot_core::parking_lot::deadlock::on_unpark
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1144
   6:     0x7ff68f92bf88 - parking_lot_core::parking_lot::park::closure$0<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:637
   7:     0x7ff68f92a777 - parking_lot_core::parking_lot::with_thread_data
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:207
                           parking_lot_core::parking_lot::park<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:600
   8:     0x7ff68f926fa0 - parking_lot::raw_mutex::RawMutex::lock_slow
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:262
   9:     0x7ff68f1daac6 - parking_lot::raw_mutex::impl$0::lock
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:72
  10:     0x7ff68ef05eb3 - lock_api::mutex::Mutex<parking_lot::raw_mutex::RawMutex,std::collections::hash::map::HashMap<isize,alloc::string::String,std::hash::random::RandomState> >::lock<parking_lot::raw_mutex::RawMutex,std::collections::hash::map::HashMap<isize,alloc::string::Str
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lock_api-0.4.12\src\mutex.rs:223
  11:     0x7ff68ef0713d - komorebi::border_manager::destroy_all_borders
                               at komorebi\src\border_manager\mod.rs:139
  12:     0x7ff68f194e61 - komorebi::window_manager::WindowManager::process_command<ref_mut$<uds_windows::stdnet::net::UnixStream> >
                               at komorebi\src\process_command.rs:918
  13:     0x7ff68ef1fdcf - komorebi::process_command::read_commands_uds
                               at komorebi\src\process_command.rs:2292
  14:     0x7ff68f231eb5 - komorebi::process_command::listen_for_commands::closure$0::closure$0::closure$0
                               at komorebi\src\process_command.rs:123
  15:     0x7ff68f32bcf3 - core::hint::black_box
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\hint.rs:477
                           std::sys::backtrace::__rust_begin_short_backtrace<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\backtrace.rs:152
  16:     0x7ff68f00d1b4 - std::thread::impl$0::spawn_unchecked_::closure$1::closure$0<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\thread\mod.rs:559
  17:     0x7ff68f356ea1 - core::panic::unwind_safe::impl$25::call_once<tuple$<>,std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> > >
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\panic\unwind_safe.rs:272
  18:     0x7ff68f1d1e00 - std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> > >,tuple$<> >
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:587
  19:     0x7ff68f0102b3 - std::thread::impl$7::drop::closure$0<enum2$<core::result::Result<tuple$<>,eyre::Report> > >
  20:     0x7ff68f007be7 - std::panicking::try
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:550
                           std::panic::catch_unwind
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:358
                           std::thread::impl$0::spawn_unchecked_::closure$1<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\thread\mod.rs:557
  21:     0x7ff68ecfeb8e - core::ops::function::FnOnce::call_once<std::thread::impl$0::spawn_unchecked_::closure_env$1<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >,tuple$<> >
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:250
  22:     0x7ff68fe84f1d - alloc::boxed::impl$28::call_once
                               at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\alloc\src\boxed.rs:1976
                           alloc::boxed::impl$28::call_once
                               at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\alloc\src\boxed.rs:1976
                           std::sys::pal::windows::thread::impl$0::new::thread_start
                               at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\pal\windows\thread.rs:56
  23:     0x7ff8ef27257d - BaseThreadInitThunk
  24:     0x7ff8f042af28 - RtlUserThreadStart

2025-04-08T22:49:39.228617Z ERROR komorebi: thread id: 62364
2025-04-08T22:49:39.228731Z ERROR komorebi:    0:     0x7ff68fd33dec - backtrace::backtrace::dbghelp64::trace
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\dbghelp64.rs:99
                           backtrace::backtrace::trace_unsynchronized<backtrace::capture::impl$1::create::closure_env$0>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:66
   1:     0x7ff68fd33c87 - backtrace::backtrace::trace<backtrace::capture::impl$1::create::closure_env$0>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:53
   2:     0x7ff68fd3c03e - backtrace::capture::Backtrace::create
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:193
   3:     0x7ff68fd3bfae - backtrace::capture::Backtrace::new
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:158
   4:     0x7ff68f937b54 - parking_lot_core::parking_lot::deadlock_impl::on_unpark
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1211
   5:     0x7ff68f921f0e - parking_lot_core::parking_lot::deadlock::on_unpark
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1144
   6:     0x7ff68f92bf88 - parking_lot_core::parking_lot::park::closure$0<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:637
   7:     0x7ff68f92a777 - parking_lot_core::parking_lot::with_thread_data
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:207
                           parking_lot_core::parking_lot::park<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:600
   8:     0x7ff68f926fa0 - parking_lot::raw_mutex::RawMutex::lock_slow
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:262
   9:     0x7ff68f1daac6 - parking_lot::raw_mutex::impl$0::lock
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:72
  10:     0x7ff68ef05d93 - lock_api::mutex::Mutex<parking_lot::raw_mutex::RawMutex,std::collections::hash::map::HashMap<alloc::string::String,alloc::boxed::Box<komorebi::border_manager::border::Border,alloc::alloc::Global>,std::hash::random::RandomState> >::lock<parking_lot::raw_mu
                               at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lock_api-0.4.12\src\mutex.rs:223
  11:     0x7ff68f2064de - komorebi::border_manager::window_border::closure$0
                               at komorebi\src\border_manager\mod.rs:109
  12:     0x7ff68eddeca9 - enum2$<core::option::Option<ref$<alloc::string::String> > >::and_then<ref$<alloc::string::String>,komorebi::border_manager::BorderInfo,komorebi::border_manager::window_border::closure_env$0>
                               at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:1452
  13:     0x7ff68ef06339 - komorebi::border_manager::window_border
                               at komorebi\src\border_manager\mod.rs:108
2025-04-08 16:14:41 -07:00
LGUG2Z
69d252ba12 feat(wm): drop empty containers on ws update
We shouldn't ever have empty containers, but never say never because
someone on the Discord has an empty container with no Windows that
continues to take up a tile. This commit adds a call to drop all
containers without any windows whenever Workspace::update is called.
2025-04-07 15:28:29 -07:00
LGUG2Z
2ac477d89f docs(mkdocs): reduce number of tabs to improve nav 2025-04-07 11:02:57 -07:00
47 changed files with 2894 additions and 578 deletions

268
Cargo.lock generated
View File

@@ -180,6 +180,12 @@ dependencies = [
"alloc-no-stdlib",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android-activity"
version = "0.6.0"
@@ -274,9 +280,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.97"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "approx"
@@ -302,11 +308,11 @@ dependencies = [
"clipboard-win",
"image 0.25.6",
"log",
"objc2 0.6.0",
"objc2-app-kit 0.3.0",
"objc2 0.6.1",
"objc2-app-kit 0.3.1",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation 0.3.0",
"objc2-foundation 0.3.1",
"parking_lot",
"percent-encoding",
"windows-sys 0.59.0",
@@ -844,9 +850,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.18"
version = "1.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
dependencies = [
"jobserver",
"libc",
@@ -933,10 +939,20 @@ dependencies = [
]
[[package]]
name = "clap"
version = "4.5.35"
name = "chumsky"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9"
dependencies = [
"hashbrown 0.14.5",
"stacker",
]
[[package]]
name = "clap"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
dependencies = [
"clap_builder",
"clap_derive",
@@ -944,9 +960,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.35"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
dependencies = [
"anstream",
"anstyle",
@@ -1183,9 +1199,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.14"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
@@ -1368,6 +1384,16 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dispatch2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.1",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
@@ -1739,7 +1765,7 @@ dependencies = [
"bit_field",
"half",
"lebe",
"miniz_oxide 0.8.7",
"miniz_oxide 0.8.8",
"rayon-core",
"smallvec",
"zune-inflate",
@@ -1804,7 +1830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"miniz_oxide 0.8.7",
"miniz_oxide 0.8.8",
]
[[package]]
@@ -2277,9 +2303,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.4.8"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
dependencies = [
"atomic-waker",
"bytes",
@@ -2296,9 +2322,9 @@ dependencies = [
[[package]]
name = "half"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
dependencies = [
"cfg-if 1.0.0",
"crunchy",
@@ -2310,6 +2336,16 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
@@ -2909,7 +2945,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "komorebi"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"bitflags 2.9.0",
"clap",
@@ -2939,7 +2975,7 @@ dependencies = [
"serde_yaml 0.9.34+deprecated",
"shadow-rs",
"strum 0.27.1",
"sysinfo",
"sysinfo 0.34.2",
"tracing",
"tracing-appender",
"tracing-subscriber",
@@ -2958,7 +2994,7 @@ dependencies = [
[[package]]
name = "komorebi-bar"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"chrono",
"chrono-tz",
@@ -2985,9 +3021,10 @@ dependencies = [
"serde",
"serde_json_lenient",
"starship-battery",
"sysinfo",
"sysinfo 0.34.2",
"tracing",
"tracing-subscriber",
"which",
"windows 0.61.1",
"windows-core 0.61.0",
"windows-icons 0.1.0 (git+https://github.com/LGUG2Z/windows-icons?rev=0c9d7ee1b807347c507d3a9862dd007b4d3f4354)",
@@ -2996,7 +3033,7 @@ dependencies = [
[[package]]
name = "komorebi-client"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"komorebi",
"serde_json_lenient",
@@ -3005,7 +3042,7 @@ dependencies = [
[[package]]
name = "komorebi-gui"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"eframe",
"egui_extras",
@@ -3016,9 +3053,19 @@ dependencies = [
"windows-core 0.61.0",
]
[[package]]
name = "komorebi-shortcuts"
version = "0.1.0"
dependencies = [
"dirs 6.0.0",
"eframe",
"whkd-core",
"whkd-parser",
]
[[package]]
name = "komorebi-themes"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"base16-egui-themes",
"catppuccin-egui",
@@ -3033,7 +3080,7 @@ dependencies = [
[[package]]
name = "komorebic"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"chrono",
"clap",
@@ -3051,7 +3098,7 @@ dependencies = [
"serde",
"serde_json_lenient",
"shadow-rs",
"sysinfo",
"sysinfo 0.34.2",
"thiserror 2.0.12",
"which",
"windows 0.61.1",
@@ -3059,7 +3106,7 @@ dependencies = [
[[package]]
name = "komorebic-no-console"
version = "0.1.36"
version = "0.1.37"
[[package]]
name = "kqueue"
@@ -3101,9 +3148,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libfuzzer-sys"
@@ -3174,9 +3221,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litemap"
@@ -3326,9 +3373,9 @@ dependencies = [
[[package]]
name = "miette"
version = "7.5.0"
version = "7.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484"
checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7"
dependencies = [
"backtrace",
"backtrace-ext",
@@ -3340,15 +3387,14 @@ dependencies = [
"supports-unicode",
"terminal_size",
"textwrap",
"thiserror 1.0.69",
"unicode-width 0.1.14",
]
[[package]]
name = "miette-derive"
version = "7.5.0"
version = "7.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147"
checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
dependencies = [
"proc-macro2",
"quote",
@@ -3409,9 +3455,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
"simd-adler32",
@@ -3549,9 +3595,9 @@ dependencies = [
[[package]]
name = "netdev"
version = "0.33.0"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccc812280a9201cb442e008d63d90933612ca7df8c0d4b49cc1825b383ba0add"
checksum = "1f2cc40be8e7967f3f90b0cd9de6885772468b576c122b91054517e1ff526b8d"
dependencies = [
"dlopen2",
"ipnet",
@@ -3577,9 +3623,9 @@ dependencies = [
[[package]]
name = "netlink-packet-route"
version = "0.21.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "483325d4bfef65699214858f097d504eb812c38ce7077d165f301ec406c3066e"
checksum = "fc0e7987b28514adf555dc1f9a5c30dfc3e50750bbaffb1aec41ca7b23dcd8e4"
dependencies = [
"anyhow",
"bitflags 2.9.0",
@@ -3863,9 +3909,9 @@ dependencies = [
[[package]]
name = "objc2"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59"
checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551"
dependencies = [
"objc2-encode",
]
@@ -3888,14 +3934,14 @@ dependencies = [
[[package]]
name = "objc2-app-kit"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb"
checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.0",
"objc2 0.6.1",
"objc2-core-graphics",
"objc2-foundation 0.3.0",
"objc2-foundation 0.3.1",
]
[[package]]
@@ -3936,22 +3982,24 @@ dependencies = [
[[package]]
name = "objc2-core-foundation"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.0",
"dispatch2",
"objc2 0.6.1",
]
[[package]]
name = "objc2-core-graphics"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02"
checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.0",
"dispatch2",
"objc2 0.6.1",
"objc2-core-foundation",
"objc2-io-surface",
]
@@ -4001,23 +4049,23 @@ dependencies = [
[[package]]
name = "objc2-foundation"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998"
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.0",
"objc2 0.6.1",
"objc2-core-foundation",
]
[[package]]
name = "objc2-io-surface"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19"
checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.0",
"objc2 0.6.1",
"objc2-core-foundation",
]
@@ -4507,7 +4555,7 @@ dependencies = [
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide 0.8.7",
"miniz_oxide 0.8.8",
]
[[package]]
@@ -4579,9 +4627,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
@@ -4605,6 +4653,15 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "psm"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f"
dependencies = [
"cc",
]
[[package]]
name = "qoi"
version = "0.4.1"
@@ -4807,9 +4864,9 @@ dependencies = [
[[package]]
name = "ravif"
version = "0.11.11"
version = "0.11.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6"
checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6"
dependencies = [
"avif-serialize",
"imgref",
@@ -5044,15 +5101,15 @@ dependencies = [
"bitflags 2.9.0",
"errno",
"libc",
"linux-raw-sys 0.9.3",
"linux-raw-sys 0.9.4",
"windows-sys 0.59.0",
]
[[package]]
name = "rustls"
version = "0.23.25"
version = "0.23.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
dependencies = [
"once_cell",
"rustls-pki-types",
@@ -5424,9 +5481,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
dependencies = [
"libc",
]
@@ -5552,6 +5609,19 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "stacker"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b"
dependencies = [
"cc",
"cfg-if 1.0.0",
"libc",
"psm",
"windows-sys 0.52.0",
]
[[package]]
name = "starship-battery"
version = "0.10.1"
@@ -5715,6 +5785,19 @@ dependencies = [
"windows 0.57.0",
]
[[package]]
name = "sysinfo"
version = "0.34.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2"
dependencies = [
"libc",
"memchr",
"ntapi",
"objc2-core-foundation",
"windows 0.57.0",
]
[[package]]
name = "system-configuration"
version = "0.6.1"
@@ -6194,9 +6277,9 @@ dependencies = [
[[package]]
name = "tzdb_data"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0604b35c1f390a774fdb138cac75a99981078895d24bcab175987440bbff803b"
checksum = "9c4c81d75033770e40fbd3643ce7472a1a9fd301f90b7139038228daf8af03ec"
dependencies = [
"tz-rs",
]
@@ -6600,8 +6683,8 @@ dependencies = [
"jni",
"log",
"ndk-context",
"objc2 0.6.0",
"objc2-foundation 0.3.0",
"objc2 0.6.1",
"objc2-foundation 0.3.1",
"url",
"web-sys",
]
@@ -6717,16 +6800,31 @@ dependencies = [
[[package]]
name = "which"
version = "7.0.2"
version = "7.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
dependencies = [
"either",
"env_home",
"rustix 0.38.44",
"rustix 1.0.5",
"winsafe",
]
[[package]]
name = "whkd-core"
version = "0.2.9"
source = "git+https://github.com/LGUG2Z/whkd?rev=29df24ff2dd715655b0366bd2a598837c699a8e9#29df24ff2dd715655b0366bd2a598837c699a8e9"
[[package]]
name = "whkd-parser"
version = "0.2.9"
source = "git+https://github.com/LGUG2Z/whkd?rev=29df24ff2dd715655b0366bd2a598837c699a8e9#29df24ff2dd715655b0366bd2a598837c699a8e9"
dependencies = [
"chumsky",
"thiserror 2.0.12",
"whkd-core",
]
[[package]]
name = "win32-display-data"
version = "0.1.0"
@@ -6915,7 +7013,7 @@ dependencies = [
"image 0.25.6",
"regex",
"roxmltree",
"sysinfo",
"sysinfo 0.33.1",
"winapi",
"windows 0.58.0",
]
@@ -7432,9 +7530,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.7.4"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
dependencies = [
"memchr",
]
@@ -7569,9 +7667,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
[[package]]
name = "xml-rs"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
[[package]]
name = "yaml-rust"

View File

@@ -8,7 +8,8 @@ members = [
"komorebic",
"komorebic-no-console",
"komorebi-bar",
"komorebi-themes"
"komorebi-themes",
"komorebi-shortcuts"
]
[workspace.dependencies]
@@ -33,7 +34,7 @@ tracing = "0.1"
tracing-appender = "0.2"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
paste = "1"
sysinfo = "0.33"
sysinfo = "0.34"
uds_windows = "1"
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "a28c6559a9de2f92c142a714947a9b081776caca" }
windows-numerics = { version = "0.2" }
@@ -72,4 +73,4 @@ features = [
"Win32_System_WindowsProgramming",
"Media",
"Media_Control"
]
]

View File

@@ -394,7 +394,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c
Below is a simple example of how to use `komorebi-client` in a basic Rust application.
```rust
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.35"}
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.36"}
use anyhow::Result;
use komorebi_client::Notification;

View File

@@ -34,43 +34,58 @@ allow = [
"Ubuntu-font-1.0",
"Unicode-3.0",
"Zlib",
"LicenseRef-Komorebi-1.0"
"LicenseRef-Komorebi-2.0"
]
confidence-threshold = 0.8
[[licenses.clarify]]
crate = "komorebi"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebi-client"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebic"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebic-no-console"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebi-themes"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebi-gui"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebi-bar"
expression = "LicenseRef-Komorebi-1.0"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebi-shortcuts"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "whkd-core"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "whkd-parser"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
@@ -96,4 +111,5 @@ allow-git = [
"https://github.com/LGUG2Z/win32-display-data",
"https://github.com/LGUG2Z/flavours",
"https://github.com/LGUG2Z/base16_color_scheme",
"https://github.com/LGUG2Z/whkd",
]

View File

@@ -3,8 +3,9 @@
[
"0BSD",
[
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"win32-display-data 0.1.0 git+https://github.com/LGUG2Z/win32-display-data?rev=55cebdebfbd68dbd14945a1ba90f6b05b7be2893"
"win32-display-data 0.1.0 git+https://github.com/LGUG2Z/win32-display-data?rev=a28c6559a9de2f92c142a714947a9b081776caca"
]
],
[
@@ -16,74 +17,85 @@
"accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_winit 0.23.1 registry+https://github.com/rust-lang/crates.io-index",
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index",
"allocator-api2 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
"anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index",
"anstyle 1.0.10 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-parse 0.2.6 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index",
"anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index",
"arboard 3.4.1 registry+https://github.com/rust-lang/crates.io-index",
"anyhow 1.0.98 registry+https://github.com/rust-lang/crates.io-index",
"approx 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"arboard 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
"backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index",
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
"bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
"cc 1.2.16 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
"cc 1.2.19 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index",
"clap 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"clap_builder 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"clap_derive 4.5.28 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"clap 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
"clap_builder 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
"color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index",
"color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-channel 0.5.14 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-channel 0.5.15 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
"ctrlc 3.4.5 registry+https://github.com/rust-lang/crates.io-index",
"ctrlc 3.4.6 registry+https://github.com/rust-lang/crates.io-index",
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"deranged 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"deranged 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 3.0.2 registry+https://github.com/rust-lang/crates.io-index",
"dirs 4.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
"dpi 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
"ecolor 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"eframe 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-winit 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_extras 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_glow 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"either 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"emath 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-winit 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui_extras 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui_glow 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"either 1.15.0 registry+https://github.com/rust-lang/crates.io-index",
"emath 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index",
"enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index",
"enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index",
"env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index",
"fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index",
"fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index",
"flate2 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"flate2 1.1.1 registry+https://github.com/rust-lang/crates.io-index",
"fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index",
"form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
"futures 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
@@ -95,53 +107,67 @@
"futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
"git2 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"git2 0.20.1 registry+https://github.com/rust-lang/crates.io-index",
"gl_generator 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
"glutin 0.32.2 registry+https://github.com/rust-lang/crates.io-index",
"glutin_egl_sys 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"glutin_wgl_sys 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
"half 2.4.1 registry+https://github.com/rust-lang/crates.io-index",
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.14.5 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
"hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"http 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"http 1.3.1 registry+https://github.com/rust-lang/crates.io-index",
"httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
"hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"iana-time-zone 0.1.61 registry+https://github.com/rust-lang/crates.io-index",
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"image 0.25.5 registry+https://github.com/rust-lang/crates.io-index",
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
"immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index",
"indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 2.7.1 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
"ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
"is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
"itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
"jobserver 0.1.32 registry+https://github.com/rust-lang/crates.io-index",
"jobserver 0.1.33 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.1.22 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"khronos_api 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
"lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"libc 0.2.170 registry+https://github.com/rust-lang/crates.io-index",
"libgit2-sys 0.18.0+1.9.0 registry+https://github.com/rust-lang/crates.io-index",
"libz-sys 1.1.21 registry+https://github.com/rust-lang/crates.io-index",
"libc 0.2.172 registry+https://github.com/rust-lang/crates.io-index",
"libgit2-sys 0.18.1+1.9.0 registry+https://github.com/rust-lang/crates.io-index",
"libz-sys 1.1.22 registry+https://github.com/rust-lang/crates.io-index",
"linked-hash-map 0.5.6 registry+https://github.com/rust-lang/crates.io-index",
"litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"log 0.4.26 registry+https://github.com/rust-lang/crates.io-index",
"miette 7.5.0 registry+https://github.com/rust-lang/crates.io-index",
"miette-derive 7.5.0 registry+https://github.com/rust-lang/crates.io-index",
"log 0.4.27 registry+https://github.com/rust-lang/crates.io-index",
"logos 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-codegen 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-derive 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"miette 7.6.0 registry+https://github.com/rust-lang/crates.io-index",
"miette-derive 7.6.0 registry+https://github.com/rust-lang/crates.io-index",
"mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index",
"minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
"miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index",
"net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index",
@@ -154,10 +180,13 @@
"num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index",
"num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index",
"once_cell 1.20.3 registry+https://github.com/rust-lang/crates.io-index",
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index",
"owned_ttf_parser 0.25.0 registry+https://github.com/rust-lang/crates.io-index",
"palette 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"palette_derive 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index",
"paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
@@ -165,20 +194,26 @@
"pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index",
"pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index",
"png 0.16.8 registry+https://github.com/rust-lang/crates.io-index",
"png 0.17.16 registry+https://github.com/rust-lang/crates.io-index",
"powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"ppv-lite86 0.2.20 registry+https://github.com/rust-lang/crates.io-index",
"ppv-lite86 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro2 1.0.95 registry+https://github.com/rust-lang/crates.io-index",
"profiling 1.0.16 registry+https://github.com/rust-lang/crates.io-index",
"profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index",
"psm 0.1.26 registry+https://github.com/rust-lang/crates.io-index",
"qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"quote 1.0.39 registry+https://github.com/rust-lang/crates.io-index",
"quote 1.0.40 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.7.3 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.5.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
"rand_pcg 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
"rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index",
"rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index",
@@ -186,46 +221,58 @@
"regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"reqwest 0.12.12 registry+https://github.com/rust-lang/crates.io-index",
"reqwest 0.12.15 registry+https://github.com/rust-lang/crates.io-index",
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
"rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
"ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
"scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"serde 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index",
"serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index",
"serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
"serde_with 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_with_macros 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index",
"shadow-rs 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"shadow-rs 1.1.1 registry+https://github.com/rust-lang/crates.io-index",
"shell-words 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"shellexpand 2.1.2 registry+https://github.com/rust-lang/crates.io-index",
"shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index",
"smallvec 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"smallvec 1.15.0 registry+https://github.com/rust-lang/crates.io-index",
"smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"socket2 0.5.8 registry+https://github.com/rust-lang/crates.io-index",
"socket2 0.5.9 registry+https://github.com/rust-lang/crates.io-index",
"stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"stacker 0.1.21 registry+https://github.com/rust-lang/crates.io-index",
"static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"supports-color 3.0.2 registry+https://github.com/rust-lang/crates.io-index",
"supports-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
"supports-unicode 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
"syn 2.0.99 registry+https://github.com/rust-lang/crates.io-index",
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
"syn 2.0.100 registry+https://github.com/rust-lang/crates.io-index",
"sync_wrapper 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"tempfile 3.17.1 registry+https://github.com/rust-lang/crates.io-index",
"terminal_size 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"tempfile 3.19.1 registry+https://github.com/rust-lang/crates.io-index",
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index",
"time 0.3.37 registry+https://github.com/rust-lang/crates.io-index",
"time-core 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"time 0.3.41 registry+https://github.com/rust-lang/crates.io-index",
"time-core 0.1.4 registry+https://github.com/rust-lang/crates.io-index",
"toml 0.5.11 registry+https://github.com/rust-lang/crates.io-index",
"ttf-parser 0.25.1 registry+https://github.com/rust-lang/crates.io-index",
"typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index",
"tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index",
"tzdb 0.7.2 registry+https://github.com/rust-lang/crates.io-index",
"tzdb_data 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"unicase 2.8.1 registry+https://github.com/rust-lang/crates.io-index",
"unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index",
"unicode-linebreak 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
@@ -241,48 +288,59 @@
"vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
"version_check 0.9.5 registry+https://github.com/rust-lang/crates.io-index",
"web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"webbrowser 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"webbrowser 1.0.4 registry+https://github.com/rust-lang/crates.io-index",
"weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index",
"winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.61.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-link 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.59.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-link 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-registry 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"winit 0.30.9 registry+https://github.com/rust-lang/crates.io-index",
"wmi 0.15.1 registry+https://github.com/rust-lang/crates.io-index",
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
"write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"yaml-rust 0.4.5 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index",
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
@@ -302,7 +360,7 @@
"rav1e 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"v_frame 0.3.8 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index"
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
@@ -316,7 +374,7 @@
"encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index",
"exr 1.73.0 registry+https://github.com/rust-lang/crates.io-index",
"lebe 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"ravif 0.11.11 registry+https://github.com/rust-lang/crates.io-index"
"ravif 0.11.12 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
@@ -343,7 +401,7 @@
"is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"libloading 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
"starship-battery 0.10.0 registry+https://github.com/rust-lang/crates.io-index"
"starship-battery 0.10.1 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
@@ -352,24 +410,28 @@
"accesskit 0.17.1 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index",
"aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index",
"aligned-vec 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"allocator-api2 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
"anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index",
"anstyle 1.0.10 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-parse 0.2.6 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index",
"anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index",
"arboard 3.4.1 registry+https://github.com/rust-lang/crates.io-index",
"anyhow 1.0.98 registry+https://github.com/rust-lang/crates.io-index",
"arboard 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
"arg_enum_proc_macro 0.3.4 registry+https://github.com/rust-lang/crates.io-index",
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
"backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index",
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
@@ -378,58 +440,72 @@
"brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index",
"built 0.7.7 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
"byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"bytes 1.10.0 registry+https://github.com/rust-lang/crates.io-index",
"bytes 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
"calm_io 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"calmio_filters 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"catppuccin-egui 5.3.1 git+https://github.com/LGUG2Z/catppuccin-egui?rev=bdaff30959512c4f7ee7304117076a48633d777f",
"cc 1.2.16 registry+https://github.com/rust-lang/crates.io-index",
"cc 1.2.19 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"cfg_aliases 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index",
"clap 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"clap_builder 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"clap_derive 4.5.28 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"chumsky 0.9.3 registry+https://github.com/rust-lang/crates.io-index",
"clap 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
"clap_builder 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
"color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index",
"color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"color-thief 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"color_quant 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-channel 0.5.14 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-channel 0.5.15 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
"ctrlc 3.4.5 registry+https://github.com/rust-lang/crates.io-index",
"ctrlc 3.4.6 registry+https://github.com/rust-lang/crates.io-index",
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"deranged 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"darling 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
"darling_core 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
"darling_macro 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"deranged 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 3.0.2 registry+https://github.com/rust-lang/crates.io-index",
"dirs 4.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
"ecolor 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"eframe 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-winit 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_extras 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_glow 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"either 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"emath 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-winit 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui_extras 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"egui_glow 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"either 1.15.0 registry+https://github.com/rust-lang/crates.io-index",
"emath 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index",
"enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index",
"enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index",
"env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
"equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index",
"fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index",
"fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index",
"flate2 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"flate2 1.1.1 registry+https://github.com/rust-lang/crates.io-index",
"flavours 0.7.2 git+https://github.com/LGUG2Z/flavours",
"fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index",
"font-loader 0.11.0 registry+https://github.com/rust-lang/crates.io-index",
"form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
@@ -443,64 +519,80 @@
"futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"getset 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
"git2 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"git2 0.20.1 registry+https://github.com/rust-lang/crates.io-index",
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
"glutin-winit 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"h2 0.4.8 registry+https://github.com/rust-lang/crates.io-index",
"half 2.4.1 registry+https://github.com/rust-lang/crates.io-index",
"h2 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.14.5 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
"hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"http 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"http 1.3.1 registry+https://github.com/rust-lang/crates.io-index",
"http-body 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"http-body-util 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"http-body-util 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
"httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
"hyper 1.6.0 registry+https://github.com/rust-lang/crates.io-index",
"hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"hyper-util 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
"iana-time-zone 0.1.61 registry+https://github.com/rust-lang/crates.io-index",
"hyper-util 0.1.11 registry+https://github.com/rust-lang/crates.io-index",
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"image 0.25.5 registry+https://github.com/rust-lang/crates.io-index",
"image 0.23.14 registry+https://github.com/rust-lang/crates.io-index",
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index",
"indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 2.7.1 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
"ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
"is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
"itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
"jobserver 0.1.32 registry+https://github.com/rust-lang/crates.io-index",
"jobserver 0.1.33 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.1.22 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"libc 0.2.170 registry+https://github.com/rust-lang/crates.io-index",
"libgit2-sys 0.18.0+1.9.0 registry+https://github.com/rust-lang/crates.io-index",
"libz-sys 1.1.21 registry+https://github.com/rust-lang/crates.io-index",
"libc 0.2.172 registry+https://github.com/rust-lang/crates.io-index",
"libgit2-sys 0.18.1+1.9.0 registry+https://github.com/rust-lang/crates.io-index",
"libz-sys 1.1.22 registry+https://github.com/rust-lang/crates.io-index",
"linked-hash-map 0.5.6 registry+https://github.com/rust-lang/crates.io-index",
"litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"log 0.4.26 registry+https://github.com/rust-lang/crates.io-index",
"log 0.4.27 registry+https://github.com/rust-lang/crates.io-index",
"logos 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-codegen 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-derive 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"loop9 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
"matchers 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"maybe-rayon 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index",
"memoffset 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
"mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index",
"mime_guess2 2.0.5 registry+https://github.com/rust-lang/crates.io-index",
"mime_guess2 2.3.0 registry+https://github.com/rust-lang/crates.io-index",
"minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
"mio 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"nanoid 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index",
"net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index",
"netdev 0.32.0 registry+https://github.com/rust-lang/crates.io-index",
"netdev 0.34.0 registry+https://github.com/rust-lang/crates.io-index",
"new_debug_unreachable 1.0.6 registry+https://github.com/rust-lang/crates.io-index",
"nohash-hasher 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"nom 7.1.3 registry+https://github.com/rust-lang/crates.io-index",
@@ -514,36 +606,54 @@
"num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index",
"num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index",
"once_cell 1.20.3 registry+https://github.com/rust-lang/crates.io-index",
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index",
"os_info 3.10.0 registry+https://github.com/rust-lang/crates.io-index",
"overload 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"owo-colors 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
"owo-colors 4.2.0 registry+https://github.com/rust-lang/crates.io-index",
"palette 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"palette_derive 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index",
"parse-zoneinfo 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
"percent-encoding 2.3.1 registry+https://github.com/rust-lang/crates.io-index",
"phf 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"phf_codegen 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf_codegen 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"phf_generator 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf_generator 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"phf_shared 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf_shared 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index",
"pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index",
"png 0.16.8 registry+https://github.com/rust-lang/crates.io-index",
"png 0.17.16 registry+https://github.com/rust-lang/crates.io-index",
"powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"powershell_script 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"ppv-lite86 0.2.20 registry+https://github.com/rust-lang/crates.io-index",
"ppv-lite86 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro2 1.0.95 registry+https://github.com/rust-lang/crates.io-index",
"profiling 1.0.16 registry+https://github.com/rust-lang/crates.io-index",
"profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index",
"psm 0.1.26 registry+https://github.com/rust-lang/crates.io-index",
"qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"quote 1.0.39 registry+https://github.com/rust-lang/crates.io-index",
"quote 1.0.40 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.7.3 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.5.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
"random_word 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
"rand_pcg 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"random_word 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
"rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index",
"rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index",
@@ -552,8 +662,9 @@
"regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"reqwest 0.12.12 registry+https://github.com/rust-lang/crates.io-index",
"reqwest 0.12.15 registry+https://github.com/rust-lang/crates.io-index",
"rgb 0.8.50 registry+https://github.com/rust-lang/crates.io-index",
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
@@ -562,46 +673,59 @@
"schannel 0.1.27 registry+https://github.com/rust-lang/crates.io-index",
"schemars 0.8.22 registry+https://github.com/rust-lang/crates.io-index",
"schemars_derive 0.8.22 registry+https://github.com/rust-lang/crates.io-index",
"scoped_threadpool 0.1.9 registry+https://github.com/rust-lang/crates.io-index",
"scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"serde 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index",
"serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index",
"serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
"serde_with 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_with_macros 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index",
"shadow-rs 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"shadow-rs 1.1.1 registry+https://github.com/rust-lang/crates.io-index",
"sharded-slab 0.1.7 registry+https://github.com/rust-lang/crates.io-index",
"shell-words 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"shellexpand 2.1.2 registry+https://github.com/rust-lang/crates.io-index",
"shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index",
"simd-adler32 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"simd_helpers 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"slab 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"smallvec 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"smallvec 1.15.0 registry+https://github.com/rust-lang/crates.io-index",
"smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"socket2 0.5.8 registry+https://github.com/rust-lang/crates.io-index",
"socket2 0.5.9 registry+https://github.com/rust-lang/crates.io-index",
"stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"stacker 0.1.21 registry+https://github.com/rust-lang/crates.io-index",
"static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"strsim 0.11.1 registry+https://github.com/rust-lang/crates.io-index",
"strum 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
"strum_macros 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
"syn 2.0.99 registry+https://github.com/rust-lang/crates.io-index",
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
"syn 2.0.100 registry+https://github.com/rust-lang/crates.io-index",
"synstructure 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
"sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index",
"tempfile 3.17.1 registry+https://github.com/rust-lang/crates.io-index",
"terminal_size 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"sysinfo 0.34.2 registry+https://github.com/rust-lang/crates.io-index",
"tempfile 3.19.1 registry+https://github.com/rust-lang/crates.io-index",
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"textwrap 0.16.2 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index",
"tiff 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
"tiff 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
"time 0.3.37 registry+https://github.com/rust-lang/crates.io-index",
"time-core 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"tokio 1.43.0 registry+https://github.com/rust-lang/crates.io-index",
"time 0.3.41 registry+https://github.com/rust-lang/crates.io-index",
"time-core 0.1.4 registry+https://github.com/rust-lang/crates.io-index",
"tokio 1.44.2 registry+https://github.com/rust-lang/crates.io-index",
"tokio-native-tls 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"tokio-util 0.7.13 registry+https://github.com/rust-lang/crates.io-index",
"tokio-util 0.7.14 registry+https://github.com/rust-lang/crates.io-index",
"toml 0.5.11 registry+https://github.com/rust-lang/crates.io-index",
"tower 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"tower-layer 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
"tower-service 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
@@ -616,6 +740,7 @@
"ttf-parser 0.25.1 registry+https://github.com/rust-lang/crates.io-index",
"typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index",
"tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index",
"tzdb_data 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"uds_windows 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"unicase 2.8.1 registry+https://github.com/rust-lang/crates.io-index",
"unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index",
@@ -634,54 +759,66 @@
"walkdir 2.5.0 registry+https://github.com/rust-lang/crates.io-index",
"want 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"webbrowser 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"webbrowser 1.0.4 registry+https://github.com/rust-lang/crates.io-index",
"weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index",
"which 7.0.2 registry+https://github.com/rust-lang/crates.io-index",
"which 7.0.3 registry+https://github.com/rust-lang/crates.io-index",
"winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index",
"winapi-util 0.1.9 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.61.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=0c9d7ee1b807347c507d3a9862dd007b4d3f4354",
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=d67cc9920aa9b4883393e411fb4fa2ddd4c498b5",
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-link 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.59.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-link 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-registry 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"winput 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
"winreg 0.55.0 registry+https://github.com/rust-lang/crates.io-index",
"winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index",
"wmi 0.15.1 registry+https://github.com/rust-lang/crates.io-index",
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
"write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"xml-rs 0.8.25 registry+https://github.com/rust-lang/crates.io-index",
"xml-rs 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
"yaml-rust 0.4.5 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index",
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
@@ -691,25 +828,26 @@
"MIT-0",
[
"dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
"tzdb_data 0.2.1 registry+https://github.com/rust-lang/crates.io-index"
"tzdb_data 0.2.2 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
"MPL-2.0",
[
"option-ext 0.2.0 registry+https://github.com/rust-lang/crates.io-index"
"option-ext 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"ramhorns 1.0.1 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
"OFL-1.1",
[
"epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index"
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
"Ubuntu-font-1.0",
[
"epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index"
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index"
]
],
[
@@ -718,11 +856,11 @@
"icu_collections 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid_transform 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid_transform_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid_transform_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
"icu_normalizer 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_normalizer_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_normalizer_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
"icu_properties 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
"icu_properties_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_properties_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
"icu_provider 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_provider_macros 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"litemap 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
@@ -753,14 +891,16 @@
[
"Zlib",
[
"adler32 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
"const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
"const_format_proc_macros 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"foldhash 0.1.4 registry+https://github.com/rust-lang/crates.io-index",
"foldhash 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.35/schema.bar.json",
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.36/schema.bar.json",
"monitor": 0,
"font_family": "JetBrains Mono",
"theme": {

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.35/schema.json",
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.36/schema.json",
"app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
"window_hiding_behaviour": "Cloak",
"cross_monitor_move_behaviour": "Insert",
@@ -14,13 +14,6 @@
"unfocused_border": "Base03",
"bar_accent": "Base0D"
},
"stackbar": {
"height": 40,
"mode": "OnStack",
"tabs": {
"width": 300
}
},
"monitors": [
{
"workspaces": [

View File

@@ -5,6 +5,8 @@
alt + o : taskkill /f /im whkd.exe; Start-Process whkd -WindowStyle hidden # if shell is pwsh / powershell
alt + shift + o : komorebic reload-configuration
alt + i : komorebic toggle-shortcuts
# App shortcuts - these require shell to be pwsh / powershell
# The apps will be focused if open, or launched if not open
# alt + f : if ($wshell.AppActivate('Firefox') -eq $False) { start firefox }

View File

@@ -31,7 +31,7 @@ install:
just install-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
install-with-jsonschema:
just install-targets-with-jsonschema komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
just install-targets-with-jsonschema komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui komorebi-shortcuts
build-targets *targets:
"{{ targets }}" -split ' ' | ForEach-Object { just build-target $_ }
@@ -40,7 +40,7 @@ build-target target:
cargo +stable build --package {{ target }} --locked --release --no-default-features
build:
just build-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
just build-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui komorebi-shortcuts
copy-target target:
cp .\target\release\{{ target }}.exe $Env:USERPROFILE\.cargo\bin
@@ -88,3 +88,6 @@ schemagen:
generate-schema-doc ./schema.json --config template_name=js_offline --config minify=false ./static-config-docs/
generate-schema-doc ./schema.bar.json --config template_name=js_offline --config minify=false ./bar-config-docs/
mv ./bar-config-docs/schema.bar.html ./bar-config-docs/schema.html
depgen:
cargo deny list --format json | jq 'del(.unlicensed)' > dependencies.json

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-bar"
version = "0.1.36"
version = "0.1.37"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -22,7 +22,7 @@ font-loader = "0.11"
hotwatch = { workspace = true }
image = "0.25"
lazy_static = { workspace = true }
netdev = "0.33"
netdev = "0.34"
num = "0.4"
num-derive = "0.4"
num-traits = "0.2"
@@ -35,6 +35,7 @@ starship-battery = "0.10"
sysinfo = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
which = { workspace = true }
windows = { workspace = true }
windows-core = { workspace = true }
windows-icons = { git = "https://github.com/LGUG2Z/windows-icons", rev = "0c9d7ee1b807347c507d3a9862dd007b4d3f4354" }
@@ -42,4 +43,4 @@ windows-icons-fallback = { package = "windows-icons", git = "https://github.com/
[features]
default = ["schemars"]
schemars = ["dep:schemars"]
schemars = ["dep:schemars", "komorebi-client/schemars", "komorebi-themes/schemars"]

View File

@@ -51,6 +51,7 @@ use komorebi_client::MonitorNotification;
use komorebi_client::NotificationEvent;
use komorebi_client::PathExt;
use komorebi_client::SocketMessage;
use komorebi_client::VirtualDesktopNotification;
use komorebi_themes::catppuccin_egui;
use komorebi_themes::Base16Value;
use komorebi_themes::Base16Wrapper;
@@ -758,6 +759,30 @@ impl eframe::App for Komobar {
self.monitor_index = monitor_index;
let mut should_apply_config = false;
match notification.event {
NotificationEvent::VirtualDesktop(
VirtualDesktopNotification::EnteredAssociatedVirtualDesktop,
) => {
tracing::debug!(
"back on komorebi's associated virtual desktop - restoring bar"
);
if let Some(hwnd) = self.hwnd {
komorebi_client::WindowsApi::restore_window(hwnd);
}
}
NotificationEvent::VirtualDesktop(
VirtualDesktopNotification::LeftAssociatedVirtualDesktop,
) => {
tracing::debug!(
"no longer on komorebi's associated virtual desktop - minimizing bar"
);
if let Some(hwnd) = self.hwnd {
komorebi_client::WindowsApi::minimize_window(hwnd);
}
}
_ => {}
}
if self.monitor_index.is_none()
|| self
.monitor_index

View File

@@ -13,7 +13,7 @@ use std::path::PathBuf;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// The `komorebi.bar.json` configuration file reference for `v0.1.36`
/// The `komorebi.bar.json` configuration file reference for `v0.1.37`
pub struct KomobarConfig {
/// Bar height (default: 50)
pub height: Option<f32>,

View File

@@ -0,0 +1,356 @@
use super::komorebi::img_to_texture;
use crate::render::RenderConfig;
use crate::selected_frame::SelectableFrame;
use crate::widgets::widget::BarWidget;
use eframe::egui::vec2;
use eframe::egui::Color32;
use eframe::egui::Context;
use eframe::egui::CornerRadius;
use eframe::egui::FontId;
use eframe::egui::Frame;
use eframe::egui::Image;
use eframe::egui::Label;
use eframe::egui::Margin;
use eframe::egui::RichText;
use eframe::egui::Sense;
use eframe::egui::Stroke;
use eframe::egui::StrokeKind;
use eframe::egui::Ui;
use eframe::egui::Vec2;
use image::DynamicImage;
use image::RgbaImage;
use komorebi_client::PathExt;
use serde::Deserialize;
use serde::Serialize;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::time::Duration;
use std::time::Instant;
use tracing;
use which::which;
/// Minimum interval between consecutive application launches to prevent accidental spamming.
const MIN_LAUNCH_INTERVAL: Duration = Duration::from_millis(800);
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ApplicationsConfig {
/// Enables or disables the applications widget.
pub enable: bool,
/// Whether to show the launch command on hover (optional).
/// Could be overridden per application. Defaults to `false` if not set.
pub show_command_on_hover: Option<bool>,
/// Horizontal spacing between application buttons.
pub spacing: Option<f32>,
/// Default display format for all applications (optional).
/// Could be overridden per application. Defaults to `Icon`.
pub display: Option<DisplayFormat>,
/// List of configured applications to display.
pub items: Vec<AppConfig>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct AppConfig {
/// Whether to enable this application button (optional).
/// Inherits from the global `Applications` setting if omitted.
pub enable: Option<bool>,
/// Whether to show the launch command on hover (optional).
/// Inherits from the global `Applications` setting if omitted.
pub show_command_on_hover: Option<bool>,
/// Display name of the application.
pub name: String,
/// Optional icon: a path to an image or a text-based glyph (e.g., from Nerd Fonts).
/// If not set, and if the `command` is a path to an executable, an icon might be extracted from it.
/// Note: glyphs require a compatible `font_family`.
pub icon: Option<String>,
/// Command to execute (e.g. path to the application or shell command).
pub command: String,
/// Display format for this application button (optional). Overrides global format if set.
pub display: Option<DisplayFormat>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum DisplayFormat {
/// Show only the application icon.
#[default]
Icon,
/// Show only the application name as text.
Text,
/// Show both the application icon and name.
IconAndText,
}
#[derive(Clone, Debug)]
pub struct Applications {
/// Whether the applications widget is enabled.
pub enable: bool,
/// Horizontal spacing between application buttons.
pub spacing: Option<f32>,
/// Applications to be rendered in the UI.
pub items: Vec<App>,
}
impl BarWidget for Applications {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if !self.enable {
return;
}
let icon_config = IconConfig {
font_id: config.icon_font_id.clone(),
size: config.icon_font_id.size,
color: ctx.style().visuals.selection.stroke.color,
};
if let Some(spacing) = self.spacing {
ui.spacing_mut().item_spacing.x = spacing;
}
config.apply_on_widget(false, ui, |ui| {
for app in &mut self.items {
app.render(ctx, ui, &icon_config);
}
});
}
}
impl From<&ApplicationsConfig> for Applications {
fn from(applications_config: &ApplicationsConfig) -> Self {
// Allow immediate launch by initializing last_launch in the past.
let last_launch = Instant::now() - 2 * MIN_LAUNCH_INTERVAL;
let mut applications_config = applications_config.clone();
let items = applications_config
.items
.iter_mut()
.enumerate()
.map(|(index, app_config)| {
app_config.command = app_config
.command
.replace_env()
.to_string_lossy()
.to_string();
if let Some(icon) = &mut app_config.icon {
*icon = icon.replace_env().to_string_lossy().to_string();
}
App {
enable: app_config.enable.unwrap_or(applications_config.enable),
name: app_config
.name
.is_empty()
.then(|| format!("App {}", index + 1))
.unwrap_or_else(|| app_config.name.clone()),
icon: Icon::try_from(app_config),
command: app_config.command.clone(),
display: app_config
.display
.or(applications_config.display)
.unwrap_or_default(),
show_command_on_hover: app_config
.show_command_on_hover
.or(applications_config.show_command_on_hover)
.unwrap_or(false),
last_launch,
}
})
.collect();
Self {
enable: applications_config.enable,
items,
spacing: applications_config.spacing,
}
}
}
/// A single resolved application entry used at runtime.
#[derive(Clone, Debug)]
pub struct App {
/// Whether this application is enabled.
pub enable: bool,
/// Display name of the application. Defaults to "App N" if not set.
pub name: String,
/// Icon to display for this application, if available.
pub icon: Option<Icon>,
/// Command to execute when the application is launched.
pub command: String,
/// Display format (icon, text, or both).
pub display: DisplayFormat,
/// Whether to show the launch command on hover.
pub show_command_on_hover: bool,
/// Last time this application was launched (used for cooldown control).
pub last_launch: Instant,
}
impl App {
/// Renders the application button in the provided `Ui` context with a given icon size.
#[inline]
pub fn render(&mut self, ctx: &Context, ui: &mut Ui, icon_config: &IconConfig) {
if self.enable
&& SelectableFrame::new(false)
.show(ui, |ui| {
ui.spacing_mut().item_spacing = Vec2::splat(4.0);
match self.display {
DisplayFormat::Icon => self.draw_icon(ctx, ui, icon_config),
DisplayFormat::Text => self.draw_name(ui),
DisplayFormat::IconAndText => {
self.draw_icon(ctx, ui, icon_config);
self.draw_name(ui);
}
}
// Add hover text with command information
if self.show_command_on_hover {
ui.response()
.on_hover_text(format!("Launch: {}", self.command));
} else {
ui.response();
}
})
.clicked()
{
// Launch the application when clicked
self.launch_if_ready();
}
}
/// Draws the application's icon within the UI if available,
/// or falls back to a default placeholder icon.
#[inline]
fn draw_icon(&self, ctx: &Context, ui: &mut Ui, icon_config: &IconConfig) {
if let Some(icon) = &self.icon {
icon.draw(ctx, ui, icon_config);
} else {
Icon::draw_fallback(ui, Vec2::splat(icon_config.size));
}
}
/// Displays the application's name as a non-selectable label within the UI.
#[inline]
fn draw_name(&self, ui: &mut Ui) {
ui.add(Label::new(&self.name).selectable(false));
}
/// Attempts to launch the specified command in a separate thread if enough time has passed
/// since the last launch. This prevents repeated launches from rapid consecutive clicks.
///
/// Errors during launch are logged using the `tracing` crate.
pub fn launch_if_ready(&mut self) {
let now = Instant::now();
if now.duration_since(self.last_launch) < MIN_LAUNCH_INTERVAL {
return;
}
self.last_launch = now;
let command_string = self.command.clone();
// Launch the application in a separate thread to avoid blocking the UI
std::thread::spawn(move || {
if let Err(e) = Command::new("cmd").args(["/C", &command_string]).spawn() {
tracing::error!("Failed to launch command '{}': {}", command_string, e);
}
});
}
}
/// Holds decoded image data to be used as an icon in the UI.
#[derive(Clone, Debug)]
pub enum Icon {
/// RGBA image used for rendering the icon.
Image(RgbaImage),
/// Text-based icon, e.g. from a font like Nerd Fonts.
Text(String),
}
impl Icon {
/// Attempts to create an `Icon` from the given `AppConfig`.
/// Loads the image from a specified icon path or extracts it from the application's
/// executable if the command points to a valid executable file.
#[inline]
pub fn try_from(config: &AppConfig) -> Option<Self> {
if let Some(icon) = config.icon.as_deref().map(str::trim) {
if !icon.is_empty() {
let path = Path::new(&icon);
if path.is_file() {
match image::open(path).as_ref().map(DynamicImage::to_rgba8) {
Ok(image) => return Some(Icon::Image(image)),
Err(err) => {
tracing::error!("Failed to load icon from {}, error: {}", icon, err)
}
}
} else {
return Some(Icon::Text(icon.to_owned()));
}
}
}
let binary = PathBuf::from(config.command.split(".exe").next()?);
let path = if binary.is_file() {
Some(binary)
} else {
which(binary).ok()
};
match path {
Some(path) => windows_icons::get_icon_by_path(&path.to_string_lossy())
.or_else(|| windows_icons_fallback::get_icon_by_path(&path.to_string_lossy()))
.map(Icon::Image),
None => None,
}
}
/// Renders the icon in the given `Ui` context with the specified size.
#[inline]
pub fn draw(&self, ctx: &Context, ui: &mut Ui, icon_config: &IconConfig) {
match self {
Icon::Image(image) => {
Frame::NONE
.inner_margin(Margin::same(ui.style().spacing.button_padding.y as i8))
.show(ui, |ui| {
ui.add(
Image::from(&img_to_texture(ctx, image))
.maintain_aspect_ratio(true)
.fit_to_exact_size(Vec2::splat(icon_config.size)),
);
});
}
Icon::Text(icon) => {
let rich_text = RichText::new(icon)
.font(icon_config.font_id.clone())
.size(icon_config.size)
.color(icon_config.color);
ui.add(Label::new(rich_text).selectable(false));
}
}
}
/// Draws a fallback icon when the specified icon cannot be loaded.
/// Displays a simple crossed-out rectangle as a placeholder.
#[inline]
pub fn draw_fallback(ui: &mut Ui, icon_size: Vec2) {
let (response, painter) = ui.allocate_painter(icon_size, Sense::hover());
let stroke = Stroke::new(1.0, ui.style().visuals.text_color());
let mut rect = response.rect;
let rounding = CornerRadius::same((rect.width() * 0.1) as u8);
rect = rect.shrink(stroke.width);
let c = rect.center();
let r = rect.width() / 2.0;
painter.rect_stroke(rect, rounding, stroke, StrokeKind::Outside);
painter.line_segment([c - vec2(r, r), c + vec2(r, r)], stroke);
}
}
/// Configuration structure for icon rendering
#[derive(Clone, Debug)]
pub struct IconConfig {
/// Font used for text-based icons
pub font_id: FontId,
/// Size of the icon
pub size: f32,
/// Color of the icon used for text-based icons
pub color: Color32,
}

View File

@@ -292,7 +292,6 @@ impl BarWidget for Komorebi {
komorebi_notification_state.monitor_index,
i,
),
SocketMessage::RetileWithResizeDimensions,
SocketMessage::MouseFollowsFocus(true),
])
.is_err()
@@ -301,7 +300,6 @@ impl BarWidget for Komorebi {
"could not send the following batch of messages to komorebi:\n
MouseFollowsFocus(false)\n
FocusMonitorWorkspaceNumber({}, {})\n
RetileWithResizeDimensions
MouseFollowsFocus(true)\n",
komorebi_notification_state.monitor_index,
i,
@@ -312,14 +310,12 @@ impl BarWidget for Komorebi {
komorebi_notification_state.monitor_index,
i,
),
SocketMessage::RetileWithResizeDimensions,
])
.is_err()
{
tracing::error!(
"could not send the following batch of messages to komorebi:\n
FocusMonitorWorkspaceNumber({}, {})\n
RetileWithResizeDimensions",
FocusMonitorWorkspaceNumber({}, {})\n",
komorebi_notification_state.monitor_index,
i,
);
@@ -674,7 +670,7 @@ impl BarWidget for Komorebi {
}
}
fn img_to_texture(ctx: &Context, rgba_image: &RgbaImage) -> TextureHandle {
pub(super) fn img_to_texture(ctx: &Context, rgba_image: &RgbaImage) -> TextureHandle {
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
let pixels = rgba_image.as_flat_samples();
let color_image = ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
@@ -722,6 +718,7 @@ impl KomorebiNotificationState {
let show_all_icons = render_config.borrow().show_all_icons;
match notification.event {
NotificationEvent::VirtualDesktop(_) => {}
NotificationEvent::WindowManager(_) => {}
NotificationEvent::Monitor(_) => {}
NotificationEvent::Socket(message) => match message {

View File

@@ -1,3 +1,4 @@
pub mod applications;
pub mod battery;
pub mod cpu;
pub mod date;

View File

@@ -1,4 +1,6 @@
use crate::render::RenderConfig;
use crate::widgets::applications::Applications;
use crate::widgets::applications::ApplicationsConfig;
use crate::widgets::battery::Battery;
use crate::widgets::battery::BatteryConfig;
use crate::widgets::cpu::Cpu;
@@ -33,6 +35,7 @@ pub trait BarWidget {
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum WidgetConfig {
Applications(ApplicationsConfig),
Battery(BatteryConfig),
Cpu(CpuConfig),
Date(DateConfig),
@@ -49,6 +52,7 @@ pub enum WidgetConfig {
impl WidgetConfig {
pub fn as_boxed_bar_widget(&self) -> Box<dyn BarWidget> {
match self {
WidgetConfig::Applications(config) => Box::new(Applications::from(config)),
WidgetConfig::Battery(config) => Box::new(Battery::from(*config)),
WidgetConfig::Cpu(config) => Box::new(Cpu::from(*config)),
WidgetConfig::Date(config) => Box::new(Date::from(config.clone())),
@@ -65,6 +69,7 @@ impl WidgetConfig {
pub fn enabled(&self) -> bool {
match self {
WidgetConfig::Applications(config) => config.enable,
WidgetConfig::Battery(config) => config.enable,
WidgetConfig::Cpu(config) => config.enable,
WidgetConfig::Date(config) => config.enable,

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-client"
version = "0.1.36"
version = "0.1.37"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -70,6 +70,7 @@ pub use komorebi::State;
pub use komorebi::StaticConfig;
pub use komorebi::SubscribeOptions;
pub use komorebi::TabsConfig;
pub use komorebi::VirtualDesktopNotification;
pub use komorebi::WindowContainerBehaviour;
pub use komorebi::WindowsApi;
pub use komorebi::WorkspaceConfig;

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-gui"
version = "0.1.36"
version = "0.1.37"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -0,0 +1,11 @@
[package]
name = "komorebi-shortcuts"
version = "0.1.0"
edition = "2024"
[dependencies]
whkd-parser = { git = "https://github.com/LGUG2Z/whkd", rev = "29df24ff2dd715655b0366bd2a598837c699a8e9" }
whkd-core = { git = "https://github.com/LGUG2Z/whkd", rev = "29df24ff2dd715655b0366bd2a598837c699a8e9" }
eframe = { workspace = true }
dirs = { workspace = true }

View File

@@ -0,0 +1,106 @@
use eframe::egui::ViewportBuilder;
use std::path::PathBuf;
use whkd_core::HotkeyBinding;
use whkd_core::Whkdrc;
#[derive(Default)]
struct Quicklook {
whkdrc: Option<Whkdrc>,
filter: String,
}
impl Quicklook {
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
// Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
// Restore app state using cc.storage (requires the "persistence" feature).
// Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
// for e.g. egui::PaintCallback.
let mut home = std::env::var("WHKD_CONFIG_HOME").map_or_else(
|_| {
dirs::home_dir()
.expect("no home directory found")
.join(".config")
},
|home_path| {
let home = PathBuf::from(&home_path);
if home.as_path().is_dir() {
home
} else {
panic!(
"$Env:WHKD_CONFIG_HOME is set to '{home_path}', which is not a valid directory",
);
}
},
);
home.push("whkdrc");
Self {
whkdrc: whkd_parser::load(&home).ok(),
filter: String::new(),
}
}
}
impl eframe::App for Quicklook {
fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) {
eframe::egui::CentralPanel::default().show(ctx, |ui| {
ui.set_max_width(ui.available_width());
ui.set_max_height(ui.available_height());
eframe::egui::ScrollArea::vertical().show(ui, |ui| {
eframe::egui::Grid::new("grid")
.num_columns(2)
.striped(true)
.spacing([40.0, 4.0])
.min_col_width(ui.available_width() / 2.0 - 20.0)
.show(ui, |ui| {
if let Some(whkdrc) = &self.whkdrc {
ui.label("Filter");
ui.add(
eframe::egui::text_edit::TextEdit::singleline(&mut self.filter)
.background_color(ctx.style().visuals.faint_bg_color),
);
ui.end_row();
ui.end_row();
for binding in &whkdrc.bindings {
if is_komorebic_binding(binding) {
let keys = binding.keys.join(" + ");
if self.filter.is_empty()
|| binding.command.contains(&self.filter)
{
ui.label(keys);
ui.label(&binding.command);
ui.end_row();
}
}
}
}
});
});
});
}
}
fn main() {
let viewport_builder = ViewportBuilder::default()
.with_resizable(true)
.with_decorations(false);
let native_options = eframe::NativeOptions {
viewport: viewport_builder,
centered: true,
..Default::default()
};
eframe::run_native(
"komorebi-shortcuts",
native_options,
Box::new(|cc| Ok(Box::new(Quicklook::new(cc)))),
)
.unwrap();
}
fn is_komorebic_binding(binding: &HotkeyBinding) -> bool {
binding.command.starts_with("komorebic")
}

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-themes"
version = "0.1.36"
version = "0.1.37"
edition = "2021"
[dependencies]

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi"
version = "0.1.36"
version = "0.1.37"
description = "A tiling window manager for Windows"
repository = "https://github.com/LGUG2Z/komorebi"
edition = "2021"

View File

@@ -355,6 +355,61 @@ impl Ease for EaseInOutBounce {
}
}
pub struct CubicBezier {
pub x1: f64,
pub y1: f64,
pub x2: f64,
pub y2: f64,
}
impl CubicBezier {
fn x(&self, s: f64) -> f64 {
3.0 * self.x1 * s * (1.0 - s).powi(2) + 3.0 * self.x2 * s.powi(2) * (1.0 - s) + s.powi(3)
}
fn y(&self, s: f64) -> f64 {
3.0 * self.y1 * s * (1.0 - s).powi(2) + 3.0 * self.y2 * s.powi(2) * (1.0 - s) + s.powi(3)
}
fn dx_ds(&self, s: f64) -> f64 {
3.0 * self.x1 * (1.0 - s) * (1.0 - 3.0 * s)
+ 3.0 * self.x2 * (2.0 * s - 3.0 * s.powi(2))
+ 3.0 * s.powi(2)
}
fn find_s(&self, t: f64) -> f64 {
if t <= 0.0 {
return 0.0;
}
if t >= 1.0 {
return 1.0;
}
let mut s = t;
for _ in 0..8 {
let x_val = self.x(s);
let dx_val = self.dx_ds(s);
if dx_val.abs() < 1e-6 {
break;
}
let delta = (x_val - t) / dx_val;
s = (s - delta).clamp(0.0, 1.0);
if delta.abs() < 1e-6 {
break;
}
}
s
}
fn evaluate(&self, t: f64) -> f64 {
let s = self.find_s(t.clamp(0.0, 1.0));
self.y(s)
}
}
pub fn apply_ease_func(t: f64, style: AnimationStyle) -> f64 {
match style {
AnimationStyle::Linear => Linear::evaluate(t),
@@ -387,5 +442,6 @@ pub fn apply_ease_func(t: f64, style: AnimationStyle) -> f64 {
AnimationStyle::EaseInBounce => EaseInBounce::evaluate(t),
AnimationStyle::EaseOutBounce => EaseOutBounce::evaluate(t),
AnimationStyle::EaseInOutBounce => EaseInOutBounce::evaluate(t),
AnimationStyle::CubicBezier(x1, y1, x2, y2) => CubicBezier { x1, y1, x2, y2 }.evaluate(t),
}
}

View File

@@ -105,11 +105,10 @@ fn event_rx() -> Receiver<Notification> {
}
pub fn window_border(hwnd: isize) -> Option<BorderInfo> {
WINDOWS_BORDERS.lock().get(&hwnd).and_then(|id| {
BORDER_STATE.lock().get(id).map(|b| BorderInfo {
border_hwnd: b.hwnd,
window_kind: b.window_kind,
})
let id = WINDOWS_BORDERS.lock().get(&hwnd)?.clone();
BORDER_STATE.lock().get(&id).map(|b| BorderInfo {
border_hwnd: b.hwnd,
window_kind: b.window_kind,
})
}
@@ -136,6 +135,8 @@ pub fn destroy_all_borders() -> color_eyre::Result<()> {
let _ = destroy_border(border);
}
drop(borders);
WINDOWS_BORDERS.lock().clear();
let mut remaining_hwnds = vec![];

View File

@@ -1,11 +1,12 @@
use clap::ValueEnum;
use serde::ser::SerializeSeq;
use serde::Deserialize;
use serde::Serialize;
use strum::Display;
use strum::EnumString;
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)]
#[derive(Copy, Clone, Debug, Display, EnumString, ValueEnum, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum AnimationStyle {
Linear,
@@ -38,4 +39,81 @@ pub enum AnimationStyle {
EaseInBounce,
EaseOutBounce,
EaseInOutBounce,
#[value(skip)]
CubicBezier(f64, f64, f64, f64),
}
// Custom serde implementation
impl<'de> Deserialize<'de> for AnimationStyle {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct AnimationStyleVisitor;
impl<'de> serde::de::Visitor<'de> for AnimationStyleVisitor {
type Value = AnimationStyle;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string or an array of four f64 values")
}
// Handle string variants (e.g., "EaseInOutExpo")
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
value.parse().map_err(|_| E::unknown_variant(value, &[]))
}
// Handle CubicBezier array (e.g., [0.32, 0.72, 0.0, 1.0])
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let x1 = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
let y1 = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
let x2 = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
let y2 = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(3, &self))?;
// Ensure no extra elements
if seq.next_element::<serde::de::IgnoredAny>()?.is_some() {
return Err(serde::de::Error::invalid_length(5, &self));
}
Ok(AnimationStyle::CubicBezier(x1, y1, x2, y2))
}
}
deserializer.deserialize_any(AnimationStyleVisitor)
}
}
impl Serialize for AnimationStyle {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
// Serialize CubicBezier as an array
AnimationStyle::CubicBezier(x1, y1, x2, y2) => {
let mut seq = serializer.serialize_seq(Some(4))?;
seq.serialize_element(x1)?;
seq.serialize_element(y1)?;
seq.serialize_element(x2)?;
seq.serialize_element(y2)?;
seq.end()
}
// Serialize all other variants as strings
_ => serializer.serialize_str(&self.to_string()),
}
}
}

View File

@@ -377,6 +377,21 @@ pub struct WindowManagementBehaviour {
/// that can be later toggled to tiled, when false it will default to
/// `current_behaviour` again.
pub float_override: bool,
/// Determines if a new window should be spawned floating when on the floating layer and the
/// floating layer behaviour is set to float. This value is always calculated when checking for
/// the management behaviour on a specific workspace.
pub floating_layer_override: bool,
/// The floating layer behaviour to be used if the float override is being used
pub floating_layer_behaviour: FloatingLayerBehaviour,
/// The `Placement` to be used when toggling a window to float
pub toggle_float_placement: Placement,
/// The `Placement` to be used when spawning a window on the floating layer with the
/// `FloatingLayerBehaviour` set to `FloatingLayerBehaviour::Float`
pub floating_layer_placement: Placement,
/// The `Placement` to be used when spawning a window with float override active
pub float_override_placement: Placement,
/// The `Placement` to be used when spawning a window that matches a 'floating_applications' rule
pub float_rule_placement: Placement,
}
#[derive(
@@ -396,17 +411,59 @@ pub enum WindowContainerBehaviour {
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum FloatingLayerBehaviour {
/// Tile new windows (unless they match a float rule)
/// Tile new windows (unless they match a float rule or float override is active)
#[default]
Tile,
/// Float new windows
Float,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Display, EnumString, ValueEnum)]
#[derive(
Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Placement {
/// Does not change the size or position of the window
#[default]
None,
/// Center the window without changing the size
Center,
/// Center the window and resize it according to the `AspectRatio`
CenterAndResize,
}
impl FloatingLayerBehaviour {
pub fn should_float(&self) -> bool {
match self {
FloatingLayerBehaviour::Tile => false,
FloatingLayerBehaviour::Float => true,
}
}
}
impl Placement {
pub fn should_center(&self) -> bool {
match self {
Placement::None => false,
Placement::Center | Placement::CenterAndResize => true,
}
}
pub fn should_resize(&self) -> bool {
match self {
Placement::None | Placement::Center => false,
Placement::CenterAndResize => true,
}
}
}
#[derive(
Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Display, EnumString, ValueEnum,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum MoveBehaviour {
/// Swap the window container with the window container at the edge of the adjacent monitor
#[default]
Swap,
/// Insert the window container into the focused workspace on the adjacent monitor
Insert,
@@ -414,19 +471,22 @@ pub enum MoveBehaviour {
NoOp,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)]
#[derive(
Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum CrossBoundaryBehaviour {
/// Attempt to perform actions across a workspace boundary
Workspace,
/// Attempt to perform actions across a monitor boundary
#[default]
Monitor,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum HidingBehaviour {
/// Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)
/// END OF LIFE FEATURE: Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)
Hide,
/// Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching)
Minimize,
@@ -434,10 +494,13 @@ pub enum HidingBehaviour {
Cloak,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Display, EnumString, ValueEnum)]
#[derive(
Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Display, EnumString, ValueEnum,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum OperationBehaviour {
/// Process komorebic commands on temporarily unmanaged/floated windows
#[default]
Op,
/// Ignore komorebic commands on temporarily unmanaged/floated windows
NoOp,
@@ -466,6 +529,16 @@ impl Sizing {
}
}
#[derive(
Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum WindowHandlingBehaviour {
#[default]
Sync,
Async,
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -63,6 +63,7 @@ use crate::core::config_generation::MatchingRule;
use crate::core::config_generation::MatchingStrategy;
use crate::core::config_generation::WorkspaceMatchingRule;
use color_eyre::Result;
use crossbeam_utils::atomic::AtomicCell;
use os_info::Version;
use parking_lot::Mutex;
use parking_lot::RwLock;
@@ -159,7 +160,14 @@ lazy_static! {
})
]));
static ref SESSION_FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new()));
static ref FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new()));
static ref FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![
MatchingRule::Simple(IdWithIdentifier {
kind: ApplicationIdentifier::Exe,
id: String::from("komorebi-shortcuts.exe"),
matching_strategy: Option::from(MatchingStrategy::Equals),
})
]));
static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"Chrome_RenderWidgetHostHWND".to_string(),
]));
@@ -227,6 +235,8 @@ lazy_static! {
Arc::new(Mutex::new(HashMap::new()));
static ref FLOATING_WINDOW_TOGGLE_ASPECT_RATIO: Arc<Mutex<AspectRatio>> = Arc::new(Mutex::new(AspectRatio::Predefined(PredefinedAspectRatio::Widescreen)));
static ref CURRENT_VIRTUAL_DESKTOP: Arc<Mutex<Option<Vec<u8>>>> = Arc::new(Mutex::new(None));
}
pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10);
@@ -240,6 +250,9 @@ pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20);
pub static WINDOW_HANDLING_BEHAVIOUR: AtomicCell<WindowHandlingBehaviour> =
AtomicCell::new(WindowHandlingBehaviour::Sync);
shadow_rs::shadow!(build);
#[must_use]
@@ -293,6 +306,14 @@ pub enum NotificationEvent {
WindowManager(WindowManagerEvent),
Socket(SocketMessage),
Monitor(MonitorNotification),
VirtualDesktop(VirtualDesktopNotification),
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum VirtualDesktopNotification {
EnteredAssociatedVirtualDesktop,
LeftAssociatedVirtualDesktop,
}
#[derive(Debug, Serialize, Deserialize)]

View File

@@ -17,6 +17,7 @@ use std::time::Duration;
use clap::Parser;
use clap::ValueEnum;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use crossbeam_utils::Backoff;
use komorebi::animation::AnimationEngine;
@@ -193,8 +194,28 @@ fn main() -> Result<()> {
let opts: Opts = Opts::parse();
CUSTOM_FFM.store(opts.focus_follows_mouse, Ordering::SeqCst);
let mut set_foreground_window_retries = 5;
let mut set_foreground_window_succeeded = false;
let process_id = WindowsApi::current_process_id();
WindowsApi::allow_set_foreground_window(process_id)?;
while set_foreground_window_retries > 0 && !set_foreground_window_succeeded {
match WindowsApi::allow_set_foreground_window(process_id) {
Ok(_) => {
set_foreground_window_succeeded = true;
}
Err(error) => {
tracing::error!("{error}");
set_foreground_window_retries -= 1;
}
}
if set_foreground_window_retries == 0 {
return Err(anyhow!(
"failed call to AllowSetForegroundWindow after 5 retries"
));
}
}
WindowsApi::set_process_dpi_awareness_context()?;
let session_id = WindowsApi::process_id_to_session_id()?;

View File

@@ -23,6 +23,7 @@ use crate::workspace::Workspace;
use crate::workspace::WorkspaceGlobals;
use crate::workspace::WorkspaceLayer;
use crate::DefaultLayout;
use crate::FloatingLayerBehaviour;
use crate::Layout;
use crate::OperationDirection;
use crate::Wallpaper;
@@ -67,6 +68,8 @@ pub struct Monitor {
pub workspace_padding: Option<i32>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub wallpaper: Option<Wallpaper>,
#[getset(get_copy = "pub", set = "pub")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
}
impl_ring_elements!(Monitor, Workspace);
@@ -123,6 +126,7 @@ pub fn new(
container_padding: None,
workspace_padding: None,
wallpaper: None,
floating_layer_behaviour: None,
}
}
@@ -165,6 +169,7 @@ impl Monitor {
container_padding: None,
workspace_padding: None,
wallpaper: None,
floating_layer_behaviour: None,
}
}
@@ -221,6 +226,7 @@ impl Monitor {
let work_area_offset = self.work_area_offset.or(offset);
let window_based_work_area_offset = self.window_based_work_area_offset();
let window_based_work_area_offset_limit = self.window_based_work_area_offset_limit();
let floating_layer_behaviour = self.floating_layer_behaviour();
for workspace in self.workspaces_mut() {
workspace.globals = WorkspaceGlobals {
@@ -232,6 +238,7 @@ impl Monitor {
work_area_offset,
window_based_work_area_offset,
window_based_work_area_offset_limit,
floating_layer_behaviour,
}
}
}
@@ -258,6 +265,7 @@ impl Monitor {
let work_area_offset = self.work_area_offset.or(offset);
let window_based_work_area_offset = self.window_based_work_area_offset();
let window_based_work_area_offset_limit = self.window_based_work_area_offset_limit();
let floating_layer_behaviour = self.floating_layer_behaviour();
if let Some(workspace) = self.workspaces_mut().get_mut(workspace_idx) {
workspace.globals = WorkspaceGlobals {
@@ -269,6 +277,7 @@ impl Monitor {
work_area_offset,
window_based_work_area_offset,
window_based_work_area_offset_limit,
floating_layer_behaviour,
}
}
}
@@ -449,6 +458,18 @@ impl Monitor {
Some(workspace) => workspace,
};
if target_workspace.monocle_container().is_some() {
for container in target_workspace.containers_mut() {
container.restore();
}
for window in target_workspace.floating_windows_mut() {
window.restore();
}
target_workspace.reintegrate_monocle_container()?;
}
target_workspace.set_layer(WorkspaceLayer::Tiling);
if let Some(direction) = direction {

View File

@@ -554,6 +554,7 @@ where
container_padding: cached.container_padding,
workspace_padding: cached.workspace_padding,
wallpaper: cached.wallpaper.clone(),
floating_layer_behaviour: cached.floating_layer_behaviour,
};
let focused_workspace_idx = m.focused_workspace_idx();

View File

@@ -236,31 +236,37 @@ impl WindowManager {
}
SocketMessage::EagerFocus(ref exe) => {
let focused_monitor_idx = self.focused_monitor_idx();
let focused_workspace_idx = self.focused_workspace_idx()?;
let mut window_location = None;
let mut monitor_workspace_indices = None;
let mut monitor_to_focus = None;
let mut needs_workspace_loading = false;
'search: for (monitor_idx, monitor) in self.monitors().iter().enumerate() {
'search: for (monitor_idx, monitor) in self.monitors_mut().iter_mut().enumerate() {
for (workspace_idx, workspace) in monitor.workspaces().iter().enumerate() {
if let Some(location) = workspace.location_from_exe(exe) {
window_location = Some(location);
monitor_workspace_indices = Some((monitor_idx, workspace_idx));
if monitor_idx != focused_monitor_idx {
monitor_to_focus = Some(monitor_idx);
}
// Focus workspace if it is not already the focused one, without
// loading it so that we don't give focus to the wrong window, we will
// load it later after focusing the wanted window
let focused_ws_idx = monitor.focused_workspace_idx();
if focused_ws_idx != workspace_idx {
monitor.set_last_focused_workspace(Option::from(focused_ws_idx));
monitor.focus_workspace(workspace_idx)?;
needs_workspace_loading = true;
}
break 'search;
}
}
}
if let Some((monitor_idx, workspace_idx)) = monitor_workspace_indices {
if monitor_idx != focused_monitor_idx {
self.focus_monitor(monitor_idx)?;
let focused_ws_idx = self.focused_workspace_idx()?;
if focused_ws_idx != workspace_idx {
self.focus_workspace(workspace_idx)?;
}
} else if workspace_idx != focused_workspace_idx {
self.focus_workspace(workspace_idx)?;
}
if let Some(monitor_idx) = monitor_to_focus {
self.focus_monitor(monitor_idx)?;
}
if let Some(location) = window_location {
@@ -293,6 +299,13 @@ impl WindowManager {
}
}
}
if needs_workspace_loading {
let mouse_follows_focus = self.mouse_follows_focus;
if let Some(monitor) = self.focused_monitor_mut() {
monitor.load_focused_workspace(mouse_follows_focus)?;
}
}
}
}
SocketMessage::FocusWindow(direction) => {
@@ -1283,6 +1296,12 @@ impl WindowManager {
window.lower()?;
}
}
if let Some(container) = workspace.monocle_container() {
if let Some(window) = container.focused_window() {
window.lower()?;
}
}
}
WorkspaceLayer::Floating => {
workspace.set_layer(WorkspaceLayer::Tiling);

View File

@@ -28,7 +28,9 @@ use crate::workspace::WorkspaceLayer;
use crate::Notification;
use crate::NotificationEvent;
use crate::State;
use crate::VirtualDesktopNotification;
use crate::Window;
use crate::CURRENT_VIRTUAL_DESKTOP;
use crate::FLOATING_APPLICATIONS;
use crate::HIDDEN_HWNDS;
use crate::REGEX_IDENTIFIERS;
@@ -116,15 +118,62 @@ impl WindowManager {
}
}
let mut last_known_virtual_desktop_id = CURRENT_VIRTUAL_DESKTOP.lock();
if let Some(virtual_desktop_id) = &self.virtual_desktop_id {
if let Some(id) = current_virtual_desktop() {
let latest_virtual_desktop_id = current_virtual_desktop();
if let Some(id) = latest_virtual_desktop_id {
// if we are on the vd associated with komorebi
let should_retile = id == *virtual_desktop_id
// and we came from a vd not associated with komorebi
&& (*last_known_virtual_desktop_id).clone().unwrap_or_default() != id;
*last_known_virtual_desktop_id = Some(id.clone());
if id != *virtual_desktop_id {
tracing::info!(
"ignoring events and commands while not on virtual desktop {:?}",
virtual_desktop_id
);
// TODO: when returning from another VD to the VD associated with komorebi
// if borders are enabled, they will not be drawn again until the user interacts
// with the workspace or forces a retile
border_manager::destroy_all_borders()?;
// to be consumed by integrating gui applications like bars to know
// when to hide visual components which don't make sense when not on
// komorebi's associated virtual desktop
tracing::debug!("notifying subscribers that we have left komorebi's associated virtual desktop");
notify_subscribers(
Notification {
event: NotificationEvent::VirtualDesktop(
VirtualDesktopNotification::LeftAssociatedVirtualDesktop,
),
state: self.as_ref().into(),
},
true,
)?;
return Ok(());
}
if should_retile {
self.retile_all(true)?;
// to be consumed by integrating gui applications like bars to know
// when to show visual components associated with komorebi's virtual
// desktop
tracing::debug!("notifying subscribers that we are back on komorebi's associated virtual desktop");
notify_subscribers(
Notification {
event: NotificationEvent::VirtualDesktop(
VirtualDesktopNotification::EnteredAssociatedVirtualDesktop,
),
state: self.as_ref().into(),
},
true,
)?;
}
}
}
@@ -290,11 +339,10 @@ impl WindowManager {
WindowManagerEvent::Show(_, window)
| WindowManagerEvent::Manage(window)
| WindowManagerEvent::Uncloak(_, window) => {
if matches!(event, WindowManagerEvent::Uncloak(_, _))
&& self.uncloack_to_ignore >= 1
if matches!(event, WindowManagerEvent::Uncloak(_, _)) && self.uncloak_to_ignore >= 1
{
tracing::info!("ignoring uncloak after monocle move by mouse across monitors");
self.uncloack_to_ignore = self.uncloack_to_ignore.saturating_sub(1);
self.uncloak_to_ignore = self.uncloak_to_ignore.saturating_sub(1);
} else {
let focused_monitor_idx = self.focused_monitor_idx();
let focused_workspace_idx =
@@ -346,13 +394,14 @@ impl WindowManager {
}
if proceed {
let mut behaviour = self.window_management_behaviour(
let behaviour = self.window_management_behaviour(
focused_monitor_idx,
focused_workspace_idx,
);
let workspace = self.focused_workspace_mut()?;
let workspace_contains_window = workspace.contains_window(window.hwnd);
let monocle_container = workspace.monocle_container().clone();
let mut workspace_layer = *workspace.layer();
if !workspace_contains_window && needs_reconciliation.is_none() {
let floating_applications = FLOATING_APPLICATIONS.lock();
@@ -376,23 +425,33 @@ impl WindowManager {
}
}
behaviour.float_override = behaviour.float_override
|| (should_float
&& !matches!(event, WindowManagerEvent::Manage(_)));
if behaviour.float_override {
// Center floating windows if we are already on the `Floating`
// layer and the window doesn't match a `floating_windows` rule and
// the workspace is not a floating workspace
if behaviour.float_override
|| behaviour.floating_layer_override
|| (should_float && !matches!(event, WindowManagerEvent::Manage(_)))
{
let placement = if behaviour.floating_layer_override {
// Floating layer override placement
behaviour.floating_layer_placement
} else if behaviour.float_override {
// Float override placement
behaviour.float_override_placement
} else {
// Float rule placement
behaviour.float_rule_placement
};
// Center floating windows according to the proper placement if not
// on a floating workspace
let center_spawned_floats =
matches!(workspace.layer, WorkspaceLayer::Floating)
&& !should_float
&& workspace.tile;
placement.should_center() && workspace.tile;
workspace.floating_windows_mut().push_back(window);
workspace.set_layer(WorkspaceLayer::Floating);
workspace_layer = *workspace.layer();
if center_spawned_floats {
let mut floating_window = window;
floating_window.center(&workspace.globals().work_area)?;
floating_window.center(
&workspace.globals().work_area,
placement.should_resize(),
)?;
}
self.update_focused_workspace(false, false)?;
} else {
@@ -400,6 +459,7 @@ impl WindowManager {
WindowContainerBehaviour::Create => {
workspace.new_container_for_window(window);
workspace.set_layer(WorkspaceLayer::Tiling);
workspace_layer = *workspace.layer();
self.update_focused_workspace(false, false)?;
}
WindowContainerBehaviour::Append => {
@@ -410,6 +470,7 @@ impl WindowManager {
})?
.add_window(window);
workspace.set_layer(WorkspaceLayer::Tiling);
workspace_layer = *workspace.layer();
self.update_focused_workspace(true, false)?;
stackbar_manager::send_notification();
}
@@ -442,7 +503,10 @@ impl WindowManager {
}
}
if !monocle_window_event && monocle_container.is_some() {
if !monocle_window_event
&& monocle_container.is_some()
&& matches!(workspace_layer, WorkspaceLayer::Tiling)
{
window.hide();
}
}
@@ -709,7 +773,7 @@ impl WindowManager {
// If we unmanaged a window, it shouldn't be immediately hidden behind managed windows
if let WindowManagerEvent::Unmanage(mut window) = event {
window.center(&self.focused_monitor_work_area()?)?;
window.center(&self.focused_monitor_work_area()?, true)?;
}
// Update list of known_hwnds and their monitor/workspace index pair

View File

@@ -3,11 +3,13 @@
use crate::border_manager;
use crate::notify_subscribers;
use crate::winevent::WinEvent;
use crate::HidingBehaviour;
use crate::NotificationEvent;
use crate::Window;
use crate::WindowManager;
use crate::WindowManagerEvent;
use crate::DATA_DIR;
use crate::HIDING_BEHAVIOUR;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
@@ -169,6 +171,7 @@ fn find_orphans() -> color_eyre::Result<()> {
loop {
std::thread::sleep(Duration::from_millis(20));
let hiding_behaviour = *HIDING_BEHAVIOUR.lock();
let mut cache = HWNDS_CACHE.lock();
let mut orphan_hwnds = HashMap::new();
@@ -177,13 +180,18 @@ fn find_orphans() -> color_eyre::Result<()> {
let window = Window::from(*hwnd);
if !window.is_window()
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
// docs is closed
//
// I hate every single person who worked on Microsoft Office 365, especially Word
|| !window.is_visible()
|| (
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
// docs is closed
//
// I hate every single person who worked on Microsoft Office 365, especially Word
!window.is_visible()
// We cannot execute this lovely hack if the user is using HidingBehaviour::Hide because
// it will result in legitimate hidden, non-visible windows being yeeted from the state
&& !matches!(hiding_behaviour, HidingBehaviour::Hide)
)
{
orphan_hwnds.insert(window.hwnd, (*m_idx, *w_idx));
}

View File

@@ -180,7 +180,9 @@ impl Stackbar {
layout.top -= workspace_specific_offset + STACKBAR_TAB_HEIGHT.load_consume();
layout.left -= workspace_specific_offset;
WindowsApi::position_window(self.hwnd, &layout, false)?;
// Async causes the stackbar to disappear or flicker because we modify it right after,
// so we have to do a synchronous call
WindowsApi::position_window(self.hwnd, &layout, false, false)?;
unsafe {
let hdc = GetDC(Option::from(self.hwnd()));

View File

@@ -60,8 +60,10 @@ use crate::AspectRatio;
use crate::Axis;
use crate::CrossBoundaryBehaviour;
use crate::FloatingLayerBehaviour;
use crate::Placement;
use crate::PredefinedAspectRatio;
use crate::ResolvedPathBuf;
use crate::WindowHandlingBehaviour;
use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING;
@@ -82,6 +84,7 @@ use crate::SLOW_APPLICATION_IDENTIFIERS;
use crate::TRANSPARENCY_BLACKLIST;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WINDOWS_11;
use crate::WINDOW_HANDLING_BEHAVIOUR;
use crate::WORKSPACE_MATCHING_RULES;
use color_eyre::Result;
use crossbeam_channel::Receiver;
@@ -307,7 +310,7 @@ impl From<&Workspace> for WorkspaceConfig {
window_container_behaviour_rules: Option::from(window_container_behaviour_rules),
float_override: *value.float_override(),
layout_flip: value.layout_flip(),
floating_layer_behaviour: Option::from(*value.floating_layer_behaviour()),
floating_layer_behaviour: value.floating_layer_behaviour(),
wallpaper: None,
}
}
@@ -336,6 +339,9 @@ pub struct MonitorConfig {
/// Specify a wallpaper for this monitor
#[serde(skip_serializing_if = "Option::is_none")]
pub wallpaper: Option<Wallpaper>,
/// Determine what happens to a new window when the Floating workspace layer is active (default: Tile)
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
}
impl From<&Monitor> for MonitorConfig {
@@ -372,6 +378,7 @@ impl From<&Monitor> for MonitorConfig {
container_padding,
workspace_padding,
wallpaper: value.wallpaper().clone(),
floating_layer_behaviour: value.floating_layer_behaviour(),
}
}
}
@@ -390,7 +397,7 @@ pub enum AppSpecificConfigurationPath {
#[serde_with::serde_as]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// The `komorebi.json` static configuration file reference for `v0.1.36`
/// The `komorebi.json` static configuration file reference for `v0.1.37`
pub struct StaticConfig {
/// DEPRECATED from v0.1.22: no longer required
#[serde(skip_serializing_if = "Option::is_none")]
@@ -411,6 +418,25 @@ pub struct StaticConfig {
/// (default: false)
#[serde(skip_serializing_if = "Option::is_none")]
pub float_override: Option<bool>,
/// Determines what happens on a new window when on the `FloatingLayer`
/// (default: Tile)
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
/// Determines the placement of a new window when toggling to float (default: CenterAndResize)
#[serde(skip_serializing_if = "Option::is_none")]
pub toggle_float_placement: Option<Placement>,
/// Determines the `Placement` to be used when spawning a window on the floating layer with the
/// `FloatingLayerBehaviour` set to `FloatingLayerBehaviour::Float` (default: Center)
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_layer_placement: Option<Placement>,
/// Determines the `Placement` to be used when spawning a window with float override active
/// (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub float_override_placement: Option<Placement>,
/// Determines the `Placement` to be used when spawning a window that matches a
/// 'floating_applications' rule (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub float_rule_placement: Option<Placement>,
/// Determine what happens when a window is moved across a monitor boundary (default: Swap)
#[serde(skip_serializing_if = "Option::is_none")]
pub cross_monitor_move_behaviour: Option<MoveBehaviour>,
@@ -536,6 +562,9 @@ pub struct StaticConfig {
/// Aspect ratio to resize with when toggling floating mode for a window
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_window_aspect_ratio: Option<AspectRatio>,
/// Which Windows API behaviour to use when manipulating windows (default: Sync)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_handling_behaviour: Option<WindowHandlingBehaviour>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -820,6 +849,21 @@ impl From<&WindowManager> for StaticConfig {
value.window_management_behaviour.current_behaviour,
),
float_override: Option::from(value.window_management_behaviour.float_override),
floating_layer_behaviour: Option::from(
value.window_management_behaviour.floating_layer_behaviour,
),
toggle_float_placement: Option::from(
value.window_management_behaviour.toggle_float_placement,
),
floating_layer_placement: Option::from(
value.window_management_behaviour.floating_layer_placement,
),
float_override_placement: Option::from(
value.window_management_behaviour.float_override_placement,
),
float_rule_placement: Option::from(
value.window_management_behaviour.float_rule_placement,
),
cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour),
cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour),
unmanaged_window_operation_behaviour: Option::from(
@@ -882,6 +926,7 @@ impl From<&WindowManager> for StaticConfig {
bar_configurations: None,
remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()),
floating_window_aspect_ratio: Option::from(*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock()),
window_handling_behaviour: Option::from(WINDOW_HANDLING_BEHAVIOUR.load()),
}
}
}
@@ -1169,6 +1214,10 @@ impl StaticConfig {
}
}
if let Some(behaviour) = self.window_handling_behaviour {
WINDOW_HANDLING_BEHAVIOUR.store(behaviour);
}
Ok(())
}
@@ -1223,6 +1272,16 @@ impl StaticConfig {
.window_container_behaviour
.unwrap_or(WindowContainerBehaviour::Create),
float_override: value.float_override.unwrap_or_default(),
floating_layer_override: false, // this value is always automatically calculated
floating_layer_behaviour: FloatingLayerBehaviour::default(),
toggle_float_placement: value
.toggle_float_placement
.unwrap_or(Placement::CenterAndResize),
floating_layer_placement: value
.floating_layer_placement
.unwrap_or(Placement::Center),
float_override_placement: value.float_override_placement.unwrap_or(Placement::None),
float_rule_placement: value.float_rule_placement.unwrap_or(Placement::None),
},
cross_monitor_move_behaviour: value
.cross_monitor_move_behaviour
@@ -1240,7 +1299,7 @@ impl StaticConfig {
has_pending_raise_op: false,
pending_move_op: Arc::new(None),
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
uncloack_to_ignore: 0,
uncloak_to_ignore: 0,
known_hwnds: HashMap::new(),
};
@@ -1332,6 +1391,7 @@ impl StaticConfig {
monitor.set_container_padding(monitor_config.container_padding);
monitor.set_workspace_padding(monitor_config.workspace_padding);
monitor.set_wallpaper(monitor_config.wallpaper.clone());
monitor.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
monitor.update_workspaces_globals(offset);
for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() {
@@ -1417,6 +1477,7 @@ impl StaticConfig {
);
m.set_container_padding(monitor_config.container_padding);
m.set_workspace_padding(monitor_config.workspace_padding);
m.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
m.update_workspaces_globals(offset);
@@ -1503,6 +1564,8 @@ impl StaticConfig {
);
monitor.set_container_padding(monitor_config.container_padding);
monitor.set_workspace_padding(monitor_config.workspace_padding);
monitor.set_wallpaper(monitor_config.wallpaper.clone());
monitor.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
monitor.update_workspaces_globals(offset);
@@ -1589,6 +1652,7 @@ impl StaticConfig {
);
m.set_container_padding(monitor_config.container_padding);
m.set_workspace_padding(monitor_config.workspace_padding);
m.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
m.update_workspaces_globals(offset);
@@ -1605,41 +1669,32 @@ impl StaticConfig {
wm.enforce_workspace_rules()?;
if let Some(enabled) = value.border {
border_manager::BORDER_ENABLED.store(enabled, Ordering::SeqCst);
}
if let Some(val) = value.window_container_behaviour {
wm.window_management_behaviour.current_behaviour = val;
}
if let Some(val) = value.float_override {
wm.window_management_behaviour.float_override = val;
}
if let Some(val) = value.cross_monitor_move_behaviour {
wm.cross_monitor_move_behaviour = val;
}
if let Some(val) = value.cross_boundary_behaviour {
wm.cross_boundary_behaviour = val;
}
if let Some(val) = value.unmanaged_window_operation_behaviour {
wm.unmanaged_window_operation_behaviour = val;
}
if let Some(val) = value.resize_delta {
wm.resize_delta = val;
}
if let Some(val) = value.mouse_follows_focus {
wm.mouse_follows_focus = val;
}
border_manager::BORDER_ENABLED.store(value.border.unwrap_or(true), Ordering::SeqCst);
wm.window_management_behaviour.current_behaviour =
value.window_container_behaviour.unwrap_or_default();
wm.window_management_behaviour.float_override = value.float_override.unwrap_or_default();
wm.window_management_behaviour.floating_layer_behaviour =
value.floating_layer_behaviour.unwrap_or_default();
wm.window_management_behaviour.toggle_float_placement = value
.toggle_float_placement
.unwrap_or(Placement::CenterAndResize);
wm.window_management_behaviour.floating_layer_placement =
value.floating_layer_placement.unwrap_or(Placement::Center);
wm.window_management_behaviour.float_override_placement =
value.float_override_placement.unwrap_or(Placement::None);
wm.window_management_behaviour.float_rule_placement =
value.float_rule_placement.unwrap_or(Placement::None);
wm.cross_monitor_move_behaviour = value.cross_monitor_move_behaviour.unwrap_or_default();
wm.cross_boundary_behaviour = value.cross_boundary_behaviour.unwrap_or_default();
wm.unmanaged_window_operation_behaviour = value
.unmanaged_window_operation_behaviour
.unwrap_or_default();
wm.resize_delta = value.resize_delta.unwrap_or(50);
wm.mouse_follows_focus = value.mouse_follows_focus.unwrap_or(true);
wm.work_area_offset = value.global_work_area_offset;
wm.focus_follows_mouse = value.focus_follows_mouse;
match value.focus_follows_mouse {
match wm.focus_follows_mouse {
None => WindowsApi::disable_focus_follows_mouse()?,
Some(FocusFollowsMouseImplementation::Windows) => {
WindowsApi::enable_focus_follows_mouse()?;
@@ -1647,8 +1702,6 @@ impl StaticConfig {
Some(FocusFollowsMouseImplementation::Komorebi) => {}
};
wm.focus_follows_mouse = value.focus_follows_mouse;
let monitor_count = wm.monitors().len();
for i in 0..monitor_count {

View File

@@ -203,8 +203,8 @@ impl RenderDispatcher for MovementRenderDispatcher {
fn render(&self, progress: f64) -> Result<()> {
let new_rect = self.start_rect.lerp(self.target_rect, progress, self.style);
// using MoveWindow because it runs faster than SetWindowPos
// so animation have more fps and feel smoother
// we don't check WINDOW_HANDLING_BEHAVIOUR here because animations
// are always run on a separate thread
WindowsApi::move_window(self.hwnd, &new_rect, false)?;
WindowsApi::invalidate_rect(self.hwnd, None, false);
@@ -212,7 +212,9 @@ impl RenderDispatcher for MovementRenderDispatcher {
}
fn post_render(&self) -> Result<()> {
WindowsApi::position_window(self.hwnd, &self.target_rect, self.top)?;
// we don't add the async_window_pos flag here because animations
// are always run on a separate thread
WindowsApi::position_window(self.hwnd, &self.target_rect, self.top, false)?;
if ANIMATION_MANAGER
.lock()
.count_in_progress(MovementRenderDispatcher::PREFIX)
@@ -411,12 +413,18 @@ impl Window {
Ok(())
}
pub fn center(&mut self, work_area: &Rect) -> Result<()> {
let (aspect_ratio_width, aspect_ratio_height) = FLOATING_WINDOW_TOGGLE_ASPECT_RATIO
.lock()
.width_and_height();
let target_height = work_area.bottom / 2;
let target_width = (target_height * aspect_ratio_width) / aspect_ratio_height;
pub fn center(&mut self, work_area: &Rect, resize: bool) -> Result<()> {
let (target_width, target_height) = if resize {
let (aspect_ratio_width, aspect_ratio_height) = FLOATING_WINDOW_TOGGLE_ASPECT_RATIO
.lock()
.width_and_height();
let target_height = work_area.bottom / 2;
let target_width = (target_height * aspect_ratio_width) / aspect_ratio_height;
(target_width, target_height)
} else {
let current_rect = WindowsApi::window_rect(self.hwnd)?;
(current_rect.right, current_rect.bottom)
};
let x = work_area.left + ((work_area.right - target_width) / 2);
let y = work_area.top + ((work_area.bottom - target_height) / 2);
@@ -461,7 +469,7 @@ impl Window {
AnimationEngine::animate(render_dispatcher, duration)
} else {
WindowsApi::position_window(self.hwnd, layout, top)
WindowsApi::position_window(self.hwnd, layout, top, true)
}
}

View File

@@ -80,7 +80,6 @@ use crate::workspace::WorkspaceLayer;
use crate::BorderColours;
use crate::Colour;
use crate::CrossBoundaryBehaviour;
use crate::FloatingLayerBehaviour;
use crate::Rgb;
use crate::CUSTOM_FFM;
use crate::DATA_DIR;
@@ -121,7 +120,7 @@ pub struct WindowManager {
pub has_pending_raise_op: bool,
pub pending_move_op: Arc<Option<(usize, usize, isize)>>,
pub already_moved_window_handles: Arc<Mutex<HashSet<isize>>>,
pub uncloack_to_ignore: usize,
pub uncloak_to_ignore: usize,
/// Maps each known window hwnd to the (monitor, workspace) index pair managing it
pub known_hwnds: HashMap<isize, (usize, usize)>,
}
@@ -360,6 +359,7 @@ impl From<&WindowManager> for State {
container_padding: monitor.container_padding,
workspace_padding: monitor.workspace_padding,
wallpaper: monitor.wallpaper.clone(),
floating_layer_behaviour: monitor.floating_layer_behaviour,
})
.collect::<VecDeque<_>>();
stripped_monitors.focus(wm.monitors.focused_idx());
@@ -438,7 +438,7 @@ impl WindowManager {
work_area_offset: None,
window_management_behaviour: WindowManagementBehaviour::default(),
cross_monitor_move_behaviour: MoveBehaviour::Swap,
cross_boundary_behaviour: CrossBoundaryBehaviour::Workspace,
cross_boundary_behaviour: CrossBoundaryBehaviour::Monitor,
unmanaged_window_operation_behaviour: OperationBehaviour::Op,
resize_delta: 50,
focus_follows_mouse: None,
@@ -447,7 +447,7 @@ impl WindowManager {
has_pending_raise_op: false,
pending_move_op: Arc::new(None),
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
uncloack_to_ignore: 0,
uncloak_to_ignore: 0,
known_hwnds: HashMap::new(),
})
}
@@ -645,24 +645,40 @@ impl WindowManager {
self.window_management_behaviour.current_behaviour
};
let mut float_override = if let Some(float_override) = workspace.float_override() {
let float_override = if let Some(float_override) = workspace.float_override() {
*float_override
} else {
self.window_management_behaviour.float_override
};
// If the workspace layer is `Floating` and the floating layer behaviour is `Float`,
// then consider it as if it had float override so that new windows spawn as floating
float_override = float_override
|| (matches!(workspace.layer, WorkspaceLayer::Floating)
&& matches!(
workspace.floating_layer_behaviour,
FloatingLayerBehaviour::Float
));
let floating_layer_behaviour =
if let Some(behaviour) = workspace.floating_layer_behaviour() {
behaviour
} else {
monitor
.floating_layer_behaviour()
.unwrap_or(self.window_management_behaviour.floating_layer_behaviour)
};
// If the workspace layer is `Floating` and the floating layer behaviour should
// float then change floating_layer_override to true so that new windows spawn
// as floating
let floating_layer_override = matches!(workspace.layer, WorkspaceLayer::Floating)
&& floating_layer_behaviour.should_float();
return WindowManagementBehaviour {
current_behaviour,
float_override,
floating_layer_override,
floating_layer_behaviour,
toggle_float_placement: self.window_management_behaviour.toggle_float_placement,
floating_layer_placement: self
.window_management_behaviour
.floating_layer_placement,
float_override_placement: self
.window_management_behaviour
.float_override_placement,
float_rule_placement: self.window_management_behaviour.float_rule_placement,
};
}
}
@@ -670,6 +686,12 @@ impl WindowManager {
WindowManagementBehaviour {
current_behaviour: WindowContainerBehaviour::Create,
float_override: self.window_management_behaviour.float_override,
floating_layer_override: self.window_management_behaviour.floating_layer_override,
floating_layer_behaviour: self.window_management_behaviour.floating_layer_behaviour,
toggle_float_placement: self.window_management_behaviour.toggle_float_placement,
floating_layer_placement: self.window_management_behaviour.floating_layer_placement,
float_override_placement: self.window_management_behaviour.float_override_placement,
float_rule_placement: self.window_management_behaviour.float_rule_placement,
}
}
@@ -1212,7 +1234,7 @@ impl WindowManager {
// That workspace reconciliation would focus the window on the origin monitor.
// So we need to ignore the uncloak events produced by the origin workspace
// restore to avoid that issue.
self.uncloack_to_ignore = uncloack_amount;
self.uncloak_to_ignore = uncloack_amount;
}
} else if origin_workspace
.maximized_window()
@@ -1495,7 +1517,7 @@ impl WindowManager {
}
}
WindowsApi::position_window(window.hwnd, &rect, false)?;
WindowsApi::position_window(window.hwnd, &rect, false, true)?;
if mouse_follows_focus {
WindowsApi::center_cursor_in_rect(&rect)?;
}
@@ -1901,6 +1923,18 @@ impl WindowManager {
.focused_workspace_mut()
.ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?;
if target_workspace.monocle_container().is_some() {
for container in target_workspace.containers_mut() {
container.restore();
}
for window in target_workspace.floating_windows_mut() {
window.restore();
}
target_workspace.reintegrate_monocle_container()?;
}
if let Some(window) = floating_window {
target_workspace.floating_windows_mut().push_back(window);
target_workspace.set_layer(WorkspaceLayer::Floating);
@@ -2499,7 +2533,7 @@ impl WindowManager {
}
}
WindowsApi::position_window(window.hwnd, &rect, false)?;
WindowsApi::position_window(window.hwnd, &rect, false, true)?;
if mouse_follows_focus {
WindowsApi::center_cursor_in_rect(&rect)?;
}
@@ -3137,6 +3171,8 @@ impl WindowManager {
let work_area = self.focused_monitor_work_area()?;
let toggle_float_placement = self.window_management_behaviour.toggle_float_placement;
let workspace = self.focused_workspace_mut()?;
workspace.new_floating_window()?;
@@ -3145,7 +3181,9 @@ impl WindowManager {
.back_mut()
.ok_or_else(|| anyhow!("there is no floating window"))?;
window.center(&work_area)?;
if toggle_float_placement.should_center() {
window.center(&work_area, toggle_float_placement.should_resize())?;
}
window.focus(self.mouse_follows_focus)?;
Ok(())
@@ -5017,4 +5055,534 @@ mod tests {
assert!(*workspace.tile());
}
}
#[test]
fn test_toggle_lock() {
let (mut wm, _context) = setup_window_manager();
{
// Add monitor with default workspace to
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
let workspace = m.focused_workspace_mut().unwrap();
// Create containers to add to the workspace
for _ in 0..3 {
let container = Container::default();
workspace.add_container_to_back(container);
}
wm.monitors_mut().push_back(m);
}
{
// Ensure container 2 is not locked
let workspace = wm.focused_workspace_mut().unwrap();
assert!(!workspace.locked_containers().contains(&2));
}
// Toggle lock on focused container
wm.toggle_lock().unwrap();
{
// Ensure container 2 is locked
let workspace = wm.focused_workspace_mut().unwrap();
assert!(workspace.locked_containers().contains(&2));
}
// Toggle lock on focused container
wm.toggle_lock().unwrap();
{
// Ensure container 2 is not locked
let workspace = wm.focused_workspace_mut().unwrap();
assert!(!workspace.locked_containers().contains(&2));
}
}
#[test]
fn test_float_window() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create a container
let mut container = Container::default();
// Add three windows to the container
for i in 0..3 {
container.windows_mut().push_back(Window::from(i));
}
// Should have 3 windows in the container
assert_eq!(container.windows().len(), 3);
// Add the container to the workspace
let workspace = m.focused_workspace_mut().unwrap();
workspace.add_container_to_back(container);
// Add monitor to the window manager
wm.monitors_mut().push_back(m);
}
// Add focused window to floating window list
wm.float_window().ok();
{
let workspace = wm.focused_workspace().unwrap();
let floating_windows = workspace.floating_windows();
let container = workspace.focused_container().unwrap();
// Hwnd 0 should be added to floating_windows
assert_eq!(floating_windows[0].hwnd, 0);
// Should have a length of 1
assert_eq!(floating_windows.len(), 1);
// Should have 2 windows in the container
assert_eq!(container.windows().len(), 2);
// Should be focused on window 1
assert_eq!(container.focused_window(), Some(&Window { hwnd: 1 }));
}
// Add focused window to floating window list
wm.float_window().ok();
{
let workspace = wm.focused_workspace().unwrap();
let floating_windows = workspace.floating_windows();
let container = workspace.focused_container().unwrap();
// Hwnd 1 should be added to floating_windows
assert_eq!(floating_windows[1].hwnd, 1);
// Should have a length of 2
assert_eq!(floating_windows.len(), 2);
// Should have 1 window in the container
assert_eq!(container.windows().len(), 1);
// Should be focused on window 2
assert_eq!(container.focused_window(), Some(&Window { hwnd: 2 }));
}
}
#[test]
fn test_maximize_and_unmaximize_window() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create a container
let mut container = Container::default();
// Add three windows to the container
for i in 0..3 {
container.windows_mut().push_back(Window::from(i));
}
// Should have 3 windows in the container
assert_eq!(container.windows().len(), 3);
// Add the container to the workspace
let workspace = m.focused_workspace_mut().unwrap();
workspace.add_container_to_back(container);
// Add monitor to the window manager
wm.monitors_mut().push_back(m);
}
{
// No windows should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, None);
}
// Maximize the focused window
wm.maximize_window().ok();
{
// Window 0 should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, Some(Window::from(0)));
}
wm.unmaximize_window().ok();
{
// No windows should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, None);
}
// Focus container at index 1
wm.focused_workspace_mut().unwrap().focus_container(1);
{
// Focus the window at index 1
let container = wm.focused_container_mut().unwrap();
container.focus_window(1);
}
// Maximize the focused window
wm.maximize_window().ok();
{
// Window 2 should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, Some(Window::from(2)));
}
wm.unmaximize_window().ok();
{
// No windows should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, None);
}
}
#[test]
fn test_toggle_maximize() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create a container
let mut container = Container::default();
// Add three windows to the container
for i in 0..3 {
container.windows_mut().push_back(Window::from(i));
}
// Should have 3 windows in the container
assert_eq!(container.windows().len(), 3);
// Add the container to the workspace
let workspace = m.focused_workspace_mut().unwrap();
workspace.add_container_to_back(container);
// Add monitor to the window manager
wm.monitors_mut().push_back(m);
}
// Toggle maximize on
wm.toggle_maximize().ok();
{
// Window 0 should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, Some(Window::from(0)));
}
// Toggle maximize off
wm.toggle_maximize().ok();
{
// No windows should be maximized
let workspace = wm.focused_workspace().unwrap();
let maximized_window = workspace.maximized_window();
assert_eq!(*maximized_window, None);
}
}
#[test]
fn test_monocle_on_and_monocle_off() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create a container
let mut container = Container::default();
// Add a window to the container
container.windows_mut().push_back(Window::from(1));
// Should have 1 window in the container
assert_eq!(container.windows().len(), 1);
// Add the container to the workspace
let workspace = m.focused_workspace_mut().unwrap();
workspace.add_container_to_back(container);
// Add monitor to the window manager
wm.monitors_mut().push_back(m);
}
// Move container to monocle container
wm.monocle_on().ok();
{
// Container should be a monocle container
let monocle_container = wm
.focused_workspace()
.unwrap()
.monocle_container()
.as_ref()
.unwrap();
assert_eq!(monocle_container.windows().len(), 1);
assert_eq!(monocle_container.windows()[0].hwnd, 1);
}
{
// Should not have any containers
let container = wm.focused_workspace().unwrap();
assert_eq!(container.containers().len(), 0);
}
// Move monocle container to regular container
wm.monocle_off().ok();
{
// Should have 1 container in the workspace
let container = wm.focused_workspace().unwrap();
assert_eq!(container.containers().len(), 1);
assert_eq!(container.containers()[0].windows()[0].hwnd, 1);
}
{
// No windows should be in the monocle container
let monocle_container = wm.focused_workspace().unwrap().monocle_container();
assert_eq!(*monocle_container, None);
}
}
#[test]
fn test_toggle_monocle() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create a container
let mut container = Container::default();
// Add a window to the container
container.windows_mut().push_back(Window::from(1));
// Should have 1 window in the container
assert_eq!(container.windows().len(), 1);
// Add the container to the workspace
let workspace = m.focused_workspace_mut().unwrap();
workspace.add_container_to_back(container);
// Add monitor to the window manager
wm.monitors_mut().push_back(m);
}
// Toggle monocle on
wm.toggle_monocle().ok();
{
// Container should be a monocle container
let monocle_container = wm
.focused_workspace()
.unwrap()
.monocle_container()
.as_ref()
.unwrap();
assert_eq!(monocle_container.windows().len(), 1);
assert_eq!(monocle_container.windows()[0].hwnd, 1);
}
{
// Should not have any containers
let container = wm.focused_workspace().unwrap();
assert_eq!(container.containers().len(), 0);
}
// Toggle monocle off
wm.toggle_monocle().ok();
{
// Should have 1 container in the workspace
let container = wm.focused_workspace().unwrap();
assert_eq!(container.containers().len(), 1);
assert_eq!(container.containers()[0].windows()[0].hwnd, 1);
}
{
// No windows should be in the monocle container
let monocle_container = wm.focused_workspace().unwrap().monocle_container();
assert_eq!(*monocle_container, None);
}
}
#[test]
fn test_ensure_named_workspace_for_monitor() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Add the monitor to the window manager
wm.monitors_mut().push_back(m);
}
{
// Create a monitor
let m = monitor::new(
1,
Rect::default(),
Rect::default(),
"TestMonitor1".to_string(),
"TestDevice1".to_string(),
"TestDeviceID1".to_string(),
Some("TestMonitorID1".to_string()),
);
// Add the monitor to the window manager
wm.monitors_mut().push_back(m);
}
// Workspace names list
let mut workspace_names = vec!["Workspace".to_string(), "Workspace1".to_string()];
// Ensure workspaces for monitor 1
wm.ensure_named_workspaces_for_monitor(1, &workspace_names)
.ok();
{
// Monitor 1 should have 2 workspaces with names "Workspace" and "Workspace1"
let monitor = wm.monitors().get(1).unwrap();
let workspaces = monitor.workspaces();
assert_eq!(workspaces.len(), workspace_names.len());
for (i, workspace) in workspaces.iter().enumerate() {
assert_eq!(workspace.name(), &Some(workspace_names[i].clone()));
}
}
// Add more workspaces to list
workspace_names.push("Workspace2".to_string());
workspace_names.push("Workspace3".to_string());
// Ensure workspaces for monitor 0
wm.ensure_named_workspaces_for_monitor(0, &workspace_names)
.ok();
{
// Monitor 0 should have 4 workspaces with names "Workspace", "Workspace1",
// "Workspace2" and "Workspace3"
let monitor = wm.monitors().front().unwrap();
let workspaces = monitor.workspaces();
assert_eq!(workspaces.len(), workspace_names.len());
for (i, workspace) in workspaces.iter().enumerate() {
assert_eq!(workspace.name(), &Some(workspace_names[i].clone()));
}
}
}
#[test]
fn test_add_window_handle_to_move_based_on_workspace_rule() {
let (wm, _context) = setup_window_manager();
// Mock Data representing a window and its workspace/movement details
let window_title = String::from("TestWindow");
let hwnd = 12345;
let origin_monitor_idx = 0;
let origin_workspace_idx = 0;
let target_monitor_idx = 2;
let target_workspace_idx = 3;
let floating = false;
// Empty vector to hold workspace rule enforcement operations
let mut to_move: Vec<EnforceWorkspaceRuleOp> = Vec::new();
// Call the function to add a window movement operation based on workspace rules
wm.add_window_handle_to_move_based_on_workspace_rule(
&window_title,
hwnd,
origin_monitor_idx,
origin_workspace_idx,
target_monitor_idx,
target_workspace_idx,
floating,
&mut to_move,
);
// Verify that the vector contains the expected operation with the correct values
assert_eq!(to_move.len(), 1);
let op = &to_move[0];
assert_eq!(op.hwnd, hwnd); // 12345
assert_eq!(op.origin_monitor_idx, origin_monitor_idx); // 0
assert_eq!(op.origin_workspace_idx, origin_workspace_idx); // 0
assert_eq!(op.target_monitor_idx, target_monitor_idx); // 2
assert_eq!(op.target_workspace_idx, target_workspace_idx); // 3
assert_eq!(op.floating, floating); // false
}
}

View File

@@ -106,6 +106,7 @@ use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
use windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
use windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
use windows::Win32::UI::WindowsAndMessaging::ShowWindowAsync;
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
@@ -125,6 +126,7 @@ use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING;
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
use windows::Win32::UI::WindowsAndMessaging::SWP_ASYNCWINDOWPOS;
use windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE;
use windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE;
use windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW;
@@ -157,10 +159,12 @@ use crate::ring::Ring;
use crate::set_window_position::SetWindowPosition;
use crate::windows_callbacks;
use crate::Window;
use crate::WindowHandlingBehaviour;
use crate::WindowManager;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::WINDOW_HANDLING_BEHAVIOUR;
macro_rules! as_ptr {
($value:expr) => {
@@ -473,7 +477,12 @@ impl WindowsApi {
/// position window resizes the target window to the given layout, adjusting
/// the layout to account for any window shadow borders (the window painted
/// region will match layout on completion).
pub fn position_window(hwnd: isize, layout: &Rect, top: bool) -> Result<()> {
pub fn position_window(
hwnd: isize,
layout: &Rect,
top: bool,
with_async_window_pos: bool,
) -> Result<()> {
let hwnd = HWND(as_ptr!(hwnd));
let mut flags = SetWindowPosition::NO_ACTIVATE
@@ -484,6 +493,19 @@ impl WindowsApi {
// If the request is to place the window on top, then HWND_TOP will take
// effect, otherwise pass NO_Z_ORDER that will cause set_window_pos to
// ignore the z-order paramter.
// By default SetWindowPos waits for target window's WindowProc thread
// to process the message, so we have to use ASYNC_WINDOW_POS to avoid
// blocking our thread in case the target window is not responding.
if with_async_window_pos
&& matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
)
{
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
if !top {
flags |= SetWindowPosition::NO_Z_ORDER;
}
@@ -518,11 +540,18 @@ impl WindowsApi {
/// Raise the window to the top of the Z order, but do not activate or focus
/// it. Use raise_and_focus_window to activate and focus a window.
pub fn raise_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE
let mut flags = SetWindowPosition::NO_MOVE
| SetWindowPosition::NO_SIZE
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW;
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
let position = HWND_TOP;
Self::set_window_pos(
HWND(as_ptr!(hwnd)),
@@ -535,11 +564,18 @@ impl WindowsApi {
/// Lower the window to the bottom of the Z order, but do not activate or focus
/// it.
pub fn lower_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE
let mut flags = SetWindowPosition::NO_MOVE
| SetWindowPosition::NO_SIZE
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW;
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
let position = HWND_BOTTOM;
Self::set_window_pos(
HWND(as_ptr!(hwnd)),
@@ -550,12 +586,17 @@ impl WindowsApi {
}
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> {
let flags = {
SetWindowPosition::NO_SEND_CHANGING
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::NO_REDRAW
| SetWindowPosition::SHOW_WINDOW
};
let mut flags = SetWindowPosition::NO_SEND_CHANGING
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::NO_REDRAW
| SetWindowPosition::SHOW_WINDOW;
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
Self::set_window_pos(
HWND(as_ptr!(hwnd)),
@@ -581,6 +622,7 @@ impl WindowsApi {
.process()
}
/// move_windows calls MoveWindow, but cannot be called with async window pos, so it might hang
pub fn move_window(hwnd: isize, layout: &Rect, repaint: bool) -> Result<()> {
let hwnd = HWND(as_ptr!(hwnd));
@@ -598,9 +640,18 @@ impl WindowsApi {
// BOOL is returned but does not signify whether or not the operation was succesful
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
// TODO: error handling
unsafe {
let _ = ShowWindow(HWND(as_ptr!(hwnd)), command);
};
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
unsafe {
let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command);
};
} else {
unsafe {
let _ = ShowWindow(HWND(as_ptr!(hwnd)), command);
};
}
}
pub fn minimize_window(hwnd: isize) {
@@ -656,7 +707,7 @@ impl WindowsApi {
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS,
)
.process();
SetForegroundWindow(HWND(as_ptr!(hwnd)))

View File

@@ -97,8 +97,8 @@ pub struct Workspace {
pub globals: WorkspaceGlobals,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub layer: WorkspaceLayer,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub floating_layer_behaviour: FloatingLayerBehaviour,
#[getset(get_copy = "pub", get_mut = "pub", set = "pub")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub locked_containers: BTreeSet<usize>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
@@ -192,6 +192,7 @@ pub struct WorkspaceGlobals {
pub work_area_offset: Option<Rect>,
pub window_based_work_area_offset: Option<Rect>,
pub window_based_work_area_offset_limit: isize,
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
}
impl Workspace {
@@ -264,7 +265,7 @@ impl Workspace {
self.set_float_override(config.float_override);
self.set_layout_flip(config.layout_flip);
self.set_floating_layer_behaviour(config.floating_layer_behaviour.unwrap_or_default());
self.set_floating_layer_behaviour(config.floating_layer_behaviour);
self.set_wallpaper(config.wallpaper.clone());
self.set_workspace_config(Some(config.clone()));
@@ -480,6 +481,9 @@ impl Workspace {
return Ok(());
}
// make sure we are never holding on to empty containers
self.containers_mut().retain(|c| !c.windows().is_empty());
let container_padding = self
.container_padding()
.or(self.globals().container_padding)
@@ -656,84 +660,6 @@ impl Workspace {
Ok(())
}
pub fn reap_orphans(&mut self) -> Result<(usize, usize)> {
let mut hwnds = vec![];
let mut floating_hwnds = vec![];
let mut remove_monocle = false;
let mut remove_maximized = false;
if let Some(monocle) = &self.monocle_container {
let window_count = monocle.windows().len();
let mut orphan_count = 0;
for window in monocle.windows() {
if !window.is_window() {
hwnds.push(window.hwnd);
orphan_count += 1;
}
}
remove_monocle = orphan_count == window_count;
}
if let Some(window) = &self.maximized_window {
if !window.is_window() {
hwnds.push(window.hwnd);
remove_maximized = true;
}
}
for window in self.visible_windows().into_iter().flatten() {
if !window.is_window()
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
// docs is closed
//
// I hate every single person who worked on Microsoft Office 365, especially Word
|| !window.is_visible()
{
hwnds.push(window.hwnd);
}
}
for window in self.floating_windows() {
if !window.is_window() {
floating_hwnds.push(window.hwnd);
}
}
for hwnd in &hwnds {
tracing::debug!("reaping hwnd: {}", hwnd);
self.remove_window(*hwnd)?;
}
for hwnd in &floating_hwnds {
tracing::debug!("reaping floating hwnd: {}", hwnd);
self.floating_windows_mut()
.retain(|w| !floating_hwnds.contains(&w.hwnd));
}
let mut container_ids = vec![];
for container in self.containers() {
if container.windows().is_empty() {
container_ids.push(container.id().clone());
}
}
self.containers_mut()
.retain(|c| !container_ids.contains(c.id()));
if remove_monocle {
self.set_monocle_container(None);
}
if remove_maximized {
self.set_maximized_window(None);
}
Ok((hwnds.len() + floating_hwnds.len(), container_ids.len()))
}
pub fn container_for_window(&self, hwnd: isize) -> Option<&Container> {
self.containers().get(self.container_idx_for_window(hwnd)?)
}

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebic-no-console"
version = "0.1.36"
version = "0.1.37"
description = "The command-line interface (without a console) for Komorebi, a tiling window manager for Windows"
repository = "https://github.com/LGUG2Z/komorebi"
edition = "2021"

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebic"
version = "0.1.36"
version = "0.1.37"
description = "The command-line interface for Komorebi, a tiling window manager for Windows"
repository = "https://github.com/LGUG2Z/komorebi"
edition = "2021"
@@ -36,7 +36,7 @@ shadow-rs = { workspace = true }
[features]
default = ["schemars"]
schemars = ["dep:schemars"]
schemars = ["dep:schemars", "komorebi-client/schemars"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(FALSE)'] }

View File

@@ -1003,6 +1003,8 @@ enum SubCommand {
GlobalState,
/// Launch the komorebi-gui debugging tool
Gui,
/// Toggle the komorebi-shortcuts helper
ToggleShortcuts,
/// Show a JSON representation of visible windows
VisibleWindows,
/// Show information about connected monitors
@@ -2713,6 +2715,15 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
SubCommand::Gui => {
Command::new("komorebi-gui").spawn()?;
}
SubCommand::ToggleShortcuts => {
let output = Command::new("taskkill")
.args(["/F", "/IM", "komorebi-shortcuts.exe"])
.output()?;
if !output.status.success() {
Command::new("komorebi-shortcuts.exe").spawn()?;
}
}
SubCommand::VisibleWindows => {
print_query(&SocketMessage::VisibleWindows);
}

View File

@@ -49,37 +49,40 @@ plugins:
nav:
- Komorebi:
- index.md
- Design: design.md
- Getting started:
- Installation: installation.md
- Example configurations: example-configurations.md
- Troubleshooting: troubleshooting.md
- Usage:
- usage/focusing-windows.md
- usage/moving-windows.md
- usage/stacking-windows.md
- usage/focusing-workspaces.md
- usage/moving-windows-across-workspaces.md
- Common workflows:
- common-workflows/komorebi-config-home.md
- common-workflows/autostart.md
- common-workflows/animations.md
- common-workflows/autohotkey.md
- common-workflows/borders.md
- common-workflows/stackbar.md
- common-workflows/remove-gaps.md
- common-workflows/ignore-windows.md
- common-workflows/force-manage-windows.md
- common-workflows/floating-applications.md
- common-workflows/tray-and-multi-window-applications.md
- common-workflows/mouse-follows-focus.md
- common-workflows/dynamic-layout-switching.md
- common-workflows/set-display-index.md
- common-workflows/multiple-bar-instances.md
- common-workflows/multi-monitor-setup.md
- Configuration reference: https://komorebi.lgug2z.com/schema
- Bar reference: https://komorebi-bar.lgug2z.com/schema
- About:
- index.md
- design.md
- Getting started:
- Installation: installation.md
- Example configurations: example-configurations.md
- Troubleshooting: troubleshooting.md
- Usage:
- usage/focusing-windows.md
- usage/moving-windows.md
- usage/stacking-windows.md
- usage/focusing-workspaces.md
- usage/moving-windows-across-workspaces.md
- Komorebi Configuration:
- Schema: https://komorebi.lgug2z.com/schema
- Komorebi Bar Configuration:
- Schema: https://komorebi-bar.lgug2z.com/schema
- Common workflows:
- common-workflows/komorebi-config-home.md
- common-workflows/autostart.md
- common-workflows/animations.md
- common-workflows/autohotkey.md
- common-workflows/borders.md
- common-workflows/stackbar.md
- common-workflows/remove-gaps.md
- common-workflows/ignore-windows.md
- common-workflows/force-manage-windows.md
- common-workflows/floating-applications.md
- common-workflows/tray-and-multi-window-applications.md
- common-workflows/mouse-follows-focus.md
- common-workflows/dynamic-layout-switching.md
- common-workflows/set-display-index.md
- common-workflows/multiple-bar-instances.md
- common-workflows/multi-monitor-setup.md
- CLI reference:
- cli/quickstart.md
- cli/start.md
@@ -250,4 +253,4 @@ nav:
- cli/static-config-schema.md
- cli/generate-static-config.md
- cli/enable-autostart.md
- cli/disable-autostart.md
- cli/disable-autostart.md

View File

@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "KomobarConfig",
"description": "The `komorebi.bar.json` configuration file reference for `v0.1.36`",
"description": "The `komorebi.bar.json` configuration file reference for `v0.1.37`",
"type": "object",
"required": [
"left_widgets",
@@ -14,6 +14,122 @@
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"required": [
"Applications"
],
"properties": {
"Applications": {
"type": "object",
"required": [
"enable",
"items"
],
"properties": {
"display": {
"description": "Default display format for all applications (optional). Could be overridden per application. Defaults to `Icon`.",
"oneOf": [
{
"description": "Show only the application icon.",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show only the application name as text.",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show both the application icon and name.",
"type": "string",
"enum": [
"IconAndText"
]
}
]
},
"enable": {
"description": "Enables or disables the applications widget.",
"type": "boolean"
},
"items": {
"description": "List of configured applications to display.",
"type": "array",
"items": {
"type": "object",
"required": [
"command",
"name"
],
"properties": {
"command": {
"description": "Command to execute (e.g. path to the application or shell command).",
"type": "string"
},
"display": {
"description": "Display format for this application button (optional). Overrides global format if set.",
"oneOf": [
{
"description": "Show only the application icon.",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show only the application name as text.",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show both the application icon and name.",
"type": "string",
"enum": [
"IconAndText"
]
}
]
},
"enable": {
"description": "Whether to enable this application button (optional). Inherits from the global `Applications` setting if omitted.",
"type": "boolean"
},
"icon": {
"description": "Optional icon: a path to an image or a text-based glyph (e.g., from Nerd Fonts). If not set, and if the `command` is a path to an executable, an icon might be extracted from it. Note: glyphs require a compatible `font_family`.",
"type": "string"
},
"name": {
"description": "Display name of the application.",
"type": "string"
},
"show_command_on_hover": {
"description": "Whether to show the launch command on hover (optional). Inherits from the global `Applications` setting if omitted.",
"type": "boolean"
}
}
}
},
"show_command_on_hover": {
"description": "Whether to show the launch command on hover (optional). Could be overridden per application. Defaults to `false` if not set.",
"type": "boolean"
},
"spacing": {
"description": "Horizontal spacing between application buttons.",
"type": "number",
"format": "float"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -1541,6 +1657,122 @@
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"required": [
"Applications"
],
"properties": {
"Applications": {
"type": "object",
"required": [
"enable",
"items"
],
"properties": {
"display": {
"description": "Default display format for all applications (optional). Could be overridden per application. Defaults to `Icon`.",
"oneOf": [
{
"description": "Show only the application icon.",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show only the application name as text.",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show both the application icon and name.",
"type": "string",
"enum": [
"IconAndText"
]
}
]
},
"enable": {
"description": "Enables or disables the applications widget.",
"type": "boolean"
},
"items": {
"description": "List of configured applications to display.",
"type": "array",
"items": {
"type": "object",
"required": [
"command",
"name"
],
"properties": {
"command": {
"description": "Command to execute (e.g. path to the application or shell command).",
"type": "string"
},
"display": {
"description": "Display format for this application button (optional). Overrides global format if set.",
"oneOf": [
{
"description": "Show only the application icon.",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show only the application name as text.",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show both the application icon and name.",
"type": "string",
"enum": [
"IconAndText"
]
}
]
},
"enable": {
"description": "Whether to enable this application button (optional). Inherits from the global `Applications` setting if omitted.",
"type": "boolean"
},
"icon": {
"description": "Optional icon: a path to an image or a text-based glyph (e.g., from Nerd Fonts). If not set, and if the `command` is a path to an executable, an icon might be extracted from it. Note: glyphs require a compatible `font_family`.",
"type": "string"
},
"name": {
"description": "Display name of the application.",
"type": "string"
},
"show_command_on_hover": {
"description": "Whether to show the launch command on hover (optional). Inherits from the global `Applications` setting if omitted.",
"type": "boolean"
}
}
}
},
"show_command_on_hover": {
"description": "Whether to show the launch command on hover (optional). Could be overridden per application. Defaults to `false` if not set.",
"type": "boolean"
},
"spacing": {
"description": "Horizontal spacing between application buttons.",
"type": "number",
"format": "float"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -3001,6 +3233,122 @@
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"required": [
"Applications"
],
"properties": {
"Applications": {
"type": "object",
"required": [
"enable",
"items"
],
"properties": {
"display": {
"description": "Default display format for all applications (optional). Could be overridden per application. Defaults to `Icon`.",
"oneOf": [
{
"description": "Show only the application icon.",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show only the application name as text.",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show both the application icon and name.",
"type": "string",
"enum": [
"IconAndText"
]
}
]
},
"enable": {
"description": "Enables or disables the applications widget.",
"type": "boolean"
},
"items": {
"description": "List of configured applications to display.",
"type": "array",
"items": {
"type": "object",
"required": [
"command",
"name"
],
"properties": {
"command": {
"description": "Command to execute (e.g. path to the application or shell command).",
"type": "string"
},
"display": {
"description": "Display format for this application button (optional). Overrides global format if set.",
"oneOf": [
{
"description": "Show only the application icon.",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show only the application name as text.",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show both the application icon and name.",
"type": "string",
"enum": [
"IconAndText"
]
}
]
},
"enable": {
"description": "Whether to enable this application button (optional). Inherits from the global `Applications` setting if omitted.",
"type": "boolean"
},
"icon": {
"description": "Optional icon: a path to an image or a text-based glyph (e.g., from Nerd Fonts). If not set, and if the `command` is a path to an executable, an icon might be extracted from it. Note: glyphs require a compatible `font_family`.",
"type": "string"
},
"name": {
"description": "Display name of the application.",
"type": "string"
},
"show_command_on_hover": {
"description": "Whether to show the launch command on hover (optional). Inherits from the global `Applications` setting if omitted.",
"type": "boolean"
}
}
}
},
"show_command_on_hover": {
"description": "Whether to show the launch command on hover (optional). Could be overridden per application. Defaults to `false` if not set.",
"type": "boolean"
},
"spacing": {
"description": "Horizontal spacing between application buttons.",
"type": "number",
"format": "float"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [

View File

@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "StaticConfig",
"description": "The `komorebi.json` static configuration file reference for `v0.1.36`",
"description": "The `komorebi.json` static configuration file reference for `v0.1.37`",
"type": "object",
"properties": {
"animation": {
@@ -55,74 +55,146 @@
{
"type": "object",
"additionalProperties": {
"type": "string",
"enum": [
"Linear",
"EaseInSine",
"EaseOutSine",
"EaseInOutSine",
"EaseInQuad",
"EaseOutQuad",
"EaseInOutQuad",
"EaseInCubic",
"EaseInOutCubic",
"EaseInQuart",
"EaseOutQuart",
"EaseInOutQuart",
"EaseInQuint",
"EaseOutQuint",
"EaseInOutQuint",
"EaseInExpo",
"EaseOutExpo",
"EaseInOutExpo",
"EaseInCirc",
"EaseOutCirc",
"EaseInOutCirc",
"EaseInBack",
"EaseOutBack",
"EaseInOutBack",
"EaseInElastic",
"EaseOutElastic",
"EaseInOutElastic",
"EaseInBounce",
"EaseOutBounce",
"EaseInOutBounce"
"oneOf": [
{
"type": "string",
"enum": [
"Linear",
"EaseInSine",
"EaseOutSine",
"EaseInOutSine",
"EaseInQuad",
"EaseOutQuad",
"EaseInOutQuad",
"EaseInCubic",
"EaseInOutCubic",
"EaseInQuart",
"EaseOutQuart",
"EaseInOutQuart",
"EaseInQuint",
"EaseOutQuint",
"EaseInOutQuint",
"EaseInExpo",
"EaseOutExpo",
"EaseInOutExpo",
"EaseInCirc",
"EaseOutCirc",
"EaseInOutCirc",
"EaseInBack",
"EaseOutBack",
"EaseInOutBack",
"EaseInElastic",
"EaseOutElastic",
"EaseInOutElastic",
"EaseInBounce",
"EaseOutBounce",
"EaseInOutBounce"
]
},
{
"type": "object",
"required": [
"CubicBezier"
],
"properties": {
"CubicBezier": {
"type": "array",
"items": [
{
"type": "number",
"format": "double"
},
{
"type": "number",
"format": "double"
},
{
"type": "number",
"format": "double"
},
{
"type": "number",
"format": "double"
}
],
"maxItems": 4,
"minItems": 4
}
},
"additionalProperties": false
}
]
}
},
{
"type": "string",
"enum": [
"Linear",
"EaseInSine",
"EaseOutSine",
"EaseInOutSine",
"EaseInQuad",
"EaseOutQuad",
"EaseInOutQuad",
"EaseInCubic",
"EaseInOutCubic",
"EaseInQuart",
"EaseOutQuart",
"EaseInOutQuart",
"EaseInQuint",
"EaseOutQuint",
"EaseInOutQuint",
"EaseInExpo",
"EaseOutExpo",
"EaseInOutExpo",
"EaseInCirc",
"EaseOutCirc",
"EaseInOutCirc",
"EaseInBack",
"EaseOutBack",
"EaseInOutBack",
"EaseInElastic",
"EaseOutElastic",
"EaseInOutElastic",
"EaseInBounce",
"EaseOutBounce",
"EaseInOutBounce"
"oneOf": [
{
"type": "string",
"enum": [
"Linear",
"EaseInSine",
"EaseOutSine",
"EaseInOutSine",
"EaseInQuad",
"EaseOutQuad",
"EaseInOutQuad",
"EaseInCubic",
"EaseInOutCubic",
"EaseInQuart",
"EaseOutQuart",
"EaseInOutQuart",
"EaseInQuint",
"EaseOutQuint",
"EaseInOutQuint",
"EaseInExpo",
"EaseOutExpo",
"EaseInOutExpo",
"EaseInCirc",
"EaseOutCirc",
"EaseInOutCirc",
"EaseInBack",
"EaseOutBack",
"EaseInOutBack",
"EaseInElastic",
"EaseOutElastic",
"EaseInOutElastic",
"EaseInBounce",
"EaseOutBounce",
"EaseInOutBounce"
]
},
{
"type": "object",
"required": [
"CubicBezier"
],
"properties": {
"CubicBezier": {
"type": "array",
"items": [
{
"type": "number",
"format": "double"
},
{
"type": "number",
"format": "double"
},
{
"type": "number",
"format": "double"
},
{
"type": "number",
"format": "double"
}
],
"maxItems": 4,
"minItems": 4
}
},
"additionalProperties": false
}
]
}
]
@@ -610,6 +682,58 @@
"description": "Enable or disable float override, which makes it so every new window opens in floating mode (default: false)",
"type": "boolean"
},
"float_override_placement": {
"description": "Determines the `Placement` to be used when spawning a window with float override active (default: None)",
"oneOf": [
{
"description": "Does not change the size or position of the window",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Center the window without changing the size",
"type": "string",
"enum": [
"Center"
]
},
{
"description": "Center the window and resize it according to the `AspectRatio`",
"type": "string",
"enum": [
"CenterAndResize"
]
}
]
},
"float_rule_placement": {
"description": "Determines the `Placement` to be used when spawning a window that matches a 'floating_applications' rule (default: None)",
"oneOf": [
{
"description": "Does not change the size or position of the window",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Center the window without changing the size",
"type": "string",
"enum": [
"Center"
]
},
{
"description": "Center the window and resize it according to the `AspectRatio`",
"type": "string",
"enum": [
"CenterAndResize"
]
}
]
},
"floating_applications": {
"description": "Identify applications which should be managed as floating windows",
"type": "array",
@@ -693,6 +817,51 @@
]
}
},
"floating_layer_behaviour": {
"description": "Determines what happens on a new window when on the `FloatingLayer` (default: Tile)",
"oneOf": [
{
"description": "Tile new windows (unless they match a float rule or float override is active)",
"type": "string",
"enum": [
"Tile"
]
},
{
"description": "Float new windows",
"type": "string",
"enum": [
"Float"
]
}
]
},
"floating_layer_placement": {
"description": "Determines the `Placement` to be used when spawning a window on the floating layer with the `FloatingLayerBehaviour` set to `FloatingLayerBehaviour::Float` (default: Center)",
"oneOf": [
{
"description": "Does not change the size or position of the window",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Center the window without changing the size",
"type": "string",
"enum": [
"Center"
]
},
{
"description": "Center the window and resize it according to the `AspectRatio`",
"type": "string",
"enum": [
"CenterAndResize"
]
}
]
},
"floating_window_aspect_ratio": {
"description": "Aspect ratio to resize with when toggling floating mode for a window",
"anyOf": [
@@ -1131,6 +1300,25 @@
"type": "integer",
"format": "int32"
},
"floating_layer_behaviour": {
"description": "Determine what happens to a new window when the Floating workspace layer is active (default: Tile)",
"oneOf": [
{
"description": "Tile new windows (unless they match a float rule or float override is active)",
"type": "string",
"enum": [
"Tile"
]
},
{
"description": "Float new windows",
"type": "string",
"enum": [
"Float"
]
}
]
},
"wallpaper": {
"description": "Specify a wallpaper for this monitor",
"type": "object",
@@ -1493,7 +1681,7 @@
"description": "Determine what happens to a new window when the Floating workspace layer is active (default: Tile)",
"oneOf": [
{
"description": "Tile new windows (unless they match a float rule)",
"description": "Tile new windows (unless they match a float rule or float override is active)",
"type": "string",
"enum": [
"Tile"
@@ -4187,6 +4375,32 @@
}
]
},
"toggle_float_placement": {
"description": "Determines the placement of a new window when toggling to float (default: CenterAndResize)",
"oneOf": [
{
"description": "Does not change the size or position of the window",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Center the window without changing the size",
"type": "string",
"enum": [
"Center"
]
},
{
"description": "Center the window and resize it according to the `AspectRatio`",
"type": "string",
"enum": [
"CenterAndResize"
]
}
]
},
"transparency": {
"description": "Add transparency to unfocused windows (default: false)",
"type": "boolean"
@@ -4401,6 +4615,14 @@
}
]
},
"window_handling_behaviour": {
"description": "Which Windows API behaviour to use when manipulating windows (default: Sync)",
"type": "string",
"enum": [
"Sync",
"Async"
]
},
"window_hiding_behaviour": {
"description": "Which Windows signal to use when hiding windows (default: Cloak)",
"oneOf": [

View File

@@ -101,6 +101,9 @@
<Component Id='binary4' Guid='*'>
<File Id='exe4' Name='komorebi-bar.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\komorebi-bar.exe' KeyPath='yes' />
</Component>
<Component Id='binary5' Guid='*'>
<File Id='exe5' Name='komorebi-shortcuts.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\komorebi-shortcuts.exe' KeyPath='yes' />
</Component>
</Directory>
</Directory>
</Directory>
@@ -123,6 +126,8 @@
<ComponentRef Id='binary4' />
<ComponentRef Id='binary5' />
<Feature Id='Environment' Title='PATH Environment Variable' Description='Add the install location of the [ProductName] executable to the PATH system environment variable. This allows the [ProductName] executable to be called from any location.' Level='1' Absent='allow'>
<ComponentRef Id='Path' />
</Feature>