diff --git a/src/Surface.zig b/src/Surface.zig index cde23a188..e71af3939 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 c24352c18..00560fd13 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); + // Estimate the initial window size before presenting so the window + // manager can position it correctly. + if (win.getActiveSurface()) |surface| { + surface.estimateInitialSize(); + 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..2f4a13a32 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); } + /// 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. 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(); + + // 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(); + + 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); + + 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();