oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git

Fixed merge conflicts.;

Commit
1ee9ed195ff6e32d60ce25a1f07161b1f6de2aee
Parents
5db5675 45257ca
Author
tonybtw <tonybtw@tonybtw.com>
Date
2026-01-11 04:39:19

Diff

diff --cc src/monitor.rs
index cae6f33,c87299c..caa18ad
--- a/src/monitor.rs
+++ b/src/monitor.rs
@@@ -6,6 -6,30 +6,36 @@@ use x11rb::rust_connection::RustConnect
  
  type WmResult<T> = Result<T, WmError>;
  
+ #[derive(Debug, Clone)]
+ pub struct Pertag {
+     pub current_tag: usize,
+     pub previous_tag: usize,
+     pub num_masters: Vec<i32>,
+     pub master_factors: Vec<f32>,
+     pub layouts: Vec<String>,
+     pub show_bars: Vec<bool>,
+ }
+ 
+ impl Pertag {
 -    pub fn new(num_tags: usize, default_num_master: i32, default_master_factor: f32, default_show_bar: bool, default_layout: &str) -> Self {
++    pub fn new(
++        num_tags: usize,
++        default_num_master: i32,
++        default_master_factor: f32,
++        default_show_bar: bool,
++        default_layout: &str,
++    ) -> Self {
+         let len = num_tags + 1;
+         Self {
+             current_tag: 1,
+             previous_tag: 1,
+             num_masters: vec![default_num_master; len],
+             master_factors: vec![default_master_factor; len],
+             layouts: vec![default_layout.to_string(); len],
+             show_bars: vec![default_show_bar; len],
+         }
+     }
+ }
+ 
  #[derive(Debug, Clone)]
  pub struct Monitor {
      pub layout_symbol: String,
@@@ -35,7 -59,7 +65,8 @@@
      pub stack_head: Option<Window>,
      pub bar_window: Option<Window>,
      pub layout_indices: [usize; 2],
 +    pub scroll_offset: i32,
+     pub pertag: Option<Pertag>,
  }
  
  impl Monitor {
@@@ -68,7 -92,7 +99,8 @@@
              stack_head: None,
              bar_window: None,
              layout_indices: [0, 1],
 +            scroll_offset: 0,
+             pertag: None,
          }
      }
  
diff --cc src/window_manager.rs
index 6c8a546,94180b4..26b9499
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@@ -1,8 -1,7 +1,8 @@@
  use crate::Config;
 +use crate::animations::{AnimationConfig, ScrollAnimation};
  use crate::bar::Bar;
  use crate::client::{Client, TagMask};
- use crate::errors::WmError;
+ use crate::errors::{ConfigError, WmError};
  use crate::keyboard::{self, Arg, KeyAction, handlers};
  use crate::layout::GapConfig;
  use crate::layout::tiling::TilingLayout;
