use super::*;
use crate::compositor::actions::window::toggle_focused_active_node_state;
use halley_core::field::Vec2;
use smithay::reexports::wayland_server::Display;
fn single_monitor_tuning() -> halley_config::RuntimeTuning {
let mut tuning = halley_config::RuntimeTuning::default();
tuning.cluster_default_layout = halley_config::ClusterDefaultLayout::Tiling;
tuning.tile_gaps_outer_px = 20.0;
tuning.tile_gaps_inner_px = 20.0;
tuning.decorations.border.size_px = 0;
tuning.tty_viewports = vec![halley_config::ViewportOutputConfig {
connector: "monitor_a".to_string(),
enabled: true,
offset_x: 0,
offset_y: 0,
width: 800,
height: 600,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
}];
tuning
}
fn dual_monitor_tuning() -> halley_config::RuntimeTuning {
let mut tuning = halley_config::RuntimeTuning::default();
tuning.tty_viewports = vec![
halley_config::ViewportOutputConfig {
connector: "monitor_a".to_string(),
enabled: true,
offset_x: 0,
offset_y: 0,
width: 800,
height: 600,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
},
halley_config::ViewportOutputConfig {
connector: "monitor_b".to_string(),
enabled: true,
offset_x: 800,
offset_y: 0,
width: 800,
height: 600,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
},
];
tuning
}
fn assert_close(actual: f32, expected: f32) {
assert!(
(actual - expected).abs() <= 0.5,
"expected {expected}, got {actual}"
);
}
fn node_edges(st: &Halley, id: NodeId) -> (f32, f32, f32, f32) {
let node = st.model.field.node(id).expect("node");
let half_w = node.intrinsic_size.x * 0.5;
let half_h = node.intrinsic_size.y * 0.5;
(
node.pos.x - half_w,
node.pos.y - half_h,
node.pos.x + half_w,
node.pos.y + half_h,
)
}
fn create_named_test_cluster(
st: &mut Halley,
monitor: &str,
labels: [&str; 2],
x: f32,
) -> (ClusterId, NodeId) {
let a =
st.model
.field
.spawn_surface(labels[0], Vec2 { x, y: 120.0 }, Vec2 { x: 240.0, y: 180.0 });
let b = st.model.field.spawn_surface(
labels[1],
Vec2 {
x: x + 260.0,
y: 120.0,
},
Vec2 { x: 240.0, y: 180.0 },
);
st.assign_node_to_monitor(a, monitor);
st.assign_node_to_monitor(b, monitor);
let cid = st.create_cluster(vec![a, b]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, monitor);
let _ =
cluster_system_controller(&mut *st).ensure_cluster_name_record_for_monitor(cid, monitor);
(cid, core)
}
fn core_pos(st: &Halley, core: NodeId) -> Vec2 {
st.model.field.node(core).expect("core").pos
}
#[test]
fn generic_cluster_names_are_monitor_local_reclaimable_and_moveable() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, dual_monitor_tuning());
let (cid_a1, core_a1) = create_named_test_cluster(&mut st, "monitor_a", ["a1", "a2"], 120.0);
let (_cid_a2, core_a2) = create_named_test_cluster(&mut st, "monitor_a", ["a3", "a4"], 520.0);
assert_eq!(
st.model.field.node(core_a1).expect("core a1").label,
"Cluster 1"
);
assert_eq!(
st.model.field.node(core_a2).expect("core a2").label,
"Cluster 2"
);
let (_cid_b1, core_b1) = create_named_test_cluster(&mut st, "monitor_b", ["b1", "b2"], 920.0);
let (_cid_b2, core_b2) = create_named_test_cluster(&mut st, "monitor_b", ["b3", "b4"], 1320.0);
assert_eq!(
st.model.field.node(core_b1).expect("core b1").label,
"Cluster 1"
);
assert_eq!(
st.model.field.node(core_b2).expect("core b2").label,
"Cluster 2"
);
let member_to_remove = st
.model
.field
.cluster(cid_a1)
.expect("cluster a1")
.members()[0];
let _ = st.remove_node_from_field(member_to_remove, st.now_ms(Instant::now()));
let (_cid_a3, core_a3) = create_named_test_cluster(&mut st, "monitor_a", ["a5", "a6"], 220.0);
assert_eq!(
st.model.field.node(core_a3).expect("core a3").label,
"Cluster 1"
);
st.assign_node_to_monitor(core_a3, "monitor_b");
let _ = st.sync_cluster_monitor(
st.model
.field
.cluster_id_for_core_public(core_a3)
.expect("cluster for moved core"),
Some("monitor_b"),
);
assert_eq!(
st.model
.field
.node(core_a3)
.expect("moved generic core")
.label,
"Cluster 3"
);
}
#[test]
fn cluster_slot_order_is_creation_order_per_monitor() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, dual_monitor_tuning());
let (cid_a1, _core_a1) = create_named_test_cluster(&mut st, "monitor_a", ["a1", "a2"], 120.0);
let (cid_a2, _core_a2) = create_named_test_cluster(&mut st, "monitor_a", ["a3", "a4"], 520.0);
let (cid_b1, _core_b1) = create_named_test_cluster(&mut st, "monitor_b", ["b1", "b2"], 920.0);
assert_eq!(
cluster_system_controller(&st).cluster_slot_order_for_monitor("monitor_a"),
vec![cid_a1, cid_a2]
);
assert_eq!(
cluster_system_controller(&st).cluster_slot_order_for_monitor("monitor_b"),
vec![cid_b1]
);
}
#[test]
fn cluster_slot_action_pans_then_opens_target_cluster() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let (cid, core) = create_named_test_cluster(&mut st, "monitor_a", ["a1", "a2"], 120.0);
st.model.viewport.center = Vec2 { x: 700.0, y: 300.0 };
st.model.camera_target_center = st.model.viewport.center;
assert!(st.activate_cluster_slot_on_current_monitor(1, Instant::now()));
assert_eq!(st.active_cluster_workspace_for_monitor("monitor_a"), None);
assert!(
st.model
.cluster_state
.pending_cluster_slot_transition
.contains_key("monitor_a")
);
st.input.interaction_state.viewport_pan_anim = None;
st.model.viewport.center = core_pos(&st, core);
st.model.camera_target_center = st.model.viewport.center;
assert!(st.process_pending_cluster_slot_transition_for_current_monitor(Instant::now()));
assert_eq!(
st.active_cluster_workspace_for_monitor("monitor_a"),
Some(cid)
);
}
#[test]
fn cluster_slot_action_switches_between_clusters_with_collapse_then_open() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let (_cid_a, core_a) = create_named_test_cluster(&mut st, "monitor_a", ["a1", "a2"], 120.0);
let (cid_b, core_b) = create_named_test_cluster(&mut st, "monitor_a", ["b1", "b2"], 820.0);
st.model.viewport.center = core_pos(&st, core_a);
st.model.camera_target_center = st.model.viewport.center;
assert!(st.activate_cluster_slot_on_current_monitor(1, Instant::now()));
assert_eq!(
st.active_cluster_workspace_for_monitor("monitor_a")
.is_some(),
true
);
assert!(st.activate_cluster_slot_on_current_monitor(2, Instant::now()));
assert_eq!(st.active_cluster_workspace_for_monitor("monitor_a"), None);
assert!(
st.model
.cluster_state
.pending_cluster_slot_transition
.contains_key("monitor_a")
);
st.input.interaction_state.viewport_pan_anim = None;
st.model.viewport.center = core_pos(&st, core_b);
st.model.camera_target_center = st.model.viewport.center;
assert!(st.process_pending_cluster_slot_transition_for_current_monitor(Instant::now()));
assert_eq!(
st.active_cluster_workspace_for_monitor("monitor_a"),
Some(cid_b)
);
}
#[test]
fn cluster_slot_action_toggles_same_cluster_back_to_core() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let (_cid, core) = create_named_test_cluster(&mut st, "monitor_a", ["a1", "a2"], 120.0);
st.model.viewport.center = core_pos(&st, core);
st.model.camera_target_center = st.model.viewport.center;
assert!(st.activate_cluster_slot_on_current_monitor(1, Instant::now()));
assert!(
st.active_cluster_workspace_for_monitor("monitor_a")
.is_some()
);
assert!(st.activate_cluster_slot_on_current_monitor(1, Instant::now()));
assert_eq!(st.active_cluster_workspace_for_monitor("monitor_a"), None);
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(core));
}
#[test]
fn cluster_mode_confirm_opens_name_prompt_before_creating() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let now = Instant::now();
let first = st.model.field.spawn_surface(
"first",
Vec2 { x: 160.0, y: 160.0 },
Vec2 { x: 220.0, y: 160.0 },
);
let second = st.model.field.spawn_surface(
"second",
Vec2 { x: 460.0, y: 160.0 },
Vec2 { x: 220.0, y: 160.0 },
);
st.assign_node_to_monitor(first, "monitor_a");
st.assign_node_to_monitor(second, "monitor_a");
assert!(st.enter_cluster_mode());
assert!(st.toggle_cluster_mode_selection(first));
assert!(st.toggle_cluster_mode_selection(second));
assert!(st.confirm_cluster_mode(now));
assert!(
st.model
.cluster_state
.cluster_name_prompt
.contains_key("monitor_a")
);
assert!(st.model.field.cluster_id_for_member_public(first).is_none());
assert!(
st.model
.field
.cluster_id_for_member_public(second)
.is_none()
);
assert!(cluster_system_controller(&mut st).cancel_cluster_name_prompt_for_monitor("monitor_a"));
assert!(
!st.model
.cluster_state
.cluster_name_prompt
.contains_key("monitor_a")
);
assert!(st.cluster_mode_active_for_monitor("monitor_a"));
assert_eq!(
st.model
.cluster_state
.cluster_mode_selected_nodes
.get("monitor_a")
.map(|nodes| nodes.len()),
Some(2)
);
assert!(st.exit_cluster_mode());
assert!(!st.cluster_mode_active_for_monitor("monitor_a"));
}
#[test]
fn custom_cluster_name_stays_unique_and_survives_monitor_move() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, dual_monitor_tuning());
let (cid, core) = create_named_test_cluster(&mut st, "monitor_a", ["x", "y"], 120.0);
st.model.cluster_state.cluster_names.insert(
cid,
crate::compositor::clusters::state::ClusterNameRecord::Custom {
name: "Studio".to_string(),
},
);
let _ = cluster_system_controller(&mut st).relabel_cluster_core(cid);
st.assign_node_to_monitor(core, "monitor_b");
let _ = st.sync_cluster_monitor(cid, Some("monitor_b"));
assert_eq!(
st.model.field.node(core).expect("custom core").label,
"Studio"
);
}
#[test]
fn test_cluster_monitor_transfer_reopen() {
let mut tuning = halley_config::RuntimeTuning::default();
tuning.tty_viewports = vec![
halley_config::ViewportOutputConfig {
connector: "monitor_a".to_string(),
enabled: true,
offset_x: 0,
offset_y: 0,
width: 1920,
height: 1080,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
},
halley_config::ViewportOutputConfig {
connector: "monitor_b".to_string(),
enabled: true,
offset_x: 1920,
offset_y: 0,
width: 1920,
height: 1080,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
},
];
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, tuning);
let n1 = st.model.field.spawn_surface(
"monitor_a",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 400.0, y: 300.0 },
);
let n2 = st.model.field.spawn_surface(
"monitor_a",
Vec2 { x: 600.0, y: 100.0 },
Vec2 { x: 400.0, y: 300.0 },
);
st.assign_node_to_monitor(n1, "monitor_a");
st.assign_node_to_monitor(n2, "monitor_a");
let cid = st.create_cluster(vec![n1, n2]).expect("cluster");
let core_id = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core_id, "monitor_a");
st.assign_node_to_monitor(core_id, "monitor_b");
let _ = st.model.field.carry(
core_id,
Vec2 {
x: 1920.0 + 500.0,
y: 500.0,
},
);
let now = Instant::now();
st.focus_monitor_view("monitor_b", now);
let success = st.enter_cluster_workspace_by_core(core_id, "monitor_b", now);
assert!(success);
assert_eq!(
st.model
.monitor_state
.node_monitor
.get(&n1)
.map(|s| s.as_str()),
Some("monitor_b")
);
assert_eq!(
st.model
.monitor_state
.node_monitor
.get(&n2)
.map(|s| s.as_str()),
Some("monitor_b")
);
assert_eq!(
st.model
.monitor_state
.node_monitor
.get(&core_id)
.map(|s| s.as_str()),
Some("monitor_b")
);
}
#[test]
fn test_cluster_monitor_maintenance_sync() {
let mut tuning = halley_config::RuntimeTuning::default();
tuning.tty_viewports = vec![
halley_config::ViewportOutputConfig {
connector: "monitor_a".to_string(),
enabled: true,
offset_x: 0,
offset_y: 0,
width: 1920,
height: 1080,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
},
halley_config::ViewportOutputConfig {
connector: "monitor_b".to_string(),
enabled: true,
offset_x: 1920,
offset_y: 0,
width: 1920,
height: 1080,
refresh_rate: None,
transform_degrees: 0,
vrr: halley_config::ViewportVrrMode::Off,
focus_ring: None,
},
];
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, tuning);
let n1 = st.model.field.spawn_surface(
"monitor_a",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 400.0, y: 300.0 },
);
let n2 = st.model.field.spawn_surface(
"monitor_a",
Vec2 { x: 600.0, y: 100.0 },
Vec2 { x: 400.0, y: 300.0 },
);
st.assign_node_to_monitor(n1, "monitor_a");
st.assign_node_to_monitor(n2, "monitor_a");
let cid = st.create_cluster(vec![n1, n2]).expect("cluster");
let core_id = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core_id, "monitor_a");
st.assign_node_to_monitor(n1, "monitor_a");
st.assign_node_to_monitor(n2, "monitor_a");
st.assign_node_to_monitor(core_id, "monitor_b");
let success = st.sync_cluster_monitor(cid, None);
assert!(success);
assert_eq!(
st.model
.monitor_state
.node_monitor
.get(&n1)
.map(|s| s.as_str()),
Some("monitor_b")
);
assert_eq!(
st.model
.monitor_state
.node_monitor
.get(&n2)
.map(|s| s.as_str()),
Some("monitor_b")
);
assert_eq!(
st.model
.monitor_state
.node_monitor
.get(&core_id)
.map(|s| s.as_str()),
Some("monitor_b")
);
}
#[test]
fn entering_two_window_cluster_keeps_outer_gap_exact() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
st.assign_node_to_monitor(master, "monitor_a");
st.assign_node_to_monitor(stack, "monitor_a");
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
let (master_left, master_top, master_right, master_bottom) = node_edges(&st, master);
let (stack_left, stack_top, stack_right, stack_bottom) = node_edges(&st, stack);
assert_close(master_left, 20.0);
assert_close(master_top, 20.0);
assert_close(master_bottom, 580.0);
assert_close(stack_top, 20.0);
assert_close(stack_bottom, 580.0);
assert_close(stack_right, 780.0);
assert_close(stack_left - master_right, 20.0);
}
#[test]
fn entering_three_window_cluster_keeps_master_outer_gap_exact() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_a = st.model.field.spawn_surface(
"stack-a",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_b = st.model.field.spawn_surface(
"stack-b",
Vec2 { x: 500.0, y: 400.0 },
Vec2 { x: 320.0, y: 240.0 },
);
for id in [master, stack_a, stack_b] {
st.assign_node_to_monitor(id, "monitor_a");
}
let cid = st
.create_cluster(vec![master, stack_a, stack_b])
.expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
let (_, master_top, master_right, master_bottom) = node_edges(&st, master);
let mut stack_edges = [node_edges(&st, stack_a), node_edges(&st, stack_b)];
stack_edges.sort_by(|a, b| a.1.partial_cmp(&b.1).expect("finite"));
let upper = stack_edges[0];
let lower = stack_edges[1];
assert_close(master_top, 20.0);
assert_close(master_bottom, 580.0);
assert_close(upper.1, 20.0);
assert_close(lower.3, 580.0);
assert_close(lower.1 - upper.3, 20.0);
assert_close(upper.0 - master_right, 20.0);
}
#[test]
fn entering_cluster_keeps_current_monitor_live_viewport_full_size() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let full_viewport = st.model.viewport;
st.model
.monitor_state
.monitors
.get_mut("monitor_a")
.expect("monitor")
.usable_viewport = halley_core::viewport::Viewport::new(
Vec2 { x: 400.0, y: 320.0 },
Vec2 { x: 800.0, y: 560.0 },
);
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
st.assign_node_to_monitor(master, "monitor_a");
st.assign_node_to_monitor(stack, "monitor_a");
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", Instant::now()));
assert_eq!(st.model.viewport, full_viewport);
assert_eq!(st.model.camera_target_view_size, full_viewport.size);
}
#[test]
fn entering_tiled_cluster_workspace_focuses_master_tile() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
st.assign_node_to_monitor(master, "monitor_a");
st.assign_node_to_monitor(stack, "monitor_a");
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", Instant::now()));
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(master));
}
#[test]
fn tiled_cluster_focus_retargets_replacement_tile_by_index() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_a = st.model.field.spawn_surface(
"stack-a",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_b = st.model.field.spawn_surface(
"stack-b",
Vec2 { x: 500.0, y: 400.0 },
Vec2 { x: 320.0, y: 240.0 },
);
for id in [master, stack_a, stack_b] {
st.assign_node_to_monitor(id, "monitor_a");
}
let cid = st
.create_cluster(vec![master, stack_a, stack_b])
.expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
let removed = cluster_system_controller(&mut st).detach_member_from_cluster(
cid,
stack_a,
Vec2 { x: 0.0, y: 0.0 },
now,
);
assert!(removed);
st.layout_active_cluster_workspace_for_monitor("monitor_a", st.now_ms(now));
assert!(st.focus_active_tiled_cluster_member_for_monitor("monitor_a", Some(1), now));
assert_eq!(
st.model.focus_state.primary_interaction_focus,
Some(stack_b)
);
}
#[test]
fn tile_focus_moves_between_visible_neighbors() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_a = st.model.field.spawn_surface(
"stack-a",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_b = st.model.field.spawn_surface(
"stack-b",
Vec2 { x: 500.0, y: 400.0 },
Vec2 { x: 320.0, y: 240.0 },
);
for id in [master, stack_a, stack_b] {
st.assign_node_to_monitor(id, "monitor_a");
}
let cid = st
.create_cluster(vec![master, stack_a, stack_b])
.expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
assert!(st.tile_focus_active_cluster_member_for_monitor(
"monitor_a",
DirectionalAction::Right,
now,
));
assert_eq!(
st.model.focus_state.primary_interaction_focus,
Some(stack_a)
);
assert!(st.tile_focus_active_cluster_member_for_monitor(
"monitor_a",
DirectionalAction::Down,
now,
));
assert_eq!(
st.model.focus_state.primary_interaction_focus,
Some(stack_b)
);
assert!(st.tile_focus_active_cluster_member_for_monitor(
"monitor_a",
DirectionalAction::Left,
now,
));
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(master));
}
#[test]
fn tile_swap_exchanges_adjacent_visible_tiles() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_a = st.model.field.spawn_surface(
"stack-a",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_b = st.model.field.spawn_surface(
"stack-b",
Vec2 { x: 500.0, y: 400.0 },
Vec2 { x: 320.0, y: 240.0 },
);
for id in [master, stack_a, stack_b] {
st.assign_node_to_monitor(id, "monitor_a");
}
let cid = st
.create_cluster(vec![master, stack_a, stack_b])
.expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
st.set_interaction_focus(Some(stack_a), 30_000, now);
let before_a = st
.active_cluster_tile_rect_for_member("monitor_a", stack_a)
.expect("stack a rect");
let before_b = st
.active_cluster_tile_rect_for_member("monitor_a", stack_b)
.expect("stack b rect");
assert!(st.tile_swap_active_cluster_member_for_monitor(
"monitor_a",
DirectionalAction::Down,
now,
));
assert_eq!(
st.model.focus_state.primary_interaction_focus,
Some(stack_a)
);
let after_a = st
.active_cluster_tile_rect_for_member("monitor_a", stack_a)
.expect("stack a rect after swap");
let after_b = st
.active_cluster_tile_rect_for_member("monitor_a", stack_b)
.expect("stack b rect after swap");
assert!((after_a.y - before_b.y).abs() <= 0.5);
assert!((after_b.y - before_a.y).abs() <= 0.5);
}
#[test]
fn cluster_layout_cycle_toggles_active_workspace_layout() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
for id in [master, stack] {
st.assign_node_to_monitor(id, "monitor_a");
}
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
assert_eq!(
st.runtime.tuning.cluster_layout_kind(),
ClusterWorkspaceLayoutKind::Tiling
);
assert!(st.cycle_active_cluster_layout_for_monitor("monitor_a", now));
assert_eq!(
st.runtime.tuning.cluster_layout_kind(),
ClusterWorkspaceLayoutKind::Stacking
);
assert!(st.cycle_active_cluster_layout_for_monitor("monitor_a", now));
assert_eq!(
st.runtime.tuning.cluster_layout_kind(),
ClusterWorkspaceLayoutKind::Tiling
);
}
#[test]
fn switching_from_tiling_to_stacking_focuses_front_stack_member() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_a = st.model.field.spawn_surface(
"stack-a",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack_b = st.model.field.spawn_surface(
"stack-b",
Vec2 { x: 500.0, y: 400.0 },
Vec2 { x: 320.0, y: 240.0 },
);
for id in [master, stack_a, stack_b] {
st.assign_node_to_monitor(id, "monitor_a");
}
let cid = st
.create_cluster(vec![master, stack_a, stack_b])
.expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
assert!(st.tile_focus_active_cluster_member_for_monitor(
"monitor_a",
DirectionalAction::Right,
now,
));
assert_eq!(
st.model.focus_state.primary_interaction_focus,
Some(stack_a)
);
assert!(st.cycle_active_cluster_layout_for_monitor("monitor_a", now));
assert_eq!(
st.runtime.tuning.cluster_layout_kind(),
ClusterWorkspaceLayoutKind::Stacking
);
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(master));
}
#[test]
fn closing_cluster_bloom_refocuses_core() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
st.assign_node_to_monitor(master, "monitor_a");
st.assign_node_to_monitor(stack, "monitor_a");
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
assert!(st.open_cluster_bloom_for_monitor("monitor_a", cid));
st.set_interaction_focus(Some(master), 30_000, Instant::now());
assert!(st.close_cluster_bloom_for_monitor("monitor_a"));
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(core));
assert_eq!(st.focused_node_for_monitor("monitor_a"), Some(core));
}
#[test]
fn collapsing_cluster_workspace_keeps_core_focused() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
st.assign_node_to_monitor(master, "monitor_a");
st.assign_node_to_monitor(stack, "monitor_a");
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
assert!(st.collapse_active_cluster_workspace(now));
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(core));
assert_eq!(st.focused_node_for_monitor("monitor_a"), Some(core));
}
#[test]
fn toggle_state_reopens_cluster_from_focused_core() {
let dh = Display::<Halley>::new().expect("display").handle();
let mut st = Halley::new_for_test(&dh, single_monitor_tuning());
let master = st.model.field.spawn_surface(
"master",
Vec2 { x: 100.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
let stack = st.model.field.spawn_surface(
"stack",
Vec2 { x: 500.0, y: 100.0 },
Vec2 { x: 320.0, y: 240.0 },
);
st.assign_node_to_monitor(master, "monitor_a");
st.assign_node_to_monitor(stack, "monitor_a");
let cid = st.create_cluster(vec![master, stack]).expect("cluster");
let core = st.collapse_cluster(cid).expect("core");
st.assign_node_to_monitor(core, "monitor_a");
let now = Instant::now();
assert!(st.enter_cluster_workspace_by_core(core, "monitor_a", now));
assert!(st.collapse_active_cluster_workspace(now));
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(core));
assert!(toggle_focused_active_node_state(&mut st));
assert_eq!(
st.active_cluster_workspace_for_monitor("monitor_a"),
Some(cid)
);
assert_eq!(st.model.focus_state.primary_interaction_focus, Some(master));
}