mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk-ng: initial size apprt action (window-width/height) (#8115)
Simple port. I might add size limits if I get to it, but finished this and it works so opened it up.
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const build_config = @import("../build_config.zig");
|
||||
const assert = std.debug.assert;
|
||||
const apprt = @import("../apprt.zig");
|
||||
const configpkg = @import("../config.zig");
|
||||
@ -533,6 +534,16 @@ pub const SizeLimit = extern struct {
|
||||
pub const InitialSize = extern struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
/// Make this a valid gobject if we're in a GTK environment.
|
||||
pub const getGObjectType = switch (build_config.app_runtime) {
|
||||
.gtk, .@"gtk-ng" => @import("gobject").ext.defineBoxed(
|
||||
InitialSize,
|
||||
.{ .name = "GhosttyApprtInitialSize" },
|
||||
),
|
||||
|
||||
.none => void,
|
||||
};
|
||||
};
|
||||
|
||||
pub const CellSize = extern struct {
|
||||
|
@ -501,6 +501,8 @@ pub const Application = extern struct {
|
||||
|
||||
.goto_tab => return Action.gotoTab(target, value),
|
||||
|
||||
.initial_size => return Action.initialSize(target, value),
|
||||
|
||||
.mouse_over_link => Action.mouseOverLink(target, value),
|
||||
.mouse_shape => Action.mouseShape(target, value),
|
||||
.mouse_visibility => Action.mouseVisibility(target, value),
|
||||
@ -548,7 +550,6 @@ pub const Application = extern struct {
|
||||
.toggle_tab_overview => return Action.toggleTabOverview(target),
|
||||
|
||||
// Unimplemented but todo on gtk-ng branch
|
||||
.initial_size,
|
||||
.size_limit,
|
||||
.prompt_title,
|
||||
.toggle_command_palette,
|
||||
@ -1346,6 +1347,23 @@ const Action = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialSize(
|
||||
target: apprt.Target,
|
||||
value: apprt.action.InitialSize,
|
||||
) bool {
|
||||
switch (target) {
|
||||
.app => return false,
|
||||
.surface => |core| {
|
||||
const surface = core.rt_surface.surface;
|
||||
surface.setDefaultSize(
|
||||
value.width,
|
||||
value.height,
|
||||
);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouseOverLink(
|
||||
target: apprt.Target,
|
||||
value: apprt.action.MouseOverLink,
|
||||
|
@ -16,6 +16,7 @@ const renderer = @import("../../../renderer.zig");
|
||||
const terminal = @import("../../../terminal/main.zig");
|
||||
const CoreSurface = @import("../../../Surface.zig");
|
||||
const gresource = @import("../build/gresource.zig");
|
||||
const ext = @import("../ext.zig");
|
||||
const adw_version = @import("../adw_version.zig");
|
||||
const gtk_key = @import("../key.zig");
|
||||
const ApprtSurface = @import("../Surface.zig");
|
||||
@ -75,6 +76,20 @@ pub const Surface = extern struct {
|
||||
);
|
||||
};
|
||||
|
||||
pub const @"default-size" = struct {
|
||||
pub const name = "default-size";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
name,
|
||||
Self,
|
||||
?*apprt.action.InitialSize,
|
||||
.{
|
||||
.nick = "Default Size",
|
||||
.blurb = "The default size of the window for this surface.",
|
||||
.accessor = C.privateBoxedFieldAccessor("default_size"),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
pub const @"font-size-request" = struct {
|
||||
pub const name = "font-size-request";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
@ -333,6 +348,9 @@ pub const Surface = extern struct {
|
||||
/// if `Application.transient_cgroup_base` is set.
|
||||
cgroup_path: ?[]const u8 = null,
|
||||
|
||||
/// The default size for a window that embeds this surface.
|
||||
default_size: ?*apprt.action.InitialSize = null,
|
||||
|
||||
/// The requested font size. This only applies to initialization
|
||||
/// and has no effect later.
|
||||
font_size_request: ?*font.face.DesiredSize = null,
|
||||
@ -1182,6 +1200,10 @@ pub const Surface = extern struct {
|
||||
glib.free(@constCast(@ptrCast(v)));
|
||||
priv.mouse_hover_url = null;
|
||||
}
|
||||
if (priv.default_size) |v| {
|
||||
ext.boxedFree(apprt.action.InitialSize, v);
|
||||
priv.default_size = null;
|
||||
}
|
||||
if (priv.font_size_request) |v| {
|
||||
glib.ext.destroy(v);
|
||||
priv.font_size_request = null;
|
||||
@ -1223,6 +1245,28 @@ pub const Surface = extern struct {
|
||||
self.as(gobject.Object).notifyByPspec(properties.config.impl.param_spec);
|
||||
}
|
||||
|
||||
/// Return the default size, if set.
|
||||
pub fn getDefaultSize(self: *Self) ?*apprt.action.InitialSize {
|
||||
const priv = self.private();
|
||||
return priv.default_size;
|
||||
}
|
||||
|
||||
/// Set the default size for a window that contains this surface.
|
||||
/// This is up to the embedding widget to respect this. Generally, only
|
||||
/// the first surface in a window respects this.
|
||||
pub fn setDefaultSize(self: *Self, width: u32, height: u32) void {
|
||||
const priv = self.private();
|
||||
if (priv.default_size) |v| ext.boxedFree(
|
||||
apprt.action.InitialSize,
|
||||
v,
|
||||
);
|
||||
priv.default_size = ext.boxedCopy(
|
||||
apprt.action.InitialSize,
|
||||
&.{ .width = width, .height = height },
|
||||
);
|
||||
self.as(gobject.Object).notifyByPspec(properties.@"default-size".impl.param_spec);
|
||||
}
|
||||
|
||||
fn propConfig(
|
||||
self: *Self,
|
||||
_: *gobject.ParamSpec,
|
||||
@ -2182,6 +2226,7 @@ pub const Surface = extern struct {
|
||||
gobject.ext.registerProperties(class, &.{
|
||||
properties.config.impl,
|
||||
properties.@"child-exited".impl,
|
||||
properties.@"default-size".impl,
|
||||
properties.@"font-size-request".impl,
|
||||
properties.focused.impl,
|
||||
properties.@"mouse-shape".impl,
|
||||
|
@ -983,6 +983,13 @@ pub const Window = extern struct {
|
||||
self,
|
||||
.{},
|
||||
);
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
surface,
|
||||
*Self,
|
||||
surfaceDefaultSize,
|
||||
self,
|
||||
.{ .detail = "default-size" },
|
||||
);
|
||||
}
|
||||
|
||||
fn tabViewPageDetached(
|
||||
@ -1172,6 +1179,23 @@ pub const Window = extern struct {
|
||||
// We react to the changes in the propMaximized callback
|
||||
}
|
||||
|
||||
fn surfaceDefaultSize(
|
||||
surface: *Surface,
|
||||
_: *gobject.ParamSpec,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
const size = surface.getDefaultSize() orelse return;
|
||||
|
||||
// We previously gated this on whether this was called before but
|
||||
// its useful to always set this to whatever the expected value is
|
||||
// so we can do a "return to default size" later. This call only
|
||||
// affects the window on first load. It won't resize it again later.
|
||||
self.as(gtk.Window).setDefaultSize(
|
||||
@intCast(size.width),
|
||||
@intCast(size.height),
|
||||
);
|
||||
}
|
||||
|
||||
fn actionAbout(
|
||||
_: *gio.SimpleAction,
|
||||
_: ?*glib.Variant,
|
||||
|
@ -9,6 +9,20 @@ const assert = std.debug.assert;
|
||||
const gobject = @import("gobject");
|
||||
const gtk = @import("gtk");
|
||||
|
||||
/// Wrapper around `gobject.boxedCopy` to copy a boxed type `T`.
|
||||
pub fn boxedCopy(comptime T: type, ptr: *const T) *T {
|
||||
const copy = gobject.boxedCopy(T.getGObjectType(), ptr);
|
||||
return @ptrCast(@alignCast(copy));
|
||||
}
|
||||
|
||||
/// Wrapper around `gobject.boxedFree` to free a boxed type `T`.
|
||||
pub fn boxedFree(comptime T: type, ptr: ?*T) void {
|
||||
if (ptr) |p| gobject.boxedFree(
|
||||
T.getGObjectType(),
|
||||
p,
|
||||
);
|
||||
}
|
||||
|
||||
/// Wrapper around `gtk.Widget.getAncestor` to get the widget ancestor
|
||||
/// of the given type `T`, or null if it doesn't exist.
|
||||
pub fn getAncestor(comptime T: type, widget: *gtk.Widget) ?*T {
|
||||
|
Reference in New Issue
Block a user