model.rs (97961B)
1 #[allow(unused_imports)] 2 use crate::util::Util; 3 4 use crate::binding::KeyBindings; 5 use crate::binding::MouseBindings; 6 use crate::change::Change; 7 use crate::change::Direction; 8 use crate::change::Toggle; 9 use crate::client::Client; 10 use crate::consume::get_spawner_pid; 11 use crate::cycle::Cycle; 12 use crate::cycle::InsertPos; 13 use crate::cycle::Selector; 14 use crate::decoration::Decoration; 15 use crate::defaults; 16 use crate::error::StateChangeError; 17 use crate::identify::Ident; 18 use crate::identify::Index; 19 use crate::jump::JumpCriterium; 20 use crate::layout::Layout; 21 use crate::layout::LayoutKind; 22 use crate::partition::Partition; 23 use crate::placement::Placement; 24 use crate::placement::PlacementClass; 25 use crate::placement::PlacementMethod; 26 use crate::placement::PlacementRegion; 27 use crate::placement::PlacementTarget; 28 use crate::rule::Rules; 29 use crate::stack::StackLayer; 30 use crate::stack::StackManager; 31 use crate::util::BuildIdHasher; 32 use crate::workspace::Buffer; 33 use crate::workspace::BufferKind; 34 use crate::workspace::Workspace; 35 use crate::zone::ZoneContent; 36 use crate::zone::ZoneManager; 37 38 use winsys::connection::Connection; 39 use winsys::connection::Pid; 40 use winsys::event::Event; 41 use winsys::event::PropertyKind; 42 use winsys::event::StackMode; 43 use winsys::event::ToggleAction; 44 use winsys::geometry::Corner; 45 use winsys::geometry::Dim; 46 use winsys::geometry::Edge; 47 use winsys::geometry::Pos; 48 use winsys::geometry::Region; 49 use winsys::hints::Hints; 50 use winsys::input::Grip; 51 use winsys::input::KeyEvent; 52 use winsys::input::KeyInput; 53 use winsys::input::MouseEvent; 54 use winsys::input::MouseEventKind; 55 use winsys::input::MouseInput; 56 use winsys::input::MouseInputTarget; 57 use winsys::screen::Screen; 58 use winsys::window::IcccmWindowState; 59 use winsys::window::Window; 60 use winsys::window::WindowState; 61 use winsys::window::WindowType; 62 63 use std::cell::Cell; 64 use std::cell::RefCell; 65 use std::collections::HashMap; 66 use std::collections::HashSet; 67 68 pub struct Model<'model> { 69 conn: &'model mut dyn Connection, 70 zone_manager: ZoneManager, 71 stack_manager: StackManager, 72 stacking_order: RefCell<Vec<Window>>, 73 pid_map: HashMap<Pid, Window>, 74 client_map: HashMap<Window, Client, BuildIdHasher>, 75 window_map: HashMap<Window, Window, BuildIdHasher>, 76 frame_map: HashMap<Window, Window, BuildIdHasher>, 77 sticky_clients: RefCell<HashSet<Window, BuildIdHasher>>, 78 unmanaged_windows: RefCell<HashSet<Window, BuildIdHasher>>, 79 fullscreen_regions: RefCell<HashMap<Window, Region, BuildIdHasher>>, 80 partitions: Cycle<Partition>, 81 workspaces: Cycle<Workspace>, 82 move_buffer: Buffer, 83 resize_buffer: Buffer, 84 prev_partition: Cell<Index>, 85 prev_workspace: Cell<Index>, 86 running: bool, 87 focus: Cell<Option<Window>>, 88 jumped_from: Cell<Option<Window>>, 89 } 90 91 impl<'model> Model<'model> { 92 pub fn new( 93 conn: &'model mut dyn Connection, 94 key_bindings: &KeyBindings, 95 mouse_bindings: &MouseBindings, 96 ) -> Self { 97 Self::init( 98 Self { 99 zone_manager: ZoneManager::new(), 100 stack_manager: StackManager::new(), 101 stacking_order: RefCell::new(Vec::with_capacity(200)), 102 pid_map: HashMap::new(), 103 client_map: HashMap::with_hasher(BuildIdHasher), 104 window_map: HashMap::with_hasher(BuildIdHasher), 105 frame_map: HashMap::with_hasher(BuildIdHasher), 106 sticky_clients: RefCell::new(HashSet::with_hasher(BuildIdHasher)), 107 unmanaged_windows: RefCell::new(HashSet::with_hasher(BuildIdHasher)), 108 fullscreen_regions: RefCell::new(HashMap::with_hasher(BuildIdHasher)), 109 partitions: Cycle::new(Vec::new(), false), 110 workspaces: Cycle::new(Vec::with_capacity(defaults::WORKSPACE_NAMES.len()), false), 111 move_buffer: Buffer::new(BufferKind::Move, conn.create_handle()), 112 resize_buffer: Buffer::new(BufferKind::Resize, conn.create_handle()), 113 prev_partition: Cell::new(0), 114 prev_workspace: Cell::new(0), 115 running: true, 116 focus: Cell::new(None), 117 jumped_from: Cell::new(None), 118 conn, 119 }, 120 key_bindings, 121 mouse_bindings, 122 ) 123 } 124 125 fn init( 126 mut model: Self, 127 key_bindings: &KeyBindings, 128 mouse_bindings: &MouseBindings, 129 ) -> Self { 130 info!("initializing window manager"); 131 132 model.acquire_partitions(); 133 let screen_region = model 134 .partitions 135 .active_element() 136 .expect("no screen region found") 137 .placeable_region(); 138 139 defaults::WORKSPACE_NAMES 140 .iter() 141 .enumerate() 142 .for_each(|(i, &workspace_name)| { 143 let root_id = model.zone_manager.new_zone( 144 None, 145 ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), 146 ); 147 148 model 149 .workspaces 150 .push_back(Workspace::new(workspace_name, i as Ident, root_id)); 151 152 model 153 .zone_manager 154 .zone_mut(root_id) 155 .set_region(screen_region); 156 }); 157 158 model.workspaces.activate_for(&Selector::AtIndex(0)); 159 model.conn.set_current_desktop(0); 160 161 model 162 .conn 163 .init_wm_properties(WM_NAME!(), &defaults::WORKSPACE_NAMES); 164 165 model.conn.grab_bindings( 166 &key_bindings.keys().into_iter().collect::<Vec<&KeyInput>>(), 167 &mouse_bindings 168 .keys() 169 .into_iter() 170 .collect::<Vec<&MouseInput>>(), 171 ); 172 173 model 174 .conn 175 .top_level_windows() 176 .into_iter() 177 .for_each(|window| { 178 model.manage(window, !model.conn.must_manage_window(window)); 179 }); 180 181 if cfg!(not(debug_assertions)) { 182 let nonblocking = concat!("$HOME/.config/", WM_NAME!(), "/nonblocking_autostart &"); 183 let blocking = concat!("$HOME/.config/", WM_NAME!(), "/blocking_autostart"); 184 185 info!("executing startup scripts"); 186 Util::spawn_shell(nonblocking); 187 Util::spawn_shell(blocking); 188 } 189 190 model 191 } 192 193 #[inline(always)] 194 fn window( 195 &self, 196 window: Window, 197 ) -> Option<Window> { 198 if self.window_map.contains_key(&window) { 199 return Some(window); 200 } 201 202 self.frame_map.get(&window).map(|window| window.to_owned()) 203 } 204 205 #[inline(always)] 206 fn window_unchecked( 207 &self, 208 window: Window, 209 ) -> Window { 210 self.window(window).unwrap() 211 } 212 213 #[inline(always)] 214 fn frame( 215 &self, 216 window: Window, 217 ) -> Option<Window> { 218 if self.frame_map.contains_key(&window) { 219 return Some(window); 220 } 221 222 self.window_map.get(&window).map(|window| window.to_owned()) 223 } 224 225 #[inline(always)] 226 fn frame_unchecked( 227 &self, 228 window: Window, 229 ) -> Window { 230 self.frame(window).unwrap() 231 } 232 233 #[inline(always)] 234 fn client_any( 235 &self, 236 mut window: Window, 237 ) -> Option<&Client> { 238 if let Some(&inside) = self.frame_map.get(&window) { 239 window = inside; 240 } 241 242 self.client_map.get(&window) 243 } 244 245 #[inline(always)] 246 fn client_any_unchecked( 247 &self, 248 mut window: Window, 249 ) -> &Client { 250 if let Some(&inside) = self.frame_map.get(&window) { 251 window = inside; 252 } 253 254 &self.client_map[&window] 255 } 256 257 #[inline(always)] 258 fn client( 259 &self, 260 window: Window, 261 ) -> Option<&Client> { 262 self.client_any(window).filter(|client| client.is_managed()) 263 } 264 265 #[inline(always)] 266 fn client_unchecked( 267 &self, 268 window: Window, 269 ) -> &Client { 270 self.client_any(window) 271 .filter(|&client| client.is_managed()) 272 .unwrap() 273 } 274 275 #[inline(always)] 276 fn active_partition(&self) -> usize { 277 self.partitions.active_index() 278 } 279 280 #[inline(always)] 281 fn active_screen(&self) -> &Screen { 282 self.partitions.active_element().unwrap().screen() 283 } 284 285 #[inline(always)] 286 pub fn active_workspace(&self) -> usize { 287 self.workspaces.active_index() 288 } 289 290 #[inline(always)] 291 fn focused_client(&self) -> Option<&Client> { 292 self.focus 293 .get() 294 .or_else(|| self.workspace(self.active_workspace()).focused_client()) 295 .and_then(|focus| self.client_map.get(&focus)) 296 } 297 298 #[inline(always)] 299 fn workspace( 300 &self, 301 index: Index, 302 ) -> &Workspace { 303 &self.workspaces[index] 304 } 305 306 fn acquire_partitions(&mut self) { 307 let partitions: Vec<Partition> = self 308 .conn 309 .connected_outputs() 310 .into_iter() 311 .enumerate() 312 .map(|(i, screen)| { 313 screen.compute_placeable_region(); 314 Partition::new(screen, i) 315 }) 316 .collect(); 317 318 if partitions.is_empty() { 319 error!("no screen resources found, keeping old partitions"); 320 } else { 321 info!("acquired partitions: {:#?}", partitions); 322 self.partitions = Cycle::new(partitions, false); 323 } 324 } 325 326 #[inline] 327 pub fn toggle_screen_struts(&self) { 328 let screen = self.active_screen(); 329 let show = !screen.showing_struts(); 330 331 screen 332 .show_and_yield_struts(show) 333 .iter() 334 .for_each(|&strut| { 335 if show { 336 self.conn.map_window(strut); 337 } else { 338 self.conn.unmap_window(strut); 339 } 340 }); 341 342 self.apply_layout(self.active_workspace()); 343 } 344 345 fn apply_layout( 346 &self, 347 index: Index, 348 ) { 349 let workspace = match self.workspaces.get(index) { 350 Some(workspace) if index == self.active_workspace() => workspace, 351 _ => return, 352 }; 353 354 info!("applying layout on workspace {}", index); 355 356 let (show, hide): (Vec<Placement>, Vec<Placement>) = workspace 357 .arrange( 358 &self.zone_manager, 359 &self.client_map, 360 self.partitions.active_element().unwrap().placeable_region(), 361 |client| !Self::is_applyable(client) || client.is_iconified(), 362 ) 363 .into_iter() 364 .partition(|placement| placement.region != PlacementRegion::NoRegion); 365 366 show.into_iter().for_each(|placement| { 367 match placement.kind { 368 PlacementTarget::Client(window) => { 369 let client = &self.client_map[&window]; 370 371 self.update_client_placement(client, &placement); 372 self.place_client(client, placement.method); 373 self.map_client(client); 374 }, 375 PlacementTarget::Tab(_) => {}, 376 PlacementTarget::Layout => {}, 377 }; 378 }); 379 380 hide.into_iter().for_each(|placement| { 381 match placement.kind { 382 PlacementTarget::Client(window) => { 383 self.unmap_client(&self.client_map[&window]); 384 }, 385 PlacementTarget::Tab(_) => {}, 386 PlacementTarget::Layout => {}, 387 }; 388 }); 389 } 390 391 fn apply_stack( 392 &self, 393 index: Index, 394 ) { 395 let workspace = match self.workspaces.get(index) { 396 Some(workspace) if index == self.active_workspace() => workspace, 397 _ => return, 398 }; 399 400 info!("applying stack on workspace {}", index); 401 402 let desktop = self.stack_manager.layer_windows(StackLayer::Desktop); 403 let below = self.stack_manager.layer_windows(StackLayer::Below); 404 let dock = self.stack_manager.layer_windows(StackLayer::Dock); 405 let above = self.stack_manager.layer_windows(StackLayer::Above); 406 let notification = self.stack_manager.layer_windows(StackLayer::Notification); 407 408 let stack = workspace 409 .stack_after_focus() 410 .into_iter() 411 .map(|window| self.frame_unchecked(window)) 412 .collect::<Vec<Window>>(); 413 414 let (regular, fullscreen): (Vec<_>, Vec<_>) = stack.iter().partition(|&&window| { 415 let client = self.client_unchecked(window); 416 !client.is_fullscreen() || client.is_contained() 417 }); 418 419 let (free, regular): (Vec<_>, Vec<_>) = regular 420 .into_iter() 421 .partition(|&window| self.is_free(self.client_unchecked(window))); 422 423 let mut windows = desktop 424 .into_iter() 425 .chain(below.into_iter()) 426 .chain(dock.into_iter()) 427 .chain(regular.into_iter()) 428 .chain(fullscreen.into_iter()) 429 .chain(free.into_iter()) 430 .chain(above.into_iter()) 431 .chain(notification) 432 .into_iter() 433 .collect::<Vec<Window>>(); 434 435 // handle {above,below}-other relationships 436 self.stack_manager 437 .above_other() 438 .keys() 439 .chain(self.stack_manager.below_other().keys()) 440 .for_each(|&window| { 441 if let Some(index) = windows.iter().position(|&candidate| candidate == window) { 442 windows.remove(index); 443 } 444 }); 445 446 self.stack_manager 447 .above_other() 448 .iter() 449 .for_each(|(&window, &sibling)| { 450 if let Some(index) = windows.iter().position(|&candidate| candidate == sibling) { 451 if index < windows.len() { 452 windows.insert(index + 1, window); 453 } 454 } 455 }); 456 457 self.stack_manager 458 .below_other() 459 .iter() 460 .for_each(|(&window, &sibling)| { 461 if let Some(index) = windows.iter().position(|&candidate| candidate == sibling) { 462 windows.insert(index, window); 463 } 464 }); 465 466 let mut stack_iter = windows.iter(); 467 let mut prev_window = stack_iter.next().cloned(); 468 let mut order_changed = false; 469 let stacking_order = self.stacking_order.borrow(); 470 471 stack_iter.enumerate().for_each(|(i, &window)| { 472 order_changed |= stacking_order.get(i + 1) != Some(&window); 473 474 if order_changed { 475 self.conn.stack_window_above(window, prev_window); 476 } 477 478 prev_window = Some(window); 479 }); 480 481 if !order_changed { 482 return; 483 } 484 485 drop(stacking_order); 486 self.stacking_order.replace(windows); 487 488 let mut client_list = self.client_map.values().collect::<Vec<&Client>>(); 489 client_list.sort_by_key(|&a| a.managed_since()); 490 491 let client_list = client_list 492 .into_iter() 493 .map(|client| client.window()) 494 .collect::<Vec<Window>>(); 495 496 self.conn.update_client_list(&client_list); 497 498 let mut client_list_stacking = client_list; 499 let stack_windows = stack 500 .into_iter() 501 .map(|window| self.window_unchecked(window)) 502 .collect::<Vec<_>>(); 503 504 client_list_stacking.retain(|&window| !stack_windows.contains(&window)); 505 client_list_stacking = client_list_stacking 506 .iter() 507 .chain(stack_windows.iter()) 508 .copied() 509 .collect(); 510 511 self.conn.update_client_list_stacking(&client_list_stacking); 512 } 513 514 #[inline] 515 fn detect_rules( 516 &self, 517 instance: &str, 518 ) -> Rules { 519 const PREFIX: &str = &concat!(WM_NAME!(), ":"); 520 const PREFIX_LEN: usize = PREFIX.len(); 521 522 let mut rules: Rules = Default::default(); 523 524 match (instance.get(..PREFIX_LEN), instance.get(PREFIX_LEN..)) { 525 (Some(PREFIX), Some(flags)) if !flags.is_empty() => { 526 let mut invert = false; 527 let mut workspace = false; 528 529 for i in 0..flags.len() { 530 let flag = &flags[i..=i]; 531 532 match flag { 533 "!" => { 534 invert = true; 535 continue; 536 }, 537 "w" => { 538 workspace = true; 539 continue; 540 }, 541 number if workspace => { 542 if let Ok(number) = number.parse::<usize>() { 543 if number < self.workspaces.len() { 544 rules.workspace = Some(number); 545 } 546 } 547 }, 548 "f" => rules.float = Some(!invert), 549 "F" => rules.fullscreen = Some(!invert), 550 "c" => rules.center = Some(!invert), 551 _ => {}, 552 } 553 554 invert = false; 555 workspace = false; 556 } 557 }, 558 _ => {}, 559 } 560 561 rules 562 } 563 564 fn manage( 565 &mut self, 566 window: Window, 567 ignore: bool, 568 ) { 569 if ignore { 570 if self.conn.window_is_mappable(window) { 571 self.conn.map_window(window); 572 } 573 574 self.conn.init_unmanaged(window); 575 self.unmanaged_windows.borrow_mut().insert(window); 576 577 return; 578 } 579 580 let pid = self.conn.get_window_pid(window); 581 let ppid = pid.and_then(|pid| { 582 get_spawner_pid(pid, std::process::id(), &self.pid_map, &self.client_map) 583 }); 584 585 let name = self.conn.get_icccm_window_name(window); 586 let class = self.conn.get_icccm_window_class(window); 587 let instance = self.conn.get_icccm_window_instance(window); 588 589 let preferred_state = self.conn.get_window_preferred_state(window); 590 let preferred_type = self.conn.get_window_preferred_type(window); 591 592 let mut geometry = match self.conn.get_window_geometry(window) { 593 Ok(geometry) => geometry, 594 Err(_) => return, 595 }; 596 597 self.stop_moving(); 598 self.stop_resizing(); 599 600 let at_origin = geometry.pos.is_origin(); 601 let frame = self.conn.create_frame(geometry); 602 let rules = self.detect_rules(&instance); 603 let hints = self.conn.get_icccm_window_hints(window); 604 let size_hints = self 605 .conn 606 .get_icccm_window_size_hints(window, Some(Client::MIN_CLIENT_DIM), &None) 607 .1; 608 609 geometry = match size_hints { 610 Some(size_hints) => geometry 611 .with_size_hints(&Some(size_hints)) 612 .with_extents(Decoration::FREE_DECORATION.extents()), 613 None => geometry 614 .with_minimum_dim(&Client::MIN_CLIENT_DIM) 615 .with_extents(Decoration::FREE_DECORATION.extents()), 616 }; 617 618 let parent = self.conn.get_icccm_window_transient_for(window); 619 let screen = self.active_screen(); 620 let context = 0; 621 let workspace = rules.workspace.unwrap_or_else(|| { 622 self.conn 623 .get_window_desktop(window) 624 .filter(|&workspace| workspace < self.workspaces.len()) 625 .unwrap_or_else(|| self.active_workspace()) 626 }); 627 628 if rules.center() || size_hints.map_or(true, |size_hints| !size_hints.by_user) && at_origin 629 { 630 geometry = screen 631 .full_region() 632 .from_absolute_inner_center(geometry.dim); 633 } 634 635 let parent_zone = self.workspaces[workspace] 636 .active_spawn_zone() 637 .map(|id| self.zone_manager.nearest_cycle(id)); 638 639 let zone = self 640 .zone_manager 641 .new_zone(parent_zone, ZoneContent::Client(window)); 642 643 let mut client = Client::new( 644 zone, 645 window, 646 frame, 647 name, 648 class, 649 instance, 650 preferred_type, 651 pid, 652 ppid, 653 ); 654 655 let mut floating = self.conn.must_free_window(window) | rules.float(); 656 let fullscreen = self.conn.window_is_fullscreen(window) | rules.fullscreen(); 657 let sticky = self.conn.window_is_sticky(window); 658 659 if let Some(parent) = parent { 660 floating = true; 661 client.set_parent(parent); 662 } 663 664 let leader = self 665 .conn 666 .get_icccm_window_client_leader(window) 667 .and_then(|leader| self.client_any(leader)); 668 669 if let Some(leader) = leader { 670 let leader_window = leader.window(); 671 672 if leader_window != window { 673 floating = true; 674 client.set_leader(leader_window); 675 } 676 } 677 678 if let Some(hints) = hints { 679 client.set_urgent(Toggle::from(hints.urgent)); 680 } 681 682 client.set_floating(Toggle::from(floating)); 683 client.set_region(PlacementClass::Free(geometry)); 684 client.set_size_hints(size_hints); 685 client.set_context(context); 686 client.set_workspace(workspace); 687 688 self.conn.reparent_window(window, frame, { 689 let extents = Decoration::FREE_DECORATION.extents(); 690 691 Pos { 692 x: extents.left, 693 y: extents.top, 694 } 695 }); 696 697 if let Some(parent) = parent.and_then(|parent| self.client_any(parent)) { 698 let parent_frame = parent.frame(); 699 700 parent.add_child(window); 701 self.stack_manager.add_above_other(frame, parent_frame); 702 } 703 704 if let Some(pid) = pid { 705 self.pid_map.insert(pid, window); 706 } 707 708 self.workspaces[workspace].add_client(window, &InsertPos::AfterActive); 709 self.client_map.insert(window, client); 710 self.frame_map.insert(frame, window); 711 self.window_map.insert(window, frame); 712 713 self.conn.insert_window_in_save_set(window); 714 self.conn.init_window(window, false); 715 self.conn.init_frame(frame, false); 716 self.conn.set_window_border_width(window, 0); 717 self.conn.set_window_desktop(window, workspace); 718 self.conn 719 .set_icccm_window_state(window, IcccmWindowState::Normal); 720 721 self.apply_layout(workspace); 722 self.focus_window(window); 723 724 if let Some(WindowState::DemandsAttention) = preferred_state { 725 self.handle_state_request( 726 window, 727 WindowState::DemandsAttention, 728 ToggleAction::Add, 729 false, 730 ); 731 } 732 733 let client = &self.client_map[&window]; 734 735 if sticky { 736 self.stick(client); 737 } 738 739 if fullscreen { 740 self.fullscreen(client); 741 } 742 743 if let Some(&ppid_window) = ppid.and_then(|ppid| self.pid_map.get(&ppid)) { 744 if let Some(ppid_client) = self.client(ppid_window) { 745 if ppid_client.is_producing() { 746 self.consume_client(client, ppid_client); 747 } 748 } 749 } 750 751 if let Some(warp_pos) = client 752 .active_region() 753 .quadrant_center_from_pos(self.conn.get_pointer_position()) 754 { 755 self.conn.warp_pointer(warp_pos); 756 } 757 758 info!("managing client {:#?}", client); 759 } 760 761 fn remanage( 762 &self, 763 client: &Client, 764 must_alter_workspace: bool, 765 ) { 766 if client.is_managed() { 767 return; 768 } 769 770 let window = client.window(); 771 info!("remanaging client with window {:#0x}", window); 772 773 client.set_managed(Toggle::On); 774 775 if must_alter_workspace { 776 let workspace = client 777 .leader() 778 .and_then(|leader| self.client(leader)) 779 .map(|leader| { 780 let workspace = leader.workspace(); 781 782 client.set_workspace(workspace); 783 self.workspace(leader.workspace()) 784 }); 785 786 if let Some(workspace) = workspace { 787 if !workspace.contains(window) { 788 workspace.add_client(window, &InsertPos::Back); 789 } 790 } 791 } 792 793 if client.is_sticky() { 794 client.set_sticky(Toggle::Off); 795 self.stick(client); 796 self.map_client(client); 797 } 798 799 self.focus(client); 800 } 801 802 fn unmanage( 803 &self, 804 client: &Client, 805 ) { 806 if !client.is_managed() { 807 return; 808 } 809 810 let window = client.window(); 811 info!("unmanaging client with window {:#0x}", window); 812 813 client.set_managed(Toggle::Off); 814 815 if client.is_sticky() { 816 self.unstick(client); 817 client.set_sticky(Toggle::On); 818 } 819 820 self.unmap_client(client); 821 self.workspace(client.workspace()).remove_client(window); 822 } 823 824 // TODO: zones 825 pub fn create_layout_zone(&mut self) { 826 let workspace_index = self.active_workspace(); 827 let workspace = self.workspace(workspace_index); 828 829 let cycle = workspace.active_focus_zone().unwrap(); 830 let cycle = self.zone_manager.nearest_cycle(cycle); 831 let id = self.zone_manager.new_zone( 832 Some(cycle), 833 ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), 834 ); 835 836 let workspace = self.workspace(workspace_index); 837 workspace.add_zone(id, &InsertPos::Back); 838 self.apply_layout(workspace_index); 839 self.apply_stack(workspace_index); 840 } 841 842 // TODO: zones 843 pub fn create_tab_zone(&mut self) { 844 let workspace_index = self.active_workspace(); 845 let workspace = self.workspace(workspace_index); 846 847 let cycle = workspace.active_focus_zone().unwrap(); 848 let cycle = self.zone_manager.nearest_cycle(cycle); 849 let id = self 850 .zone_manager 851 .new_zone(Some(cycle), ZoneContent::Tab(Cycle::new(Vec::new(), true))); 852 853 let workspace = self.workspace(workspace_index); 854 workspace.add_zone(id, &InsertPos::Back); 855 self.apply_layout(workspace_index); 856 self.apply_stack(workspace_index); 857 } 858 859 // TODO: zones 860 pub fn delete_zone(&mut self) { 861 let workspace_index = self.active_workspace(); 862 let workspace = self.workspace(workspace_index); 863 864 let cycle = workspace.active_spawn_zone().unwrap(); 865 let cycle = self.zone_manager.nearest_cycle(cycle); 866 867 if cycle == workspace.root_zone() { 868 return; 869 } 870 871 self.zone_manager.remove_zone(cycle); 872 873 let workspace = self.workspace(workspace_index); 874 workspace.remove_zone(cycle); 875 } 876 877 #[inline] 878 fn is_applyable(client: &Client) -> bool { 879 !client.is_floating() 880 && !client.is_disowned() 881 && client.is_managed() 882 && (!client.is_fullscreen() || client.is_contained()) 883 } 884 885 #[inline] 886 fn is_free( 887 &self, 888 client: &Client, 889 ) -> bool { 890 client.is_free() || self.zone_manager.zone(client.zone()).method() == PlacementMethod::Free 891 } 892 893 #[inline] 894 fn is_focusable( 895 &self, 896 client: &Client, 897 ) -> bool { 898 !client.is_disowned() && !client.is_iconified() 899 } 900 901 fn remove_window( 902 &mut self, 903 window: Window, 904 ) { 905 let client = match self.client_any(window) { 906 Some(client) if !client.consume_unmap_if_expecting() => client, 907 _ => return, 908 }; 909 910 let (window, frame) = client.windows(); 911 let workspace = client.workspace(); 912 913 info!("removing client with window {:#0x}", window); 914 915 if !client.is_managed() { 916 self.remanage(client, true); 917 } 918 919 if let Ok(geometry) = self.conn.get_window_geometry(frame) { 920 self.conn.unparent_window(window, geometry.pos); 921 } 922 923 self.conn.cleanup_window(window); 924 self.conn.destroy_window(frame); 925 926 if client.is_sticky() { 927 self.unstick(client); 928 } 929 930 if Some(window) == self.jumped_from.get() { 931 self.jumped_from.set(None); 932 } 933 934 if client.producer().is_some() { 935 self.unconsume_client(client); 936 } 937 938 if let Some(parent) = client.parent().and_then(|parent| self.client(parent)) { 939 parent.remove_child(window); 940 } 941 942 let id = client.zone(); 943 self.zone_manager.remove_zone(id); 944 945 { 946 let workspace = self.workspace(workspace); 947 workspace.remove_client(window); 948 workspace.remove_icon(window); 949 } 950 951 self.stack_manager.remove_window(window); 952 self.frame_map.remove(&frame); 953 self.window_map.remove(&window); 954 self.client_map.remove(&window); 955 self.pid_map.remove(&window); 956 self.fullscreen_regions.borrow_mut().remove(&window); 957 958 self.sync_focus(); 959 self.apply_layout(workspace); 960 } 961 962 #[inline(always)] 963 fn render_decoration( 964 &self, 965 client: &Client, 966 ) { 967 let (border, frame_color) = client.decoration_colors(); 968 969 if let Some((width, color)) = border { 970 self.conn.set_window_border_width(client.frame(), width); 971 self.conn.set_window_border_color(client.frame(), color); 972 } 973 974 if let Some(color) = frame_color { 975 self.conn.set_window_background_color(client.frame(), color); 976 } 977 } 978 979 #[inline(always)] 980 fn update_client_placement( 981 &self, 982 client: &Client, 983 placement: &Placement, 984 ) { 985 let region = match placement.region { 986 PlacementRegion::FreeRegion => client.free_region(), 987 PlacementRegion::NewRegion(region) => region, 988 PlacementRegion::NoRegion => return, 989 }; 990 991 let zone = self.zone_manager.zone(client.zone()); 992 zone.set_method(placement.method); 993 994 client.set_decoration(placement.decoration); 995 client.set_region(match placement.method { 996 PlacementMethod::Free => { 997 zone.set_region(region); 998 PlacementClass::Free(region) 999 }, 1000 PlacementMethod::Tile => PlacementClass::Tile(region), 1001 }); 1002 } 1003 1004 #[inline(always)] 1005 fn place_client( 1006 &self, 1007 client: &Client, 1008 method: PlacementMethod, 1009 ) { 1010 let (window, frame) = client.windows(); 1011 1012 self.conn.place_window(window, &client.inner_region()); 1013 self.conn.place_window(frame, &match method { 1014 PlacementMethod::Free => client.free_region(), 1015 PlacementMethod::Tile => client.tile_region(), 1016 }); 1017 1018 self.render_decoration(client); 1019 self.conn.update_window_offset(window, frame); 1020 } 1021 1022 #[inline(always)] 1023 fn map_client( 1024 &self, 1025 client: &Client, 1026 ) { 1027 if !client.is_mapped() { 1028 let (window, frame) = client.windows(); 1029 info!("mapping client with window {:#0x}", window); 1030 1031 self.conn.map_window(window); 1032 self.conn.map_window(frame); 1033 self.render_decoration(client); 1034 client.set_mapped(Toggle::On); 1035 } 1036 } 1037 1038 #[inline(always)] 1039 fn unmap_client( 1040 &self, 1041 client: &Client, 1042 ) { 1043 if client.is_mapped() { 1044 let (window, frame) = client.windows(); 1045 info!("unmapping client with window {:#0x}", window); 1046 1047 self.conn.unmap_window(frame); 1048 client.expect_unmap(); 1049 client.set_mapped(Toggle::Off); 1050 } 1051 } 1052 1053 fn consume_client( 1054 &self, 1055 consumer: &Client, 1056 producer: &Client, 1057 ) { 1058 if producer.is_iconified() || consumer.is_iconified() { 1059 return; 1060 } 1061 1062 let (cwindow, pwindow) = (consumer.window(), producer.window()); 1063 let (cworkspace, pworkspace) = (consumer.workspace(), producer.workspace()); 1064 1065 info!( 1066 "consuming client with window {:#0x} and producer window {:#0x}", 1067 cwindow, pwindow 1068 ); 1069 1070 consumer.set_producer(pwindow); 1071 1072 if producer.consumer_len() == 0 { 1073 let workspace = self.workspace(pworkspace); 1074 1075 if pworkspace == cworkspace { 1076 workspace.replace_client(pwindow, cwindow); 1077 } else { 1078 workspace.remove_client(pwindow); 1079 } 1080 1081 self.apply_layout(cworkspace); 1082 self.apply_stack(cworkspace); 1083 } 1084 1085 producer.add_consumer(cwindow); 1086 self.unmanage(producer); 1087 } 1088 1089 fn unconsume_client( 1090 &self, 1091 consumer: &Client, 1092 ) { 1093 let producer = match consumer 1094 .producer() 1095 .and_then(|producer| self.client_any(producer)) 1096 { 1097 Some(producer) => producer, 1098 None => return, 1099 }; 1100 1101 info!( 1102 "unconsuming client with window {:#0x} and producer window {:#0x}", 1103 consumer.window(), 1104 producer.window() 1105 ); 1106 1107 producer.remove_consumer(consumer.window()); 1108 1109 if producer.consumer_len() == 0 { 1110 let workspace = consumer.workspace(); 1111 1112 { 1113 let workspace = self.workspace(workspace); 1114 1115 if workspace.contains(consumer.window()) { 1116 workspace.replace_client(consumer.window(), producer.window()); 1117 } else { 1118 workspace.add_client(producer.window(), &InsertPos::Back); 1119 } 1120 } 1121 1122 producer.set_workspace(workspace); 1123 self.remanage(producer, false); 1124 self.apply_layout(workspace); 1125 self.apply_stack(workspace); 1126 } 1127 1128 consumer.unset_producer(); 1129 } 1130 1131 #[inline(always)] 1132 pub fn kill_focus(&self) { 1133 if let Some(focus) = self.focus.get() { 1134 self.kill_window(focus); 1135 } 1136 } 1137 1138 #[inline] 1139 pub fn kill_window( 1140 &self, 1141 window: Window, 1142 ) { 1143 match self.client_any(window) { 1144 Some(client) if !client.is_invincible() => { 1145 info!("killing client with window {:#0x}", window); 1146 1147 self.conn.kill_window(window); 1148 self.conn.flush(); 1149 }, 1150 _ => {}, 1151 } 1152 } 1153 1154 #[inline(always)] 1155 pub fn cycle_zones( 1156 &self, 1157 dir: Direction, 1158 ) { 1159 self.workspace(self.active_workspace()) 1160 .cycle_zones(dir, &self.zone_manager); 1161 } 1162 1163 #[inline(always)] 1164 pub fn cycle_focus( 1165 &self, 1166 dir: Direction, 1167 ) { 1168 if let Some((_, window)) = self.workspace(self.active_workspace()).cycle_focus( 1169 dir, 1170 &self.client_map, 1171 &self.zone_manager, 1172 ) { 1173 self.focus_window(window); 1174 self.sync_focus(); 1175 } 1176 } 1177 1178 #[inline(always)] 1179 pub fn drag_focus( 1180 &self, 1181 dir: Direction, 1182 ) { 1183 if let Some(focus) = self.focus.get() { 1184 let workspace = self.active_workspace(); 1185 1186 self.workspace(workspace).drag_focus(dir); 1187 self.apply_layout(workspace); 1188 self.focus_window(focus); 1189 } 1190 } 1191 1192 #[inline(always)] 1193 pub fn rotate_clients( 1194 &self, 1195 dir: Direction, 1196 ) { 1197 let workspace = self.workspace(self.active_workspace()); 1198 1199 if let Some(next) = workspace.next_client(dir.rev()) { 1200 workspace.rotate_clients(dir); 1201 self.apply_layout(self.active_workspace()); 1202 self.focus_window(next); 1203 } 1204 } 1205 1206 #[inline] 1207 pub fn move_focus_to_next_workspace( 1208 &self, 1209 dir: Direction, 1210 ) { 1211 if let Some(focus) = self.focus.get() { 1212 self.move_window_to_next_workspace(focus, dir); 1213 } 1214 } 1215 1216 #[inline] 1217 pub fn move_window_to_next_workspace( 1218 &self, 1219 window: Window, 1220 dir: Direction, 1221 ) { 1222 if let Some(client) = self.client(window) { 1223 self.move_client_to_next_workspace(client, dir); 1224 } 1225 } 1226 1227 #[inline] 1228 pub fn move_client_to_next_workspace( 1229 &self, 1230 client: &Client, 1231 dir: Direction, 1232 ) { 1233 self.move_client_to_workspace( 1234 client, 1235 Util::next_index(self.workspaces.iter(), self.active_workspace(), dir), 1236 ); 1237 } 1238 1239 #[inline] 1240 pub fn move_focus_to_workspace( 1241 &self, 1242 to: Index, 1243 ) { 1244 if let Some(focus) = self.focus.get() { 1245 self.move_window_to_workspace(focus, to); 1246 } 1247 } 1248 1249 #[inline] 1250 fn move_window_to_workspace( 1251 &self, 1252 window: Window, 1253 to: Index, 1254 ) { 1255 if let Some(client) = self.client(window) { 1256 self.move_client_to_workspace(client, to); 1257 } 1258 } 1259 1260 fn move_client_to_workspace( 1261 &self, 1262 client: &Client, 1263 to: Index, 1264 ) { 1265 let (window, from) = 1266 if to != self.active_workspace() && to < self.workspaces.len() && !client.is_sticky() { 1267 (client.window(), client.workspace()) 1268 } else { 1269 return; 1270 }; 1271 1272 info!( 1273 "moving client with window {:#0x} to workspace {}", 1274 window, to 1275 ); 1276 1277 client.set_workspace(to); 1278 self.unmap_client(client); 1279 1280 self.workspace(to).add_client(window, &InsertPos::Back); 1281 self.apply_layout(to); 1282 self.apply_stack(to); 1283 1284 self.workspace(from).remove_client(window); 1285 self.apply_layout(from); 1286 self.apply_stack(from); 1287 1288 self.sync_focus(); 1289 } 1290 1291 #[inline(always)] 1292 pub fn toggle_workspace(&self) { 1293 self.activate_workspace(self.prev_workspace.get()); 1294 } 1295 1296 #[inline(always)] 1297 pub fn activate_next_workspace( 1298 &self, 1299 dir: Direction, 1300 ) { 1301 self.activate_workspace(Util::next_index( 1302 self.workspaces.iter(), 1303 self.active_workspace(), 1304 dir, 1305 )); 1306 } 1307 1308 pub fn activate_workspace( 1309 &self, 1310 to: Index, 1311 ) { 1312 if to == self.active_workspace() || to >= self.workspaces.len() { 1313 return; 1314 } 1315 1316 info!("activating workspace {}", to); 1317 1318 self.stop_moving(); 1319 self.stop_resizing(); 1320 1321 let from = self.workspaces.active_index(); 1322 self.prev_workspace.set(from); 1323 1324 self.workspace(to) 1325 .on_each_client(&self.client_map, |client| { 1326 if !client.is_mapped() { 1327 self.map_client(client); 1328 } 1329 }); 1330 1331 self.workspace(from) 1332 .on_each_client(&self.client_map, |client| { 1333 if client.is_mapped() && !client.is_sticky() { 1334 self.unmap_client(client); 1335 } 1336 }); 1337 1338 self.sticky_clients.borrow().iter().for_each(|&window| { 1339 self.client_unchecked(window).set_workspace(to); 1340 }); 1341 1342 self.conn.set_current_desktop(to); 1343 1344 self.workspaces.activate_for(&Selector::AtIndex(to)); 1345 self.apply_layout(to); 1346 self.apply_stack(to); 1347 1348 self.sync_focus(); 1349 } 1350 1351 #[inline] 1352 pub fn change_gap_size( 1353 &mut self, 1354 change: Change<u32>, 1355 ) -> Result<(), StateChangeError> { 1356 let workspace = self.active_workspace(); 1357 1358 self.workspaces[workspace].change_gap_size(change, &mut self.zone_manager)?; 1359 self.apply_layout(workspace); 1360 self.apply_stack(workspace); 1361 1362 Ok(()) 1363 } 1364 1365 #[inline] 1366 pub fn copy_prev_layout_data(&mut self) -> Result<(), StateChangeError> { 1367 let workspace = self.active_workspace(); 1368 1369 self.workspaces[workspace].copy_prev_layout_data(&mut self.zone_manager)?; 1370 self.apply_layout(workspace); 1371 self.apply_stack(workspace); 1372 1373 Ok(()) 1374 } 1375 1376 #[inline] 1377 pub fn reset_layout_data(&mut self) -> Result<(), StateChangeError> { 1378 let workspace = self.active_workspace(); 1379 1380 self.workspaces[workspace].reset_layout_data(&mut self.zone_manager)?; 1381 self.apply_layout(workspace); 1382 self.apply_stack(workspace); 1383 1384 Ok(()) 1385 } 1386 1387 #[inline] 1388 pub fn reset_gap_size(&mut self) -> Result<(), StateChangeError> { 1389 let workspace = self.active_workspace(); 1390 1391 self.workspaces[workspace].reset_gap_size(&mut self.zone_manager)?; 1392 self.apply_layout(workspace); 1393 self.apply_stack(workspace); 1394 1395 Ok(()) 1396 } 1397 1398 #[inline] 1399 pub fn change_main_count( 1400 &mut self, 1401 change: Change<u32>, 1402 ) -> Result<(), StateChangeError> { 1403 let workspace = self.active_workspace(); 1404 1405 self.workspaces[workspace].change_main_count(change, &mut self.zone_manager)?; 1406 self.apply_layout(workspace); 1407 self.apply_stack(workspace); 1408 1409 Ok(()) 1410 } 1411 1412 #[inline] 1413 pub fn change_main_factor( 1414 &mut self, 1415 change: Change<f32>, 1416 ) -> Result<(), StateChangeError> { 1417 let workspace = self.active_workspace(); 1418 1419 self.workspaces[workspace].change_main_factor(change, &mut self.zone_manager)?; 1420 self.apply_layout(workspace); 1421 self.apply_stack(workspace); 1422 1423 Ok(()) 1424 } 1425 1426 #[inline] 1427 pub fn change_margin( 1428 &mut self, 1429 edge: Edge, 1430 change: Change<i32>, 1431 ) -> Result<(), StateChangeError> { 1432 let workspace = self.active_workspace(); 1433 1434 self.workspaces[workspace].change_margin(edge, change, &mut self.zone_manager)?; 1435 self.apply_layout(workspace); 1436 self.apply_stack(workspace); 1437 1438 Ok(()) 1439 } 1440 1441 #[inline] 1442 pub fn reset_margin(&mut self) -> Result<(), StateChangeError> { 1443 let workspace = self.active_workspace(); 1444 1445 self.workspaces[workspace].reset_margin(&mut self.zone_manager)?; 1446 self.apply_layout(workspace); 1447 self.apply_stack(workspace); 1448 1449 Ok(()) 1450 } 1451 1452 #[inline] 1453 pub fn set_layout( 1454 &mut self, 1455 kind: LayoutKind, 1456 ) -> Result<(), StateChangeError> { 1457 let workspace = self.active_workspace(); 1458 1459 if let Some(id) = self.workspaces[workspace].active_focus_zone() { 1460 info!("activating layout {:?} on workspace {}", kind, workspace); 1461 1462 self.zone_manager.set_kind(id, kind)?; 1463 self.apply_layout(workspace); 1464 self.apply_stack(workspace); 1465 } 1466 1467 Ok(()) 1468 } 1469 1470 #[inline] 1471 pub fn toggle_layout(&mut self) { 1472 let workspace = self.active_workspace(); 1473 1474 if let Some(id) = self.workspaces[workspace].active_focus_zone() { 1475 let prev_kind = self.zone_manager.set_prev_kind(id); 1476 1477 info!( 1478 "activating layout {:?} on workspace {}", 1479 prev_kind, workspace 1480 ); 1481 1482 self.apply_layout(workspace); 1483 self.apply_stack(workspace); 1484 } 1485 } 1486 1487 #[inline(always)] 1488 pub fn set_floating_focus( 1489 &self, 1490 toggle: Toggle, 1491 ) { 1492 if let Some(focus) = self.focus.get() { 1493 self.set_floating_window(focus, toggle); 1494 } 1495 } 1496 1497 #[inline(always)] 1498 pub fn set_floating_window( 1499 &self, 1500 window: Window, 1501 toggle: Toggle, 1502 ) { 1503 if let Some(client) = self.client(window) { 1504 self.set_floating_client(client, toggle); 1505 } 1506 } 1507 1508 #[inline] 1509 fn set_floating_client( 1510 &self, 1511 client: &Client, 1512 toggle: Toggle, 1513 ) { 1514 info!( 1515 "{}floating client with window {:#0x}", 1516 if toggle.eval(client.is_floating()) { 1517 "" 1518 } else { 1519 "un" 1520 }, 1521 client.window() 1522 ); 1523 1524 let workspace = client.workspace(); 1525 1526 client.set_floating(toggle); 1527 self.apply_layout(workspace); 1528 self.apply_stack(workspace); 1529 } 1530 1531 #[inline] 1532 pub fn set_fullscreen_focus( 1533 &self, 1534 toggle: Toggle, 1535 ) { 1536 if let Some(focus) = self.focus.get() { 1537 self.set_fullscreen_window(focus, toggle); 1538 } 1539 } 1540 1541 #[inline] 1542 pub fn set_fullscreen_window( 1543 &self, 1544 window: Window, 1545 toggle: Toggle, 1546 ) { 1547 if let Some(client) = self.client(window) { 1548 self.set_fullscreen_client(client, toggle); 1549 } 1550 } 1551 1552 fn set_fullscreen_client( 1553 &self, 1554 client: &Client, 1555 toggle: Toggle, 1556 ) { 1557 if toggle.eval(client.is_fullscreen()) { 1558 self.fullscreen(client); 1559 } else { 1560 self.unfullscreen(client); 1561 } 1562 } 1563 1564 #[inline(always)] 1565 fn fullscreen( 1566 &self, 1567 client: &Client, 1568 ) { 1569 if client.is_fullscreen() { 1570 return; 1571 } 1572 1573 let window = client.window(); 1574 let workspace = client.workspace(); 1575 info!("enabling fullscreen for client with window {:#0x}", window); 1576 1577 self.conn 1578 .set_window_state(window, WindowState::Fullscreen, true); 1579 1580 client.set_fullscreen(Toggle::On); 1581 self.apply_layout(workspace); 1582 self.apply_stack(workspace); 1583 1584 self.fullscreen_regions 1585 .borrow_mut() 1586 .insert(window, client.free_region()); 1587 } 1588 1589 #[inline(always)] 1590 fn unfullscreen( 1591 &self, 1592 client: &Client, 1593 ) { 1594 if !client.is_fullscreen() { 1595 return; 1596 } 1597 1598 let window = client.window(); 1599 let workspace = client.workspace(); 1600 info!("disabling fullscreen for client with window {:#0x}", window); 1601 1602 if let Some(free_region) = self.fullscreen_regions.borrow().get(&window).cloned() { 1603 client.set_region(PlacementClass::Free(free_region)); 1604 } 1605 1606 self.conn 1607 .set_window_state(window, WindowState::Fullscreen, false); 1608 1609 client.set_fullscreen(Toggle::Off); 1610 self.apply_layout(workspace); 1611 self.apply_stack(workspace); 1612 1613 self.fullscreen_regions.borrow_mut().remove(&window); 1614 } 1615 1616 #[inline(always)] 1617 pub fn set_contained_focus( 1618 &self, 1619 toggle: Toggle, 1620 ) { 1621 if let Some(focus) = self.focus.get() { 1622 self.set_contained_window(focus, toggle); 1623 } 1624 } 1625 1626 #[inline(always)] 1627 pub fn set_contained_window( 1628 &self, 1629 window: Window, 1630 toggle: Toggle, 1631 ) { 1632 if let Some(client) = self.client(window) { 1633 self.set_contained_client(client, toggle); 1634 } 1635 } 1636 1637 #[inline] 1638 fn set_contained_client( 1639 &self, 1640 client: &Client, 1641 toggle: Toggle, 1642 ) { 1643 client.set_contained(toggle); 1644 self.set_fullscreen_client(client, Toggle::from(!client.is_contained())); 1645 } 1646 1647 #[inline(always)] 1648 pub fn set_invincible_focus( 1649 &self, 1650 toggle: Toggle, 1651 ) { 1652 if let Some(focus) = self.focus.get() { 1653 self.set_invincible_window(focus, toggle); 1654 } 1655 } 1656 1657 #[inline(always)] 1658 pub fn set_invincible_window( 1659 &self, 1660 window: Window, 1661 toggle: Toggle, 1662 ) { 1663 if let Some(client) = self.client(window) { 1664 self.set_invincible_client(client, toggle); 1665 } 1666 } 1667 1668 #[inline(always)] 1669 fn set_invincible_client( 1670 &self, 1671 client: &Client, 1672 toggle: Toggle, 1673 ) { 1674 client.set_invincible(toggle); 1675 } 1676 1677 #[inline(always)] 1678 pub fn set_producing_focus( 1679 &self, 1680 toggle: Toggle, 1681 ) { 1682 if let Some(focus) = self.focus.get() { 1683 self.set_producing_window(focus, toggle); 1684 } 1685 } 1686 1687 #[inline(always)] 1688 pub fn set_producing_window( 1689 &self, 1690 window: Window, 1691 toggle: Toggle, 1692 ) { 1693 if let Some(client) = self.client(window) { 1694 self.set_producing_client(client, toggle); 1695 } 1696 } 1697 1698 #[inline(always)] 1699 fn set_producing_client( 1700 &self, 1701 client: &Client, 1702 toggle: Toggle, 1703 ) { 1704 client.set_producing(toggle); 1705 } 1706 1707 #[inline(always)] 1708 pub fn set_iconifyable_focus( 1709 &self, 1710 toggle: Toggle, 1711 ) { 1712 if let Some(focus) = self.focus.get() { 1713 self.set_iconifyable_window(focus, toggle); 1714 } 1715 } 1716 1717 #[inline(always)] 1718 pub fn set_iconifyable_window( 1719 &self, 1720 window: Window, 1721 toggle: Toggle, 1722 ) { 1723 if let Some(client) = self.client(window) { 1724 self.set_iconifyable_client(client, toggle); 1725 } 1726 } 1727 1728 #[inline(always)] 1729 fn set_iconifyable_client( 1730 &self, 1731 client: &Client, 1732 toggle: Toggle, 1733 ) { 1734 client.set_iconifyable(toggle); 1735 } 1736 1737 #[inline] 1738 pub fn set_iconify_focus( 1739 &self, 1740 toggle: Toggle, 1741 ) { 1742 if let Some(focus) = self.focus.get() { 1743 self.set_iconify_window(focus, toggle); 1744 } 1745 } 1746 1747 #[inline] 1748 pub fn set_iconify_window( 1749 &self, 1750 window: Window, 1751 toggle: Toggle, 1752 ) { 1753 if let Some(client) = self.client(window) { 1754 self.set_iconify_client(client, toggle); 1755 } 1756 } 1757 1758 fn set_iconify_client( 1759 &self, 1760 client: &Client, 1761 toggle: Toggle, 1762 ) { 1763 if toggle.eval(client.is_iconified()) { 1764 if client.is_iconifyable() { 1765 self.iconify(client); 1766 } 1767 } else { 1768 self.deiconify(client); 1769 } 1770 } 1771 1772 #[inline] 1773 pub fn pop_deiconify(&self) { 1774 if let Some(icon) = self.workspaces[self.active_workspace()].focused_icon() { 1775 self.set_iconify_window(icon, Toggle::Off); 1776 } 1777 } 1778 1779 #[inline] 1780 pub fn deiconify_all( 1781 &self, 1782 index: Index, 1783 ) { 1784 if index >= self.workspaces.len() { 1785 warn!( 1786 "attempting to deicony_all from nonexistent workspace {}", 1787 index 1788 ); 1789 return; 1790 } 1791 1792 let workspace = &self.workspaces[index]; 1793 1794 while let Some(icon) = workspace.focused_icon() { 1795 self.set_iconify_window(icon, Toggle::Off); 1796 } 1797 } 1798 1799 #[inline(always)] 1800 fn iconify( 1801 &self, 1802 client: &Client, 1803 ) { 1804 if client.is_iconified() { 1805 return; 1806 } 1807 1808 let window = client.window(); 1809 let workspace = client.workspace(); 1810 1811 info!("iconifying client with window {:#0x}", window); 1812 1813 self.workspaces[workspace].client_to_icon(window); 1814 1815 self.conn 1816 .set_icccm_window_state(window, IcccmWindowState::Iconic); 1817 1818 client.set_iconified(Toggle::On); 1819 self.unmap_client(client); 1820 1821 self.apply_layout(workspace); 1822 self.apply_stack(workspace); 1823 1824 self.sync_focus(); 1825 } 1826 1827 #[inline(always)] 1828 fn deiconify( 1829 &self, 1830 client: &Client, 1831 ) { 1832 if !client.is_iconified() { 1833 return; 1834 } 1835 1836 let window = client.window(); 1837 let workspace = client.workspace(); 1838 1839 info!("deiconifying client with window {:#0x}", window); 1840 1841 self.workspaces[workspace].icon_to_client(window); 1842 1843 self.conn 1844 .set_icccm_window_state(window, IcccmWindowState::Normal); 1845 1846 client.set_iconified(Toggle::Off); 1847 self.map_client(client); 1848 1849 self.apply_layout(workspace); 1850 self.apply_stack(workspace); 1851 1852 self.sync_focus(); 1853 } 1854 1855 #[inline] 1856 pub fn set_stick_focus( 1857 &self, 1858 toggle: Toggle, 1859 ) { 1860 if let Some(focus) = self.focus.get() { 1861 self.set_stick_window(focus, toggle); 1862 } 1863 } 1864 1865 #[inline] 1866 pub fn set_stick_window( 1867 &self, 1868 window: Window, 1869 toggle: Toggle, 1870 ) { 1871 if let Some(client) = self.client(window) { 1872 self.set_stick_client(client, toggle); 1873 } 1874 } 1875 1876 fn set_stick_client( 1877 &self, 1878 client: &Client, 1879 toggle: Toggle, 1880 ) { 1881 if toggle.eval(client.is_sticky()) { 1882 self.stick(client); 1883 } else { 1884 self.unstick(client); 1885 } 1886 } 1887 1888 #[inline(always)] 1889 fn stick( 1890 &self, 1891 client: &Client, 1892 ) { 1893 if client.is_sticky() { 1894 return; 1895 } 1896 1897 let window = client.window(); 1898 info!("sticking client with window {:#0x}", window); 1899 1900 self.workspaces 1901 .iter() 1902 .filter(|workspace| workspace.number() as Index != client.workspace()) 1903 .for_each(|workspace| workspace.add_client(window, &InsertPos::Back)); 1904 1905 self.conn 1906 .set_window_state(window, WindowState::Sticky, true); 1907 1908 client.set_sticky(Toggle::On); 1909 self.render_decoration(client); 1910 1911 self.sticky_clients.borrow_mut().insert(window); 1912 } 1913 1914 #[inline(always)] 1915 fn unstick( 1916 &self, 1917 client: &Client, 1918 ) { 1919 if !client.is_sticky() { 1920 return; 1921 } 1922 1923 let window = client.window(); 1924 info!("unsticking client with window {:#0x}", window); 1925 1926 self.workspaces 1927 .iter() 1928 .filter(|workspace| workspace.number() as Index != client.workspace()) 1929 .for_each(|workspace| { 1930 workspace.remove_client(window); 1931 workspace.remove_icon(window); 1932 }); 1933 1934 self.conn 1935 .set_window_state(window, WindowState::Sticky, false); 1936 1937 client.set_sticky(Toggle::Off); 1938 self.render_decoration(client); 1939 1940 self.sticky_clients.borrow_mut().remove(&window); 1941 } 1942 1943 #[inline(always)] 1944 fn focus_window( 1945 &self, 1946 window: Window, 1947 ) { 1948 if let Some(client) = self.client(window) { 1949 self.focus(client); 1950 } 1951 } 1952 1953 fn focus( 1954 &self, 1955 client: &Client, 1956 ) { 1957 let (window, frame) = match client.windows() { 1958 windows if self.is_focusable(client) && Some(windows.0) != self.focus.get() => windows, 1959 _ => return, 1960 }; 1961 1962 info!("focusing client with window {:#0x}", window); 1963 1964 if self.active_workspace() != client.workspace() { 1965 self.activate_workspace(client.workspace()); 1966 } 1967 1968 let workspace = client.workspace(); 1969 1970 if let Some(prev_focus) = self.focus.get() { 1971 self.unfocus_window(prev_focus); 1972 } 1973 1974 self.conn.ungrab_buttons(frame); 1975 1976 if let Some(client) = self.client(window) { 1977 client.set_focused(Toggle::On); 1978 client.set_urgent(Toggle::Off); 1979 } 1980 1981 let id = client.zone(); 1982 let cycle = self.zone_manager.nearest_cycle(id); 1983 self.zone_manager.activate_zone(id); 1984 1985 { 1986 let workspace = self.workspace(workspace); 1987 workspace.activate_zone(cycle); 1988 workspace.focus_client(window); 1989 } 1990 1991 if self.zone_manager.is_within_persisent(id) { 1992 self.apply_layout(workspace); 1993 } 1994 1995 if self.conn.get_focused_window() != window { 1996 self.conn.focus_window(window); 1997 } 1998 1999 self.focus.set(Some(window)); 2000 self.render_decoration(client); 2001 self.apply_stack(workspace); 2002 } 2003 2004 #[inline] 2005 fn unfocus_window( 2006 &self, 2007 window: Window, 2008 ) { 2009 if let Some(client) = self.client(window) { 2010 self.unfocus(client); 2011 } 2012 } 2013 2014 #[inline] 2015 fn unfocus( 2016 &self, 2017 client: &Client, 2018 ) { 2019 let (window, frame) = client.windows(); 2020 info!("unfocusing client with window {:#0x}", window); 2021 2022 client.set_warp_pos(self.conn.get_pointer_position()); 2023 client.set_focused(Toggle::Off); 2024 2025 self.conn.regrab_buttons(frame); 2026 self.render_decoration(client); 2027 } 2028 2029 #[inline(always)] 2030 fn sync_focus(&self) { 2031 let workspace = self.workspace(self.active_workspace()); 2032 2033 match workspace.focused_client() { 2034 Some(focus) if Some(focus) != self.focus.get() => { 2035 self.focus_window(focus); 2036 }, 2037 _ if workspace.is_empty() => { 2038 self.conn.unfocus(); 2039 self.focus.set(None); 2040 }, 2041 _ => {}, 2042 } 2043 } 2044 2045 pub fn jump_client( 2046 &self, 2047 criterium: JumpCriterium, 2048 ) { 2049 let mut window = match criterium { 2050 JumpCriterium::OnWorkspaceBySelector(index, &sel) if index < self.workspaces.len() => { 2051 match self.workspaces[index].get_client_for(sel, &self.zone_manager) { 2052 Some(window) => window, 2053 _ => return, 2054 } 2055 }, 2056 JumpCriterium::ByName(method) => { 2057 match self 2058 .client_map 2059 .values() 2060 .filter(|&client| client.is_managed() && client.name_matches(method)) 2061 .max_by_key(|client| client.last_focused()) 2062 { 2063 Some(client) => client.window(), 2064 None => return, 2065 } 2066 }, 2067 JumpCriterium::ByClass(method) => { 2068 match self 2069 .client_map 2070 .values() 2071 .filter(|&client| client.is_managed() && client.class_matches(method)) 2072 .max_by_key(|client| client.last_focused()) 2073 { 2074 Some(client) => client.window(), 2075 None => return, 2076 } 2077 }, 2078 JumpCriterium::ByInstance(method) => { 2079 match self 2080 .client_map 2081 .values() 2082 .filter(|&client| client.is_managed() && client.instance_matches(method)) 2083 .max_by_key(|client| client.last_focused()) 2084 { 2085 Some(client) => client.window(), 2086 None => return, 2087 } 2088 }, 2089 JumpCriterium::ForCond(cond) => { 2090 match self 2091 .client_map 2092 .values() 2093 .filter(|&client| client.is_managed() && cond(client)) 2094 .max_by_key(|client| client.last_focused()) 2095 { 2096 Some(client) => client.window(), 2097 None => return, 2098 } 2099 }, 2100 _ => return, 2101 }; 2102 2103 if let Some(focus) = self.focus.get() { 2104 if window == focus { 2105 match self.jumped_from.get() { 2106 Some(jumped_from) if jumped_from != focus => { 2107 window = jumped_from; 2108 }, 2109 _ => {}, 2110 } 2111 } 2112 2113 self.jumped_from.set(Some(focus)); 2114 } 2115 2116 info!("jumping to client with window {:#0x}", window); 2117 self.focus_window(window); 2118 } 2119 2120 #[inline(always)] 2121 pub fn center_focus(&self) { 2122 if let Some(focus) = self.focus.get() { 2123 self.center_window(focus); 2124 } 2125 } 2126 2127 #[inline(always)] 2128 pub fn center_window( 2129 &self, 2130 window: Window, 2131 ) { 2132 if let Some(client) = self.client(window) { 2133 self.center_client(client); 2134 } 2135 } 2136 2137 pub fn center_client( 2138 &self, 2139 client: &Client, 2140 ) { 2141 if !self.is_free(client) { 2142 return; 2143 } 2144 2145 info!("centering client with window {:#0x}", client.window()); 2146 2147 let mut region = client.free_region(); 2148 region.pos = self 2149 .active_screen() 2150 .full_region() 2151 .from_absolute_inner_center(region.dim) 2152 .pos; 2153 2154 self.conn.move_window(client.frame(), region.pos); 2155 client.set_region(PlacementClass::Free(region)); 2156 } 2157 2158 pub fn apply_float_retain_region(&mut self) { 2159 let workspace = self.active_workspace(); 2160 2161 self.workspace(workspace) 2162 .clients() 2163 .into_iter() 2164 .map(|window| self.client_unchecked(window)) 2165 .for_each(|client| client.set_region(PlacementClass::Free(client.active_region()))); 2166 2167 self.set_layout(LayoutKind::Float).ok(); 2168 self.apply_layout(workspace); 2169 } 2170 2171 #[inline(always)] 2172 pub fn snap_focus( 2173 &self, 2174 edge: Edge, 2175 ) { 2176 if let Some(focus) = self.focus.get() { 2177 self.snap_window(focus, edge); 2178 } 2179 } 2180 2181 #[inline(always)] 2182 pub fn snap_window( 2183 &self, 2184 window: Window, 2185 edge: Edge, 2186 ) { 2187 if let Some(client) = self.client(window) { 2188 self.snap_client(client, edge); 2189 } 2190 } 2191 2192 fn snap_client( 2193 &self, 2194 client: &Client, 2195 edge: Edge, 2196 ) { 2197 if !self.is_free(client) { 2198 return; 2199 } 2200 2201 let window = client.window(); 2202 2203 info!( 2204 "snapping client with window {:#0x} to edge {:?}", 2205 window, edge 2206 ); 2207 2208 let placeable_region = self.active_screen().placeable_region(); 2209 let mut region = client.free_region(); 2210 2211 match edge { 2212 Edge::Left => region.pos.x = placeable_region.pos.x, 2213 Edge::Right => { 2214 let x = placeable_region.dim.w + placeable_region.pos.x; 2215 region.pos.x = std::cmp::max(0, x - region.dim.w) 2216 }, 2217 Edge::Top => region.pos.y = placeable_region.pos.y, 2218 Edge::Bottom => { 2219 let y = placeable_region.dim.h + placeable_region.pos.y; 2220 region.pos.y = std::cmp::max(0, y - region.dim.h) 2221 }, 2222 } 2223 2224 client.set_region(PlacementClass::Free(region)); 2225 2226 let placement = Placement { 2227 method: PlacementMethod::Free, 2228 kind: PlacementTarget::Client(window), 2229 zone: client.zone(), 2230 region: PlacementRegion::FreeRegion, 2231 decoration: client.decoration(), 2232 }; 2233 2234 self.update_client_placement(client, &placement); 2235 self.place_client(client, placement.method); 2236 } 2237 2238 #[inline(always)] 2239 pub fn nudge_focus( 2240 &self, 2241 edge: Edge, 2242 step: i32, 2243 ) { 2244 if let Some(focus) = self.focus.get() { 2245 self.nudge_window(focus, edge, step); 2246 } 2247 } 2248 2249 #[inline(always)] 2250 pub fn nudge_window( 2251 &self, 2252 window: Window, 2253 edge: Edge, 2254 step: i32, 2255 ) { 2256 if let Some(client) = self.client(window) { 2257 self.nudge_client(client, edge, step); 2258 } 2259 } 2260 2261 fn nudge_client( 2262 &self, 2263 client: &Client, 2264 edge: Edge, 2265 step: i32, 2266 ) { 2267 if !self.is_free(client) { 2268 return; 2269 } 2270 2271 let window = client.window(); 2272 2273 info!( 2274 "nudging client with window {:#0x} at the {:?} by {}", 2275 window, edge, step 2276 ); 2277 2278 let mut region = client.free_region(); 2279 2280 match edge { 2281 Edge::Left => region.pos.x -= step, 2282 Edge::Right => region.pos.x += step, 2283 Edge::Top => region.pos.y -= step, 2284 Edge::Bottom => region.pos.y += step, 2285 } 2286 2287 client.set_region(PlacementClass::Free(region)); 2288 2289 let placement = Placement { 2290 method: PlacementMethod::Free, 2291 kind: PlacementTarget::Client(window), 2292 zone: client.zone(), 2293 region: PlacementRegion::FreeRegion, 2294 decoration: client.decoration(), 2295 }; 2296 2297 self.update_client_placement(client, &placement); 2298 self.place_client(client, placement.method); 2299 } 2300 2301 #[inline(always)] 2302 pub fn grow_ratio_focus( 2303 &self, 2304 step: i32, 2305 ) { 2306 if let Some(focus) = self.focus.get() { 2307 self.grow_ratio_window(focus, step); 2308 } 2309 } 2310 2311 #[inline(always)] 2312 pub fn grow_ratio_window( 2313 &self, 2314 window: Window, 2315 step: i32, 2316 ) { 2317 if let Some(client) = self.client(window) { 2318 self.grow_ratio_client(client, step); 2319 } 2320 } 2321 2322 fn grow_ratio_client( 2323 &self, 2324 client: &Client, 2325 step: i32, 2326 ) { 2327 if !self.is_free(client) { 2328 return; 2329 } 2330 2331 let frame_extents = client.frame_extents(); 2332 2333 let original_region = client.free_region(); 2334 let region = original_region; 2335 let (width, height) = region.dim.values(); 2336 2337 let fraction = width as f64 / (width + height) as f64; 2338 let width_inc = fraction * step as f64; 2339 let height_inc = step as f64 - width_inc; 2340 let width_inc = width_inc.round() as i32; 2341 let height_inc = height_inc.round() as i32; 2342 2343 let mut region = region.without_extents(frame_extents); 2344 2345 if (width_inc.is_negative() && -width_inc >= region.dim.w) 2346 || (height_inc.is_negative() && -height_inc >= region.dim.h) 2347 || (region.dim.w + width_inc <= Client::MIN_CLIENT_DIM.w) 2348 || (region.dim.h + height_inc <= Client::MIN_CLIENT_DIM.h) 2349 { 2350 return; 2351 } 2352 2353 let window = client.window(); 2354 2355 info!( 2356 "{} client with window {:#0x} by {}", 2357 if step >= 0 { "growing" } else { "shrinking" }, 2358 window, 2359 step.abs() 2360 ); 2361 2362 region.dim.w += width_inc; 2363 region.dim.h += height_inc; 2364 2365 region = region.with_extents(frame_extents); 2366 let dx = region.dim.w - original_region.dim.w; 2367 let dy = region.dim.h - original_region.dim.h; 2368 2369 let width_shift = (dx as f64 / 2f64) as i32; 2370 let height_shift = (dy as f64 / 2f64) as i32; 2371 2372 region.pos.x -= width_shift; 2373 region.pos.y -= height_shift; 2374 2375 client.set_region(PlacementClass::Free(region)); 2376 2377 let placement = Placement { 2378 method: PlacementMethod::Free, 2379 kind: PlacementTarget::Client(window), 2380 zone: client.zone(), 2381 region: PlacementRegion::FreeRegion, 2382 decoration: client.decoration(), 2383 }; 2384 2385 self.update_client_placement(client, &placement); 2386 self.place_client(client, placement.method); 2387 } 2388 2389 #[inline(always)] 2390 pub fn stretch_focus( 2391 &self, 2392 edge: Edge, 2393 step: i32, 2394 ) { 2395 if let Some(focus) = self.focus.get() { 2396 self.stretch_window(focus, edge, step); 2397 } 2398 } 2399 2400 #[inline(always)] 2401 pub fn stretch_window( 2402 &self, 2403 window: Window, 2404 edge: Edge, 2405 step: i32, 2406 ) { 2407 if let Some(client) = self.client(window) { 2408 self.stretch_client(client, edge, step); 2409 } 2410 } 2411 2412 fn stretch_client( 2413 &self, 2414 client: &Client, 2415 edge: Edge, 2416 step: i32, 2417 ) { 2418 if !self.is_free(client) { 2419 return; 2420 } 2421 2422 let window = client.window(); 2423 2424 info!( 2425 "stretching client with window {:#0x} at the {:?} by {}", 2426 window, edge, step 2427 ); 2428 2429 let frame_extents = client.frame_extents(); 2430 let mut region = client.free_region().without_extents(frame_extents); 2431 2432 match edge { 2433 Edge::Left if !(step.is_negative() && -step >= region.dim.w) => { 2434 if region.dim.w + step <= Client::MIN_CLIENT_DIM.w { 2435 region.pos.x -= Client::MIN_CLIENT_DIM.w - region.dim.w; 2436 region.dim.w = Client::MIN_CLIENT_DIM.w; 2437 } else { 2438 region.pos.x -= step; 2439 region.dim.w += step; 2440 } 2441 }, 2442 Edge::Right if !(step.is_negative() && -step >= region.dim.w) => { 2443 if region.dim.w + step <= Client::MIN_CLIENT_DIM.w { 2444 region.dim.w = Client::MIN_CLIENT_DIM.w; 2445 } else { 2446 region.dim.w += step; 2447 } 2448 }, 2449 Edge::Top if !(step.is_negative() && -step >= region.dim.h) => { 2450 if region.dim.h + step <= Client::MIN_CLIENT_DIM.h { 2451 region.pos.y -= Client::MIN_CLIENT_DIM.h - region.dim.h; 2452 region.dim.h = Client::MIN_CLIENT_DIM.h; 2453 } else { 2454 region.pos.y -= step; 2455 region.dim.h += step; 2456 } 2457 }, 2458 Edge::Bottom if (!step.is_negative() && -step >= region.dim.h) => { 2459 if region.dim.h + step <= Client::MIN_CLIENT_DIM.h { 2460 region.dim.h = Client::MIN_CLIENT_DIM.h; 2461 } else { 2462 region.dim.h += step; 2463 } 2464 }, 2465 _ => return, 2466 } 2467 2468 client.set_region(PlacementClass::Free(region.with_extents(frame_extents))); 2469 2470 let placement = Placement { 2471 method: PlacementMethod::Free, 2472 kind: PlacementTarget::Client(window), 2473 zone: client.zone(), 2474 region: PlacementRegion::FreeRegion, 2475 decoration: client.decoration(), 2476 }; 2477 2478 self.update_client_placement(client, &placement); 2479 self.place_client(client, placement.method); 2480 } 2481 2482 pub fn start_moving( 2483 &self, 2484 window: Window, 2485 ) { 2486 if self.move_buffer.is_occupied() || self.resize_buffer.is_occupied() { 2487 return; 2488 } 2489 2490 if let Some(client) = self.client(window) { 2491 self.move_buffer.set( 2492 client.window(), 2493 Grip::Corner(Corner::TopLeft), 2494 self.conn.get_pointer_position(), 2495 client.free_region(), 2496 ); 2497 2498 self.conn.confine_pointer(self.move_buffer.handle()); 2499 } 2500 } 2501 2502 #[inline(always)] 2503 pub fn stop_moving(&self) { 2504 if self.move_buffer.is_occupied() { 2505 self.conn.release_pointer(); 2506 self.move_buffer.unset(); 2507 } 2508 } 2509 2510 #[inline(always)] 2511 pub fn handle_move( 2512 &self, 2513 pos: &Pos, 2514 ) { 2515 if !self.move_buffer.is_occupied() { 2516 return; 2517 } 2518 2519 let client = self 2520 .move_buffer 2521 .window() 2522 .and_then(|window| self.client(window)) 2523 .unwrap(); 2524 2525 if !self.is_free(client) { 2526 return; 2527 } 2528 2529 client.set_region(PlacementClass::Free(Region { 2530 pos: self.move_buffer.window_region().unwrap().pos 2531 + self.move_buffer.grip_pos().unwrap().dist(*pos), 2532 dim: client.free_region().dim, 2533 })); 2534 2535 let placement = Placement { 2536 method: PlacementMethod::Free, 2537 kind: PlacementTarget::Client(client.window()), 2538 zone: client.zone(), 2539 region: PlacementRegion::FreeRegion, 2540 decoration: client.decoration(), 2541 }; 2542 2543 self.update_client_placement(client, &placement); 2544 self.place_client(client, placement.method); 2545 } 2546 2547 pub fn start_resizing( 2548 &self, 2549 window: Window, 2550 ) { 2551 if self.move_buffer.is_occupied() || self.resize_buffer.is_occupied() { 2552 return; 2553 } 2554 2555 if let Some(client) = self.client(window) { 2556 let pos = self.conn.get_pointer_position(); 2557 2558 self.resize_buffer.set( 2559 client.window(), 2560 Grip::Corner(client.free_region().nearest_corner(pos)), 2561 pos, 2562 client.free_region(), 2563 ); 2564 2565 self.conn.confine_pointer(self.resize_buffer.handle()); 2566 } 2567 } 2568 2569 pub fn stop_resizing(&self) { 2570 if self.resize_buffer.is_occupied() { 2571 self.conn.release_pointer(); 2572 self.resize_buffer.unset(); 2573 } 2574 } 2575 2576 #[inline(always)] 2577 pub fn handle_resize( 2578 &self, 2579 pos: &Pos, 2580 ) { 2581 if !self.resize_buffer.is_occupied() { 2582 return; 2583 } 2584 2585 let client = self 2586 .resize_buffer 2587 .window() 2588 .and_then(|window| self.client(window)) 2589 .unwrap(); 2590 2591 if !self.is_free(client) { 2592 return; 2593 } 2594 2595 let mut region = client.free_region().without_extents(client.frame_extents()); 2596 2597 let window_region = self.resize_buffer.window_region().unwrap(); 2598 let grip = self.resize_buffer.grip().unwrap(); 2599 2600 let top_grip = grip.is_top_grip(); 2601 let left_grip = grip.is_left_grip(); 2602 let delta = self.resize_buffer.grip_pos().unwrap().dist(pos.to_owned()); 2603 2604 let dest_w = if left_grip { 2605 window_region.dim.w - delta.dx 2606 } else { 2607 window_region.dim.w + delta.dx 2608 }; 2609 2610 let dest_h = if top_grip { 2611 window_region.dim.h - delta.dy 2612 } else { 2613 window_region.dim.h + delta.dy 2614 }; 2615 2616 region.dim.w = std::cmp::max(0, dest_w); 2617 region.dim.h = std::cmp::max(0, dest_h); 2618 2619 if let Some(size_hints) = client.size_hints() { 2620 size_hints.apply(&mut region.dim); 2621 } 2622 2623 region = region.with_extents(client.frame_extents()); 2624 2625 if top_grip { 2626 region.pos.y = window_region.pos.y + (window_region.dim.h - region.dim.h); 2627 } 2628 2629 if left_grip { 2630 region.pos.x = window_region.pos.x + (window_region.dim.w - region.dim.w); 2631 } 2632 2633 if region == client.previous_region() { 2634 return; 2635 } 2636 2637 let placement = Placement { 2638 method: PlacementMethod::Free, 2639 kind: PlacementTarget::Client(client.window()), 2640 zone: client.zone(), 2641 region: PlacementRegion::NewRegion(region), 2642 decoration: client.decoration(), 2643 }; 2644 2645 self.update_client_placement(client, &placement); 2646 self.place_client(client, placement.method); 2647 } 2648 2649 pub fn run( 2650 &mut self, 2651 mut key_bindings: KeyBindings, 2652 mut mouse_bindings: MouseBindings, 2653 ) { 2654 while self.running { 2655 if let Some(event) = self.conn.step() { 2656 trace!("received event: {:?}", event); 2657 2658 match event { 2659 Event::Mouse { 2660 event, 2661 on_root, 2662 } => self.handle_mouse(event, on_root, &mut mouse_bindings), 2663 Event::Key { 2664 event, 2665 } => self.handle_key(event, &mut key_bindings), 2666 Event::MapRequest { 2667 window, 2668 ignore, 2669 } => self.handle_map_request(window, ignore), 2670 Event::Map { 2671 window, 2672 ignore, 2673 } => self.handle_map(window, ignore), 2674 Event::Enter { 2675 window, 2676 root_rpos, 2677 window_rpos, 2678 } => self.handle_enter(window, root_rpos, window_rpos), 2679 Event::Leave { 2680 window, 2681 root_rpos, 2682 window_rpos, 2683 } => self.handle_leave(window, root_rpos, window_rpos), 2684 Event::Destroy { 2685 window, 2686 } => self.handle_destroy(window), 2687 Event::Expose { 2688 window, 2689 } => self.handle_expose(window), 2690 Event::Unmap { 2691 window, 2692 ignore, 2693 } => self.handle_unmap(window, ignore), 2694 Event::Configure { 2695 window, 2696 region, 2697 on_root, 2698 } => self.handle_configure(window, region, on_root), 2699 Event::StateRequest { 2700 window, 2701 state, 2702 action, 2703 on_root, 2704 } => self.handle_state_request(window, state, action, on_root), 2705 Event::FocusRequest { 2706 window, 2707 on_root, 2708 } => self.handle_focus_request(window, on_root), 2709 Event::CloseRequest { 2710 window, 2711 on_root, 2712 } => self.handle_close_request(window, on_root), 2713 Event::WorkspaceRequest { 2714 window, 2715 index, 2716 on_root, 2717 } => self.handle_workspace_request(window, index, on_root), 2718 Event::PlacementRequest { 2719 window, 2720 pos, 2721 dim, 2722 on_root, 2723 } => self.handle_placement_request(window, pos, dim, on_root), 2724 Event::GripRequest { 2725 window, 2726 pos, 2727 grip, 2728 on_root, 2729 } => self.handle_grip_request(window, pos, grip, on_root), 2730 Event::RestackRequest { 2731 window, 2732 sibling, 2733 mode, 2734 on_root, 2735 } => self.handle_restack_request(window, sibling, mode, on_root), 2736 Event::Property { 2737 window, 2738 kind, 2739 on_root, 2740 } => self.handle_property(window, kind, on_root), 2741 Event::FrameExtentsRequest { 2742 window, 2743 on_root, 2744 } => self.handle_frame_extents_request(window, on_root), 2745 Event::ScreenChange => self.handle_screen_change(), 2746 } 2747 } 2748 2749 self.conn.flush(); 2750 } 2751 } 2752 2753 #[inline(always)] 2754 fn handle_mouse( 2755 &mut self, 2756 event: MouseEvent, 2757 on_root: bool, 2758 mouse_bindings: &mut MouseBindings, 2759 ) { 2760 let mut input = event.input; 2761 let window = event.window; 2762 2763 match event.kind { 2764 MouseEventKind::Release => { 2765 self.stop_moving(); 2766 self.stop_resizing(); 2767 2768 return; 2769 }, 2770 MouseEventKind::Motion => { 2771 self.handle_move(&event.root_rpos); 2772 self.handle_resize(&event.root_rpos); 2773 2774 return; 2775 }, 2776 _ => {}, 2777 } 2778 2779 { 2780 // handle global mouse bindings 2781 input.target = MouseInputTarget::Global; 2782 let binding = mouse_bindings.get_mut(&input); 2783 2784 if let Some(action) = binding { 2785 if action(self, None) { 2786 // TODO: config.focus_follows_mouse 2787 if let Some(focus) = self.focus.get() { 2788 if window.is_some() && window != Some(focus) { 2789 self.focus_window(window.unwrap()); 2790 } 2791 } 2792 } 2793 2794 return; 2795 } 2796 } 2797 2798 if on_root { 2799 // handle root-targeted mouse bindings 2800 input.target = MouseInputTarget::Root; 2801 let binding = mouse_bindings.get_mut(&input); 2802 2803 if let Some(action) = binding { 2804 action(self, None); 2805 return; 2806 } 2807 } 2808 2809 { 2810 // handle client-targeted mouse bindings 2811 input.target = MouseInputTarget::Client; 2812 let binding = mouse_bindings.get_mut(&input); 2813 2814 if let Some(window) = event.window { 2815 if let Some(window) = self.window(window) { 2816 if let Some(action) = binding { 2817 if action(self, Some(window)) { 2818 // TODO: config.focus_follows_mouse 2819 if let Some(focus) = self.focus.get() { 2820 if window != focus { 2821 self.focus_window(window); 2822 } 2823 } 2824 } 2825 } else { 2826 if event.kind != MouseEventKind::Release { 2827 if let Some(focus) = self.focus.get() { 2828 if window != focus { 2829 self.focus_window(window); 2830 } 2831 } 2832 } 2833 } 2834 } 2835 } 2836 } 2837 } 2838 2839 #[inline(always)] 2840 fn handle_key( 2841 &mut self, 2842 event: KeyEvent, 2843 key_bindings: &mut KeyBindings, 2844 ) { 2845 if let Some(action) = key_bindings.get_mut(&event.input) { 2846 debug!("processing key binding: {:?}", event.input); 2847 action(self); 2848 } 2849 } 2850 2851 #[inline(always)] 2852 fn handle_map_request( 2853 &mut self, 2854 window: Window, 2855 ignore: bool, 2856 ) { 2857 debug!("MAP_REQUEST for window {:#0x}", window); 2858 2859 let workspace = self.active_workspace(); 2860 2861 if ignore { 2862 if let Some(struts) = self.conn.get_window_strut(window) { 2863 let screen = self.active_screen(); 2864 screen.add_struts(struts); 2865 2866 if !screen.showing_struts() { 2867 self.conn.unmap_window(window); 2868 } else { 2869 screen.compute_placeable_region(); 2870 self.apply_layout(workspace); 2871 self.apply_stack(workspace); 2872 } 2873 } 2874 2875 let preferred_state = self.conn.get_window_preferred_state(window); 2876 let preferred_type = self.conn.get_window_preferred_type(window); 2877 let geometry = self.conn.get_window_geometry(window); 2878 2879 if let Some(layer) = match (preferred_state, preferred_type) { 2880 (Some(WindowState::Below), _) => Some(StackLayer::Below), 2881 (_, WindowType::Desktop) => Some(StackLayer::Desktop), 2882 (_, WindowType::Dock) => { 2883 if let Ok(geometry) = geometry { 2884 let screen = self.active_screen(); 2885 let full_region = screen.full_region(); 2886 2887 if !screen.contains_window(window) { 2888 let strut = match ( 2889 (geometry.pos.x, geometry.pos.y), 2890 (geometry.dim.w, geometry.dim.h), 2891 ) { 2892 ((0, 0), (w, h)) if w == full_region.dim.w => Some((Edge::Top, h)), 2893 ((0, 0), (w, h)) if h == full_region.dim.h => Some((Edge::Left, w)), 2894 ((0, 0), (w, h)) if w > h => Some((Edge::Top, h)), 2895 ((0, 0), (w, h)) if w < h => Some((Edge::Left, w)), 2896 ((_, y), (_, h)) if y == full_region.dim.h - h => { 2897 Some((Edge::Bottom, h)) 2898 }, 2899 ((x, _), (w, _)) if x == full_region.dim.w - w => { 2900 Some((Edge::Right, w)) 2901 }, 2902 _ => None, 2903 }; 2904 2905 if let Some((edge, width)) = strut { 2906 screen.add_strut(edge, window, width as u32); 2907 2908 if !screen.showing_struts() { 2909 self.conn.unmap_window(window); 2910 } else { 2911 screen.compute_placeable_region(); 2912 self.apply_layout(workspace); 2913 self.apply_stack(workspace); 2914 } 2915 } 2916 } 2917 } 2918 2919 Some(StackLayer::Dock) 2920 }, 2921 (_, WindowType::Notification) => Some(StackLayer::Notification), 2922 (Some(WindowState::Above), _) => Some(StackLayer::Above), 2923 (..) => None, 2924 } { 2925 self.stack_manager.add_window(window, layer) 2926 }; 2927 2928 self.apply_stack(self.active_workspace()); 2929 } 2930 2931 if self.client_map.contains_key(&window) { 2932 return; 2933 } 2934 2935 self.manage(window, ignore); 2936 } 2937 2938 #[inline] 2939 fn handle_map( 2940 &self, 2941 window: Window, 2942 _ignore: bool, 2943 ) { 2944 debug!("MAP for window {:#0x}", window); 2945 } 2946 2947 #[inline] 2948 fn handle_enter( 2949 &self, 2950 window: Window, 2951 _root_rpos: Pos, 2952 _window_rpos: Pos, 2953 ) { 2954 debug!("ENTER for window {:#0x}", window); 2955 2956 if let Some(client) = self.client(window) { 2957 if let Some(focus) = self.focus.get() { 2958 if client.window() != focus { 2959 self.unfocus_window(focus); 2960 } else { 2961 return; 2962 } 2963 } 2964 2965 self.focus(client); 2966 } 2967 } 2968 2969 #[inline] 2970 fn handle_leave( 2971 &self, 2972 window: Window, 2973 _root_rpos: Pos, 2974 _window_rpos: Pos, 2975 ) { 2976 debug!("LEAVE for window {:#0x}", window); 2977 self.unfocus_window(window); 2978 } 2979 2980 #[inline] 2981 fn handle_destroy( 2982 &mut self, 2983 window: Window, 2984 ) { 2985 debug!("DESTROY for window {:#0x}", window); 2986 2987 let screen = self.active_screen(); 2988 2989 if screen.has_strut_window(window) { 2990 screen.remove_window_strut(window); 2991 screen.compute_placeable_region(); 2992 2993 let workspace = self.active_workspace(); 2994 self.apply_layout(workspace); 2995 self.apply_stack(workspace); 2996 } 2997 2998 self.unmanaged_windows.borrow_mut().remove(&window); 2999 self.remove_window(window); 3000 } 3001 3002 #[inline] 3003 fn handle_expose( 3004 &self, 3005 _window: Window, 3006 ) { 3007 } 3008 3009 #[inline] 3010 fn handle_unmap( 3011 &mut self, 3012 window: Window, 3013 _ignore: bool, 3014 ) { 3015 debug!("UNMAP for window {:#0x}", window); 3016 3017 if self.unmanaged_windows.borrow().contains(&window) { 3018 return; 3019 } 3020 3021 self.handle_destroy(window); 3022 } 3023 3024 #[inline] 3025 fn handle_configure( 3026 &mut self, 3027 window: Window, 3028 _region: Region, 3029 on_root: bool, 3030 ) { 3031 if on_root { 3032 debug!("CONFIGURE for window {:#0x}", window); 3033 self.acquire_partitions(); 3034 } 3035 } 3036 3037 #[inline] 3038 fn handle_state_request( 3039 &self, 3040 window: Window, 3041 state: WindowState, 3042 action: ToggleAction, 3043 on_root: bool, 3044 ) { 3045 let client = match self.client_any(window) { 3046 Some(client) => client, 3047 _ => return, 3048 }; 3049 3050 debug!( 3051 "STATE_REQUEST for window {:#0x}, with state {:?} and action {:?}", 3052 window, state, action 3053 ); 3054 3055 match action { 3056 ToggleAction::Add => match state { 3057 WindowState::Fullscreen => self.fullscreen(client), 3058 WindowState::Sticky => self.stick(client), 3059 WindowState::DemandsAttention => { 3060 self.conn.set_icccm_window_hints(window, Hints { 3061 urgent: true, 3062 input: None, 3063 initial_state: None, 3064 group: None, 3065 }); 3066 3067 if let Some(client) = self.client_any(window) { 3068 client.set_urgent(Toggle::On); 3069 self.render_decoration(client); 3070 } 3071 }, 3072 _ => {}, 3073 }, 3074 ToggleAction::Remove => match state { 3075 WindowState::Fullscreen => self.unfullscreen(client), 3076 WindowState::Sticky => self.unstick(client), 3077 WindowState::DemandsAttention => { 3078 self.conn.set_icccm_window_hints(window, Hints { 3079 urgent: false, 3080 input: None, 3081 initial_state: None, 3082 group: None, 3083 }); 3084 3085 if let Some(client) = self.client_any(window) { 3086 client.set_urgent(Toggle::Off); 3087 self.render_decoration(client); 3088 } 3089 }, 3090 _ => {}, 3091 }, 3092 ToggleAction::Toggle => { 3093 let is_fullscreen = client.is_fullscreen(); 3094 3095 self.handle_state_request( 3096 window, 3097 state, 3098 if is_fullscreen { 3099 ToggleAction::Remove 3100 } else { 3101 ToggleAction::Add 3102 }, 3103 on_root, 3104 ); 3105 }, 3106 } 3107 } 3108 3109 #[inline] 3110 fn handle_focus_request( 3111 &self, 3112 window: Window, 3113 on_root: bool, 3114 ) { 3115 debug!("FOCUS_REQUEST for window {:#0x}", window); 3116 3117 if !on_root { 3118 self.focus_window(window); 3119 } 3120 } 3121 3122 #[inline] 3123 fn handle_close_request( 3124 &self, 3125 window: Window, 3126 on_root: bool, 3127 ) { 3128 debug!("CLOSE_REQUEST for window {:#0x}", window); 3129 3130 if !on_root { 3131 self.conn.kill_window(window); 3132 } 3133 } 3134 3135 #[inline] 3136 fn handle_workspace_request( 3137 &self, 3138 window: Option<Window>, 3139 index: usize, 3140 on_root: bool, 3141 ) { 3142 debug!( 3143 "WORKSPACE_REQUEST for workspace {} by window {:?}", 3144 index, 3145 window.map(|window| format!("{:#0x}", window)) 3146 ); 3147 3148 if on_root { 3149 self.activate_workspace(index); 3150 } 3151 } 3152 3153 #[inline] 3154 fn handle_placement_request( 3155 &self, 3156 window: Window, 3157 pos: Option<Pos>, 3158 dim: Option<Dim>, 3159 _on_root: bool, 3160 ) { 3161 if pos.is_none() && dim.is_none() { 3162 return; 3163 } 3164 3165 debug!( 3166 "PLACEMENT_REQUEST for window {:#0x} with pos {:?} and dim {:?}", 3167 window, pos, dim 3168 ); 3169 3170 let client = match self.client(window) { 3171 Some(client) if self.is_free(client) => client, 3172 None => { 3173 if let Ok(mut geometry) = self.conn.get_window_geometry(window) { 3174 if let Some(pos) = pos { 3175 geometry.pos = pos; 3176 } 3177 3178 if let Some(dim) = dim { 3179 geometry.dim = dim; 3180 } 3181 3182 self.conn.place_window(window, &geometry); 3183 } 3184 3185 return; 3186 }, 3187 _ => return, 3188 }; 3189 3190 let extents = client.frame_extents(); 3191 let mut region = if window == client.window() { 3192 Region { 3193 pos: if let Some(pos) = pos { 3194 Pos { 3195 x: pos.x - extents.left, 3196 y: pos.y - extents.top, 3197 } 3198 } else { 3199 client.free_region().pos 3200 }, 3201 dim: if let Some(dim) = dim { 3202 Dim { 3203 w: dim.w + extents.left + extents.right, 3204 h: dim.h + extents.top + extents.bottom, 3205 } 3206 } else { 3207 client.free_region().dim 3208 }, 3209 } 3210 } else { 3211 Region { 3212 pos: pos.unwrap_or(client.free_region().pos), 3213 dim: dim.unwrap_or(client.free_region().dim), 3214 } 3215 }; 3216 3217 region = region 3218 .without_extents(extents) 3219 .with_size_hints(&client.size_hints()) 3220 .with_minimum_dim(&Client::MIN_CLIENT_DIM) 3221 .with_extents(extents); 3222 3223 client.set_region(PlacementClass::Free(region)); 3224 3225 let placement = Placement { 3226 method: PlacementMethod::Free, 3227 kind: PlacementTarget::Client(window), 3228 zone: client.zone(), 3229 region: PlacementRegion::FreeRegion, 3230 decoration: client.decoration(), 3231 }; 3232 3233 self.update_client_placement(client, &placement); 3234 self.place_client(client, placement.method); 3235 } 3236 3237 #[inline] 3238 fn handle_grip_request( 3239 &self, 3240 window: Window, 3241 pos: Pos, 3242 grip: Option<Grip>, 3243 _on_root: bool, 3244 ) { 3245 debug!( 3246 "GRIP_REQUEST for window {:#0x} with pos {:?} and grip {:?}", 3247 window, pos, grip 3248 ); 3249 3250 if let Some(grip) = grip { 3251 self.move_buffer.unset(); 3252 self.resize_buffer.unset(); 3253 3254 if let Some(client) = self.client(window) { 3255 self.resize_buffer.set( 3256 client.window(), 3257 grip, 3258 self.conn.get_pointer_position(), 3259 client.free_region(), 3260 ); 3261 3262 self.conn.confine_pointer(self.resize_buffer.handle()); 3263 } 3264 } else { 3265 self.start_moving(window); 3266 } 3267 } 3268 3269 #[inline] 3270 fn handle_restack_request( 3271 &mut self, 3272 window: Window, 3273 sibling: Window, 3274 mode: StackMode, 3275 _on_root: bool, 3276 ) { 3277 debug!( 3278 "RESTACK_REQUEST for window {:#0x} with sibling {:?} and mode {:?}", 3279 window, sibling, mode 3280 ); 3281 3282 match mode { 3283 StackMode::Above => self.stack_manager.add_above_other(window, sibling), 3284 StackMode::Below => self.stack_manager.add_below_other(window, sibling), 3285 } 3286 3287 self.apply_stack(self.active_workspace()); 3288 } 3289 3290 #[inline] 3291 fn handle_property( 3292 &self, 3293 window: Window, 3294 kind: PropertyKind, 3295 _on_root: bool, 3296 ) { 3297 debug!("PROPERTY for window {:#0x} of kind {:?}", window, kind); 3298 3299 match kind { 3300 PropertyKind::Name => { 3301 if let Some(client) = self.client_any(window) { 3302 client.set_name(self.conn.get_icccm_window_name(window)); 3303 } 3304 }, 3305 PropertyKind::Class => { 3306 if let Some(client) = self.client_any(window) { 3307 client.set_class(self.conn.get_icccm_window_class(window)); 3308 client.set_instance(self.conn.get_icccm_window_instance(window)); 3309 } 3310 }, 3311 PropertyKind::Size => { 3312 if let Some(client) = self.client_any(window) { 3313 let window = client.window(); 3314 3315 let size_hints = self 3316 .conn 3317 .get_icccm_window_size_hints( 3318 window, 3319 Some(Client::MIN_CLIENT_DIM), 3320 &client.size_hints(), 3321 ) 3322 .1; 3323 3324 let mut geometry = match self.conn.get_window_geometry(window) { 3325 Ok(geometry) => geometry, 3326 Err(_) => return, 3327 } 3328 .with_size_hints(&size_hints) 3329 .with_minimum_dim(&Client::MIN_CLIENT_DIM); 3330 3331 let extents = client.frame_extents(); 3332 geometry.pos = client.free_region().pos; 3333 geometry.dim.w += extents.left + extents.right; 3334 geometry.dim.h += extents.top + extents.bottom; 3335 3336 client.set_size_hints(size_hints); 3337 client.set_region(PlacementClass::Free(geometry)); 3338 3339 if client.is_managed() { 3340 let workspace = client.workspace(); 3341 self.apply_layout(workspace); 3342 self.apply_stack(workspace); 3343 } 3344 } 3345 }, 3346 PropertyKind::Strut => { 3347 if let Some(struts) = self.conn.get_window_strut(window) { 3348 let screen = self.active_screen(); 3349 screen.remove_window_strut(window); 3350 screen.add_struts(struts); 3351 screen.compute_placeable_region(); 3352 3353 let workspace = self.active_workspace(); 3354 self.apply_layout(workspace); 3355 self.apply_stack(workspace); 3356 } 3357 }, 3358 } 3359 } 3360 3361 #[inline] 3362 fn handle_frame_extents_request( 3363 &self, 3364 window: Window, 3365 _on_root: bool, 3366 ) { 3367 debug!("FRAME_EXTENTS_REQUEST for window {:#0x}", window); 3368 3369 self.conn.set_window_frame_extents( 3370 window, 3371 if let Some(client) = self.client_any(window) { 3372 client.frame_extents() 3373 } else { 3374 Decoration::NO_DECORATION.extents() 3375 }, 3376 ); 3377 } 3378 3379 #[cold] 3380 fn handle_screen_change(&mut self) { 3381 debug!("SCREEN_CHANGE"); 3382 3383 self.acquire_partitions(); 3384 self.workspaces 3385 .activate_for(&Selector::AtIndex(self.active_screen().number())); 3386 } 3387 3388 #[cold] 3389 pub fn exit(&mut self) { 3390 info!("exit called, shutting down {}", WM_NAME!()); 3391 3392 (0..self.workspaces.len()).for_each(|workspace| { 3393 self.deiconify_all(workspace); 3394 }); 3395 3396 self.client_map.iter().for_each(|(&window, client)| { 3397 self.conn.unparent_window(window, client.free_region().pos); 3398 }); 3399 3400 self.conn.cleanup(); 3401 self.conn.flush(); 3402 3403 self.running = false; 3404 } 3405 }