Skip to content

Commit

Permalink
fix(wm): allow cross-monitor floating window moves
Browse files Browse the repository at this point in the history
This commit changes the `move_container_to_monitor` from the WM to allow
moving floating windows as well.

It also adds a new method `move_to_area` to the `Window` that allows
moving a window from one monitor to another keeping its size.
  • Loading branch information
alex-ds13 authored and LGUG2Z committed Oct 13, 2024
1 parent f91d0aa commit 9151922
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
25 changes: 25 additions & 0 deletions komorebi/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,31 @@ impl Window {
HWND(windows_api::as_ptr!(self.hwnd))
}

pub fn move_to_area(&mut self, current_area: &Rect, target_area: &Rect) -> Result<()> {
let current_rect = WindowsApi::window_rect(self.hwnd)?;
let x_diff = target_area.left - current_area.left;
let y_diff = target_area.top - current_area.top;
let x_ratio = f32::abs((target_area.right as f32) / (current_area.right as f32));
let y_ratio = f32::abs((target_area.bottom as f32) / (current_area.bottom as f32));
let window_relative_x = current_rect.left - current_area.left;
let window_relative_y = current_rect.top - current_area.top;
let corrected_relative_x = (window_relative_x as f32 * x_ratio) as i32;
let corrected_relative_y = (window_relative_y as f32 * y_ratio) as i32;
let window_x = current_area.left + corrected_relative_x;
let window_y = current_area.top + corrected_relative_y;

let new_rect = Rect {
left: x_diff + window_x,
top: y_diff + window_y,
right: current_rect.right,
bottom: current_rect.bottom,
};
//TODO: We might need to take into account the differences in DPI for the new_rect, unless
//we can use the xy ratios above to the right/bottom (width/height of window) as well?

self.set_position(&new_rect, true)
}

pub fn center(&mut self, work_area: &Rect) -> Result<()> {
let half_width = work_area.right / 2;
let half_weight = work_area.bottom / 2;
Expand Down
52 changes: 38 additions & 14 deletions komorebi/src/window_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,8 @@ impl WindowManager {
.focused_monitor_mut()
.ok_or_else(|| anyhow!("there is no monitor"))?;

let current_area = *monitor.work_area_size();

let workspace = monitor
.focused_workspace_mut()
.ok_or_else(|| anyhow!("there is no workspace"))?;
Expand All @@ -1185,35 +1187,57 @@ impl WindowManager {
bail!("cannot move native maximized window to another monitor or workspace");
}

let container = workspace
.remove_focused_container()
.ok_or_else(|| anyhow!("there is no container"))?;

let container_hwnds = container
.windows()
let foreground_hwnd = WindowsApi::foreground_window()?;
let floating_window_index = workspace
.floating_windows()
.iter()
.map(|w| w.hwnd)
.collect::<Vec<_>>();
.position(|w| w.hwnd == foreground_hwnd);

let floating_window = floating_window_index.map(|idx| {
workspace.floating_windows_mut().remove(idx)
});
let container = if floating_window_index.is_none() {
Some(workspace
.remove_focused_container()
.ok_or_else(|| anyhow!("there is no container"))?)
} else {
None
};
monitor.update_focused_workspace(offset)?;

let target_monitor = self
.monitors_mut()
.get_mut(monitor_idx)
.ok_or_else(|| anyhow!("there is no monitor"))?;

target_monitor.add_container(container, workspace_idx)?;

if let Some(workspace_idx) = workspace_idx {
target_monitor.focus_workspace(workspace_idx)?;
}

if let Some(workspace) = target_monitor.focused_workspace() {
if !*workspace.tile() {
for hwnd in container_hwnds {
Window::from(hwnd).center(target_monitor.work_area_size())?;
let target_workspace = target_monitor.focused_workspace_mut()
.ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?;

if let Some(window) = floating_window {
target_workspace.floating_windows_mut().push(window);
Window::from(window.hwnd).move_to_area(&current_area, target_monitor.work_area_size())?;
} else if let Some(container) = container {
let container_hwnds = container
.windows()
.iter()
.map(|w| w.hwnd)
.collect::<Vec<_>>();

target_monitor.add_container(container, workspace_idx)?;

if let Some(workspace) = target_monitor.focused_workspace() {
if !*workspace.tile() {
for hwnd in container_hwnds {
Window::from(hwnd).move_to_area(&current_area, target_monitor.work_area_size())?;
}
}
}
} else {
bail!("failed to find a window to move");
}

target_monitor.load_focused_workspace(mouse_follows_focus)?;
Expand Down

0 comments on commit 9151922

Please sign in to comment.