mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Merge pull request #816 from Raiden1411/feat/options
feat: add support for `--fullscreen`, `--title` and `--class` values
This commit is contained in:
@ -67,6 +67,11 @@ class TerminalManager {
|
|||||||
Self.lastCascadePoint = window.cascadeTopLeft(from: Self.lastCascadePoint)
|
Self.lastCascadePoint = window.cascadeTopLeft(from: Self.lastCascadePoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ghostty.windowFullscreen) {
|
||||||
|
// NOTE: this doesn't properly handle non-native fullscreen yet
|
||||||
|
c.window?.toggleFullScreen(nil)
|
||||||
|
}
|
||||||
|
|
||||||
c.showWindow(self)
|
c.showWindow(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +106,15 @@ extension Ghostty {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether to open new windows in fullscreen.
|
||||||
|
var windowFullscreen: Bool {
|
||||||
|
guard let config = self.config else { return true }
|
||||||
|
var v = false
|
||||||
|
let key = "fullscreen"
|
||||||
|
_ = ghostty_config_get(config, &v, key, UInt(key.count))
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
/// The background opacity.
|
/// The background opacity.
|
||||||
var backgroundOpacity: Double {
|
var backgroundOpacity: Double {
|
||||||
guard let config = self.config else { return 1 }
|
guard let config = self.config else { return 1 }
|
||||||
|
@ -155,6 +155,7 @@ const DerivedConfig = struct {
|
|||||||
window_padding_x: u32,
|
window_padding_x: u32,
|
||||||
window_padding_y: u32,
|
window_padding_y: u32,
|
||||||
window_padding_balance: bool,
|
window_padding_balance: bool,
|
||||||
|
title: ?[:0]const u8,
|
||||||
|
|
||||||
pub fn init(alloc_gpa: Allocator, config: *const configpkg.Config) !DerivedConfig {
|
pub fn init(alloc_gpa: Allocator, config: *const configpkg.Config) !DerivedConfig {
|
||||||
var arena = ArenaAllocator.init(alloc_gpa);
|
var arena = ArenaAllocator.init(alloc_gpa);
|
||||||
@ -180,6 +181,7 @@ const DerivedConfig = struct {
|
|||||||
.window_padding_x = config.@"window-padding-x",
|
.window_padding_x = config.@"window-padding-x",
|
||||||
.window_padding_y = config.@"window-padding-y",
|
.window_padding_y = config.@"window-padding-y",
|
||||||
.window_padding_balance = config.@"window-padding-balance",
|
.window_padding_balance = config.@"window-padding-balance",
|
||||||
|
.title = config.title,
|
||||||
|
|
||||||
// Assignments happen sequentially so we have to do this last
|
// Assignments happen sequentially so we have to do this last
|
||||||
// so that the memory is captured from allocs above.
|
// so that the memory is captured from allocs above.
|
||||||
@ -544,6 +546,8 @@ pub fn init(
|
|||||||
log.warn("unable to set initial window size: {s}", .{err});
|
log.warn("unable to set initial window size: {s}", .{err});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.title) |title| try rt_surface.setTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Surface) void {
|
pub fn deinit(self: *Surface) void {
|
||||||
@ -663,6 +667,12 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
|
|||||||
.change_config => |config| try self.changeConfig(config),
|
.change_config => |config| try self.changeConfig(config),
|
||||||
|
|
||||||
.set_title => |*v| {
|
.set_title => |*v| {
|
||||||
|
// We ignore the message in case the title was set via config.
|
||||||
|
if (self.config.title != null) {
|
||||||
|
log.debug("ignoring title change request since static title is set via config", .{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The ptrCast just gets sliceTo to return the proper type.
|
// The ptrCast just gets sliceTo to return the proper type.
|
||||||
// We know that our title should end in 0.
|
// We know that our title should end in 0.
|
||||||
const slice = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(v)), 0);
|
const slice = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(v)), 0);
|
||||||
|
@ -28,6 +28,7 @@ const UnsafePasteWindow = @import("UnsafePasteWindow.zig");
|
|||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
const inspector = @import("inspector.zig");
|
const inspector = @import("inspector.zig");
|
||||||
const key = @import("key.zig");
|
const key = @import("key.zig");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
@ -103,9 +104,17 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
|
|||||||
// Our app ID determines uniqueness and maps to our desktop file.
|
// Our app ID determines uniqueness and maps to our desktop file.
|
||||||
// We append "-debug" to the ID if we're in debug mode so that we
|
// We append "-debug" to the ID if we're in debug mode so that we
|
||||||
// can develop Ghostty in Ghostty.
|
// can develop Ghostty in Ghostty.
|
||||||
const app_id: [:0]const u8 = comptime app_id: {
|
const app_id: [:0]const u8 = app_id: {
|
||||||
var id = "com.mitchellh.ghostty";
|
if (config.class) |class| {
|
||||||
break :app_id if (builtin.mode == .Debug) id ++ "-debug" else id;
|
if (isValidAppId(class)) {
|
||||||
|
break :app_id class;
|
||||||
|
} else {
|
||||||
|
log.warn("invalid 'class' in config, ignoring", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const default_id = "com.mitchellh.ghostty";
|
||||||
|
break :app_id if (builtin.mode == .Debug) default_id ++ "-debug" else default_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create our GTK Application which encapsulates our process.
|
// Create our GTK Application which encapsulates our process.
|
||||||
@ -159,7 +168,6 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
|
|||||||
.config = config,
|
.config = config,
|
||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.cursor_none = cursor_none,
|
.cursor_none = cursor_none,
|
||||||
|
|
||||||
// If we are NOT the primary instance, then we never want to run.
|
// If we are NOT the primary instance, then we never want to run.
|
||||||
// This means that another instance of the GTK app is running and
|
// This means that another instance of the GTK app is running and
|
||||||
// our "activate" call above will open a window.
|
// our "activate" call above will open a window.
|
||||||
@ -490,3 +498,32 @@ fn initMenu(self: *App) void {
|
|||||||
|
|
||||||
self.menu = menu;
|
self.menu = menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn isValidAppId(app_id: [:0]const u8) bool {
|
||||||
|
if (app_id.len > 255 or app_id.len == 0) return false;
|
||||||
|
if (app_id[0] == '.') return false;
|
||||||
|
if (app_id[app_id.len - 1] == '.') return false;
|
||||||
|
|
||||||
|
var hasDot = false;
|
||||||
|
for (app_id) |char| {
|
||||||
|
switch (char) {
|
||||||
|
'a'...'z', 'A'...'Z', '0'...'9', '_', '-' => {},
|
||||||
|
'.' => hasDot = true,
|
||||||
|
else => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasDot) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "isValidAppId" {
|
||||||
|
try testing.expect(isValidAppId("foo.bar"));
|
||||||
|
try testing.expect(isValidAppId("foo.bar.baz"));
|
||||||
|
try testing.expect(!isValidAppId("foo"));
|
||||||
|
try testing.expect(!isValidAppId("foo.bar?"));
|
||||||
|
try testing.expect(!isValidAppId("foo."));
|
||||||
|
try testing.expect(!isValidAppId(".foo"));
|
||||||
|
try testing.expect(!isValidAppId(""));
|
||||||
|
try testing.expect(!isValidAppId("foo" ** 86));
|
||||||
|
}
|
||||||
|
@ -123,6 +123,9 @@ pub fn init(self: *Window, app: *App) !void {
|
|||||||
}
|
}
|
||||||
c.gtk_box_append(@ptrCast(box), notebook_widget);
|
c.gtk_box_append(@ptrCast(box), notebook_widget);
|
||||||
|
|
||||||
|
// If we are in fullscreen mode, new windows start fullscreen.
|
||||||
|
if (app.config.fullscreen) c.gtk_window_fullscreen(self.window);
|
||||||
|
|
||||||
// All of our events
|
// All of our events
|
||||||
_ = c.g_signal_connect_data(window, "close-request", c.G_CALLBACK(>kCloseRequest), self, null, c.G_CONNECT_DEFAULT);
|
_ = c.g_signal_connect_data(window, "close-request", c.G_CALLBACK(>kCloseRequest), self, null, c.G_CONNECT_DEFAULT);
|
||||||
_ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT);
|
_ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT);
|
||||||
|
@ -278,6 +278,30 @@ command: ?[]const u8 = null,
|
|||||||
/// indicate that it is a login shell, depending on the OS).
|
/// indicate that it is a login shell, depending on the OS).
|
||||||
@"command-arg": RepeatableString = .{},
|
@"command-arg": RepeatableString = .{},
|
||||||
|
|
||||||
|
/// Start new windows in fullscreen. This setting applies to new
|
||||||
|
/// windows and does not apply to tabs, splits, etc. However, this
|
||||||
|
/// setting will apply to all new windows, not just the first one.
|
||||||
|
///
|
||||||
|
/// On macOS, this always creates the window in native fullscreen.
|
||||||
|
/// Non-native fullscreen is not currently supported with this
|
||||||
|
/// setting.
|
||||||
|
fullscreen: bool = false,
|
||||||
|
|
||||||
|
/// The title Ghostty will use for the window. This will force the title
|
||||||
|
/// of the window to be this title at all times and Ghostty will ignore any
|
||||||
|
/// set title escape sequences programs (such as Neovim) may send.
|
||||||
|
title: ?[:0]const u8 = null,
|
||||||
|
|
||||||
|
/// The setting that will change the application class value. This value is
|
||||||
|
/// often used with Linux window managers to change behavior (such as
|
||||||
|
/// floating vs tiled). If you don't know what this is, don't set it.
|
||||||
|
///
|
||||||
|
/// The class name must follow the GTK requirements defined here:
|
||||||
|
/// https://docs.gtk.org/gio/type_func.Application.id_is_valid.html
|
||||||
|
///
|
||||||
|
/// This only affects GTK builds.
|
||||||
|
class: ?[:0]const u8 = null,
|
||||||
|
|
||||||
/// The directory to change to after starting the command.
|
/// The directory to change to after starting the command.
|
||||||
///
|
///
|
||||||
/// This setting is secondary to the "window-inherit-working-directory"
|
/// This setting is secondary to the "window-inherit-working-directory"
|
||||||
|
Reference in New Issue
Block a user