const WindowManager = @This(); pub const Error = error{NoMonitors}; allocator: std.mem.Allocator, window_hook: WindowHook, keyboard_hook: KeyboardHook, screens: std.ArrayList(Screen) = .empty, config: Configuration = .default, pub fn init(allocator: std.mem.Allocator) !WindowManager { log.debug("getting the window manager ready", .{}); const window_hook: WindowHook = try .start(); errdefer window_hook.stop(); const keyboard_hook: KeyboardHook = try .start(); errdefer keyboard_hook.stop(); return .{ .allocator = allocator, .window_hook = window_hook, .keyboard_hook = keyboard_hook }; } fn findScreen(wm: *WindowManager, monitor: Monitor) ?*Screen { for (wm.screens.items) |*screen| { if (screen.monitor.handle == monitor.handle) return screen; } return null; } pub fn deinit(wm: *WindowManager) void { wm.keyboard_hook.stop(); wm.window_hook.stop(); for (wm.screens.items) |*screen| screen.deinit(wm.allocator); wm.screens.deinit(wm.allocator); } pub fn start(wm: *WindowManager) !void { try wm.discoverScreens(); try wm.registerWindows(); log.info("mimi is ready, listening for messages", .{}); pumpMessages(); } fn discoverScreens(wm: *WindowManager) !void { var monitors: std.ArrayList(Monitor) = .empty; defer monitors.deinit(wm.allocator); log.debug("looking for monitors", .{}); try Monitor.enumerate(wm.allocator, &monitors); log.info("found {d} monitor(s)", .{monitors.items.len}); if (monitors.items.len == 0) { log.err("no monitors found, mimi can't run without a display", .{}); return Error.NoMonitors; } try wm.screens.ensureTotalCapacityPrecise(wm.allocator, monitors.items.len); for (monitors.items) |monitor| { wm.screens.appendAssumeCapacity(.init(monitor)); } } fn registerWindows(wm: *WindowManager) !void { var windows: std.ArrayList(Window) = .empty; defer windows.deinit(wm.allocator); log.debug("looking for open windows", .{}); try Window.enumerate(wm.allocator, &windows); log.info("found {d} open window(s)", .{windows.items.len}); for (windows.items) |window| { const screen: *Screen = wm.findScreen(window.monitor()) orelse { log.debug("window on unknown monitor, skipping", .{}); continue; }; try screen.windows.append(wm.allocator, window); } } fn pumpMessages() void { var msg: win32.ui.windows_and_messaging.MSG = undefined; while (win32.ui.windows_and_messaging.GetMessageW(&msg, null, 0, 0) != 0) { _ = win32.ui.windows_and_messaging.TranslateMessage(&msg); _ = win32.ui.windows_and_messaging.DispatchMessageW(&msg); } } const log = std.log.scoped(.window_manager); const Configuration = @import("Configuration.zig"); const KeyboardHook = @import("KeyboardHook.zig"); const WindowHook = @import("WindowHook.zig"); const Screen = @import("Screen.zig"); const Window = @import("Window.zig"); const Monitor = @import("Monitor.zig"); const win32 = @import("win32"); const std = @import("std");