#![allow(clippy::wildcard_imports)]
mod scratchpad_handler;
pub use scratchpad_handler::{Direction, ReleaseScratchPadOption};
use super::*;
use crate::command::FocusDeltaBehavior;
use crate::display_action::DisplayAction;
use crate::display_servers::DisplayServer;
use crate::layouts::Layout;
use crate::models::{LayoutMode, TagId, WindowState};
use crate::state::State;
use crate::utils::helpers;
use crate::utils::helpers::relative_find;
use crate::{config::Config, models::FocusBehaviour};
impl<C: Config, SERVER: DisplayServer> Manager<C, SERVER> {
pub fn command_handler(&mut self, command: &Command) -> bool {
process_internal(self, command).unwrap_or(false)
}
}
macro_rules! move_focus_common_vars {
($func:ident ($state:expr $(, $arg:expr )* $(,)? )) => {{
let handle = $state.focus_manager.window(&$state.windows)?.handle;
let tag_id = $state.focus_manager.tag(0)?;
let tag = $state.tags.get(tag_id)?;
let layout = Some(tag.layout);
let for_active_workspace =
|x: &Window| -> bool { x.tag == Some(tag_id) && x.is_managed() };
let to_reorder = helpers::vec_extract(&mut $state.windows, for_active_workspace);
$func($state, handle, layout, to_reorder, $($arg),*)
}};
}
fn process_internal<C: Config, SERVER: DisplayServer>(
manager: &mut Manager<C, SERVER>,
command: &Command,
) -> Option<bool> {
let state = &mut manager.state;
match command {
Command::ToggleScratchPad(name) => scratchpad_handler::toggle_scratchpad(manager, name),
Command::AttachScratchPad { window, scratchpad } => {
scratchpad_handler::attach_scratchpad(*window, scratchpad, manager)
}
Command::ReleaseScratchPad { window, tag } => {
scratchpad_handler::release_scratchpad(window.clone(), *tag, manager)
}
Command::NextScratchPadWindow { scratchpad } => {
scratchpad_handler::cycle_scratchpad_window(manager, scratchpad, Direction::Forward)
}
Command::PrevScratchPadWindow { scratchpad } => {
scratchpad_handler::cycle_scratchpad_window(manager, scratchpad, Direction::Backward)
}
Command::ToggleFullScreen => toggle_state(state, WindowState::Fullscreen),
Command::ToggleSticky => toggle_state(state, WindowState::Sticky),
Command::SendWindowToTag { window, tag } => move_to_tag(*window, *tag, manager),
Command::MoveWindowToNextTag { follow } => move_to_tag_relative(manager, *follow, 1),
Command::MoveWindowToPreviousTag { follow } => move_to_tag_relative(manager, *follow, -1),
Command::MoveWindowToLastWorkspace => move_to_last_workspace(state),
Command::MoveWindowToNextWorkspace => move_window_to_workspace_change(manager, 1),
Command::MoveWindowToPreviousWorkspace => move_window_to_workspace_change(manager, -1),
Command::MoveWindowUp => move_focus_common_vars!(move_window_change(state, -1)),
Command::MoveWindowDown => move_focus_common_vars!(move_window_change(state, 1)),
Command::MoveWindowTop { swap } => move_focus_common_vars!(move_window_top(state, *swap)),
Command::SwapWindowTop { swap } => move_focus_common_vars!(swap_window_top(state, *swap)),
Command::GoToTag { tag, swap } => goto_tag(state, *tag, *swap),
Command::ReturnToLastTag => return_to_last_tag(state),
Command::CloseWindow => close_window(state),
Command::SwapScreens => swap_tags(state),
Command::NextLayout => next_layout(state),
Command::PreviousLayout => previous_layout(state),
Command::SetLayout(layout) => set_layout(*layout, state),
Command::FloatingToTile => floating_to_tile(state),
Command::TileToFloating => tile_to_floating(state),
Command::ToggleFloating => toggle_floating(state),
Command::FocusNextTag { behavior } => match *behavior {
FocusDeltaBehavior::Default => focus_tag_change(state, 1),
FocusDeltaBehavior::IgnoreEmpty => focus_next_used_tag(state),
FocusDeltaBehavior::IgnoreUsed => focus_next_empty_tag(state),
},
Command::FocusPreviousTag { behavior } => match *behavior {
FocusDeltaBehavior::Default => focus_tag_change(state, -1),
FocusDeltaBehavior::IgnoreEmpty => focus_previous_used_tag(state),
FocusDeltaBehavior::IgnoreUsed => focus_previous_empty_tag(state),
},
Command::FocusWindow(param) => focus_window(state, param),
Command::FocusWindowUp => move_focus_common_vars!(focus_window_change(state, -1)),
Command::FocusWindowDown => move_focus_common_vars!(focus_window_change(state, 1)),
Command::FocusWindowTop { swap } => focus_window_top(state, *swap),
Command::FocusWorkspaceNext => focus_workspace_change(state, 1),
Command::FocusWorkspacePrevious => focus_workspace_change(state, -1),
Command::SoftReload => {
if let Some((handle, Some(tag))) = state
.focus_manager
.window(&state.windows)
.map(|w| (w.handle, w.tag))
{
let old_handle = state
.focus_manager
.tags_last_window
.entry(tag)
.or_insert(handle);
*old_handle = handle;
}
manager.config.save_state(&manager.state);
manager.hard_reload();
None
}
Command::HardReload => {
manager.hard_reload();
None
}
Command::RotateTag => rotate_tag(state),
Command::IncreaseMainWidth(delta) => change_main_width(state, *delta, 1),
Command::DecreaseMainWidth(delta) => change_main_width(state, *delta, -1),
Command::SetMarginMultiplier(multiplier) => set_margin_multiplier(state, *multiplier),
Command::SendWorkspaceToTag(ws_index, tag_index) => {
Some(send_workspace_to_tag(state, *ws_index, *tag_index))
}
Command::CloseAllOtherWindows => close_all_other_windows(state),
Command::Other(cmd) => Some(C::command_handler(cmd, manager)),
}
}
fn focus_next_empty_tag(state: &mut State) -> Option<bool> {
let used_tags: Vec<usize> = state.windows.iter().filter_map(|w| w.tag).collect();
let unused_tags: Vec<usize> = state
.tags
.normal()
.iter()
.filter(|t| !used_tags.contains(&t.to_owned().id))
.map(|t| t.id)
.collect();
let next_unused_tag = match unused_tags
.iter()
.find(|t| **t > state.focus_manager.tag(0).unwrap_or_default())
{
Some(t) => t,
None => match unused_tags.first() {
Some(t) => t,
None => return Some(false),
},
};
state.goto_tag_handler(*next_unused_tag)
}
fn focus_previous_empty_tag(state: &mut State) -> Option<bool> {
let used_tags: Vec<usize> = state.windows.iter().filter_map(|w| w.tag).collect();
let unused_tags: Vec<usize> = state
.tags
.normal()
.iter()
.filter(|t| !used_tags.contains(&t.to_owned().id))
.map(|t| t.id)
.collect();
let previous_unused_tag = match unused_tags
.iter()
.rfind(|t| **t < state.focus_manager.tag(0).unwrap_or_default())
{
Some(t) => t,
None => match unused_tags.last() {
Some(t) => t,
None => return Some(false),
},
};
state.goto_tag_handler(*previous_unused_tag)
}
fn focus_next_used_tag(state: &mut State) -> Option<bool> {
let mut used_tags: Vec<usize> = state.windows.iter().filter_map(|w| w.tag).collect();
used_tags.sort_unstable();
let next_used_tag = match used_tags
.iter()
.find(|t| **t > state.focus_manager.tag(0).unwrap_or_default())
{
Some(t) => t,
None => match used_tags.first() {
Some(t) => t,
None => return Some(false),
},
};
state.goto_tag_handler(*next_used_tag)
}
fn focus_previous_used_tag(state: &mut State) -> Option<bool> {
let mut used_tags: Vec<usize> = state.windows.iter().filter_map(|w| w.tag).collect();
used_tags.sort_unstable();
used_tags.reverse();
let previous_used_tag = match used_tags
.iter()
.find(|t| **t < state.focus_manager.tag(0).unwrap_or_default())
{
Some(t) => t,
None => match used_tags.first() {
Some(t) => t,
None => return Some(false),
},
};
state.goto_tag_handler(*previous_used_tag)
}
fn toggle_state(state: &mut State, window_state: WindowState) -> Option<bool> {
let window = state.focus_manager.window(&state.windows)?;
let handle = window.handle;
let toggle_to = !window.has_state(&window_state);
let tag_id = state.focus_manager.tag(0)?;
if window_state == WindowState::Fullscreen {
if toggle_to {
let handles = state
.windows
.iter()
.filter(|window| window.tag == Some(tag_id) && window.is_managed())
.map(|w| w.handle)
.collect();
state.window_history.insert(tag_id, handles);
} else if let Some(window_order) = state.window_history.get(&tag_id) {
for window_handle in window_order {
if let Some(pos) = state
.windows
.iter()
.position(|w| w.handle == *window_handle)
{
let window = state.windows.remove(pos);
state.windows.push(window);
}
}
}
}
let act = DisplayAction::SetState(handle, toggle_to, window_state);
state.actions.push_back(act);
state.handle_window_focus(&handle);
match window_state {
WindowState::Fullscreen => Some(true),
_ => Some(false),
}
}
fn move_to_tag<C: Config, SERVER: DisplayServer>(
window: Option<WindowHandle>,
tag_id: TagId,
manager: &mut Manager<C, SERVER>,
) -> Option<bool> {
let tag = manager.state.tags.get(tag_id)?.clone();
let margin_multiplier = match manager.state.windows.iter().find(|w| w.has_tag(&tag.id)) {
Some(w) => w.margin_multiplier(),
None => 1.0,
};
let handle = window.or(*manager.state.focus_manager.window_history.get(0)?)?;
let handle_focus = window.is_none();
let new_handle = if handle_focus {
manager.get_next_or_previous_handle(&handle)
} else {
None
};
let window = manager
.state
.windows
.iter_mut()
.find(|w| w.handle == handle)?;
window.untag();
window.set_floating(false);
window.tag(&tag.id);
window.apply_margin_multiplier(margin_multiplier);
let act = DisplayAction::SetWindowTag(window.handle, Some(tag.id));
manager.state.actions.push_back(act);
manager.state.sort_windows();
manager
.state
.handle_single_border(manager.config.border_width());
if handle_focus {
if let Some(new_handle) = new_handle {
manager.state.focus_window(&new_handle);
} else {
let act = DisplayAction::Unfocus(Some(handle), false);
manager.state.actions.push_back(act);
manager.state.focus_manager.window_history.push_front(None);
}
}
Some(true)
}
fn move_to_tag_relative<C: Config, SERVER: DisplayServer>(
manager: &mut Manager<C, SERVER>,
follow: bool,
delta: i32,
) -> Option<bool> {
let current_tag = manager.state.focus_manager.tag(0).unwrap_or_default() - 1;
let tags_len = manager.state.tags.normal().len() as isize;
let desired_tag = (current_tag as isize + delta as isize).rem_euclid(tags_len) + 1;
let desired_tag = desired_tag as usize;
move_to_tag(None, desired_tag, manager);
if follow {
let moved_window = *manager.state.focus_manager.window_history.get(1)?;
manager.state.goto_tag_handler(desired_tag);
manager.state.handle_window_focus(&moved_window?);
}
Some(true)
}
fn move_window_to_workspace_change<C: Config, SERVER: DisplayServer>(
manager: &mut Manager<C, SERVER>,
delta: i32,
) -> Option<bool> {
let current = manager
.state
.focus_manager
.workspace(&manager.state.workspaces)?;
let workspace =
helpers::relative_find(&manager.state.workspaces, |w| w == current, delta, true)?.clone();
let tag_id = workspace.tag?;
move_to_tag(None, tag_id, manager)
}
fn goto_tag(state: &mut State, input_tag: TagId, current_tag_swap: bool) -> Option<bool> {
let current_tag = state.focus_manager.tag(0).unwrap_or_default();
let previous_tag = state.focus_manager.tag(1).unwrap_or_default();
let destination_tag = if current_tag_swap && current_tag == input_tag {
previous_tag
} else {
input_tag
};
state.goto_tag_handler(destination_tag)
}
fn return_to_last_tag(state: &mut State) -> Option<bool> {
let previous_tag = state.focus_manager.tag(1).unwrap_or_default();
state.goto_tag_handler(previous_tag)
}
fn focus_window(state: &mut State, param: &str) -> Option<bool> {
match param.parse::<usize>() {
Ok(index) if index > 0 => {
let handle = state
.windows
.iter()
.filter(|w| w.visible())
.nth(index - 1)?
.handle;
state.handle_window_focus(&handle);
None
}
Err(_) => focus_window_by_class(state, param),
Ok(_) => None,
}
}
fn focus_window_by_class(state: &mut State, window_class: &str) -> Option<bool> {
let is_target = |w: &Window| -> bool {
w.res_name
.as_ref()
.zip(w.res_class.as_ref())
.map_or(false, |(res_name, res_class)| {
window_class == res_name || window_class == res_class
})
};
let current_window = state.focus_manager.window(&state.windows)?;
let target_window = if is_target(current_window) {
let previous_window_handle = state.focus_manager.window_history.get(1);
state
.windows
.iter()
.find(|w| Some(&Some(w.handle)) == previous_window_handle)
.cloned()
} else {
state.windows.iter().find(|w| is_target(w)).cloned()
}?;
let handle = target_window.handle;
if target_window.visible() {
state.handle_window_focus(&handle);
return None;
}
let tag_id = target_window.tag?;
state.goto_tag_handler(tag_id)?;
match state
.focus_manager
.workspace(&state.workspaces)
.map(|ws| ws.layout)
{
Some(layout) if layout == Layout::Monocle || layout == Layout::MainAndDeck => {
let mut windows = helpers::vec_extract(&mut state.windows, |w| {
w.has_tag(&tag_id) && w.is_managed() && !w.floating()
});
let cycle = |wins: &mut Vec<Window>, s: &mut State| {
let window_index = wins.iter().position(|w| w.handle == handle).unwrap_or(0);
_ = helpers::cycle_vec(wins, -(window_index as i32));
s.windows.append(wins);
};
if layout == Layout::Monocle && windows.len() > 1 {
cycle(&mut windows, state);
} else if layout == Layout::MainAndDeck && windows.len() > 2 {
let main_window = windows.remove(0);
state.windows.push(main_window);
cycle(&mut windows, state);
} else {
state.windows.append(&mut windows);
}
state.handle_window_focus(&handle);
Some(true)
}
Some(_) => {
state.handle_window_focus(&handle);
Some(true)
}
None => None,
}
}
fn focus_tag_change(state: &mut State, delta: i8) -> Option<bool> {
let current_tag = state.focus_manager.tag(0)?;
let tags = state.tags.normal();
let relative_tag_id = relative_find(tags, |tag| tag.id == current_tag, i32::from(delta), true)
.map(|tag| tag.id)?;
state.goto_tag_handler(relative_tag_id)
}
fn swap_tags(state: &mut State) -> Option<bool> {
if state.workspaces.len() >= 2 && state.focus_manager.workspace_history.len() >= 2 {
let hist_a = *state.focus_manager.workspace_history.get(0)?;
let hist_b = *state.focus_manager.workspace_history.get(1)?;
let mut temp = None;
std::mem::swap(&mut state.workspaces.get_mut(hist_a)?.tag, &mut temp);
std::mem::swap(&mut state.workspaces.get_mut(hist_b)?.tag, &mut temp);
std::mem::swap(&mut state.workspaces.get_mut(hist_a)?.tag, &mut temp);
state.update_static();
state
.layout_manager
.update_layouts(&mut state.workspaces, state.tags.all_mut());
return Some(true);
}
if state.workspaces.len() == 1 {
let last = *state.focus_manager.tag_history.get(1)?;
return state.goto_tag_handler(last);
}
None
}
fn close_window(state: &mut State) -> Option<bool> {
let window = state.focus_manager.window(&state.windows)?;
if window.is_managed() {
let act = DisplayAction::KillWindow(window.handle);
state.actions.push_back(act);
}
None
}
fn move_to_last_workspace(state: &mut State) -> Option<bool> {
if state.workspaces.len() >= 2 && state.focus_manager.workspace_history.len() >= 2 {
let index = *state.focus_manager.workspace_history.get(1)?;
let wp_tags = state.workspaces.get(index)?.tag;
let window = state.focus_manager.window_mut(&mut state.windows)?;
window.tag = wp_tags;
return Some(true);
}
None
}
fn next_layout(state: &mut State) -> Option<bool> {
let workspace = state.focus_manager.workspace_mut(&mut state.workspaces)?;
let layout = state.layout_manager.next_layout(workspace);
set_layout(layout, state)
}
fn previous_layout(state: &mut State) -> Option<bool> {
let workspace = state.focus_manager.workspace_mut(&mut state.workspaces)?;
let layout = state.layout_manager.previous_layout(workspace);
set_layout(layout, state)
}
fn set_layout(layout: Layout, state: &mut State) -> Option<bool> {
let tag_id = state.focus_manager.tag(0)?;
if state.focus_manager.behaviour != FocusBehaviour::Sloppy {
let focused_window = state.focus_manager.window_history.get(0);
let is_focused_floating = match state
.windows
.iter()
.find(|w| Some(&Some(w.handle)) == focused_window)
{
Some(w) => w.floating(),
None => false,
};
if !is_focused_floating {
let mut to_focus = None;
if layout == Layout::Monocle {
to_focus = state
.windows
.iter()
.find(|w| w.has_tag(&tag_id) && w.is_managed() && !w.floating());
} else if layout == Layout::MainAndDeck {
if let Some(&Some(h)) = focused_window {
let mut tags_windows = state
.windows
.iter()
.filter(|w| w.has_tag(&tag_id) && w.is_managed() && !w.floating());
let mw = tags_windows.next();
let tdw = tags_windows.next();
if let (Some(mw), Some(tdw)) = (mw, tdw) {
if mw.handle != h && tdw.handle != h {
to_focus = Some(tdw);
}
}
}
}
if let Some(handle) = to_focus.map(|w| w.handle) {
state.focus_window(&handle);
}
}
}
let workspace = state.focus_manager.workspace_mut(&mut state.workspaces)?;
workspace.layout = layout;
if state.layout_manager.mode == LayoutMode::Workspace {
workspace.main_width_percentage = layout.main_width();
}
let tag = state.tags.get_mut(tag_id)?;
tag.set_layout(layout, layout.main_width());
Some(true)
}
fn floating_to_tile(state: &mut State) -> Option<bool> {
let workspace = state.focus_manager.workspace(&state.workspaces)?;
let window = state.focus_manager.window_mut(&mut state.windows)?;
if window.must_float() {
return None;
}
if !window.floating() {
return None;
}
let handle = window.handle;
if window.snap_to_workspace(workspace) {
state.sort_windows();
}
state.handle_window_focus(&handle);
Some(true)
}
fn tile_to_floating(state: &mut State) -> Option<bool> {
let width = state.default_width;
let height = state.default_height;
let window = state.focus_manager.window_mut(&mut state.windows)?;
if window.must_float() {
return None;
}
if window.floating() {
return None;
}
let mut normal = window.normal;
let offset = window.container_size.unwrap_or_default();
normal.set_x(normal.x() + window.margin.left as i32);
normal.set_y(normal.y() + window.margin.top as i32);
normal.set_w(width);
normal.set_h(height);
let floating = normal - offset;
window.set_floating_offsets(Some(floating));
window.start_loc = Some(floating);
window.set_floating(true);
state.sort_windows();
Some(true)
}
fn toggle_floating(state: &mut State) -> Option<bool> {
let window = state.focus_manager.window(&state.windows)?;
if window.floating() {
floating_to_tile(state)
} else {
tile_to_floating(state)
}
}
fn move_window_change(
state: &mut State,
mut handle: WindowHandle,
layout: Option<Layout>,
mut to_reorder: Vec<Window>,
val: i32,
) -> Option<bool> {
let is_handle = |x: &Window| -> bool { x.handle == handle };
if layout == Some(Layout::Monocle) {
handle = helpers::relative_find(&to_reorder, is_handle, -val, true)?.handle;
_ = helpers::cycle_vec(&mut to_reorder, val);
} else if layout == Some(Layout::MainAndDeck) {
if let Some(index) = to_reorder.iter().position(|x: &Window| !x.floating()) {
let mut window_group = to_reorder.split_off(index + 1);
if !to_reorder.iter().any(|w| w.handle == handle) {
handle = helpers::relative_find(&window_group, is_handle, -val, true)?.handle;
}
_ = helpers::cycle_vec(&mut window_group, val);
to_reorder.append(&mut window_group);
}
} else {
_ = helpers::reorder_vec(&mut to_reorder, is_handle, val);
}
state.windows.append(&mut to_reorder);
state.handle_window_focus(&handle);
Some(true)
}
fn move_window_top(
state: &mut State,
handle: WindowHandle,
_layout: Option<Layout>,
mut to_reorder: Vec<Window>,
swap: bool,
) -> Option<bool> {
let is_handle = |x: &Window| -> bool { x.handle == handle };
let list = &mut to_reorder;
let len = list.len();
let index = list.iter().position(|x| is_handle(x))?;
let item = list.get(index)?.clone();
list.remove(index);
let mut new_index: usize = match index {
0 if swap => 1,
_ => 0,
};
if new_index >= len {
new_index -= len;
}
list.insert(new_index, item);
state.windows.append(&mut to_reorder);
if index > 0 {
state.handle_window_focus(&handle);
}
Some(true)
}
fn swap_window_top(
state: &mut State,
handle: WindowHandle,
_layout: Option<Layout>,
mut to_reorder: Vec<Window>,
swap: bool,
) -> Option<bool> {
let is_handle = |x: &Window| -> bool { x.handle == handle };
let list = &mut to_reorder;
let len = list.len();
let index = list.iter().position(|x| is_handle(x))?;
let mut new_index: usize = match index {
0 if swap => 1,
_ => 0,
};
if new_index >= len {
new_index -= len;
}
list.swap(index, new_index);
state.windows.append(&mut to_reorder);
if index > 0 {
state.handle_window_focus(&handle);
}
Some(true)
}
fn focus_window_change(
state: &mut State,
mut handle: WindowHandle,
layout: Option<Layout>,
mut to_reorder: Vec<Window>,
val: i32,
) -> Option<bool> {
let is_handle = |x: &Window| -> bool { x.handle == handle };
if layout == Some(Layout::Monocle) {
handle = helpers::relative_find(&to_reorder, is_handle, -val, true)?.handle;
_ = helpers::cycle_vec(&mut to_reorder, val);
} else if layout == Some(Layout::MainAndDeck) {
let len = to_reorder.len() as i32;
if len > 0 {
let index = match to_reorder.iter().position(|x: &Window| !x.floating()) {
Some(i) => {
if i as i32 == len - 1 {
i
} else {
i + 1
}
}
None => len.saturating_sub(1) as usize,
};
let window_group = &to_reorder[..=index];
handle = helpers::relative_find(window_group, is_handle, -val, true)?.handle;
}
} else if let Some(new_focused) = helpers::relative_find(&to_reorder, is_handle, val, true) {
handle = new_focused.handle;
}
state.windows.append(&mut to_reorder);
state.handle_window_focus(&handle);
Some(layout == Some(Layout::Monocle))
}
fn focus_window_top(state: &mut State, swap: bool) -> Option<bool> {
let tag = state.focus_manager.tag(0)?;
let cur = state.focus_manager.window(&state.windows).map(|w| w.handle);
let prev = state.focus_manager.tags_last_window.get(&tag).copied();
let next = state
.windows
.iter()
.find(|x| x.tag == Some(tag) && !x.floating() && x.is_managed())
.map(|w| w.handle);
match (next, cur, prev) {
(Some(next), Some(cur), Some(prev)) if next == cur && swap => {
state.handle_window_focus(&prev);
}
(Some(next), Some(cur), _) if next != cur => state.handle_window_focus(&next),
_ => {}
}
None
}
fn close_all_other_windows(state: &mut State) -> Option<bool> {
let current_window: Option<WindowHandle> =
state.focus_manager.window(&state.windows).map(|w| w.handle);
let current_workspace = state.focus_manager.workspace(&state.workspaces);
for window in &state.windows {
if window.handle.ne(¤t_window?)
&& current_workspace?.is_displaying(window)
&& window.r#type.ne(&WindowType::Normal)
{
let act = DisplayAction::KillWindow(window.handle);
state.actions.push_back(act);
}
}
Some(true)
}
fn focus_workspace_change(state: &mut State, val: i32) -> Option<bool> {
let current = state.focus_manager.workspace(&state.workspaces)?;
let workspace = helpers::relative_find(&state.workspaces, |w| w == current, val, true)?.clone();
if state.focus_manager.behaviour.is_sloppy() && state.focus_manager.sloppy_mouse_follows_focus {
let action = workspace
.tag
.as_ref()
.and_then(|tag| state.focus_manager.tags_last_window.get(tag))
.map_or_else(
|| DisplayAction::MoveMouseOverPoint(workspace.xyhw.center()),
|h| DisplayAction::MoveMouseOver(*h, true),
);
state.actions.push_back(action);
}
state.focus_workspace(&workspace);
None
}
fn rotate_tag(state: &mut State) -> Option<bool> {
let tag_id = state.focus_manager.tag(0)?;
let tag = state.tags.get_mut(tag_id)?;
tag.rotate_layout()?;
Some(true)
}
fn change_main_width(state: &mut State, delta: i8, factor: i8) -> Option<bool> {
let workspace = state.focus_manager.workspace_mut(&mut state.workspaces)?;
workspace.change_main_width(delta * factor);
let tag_id = state.focus_manager.tag(0)?;
let tag = state.tags.get_mut(tag_id)?;
tag.change_main_width(delta * factor);
Some(true)
}
fn set_margin_multiplier(state: &mut State, margin_multiplier: f32) -> Option<bool> {
let ws = state.focus_manager.workspace_mut(&mut state.workspaces)?;
ws.set_margin_multiplier(margin_multiplier);
let tag = ws.tag;
if state.windows.iter().any(|w| w.r#type == WindowType::Normal) {
let for_active_workspace =
|x: &Window| -> bool { tag == x.tag && x.r#type == WindowType::Normal };
let mut to_apply_margin_multiplier =
helpers::vec_extract(&mut state.windows, for_active_workspace);
for w in &mut to_apply_margin_multiplier {
if let Some(ws) = state.focus_manager.workspace(&state.workspaces) {
w.apply_margin_multiplier(ws.margin_multiplier());
}
}
state.windows.append(&mut to_apply_margin_multiplier);
}
Some(true)
}
fn send_workspace_to_tag(state: &mut State, ws_index: usize, tag_index: usize) -> bool {
if ws_index < state.workspaces.len() && tag_index < state.tags.len_normal() {
let workspace = &state.workspaces[ws_index].clone();
state.focus_workspace(workspace);
state.goto_tag_handler(tag_index + 1);
return true;
}
false
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::Tags;
fn split_window_vec(windows: Vec<Window>, first_tag_id: usize) -> (Vec<Window>, Vec<Window>) {
let mut windows_first_tag = vec![];
let mut windows_second_tag = vec![];
for w in windows {
if w.tag == Some(first_tag_id) {
windows_first_tag.push(w);
} else {
windows_second_tag.push(w);
}
}
(windows_first_tag, windows_second_tag)
}
fn get_current_handles(
manager: &mut Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
>,
tag_id: Option<TagId>,
) -> Vec<WindowHandle> {
manager
.state
.windows
.iter()
.filter(|window| window.tag == tag_id && window.is_managed())
.map(|w| w.handle)
.collect::<Vec<_>>()
}
fn mock_update(
manager: &mut Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
>,
) {
while let Some(act) = manager.state.actions.pop_front() {
if let DisplayAction::SetState(window_handle, toggle_to, window_state) = act {
if let Some(window) = manager
.state
.windows
.iter_mut()
.find(|w| w.handle == window_handle)
{
if window_state == WindowState::Fullscreen {
if toggle_to {
window.set_states(vec![WindowState::Fullscreen]);
} else if let Some(state_pos) = window
.states()
.iter()
.position(|s| *s == WindowState::Fullscreen)
{
let mut states = window.states();
states.remove(state_pos);
window.set_states(states);
}
}
}
}
}
}
#[test]
fn toggle_fullscreen() {
let mut manager = Manager::new_test(vec!["1".to_string()]);
let tag_id = manager.state.tags.get(1).unwrap().id;
manager.screen_create_handler(Screen::default());
for i in 1..=3 {
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(i), None, None),
-1,
-1,
);
}
let expected = get_current_handles(&mut manager, Some(tag_id));
assert!(!manager
.state
.windows
.iter()
.any(|w| w.has_state(&WindowState::Fullscreen)));
manager.command_handler(&Command::ToggleFullScreen);
mock_update(&mut manager);
assert!(manager
.state
.windows
.iter()
.any(|w| w.has_state(&WindowState::Fullscreen)));
manager.state.windows.reverse();
let actual = get_current_handles(&mut manager, Some(tag_id));
assert_ne!(expected, actual);
manager.command_handler(&Command::ToggleFullScreen);
mock_update(&mut manager);
let actual = get_current_handles(&mut manager, Some(tag_id));
assert_eq!(expected, actual);
}
#[test]
fn toggle_fullscreen_with_multiple_tags() {
let mut manager = Manager::new_test(vec!["1".to_string(), "2".to_string()]);
let first_tag = manager.state.tags.get(1).unwrap().id;
let second_tag = manager.state.tags.get(2).unwrap().id;
manager.screen_create_handler(Screen::default());
for i in 1..=3 {
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(i), None, None),
-1,
-1,
);
}
let expected_first_tag_window_order = get_current_handles(&mut manager, Some(first_tag));
assert!(!manager
.state
.windows
.iter()
.any(|w| w.has_state(&WindowState::Fullscreen)));
manager.command_handler(&Command::ToggleFullScreen);
mock_update(&mut manager);
assert!(manager
.state
.windows
.iter()
.any(|w| w.has_state(&WindowState::Fullscreen)));
manager.state.windows.reverse();
assert!(manager.command_handler(&Command::GoToTag {
tag: 2,
swap: false
}));
for i in 4..=6 {
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(i), None, None),
-1,
-1,
);
}
let expected_second_tag_window_order = get_current_handles(&mut manager, Some(second_tag));
assert_eq!(
manager
.state
.windows
.iter()
.find(|w| w.has_state(&WindowState::Fullscreen))
.iter()
.count(),
1
);
manager.command_handler(&Command::ToggleFullScreen);
mock_update(&mut manager);
assert_eq!(
manager
.state
.windows
.iter()
.filter(|w| w.has_state(&WindowState::Fullscreen))
.count(),
2
);
let (mut windows_first_tag, mut windows_second_tag) =
split_window_vec(manager.state.windows, first_tag);
windows_second_tag.reverse();
windows_first_tag.append(&mut windows_second_tag);
manager.state.windows = windows_first_tag;
manager.command_handler(&Command::GoToTag {
tag: 1,
swap: false,
});
manager.command_handler(&Command::ToggleFullScreen);
mock_update(&mut manager);
manager.command_handler(&Command::GoToTag {
tag: 2,
swap: false,
});
manager.command_handler(&Command::ToggleFullScreen);
mock_update(&mut manager);
let actual_first_tag_window_order = get_current_handles(&mut manager, Some(first_tag));
let actual_second_tag_window_order = get_current_handles(&mut manager, Some(second_tag));
assert_eq!(
expected_first_tag_window_order,
actual_first_tag_window_order
);
assert_eq!(
expected_second_tag_window_order,
actual_second_tag_window_order
);
}
#[test]
fn return_to_last_tag_should_go_back_to_last_tag() {
let mut manager = Manager::new_test(vec![
"A15".to_string(),
"B24".to_string(),
"C".to_string(),
"6D4".to_string(),
"E39".to_string(),
"F67".to_string(),
]);
manager.screen_create_handler(Screen::default());
manager.screen_create_handler(Screen::default());
assert!(manager.command_handler(&Command::GoToTag {
tag: 1,
swap: false
}));
let current_tag = manager.state.focus_manager.tag(0).unwrap();
assert_eq!(current_tag, 1);
assert!(manager.command_handler(&Command::GoToTag {
tag: 2,
swap: false
}));
let current_tag = manager.state.focus_manager.tag(0).unwrap_or_default();
assert_eq!(current_tag, 2);
manager.command_handler(&Command::ReturnToLastTag);
let current_tag = manager.state.focus_manager.tag(0).unwrap_or_default();
assert_eq!(current_tag, 1);
}
#[test]
fn go_to_tag_should_return_false_if_no_screen_is_created() {
let mut manager = Manager::new_test(vec![]);
assert!(!manager.command_handler(&Command::GoToTag {
tag: 6,
swap: false
}));
assert!(!manager.command_handler(&Command::GoToTag {
tag: 2,
swap: false
}));
assert!(!manager.command_handler(&Command::GoToTag {
tag: 15,
swap: false
}));
}
#[test]
fn go_to_tag_should_create_at_least_one_tag_per_screen_no_more() {
let mut manager = Manager::new_test(vec![]);
manager.screen_create_handler(Screen::default());
manager.screen_create_handler(Screen::default());
assert!(manager.command_handler(&Command::GoToTag {
tag: 2,
swap: false
}));
assert!(manager.command_handler(&Command::GoToTag {
tag: 1,
swap: false
}));
assert!(!manager.command_handler(&Command::GoToTag {
tag: 3,
swap: false
}));
}
#[test]
fn go_to_tag_should_return_false_on_invalid_input() {
let mut manager = Manager::new_test(vec![]);
manager.screen_create_handler(Screen::default());
manager.state.tags = Tags::new();
manager.state.tags.add_new("A15", Layout::default());
manager.state.tags.add_new("B24", Layout::default());
manager.state.tags.add_new("C", Layout::default());
manager.state.tags.add_new("6D4", Layout::default());
manager.state.tags.add_new("E39", Layout::default());
manager.state.tags.add_new("F67", Layout::default());
assert!(!manager.command_handler(&Command::GoToTag {
tag: 0,
swap: false
}));
assert!(!manager.command_handler(&Command::GoToTag {
tag: 999,
swap: false
}));
}
#[test]
fn go_to_tag_should_go_to_tag_and_set_history() {
let mut manager = Manager::new_test(vec![
"A15".to_string(),
"B24".to_string(),
"C".to_string(),
"6D4".to_string(),
"E39".to_string(),
"F67".to_string(),
]);
manager.screen_create_handler(Screen::default());
manager.screen_create_handler(Screen::default());
assert!(manager.command_handler(&Command::GoToTag {
tag: 6,
swap: false
}));
let current_tag = manager.state.focus_manager.tag(0).unwrap();
assert_eq!(current_tag, 6);
assert!(manager.command_handler(&Command::GoToTag {
tag: 2,
swap: false
}));
let current_tag = manager.state.focus_manager.tag(0).unwrap_or_default();
assert_eq!(current_tag, 2);
assert!(manager.command_handler(&Command::GoToTag {
tag: 3,
swap: false
}));
let current_tag = manager.state.focus_manager.tag(0).unwrap_or_default();
assert_eq!(current_tag, 3);
assert!(manager.command_handler(&Command::GoToTag {
tag: 4,
swap: false
}));
let current_tag = manager.state.focus_manager.tag(0).unwrap_or_default();
assert_eq!(current_tag, 4);
assert_eq!(manager.state.focus_manager.tag(1).unwrap_or_default(), 3);
assert_eq!(manager.state.focus_manager.tag(2).unwrap_or_default(), 2);
assert_eq!(manager.state.focus_manager.tag(3).unwrap_or_default(), 6);
}
#[test]
fn focus_tag_change_should_go_to_previous_and_next_tag() {
let mut manager = Manager::new_test(vec![
"A15".to_string(),
"B24".to_string(),
"C".to_string(),
"6D4".to_string(),
"E39".to_string(),
"F67".to_string(),
]);
manager.screen_create_handler(Screen::default());
let state = &mut manager.state;
state.focus_tag(&2);
assert_eq!(state.focus_manager.tag(0).unwrap(), 2);
focus_tag_change(state, 1);
assert_eq!(state.focus_manager.tag(0).unwrap(), 3);
focus_tag_change(state, -1);
assert_eq!(state.focus_manager.tag(0).unwrap(), 2);
focus_tag_change(state, 2);
assert_eq!(state.focus_manager.tag(0).unwrap(), 4);
focus_tag_change(state, -5);
assert_eq!(state.focus_manager.tag(0).unwrap(), 5);
focus_tag_change(state, 3);
assert_eq!(state.focus_manager.tag(0).unwrap(), 2);
focus_tag_change(state, 13);
assert_eq!(state.focus_manager.tag(0).unwrap(), 3);
}
#[test]
fn focus_window_top() {
let mut manager = Manager::new_test(vec![]);
manager.screen_create_handler(Screen::default());
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(1), None, None),
-1,
-1,
);
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(2), None, None),
-1,
-1,
);
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(3), None, None),
-1,
-1,
);
let expected = manager.state.windows[0].clone();
let initial = manager.state.windows[1].clone();
manager.state.focus_window(&initial.handle);
manager.command_handler(&Command::FocusWindowTop { swap: false });
let actual = manager
.state
.focus_manager
.window(&manager.state.windows)
.unwrap()
.handle;
assert_eq!(expected.handle, actual);
manager.command_handler(&Command::FocusWindowTop { swap: false });
let actual = manager
.state
.focus_manager
.window(&manager.state.windows)
.unwrap()
.handle;
assert_eq!(expected.handle, actual);
manager.command_handler(&Command::FocusWindowTop { swap: true });
let actual = manager
.state
.focus_manager
.window(&manager.state.windows)
.unwrap()
.handle;
assert_eq!(initial.handle, actual);
}
#[test]
fn move_window_top() {
let mut manager = Manager::new_test(vec![]);
manager.screen_create_handler(Screen::default());
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(1), None, None),
-1,
-1,
);
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(2), None, None),
-1,
-1,
);
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(3), None, None),
-1,
-1,
);
let expected = manager.state.windows[0].clone();
let initial = manager.state.windows[1].clone();
manager.state.focus_window(&initial.handle);
manager.command_handler(&Command::MoveWindowTop { swap: false });
assert_eq!(manager.state.windows[0].handle, initial.handle);
manager.command_handler(&Command::MoveWindowTop { swap: false });
assert_eq!(manager.state.windows[0].handle, initial.handle);
manager.command_handler(&Command::MoveWindowTop { swap: true });
assert_eq!(manager.state.windows[0].handle, expected.handle);
}
#[test]
fn move_window_to_next_or_prev_tag_should_be_able_to_cycle() {
let mut manager = Manager::new_test(vec![
"AO".to_string(),
"EU".to_string(),
"ID".to_string(),
"HT".to_string(),
"NS".to_string(),
]);
manager.screen_create_handler(Screen::default());
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(1), None, None),
-1,
-1,
);
let first_tag = manager.state.tags.get(1).unwrap().id;
let third_tag = manager.state.tags.get(3).unwrap().id;
let last_tag = manager.state.tags.get(5).unwrap().id;
assert!(manager.state.windows[0].has_tag(&first_tag));
manager.command_handler(&Command::MoveWindowToPreviousTag { follow: true });
assert!(manager.state.windows[0].has_tag(&last_tag));
(0..3).for_each(|_| {
manager.command_handler(&Command::MoveWindowToNextTag { follow: false });
manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::Default,
});
});
assert!(manager.state.windows[0].has_tag(&third_tag));
}
#[test]
fn move_window_to_next_or_prev_tag_should_be_able_to_keep_window_focused() {
let mut manager = Manager::new_test(vec!["AO".to_string(), "EU".to_string()]);
manager.screen_create_handler(Screen::default());
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(1), None, None),
-1,
-1,
);
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(2), None, None),
-1,
-1,
);
let expected_tag = manager.state.tags.get(2).unwrap().id;
manager.command_handler(&Command::SendWindowToTag {
window: None,
tag: expected_tag,
});
let initial = manager.state.windows[0].clone();
manager.command_handler(&Command::MoveWindowToNextTag { follow: true });
assert_eq!(
*manager.state.focus_manager.tag_history.get(0).unwrap(),
expected_tag
);
assert_eq!(manager.state.windows[0].handle, initial.handle);
}
#[test]
fn after_moving_second_window_remaining_single_window_has_no_border() {
let mut manager = Manager::new_test_with_border(vec!["1".to_string(), "2".to_string()], 1);
manager.screen_create_handler(Screen::default());
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(1), None, None),
-1,
-1,
);
manager.window_created_handler(
Window::new(WindowHandle::MockHandle(2), None, None),
-1,
-1,
);
let first_tag = manager.state.tags.get(1).unwrap().id;
assert!(manager.state.windows[0].has_tag(&first_tag));
assert!(manager.state.windows[0].border() > 0);
let second_tag = manager.state.tags.get(2).unwrap().id;
assert!(manager.command_handler(&Command::SendWindowToTag {
window: Some(manager.state.windows[0].handle),
tag: second_tag,
}));
assert_eq!(manager.state.windows[0].border(), 0);
}
#[test]
fn after_moving_single_window_to_another_single_window_both_have_borders() {
let mut manager = Manager::new_test_with_border(vec!["1".to_string(), "2".to_string()], 1);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&2);
manager.window_created_handler(second_window, -1, -1);
let second_tag = manager.state.tags.get(2).unwrap().id;
assert!(manager.command_handler(&Command::SendWindowToTag {
window: Some(manager.state.windows[0].handle),
tag: second_tag,
}));
assert_eq!(manager.state.windows[0].border(), 1);
assert_eq!(manager.state.windows[1].border(), 1);
}
#[test]
fn goto_next_empty_tag_while_in_used_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Used".to_string(), "Empty".to_string()]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&1);
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_next_empty_tag_while_in_empty_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Emtpy_One".to_string(), "Empty".to_string()]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&1);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_next_empty_tag_multiple_tags() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec![
"A".to_string(),
"B".to_string(),
"C".to_string(),
"D".to_string(),
]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&1);
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&1);
manager.window_created_handler(second_window, -1, -1);
let mut third_window = Window::new(WindowHandle::MockHandle(3), None, None);
third_window.tag(&2);
let third_window_handle = third_window.handle;
manager.window_created_handler(third_window, -1, -1);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 3);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 4);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 3);
manager.window_destroyed_handler(&third_window_handle);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_previous_empty_tag_while_in_used_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Used".to_string(), "Empty".to_string()]);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&2);
manager.window_created_handler(first_window, -1, -1);
manager.state.focus_tag(&2);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
}
#[test]
fn goto_previous_empty_tag_while_in_empty_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Emtpy_One".to_string(), "Empty".to_string()]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&2);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
}
#[test]
fn goto_previous_empty_tag_multiple_tags() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec![
"A".to_string(),
"B".to_string(),
"C".to_string(),
"D".to_string(),
]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&1);
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&1);
manager.window_created_handler(second_window, -1, -1);
let mut third_window = Window::new(WindowHandle::MockHandle(3), None, None);
third_window.tag(&2);
let third_window_handle = third_window.handle;
manager.window_created_handler(third_window, -1, -1);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 4);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 3);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 4);
manager.window_destroyed_handler(&third_window_handle);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreUsed
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_next_used_tag_while_in_used_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Used".to_string(), "Empty".to_string()]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&1);
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&2);
manager.window_created_handler(second_window, -1, -1);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_next_used_tag_while_in_empty_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Emtpy_One".to_string(), "Used".to_string()]);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&2);
manager.window_created_handler(first_window, -1, -1);
manager.state.focus_tag(&1);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_next_used_tag_multiple_tags() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec![
"A".to_string(),
"B".to_string(),
"C".to_string(),
"D".to_string(),
]);
manager.screen_create_handler(Screen::default());
manager.state.focus_tag(&1);
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&2);
manager.window_created_handler(second_window, -1, -1);
let mut third_window = Window::new(WindowHandle::MockHandle(3), None, None);
third_window.tag(&4);
let third_window_handle = third_window.handle;
manager.window_created_handler(third_window, -1, -1);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 4);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
manager.window_destroyed_handler(&third_window_handle);
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert!(manager.command_handler(&Command::FocusNextTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
}
#[test]
fn goto_previous_used_tag_while_in_used_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["A".to_string(), "B".to_string(), "C".to_string()]);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&2);
manager.window_created_handler(second_window, -1, -1);
manager.state.focus_tag(&2);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
}
#[test]
fn goto_previous_used_tag_while_in_empty_tag() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["Emtpy_One".to_string(), "Used".to_string()]);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&2);
manager.window_created_handler(first_window, -1, -1);
manager.state.focus_tag(&1);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
}
#[test]
fn goto_previous_used_tag_multiple_tags() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec![
"A".to_string(),
"B".to_string(),
"C".to_string(),
"D".to_string(),
"E".to_string(),
]);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&1);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&2);
manager.window_created_handler(second_window, -1, -1);
let mut third_window = Window::new(WindowHandle::MockHandle(3), None, None);
third_window.tag(&4);
let third_window_handle = third_window.handle;
manager.window_created_handler(third_window, -1, -1);
manager.state.focus_tag(&4);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 2);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 4);
manager.window_destroyed_handler(&third_window_handle);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 1);
}
#[test]
fn goto_previous_used_tag_wraparound() {
let mut manager: Manager<
crate::config::tests::TestConfig,
crate::display_servers::MockDisplayServer,
> = Manager::new_test(vec!["A".to_string(), "B".to_string(), "C".to_string()]);
manager.screen_create_handler(Screen::default());
let mut first_window = Window::new(WindowHandle::MockHandle(1), None, None);
first_window.tag(&3);
manager.window_created_handler(first_window, -1, -1);
let mut second_window = Window::new(WindowHandle::MockHandle(2), None, None);
second_window.tag(&2);
manager.window_created_handler(second_window, -1, -1);
manager.state.focus_tag(&2);
assert!(manager.command_handler(&Command::FocusPreviousTag {
behavior: FocusDeltaBehavior::IgnoreEmpty
}));
assert_eq!(manager.state.focus_manager.tag(0).unwrap(), 3);
}
}