mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 13:22:19 +01:00
refactor(windows): name the long workspace arms of process_command as WindowManager methods
ToggleWorkspaceLayer, CycleFocusWorkspace, CycleFocusEmptyWorkspace, CloseWorkspace, FocusLastWorkspace, FocusWorkspaceNumbers and MoveContainerToLastWorkspace / SendContainerToLastWorkspace (one method with a follow flag, as the 20-line arms differed only by true/false) become pub fn toggle_workspace_layer, cycle_focus_workspace(direction), cycle_focus_empty_workspace(direction), close_workspace, focus_last_workspace, focus_workspace_numbers(idx) and move_container_to_last_workspace(follow) in a second impl WindowManager block in process_command.rs. The arm bodies moved unchanged (dedented, ending in Ok(())); each arm is now one self.x(..)? call. Same names as kfde's table in docs/dev/core-model.md where the command is the same (focus_last_workspace and focus_workspace_numbers are Windows names). Not a behaviour change. Verified: Windows clippy -D warnings via tools/fast-check PASS.
This commit is contained in:
1 parent
c87bdb7241
commit
a2f08e52e7
1 file changed
+314
-302
+314
-302
@@ -59,6 +59,7 @@ use crate::build;
|
||||
use crate::config_generation::WorkspaceMatchingRule;
|
||||
use crate::core::ApplicationIdentifier;
|
||||
use crate::core::Axis;
|
||||
use crate::core::CycleDirection;
|
||||
use crate::core::BorderImplementation;
|
||||
use crate::core::FocusFollowsMouseImplementation;
|
||||
use crate::core::Layout;
|
||||
@@ -710,59 +711,10 @@ impl WindowManager {
|
||||
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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut()
|
||||
&& 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_eyre("there is no monitor")?
|
||||
.last_focused_workspace = Option::from(idx);
|
||||
self.move_container_to_last_workspace(true)?;
|
||||
}
|
||||
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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut()
|
||||
&& 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_eyre("there is no monitor")?
|
||||
.last_focused_workspace = Option::from(idx);
|
||||
self.move_container_to_last_workspace(false)?;
|
||||
}
|
||||
SocketMessage::MoveContainerToWorkspaceNumber(workspace_idx) => {
|
||||
self.move_container_to_workspace(workspace_idx, true, None)?;
|
||||
@@ -1084,142 +1036,16 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
SocketMessage::CycleFocusWorkspace(direction) => {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let focused_monitor = self.focused_monitor().ok_or_eyre("there is no monitor")?;
|
||||
|
||||
let focused_workspace_idx = focused_monitor.focused_workspace_idx();
|
||||
let workspaces = focused_monitor.workspaces().len();
|
||||
|
||||
let workspace_idx = direction.next_idx(
|
||||
focused_workspace_idx,
|
||||
NonZeroUsize::new(workspaces)
|
||||
.ok_or_eyre("there must be at least one workspace")?,
|
||||
);
|
||||
|
||||
self.focus_workspace(workspace_idx)?;
|
||||
self.cycle_focus_workspace(direction)?;
|
||||
}
|
||||
SocketMessage::CycleFocusEmptyWorkspace(direction) => {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let focused_monitor = self.focused_monitor().ok_or_eyre("there is no monitor")?;
|
||||
|
||||
let focused_workspace_idx = focused_monitor.focused_workspace_idx();
|
||||
let workspaces = focused_monitor.workspaces().len();
|
||||
|
||||
let mut empty_workspaces = vec![];
|
||||
|
||||
for (idx, w) in focused_monitor.workspaces().iter().enumerate() {
|
||||
if w.is_empty() {
|
||||
empty_workspaces.push(idx);
|
||||
}
|
||||
}
|
||||
|
||||
if !empty_workspaces.is_empty() {
|
||||
let mut workspace_idx = direction.next_idx(
|
||||
focused_workspace_idx,
|
||||
NonZeroUsize::new(workspaces)
|
||||
.ok_or_eyre("there must be at least one workspace")?,
|
||||
);
|
||||
|
||||
while !empty_workspaces.contains(&workspace_idx) {
|
||||
workspace_idx = direction.next_idx(
|
||||
workspace_idx,
|
||||
NonZeroUsize::new(workspaces)
|
||||
.ok_or_eyre("there must be at least one workspace")?,
|
||||
);
|
||||
}
|
||||
|
||||
self.focus_workspace(workspace_idx)?;
|
||||
}
|
||||
self.cycle_focus_empty_workspace(direction)?;
|
||||
}
|
||||
SocketMessage::CloseWorkspace => {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let mut can_close = false;
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut() {
|
||||
let focused_workspace_idx = monitor.focused_workspace_idx();
|
||||
let next_focused_workspace_idx = focused_workspace_idx.saturating_sub(1);
|
||||
|
||||
if let Some(workspace) = monitor.focused_workspace()
|
||||
&& monitor.workspaces().len() > 1
|
||||
&& workspace.containers().is_empty()
|
||||
&& workspace.floating_windows().is_empty()
|
||||
&& workspace.monocle_container.is_none()
|
||||
&& workspace.maximized_window.is_none()
|
||||
&& workspace.name.is_none()
|
||||
{
|
||||
can_close = true;
|
||||
}
|
||||
|
||||
if can_close
|
||||
&& monitor
|
||||
.workspaces_mut()
|
||||
.remove(focused_workspace_idx)
|
||||
.is_some()
|
||||
{
|
||||
self.focus_workspace(next_focused_workspace_idx)?;
|
||||
}
|
||||
}
|
||||
self.close_workspace()?;
|
||||
}
|
||||
SocketMessage::FocusLastWorkspace => {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut()
|
||||
&& let Some(last_focused_workspace) = monitor.last_focused_workspace
|
||||
{
|
||||
self.focus_workspace(last_focused_workspace)?;
|
||||
}
|
||||
|
||||
self.focused_monitor_mut()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.last_focused_workspace = Option::from(idx);
|
||||
self.focus_last_workspace()?;
|
||||
}
|
||||
SocketMessage::FocusWorkspaceNumber(workspace_idx) => {
|
||||
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
||||
@@ -1239,28 +1065,7 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
SocketMessage::FocusWorkspaceNumbers(workspace_idx) => {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
|
||||
for (i, monitor) in self.monitors_mut().iter_mut().enumerate() {
|
||||
if i != focused_monitor_idx {
|
||||
monitor.focus_workspace(workspace_idx)?;
|
||||
monitor.load_focused_workspace(false)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.focus_workspace(workspace_idx)?;
|
||||
self.focus_workspace_numbers(workspace_idx)?;
|
||||
}
|
||||
SocketMessage::FocusMonitorWorkspaceNumber(monitor_idx, workspace_idx) => {
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
@@ -1282,105 +1087,7 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
SocketMessage::ToggleWorkspaceLayer => {
|
||||
let mouse_follows_focus = self.mouse_follows_focus;
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let mut to_focus = None;
|
||||
match workspace.layer {
|
||||
WorkspaceLayer::Tiling => {
|
||||
workspace.layer = WorkspaceLayer::Floating;
|
||||
|
||||
let focused_idx = workspace.focused_floating_window_idx();
|
||||
let mut window_idx_pairs = workspace
|
||||
.floating_windows_mut()
|
||||
.make_contiguous()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort by window area
|
||||
window_idx_pairs.sort_by_key(|(_, w)| {
|
||||
let rect = backend()
|
||||
.frame(WindowId::from_hwnd(w.hwnd))
|
||||
.unwrap_or_default();
|
||||
rect.right * rect.bottom
|
||||
});
|
||||
window_idx_pairs.reverse();
|
||||
|
||||
for (i, window) in window_idx_pairs {
|
||||
if i == focused_idx {
|
||||
to_focus = Some(*window);
|
||||
} else {
|
||||
let _ = backend().restore(WindowId::from_hwnd(window.hwnd));
|
||||
backend().raise(WindowId::from_hwnd(window.hwnd))?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(focused_window) = &to_focus {
|
||||
// The focused window should be the last one raised to make sure it is
|
||||
// on top
|
||||
let _ = backend().restore(WindowId::from_hwnd(focused_window.hwnd));
|
||||
backend().raise(WindowId::from_hwnd(focused_window.hwnd))?;
|
||||
}
|
||||
|
||||
for container in workspace.containers() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
window.lower()?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(monocle) = &workspace.monocle_container
|
||||
&& let Some(window) = monocle.focused_window()
|
||||
{
|
||||
window.lower()?;
|
||||
}
|
||||
}
|
||||
WorkspaceLayer::Floating => {
|
||||
workspace.layer = WorkspaceLayer::Tiling;
|
||||
|
||||
if let Some(monocle) = &workspace.monocle_container {
|
||||
if let Some(window) = monocle.focused_window() {
|
||||
to_focus = Some(*window);
|
||||
backend().raise(WindowId::from_hwnd(window.hwnd))?;
|
||||
}
|
||||
for window in workspace.floating_windows() {
|
||||
let _ = backend().hide(WindowId::from_hwnd(window.hwnd));
|
||||
}
|
||||
} else {
|
||||
let focused_container_idx = workspace.focused_container_idx();
|
||||
for (i, container) in workspace.containers_mut().iter_mut().enumerate()
|
||||
{
|
||||
if let Some(window) = container.focused_window() {
|
||||
if i == focused_container_idx {
|
||||
to_focus = Some(*window);
|
||||
}
|
||||
backend().raise(WindowId::from_hwnd(window.hwnd))?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut window_idx_pairs = workspace
|
||||
.floating_windows_mut()
|
||||
.make_contiguous()
|
||||
.iter()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort by window area
|
||||
window_idx_pairs.sort_by_key(|w| {
|
||||
let rect = backend()
|
||||
.frame(WindowId::from_hwnd(w.hwnd))
|
||||
.unwrap_or_default();
|
||||
rect.right * rect.bottom
|
||||
});
|
||||
|
||||
for window in window_idx_pairs {
|
||||
window.lower()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(window) = to_focus {
|
||||
backend().focus(WindowId::from_hwnd(window.hwnd), mouse_follows_focus)?;
|
||||
}
|
||||
self.toggle_workspace_layer()?;
|
||||
}
|
||||
SocketMessage::Stop => {
|
||||
self.stop(false)?;
|
||||
@@ -2360,6 +2067,311 @@ fn push_simple_rule(rules: &mut Vec<MatchingRule>, kind: ApplicationIdentifier,
|
||||
}
|
||||
}
|
||||
|
||||
// extracted-arms-impl
|
||||
impl WindowManager {
|
||||
pub fn move_container_to_last_workspace(&mut self, follow: bool) -> eyre::Result<()> {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut()
|
||||
&& let Some(last_focused_workspace) = monitor.last_focused_workspace
|
||||
{
|
||||
self.move_container_to_workspace(last_focused_workspace, follow, None)?;
|
||||
}
|
||||
|
||||
self.focused_monitor_mut()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.last_focused_workspace = Option::from(idx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn focus_workspace_numbers(&mut self, workspace_idx: usize) -> eyre::Result<()> {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
|
||||
for (i, monitor) in self.monitors_mut().iter_mut().enumerate() {
|
||||
if i != focused_monitor_idx {
|
||||
monitor.focus_workspace(workspace_idx)?;
|
||||
monitor.load_focused_workspace(false)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.focus_workspace(workspace_idx)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn focus_last_workspace(&mut self) -> eyre::Result<()> {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut()
|
||||
&& let Some(last_focused_workspace) = monitor.last_focused_workspace
|
||||
{
|
||||
self.focus_workspace(last_focused_workspace)?;
|
||||
}
|
||||
|
||||
self.focused_monitor_mut()
|
||||
.ok_or_eyre("there is no monitor")?
|
||||
.last_focused_workspace = Option::from(idx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn close_workspace(&mut self) -> eyre::Result<()> {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let mut can_close = false;
|
||||
|
||||
if let Some(monitor) = self.focused_monitor_mut() {
|
||||
let focused_workspace_idx = monitor.focused_workspace_idx();
|
||||
let next_focused_workspace_idx = focused_workspace_idx.saturating_sub(1);
|
||||
|
||||
if let Some(workspace) = monitor.focused_workspace()
|
||||
&& monitor.workspaces().len() > 1
|
||||
&& workspace.containers().is_empty()
|
||||
&& workspace.floating_windows().is_empty()
|
||||
&& workspace.monocle_container.is_none()
|
||||
&& workspace.maximized_window.is_none()
|
||||
&& workspace.name.is_none()
|
||||
{
|
||||
can_close = true;
|
||||
}
|
||||
|
||||
if can_close
|
||||
&& monitor
|
||||
.workspaces_mut()
|
||||
.remove(focused_workspace_idx)
|
||||
.is_some()
|
||||
{
|
||||
self.focus_workspace(next_focused_workspace_idx)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cycle_focus_empty_workspace(&mut self, direction: CycleDirection) -> eyre::Result<()> {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let focused_monitor = self.focused_monitor().ok_or_eyre("there is no monitor")?;
|
||||
|
||||
let focused_workspace_idx = focused_monitor.focused_workspace_idx();
|
||||
let workspaces = focused_monitor.workspaces().len();
|
||||
|
||||
let mut empty_workspaces = vec![];
|
||||
|
||||
for (idx, w) in focused_monitor.workspaces().iter().enumerate() {
|
||||
if w.is_empty() {
|
||||
empty_workspaces.push(idx);
|
||||
}
|
||||
}
|
||||
|
||||
if !empty_workspaces.is_empty() {
|
||||
let mut workspace_idx = direction.next_idx(
|
||||
focused_workspace_idx,
|
||||
NonZeroUsize::new(workspaces).ok_or_eyre("there must be at least one workspace")?,
|
||||
);
|
||||
|
||||
while !empty_workspaces.contains(&workspace_idx) {
|
||||
workspace_idx = direction.next_idx(
|
||||
workspace_idx,
|
||||
NonZeroUsize::new(workspaces)
|
||||
.ok_or_eyre("there must be at least one workspace")?,
|
||||
);
|
||||
}
|
||||
|
||||
self.focus_workspace(workspace_idx)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cycle_focus_workspace(&mut self, direction: CycleDirection) -> eyre::Result<()> {
|
||||
// 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()
|
||||
&& monitor_idx != self.focused_monitor_idx()
|
||||
&& let Some(monitor) = self.monitors().get(monitor_idx)
|
||||
&& let Some(workspace) = monitor.focused_workspace()
|
||||
&& workspace.is_empty()
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
let focused_monitor = self.focused_monitor().ok_or_eyre("there is no monitor")?;
|
||||
|
||||
let focused_workspace_idx = focused_monitor.focused_workspace_idx();
|
||||
let workspaces = focused_monitor.workspaces().len();
|
||||
|
||||
let workspace_idx = direction.next_idx(
|
||||
focused_workspace_idx,
|
||||
NonZeroUsize::new(workspaces).ok_or_eyre("there must be at least one workspace")?,
|
||||
);
|
||||
|
||||
self.focus_workspace(workspace_idx)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn toggle_workspace_layer(&mut self) -> eyre::Result<()> {
|
||||
let mouse_follows_focus = self.mouse_follows_focus;
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let mut to_focus = None;
|
||||
match workspace.layer {
|
||||
WorkspaceLayer::Tiling => {
|
||||
workspace.layer = WorkspaceLayer::Floating;
|
||||
|
||||
let focused_idx = workspace.focused_floating_window_idx();
|
||||
let mut window_idx_pairs = workspace
|
||||
.floating_windows_mut()
|
||||
.make_contiguous()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort by window area
|
||||
window_idx_pairs.sort_by_key(|(_, w)| {
|
||||
let rect = backend()
|
||||
.frame(WindowId::from_hwnd(w.hwnd))
|
||||
.unwrap_or_default();
|
||||
rect.right * rect.bottom
|
||||
});
|
||||
window_idx_pairs.reverse();
|
||||
|
||||
for (i, window) in window_idx_pairs {
|
||||
if i == focused_idx {
|
||||
to_focus = Some(*window);
|
||||
} else {
|
||||
let _ = backend().restore(WindowId::from_hwnd(window.hwnd));
|
||||
backend().raise(WindowId::from_hwnd(window.hwnd))?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(focused_window) = &to_focus {
|
||||
// The focused window should be the last one raised to make sure it is
|
||||
// on top
|
||||
let _ = backend().restore(WindowId::from_hwnd(focused_window.hwnd));
|
||||
backend().raise(WindowId::from_hwnd(focused_window.hwnd))?;
|
||||
}
|
||||
|
||||
for container in workspace.containers() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
window.lower()?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(monocle) = &workspace.monocle_container
|
||||
&& let Some(window) = monocle.focused_window()
|
||||
{
|
||||
window.lower()?;
|
||||
}
|
||||
}
|
||||
WorkspaceLayer::Floating => {
|
||||
workspace.layer = WorkspaceLayer::Tiling;
|
||||
|
||||
if let Some(monocle) = &workspace.monocle_container {
|
||||
if let Some(window) = monocle.focused_window() {
|
||||
to_focus = Some(*window);
|
||||
backend().raise(WindowId::from_hwnd(window.hwnd))?;
|
||||
}
|
||||
for window in workspace.floating_windows() {
|
||||
let _ = backend().hide(WindowId::from_hwnd(window.hwnd));
|
||||
}
|
||||
} else {
|
||||
let focused_container_idx = workspace.focused_container_idx();
|
||||
for (i, container) in workspace.containers_mut().iter_mut().enumerate() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
if i == focused_container_idx {
|
||||
to_focus = Some(*window);
|
||||
}
|
||||
backend().raise(WindowId::from_hwnd(window.hwnd))?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut window_idx_pairs = workspace
|
||||
.floating_windows_mut()
|
||||
.make_contiguous()
|
||||
.iter()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort by window area
|
||||
window_idx_pairs.sort_by_key(|w| {
|
||||
let rect = backend()
|
||||
.frame(WindowId::from_hwnd(w.hwnd))
|
||||
.unwrap_or_default();
|
||||
rect.right * rect.bottom
|
||||
});
|
||||
|
||||
for window in window_idx_pairs {
|
||||
window.lower()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(window) = to_focus {
|
||||
backend().focus(WindowId::from_hwnd(window.hwnd), mouse_follows_focus)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::push_simple_rule;
|
||||
|
||||
Reference in new issue
Block a user