oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
6,834 bytes raw
1
const std = @import("std");
2
const xlib = @import("x11/xlib.zig");
3
const Monitor = @import("monitor.zig").Monitor;
4
5
pub const Client = struct {
6
    name: [256]u8 = std.mem.zeroes([256]u8),
7
    min_aspect: f32 = 0,
8
    max_aspect: f32 = 0,
9
    x: i32 = 0,
10
    y: i32 = 0,
11
    width: i32 = 0,
12
    height: i32 = 0,
13
    old_x: i32 = 0,
14
    old_y: i32 = 0,
15
    old_width: i32 = 0,
16
    old_height: i32 = 0,
17
    base_width: i32 = 0,
18
    base_height: i32 = 0,
19
    increment_width: i32 = 0,
20
    increment_height: i32 = 0,
21
    max_width: i32 = 0,
22
    max_height: i32 = 0,
23
    min_width: i32 = 0,
24
    min_height: i32 = 0,
25
    hints_valid: bool = false,
26
    border_width: i32 = 0,
27
    old_border_width: i32 = 0,
28
    tags: u32 = 0,
29
    is_fixed: bool = false,
30
    is_floating: bool = false,
31
    is_urgent: bool = false,
32
    never_focus: bool = false,
33
    old_state: bool = false,
34
    is_fullscreen: bool = false,
35
    next: ?*Client = null,
36
    stack_next: ?*Client = null,
37
    monitor: ?*Monitor = null,
38
    window: xlib.Window = 0,
39
};
40
41
var allocator: std.mem.Allocator = undefined;
42
43
pub fn init(alloc: std.mem.Allocator) void {
44
    allocator = alloc;
45
}
46
47
pub fn create(window: xlib.Window) ?*Client {
48
    const client = allocator.create(Client) catch return null;
49
    client.* = Client{ .window = window };
50
    return client;
51
}
52
53
pub fn destroy(client: *Client) void {
54
    allocator.destroy(client);
55
}
56
57
pub fn attach(client: *Client) void {
58
    if (client.monitor) |monitor| {
59
        client.next = monitor.clients;
60
        monitor.clients = client;
61
    }
62
}
63
64
pub fn detach(client: *Client) void {
65
    if (client.monitor) |monitor| {
66
        var current_ptr: *?*Client = &monitor.clients;
67
        while (current_ptr.*) |current| {
68
            if (current == client) {
69
                current_ptr.* = client.next;
70
                return;
71
            }
72
            current_ptr = &current.next;
73
        }
74
    }
75
}
76
77
pub fn attach_stack(client: *Client) void {
78
    if (client.monitor) |monitor| {
79
        client.stack_next = monitor.stack;
80
        monitor.stack = client;
81
    }
82
}
83
84
pub fn detach_stack(client: *Client) void {
85
    if (client.monitor) |monitor| {
86
        var current_ptr: *?*Client = &monitor.stack;
87
        while (current_ptr.*) |current| {
88
            if (current == client) {
89
                current_ptr.* = client.stack_next;
90
                return;
91
            }
92
            current_ptr = &current.stack_next;
93
        }
94
    }
95
}
96
97
pub fn window_to_client(window: xlib.Window) ?*Client {
98
    const monitor_mod = @import("monitor.zig");
99
    var current_monitor = monitor_mod.monitors;
100
    while (current_monitor) |monitor| {
101
        var current_client = monitor.clients;
102
        while (current_client) |client| {
103
            if (client.window == window) {
104
                return client;
105
            }
106
            current_client = client.next;
107
        }
108
        current_monitor = monitor.next;
109
    }
110
    return null;
111
}
112
113
pub fn next_tiled(client: ?*Client) ?*Client {
114
    var current = client;
115
    while (current) |iter| {
116
        if (!iter.is_floating and is_visible(iter)) {
117
            return iter;
118
        }
119
        current = iter.next;
120
    }
121
    return null;
122
}
123
124
pub fn is_visible(client: *Client) bool {
125
    if (client.monitor) |monitor| {
126
        return (client.tags & monitor.tagset[monitor.sel_tags]) != 0;
127
    }
128
    return false;
129
}
130
131
pub fn is_visible_on_tag(client: *Client, tags: u32) bool {
132
    return (client.tags & tags) != 0;
133
}
134
135
pub fn next_tagged(client: *Client) ?*Client {
136
    const monitor = client.monitor orelse return null;
137
    var walked = monitor.clients;
138
    while (walked) |iter| {
139
        if (!iter.is_floating and is_visible_on_tag(iter, client.tags)) {
140
            return iter;
141
        }
142
        walked = iter.next;
143
    }
144
    return null;
145
}
146
147
pub fn attach_aside(client: *Client) void {
148
    const at = next_tagged(client);
149
    if (at == null) {
150
        attach(client);
151
        return;
152
    }
153
    client.next = at.?.next;
154
    at.?.next = client;
155
}
156
157
pub fn count_tiled(monitor: *Monitor) u32 {
158
    var count: u32 = 0;
159
    var current = next_tiled(monitor.clients);
160
    while (current) |client| {
161
        count += 1;
162
        current = next_tiled(client.next);
163
    }
164
    return count;
165
}
166
167
pub fn tiled_window_at(exclude: *Client, monitor: *Monitor, point_x: i32, point_y: i32) ?*Client {
168
    const tags = monitor.tagset[monitor.sel_tags];
169
    var current = monitor.clients;
170
171
    while (current) |client| {
172
        if (client != exclude and !client.is_floating and (client.tags & tags) != 0) {
173
            const client_x = client.x;
174
            const client_y = client.y;
175
            const client_w = client.width + client.border_width * 2;
176
            const client_h = client.height + client.border_width * 2;
177
178
            if (point_x >= client_x and point_x < client_x + client_w and
179
                point_y >= client_y and point_y < client_y + client_h)
180
            {
181
                return client;
182
            }
183
        }
184
        current = client.next;
185
    }
186
    return null;
187
}
188
189
pub fn insert_before(client: *Client, target: *Client) void {
190
    const monitor = target.monitor orelse return;
191
    if (client.monitor != monitor) return;
192
193
    detach(client);
194
195
    if (monitor.clients == target) {
196
        client.next = target;
197
        monitor.clients = client;
198
        return;
199
    }
200
201
    var current = monitor.clients;
202
    while (current) |iter| {
203
        if (iter.next == target) {
204
            client.next = target;
205
            iter.next = client;
206
            return;
207
        }
208
        current = iter.next;
209
    }
210
}
211
212
pub fn swap_clients(client_a: *Client, client_b: *Client) void {
213
    const monitor = client_a.monitor orelse return;
214
    if (client_b.monitor != monitor) return;
215
216
    var prev_a: ?*Client = null;
217
    var prev_b: ?*Client = null;
218
    var iter = monitor.clients;
219
220
    while (iter) |client| {
221
        if (client.next == client_a) prev_a = client;
222
        if (client.next == client_b) prev_b = client;
223
        iter = client.next;
224
    }
225
226
    const next_a = client_a.next;
227
    const next_b = client_b.next;
228
229
    if (next_a == client_b) {
230
        client_a.next = next_b;
231
        client_b.next = client_a;
232
        if (prev_a) |prev| {
233
            prev.next = client_b;
234
        } else {
235
            monitor.clients = client_b;
236
        }
237
    } else if (next_b == client_a) {
238
        client_b.next = next_a;
239
        client_a.next = client_b;
240
        if (prev_b) |prev| {
241
            prev.next = client_a;
242
        } else {
243
            monitor.clients = client_a;
244
        }
245
    } else {
246
        client_a.next = next_b;
247
        client_b.next = next_a;
248
        if (prev_a) |prev| {
249
            prev.next = client_b;
250
        } else {
251
            monitor.clients = client_b;
252
        }
253
        if (prev_b) |prev| {
254
            prev.next = client_a;
255
        } else {
256
            monitor.clients = client_a;
257
        }
258
    }
259
}