main.rs (19078B)
1 #![warn(clippy::all)] 2 #![warn(missing_copy_implementations)] 3 #![warn(missing_debug_implementations)] 4 #![warn(missing_debug_implementations)] 5 #![warn(rust_2018_idioms)] 6 #![warn(trivial_numeric_casts)] 7 #![warn(trivial_numeric_casts)] 8 #![warn(unsafe_code)] 9 #![warn(unused_extern_crates)] 10 #![warn(unused_import_braces)] 11 #![warn(unused_qualifications)] 12 #![allow(dead_code)] 13 #![recursion_limit = "256"] 14 15 #[macro_use] 16 extern crate log; 17 18 #[allow(unused_imports)] 19 use simplelog::LevelFilter; 20 #[allow(unused_imports)] 21 use simplelog::SimpleLogger; 22 23 use winsys::geometry::Edge; 24 use winsys::xdata::xconnection::XConnection; 25 pub use winsys::Result; 26 27 use std::collections::HashMap; 28 use std::collections::HashSet; 29 30 #[macro_use] 31 mod macros; 32 33 #[macro_use] 34 mod defaults; 35 36 mod binding; 37 mod change; 38 mod client; 39 mod compare; 40 mod consume; 41 mod cycle; 42 mod decoration; 43 mod error; 44 mod identify; 45 mod jump; 46 mod layout; 47 mod model; 48 mod partition; 49 mod placement; 50 mod rule; 51 mod stack; 52 mod util; 53 mod workspace; 54 mod zone; 55 56 use binding::KeyBindings; 57 use binding::MouseBindings; 58 use change::Change; 59 use change::Direction; 60 use change::Toggle; 61 use compare::MatchMethod; 62 use jump::JumpCriterium; 63 use layout::LayoutKind; 64 use model::Model; 65 use winsys::input::Button; 66 use winsys::input::Key; 67 use winsys::input::KeyInput; 68 use winsys::input::Modifier; 69 use winsys::input::MouseEventKind; 70 use winsys::input::MouseInput; 71 use winsys::input::MouseInputTarget; 72 use winsys::window::Window; 73 use workspace::ClientSelector; 74 75 pub fn main() -> Result<()> { 76 #[cfg(debug_assertions)] 77 SimpleLogger::init(LevelFilter::Debug, simplelog::Config::default())?; 78 79 let (conn, screen_num) = x11rb::connect(None)?; 80 let (mouse_bindings, key_bindings) = init_bindings(); 81 82 Model::new( 83 &mut XConnection::new(&conn, screen_num)?, 84 &key_bindings, 85 &mouse_bindings, 86 ) 87 .run(key_bindings, mouse_bindings); 88 89 Ok(()) 90 } 91 92 fn init_bindings() -> (MouseBindings, KeyBindings) { 93 let mut mouse_bindings = MouseBindings::new(); 94 let mut key_bindings = KeyBindings::new(); 95 96 mouse_bindings.insert( 97 MouseInput { 98 target: MouseInputTarget::Client, 99 button: Button::Right, 100 modifiers: hashset!(Modifier::Alt, Modifier::Ctrl), 101 }, 102 |model: &mut Model<'_>, window: Option<Window>| -> bool { 103 if let Some(window) = window { 104 model.set_floating_window(window, Toggle::Reverse); 105 } 106 107 true 108 }, 109 ); 110 111 mouse_bindings.insert( 112 MouseInput { 113 target: MouseInputTarget::Client, 114 button: Button::Middle, 115 modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift), 116 }, 117 |model: &mut Model<'_>, window: Option<Window>| -> bool { 118 if let Some(window) = window { 119 model.set_fullscreen_window(window, Toggle::Reverse); 120 } 121 122 true 123 }, 124 ); 125 126 mouse_bindings.insert( 127 MouseInput { 128 target: MouseInputTarget::Client, 129 button: Button::Middle, 130 modifiers: hashset!(Modifier::Alt), 131 }, 132 |model: &mut Model<'_>, window: Option<Window>| -> bool { 133 if let Some(window) = window { 134 model.center_window(window); 135 } 136 137 true 138 }, 139 ); 140 141 mouse_bindings.insert( 142 MouseInput { 143 target: MouseInputTarget::Client, 144 button: Button::Left, 145 modifiers: hashset!(Modifier::Alt), 146 }, 147 |model: &mut Model<'_>, window: Option<Window>| -> bool { 148 if let Some(window) = window { 149 model.start_moving(window); 150 } 151 152 true 153 }, 154 ); 155 156 mouse_bindings.insert( 157 MouseInput { 158 target: MouseInputTarget::Client, 159 button: Button::Right, 160 modifiers: hashset!(Modifier::Alt), 161 }, 162 |model: &mut Model<'_>, window: Option<Window>| -> bool { 163 if let Some(window) = window { 164 model.start_resizing(window); 165 } 166 167 true 168 }, 169 ); 170 171 mouse_bindings.insert( 172 MouseInput { 173 target: MouseInputTarget::Client, 174 button: Button::ScrollDown, 175 modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift), 176 }, 177 |model: &mut Model<'_>, window: Option<Window>| -> bool { 178 if let Some(window) = window { 179 model.grow_ratio_window(window, -15); 180 } 181 182 true 183 }, 184 ); 185 186 mouse_bindings.insert( 187 MouseInput { 188 target: MouseInputTarget::Client, 189 button: Button::ScrollUp, 190 modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift), 191 }, 192 |model: &mut Model<'_>, window: Option<Window>| -> bool { 193 if let Some(window) = window { 194 model.grow_ratio_window(window, 15); 195 } 196 197 true 198 }, 199 ); 200 201 mouse_bindings.insert( 202 MouseInput { 203 target: MouseInputTarget::Client, 204 button: Button::ScrollUp, 205 modifiers: hashset!(Modifier::Alt), 206 }, 207 |model: &mut Model<'_>, _: Option<Window>| -> bool { 208 model.cycle_focus(Direction::Backward); 209 false 210 } 211 ); 212 213 mouse_bindings.insert( 214 MouseInput { 215 target: MouseInputTarget::Client, 216 button: Button::ScrollDown, 217 modifiers: hashset!(Modifier::Alt), 218 }, 219 |model: &mut Model<'_>, _: Option<Window>| -> bool { 220 model.cycle_focus(Direction::Forward); 221 false 222 } 223 ); 224 225 mouse_bindings.insert( 226 MouseInput { 227 target: MouseInputTarget::Global, 228 button: Button::ScrollUp, 229 modifiers: hashset!(Modifier::Alt, Modifier::Shift), 230 }, 231 |model: &mut Model<'_>, _: Option<Window>| -> bool { 232 model.activate_next_workspace(Direction::Backward); 233 false 234 } 235 ); 236 237 mouse_bindings.insert( 238 MouseInput { 239 target: MouseInputTarget::Global, 240 button: Button::ScrollDown, 241 modifiers: hashset!(Modifier::Alt, Modifier::Shift), 242 }, 243 |model: &mut Model<'_>, _: Option<Window>| -> bool { 244 model.activate_next_workspace(Direction::Forward); 245 false 246 } 247 ); 248 249 mouse_bindings.insert( 250 MouseInput { 251 target: MouseInputTarget::Client, 252 button: Button::Backward, 253 modifiers: hashset!(Modifier::Alt), 254 }, 255 |model: &mut Model<'_>, window: Option<Window>| -> bool { 256 if let Some(window) = window { 257 model.move_window_to_next_workspace(window, Direction::Backward); 258 } 259 260 false 261 } 262 ); 263 264 mouse_bindings.insert( 265 MouseInput { 266 target: MouseInputTarget::Client, 267 button: Button::Forward, 268 modifiers: hashset!(Modifier::Alt), 269 }, 270 |model: &mut Model<'_>, window: Option<Window>| -> bool { 271 if let Some(window) = window { 272 model.move_window_to_next_workspace(window, Direction::Forward); 273 } 274 275 false 276 } 277 ); 278 279 key_bindings.insert( 280 KeyInput { 281 key: Key::Escape, 282 modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift), 283 }, 284 |model: &mut Model<'_>| { 285 model.exit(); 286 } 287 ); 288 289 key_bindings.insert( 290 KeyInput { 291 key: Key::J, 292 modifiers: hashset!(Modifier::Alt), 293 }, 294 |model: &mut Model<'_>| { 295 model.cycle_focus(Direction::Forward); 296 } 297 ); 298 299 key_bindings.insert( 300 KeyInput { 301 key: Key::K, 302 modifiers: hashset!(Modifier::Alt), 303 }, 304 |model: &mut Model<'_>| { 305 model.cycle_focus(Direction::Backward); 306 } 307 ); 308 309 // // (kind, target, focus): "[modifiers]-button" => action 310 // let mouse_bindings = build_mouse_bindings!( 311 // }), 312 313 // // "[modifiers]-key" => action 314 // let key_bindings = build_key_bindings!( 315 // "1-C-S-q" => do_internal!(exit), 316 317 // // client state modifiers 318 // "1-c" => do_internal!(kill_focus), 319 // "1-S-space" => do_internal!(set_floating_focus, Toggle::Reverse), 320 // "1-f" => do_internal!(set_fullscreen_focus, Toggle::Reverse), 321 // "1-x" => do_internal!(set_stick_focus, Toggle::Reverse), 322 // "1-2-C-f" => do_internal!(set_contained_focus, Toggle::Reverse), 323 // "1-2-C-i" => do_internal!(set_invincible_focus, Toggle::Reverse), 324 // "1-2-C-p" => do_internal!(set_producing_focus, Toggle::Reverse), 325 // "1-2-C-y" => do_internal!(set_iconifyable_focus, Toggle::Reverse), 326 // "1-y" => do_internal!(set_iconify_focus, Toggle::On), 327 // "1-u" => do_internal!(pop_deiconify), 328 // "1-2-u" => do_internal_block!(model, { 329 // model.deiconify_all(model.active_workspace()); 330 // }), 331 332 // // free client arrangers 333 // "1-C-space" => do_internal!(center_focus), 334 // "1-C-h" => do_internal!(nudge_focus, Edge::Left, 15), 335 // "1-C-j" => do_internal!(nudge_focus, Edge::Bottom, 15), 336 // "1-C-k" => do_internal!(nudge_focus, Edge::Top, 15), 337 // "1-C-l" => do_internal!(nudge_focus, Edge::Right, 15), 338 // "1-C-S-h" => do_internal!(stretch_focus, Edge::Left, 15), 339 // "1-C-S-j" => do_internal!(stretch_focus, Edge::Bottom, 15), 340 // "1-C-S-k" => do_internal!(stretch_focus, Edge::Top, 15), 341 // "1-C-S-l" => do_internal!(stretch_focus, Edge::Right, 15), 342 // "1-C-S-y" => do_internal!(stretch_focus, Edge::Left, -15), 343 // "1-C-S-u" => do_internal!(stretch_focus, Edge::Bottom, -15), 344 // "1-C-S-i" => do_internal!(stretch_focus, Edge::Top, -15), 345 // "1-C-S-o" => do_internal!(stretch_focus, Edge::Right, -15), 346 // "1-C-Left" => do_internal!(snap_focus, Edge::Left), 347 // "1-C-Down" => do_internal!(snap_focus, Edge::Bottom), 348 // "1-C-Up" => do_internal!(snap_focus, Edge::Top), 349 // "1-C-Right" => do_internal!(snap_focus, Edge::Right), 350 351 // // client order modifiers 352 // "1-j" => do_internal!(cycle_focus, Direction::Forward), 353 // "1-k" => do_internal!(cycle_focus, Direction::Backward), 354 // "1-S-j" => do_internal!(drag_focus, Direction::Forward), 355 // "1-S-k" => do_internal!(drag_focus, Direction::Backward), 356 // "1-S-semicolon" => do_internal!(rotate_clients, Direction::Forward), 357 // "1-S-comma" => do_internal!(rotate_clients, Direction::Backward), 358 359 // // zone creators 360 // "1-C-Return" => do_internal!(create_layout_zone), 361 // "1-C-S-Return" => do_internal!(create_tab_zone), 362 // "1-C-C" => do_internal!(delete_zone), 363 364 // // zone order modifiers 365 // // "1-C-j" => do_internal!(cycle_zones, Direction::Forward), 366 // // "1-C-k" => do_internal!(cycle_zones, Direction::Backward), 367 368 // // active workspace layout modifiers 369 // "1-S-f" => do_internal!(set_layout, LayoutKind::Float), 370 // "1-S-l" => do_internal!(set_layout, LayoutKind::BLFloat), 371 // "1-z" => do_internal!(set_layout, LayoutKind::SingleFloat), 372 // "1-S-z" => do_internal!(set_layout, LayoutKind::BLSingleFloat), 373 // "1-m" => do_internal!(set_layout, LayoutKind::Monocle), 374 // "1-g" => do_internal!(set_layout, LayoutKind::Center), 375 // "1-t" => do_internal!(set_layout, LayoutKind::Stack), 376 // "1-S-t" => do_internal!(set_layout, LayoutKind::SStack), 377 // "1-C-S-p" => do_internal!(set_layout, LayoutKind::Paper), 378 // "1-2-C-S-p" => do_internal!(set_layout, LayoutKind::SPaper), 379 // "1-C-S-b" => do_internal!(set_layout, LayoutKind::BStack), 380 // "1-2-C-S-b" => do_internal!(set_layout, LayoutKind::SBStack), 381 // "1-S-y" => do_internal!(set_layout, LayoutKind::Horz), 382 // "1-C-y" => do_internal!(set_layout, LayoutKind::SHorz), 383 // "1-S-v" => do_internal!(set_layout, LayoutKind::Vert), 384 // "1-C-v" => do_internal!(set_layout, LayoutKind::SVert), 385 // "1-C-S-f" => do_internal!(apply_float_retain_region), 386 // "1-space" => do_internal!(toggle_layout), 387 388 // // active workspace layout data modifiers 389 // "1-plus" => do_internal!(change_gap_size, Change::Inc(5u32)), 390 // "1-minus" => do_internal!(change_gap_size, Change::Dec(5u32)), 391 // "1-S-equal" => do_internal!(reset_gap_size), 392 // "1-i" => do_internal!(change_main_count, Change::Inc(1u32)), 393 // "1-d" => do_internal!(change_main_count, Change::Dec(1u32)), 394 // "1-l" => do_internal!(change_main_factor, Change::Inc(0.05f32)), 395 // "1-h" => do_internal!(change_main_factor, Change::Dec(0.05f32)), 396 // "1-S-Left" => do_internal!(change_margin, Edge::Left, Change::Inc(5i32)), 397 // "1-C-S-Left" => do_internal!(change_margin, Edge::Left, Change::Dec(5i32)), 398 // "1-S-Up" => do_internal!(change_margin, Edge::Top, Change::Inc(5i32)), 399 // "1-C-S-Up" => do_internal!(change_margin, Edge::Top, Change::Dec(5i32)), 400 // "1-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Inc(5i32)), 401 // "1-C-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Dec(5i32)), 402 // "1-S-Right" => do_internal!(change_margin, Edge::Right, Change::Inc(5i32)), 403 // "1-C-S-Right" => do_internal!(change_margin, Edge::Right, Change::Dec(5i32)), 404 // "1-C-S-equal" => do_internal!(reset_margin), 405 // "1-2-C-S-l" => do_internal!(copy_prev_layout_data), 406 // "1-2-C-S-equal" => do_internal!(reset_layout_data), 407 408 // // workspace activators 409 // "1-Escape" => do_internal!(toggle_workspace), 410 // "1-bracketleft" => do_internal!(activate_next_workspace, Direction::Backward), 411 // "1-bracketright" => do_internal!(activate_next_workspace, Direction::Forward), 412 // "1-1" => do_internal!(activate_workspace, 0), 413 // "1-2" => do_internal!(activate_workspace, 1), 414 // "1-3" => do_internal!(activate_workspace, 2), 415 // "1-4" => do_internal!(activate_workspace, 3), 416 // "1-5" => do_internal!(activate_workspace, 4), 417 // "1-6" => do_internal!(activate_workspace, 5), 418 // "1-7" => do_internal!(activate_workspace, 6), 419 // "1-8" => do_internal!(activate_workspace, 7), 420 // "1-9" => do_internal!(activate_workspace, 8), 421 // "1-0" => do_internal!(activate_workspace, 9), 422 423 // // workspace client movers 424 // "1-S-bracketleft" => do_internal!(move_focus_to_next_workspace, Direction::Backward), 425 // "1-S-bracketright" => do_internal!(move_focus_to_next_workspace, Direction::Forward), 426 // "1-S-1" => do_internal!(move_focus_to_workspace, 0), 427 // "1-S-2" => do_internal!(move_focus_to_workspace, 1), 428 // "1-S-3" => do_internal!(move_focus_to_workspace, 2), 429 // "1-S-4" => do_internal!(move_focus_to_workspace, 3), 430 // "1-S-5" => do_internal!(move_focus_to_workspace, 4), 431 // "1-S-6" => do_internal!(move_focus_to_workspace, 5), 432 // "1-S-7" => do_internal!(move_focus_to_workspace, 6), 433 // "1-S-8" => do_internal!(move_focus_to_workspace, 7), 434 // "1-S-9" => do_internal!(move_focus_to_workspace, 8), 435 // "1-S-0" => do_internal!(move_focus_to_workspace, 9), 436 437 // // placeable region modifiers 438 // "1-v" => do_internal!(toggle_screen_struts), 439 440 // // client jump criteria 441 // "1-b" => do_internal!(jump_client, 442 // JumpCriterium::ByClass(MatchMethod::Equals("qutebrowser")) 443 // ), 444 // "1-S-b" => do_internal!(jump_client, 445 // JumpCriterium::ByClass(MatchMethod::Equals("Firefox")) 446 // ), 447 // "1-C-b" => do_internal!(jump_client, 448 // JumpCriterium::ByClass(MatchMethod::Equals("Chromium")) 449 // ), 450 // "1-2-space" => do_internal!(jump_client, 451 // JumpCriterium::ByClass(MatchMethod::Equals("Spotify")) 452 // ), 453 // "1-e" => do_internal_block!(model, { 454 // model.jump_client(JumpCriterium::ByName( 455 // MatchMethod::Contains("[vim]"), 456 // )); 457 // }), 458 // "1-slash" => do_internal_block!(model, { 459 // model.jump_client(JumpCriterium::OnWorkspaceBySelector( 460 // model.active_workspace(), 461 // &ClientSelector::Last, 462 // )); 463 // }), 464 // "1-period" => do_internal_block!(model, { 465 // model.jump_client(JumpCriterium::OnWorkspaceBySelector( 466 // model.active_workspace(), 467 // &ClientSelector::AtMaster, 468 // )); 469 // }), 470 // "1-comma" => do_internal_block!(model, { 471 // model.jump_client(JumpCriterium::OnWorkspaceBySelector( 472 // model.active_workspace(), 473 // &ClientSelector::First, 474 // )); 475 // }), 476 477 // // external spawn commands 478 // "XF86AudioPlay", "1-2-p" => spawn_external!("playerctl play-pause"), 479 // "XF86AudioPrev", "1-2-k" => spawn_external!("playerctl previous"), 480 // "XF86AudioNext", "1-2-j" => spawn_external!("playerctl next"), 481 // "1-2-BackSpace" => spawn_external!("playerctl stop"), 482 // "XF86AudioMute" => spawn_external!("amixer -D pulse sset Master toggle"), 483 // "XF86AudioLowerVolume" => spawn_external!("amixer -D pulse sset Master 5%-"), 484 // "XF86AudioRaiseVolume" => spawn_external!("amixer -D pulse sset Master 5%+"), 485 486 // "1-Return" => spawn_external!("st"), 487 // "1-S-Return" => spawn_external!(concat!("st -n ", WM_NAME!(), ":cf")), 488 489 // "1-p" => spawn_external!("dmenu_run"), 490 // "1-q" => spawn_external!("qutebrowser"), 491 // "1-S-q" => spawn_external!("firefox"), 492 // "1-C-q" => spawn_external!("chromium"), 493 494 // "1-C-e" => spawn_external!("st -g 140x42 -e zsh -i -c neomutt"), 495 // "1-C-s" => spawn_external!("st -g 80x42 -e zsh -i -c sncli"), 496 // "1-C-i" => spawn_external!("st -g 80x42 -e zsh -i -c irssi"), 497 498 // "S-XF86AudioMute" => spawn_external!("amixer -D pulse sset Capture toggle"), 499 // "XF86AudioMicMute" => spawn_external!("amixer -D pulse sset Capture toggle"), 500 501 // // external shell commands 502 // "1-S-p" => spawn_from_shell!("$HOME/bin/dmenupass"), 503 // "1-C-p" => spawn_from_shell!("$HOME/bin/dmenupass --copy"), 504 // "1-S-o" => spawn_from_shell!("$HOME/bin/dmenunotify"), 505 // "Print", "1-2-slash" => spawn_from_shell!( 506 // "maim -u -m 1 -s \ 507 // $(date +$HOME/screenshots/scrots/SS_%Y-%h-%d_%H-%M-%S.png)" 508 // ), 509 // "S-Print", "1-2-S-slash" => spawn_from_shell!( 510 // "maim -u -m 1 \ 511 // $(date +$HOME/screenshots/scrots/SS_%Y-%h-%d_%H-%M-%S.png)" 512 // ), 513 // ); 514 515 (mouse_bindings, key_bindings) 516 }