// Copyright (C) 2021 Tassilo Horn // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . //! Functions and data structures of the swayrd demon. use crate::cmds; use crate::con; use crate::con::NodeMethods; use crate::config; use std::collections::HashMap; use swayipc as s; pub fn auto_tile(res_to_min_width: &HashMap) { if let Ok(mut con) = s::Connection::new() { if let Ok(tree) = con.get_tree() { for output in &tree.nodes { println!("output: {:?}", output.name); // Assert our assumption that all children of the tree's root // must be outputs. if output.node_type != s::NodeType::Output { panic!( "Child of Root is no Output but a {:?}", output.node_type ); } let output_width = output.rect.width; let min_window_width = &res_to_min_width.get(&output_width); if let Some(min_window_width) = min_window_width { for container in con::NodeIter::new(output).filter(|n| n.is_container()) { if container.is_scratchpad() { continue; } println!( " container: {:?}, layout {:?}, {} nodes", container.node_type, container.layout, container.nodes.len(), ); for child_win in container.nodes.iter().filter(|n| n.is_window()) { // Width if we'd split once more. let estimated_width = child_win.rect.width as f32 / 2.0; println!( " child_win: {:?}, estimated width after splith {} px", child_win.app_id, estimated_width ); let split = if container.layout == s::NodeLayout::SplitH && estimated_width <= **min_window_width as f32 { Some("splitv") } else if container.layout == s::NodeLayout::SplitV && estimated_width > **min_window_width as f32 { Some("splith") } else { None }; if let Some(split) = split { println!( "Auto-tiling performing {} on window {} \ because estimated width after another \ split is {} and the minimum window width \ is {} on this output.", split, child_win.id, estimated_width, min_window_width ); match con.run_command(format!( "[con_id={}] {}", child_win.id, split )) { Ok(_) => (), Err(e) => eprintln!( "Couldn't set {} on con {}: {:?}", split, child_win.id, e ), } } } } } else { eprintln!("No layout.auto_tile_min_window_width_per_output_width \ setting for output_width {}", output_width); } } } else { eprintln!("Couldn't call get_tree during auto_tile."); } } else { eprintln!("Couldn't get connection for auto_tile"); } } pub fn maybe_auto_tile(config: &config::Config) { if config.is_layout_auto_tile() { println!("\nauto_tile: start"); auto_tile( &config .get_layout_auto_tile_min_window_width_per_output_width_as_map( ), ); println!("auto_tile: end\n"); } } pub fn relayout_current_workspace( include_floating: bool, insert_win_fn: Box< dyn Fn(&mut [&con::Window], &mut s::Connection) -> s::Fallible<()>, >, ) -> s::Fallible<()> { let root = cmds::get_tree(); let workspaces = con::get_workspaces(&root, false, None); if let Some(cur_ws) = workspaces.iter().find(|ws| ws.is_current()) { if let Ok(mut con) = s::Connection::new() { let mut moved_wins: Vec<&con::Window> = vec![]; let mut focused_win = None; for win in &cur_ws.windows { if win.is_focused() { focused_win.insert(win); } if !include_floating && win.is_floating() { continue; } moved_wins.push(win); con.run_command(format!( "[con_id={}] move to scratchpad", win.get_id() ))?; } insert_win_fn(moved_wins.as_mut_slice(), &mut con)?; std::thread::sleep(std::time::Duration::from_millis(25)); if let Some(win) = focused_win { con.run_command(format!("[con_id={}] focus", win.get_id()))?; } Ok(()) } else { Err(s::Error::CommandFailed( "Cannot create connection.".to_string(), )) } } else { Err(s::Error::CommandFailed( "No workspace is focused.".to_string(), )) } }