From d9d65fdb9f20c7190609009717a680c18b977425 Mon Sep 17 00:00:00 2001 From: AJ Bucci Date: Mon, 26 Jan 2026 16:00:01 -0500 Subject: [PATCH 1/3] fix: calculate cell size before presenting gtk window --- src/apprt/gtk/class/application.zig | 12 +++++++ src/apprt/gtk/class/surface.zig | 49 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/apprt/gtk/class/application.zig b/src/apprt/gtk/class/application.zig index c24352c18..4c8a5fed1 100644 --- a/src/apprt/gtk/class/application.zig +++ b/src/apprt/gtk/class/application.zig @@ -2182,6 +2182,18 @@ const Action = struct { // Create a new tab with window context (first tab in new window) win.newTabForWindow(parent); + // Compute the initial window size before presenting so the window + // manager can position it correctly. + if (win.getActiveSurface()) |surface| { + surface.computeInitialSize(); + if (surface.getDefaultSize()) |size| { + win.as(gtk.Window).setDefaultSize( + @intCast(size.width), + @intCast(size.height), + ); + } + } + // Show the window gtk.Window.present(win.as(gtk.Window)); } diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index 7627470a5..fd3412072 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -2005,6 +2005,55 @@ pub const Surface = extern struct { self.as(gobject.Object).notifyByPspec(properties.@"default-size".impl.param_spec); } + /// Compute and set the initial window size from config and font metrics. + /// This can be called before the core surface exists to set up the window + /// size before presenting. + pub fn computeInitialSize(self: *Self) void { + const priv = self.private(); + const config_obj = priv.config orelse return; + const config = config_obj.get(); + + // Both dimensions must be configured + if (config.@"window-height" <= 0 or config.@"window-width" <= 0) return; + + const app = Application.default(); + const alloc = app.allocator(); + + // Get content scale and compute DPI + const content_scale = self.getContentScale(); + const x_dpi = content_scale.x * font.face.default_dpi; + const y_dpi = content_scale.y * font.face.default_dpi; + + const font_size: font.face.DesiredSize = .{ + .points = config.@"font-size", + .xdpi = @intFromFloat(x_dpi), + .ydpi = @intFromFloat(y_dpi), + }; + + // Get font grid for cell metrics + var derived_config = font.SharedGridSet.DerivedConfig.init(alloc, config) catch return; + defer derived_config.deinit(); + + const font_grid_key, const font_grid = app.core().font_grid_set.ref( + &derived_config, + font_size, + ) catch return; + defer app.core().font_grid_set.deref(font_grid_key); + + const cell = font_grid.cellSize(); + + // Calculate size (matching recomputeInitialSize logic) + const width = @max(config.@"window-width", 10) * cell.width; + const height = @max(config.@"window-height", 4) * cell.height; + const width_f32: f32 = @floatFromInt(width); + const height_f32: f32 = @floatFromInt(height); + + const final_width: u32 = @intFromFloat(@ceil(width_f32 / content_scale.x)); + const final_height: u32 = @intFromFloat(@ceil(height_f32 / content_scale.y)); + + self.setDefaultSize(.{ .width = final_width, .height = final_height }); + } + /// Get the key sequence list. Full transfer. fn getKeySequence(self: *Self) ?*ext.StringList { const priv = self.private(); From 0af3477e3540c5ad6748d67d7519a3092e219838 Mon Sep 17 00:00:00 2001 From: AJ Bucci Date: Tue, 27 Jan 2026 22:27:15 -0500 Subject: [PATCH 2/3] fix: remove max() and magic numbers --- src/apprt/gtk/class/surface.zig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index fd3412072..a19220d1a 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -2042,9 +2042,11 @@ pub const Surface = extern struct { const cell = font_grid.cellSize(); - // Calculate size (matching recomputeInitialSize logic) - const width = @max(config.@"window-width", 10) * cell.width; - const height = @max(config.@"window-height", 4) * cell.height; + // Calculate size: "best guess"; Padding unavailable pre-init. + // We do not need to @max here because the surface init will set + // size_limit which enforces minimums defined in src/Surface.zig + const width = config.@"window-width" * cell.width; + const height = config.@"window-height" * cell.height; const width_f32: f32 = @floatFromInt(width); const height_f32: f32 = @floatFromInt(height); From 733d307bf4138fe66b8eff01f1d923941c9fe7f0 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sat, 21 Feb 2026 10:41:28 -0600 Subject: [PATCH 3/3] gtk: update some comments/function names, take min sizes into account --- src/Surface.zig | 4 ++-- src/apprt/gtk/class/application.zig | 4 ++-- src/apprt/gtk/class/surface.zig | 16 +++++++--------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index b9dbefa1b..f823512a0 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -46,8 +46,8 @@ const Renderer = rendererpkg.Renderer; /// being resized to a size that is too small to be useful. These defaults /// are chosen to match the default size of Mac's Terminal.app, but is /// otherwise somewhat arbitrary. -const min_window_width_cells: u32 = 10; -const min_window_height_cells: u32 = 4; +pub const min_window_width_cells: u32 = 10; +pub const min_window_height_cells: u32 = 4; /// The maximum number of key tables that can be active at any /// given time. `activate_key_table` calls after this are ignored. diff --git a/src/apprt/gtk/class/application.zig b/src/apprt/gtk/class/application.zig index 4c8a5fed1..00560fd13 100644 --- a/src/apprt/gtk/class/application.zig +++ b/src/apprt/gtk/class/application.zig @@ -2182,10 +2182,10 @@ const Action = struct { // Create a new tab with window context (first tab in new window) win.newTabForWindow(parent); - // Compute the initial window size before presenting so the window + // Estimate the initial window size before presenting so the window // manager can position it correctly. if (win.getActiveSurface()) |surface| { - surface.computeInitialSize(); + surface.estimateInitialSize(); if (surface.getDefaultSize()) |size| { win.as(gtk.Window).setDefaultSize( @intCast(size.width), diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index a19220d1a..2f4a13a32 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -2005,11 +2005,12 @@ pub const Surface = extern struct { self.as(gobject.Object).notifyByPspec(properties.@"default-size".impl.param_spec); } - /// Compute and set the initial window size from config and font metrics. + /// Estimate and set the initial window size from config and font metrics. /// This can be called before the core surface exists to set up the window - /// size before presenting. - pub fn computeInitialSize(self: *Self) void { - const priv = self.private(); + /// size before presenting. This is an estimate because it does not take + /// into account any padding that may need to be added to the window. + pub fn estimateInitialSize(self: *Self) void { + const priv: *Private = self.private(); const config_obj = priv.config orelse return; const config = config_obj.get(); @@ -2042,11 +2043,8 @@ pub const Surface = extern struct { const cell = font_grid.cellSize(); - // Calculate size: "best guess"; Padding unavailable pre-init. - // We do not need to @max here because the surface init will set - // size_limit which enforces minimums defined in src/Surface.zig - const width = config.@"window-width" * cell.width; - const height = config.@"window-height" * cell.height; + const width = @max(CoreSurface.min_window_width_cells, config.@"window-width") * cell.width; + const height = @max(CoreSurface.min_window_height_cells, config.@"window-height") * cell.height; const width_f32: f32 = @floatFromInt(width); const height_f32: f32 = @floatFromInt(height);