Diff
diff --git a/src/client.zig b/src/client.zig
index c92c51d..0c47ed3 100644
--- a/src/client.zig
+++ b/src/client.zig
@@ -38,22 +38,19 @@ pub const Client = struct {
window: xlib.Window = 0,
};
-var allocator: std.mem.Allocator = undefined;
-
-pub fn init(alloc: std.mem.Allocator) void {
- allocator = alloc;
-}
-
-pub fn create(window: xlib.Window) ?*Client {
+/// Initialises a new `Client` for the given X window.
+pub fn create(allocator: std.mem.Allocator, window: xlib.Window) ?*Client {
const client = allocator.create(Client) catch return null;
client.* = Client{ .window = window };
return client;
}
-pub fn destroy(client: *Client) void {
+/// Frees a client previously returned by `create`.
+pub fn destroy(allocator: std.mem.Allocator, client: *Client) void {
allocator.destroy(client);
}
+/// Prepends `client` to the front of its monitor's client list.
pub fn attach(client: *Client) void {
if (client.monitor) |monitor| {
client.next = monitor.clients;
@@ -61,6 +58,7 @@ pub fn attach(client: *Client) void {
}
}
+/// Removes `client` from its monitor's client list.
pub fn detach(client: *Client) void {
if (client.monitor) |monitor| {
var current_ptr: *?*Client = &monitor.clients;
@@ -74,6 +72,7 @@ pub fn detach(client: *Client) void {
}
}
+/// Prepends `client` to the front of its monitor's focus stack.
pub fn attach_stack(client: *Client) void {
if (client.monitor) |monitor| {
client.stack_next = monitor.stack;
@@ -81,6 +80,7 @@ pub fn attach_stack(client: *Client) void {
}
}
+/// Removes `client` from its monitor's focus stack.
pub fn detach_stack(client: *Client) void {
if (client.monitor) |monitor| {
var current_ptr: *?*Client = &monitor.stack;
@@ -94,15 +94,15 @@ pub fn detach_stack(client: *Client) void {
}
}
-pub fn window_to_client(window: xlib.Window) ?*Client {
- const monitor_mod = @import("monitor.zig");
- var current_monitor = monitor_mod.monitors;
+/// Searches all monitors for a client whose X window matches `window`.
+///
+/// `monitors` is the head of the monitor linked list.
+pub fn window_to_client(monitors: ?*Monitor, window: xlib.Window) ?*Client {
+ var current_monitor = monitors;
while (current_monitor) |monitor| {
var current_client = monitor.clients;
while (current_client) |client| {
- if (client.window == window) {
- return client;
- }
+ if (client.window == window) return client;
current_client = client.next;
}
current_monitor = monitor.next;
@@ -110,17 +110,8 @@ pub fn window_to_client(window: xlib.Window) ?*Client {
return null;
}
-pub fn next_tiled(client: ?*Client) ?*Client {
- var current = client;
- while (current) |iter| {
- if (!iter.is_floating and is_visible(iter)) {
- return iter;
- }
- current = iter.next;
- }
- return null;
-}
-
+/// Returns true if `client` is visible on its monitor's currently selected
+/// tag set.
pub fn is_visible(client: *Client) bool {
if (client.monitor) |monitor| {
return (client.tags & monitor.tagset[monitor.sel_tags]) != 0;
@@ -128,22 +119,35 @@ pub fn is_visible(client: *Client) bool {
return false;
}
+/// Returns true if `client` is visible on the given tag bitmask.
pub fn is_visible_on_tag(client: *Client, tags: u32) bool {
return (client.tags & tags) != 0;
}
+/// Returns the first non-floating, visible client at or after `client`.
+pub fn next_tiled(client: ?*Client) ?*Client {
+ var current = client;
+ while (current) |iter| {
+ if (!iter.is_floating and is_visible(iter)) return iter;
+ current = iter.next;
+ }
+ return null;
+}
+
+/// Returns the first non-floating client on `client`'s monitor that shares
+/// any tag with `client`. Used for `attach_aside` ordering.
pub fn next_tagged(client: *Client) ?*Client {
const monitor = client.monitor orelse return null;
var walked = monitor.clients;
while (walked) |iter| {
- if (!iter.is_floating and is_visible_on_tag(iter, client.tags)) {
- return iter;
- }
+ if (!iter.is_floating and is_visible_on_tag(iter, client.tags)) return iter;
walked = iter.next;
}
return null;
}
+/// Inserts `client` just after the first client that shares its tags,
+/// falling back to prepend if none exists.
pub fn attach_aside(client: *Client) void {
const at = next_tagged(client);
if (at == null) {
@@ -154,6 +158,7 @@ pub fn attach_aside(client: *Client) void {
at.?.next = client;
}
+/// Counts non-floating, visible clients on `monitor`.
pub fn count_tiled(monitor: *Monitor) u32 {
var count: u32 = 0;
var current = next_tiled(monitor.clients);
@@ -164,19 +169,19 @@ pub fn count_tiled(monitor: *Monitor) u32 {
return count;
}
+/// Returns the tiled client on `monitor` whose bounds contain (`point_x`,
+/// `point_y`), excluding `exclude`. Returns null if none found.
pub fn tiled_window_at(exclude: *Client, monitor: *Monitor, point_x: i32, point_y: i32) ?*Client {
const tags = monitor.tagset[monitor.sel_tags];
var current = monitor.clients;
while (current) |client| {
if (client != exclude and !client.is_floating and (client.tags & tags) != 0) {
- const client_x = client.x;
- const client_y = client.y;
const client_w = client.width + client.border_width * 2;
const client_h = client.height + client.border_width * 2;
- if (point_x >= client_x and point_x < client_x + client_w and
- point_y >= client_y and point_y < client_y + client_h)
+ if (point_x >= client.x and point_x < client.x + client_w and
+ point_y >= client.y and point_y < client.y + client_h)
{
return client;
}
@@ -186,6 +191,8 @@ pub fn tiled_window_at(exclude: *Client, monitor: *Monitor, point_x: i32, point_
return null;
}
+/// Moves `client` to just before `target` in the monitor's client list.
+/// Does nothing if they are on different monitors.
pub fn insert_before(client: *Client, target: *Client) void {
const monitor = target.monitor orelse return;
if (client.monitor != monitor) return;
@@ -209,6 +216,8 @@ pub fn insert_before(client: *Client, target: *Client) void {
}
}
+/// Swaps the positions of `client_a` and `client_b` in their shared monitor's
+/// client list. Does nothing if they are on different monitors.
pub fn swap_clients(client_a: *Client, client_b: *Client) void {
const monitor = client_a.monitor orelse return;
if (client_b.monitor != monitor) return;
@@ -229,31 +238,15 @@ pub fn swap_clients(client_a: *Client, client_b: *Client) void {
if (next_a == client_b) {
client_a.next = next_b;
client_b.next = client_a;
- if (prev_a) |prev| {
- prev.next = client_b;
- } else {
- monitor.clients = client_b;
- }
+ if (prev_a) |prev| prev.next = client_b else monitor.clients = client_b;
} else if (next_b == client_a) {
client_b.next = next_a;
client_a.next = client_b;
- if (prev_b) |prev| {
- prev.next = client_a;
- } else {
- monitor.clients = client_a;
- }
+ if (prev_b) |prev| prev.next = client_a else monitor.clients = client_a;
} else {
client_a.next = next_b;
client_b.next = next_a;
- if (prev_a) |prev| {
- prev.next = client_b;
- } else {
- monitor.clients = client_b;
- }
- if (prev_b) |prev| {
- prev.next = client_a;
- } else {
- monitor.clients = client_a;
- }
+ if (prev_a) |prev| prev.next = client_b else monitor.clients = client_b;
+ if (prev_b) |prev| prev.next = client_a else monitor.clients = client_a;
}
}
diff --git a/src/main.zig b/src/main.zig
index d5811e1..faf0b6d 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -249,7 +249,6 @@ pub fn main() !void {
cursors = Cursors.init(&display);
_ = xlib.XDefineCursor(display.handle, display.root, cursors.normal);
- client_mod.init(allocator);
monitor_mod.init(allocator);
tiling.set_display(display.handle);
tiling.set_screen_size(display.screen_width(), display.screen_height());
@@ -697,7 +696,7 @@ fn handle_map_request(display: *Display, event: *xlib.XMapRequestEvent) void {
if (window_attributes.override_redirect != 0) {
return;
}
- if (client_mod.window_to_client(event.window) != null) {
+ if (client_mod.window_to_client(monitor_mod.monitors, event.window) != null) {
return;
}
@@ -705,7 +704,7 @@ fn handle_map_request(display: *Display, event: *xlib.XMapRequestEvent) void {
}
fn manage(display: *Display, win: xlib.Window, window_attrs: *xlib.XWindowAttributes) void {
- const client = client_mod.create(win) orelse return;
+ const client = client_mod.create(gpa.allocator(), win) orelse return;
var trans: xlib.Window = 0;
client.x = window_attrs.x;
@@ -722,7 +721,7 @@ fn manage(display: *Display, win: xlib.Window, window_attrs: *xlib.XWindowAttrib
update_title(display, client);
if (xlib.XGetTransientForHint(display.handle, win, &trans) != 0) {
- if (client_mod.window_to_client(trans)) |transient_client| {
+ if (client_mod.window_to_client(monitor_mod.monitors, trans)) |transient_client| {
client.monitor = transient_client.monitor;
client.tags = transient_client.tags;
}
@@ -790,7 +789,7 @@ fn manage(display: *Display, win: xlib.Window, window_attrs: *xlib.XWindowAttrib
}
fn handle_configure_request(display: *Display, event: *xlib.XConfigureRequestEvent) void {
- const client = client_mod.window_to_client(event.window);
+ const client = client_mod.window_to_client(monitor_mod.monitors, event.window);
if (client) |managed_client| {
if ((event.value_mask & xlib.c.CWBorderWidth) != 0) {
@@ -1816,7 +1815,7 @@ fn handle_button_press(display: *Display, event: *xlib.XButtonEvent) void {
return;
}
- const click_client = client_mod.window_to_client(event.window);
+ const click_client = client_mod.window_to_client(monitor_mod.monitors, event.window);
if (click_client) |found_client| {
focus(display, found_client);
if (monitor_mod.selected_monitor) |selmon| {
@@ -1848,7 +1847,7 @@ fn handle_button_press(display: *Display, event: *xlib.XButtonEvent) void {
}
fn handle_client_message(display: *Display, event: *xlib.XClientMessageEvent) void {
- const client = client_mod.window_to_client(event.window) orelse return;
+ const client = client_mod.window_to_client(monitor_mod.monitors, event.window) orelse return;
if (event.message_type == atoms.net_wm_state) {
const action = event.data.l[0];
@@ -1877,13 +1876,13 @@ fn handle_client_message(display: *Display, event: *xlib.XClientMessageEvent) vo
}
fn handle_destroy_notify(display: *Display, event: *xlib.XDestroyWindowEvent) void {
- const client = client_mod.window_to_client(event.window) orelse return;
+ const client = client_mod.window_to_client(monitor_mod.monitors, event.window) orelse return;
std.debug.print("destroy_notify: window=0x{x}\n", .{event.window});
unmanage(display, client);
}
fn handle_unmap_notify(display: *Display, event: *xlib.XUnmapEvent) void {
- const client = client_mod.window_to_client(event.window) orelse return;
+ const client = client_mod.window_to_client(monitor_mod.monitors, event.window) orelse return;
std.debug.print("unmap_notify: window=0x{x}\n", .{event.window});
unmanage(display, client);
}
@@ -1932,7 +1931,7 @@ fn unmanage(display: *Display, client: *Client) void {
}
}
- client_mod.destroy(client);
+ client_mod.destroy(gpa.allocator(), client);
update_client_list(display);
bar_mod.invalidate_bars();
}
@@ -1942,7 +1941,7 @@ fn handle_enter_notify(display: *Display, event: *xlib.XCrossingEvent) void {
return;
}
- const client = client_mod.window_to_client(event.window);
+ const client = client_mod.window_to_client(monitor_mod.monitors, event.window);
const target_mon = if (client) |c| c.monitor else monitor_mod.window_to_monitor(display.handle, display.root, event.window);
const selmon = monitor_mod.selected_monitor;
@@ -2001,12 +2000,12 @@ fn handle_property_notify(display: *Display, event: *xlib.XPropertyEvent) void {
return;
}
- const client = client_mod.window_to_client(event.window) orelse return;
+ const client = client_mod.window_to_client(monitor_mod.monitors, event.window) orelse return;
if (event.atom == xlib.XA_WM_TRANSIENT_FOR) {
var trans: xlib.Window = 0;
if (!client.is_floating and xlib.XGetTransientForHint(display.handle, client.window, &trans) != 0) {
- client.is_floating = client_mod.window_to_client(trans) != null;
+ client.is_floating = client_mod.window_to_client(monitor_mod.monitors, trans) != null;
if (client.is_floating) {
if (client.monitor) |monitor| {
arrange(monitor);