Diff
diff --git a/resources/test-config.lua b/resources/test-config.lua
index d094520..0ff7764 100644
--- a/resources/test-config.lua
+++ b/resources/test-config.lua
@@ -33,6 +33,7 @@ local modkey = "Mod1"
oxwm.set_terminal("st")
oxwm.set_modkey(modkey)
oxwm.set_tags({ "1", "2", "3", "4", "5", "6", "7", "8", "9" })
+oxwm.auto_tile(true);
oxwm.set_layout_symbol("tiling", "[T]")
oxwm.set_layout_symbol("normie", "[F]")
@@ -42,7 +43,7 @@ oxwm.border.set_focused_color(colors.blue)
oxwm.border.set_unfocused_color(colors.grey)
oxwm.gaps.set_enabled(true)
-oxwm.gaps.set_smart(true) -- Disable outer gaps when only 1 window (dwm smartgaps)
+oxwm.gaps.set_smart(true) -- Disable outer gaps when only 1 window (dwm smartgaps)
oxwm.gaps.set_inner(5, 5)
oxwm.gaps.set_outer(5, 5)
@@ -78,16 +79,16 @@ oxwm.key.bind({ modkey }, "N", oxwm.layout.cycle())
oxwm.key.bind({ modkey }, "A", oxwm.toggle_gaps())
-- Master area controls
-oxwm.key.bind({ modkey }, "BracketLeft", oxwm.set_master_factor(-5)) -- Decrease master area
-oxwm.key.bind({ modkey }, "BracketRight", oxwm.set_master_factor(5)) -- Increase master area
-oxwm.key.bind({ modkey }, "I", oxwm.inc_num_master(1)) -- More master windows
-oxwm.key.bind({ modkey }, "P", oxwm.inc_num_master(-1)) -- Fewer master windows
+oxwm.key.bind({ modkey }, "BracketLeft", oxwm.set_master_factor(-5)) -- Decrease master area
+oxwm.key.bind({ modkey }, "BracketRight", oxwm.set_master_factor(5)) -- Increase master area
+oxwm.key.bind({ modkey }, "I", oxwm.inc_num_master(1)) -- More master windows
+oxwm.key.bind({ modkey }, "P", oxwm.inc_num_master(-1)) -- Fewer master windows
-- Multi-monitor controls (dwm-style)
-oxwm.key.bind({ modkey }, "Comma", oxwm.monitor.focus(-1)) -- Focus previous monitor
-oxwm.key.bind({ modkey }, "Period", oxwm.monitor.focus(1)) -- Focus next monitor
-oxwm.key.bind({ modkey, "Shift" }, "Comma", oxwm.monitor.tag(-1)) -- Send window to previous monitor
-oxwm.key.bind({ modkey, "Shift" }, "Period", oxwm.monitor.tag(1)) -- Send window to next monitor
+oxwm.key.bind({ modkey }, "Comma", oxwm.monitor.focus(-1)) -- Focus previous monitor
+oxwm.key.bind({ modkey }, "Period", oxwm.monitor.focus(1)) -- Focus next monitor
+oxwm.key.bind({ modkey, "Shift" }, "Comma", oxwm.monitor.tag(-1)) -- Send window to previous monitor
+oxwm.key.bind({ modkey, "Shift" }, "Period", oxwm.monitor.tag(1)) -- Send window to next monitor
oxwm.key.bind({ modkey, "Shift" }, "Q", oxwm.quit())
oxwm.key.bind({ modkey, "Shift" }, "R", oxwm.restart())
diff --git a/src/config/lua.rs b/src/config/lua.rs
index b819702..e651a83 100644
--- a/src/config/lua.rs
+++ b/src/config/lua.rs
@@ -48,5 +48,6 @@ pub fn parse_lua_config(
scheme_occupied: builder_data.scheme_occupied,
scheme_selected: builder_data.scheme_selected,
autostart: builder_data.autostart,
+ auto_tile: builder_data.auto_tile,
});
}
diff --git a/src/config/lua_api.rs b/src/config/lua_api.rs
index e6190fa..cae6189 100644
--- a/src/config/lua_api.rs
+++ b/src/config/lua_api.rs
@@ -32,6 +32,7 @@ pub struct ConfigBuilder {
pub scheme_occupied: ColorScheme,
pub scheme_selected: ColorScheme,
pub autostart: Vec<String>,
+ pub auto_tile: bool,
}
impl Default for ConfigBuilder {
@@ -70,6 +71,7 @@ impl Default for ConfigBuilder {
underline: 0x444444,
},
autostart: Vec::new(),
+ auto_tile: false,
}
}
}
@@ -738,6 +740,12 @@ fn register_misc(lua: &Lua, parent: &Table, builder: SharedBuilder) -> Result<()
Ok(())
})?;
+ let builder_clone = builder.clone();
+ let auto_tile = lua.create_function(move |_, enabled: bool| {
+ builder_clone.borrow_mut().auto_tile = enabled;
+ Ok(())
+ })?;
+
parent.set("set_terminal", set_terminal)?;
parent.set("set_modkey", set_modkey)?;
parent.set("set_tags", set_tags)?;
@@ -750,6 +758,7 @@ fn register_misc(lua: &Lua, parent: &Table, builder: SharedBuilder) -> Result<()
parent.set("inc_num_master", inc_num_master)?;
parent.set("show_keybinds", show_keybinds)?;
parent.set("focus_monitor", focus_monitor)?;
+ parent.set("auto_tile", auto_tile)?;
Ok(())
}
diff --git a/src/lib.rs b/src/lib.rs
index 4621da7..e2cd37d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -94,8 +94,8 @@ pub struct Config {
pub scheme_occupied: ColorScheme,
pub scheme_selected: ColorScheme,
- // Autostart commands
pub autostart: Vec<String>,
+ pub auto_tile: bool,
}
#[derive(Debug, Clone, Copy)]
@@ -338,6 +338,7 @@ impl Default for Config {
underline: 0xad8ee6,
},
autostart: vec![],
+ auto_tile: false,
}
}
}
diff --git a/src/window_manager.rs b/src/window_manager.rs
index 765810b..294deda 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -2535,9 +2535,92 @@ impl WindowManager {
}
}
+ if self.config.auto_tile && !was_floating && !is_normie {
+ let drop_monitor_idx = self
+ .clients
+ .get(&window)
+ .map(|c| c.monitor_index)
+ .unwrap_or(monitor_idx);
+
+ if let Some((x, y, w, h)) = final_client {
+ let center = (x as i32 + w as i32 / 2, y as i32 + h as i32 / 2);
+ if let Some(target) = self.tiled_window_at(window, drop_monitor_idx, center) {
+ self.detach(window);
+ self.insert_before(window, target, drop_monitor_idx);
+ }
+ }
+
+ self.floating_windows.remove(&window);
+ if let Some(client) = self.clients.get_mut(&window) {
+ client.is_floating = false;
+ }
+ self.apply_layout()?;
+ }
+
Ok(())
}
+ fn tiled_window_at(
+ &self,
+ exclude: Window,
+ monitor_idx: usize,
+ (px, py): (i32, i32),
+ ) -> Option<Window> {
+ let monitor = self.monitors.get(monitor_idx)?;
+ let tags = monitor.tagset[monitor.selected_tags_index];
+ let mut current = monitor.clients_head;
+
+ while let Some(win) = current {
+ let c = self.clients.get(&win)?;
+ current = c.next;
+
+ if win == exclude || c.is_floating || (c.tags & tags) == 0 {
+ continue;
+ }
+
+ let (x, y) = (c.x_position as i32, c.y_position as i32);
+ let (w, h) = (
+ c.width as i32 + c.border_width as i32 * 2,
+ c.height as i32 + c.border_width as i32 * 2,
+ );
+
+ if px >= x && px < x + w && py >= y && py < y + h {
+ return Some(win);
+ }
+ }
+ None
+ }
+
+ fn insert_before(&mut self, window: Window, target: Window, monitor_idx: usize) {
+ let Some(monitor) = self.monitors.get_mut(monitor_idx) else {
+ return;
+ };
+
+ if monitor.clients_head == Some(target) {
+ if let Some(c) = self.clients.get_mut(&window) {
+ c.next = Some(target);
+ }
+ monitor.clients_head = Some(window);
+ return;
+ }
+
+ let mut current = monitor.clients_head;
+ while let Some(w) = current {
+ let Some(c) = self.clients.get(&w) else { break };
+ if c.next != Some(target) {
+ current = c.next;
+ continue;
+ }
+ if let Some(prev) = self.clients.get_mut(&w) {
+ prev.next = Some(window);
+ }
+ if let Some(inserted) = self.clients.get_mut(&window) {
+ inserted.next = Some(target);
+ }
+ break;
+ }
+ }
+
fn resize_window_with_mouse(&mut self, window: Window) -> WmResult<()> {
let is_fullscreen = self
.clients
@@ -2574,12 +2657,32 @@ impl WindowManager {
return Ok(());
};
- if self.monitors.get(monitor_idx).is_none() {
- return Ok(());
- }
+ let monitor = match self.monitors.get(monitor_idx) {
+ Some(m) => m,
+ None => return Ok(()),
+ };
let is_normie = self.layout.name() == "normie";
+ if self.config.auto_tile && !was_floating && !is_normie {
+ let mut tiled_count = 0;
+ let mut current = monitor.clients_head;
+ while let Some(w) = current {
+ if let Some(c) = self.clients.get(&w) {
+ let visible = (c.tags & monitor.tagset[monitor.selected_tags_index]) != 0;
+ if visible && !c.is_floating {
+ tiled_count += 1;
+ }
+ current = c.next;
+ } else {
+ break;
+ }
+ }
+ if tiled_count <= 1 {
+ return Ok(());
+ }
+ }
+
if !was_floating && !is_normie {
self.toggle_floating()?;
}
@@ -2698,6 +2801,14 @@ impl WindowManager {
}
}
+ if self.config.auto_tile && !was_floating && !is_normie {
+ self.floating_windows.remove(&window);
+ if let Some(client) = self.clients.get_mut(&window) {
+ client.is_floating = false;
+ }
+ self.apply_layout()?;
+ }
+
Ok(())
}
diff --git a/templates/oxwm.lua b/templates/oxwm.lua
index 45239a8..e2e724a 100644
--- a/templates/oxwm.lua
+++ b/templates/oxwm.lua
@@ -37,6 +37,10 @@ function oxwm.set_modkey(modkey) end
---@param tags string[] Array of tag names
function oxwm.set_tags(tags) end
+---Enable or disable automatic tiling of new windows
+---@param enabled boolean Enable or disable auto-tiling
+function oxwm.auto_tile(enabled) end
+
---Set layout symbol override
---@param name string Layout name (e.g., "tiling", "normie", "tabbed", "grid", "monocle")
---@param symbol string Symbol to display (e.g., "[T]", "[F]", "[=]")