const WindowHook = @This(); pub const Error = error{SetWinEventHookFailed}; const events = [_]struct { min: u32, max: u32 }{ .{ .min = win32.ui.windows_and_messaging.EVENT_SYSTEM_MINIMIZESTART, .max = win32.ui.windows_and_messaging.EVENT_SYSTEM_MINIMIZEEND }, .{ .min = win32.ui.windows_and_messaging.EVENT_SYSTEM_MOVESIZESTART, .max = win32.ui.windows_and_messaging.EVENT_SYSTEM_MOVESIZEEND }, }; hooks: [events.len]win32.ui.accessibility.HWINEVENTHOOK, pub fn start() !WindowHook { var window_hook: WindowHook = undefined; for (events, 0..) |event, i| { log.debug("setting up a hook for events 0x{x}..0x{x}", .{ event.min, event.max }); window_hook.hooks[i] = win32.ui.accessibility.SetWinEventHook( event.min, event.max, null, &winEventProc, 0, 0, win32.ui.windows_and_messaging.WINEVENT_OUTOFCONTEXT | win32.ui.windows_and_messaging.WINEVENT_SKIPOWNPROCESS, ) orelse { log.err("couldn't hook events 0x{x}..0x{x}", .{ event.min, event.max }); for (window_hook.hooks[0..i]) |hook| { _ = win32.ui.accessibility.UnhookWinEvent(hook); } return Error.SetWinEventHookFailed; }; } return window_hook; } pub fn stop(window_hook: WindowHook) void { for (window_hook.hooks, events) |hook, event| { log.debug("removing hook for events 0x{x}..0x{x}", .{ event.min, event.max }); _ = win32.ui.accessibility.UnhookWinEvent(hook); } } fn winEventProc( _: ?win32.ui.accessibility.HWINEVENTHOOK, _: u32, hwnd: ?win32.foundation.HWND, id_object: i32, id_child: i32, _: u32, _: u32, ) callconv(.winapi) void { if (hwnd == null) return; if (id_object != @intFromEnum(win32.ui.windows_and_messaging.OBJID_WINDOW)) return; if (id_child != @as(i32, @intCast(win32.ui.windows_and_messaging.CHILDID_SELF))) return; const window: Window = .{ .handle = hwnd.? }; if (!window.shouldManage()) return; const screen: *Screen = &wm.screens.items[0]; screen.windows.ensureUnusedCapacity(wm.allocator, 1) catch |e| { log.err("couldn't add window: {s}", .{@errorName(e)}); std.debug.panic("{s}", .{@errorName(e)}); }; screen.windows.appendAssumeCapacity(window); log.info("manageable window (now {d})", .{screen.windows.items.len}); } const wm = &@import("main.zig").wm; const log = std.log.scoped(.window_hook); const Screen = @import("Screen.zig"); const Window = @import("Window.zig"); const win32 = @import("win32"); const std = @import("std");