diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 912becb9..75f472af 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -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; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 949434df..4761d10d 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -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"))?; @@ -1185,16 +1187,23 @@ 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::>(); + .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 @@ -1202,18 +1211,33 @@ impl WindowManager { .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)?; } + let target_workspace = target_monitor.focused_workspace_mut() + .ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?; - 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())?; + if let Some(window) = floating_window { + target_workspace.floating_windows_mut().push(window); + Window::from(window.hwnd).move_to_area(¤t_area, target_monitor.work_area_size())?; + } else if let Some(container) = container { + let container_hwnds = container + .windows() + .iter() + .map(|w| w.hwnd) + .collect::>(); + + 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(¤t_area, target_monitor.work_area_size())?; + } } } + } else { + bail!("failed to find a window to move"); } target_monitor.load_focused_workspace(mouse_follows_focus)?;