@@@ -617,219 -733,21 +740,232 @@@ impl WindowManager 
          Ok(())
      }
  
 +    fn tick_animations(&mut self) -> WmResult<()> {
 +        if self.scroll_animation.is_active() {
 +            if let Some(new_offset) = self.scroll_animation.update() {
 +                if let Some(m) = self.monitors.get_mut(self.selected_monitor) {
 +                    m.scroll_offset = new_offset;
 +                }
 +                self.apply_layout()?;
 +                self.update_bar()?;
 +            }
 +        }
 +        Ok(())
 +    }
 +
 +    fn scroll_layout(&mut self, direction: i32) -> WmResult<()> {
 +        if self.layout.name() != "scrolling" {
 +            return Ok(());
 +        }
 +
 +        let monitor_index = self.selected_monitor;
 +        let monitor = match self.monitors.get(monitor_index) {
 +            Some(m) => m.clone(),
 +            None => return Ok(()),
 +        };
 +
 +        let visible_count = if monitor.num_master > 0 {
 +            monitor.num_master as usize
 +        } else {
 +            2
 +        };
 +
 +        let mut tiled_count = 0;
 +        let mut current = self.next_tiled(monitor.clients_head, &monitor);
 +        while let Some(window) = current {
 +            tiled_count += 1;
 +            if let Some(client) = self.clients.get(&window) {
 +                current = self.next_tiled(client.next, &monitor);
 +            } else {
 +                break;
 +            }
 +        }
 +
 +        if tiled_count <= visible_count {
 +            if let Some(m) = self.monitors.get_mut(monitor_index) {
 +                m.scroll_offset = 0;
 +            }
 +            return Ok(());
 +        }
 +
 +        let outer_gap = if self.gaps_enabled {
 +            self.config.gap_outer_vertical
 +        } else {
 +            0
 +        };
 +        let inner_gap = if self.gaps_enabled {
 +            self.config.gap_inner_vertical
 +        } else {
 +            0
 +        };
 +
 +        let available_width = monitor.screen_width - 2 * outer_gap as i32;
 +        let total_inner_gaps = inner_gap as i32 * (visible_count - 1) as i32;
 +        let window_width = (available_width - total_inner_gaps) / visible_count as i32;
 +        let scroll_amount = window_width + inner_gap as i32;
 +
 +        let total_width = tiled_count as i32 * window_width + (tiled_count - 1) as i32 * inner_gap as i32;
 +        let max_scroll = (total_width - available_width).max(0);
 +
 +        let current_offset = monitor.scroll_offset;
 +        let target_offset = if self.scroll_animation.is_active() {
 +            self.scroll_animation.target() + direction * scroll_amount
 +        } else {
 +            current_offset + direction * scroll_amount
 +        };
 +        let target_offset = target_offset.clamp(0, max_scroll);
 +
 +        self.scroll_animation.start(current_offset, target_offset, &self.animation_config);
 +
 +        Ok(())
 +    }
 +
 +    fn scroll_to_window(&mut self, target_window: Window, animate: bool) -> WmResult<()> {
 +        if self.layout.name() != "scrolling" {
 +            return Ok(());
 +        }
 +
 +        let monitor_index = self.selected_monitor;
 +        let monitor = match self.monitors.get(monitor_index) {
 +            Some(m) => m.clone(),
 +            None => return Ok(()),
 +        };
 +
 +        let visible_count = if monitor.num_master > 0 {
 +            monitor.num_master as usize
 +        } else {
 +            2
 +        };
 +
 +        let outer_gap = if self.gaps_enabled {
 +            self.config.gap_outer_vertical
 +        } else {
 +            0
 +        };
 +        let inner_gap = if self.gaps_enabled {
 +            self.config.gap_inner_vertical
 +        } else {
 +            0
 +        };
 +
 +        let mut tiled_windows = Vec::new();
 +        let mut current = self.next_tiled(monitor.clients_head, &monitor);
 +        while let Some(window) = current {
 +            tiled_windows.push(window);
 +            if let Some(client) = self.clients.get(&window) {
 +                current = self.next_tiled(client.next, &monitor);
 +            } else {
 +                break;
 +            }
 +        }
 +
 +        let target_idx = tiled_windows.iter().position(|&w| w == target_window);
 +        let target_idx = match target_idx {
 +            Some(idx) => idx,
 +            None => return Ok(()),
 +        };
 +
 +        let tiled_count = tiled_windows.len();
 +        if tiled_count <= visible_count {
 +            if let Some(m) = self.monitors.get_mut(monitor_index) {
 +                m.scroll_offset = 0;
 +            }
 +            return Ok(());
 +        }
 +
 +        let available_width = monitor.screen_width - 2 * outer_gap as i32;
 +        let total_inner_gaps = inner_gap as i32 * (visible_count - 1) as i32;
 +        let window_width = (available_width - total_inner_gaps) / visible_count as i32;
 +        let scroll_step = window_width + inner_gap as i32;
 +
 +        let total_width = tiled_count as i32 * window_width + (tiled_count - 1) as i32 * inner_gap as i32;
 +        let max_scroll = (total_width - available_width).max(0);
 +
 +        let target_scroll = (target_idx as i32) * scroll_step;
 +        let new_offset = target_scroll.clamp(0, max_scroll);
 +
 +        let current_offset = monitor.scroll_offset;
 +        if current_offset != new_offset {
 +            if animate {
 +                self.scroll_animation.start(current_offset, new_offset, &self.animation_config);
 +            } else {
 +                if let Some(m) = self.monitors.get_mut(monitor_index) {
 +                    m.scroll_offset = new_offset;
 +                }
 +            }
 +        }
 +
 +        Ok(())
 +    }
 +
