Something went wrong. Try again.
The cutest scrollable window manager for Windows
windows tiling-manager tiling scrollable-window-manager scrollable cute window scroll window-manager
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170const Window = @This();
handle: win32.foundation.HWND,
const EnumContext = struct { allocator: std.mem.Allocator, list: *std.ArrayList(Window), err: ?std.mem.Allocator.Error = null,};
/// Appends each manageable open window to `list`.pub fn enumerate(allocator: std.mem.Allocator, list: *std.ArrayList(Window)) !void { var ctx: EnumContext = .{ .allocator = allocator, .list = list };
_ = win32.ui.windows_and_messaging.EnumWindows(&enumWindowsProc, @intCast(@intFromPtr(&ctx)));
if (ctx.err) |e| { log.err("couldn't get the windows: {s}", .{@errorName(e)}); return e; }}
fn enumWindowsProc( hwnd: win32.foundation.HWND, lparam: win32.foundation.LPARAM,) callconv(.c) win32.foundation.BOOL { const ctx: *EnumContext = @ptrFromInt(@as(usize, @intCast(lparam)));
const window: Window = .{ .handle = hwnd };
if (!window.shouldManage()) return 1;
ctx.list.ensureUnusedCapacity(ctx.allocator, 1) catch |e| { ctx.err = e; return 0; }; ctx.list.appendAssumeCapacity(window);
log.debug("spotted window (now {d})", .{ctx.list.items.len});
return 1;}
pub fn shouldManage(window: Window) bool { if (!window.isTopLevel()) return false;
// Ignore windows owned by our own process // if (window.processId() == win32.system.threading.GetCurrentProcessId()) return false;
if (!window.isVisible()) return false;
if (window.isCloaked()) return false;
if (window.isSystemWindow()) return false;
const styles: win32.ui.windows_and_messaging.WINDOW_STYLE = window.style(); const ex_styles: win32.ui.windows_and_messaging.WINDOW_EX_STYLE = window.exStyle();
if (styles.CHILD == 1) return false;
if (ex_styles.TOOLWINDOW == 1 and ex_styles.NOACTIVATE == 1) return false;
if (window.owner() != null) { if (!(styles.BORDER == 1 and styles.DLGFRAME == 1)) return false; }
return true;}
/// Returns the monitor the window is currently on (nearest if it's off-screen).pub fn monitor(window: Window) Monitor { return .{ .handle = win32.graphics.gdi.MonitorFromWindow( window.handle, win32.graphics.gdi.MONITOR_DEFAULTTONEAREST, ).?, };}
fn rootAncestor(window: Window) ?win32.foundation.HWND { return win32.ui.windows_and_messaging.GetAncestor( window.handle, win32.ui.windows_and_messaging.GA_ROOT, );}
fn isTopLevel(window: Window) bool { return window.rootAncestor() == window.handle;}
fn processId(window: Window) u32 { var pid: u32 = 0; _ = win32.ui.windows_and_messaging.GetWindowThreadProcessId(window.handle, &pid); return pid;}
fn isVisible(window: Window) bool { return win32.ui.windows_and_messaging.IsWindowVisible(window.handle) != 0;}
fn isCloaked(window: Window) bool { var cloaked: u32 = 0; const result: win32.foundation.HRESULT = win32.graphics.dwm.DwmGetWindowAttribute( window.handle, .CLOAKED, &cloaked, @sizeOf(u32), ); return result == 0 and cloaked != 0;}
fn style(window: Window) win32.ui.windows_and_messaging.WINDOW_STYLE { const raw: isize = win32.ui.windows_and_messaging.GetWindowLongPtrW( window.handle, win32.ui.windows_and_messaging.GWL_STYLE, ); return @bitCast(@as(u32, @truncate(@as(usize, @bitCast(raw)))));}
fn exStyle(window: Window) win32.ui.windows_and_messaging.WINDOW_EX_STYLE { const raw: isize = win32.ui.windows_and_messaging.GetWindowLongPtrW( window.handle, win32.ui.windows_and_messaging.GWL_EXSTYLE, ); return @bitCast(@as(u32, @truncate(@as(usize, @bitCast(raw)))));}
fn owner(window: Window) ?win32.foundation.HWND { return win32.ui.windows_and_messaging.GetWindow( window.handle, win32.ui.windows_and_messaging.GW_OWNER, );}
const class_name_max_len: usize = 256;
fn className(window: Window, buf: *[class_name_max_len:0]u16) []const u16 { const len: i32 = win32.ui.windows_and_messaging.GetClassNameW(window.handle, buf, class_name_max_len); if (len <= 0) return &.{}; return buf[0..@intCast(len)];}
const system_classes: [4][]const u16 = .{ std.unicode.utf8ToUtf16LeStringLiteral("SysListView32"), std.unicode.utf8ToUtf16LeStringLiteral("WorkerW"), std.unicode.utf8ToUtf16LeStringLiteral("Shell_TrayWnd"), std.unicode.utf8ToUtf16LeStringLiteral("Shell_SecondaryTrayWnd"),};
fn isSystemWindow(window: Window) bool { if (window.handle == win32.ui.windows_and_messaging.GetDesktopWindow()) return true; if (window.handle == win32.ui.windows_and_messaging.GetShellWindow()) return true;
var buf: [class_name_max_len:0]u16 = undefined; const name: []const u16 = window.className(&buf);
for (system_classes) |sys_class| { if (std.mem.eql(u16, name, sys_class)) return true; }
return false;}
const log = std.log.scoped(.window);
const Monitor = @import("Monitor.zig");
const win32 = @import("win32");const std = @import("std");