wzrd

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in Rust
git clone git://git.deurzen.net/wzrd
Log | Files | Refs | LICENSE

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 }