|
|
@@ -1,6 +1,7 @@
|
|
|
const std = @import("std");
|
|
|
const C = @import("c.zig");
|
|
|
const posix = std.posix;
|
|
|
+const bar_mod = @import("bar.zig");
|
|
|
|
|
|
const Client = struct {
|
|
|
name: [256]u8 = std.mem.zeroes([256]u8),
|
|
|
@@ -49,6 +50,8 @@ var nmaster: usize = 1;
|
|
|
const terminal = "st";
|
|
|
const launcher = "zmen";
|
|
|
const autostart = "/home/smi/.scripts/ewm.sh";
|
|
|
+const bar_font: [*:0]const u8 = "monospace:size=15";
|
|
|
+const delim = "::";
|
|
|
|
|
|
var cur_resize: C.Cursor = undefined;
|
|
|
var cur_move: C.Cursor = undefined;
|
|
|
@@ -163,7 +166,9 @@ fn restack() void {
|
|
|
_ = C.XSync(display, 0);
|
|
|
}
|
|
|
|
|
|
-fn initKeyMap(allocator: std.mem.Allocator) !std.AutoHashMap(c_uint, *const fn () void) {
|
|
|
+fn initKeyMap(
|
|
|
+ allocator: std.mem.Allocator,
|
|
|
+) !std.AutoHashMap(c_uint, *const fn () void) {
|
|
|
var map = std.AutoHashMap(c_uint, *const fn () void).init(allocator);
|
|
|
errdefer map.deinit();
|
|
|
for (keys) |key| {
|
|
|
@@ -187,7 +192,9 @@ fn grabInput(window: C.Window) void {
|
|
|
);
|
|
|
}
|
|
|
for ([_]u8{ 1, 3 }) |btn| {
|
|
|
- const mask = C.ButtonPressMask | C.ButtonReleaseMask | C.PointerMotionMask;
|
|
|
+ const mask = C.ButtonPressMask |
|
|
|
+ C.ButtonReleaseMask |
|
|
|
+ C.PointerMotionMask;
|
|
|
_ = C.XGrabButton(
|
|
|
display,
|
|
|
btn,
|
|
|
@@ -224,7 +231,11 @@ fn show(allocator: std.mem.Allocator) void {
|
|
|
|
|
|
client.border = BORDER;
|
|
|
_ = C.XSetErrorHandler(ignoreError);
|
|
|
- _ = C.XSelectInput(display, client.win, C.StructureNotifyMask | C.EnterWindowMask);
|
|
|
+ _ = C.XSelectInput(
|
|
|
+ display,
|
|
|
+ client.win,
|
|
|
+ C.StructureNotifyMask | C.EnterWindowMask,
|
|
|
+ );
|
|
|
_ = C.XSetWindowBorderWidth(display, client.win, BORDER);
|
|
|
_ = C.XSetWindowBorder(display, client.win, NORMAL_COL);
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
@@ -296,7 +307,14 @@ fn scan(allocator: std.mem.Allocator) void {
|
|
|
var children: [*c]C.Window = undefined;
|
|
|
var num_children: c_uint = 0;
|
|
|
|
|
|
- if (C.XQueryTree(display, root, &root_return, &parent_return, &children, &num_children) != 0) {
|
|
|
+ if (C.XQueryTree(
|
|
|
+ display,
|
|
|
+ root,
|
|
|
+ &root_return,
|
|
|
+ &parent_return,
|
|
|
+ &children,
|
|
|
+ &num_children,
|
|
|
+ ) != 0) {
|
|
|
if (num_children > 0) {
|
|
|
for (0..num_children) |i| {
|
|
|
const win = children[i];
|
|
|
@@ -307,8 +325,15 @@ fn scan(allocator: std.mem.Allocator) void {
|
|
|
const status = C.XGetWindowAttributes(display, win, &wa);
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
|
|
|
- if (status != 0 and wa.map_state == C.IsViewable and wa.override_redirect == 0) {
|
|
|
- _ = C.XSelectInput(display, win, C.StructureNotifyMask | C.EnterWindowMask);
|
|
|
+ if (status != 0 and
|
|
|
+ wa.map_state == C.IsViewable and
|
|
|
+ wa.override_redirect == 0)
|
|
|
+ {
|
|
|
+ _ = C.XSelectInput(
|
|
|
+ display,
|
|
|
+ win,
|
|
|
+ C.StructureNotifyMask | C.EnterWindowMask,
|
|
|
+ );
|
|
|
_ = C.XSetWindowBorderWidth(display, win, BORDER);
|
|
|
|
|
|
if (addClient(allocator, win)) |index| {
|
|
|
@@ -360,7 +385,12 @@ fn floatwins() void {
|
|
|
attachStack(focus_client.win) catch {};
|
|
|
|
|
|
_ = C.XSetErrorHandler(ignoreError);
|
|
|
- _ = C.XSetInputFocus(display, focus_client.win, C.RevertToParent, C.CurrentTime);
|
|
|
+ _ = C.XSetInputFocus(
|
|
|
+ display,
|
|
|
+ focus_client.win,
|
|
|
+ C.RevertToParent,
|
|
|
+ C.CurrentTime,
|
|
|
+ );
|
|
|
_ = C.XSetWindowBorder(display, focus_client.win, FOCUS_COL);
|
|
|
_ = C.XChangeProperty(
|
|
|
display,
|
|
|
@@ -379,7 +409,7 @@ fn floatwins() void {
|
|
|
}
|
|
|
|
|
|
inline fn toDim(v: c_int) c_uint {
|
|
|
- return @as(c_uint, @intCast(@max(0, v)));
|
|
|
+ return @intCast(@max(0, v));
|
|
|
}
|
|
|
|
|
|
fn tile() void {
|
|
|
@@ -395,6 +425,20 @@ fn tile() void {
|
|
|
|
|
|
const scr_w: c_int = @intCast(sw);
|
|
|
const scr_h: c_int = @intCast(sh);
|
|
|
+ const monitor_x: c_int = sx_offset;
|
|
|
+ const monitor_y: c_int = sy_offset;
|
|
|
+ var top_bar_offset: c_int = 0;
|
|
|
+ var bottom_bar_offset: c_int = 0;
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ const height = b_ptr.barH();
|
|
|
+ switch (b_ptr.pos) {
|
|
|
+ .top => top_bar_offset = height,
|
|
|
+ .bottom => bottom_bar_offset = height,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const layout_origin_y: c_int = monitor_y + top_bar_offset;
|
|
|
+ const available_h_total: c_int = scr_h - top_bar_offset - bottom_bar_offset;
|
|
|
+ if (available_h_total <= 0) return;
|
|
|
const border2: c_int = 2 * @as(c_int, BORDER);
|
|
|
const gap2: c_int = 2 * GAP;
|
|
|
const frame_w = border2 + gap2;
|
|
|
@@ -402,23 +446,36 @@ fn tile() void {
|
|
|
|
|
|
const used_mw = @min(nmaster, tilable);
|
|
|
const stack_n = tilable - used_mw;
|
|
|
- const base_mw = @as(c_int, @intFromFloat(@as(f32, @floatFromInt(scr_w)) * mfact));
|
|
|
+ const base_mw = @as(
|
|
|
+ c_int,
|
|
|
+ @intFromFloat(@as(f32, @floatFromInt(scr_w)) * mfact),
|
|
|
+ );
|
|
|
const master_w = if (stack_n == 0) scr_w else base_mw;
|
|
|
|
|
|
- const master_gap = @as(c_int, @intCast((used_mw + 1) * GAP));
|
|
|
+ const used_mw_ci: c_int = @intCast(used_mw);
|
|
|
+ const master_gap = (used_mw_ci + 1) * GAP;
|
|
|
+ const master_span = @max(available_h_total - frame_h, @as(c_int, 1));
|
|
|
const master_h = if (used_mw <= 1)
|
|
|
- scr_h - frame_h
|
|
|
+ master_span
|
|
|
else
|
|
|
- @divTrunc(scr_h - master_gap, @as(c_int, @intCast(used_mw)));
|
|
|
+ @divTrunc(
|
|
|
+ @max(available_h_total - master_gap, @as(c_int, 1)),
|
|
|
+ used_mw_ci,
|
|
|
+ );
|
|
|
|
|
|
+ const stack_n_ci: c_int = @intCast(stack_n);
|
|
|
const stack_gap = if (stack_n <= 1)
|
|
|
0
|
|
|
else
|
|
|
- @as(c_int, @intCast((stack_n + 1) * GAP));
|
|
|
+ (stack_n_ci + 1) * GAP;
|
|
|
+ const stack_span = @max(available_h_total - frame_h, @as(c_int, 1));
|
|
|
const stack_h = if (stack_n <= 1)
|
|
|
- scr_h - frame_h
|
|
|
+ stack_span
|
|
|
else
|
|
|
- @divTrunc(scr_h - stack_gap, @as(c_int, @intCast(stack_n)));
|
|
|
+ @divTrunc(
|
|
|
+ @max(available_h_total - stack_gap, @as(c_int, 1)),
|
|
|
+ stack_n_ci,
|
|
|
+ );
|
|
|
const stack_w = scr_w - master_w - GAP;
|
|
|
|
|
|
var master_idx: usize = 0;
|
|
|
@@ -429,10 +486,11 @@ fn tile() void {
|
|
|
const ptr = &cl.items[i];
|
|
|
|
|
|
if (master_idx < used_mw) {
|
|
|
+ const idx_offset: c_int = @intCast(master_idx);
|
|
|
const y = if (used_mw <= 1)
|
|
|
- GAP
|
|
|
+ layout_origin_y + GAP
|
|
|
else
|
|
|
- GAP + @as(c_int, @intCast(master_idx)) * (master_h + GAP);
|
|
|
+ layout_origin_y + GAP + idx_offset * (master_h + GAP);
|
|
|
const inner_w = master_w - frame_w;
|
|
|
const inner_h = if (used_mw <= 1)
|
|
|
master_h
|
|
|
@@ -442,7 +500,7 @@ fn tile() void {
|
|
|
_ = C.XMoveResizeWindow(
|
|
|
display,
|
|
|
ptr.win,
|
|
|
- GAP,
|
|
|
+ monitor_x + GAP,
|
|
|
y,
|
|
|
toDim(inner_w),
|
|
|
toDim(inner_h),
|
|
|
@@ -450,10 +508,11 @@ fn tile() void {
|
|
|
master_idx += 1;
|
|
|
} else {
|
|
|
const pos = stack_idx;
|
|
|
+ const pos_offset: c_int = @intCast(pos);
|
|
|
const y = if (stack_n <= 1)
|
|
|
- GAP
|
|
|
+ layout_origin_y + GAP
|
|
|
else
|
|
|
- GAP + @as(c_int, @intCast(pos)) * (stack_h + GAP);
|
|
|
+ layout_origin_y + GAP + pos_offset * (stack_h + GAP);
|
|
|
const inner_w = stack_w - GAP - border2;
|
|
|
const inner_h = if (stack_n <= 1)
|
|
|
stack_h
|
|
|
@@ -463,7 +522,7 @@ fn tile() void {
|
|
|
_ = C.XMoveResizeWindow(
|
|
|
display,
|
|
|
ptr.win,
|
|
|
- master_w + GAP,
|
|
|
+ monitor_x + master_w + GAP,
|
|
|
y,
|
|
|
toDim(inner_w),
|
|
|
toDim(inner_h),
|
|
|
@@ -519,14 +578,19 @@ fn isfloat(window: C.Window) bool {
|
|
|
var m_float = false;
|
|
|
|
|
|
if (class_hint.res_class != null) {
|
|
|
- const class_name = std.mem.span(@as([*:0]const u8, @ptrCast(class_hint.res_class)));
|
|
|
+ const class_name = std.mem.span(
|
|
|
+ @as([*:0]const u8, @ptrCast(class_hint.res_class)),
|
|
|
+ );
|
|
|
m_float = (std.mem.indexOf(u8, class_name, "Dialog") != null);
|
|
|
_ = C.XFree(class_hint.res_class);
|
|
|
}
|
|
|
|
|
|
if (class_hint.res_name != null) {
|
|
|
- const res_name = std.mem.span(@as([*:0]const u8, @ptrCast(class_hint.res_name)));
|
|
|
- m_float = m_float or (std.mem.indexOf(u8, res_name, "dialog") != null);
|
|
|
+ const res_name = std.mem.span(
|
|
|
+ @as([*:0]const u8, @ptrCast(class_hint.res_name)),
|
|
|
+ );
|
|
|
+ m_float = m_float or
|
|
|
+ (std.mem.indexOf(u8, res_name, "dialog") != null);
|
|
|
_ = C.XFree(class_hint.res_name);
|
|
|
}
|
|
|
|
|
|
@@ -565,14 +629,29 @@ fn isfloat(window: C.Window) bool {
|
|
|
actual_type == C.XA_ATOM and actual_format == 32 and nitems > 0;
|
|
|
|
|
|
if (got_atoms and good_format) {
|
|
|
- const atoms = @as([*]C.Atom, @alignCast(@ptrCast(prop_return)));
|
|
|
- const atom_dialog = C.XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
|
|
|
- const atom_utility = C.XInternAtom(display, "_NET_WM_WINDOW_TYPE_UTILITY", 0);
|
|
|
- const atom_popup = C.XInternAtom(display, "_NET_WM_WINDOW_TYPE_POPUP_MENU", 0);
|
|
|
+ const atoms = @as([*]C.Atom, @ptrCast(@alignCast(prop_return)));
|
|
|
+ const atom_dialog = C.XInternAtom(
|
|
|
+ display,
|
|
|
+ "_NET_WM_WINDOW_TYPE_DIALOG",
|
|
|
+ 0,
|
|
|
+ );
|
|
|
+ const atom_utility = C.XInternAtom(
|
|
|
+ display,
|
|
|
+ "_NET_WM_WINDOW_TYPE_UTILITY",
|
|
|
+ 0,
|
|
|
+ );
|
|
|
+ const atom_popup = C.XInternAtom(
|
|
|
+ display,
|
|
|
+ "_NET_WM_WINDOW_TYPE_POPUP_MENU",
|
|
|
+ 0,
|
|
|
+ );
|
|
|
|
|
|
for (0..nitems) |i| {
|
|
|
const atom = atoms[i];
|
|
|
- if (atom == atom_dialog or atom == atom_utility or atom == atom_popup) {
|
|
|
+ if (atom == atom_dialog or
|
|
|
+ atom == atom_utility or
|
|
|
+ atom == atom_popup)
|
|
|
+ {
|
|
|
_ = C.XFree(prop_return);
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
return true;
|
|
|
@@ -591,7 +670,13 @@ fn isfloat(window: C.Window) bool {
|
|
|
fn focus(target_index_opt: ?usize) void {
|
|
|
if (cl.items.len == 0) {
|
|
|
sel = null;
|
|
|
- _ = C.XSetInputFocus(display, root, C.RevertToPointerRoot, C.CurrentTime);
|
|
|
+ if (bar) |b_ptr| b_ptr.setSel(null);
|
|
|
+ _ = C.XSetInputFocus(
|
|
|
+ display,
|
|
|
+ root,
|
|
|
+ C.RevertToPointerRoot,
|
|
|
+ C.CurrentTime,
|
|
|
+ );
|
|
|
_ = C.XFlush(display);
|
|
|
return;
|
|
|
}
|
|
|
@@ -600,12 +685,22 @@ fn focus(target_index_opt: ?usize) void {
|
|
|
if (sel) |sel_idx| {
|
|
|
if (sel_idx < cl.items.len) {
|
|
|
_ = C.XSetErrorHandler(ignoreError);
|
|
|
- _ = C.XSetWindowBorder(display, cl.items[sel_idx].win, NORMAL_COL);
|
|
|
+ _ = C.XSetWindowBorder(
|
|
|
+ display,
|
|
|
+ cl.items[sel_idx].win,
|
|
|
+ NORMAL_COL,
|
|
|
+ );
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
}
|
|
|
}
|
|
|
sel = null;
|
|
|
- _ = C.XSetInputFocus(display, root, C.RevertToPointerRoot, C.CurrentTime);
|
|
|
+ if (bar) |b_ptr| b_ptr.setSel(null);
|
|
|
+ _ = C.XSetInputFocus(
|
|
|
+ display,
|
|
|
+ root,
|
|
|
+ C.RevertToPointerRoot,
|
|
|
+ C.CurrentTime,
|
|
|
+ );
|
|
|
_ = C.XFlush(display);
|
|
|
return;
|
|
|
};
|
|
|
@@ -645,6 +740,7 @@ fn focus(target_index_opt: ?usize) void {
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
|
|
|
sel = index;
|
|
|
+ if (bar) |b_ptr| b_ptr.setSel(client.win);
|
|
|
|
|
|
_ = C.XFlush(display);
|
|
|
}
|
|
|
@@ -742,12 +838,17 @@ fn unmanage(index: usize, destroyed: bool) void {
|
|
|
|
|
|
var sw: c_uint = 0;
|
|
|
var sh: c_uint = 0;
|
|
|
-var cw: c_uint = 0;
|
|
|
-var ch: c_uint = 0;
|
|
|
+var sx_offset: c_int = 0;
|
|
|
+var sy_offset: c_int = 0;
|
|
|
+var srotation: c_uint = 0;
|
|
|
|
|
|
var rr_event: c_int = 0;
|
|
|
var rr_error: c_int = 0;
|
|
|
|
|
|
+var bar: ?*bar_mod.Bar = null;
|
|
|
+
|
|
|
+const NS_PER_MS: u64 = 1_000_000;
|
|
|
+
|
|
|
fn initRandR(allocator: std.mem.Allocator) !void {
|
|
|
if (C.XRRQueryExtension(display, &rr_event, &rr_error) == 0) {
|
|
|
return;
|
|
|
@@ -762,13 +863,17 @@ fn initRandR(allocator: std.mem.Allocator) !void {
|
|
|
}
|
|
|
|
|
|
fn geom(allocator: std.mem.Allocator) !void {
|
|
|
- const res = C.XRRGetScreenResources(display, root);
|
|
|
+ var res = C.XRRGetScreenResourcesCurrent(display, root);
|
|
|
+ if (res == null) {
|
|
|
+ res = C.XRRGetScreenResources(display, root);
|
|
|
+ }
|
|
|
if (res == null) {
|
|
|
const x_screen = C.DefaultScreen(display);
|
|
|
sw = @intCast(C.XDisplayWidth(display, x_screen));
|
|
|
sh = @intCast(C.XDisplayHeight(display, x_screen));
|
|
|
- cw = @divTrunc((3 * sw), 5);
|
|
|
- ch = sh - 20;
|
|
|
+ sx_offset = 0;
|
|
|
+ sy_offset = 0;
|
|
|
+ srotation = 0;
|
|
|
return;
|
|
|
}
|
|
|
defer C.XRRFreeScreenResources(res);
|
|
|
@@ -777,7 +882,12 @@ fn geom(allocator: std.mem.Allocator) !void {
|
|
|
|
|
|
const primary_output = C.XRRGetOutputPrimary(display, root);
|
|
|
if (primary_output != 0) {
|
|
|
- found_active_monitor = try tryUseMonitor(allocator, res, primary_output, "primary");
|
|
|
+ found_active_monitor = try tryUseMonitor(
|
|
|
+ allocator,
|
|
|
+ res,
|
|
|
+ primary_output,
|
|
|
+ "primary",
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
if (!found_active_monitor) {
|
|
|
@@ -788,12 +898,9 @@ fn geom(allocator: std.mem.Allocator) !void {
|
|
|
const x_screen = C.DefaultScreen(display);
|
|
|
sw = @intCast(C.XDisplayWidth(display, x_screen));
|
|
|
sh = @intCast(C.XDisplayHeight(display, x_screen));
|
|
|
- cw = @divTrunc((3 * sw), 5);
|
|
|
- ch = sh - 20;
|
|
|
- }
|
|
|
-
|
|
|
- if (cl.items.len > 0 and sw > 0 and sh > 0) {
|
|
|
- tile();
|
|
|
+ sx_offset = 0;
|
|
|
+ sy_offset = 0;
|
|
|
+ srotation = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -803,6 +910,7 @@ fn tryUseMonitor(
|
|
|
output_id: C.RROutput,
|
|
|
monitor_type: []const u8,
|
|
|
) !bool {
|
|
|
+ _ = allocator;
|
|
|
const output_info = C.XRRGetOutputInfo(display, res, output_id);
|
|
|
if (output_info == null) return false;
|
|
|
defer C.XRRFreeOutputInfo(output_info);
|
|
|
@@ -821,16 +929,21 @@ fn tryUseMonitor(
|
|
|
|
|
|
sw = @intCast(crtc_info.*.width);
|
|
|
sh = @intCast(crtc_info.*.height);
|
|
|
- cw = @divTrunc((3 * sw), 5);
|
|
|
- ch = sh - 20;
|
|
|
-
|
|
|
- const output_name = std.mem.span(@as([*:0]const u8, @ptrCast(output_info.*.name)));
|
|
|
- const log_msg = try std.fmt.allocPrint(
|
|
|
- allocator,
|
|
|
- "Using {s} monitor: {s} ({d}x{d})",
|
|
|
- .{ monitor_type, output_name, sw, sh },
|
|
|
+ sx_offset = crtc_info.*.x;
|
|
|
+ sy_offset = crtc_info.*.y;
|
|
|
+ srotation = @intCast(crtc_info.*.rotation);
|
|
|
+
|
|
|
+ const output_name = std.mem.span(
|
|
|
+ @as([*:0]const u8, @ptrCast(output_info.*.name)),
|
|
|
);
|
|
|
- defer allocator.free(log_msg);
|
|
|
+ std.log.info("Using {s} monitor: {s} at ({d},{d}) size {d}x{d}", .{
|
|
|
+ monitor_type,
|
|
|
+ output_name,
|
|
|
+ sx_offset,
|
|
|
+ sy_offset,
|
|
|
+ sw,
|
|
|
+ sh,
|
|
|
+ });
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
@@ -839,13 +952,21 @@ fn findLargestMonitor(_: std.mem.Allocator, res: *C.XRRScreenResources) !bool {
|
|
|
var largest_width: c_uint = 0;
|
|
|
var largest_height: c_uint = 0;
|
|
|
var largest_area: c_uint = 0;
|
|
|
+ var largest_x: c_int = 0;
|
|
|
+ var largest_y: c_int = 0;
|
|
|
+ var largest_rotation: c_uint = 0;
|
|
|
|
|
|
- for (0..@intCast(res.*.noutput)) |i| {
|
|
|
+ const output_count: usize = @intCast(res.*.noutput);
|
|
|
+ for (0..output_count) |i| {
|
|
|
const output_info = C.XRRGetOutputInfo(display, res, res.*.outputs[i]);
|
|
|
if (output_info == null) continue;
|
|
|
defer C.XRRFreeOutputInfo(output_info);
|
|
|
|
|
|
- if (output_info.*.connection != C.RR_Connected or output_info.*.crtc == 0) continue;
|
|
|
+ if (output_info.*.connection != C.RR_Connected or
|
|
|
+ output_info.*.crtc == 0)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
const crtc_info = C.XRRGetCrtcInfo(display, res, output_info.*.crtc);
|
|
|
if (crtc_info == null) continue;
|
|
|
@@ -853,22 +974,26 @@ fn findLargestMonitor(_: std.mem.Allocator, res: *C.XRRScreenResources) !bool {
|
|
|
|
|
|
if (crtc_info.*.width == 0 or crtc_info.*.height == 0) continue;
|
|
|
|
|
|
- const output_width = @as(c_uint, @intCast(crtc_info.*.width));
|
|
|
- const output_height = @as(c_uint, @intCast(crtc_info.*.height));
|
|
|
+ const output_width: c_uint = @intCast(crtc_info.*.width);
|
|
|
+ const output_height: c_uint = @intCast(crtc_info.*.height);
|
|
|
const output_area = output_width * output_height;
|
|
|
|
|
|
if (output_area > largest_area) {
|
|
|
largest_area = output_area;
|
|
|
largest_width = output_width;
|
|
|
largest_height = output_height;
|
|
|
+ largest_x = crtc_info.*.x;
|
|
|
+ largest_y = crtc_info.*.y;
|
|
|
+ largest_rotation = @intCast(crtc_info.*.rotation);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (largest_area > 0) {
|
|
|
sw = largest_width;
|
|
|
sh = largest_height;
|
|
|
- cw = @divTrunc((3 * sw), 5);
|
|
|
- ch = sh - 20;
|
|
|
+ sx_offset = largest_x;
|
|
|
+ sy_offset = largest_y;
|
|
|
+ srotation = largest_rotation;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -883,17 +1008,26 @@ fn onRRNotify(allocator: std.mem.Allocator, e: *C.XEvent) !void {
|
|
|
const rrev = @as(*C.XRRNotifyEvent, @ptrCast(e));
|
|
|
|
|
|
switch (rrev.subtype) {
|
|
|
- C.RRNotify_OutputChange, C.RRNotify_CrtcChange => {
|
|
|
- const old_w = sw;
|
|
|
- const old_h = sh;
|
|
|
+ C.RRNotify_OutputChange,
|
|
|
+ C.RRNotify_CrtcChange,
|
|
|
+ => try refreshMonitor(allocator),
|
|
|
+ else => {},
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- try geom(allocator);
|
|
|
+fn onRRScreenChange(allocator: std.mem.Allocator, e: *C.XEvent) !void {
|
|
|
+ _ = C.XRRUpdateConfiguration(e);
|
|
|
+ try refreshMonitor(allocator);
|
|
|
+}
|
|
|
|
|
|
- if (old_w != sw or old_h != sh and cl.items.len > 0) {
|
|
|
- tile();
|
|
|
- }
|
|
|
- },
|
|
|
- else => {},
|
|
|
+fn refreshMonitor(allocator: std.mem.Allocator) !void {
|
|
|
+ try geom(allocator);
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ b_ptr.resize(sw, sx_offset, sy_offset, sh);
|
|
|
+ b_ptr.mark();
|
|
|
+ }
|
|
|
+ if (cl.items.len > 0) {
|
|
|
+ tile();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -966,7 +1100,8 @@ fn isProtoDel(client_index: usize) bool {
|
|
|
var ret = false;
|
|
|
|
|
|
if (C.XGetWMProtocols(display, client.win, &protocols, &n) != 0) {
|
|
|
- for (0..@intCast(n)) |i| {
|
|
|
+ const hint_count: usize = @intCast(n);
|
|
|
+ for (0..hint_count) |i| {
|
|
|
if (protocols[i] == atom_del) {
|
|
|
ret = true;
|
|
|
break;
|
|
|
@@ -993,7 +1128,9 @@ fn sizehints(client: *Client) void {
|
|
|
var size: C.XSizeHints = undefined;
|
|
|
var msize: c_long = 0;
|
|
|
|
|
|
- if (C.XGetWMNormalHints(display, client.win, &size, &msize) == 0 or size.flags == 0) {
|
|
|
+ if (C.XGetWMNormalHints(display, client.win, &size, &msize) == 0 or
|
|
|
+ size.flags == 0)
|
|
|
+ {
|
|
|
size.flags = C.PSize;
|
|
|
}
|
|
|
|
|
|
@@ -1069,8 +1206,12 @@ fn title(_: std.mem.Allocator, client: *Client) void {
|
|
|
var list: [*c][*c]u8 = undefined;
|
|
|
var count: c_int = 0;
|
|
|
|
|
|
- if (C.XmbTextPropertyToTextList(display, &name, &list, &count) >= 0 and count > 0) {
|
|
|
- const src_title = std.mem.span(@as([*:0]const u8, @ptrCast(list[0])));
|
|
|
+ if (C.XmbTextPropertyToTextList(display, &name, &list, &count) >= 0 and
|
|
|
+ count > 0)
|
|
|
+ {
|
|
|
+ const src_title = std.mem.span(
|
|
|
+ @as([*:0]const u8, @ptrCast(list[0])),
|
|
|
+ );
|
|
|
const title_len = @min(src_title.len, client.name.len - 1);
|
|
|
@memcpy(client.name[0..title_len], src_title[0..title_len]);
|
|
|
client.name[title_len] = 0;
|
|
|
@@ -1204,7 +1345,11 @@ fn onmap(allocator: std.mem.Allocator, event: *C.XEvent) !void {
|
|
|
}
|
|
|
|
|
|
_ = C.XSetErrorHandler(ignoreError);
|
|
|
- _ = C.XSelectInput(display, window, C.StructureNotifyMask | C.EnterWindowMask);
|
|
|
+ _ = C.XSelectInput(
|
|
|
+ display,
|
|
|
+ window,
|
|
|
+ C.StructureNotifyMask | C.EnterWindowMask,
|
|
|
+ );
|
|
|
_ = C.XSetWindowBorderWidth(display, window, BORDER);
|
|
|
_ = C.XSetWindowBorder(display, window, NORMAL_COL);
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
@@ -1220,7 +1365,8 @@ fn onmap(allocator: std.mem.Allocator, event: *C.XEvent) !void {
|
|
|
const client = &cl.items[index];
|
|
|
|
|
|
_ = C.XSetErrorHandler(ignoreError);
|
|
|
- _ = C.XMoveWindow(display, window, client.x + 2 * @as(c_int, @intCast(sw)), client.y);
|
|
|
+ const screen_width_i: c_int = @intCast(sw);
|
|
|
+ _ = C.XMoveWindow(display, window, client.x + 2 * screen_width_i, client.y);
|
|
|
_ = C.XMapWindow(display, window);
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
|
|
|
@@ -1279,7 +1425,9 @@ fn onenter(e: *C.XEvent) void {
|
|
|
if (client.isfloat) return;
|
|
|
}
|
|
|
|
|
|
- if (e.xcrossing.mode != C.NotifyNormal or e.xcrossing.detail == C.NotifyInferior) {
|
|
|
+ if (e.xcrossing.mode != C.NotifyNormal or
|
|
|
+ e.xcrossing.detail == C.NotifyInferior)
|
|
|
+ {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -1288,7 +1436,9 @@ fn onenter(e: *C.XEvent) void {
|
|
|
|
|
|
if (getClient(e.xcrossing.window)) |index| {
|
|
|
if (sel) |sel_idx| {
|
|
|
- if (sel_idx < cl.items.len and cl.items[sel_idx].win == e.xcrossing.window) {
|
|
|
+ if (sel_idx < cl.items.len and
|
|
|
+ cl.items[sel_idx].win == e.xcrossing.window)
|
|
|
+ {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
@@ -1306,7 +1456,11 @@ fn onbtn(e: *C.XEvent) void {
|
|
|
defer _ = C.XSetErrorHandler(handleError);
|
|
|
|
|
|
var attributes: C.XWindowAttributes = undefined;
|
|
|
- if (C.XGetWindowAttributes(display, e.xbutton.subwindow, &attributes) == 0) {
|
|
|
+ if (C.XGetWindowAttributes(
|
|
|
+ display,
|
|
|
+ e.xbutton.subwindow,
|
|
|
+ &attributes,
|
|
|
+ ) == 0) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -1476,8 +1630,9 @@ pub fn main() !void {
|
|
|
|
|
|
sw = @intCast(C.XDisplayWidth(display, screen));
|
|
|
sh = @intCast(C.XDisplayHeight(display, screen));
|
|
|
- cw = @divTrunc((3 * sw), 5);
|
|
|
- ch = sh - 20;
|
|
|
+ sx_offset = 0;
|
|
|
+ sy_offset = 0;
|
|
|
+ srotation = 0;
|
|
|
|
|
|
atom_proto = C.XInternAtom(display, "WM_PROTOCOLS", 0);
|
|
|
atom_del = C.XInternAtom(display, "WM_DELETE_WINDOW", 0);
|
|
|
@@ -1500,8 +1655,41 @@ pub fn main() !void {
|
|
|
|
|
|
try initRandR(allocator);
|
|
|
|
|
|
+ if (bar == null) {
|
|
|
+ const bar_ptr = try allocator.create(bar_mod.Bar);
|
|
|
+ errdefer allocator.destroy(bar_ptr);
|
|
|
+ bar_ptr.* = try bar_mod.Bar.init(
|
|
|
+ allocator,
|
|
|
+ display,
|
|
|
+ root,
|
|
|
+ screen,
|
|
|
+ sw,
|
|
|
+ sx_offset,
|
|
|
+ sy_offset,
|
|
|
+ sh,
|
|
|
+ .top,
|
|
|
+ bar_font,
|
|
|
+ delim,
|
|
|
+ );
|
|
|
+ errdefer bar_ptr.*.deinit();
|
|
|
+ try bar_ptr.addBat(30000);
|
|
|
+ try bar_ptr.addWin(100);
|
|
|
+ try bar_ptr.addClock(1000);
|
|
|
+ bar_mod.setGlobalBar(bar_ptr);
|
|
|
+ bar = bar_ptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ defer if (bar) |b_ptr| {
|
|
|
+ b_ptr.deinit();
|
|
|
+ allocator.destroy(b_ptr);
|
|
|
+ };
|
|
|
+
|
|
|
_ = C.XSetErrorHandler(handleError);
|
|
|
- _ = C.XSelectInput(display, root, C.SubstructureRedirectMask | C.EnterWindowMask);
|
|
|
+ _ = C.XSelectInput(
|
|
|
+ display,
|
|
|
+ root,
|
|
|
+ C.SubstructureRedirectMask | C.EnterWindowMask,
|
|
|
+ );
|
|
|
_ = C.XDefineCursor(display, root, C.XCreateFontCursor(display, 68));
|
|
|
|
|
|
grabInput(root);
|
|
|
@@ -1510,12 +1698,43 @@ pub fn main() !void {
|
|
|
run();
|
|
|
|
|
|
syncmon(allocator);
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ b_ptr.resize(sw, sx_offset, sy_offset, sh);
|
|
|
+ b_ptr.mark();
|
|
|
+ }
|
|
|
|
|
|
_ = C.XSync(display, 0);
|
|
|
|
|
|
scan(allocator);
|
|
|
|
|
|
- while (!shouldQuit and C.XNextEvent(display, &event) == 0) {
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ const now_ms = std.time.milliTimestamp();
|
|
|
+ _ = b_ptr.tick(now_ms) catch {};
|
|
|
+ b_ptr.draw();
|
|
|
+ }
|
|
|
+
|
|
|
+ while (!shouldQuit) {
|
|
|
+ const pending = C.XPending(display);
|
|
|
+ if (pending == 0) {
|
|
|
+ var sleep_ns: u64 = 50 * NS_PER_MS;
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ const now_ms = std.time.milliTimestamp();
|
|
|
+ _ = b_ptr.tick(now_ms) catch {};
|
|
|
+ if (b_ptr.dirty) b_ptr.draw();
|
|
|
+ const wait_ms = b_ptr.nextDelay(now_ms);
|
|
|
+ const desired_ns = wait_ms * NS_PER_MS;
|
|
|
+ if (desired_ns < sleep_ns) {
|
|
|
+ sleep_ns = desired_ns;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (sleep_ns > 0) {
|
|
|
+ std.time.sleep(sleep_ns);
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ _ = C.XNextEvent(display, &event);
|
|
|
+
|
|
|
switch (event.type) {
|
|
|
C.MapRequest => try onmap(allocator, &event),
|
|
|
C.UnmapNotify => onunmap(allocator, &event),
|
|
|
@@ -1526,15 +1745,32 @@ pub fn main() !void {
|
|
|
C.DestroyNotify => ondestroy(allocator, &event),
|
|
|
C.ConfigureRequest => onconfig(@ptrCast(&event)),
|
|
|
C.EnterNotify => onenter(&event),
|
|
|
+ C.Expose => {
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ if (event.xexpose.window == b_ptr.win and
|
|
|
+ event.xexpose.count == 0)
|
|
|
+ {
|
|
|
+ b_ptr.mark();
|
|
|
+ b_ptr.draw();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
else => {
|
|
|
- if (rr_event != 0 and
|
|
|
- (event.type == rr_event + C.RRScreenChangeNotify or
|
|
|
- event.type == rr_event + C.RRNotify))
|
|
|
- {
|
|
|
- try onRRNotify(allocator, &event);
|
|
|
+ if (rr_event != 0) {
|
|
|
+ if (event.type == rr_event + C.RRScreenChangeNotify) {
|
|
|
+ try onRRScreenChange(allocator, &event);
|
|
|
+ } else if (event.type == rr_event + C.RRNotify) {
|
|
|
+ try onRRNotify(allocator, &event);
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
}
|
|
|
+
|
|
|
+ if (bar) |b_ptr| {
|
|
|
+ const now_ms = std.time.milliTimestamp();
|
|
|
+ _ = b_ptr.tick(now_ms) catch {};
|
|
|
+ if (b_ptr.dirty) b_ptr.draw();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
keymap.deinit();
|