+     fn toggle_bar(&mut self) -> WmResult<()> {
+         if let Some(monitor) = self.monitors.get_mut(self.selected_monitor) {
+             monitor.show_bar = !monitor.show_bar;
+             self.show_bar = monitor.show_bar;
+             if let Some(ref mut pertag) = monitor.pertag {
+                 pertag.show_bars[pertag.current_tag] = monitor.show_bar;
+             }
+         }
+         self.apply_layout()?;
+         self.update_bar()?;
+         Ok(())
+     }
+ 
      fn get_layout_symbol(&self) -> String {
          let layout_name = self.layout.name();
 +
 +        if layout_name == "scrolling" {
 +            if let Some(monitor) = self.monitors.get(self.selected_monitor) {
 +                let visible_count = if monitor.num_master > 0 {
 +                    monitor.num_master as usize
 +                } else {
 +                    2
 +                };
 +
 +                let mut tiled_count = 0;
 +                let mut current = self.next_tiled(monitor.clients_head, monitor);
 +                while let Some(window) = current {
 +                    tiled_count += 1;
 +                    if let Some(client) = self.clients.get(&window) {
 +                        current = self.next_tiled(client.next, monitor);
 +                    } else {
 +                        break;
 +                    }
 +                }
 +
 +                if tiled_count > 0 {
 +                    let outer_gap = if self.gaps_enabled {
 +                        self.config.gap_outer_vertical
 +                    } else {
 +                        0
 +                    };
 +                    let inner_gap = if self.gaps_enabled {
 +                        self.config.gap_inner_vertical
 +                    } else {
 +                        0
 +                    };
 +
 +                    let available_width = monitor.screen_width - 2 * outer_gap as i32;
 +                    let total_inner_gaps = inner_gap as i32 * (visible_count.min(tiled_count) - 1) as i32;
 +                    let window_width = if tiled_count <= visible_count {
 +                        (available_width - total_inner_gaps) / tiled_count as i32
 +                    } else {
 +                        (available_width - inner_gap as i32 * (visible_count - 1) as i32) / visible_count as i32
 +                    };
 +
 +                    let scroll_step = window_width + inner_gap as i32;
 +                    let first_visible = if scroll_step > 0 {
 +                        (monitor.scroll_offset / scroll_step) + 1
 +                    } else {
 +                        1
 +                    };
 +                    let last_visible = (first_visible + visible_count as i32 - 1).min(tiled_count as i32);
 +
 +                    return format!("[{}-{}/{}]", first_visible, last_visible, tiled_count);
 +                }
 +            }
 +        }
 +
          self.config
              .layout_symbols
              .iter()
@@@ -2204,26 -2067,9 +2299,26 @@@
          let final_tags = self.clients.get(&window).map(|c| c.tags).unwrap_or(tags);
          let _ = self.save_client_tag(window, final_tags);
  
 +        if client_monitor == self.selected_monitor
 +            && let Some(old_sel) = self
 +                .monitors
 +                .get(self.selected_monitor)
 +                .and_then(|m| m.selected_client)
 +        {
-             self.unfocus(old_sel)?;
++            self.unfocus(old_sel, false)?;
 +        }
 +
 +        if let Some(m) = self.monitors.get_mut(client_monitor) {
 +            m.selected_client = Some(window);
 +        }
 +
 +        if self.layout.name() == "scrolling" {
 +            self.scroll_to_window(window, false)?;
 +        }
 +
          self.apply_layout()?;
          self.connection.map_window(window)?;
-         self.focus(Some(window))?;
+         self.focus(None)?;
          self.update_bar()?;
  
          if self.layout.name() == "tabbed" {
@@@ -2460,11 -2403,7 +2652,12 @@@
          };
  
          self.focus(Some(next_window))?;
 +
 +        if self.layout.name() == "scrolling" {
 +            self.scroll_to_window(next_window, true)?;
 +        }
 +
+         self.restack()?;
          self.update_tab_bars()?;
  
          Ok(())