mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-01-14 14:23:36 +01:00
Compare commits
6 Commits
feature/lo
...
feature/ic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3776310d09 | ||
|
|
e702d93a8a | ||
|
|
a8c687d3d5 | ||
|
|
30fbc1ae73 | ||
|
|
cb60e91842 | ||
|
|
64d29d606a |
25
Cargo.lock
generated
25
Cargo.lock
generated
@@ -2745,7 +2745,8 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
"windows-icons",
|
||||
"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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4472,6 +4473,12 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
@@ -6085,7 +6092,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "win32-display-data"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/LGUG2Z/win32-display-data?rev=93949750b1f123fb79827ba4d66ffcab68055654#93949750b1f123fb79827ba4d66ffcab68055654"
|
||||
source = "git+https://github.com/LGUG2Z/win32-display-data?rev=a28c6559a9de2f92c142a714947a9b081776caca#a28c6559a9de2f92c142a714947a9b081776caca"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"serde",
|
||||
@@ -6270,6 +6277,20 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-icons"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/LGUG2Z/windows-icons?rev=0c9d7ee1b807347c507d3a9862dd007b4d3f4354#0c9d7ee1b807347c507d3a9862dd007b4d3f4354"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"image",
|
||||
"regex",
|
||||
"roxmltree",
|
||||
"sysinfo",
|
||||
"winapi",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-icons"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -35,7 +35,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
paste = "1"
|
||||
sysinfo = "0.33"
|
||||
uds_windows = "1"
|
||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "93949750b1f123fb79827ba4d66ffcab68055654" }
|
||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "a28c6559a9de2f92c142a714947a9b081776caca" }
|
||||
windows-numerics = { version = "0.2" }
|
||||
windows-implement = { version = "0.60" }
|
||||
windows-interface = { version = "0.59" }
|
||||
|
||||
@@ -10,9 +10,9 @@ Options:
|
||||
Desired ease function for animation
|
||||
|
||||
[default: linear]
|
||||
[possible values: linear, ease-in-sine, ease-out-sine, ease-in-out-sine, ease-in-quad, ease-out-quad, ease-in-out-quad, ease-in-cubic, ease-in-out-cubic, ease-in-quart,
|
||||
ease-out-quart, ease-in-out-quart, ease-in-quint, ease-out-quint, ease-in-out-quint, ease-in-expo, ease-out-expo, ease-in-out-expo, ease-in-circ, ease-out-circ, ease-in-out-circ,
|
||||
ease-in-back, ease-out-back, ease-in-out-back, ease-in-elastic, ease-out-elastic, ease-in-out-elastic, ease-in-bounce, ease-out-bounce, ease-in-out-bounce]
|
||||
[possible values: linear, ease-in-sine, ease-out-sine, ease-in-out-sine, ease-in-quad, ease-out-quad, ease-in-out-quad, ease-in-cubic, ease-in-out-cubic, ease-in-quart, ease-out-quart,
|
||||
ease-in-out-quart, ease-in-quint, ease-out-quint, ease-in-out-quint, ease-in-expo, ease-out-expo, ease-in-out-expo, ease-in-circ, ease-out-circ, ease-in-out-circ, ease-in-back, ease-out-back,
|
||||
ease-in-out-back, ease-in-elastic, ease-out-elastic, ease-in-out-elastic, ease-in-bounce, ease-out-bounce, ease-in-out-bounce]
|
||||
|
||||
-a, --animation-type <ANIMATION_TYPE>
|
||||
Animation type to apply the style to. If not specified, sets global style
|
||||
|
||||
@@ -18,7 +18,7 @@ Arguments:
|
||||
Options:
|
||||
-w, --window-kind <WINDOW_KIND>
|
||||
[default: single]
|
||||
[possible values: single, stack, monocle, unfocused, floating]
|
||||
[possible values: single, stack, monocle, unfocused, unfocused-locked, floating]
|
||||
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
12
docs/cli/move-to-last-workspace.md
Normal file
12
docs/cli/move-to-last-workspace.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# move-to-last-workspace
|
||||
|
||||
```
|
||||
Move the focused window to the last focused monitor workspace
|
||||
|
||||
Usage: komorebic.exe move-to-last-workspace
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
12
docs/cli/send-to-last-workspace.md
Normal file
12
docs/cli/send-to-last-workspace.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# send-to-last-workspace
|
||||
|
||||
```
|
||||
Send the focused window to the last focused monitor workspace
|
||||
|
||||
Usage: komorebic.exe send-to-last-workspace
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
12
docs/cli/toggle-lock.md
Normal file
12
docs/cli/toggle-lock.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# toggle-lock
|
||||
|
||||
```
|
||||
Toggle a lock for the focused container, ensuring it will not be displaced by any new windows
|
||||
|
||||
Usage: komorebic.exe toggle-lock
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -1,8 +1,8 @@
|
||||
# toggle-workspace-float-override
|
||||
|
||||
```
|
||||
Enable or disable float override, which makes it so every new window opens in floating mode, for the currently focused workspace. If there was no override value set for the workspace
|
||||
previously it takes the opposite of the global value
|
||||
Enable or disable float override, which makes it so every new window opens in floating mode, for the currently focused workspace. If there was no override value set for the workspace previously it takes
|
||||
the opposite of the global value
|
||||
|
||||
Usage: komorebic.exe toggle-workspace-float-override
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# toggle-workspace-window-container-behaviour
|
||||
|
||||
```
|
||||
Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused workspace. If there was no behaviour set for the workspace previously it takes the opposite of the
|
||||
global value
|
||||
Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused workspace. If there was no behaviour set for the workspace previously it takes the opposite of the global value
|
||||
|
||||
Usage: komorebic.exe toggle-workspace-window-container-behaviour
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
windows-core = { workspace = true }
|
||||
windows-icons = { git = "https://github.com/LGUG2Z/windows-icons", rev = "d67cc9920aa9b4883393e411fb4fa2ddd4c498b5" }
|
||||
windows-icons = { git = "https://github.com/LGUG2Z/windows-icons", rev = "0c9d7ee1b807347c507d3a9862dd007b4d3f4354" }
|
||||
windows-icons-fallback = { package = "windows-icons", git = "https://github.com/LGUG2Z/windows-icons", rev = "d67cc9920aa9b4883393e411fb4fa2ddd4c498b5" }
|
||||
|
||||
[features]
|
||||
default = ["schemars"]
|
||||
|
||||
@@ -47,7 +47,7 @@ pub static MONITOR_INDEX: AtomicUsize = AtomicUsize::new(0);
|
||||
pub static BAR_HEIGHT: f32 = 50.0;
|
||||
pub static DEFAULT_PADDING: f32 = 10.0;
|
||||
|
||||
pub static ICON_CACHE: LazyLock<Mutex<HashMap<String, RgbaImage>>> =
|
||||
pub static ICON_CACHE: LazyLock<Mutex<HashMap<isize, RgbaImage>>> =
|
||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
#[derive(Parser)]
|
||||
|
||||
@@ -837,11 +837,16 @@ impl From<&Container> for KomorebiNotificationStateContainerInformation {
|
||||
for window in windows {
|
||||
let mut icon_cache = ICON_CACHE.lock().unwrap();
|
||||
let mut update_cache = false;
|
||||
let exe = window.exe().unwrap_or_default();
|
||||
let hwnd = window.hwnd;
|
||||
|
||||
match icon_cache.get(&exe) {
|
||||
match icon_cache.get(&hwnd) {
|
||||
None => {
|
||||
icons.push(windows_icons::get_icon_by_process_id(window.process_id()));
|
||||
let icon = match windows_icons::get_icon_by_hwnd(window.hwnd) {
|
||||
None => windows_icons_fallback::get_icon_by_process_id(window.process_id()),
|
||||
Some(icon) => Some(icon),
|
||||
};
|
||||
|
||||
icons.push(icon);
|
||||
update_cache = true;
|
||||
}
|
||||
Some(icon) => {
|
||||
@@ -851,7 +856,7 @@ impl From<&Container> for KomorebiNotificationStateContainerInformation {
|
||||
|
||||
if update_cache {
|
||||
if let Some(Some(icon)) = icons.last() {
|
||||
icon_cache.insert(exe, icon.clone());
|
||||
icon_cache.insert(hwnd, icon.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -873,11 +878,16 @@ impl From<&Window> for KomorebiNotificationStateContainerInformation {
|
||||
let mut icon_cache = ICON_CACHE.lock().unwrap();
|
||||
let mut update_cache = false;
|
||||
let mut icons = vec![];
|
||||
let exe = value.exe().unwrap_or_default();
|
||||
let hwnd = value.hwnd;
|
||||
|
||||
match icon_cache.get(&exe) {
|
||||
match icon_cache.get(&hwnd) {
|
||||
None => {
|
||||
icons.push(windows_icons::get_icon_by_process_id(value.process_id()));
|
||||
let icon = match windows_icons::get_icon_by_hwnd(hwnd) {
|
||||
None => windows_icons_fallback::get_icon_by_process_id(value.process_id()),
|
||||
Some(icon) => Some(icon),
|
||||
};
|
||||
|
||||
icons.push(icon);
|
||||
update_cache = true;
|
||||
}
|
||||
Some(icon) => {
|
||||
@@ -887,7 +897,7 @@ impl From<&Window> for KomorebiNotificationStateContainerInformation {
|
||||
|
||||
if update_cache {
|
||||
if let Some(Some(icon)) = icons.last() {
|
||||
icon_cache.insert(exe, icon.clone());
|
||||
icon_cache.insert(hwnd, icon.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ pub use komorebi::core::WindowKind;
|
||||
pub use komorebi::monitor::Monitor;
|
||||
pub use komorebi::monitor_reconciliator::MonitorNotification;
|
||||
pub use komorebi::ring::Ring;
|
||||
pub use komorebi::win32_display_data;
|
||||
pub use komorebi::window::Window;
|
||||
pub use komorebi::window_manager_event::WindowManagerEvent;
|
||||
pub use komorebi::workspace::Workspace;
|
||||
|
||||
@@ -501,10 +501,10 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
|| focused_window_hwnd != foreground_window
|
||||
{
|
||||
if ws.locked_containers().contains(&idx) {
|
||||
WindowKind::UnfocusedLocked
|
||||
} else {
|
||||
WindowKind::Unfocused
|
||||
}
|
||||
WindowKind::UnfocusedLocked
|
||||
} else {
|
||||
WindowKind::Unfocused
|
||||
}
|
||||
} else if c.windows().len() > 1 {
|
||||
WindowKind::Stack
|
||||
} else {
|
||||
|
||||
@@ -62,6 +62,8 @@ pub enum SocketMessage {
|
||||
UnstackAll,
|
||||
ResizeWindowEdge(OperationDirection, Sizing),
|
||||
ResizeWindowAxis(Axis, Sizing),
|
||||
MoveContainerToLastWorkspace,
|
||||
SendContainerToLastWorkspace,
|
||||
MoveContainerToMonitorNumber(usize),
|
||||
CycleMoveContainerToMonitor(CycleDirection),
|
||||
MoveContainerToWorkspaceNumber(usize),
|
||||
|
||||
@@ -53,6 +53,7 @@ pub use core::*;
|
||||
pub use process_command::*;
|
||||
pub use process_event::*;
|
||||
pub use static_config::*;
|
||||
pub use win32_display_data;
|
||||
pub use window::*;
|
||||
pub use window_manager::*;
|
||||
pub use window_manager_event::*;
|
||||
|
||||
@@ -84,10 +84,12 @@ pub fn insert_in_monitor_cache(serial_or_device_id: &str, monitor: Monitor) {
|
||||
monitor_cache.insert(preferred_id, monitor);
|
||||
}
|
||||
|
||||
pub fn attached_display_devices() -> color_eyre::Result<Vec<Monitor>> {
|
||||
let all_displays = win32_display_data::connected_displays_all()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
pub fn attached_display_devices<F, I>(display_provider: F) -> color_eyre::Result<Vec<Monitor>>
|
||||
where
|
||||
F: Fn() -> I + Copy,
|
||||
I: Iterator<Item = Result<win32_display_data::Device, win32_display_data::Error>>,
|
||||
{
|
||||
let all_displays = display_provider().flatten().collect::<Vec<_>>();
|
||||
|
||||
let mut serial_id_map = HashMap::new();
|
||||
|
||||
@@ -154,7 +156,7 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Re
|
||||
tracing::info!("created hidden window to listen for monitor-related events");
|
||||
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
match handle_notifications(wm.clone(), win32_display_data::connected_displays_all) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
@@ -171,7 +173,14 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Re
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
|
||||
pub fn handle_notifications<F, I>(
|
||||
wm: Arc<Mutex<WindowManager>>,
|
||||
display_provider: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: Fn() -> I + Copy,
|
||||
I: Iterator<Item = Result<win32_display_data::Device, win32_display_data::Error>>,
|
||||
{
|
||||
tracing::info!("listening");
|
||||
|
||||
let receiver = event_rx();
|
||||
@@ -296,7 +305,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
let initial_monitor_count = wm.monitors().len();
|
||||
|
||||
// Get the currently attached display devices
|
||||
let attached_devices = attached_display_devices()?;
|
||||
let attached_devices = attached_display_devices(display_provider)?;
|
||||
|
||||
// Make sure that in our state any attached displays have the latest Win32 data
|
||||
for monitor in wm.monitors_mut() {
|
||||
|
||||
@@ -640,6 +640,67 @@ impl WindowManager {
|
||||
SocketMessage::AdjustWorkspacePadding(sizing, adjustment) => {
|
||||
self.adjust_workspace_padding(sizing, adjustment)?;
|
||||
}
|
||||
SocketMessage::MoveContainerToLastWorkspace => {
|
||||
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
||||
// secondary monitor where the cursor is focused will be used as the target for
|
||||
// the workspace switch op
|
||||
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
|
||||
if monitor_idx != self.focused_monitor_idx() {
|
||||
if let Some(monitor) = self.monitors().get(monitor_idx) {
|
||||
if let Some(workspace) = monitor.focused_workspace() {
|
||||
if workspace.is_empty() {
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut() {
|
||||
if let Some(last_focused_workspace) = monitor.last_focused_workspace() {
|
||||
self.move_container_to_workspace(last_focused_workspace, true, None)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.focused_monitor_mut()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?
|
||||
.set_last_focused_workspace(Option::from(idx));
|
||||
}
|
||||
SocketMessage::SendContainerToLastWorkspace => {
|
||||
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
||||
// secondary monitor where the cursor is focused will be used as the target for
|
||||
// the workspace switch op
|
||||
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
|
||||
if monitor_idx != self.focused_monitor_idx() {
|
||||
if let Some(monitor) = self.monitors().get(monitor_idx) {
|
||||
if let Some(workspace) = monitor.focused_workspace() {
|
||||
if workspace.is_empty() {
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut() {
|
||||
if let Some(last_focused_workspace) = monitor.last_focused_workspace() {
|
||||
self.move_container_to_workspace(last_focused_workspace, false, None)?;
|
||||
}
|
||||
}
|
||||
self.focused_monitor_mut()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?
|
||||
.set_last_focused_workspace(Option::from(idx));
|
||||
}
|
||||
SocketMessage::MoveContainerToWorkspaceNumber(workspace_idx) => {
|
||||
self.move_container_to_workspace(workspace_idx, true, None)?;
|
||||
}
|
||||
|
||||
@@ -1104,6 +1104,10 @@ enum SubCommand {
|
||||
/// Move the focused window to the specified monitor workspace
|
||||
#[clap(arg_required_else_help = true)]
|
||||
MoveToMonitorWorkspace(MoveToMonitorWorkspace),
|
||||
/// Send the focused window to the last focused monitor workspace
|
||||
SendToLastWorkspace,
|
||||
/// Move the focused window to the last focused monitor workspace
|
||||
MoveToLastWorkspace,
|
||||
/// Focus the specified monitor
|
||||
#[clap(arg_required_else_help = true)]
|
||||
FocusMonitor(FocusMonitor),
|
||||
@@ -1857,6 +1861,12 @@ fn main() -> Result<()> {
|
||||
arg.cycle_direction,
|
||||
))?;
|
||||
}
|
||||
SubCommand::MoveToLastWorkspace => {
|
||||
send_message(&SocketMessage::MoveContainerToLastWorkspace)?;
|
||||
}
|
||||
SubCommand::SendToLastWorkspace => {
|
||||
send_message(&SocketMessage::SendContainerToLastWorkspace)?;
|
||||
}
|
||||
SubCommand::SwapWorkspacesWithMonitor(arg) => {
|
||||
send_message(&SocketMessage::SwapWorkspacesToMonitorNumber(arg.target))?;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,8 @@ nav:
|
||||
- cli/cycle-send-to-workspace.md
|
||||
- cli/send-to-monitor-workspace.md
|
||||
- cli/move-to-monitor-workspace.md
|
||||
- cli/send-to-last-workspace.md
|
||||
- cli/move-to-last-workspace.md
|
||||
- cli/focus-monitor.md
|
||||
- cli/focus-monitor-at-cursor.md
|
||||
- cli/focus-last-workspace.md
|
||||
@@ -191,6 +193,7 @@ nav:
|
||||
- cli/toggle-float.md
|
||||
- cli/toggle-monocle.md
|
||||
- cli/toggle-maximize.md
|
||||
- cli/toggle-lock.md
|
||||
- cli/restore-windows.md
|
||||
- cli/manage.md
|
||||
- cli/unmanage.md
|
||||
|
||||
Reference in New Issue
Block a user