feat(linux): allow setting an intial start position

This commit is contained in:
Adam Wolf
2024-12-29 11:23:54 -06:00
committed by Mitchell Hashimoto
parent 600e417154
commit 5ced72498e
7 changed files with 73 additions and 0 deletions

View File

@ -577,6 +577,7 @@ typedef enum {
GHOSTTY_ACTION_PRESENT_TERMINAL, GHOSTTY_ACTION_PRESENT_TERMINAL,
GHOSTTY_ACTION_SIZE_LIMIT, GHOSTTY_ACTION_SIZE_LIMIT,
GHOSTTY_ACTION_INITIAL_SIZE, GHOSTTY_ACTION_INITIAL_SIZE,
GHOSTTY_ACTION_INITIAL_POSITION,
GHOSTTY_ACTION_CELL_SIZE, GHOSTTY_ACTION_CELL_SIZE,
GHOSTTY_ACTION_INSPECTOR, GHOSTTY_ACTION_INSPECTOR,
GHOSTTY_ACTION_RENDER_INSPECTOR, GHOSTTY_ACTION_RENDER_INSPECTOR,

View File

@ -621,6 +621,8 @@ pub fn init(
const width = @max(config.@"window-width" * cell_size.width, 640); const width = @max(config.@"window-width" * cell_size.width, 640);
const width_f32: f32 = @floatFromInt(width); const width_f32: f32 = @floatFromInt(width);
const height_f32: f32 = @floatFromInt(height); const height_f32: f32 = @floatFromInt(height);
const position_x = config.@"window-position-x";
const position_y = config.@"window-position-y";
// The final values are affected by content scale and we need to // The final values are affected by content scale and we need to
// account for the padding so we get the exact correct grid size. // account for the padding so we get the exact correct grid size.
@ -642,6 +644,14 @@ pub fn init(
// an initial size shouldn't stop our terminal from working. // an initial size shouldn't stop our terminal from working.
log.warn("unable to set initial window size: {s}", .{err}); log.warn("unable to set initial window size: {s}", .{err});
}; };
rt_app.performAction(
.{ .surface = self },
.initial_position,
.{ .x = position_x, .y = position_y },
) catch |err| {
log.warn("unable to set initial window position: {s}", .{err});
};
} }
if (config.title) |title| { if (config.title) |title| {

View File

@ -136,6 +136,11 @@ pub const Action = union(Key) {
/// after the surface is initialized it should be ignored. /// after the surface is initialized it should be ignored.
initial_size: InitialSize, initial_size: InitialSize,
// Specifies the initial position of the target terminal. This will be
// sent only during the initialization of a surface. If it is received
// after the surface is initialized it should be ignored.
initial_position: InitialPosition,
/// The cell size has changed to the given dimensions in pixels. /// The cell size has changed to the given dimensions in pixels.
cell_size: CellSize, cell_size: CellSize,
@ -237,6 +242,7 @@ pub const Action = union(Key) {
present_terminal, present_terminal,
size_limit, size_limit,
initial_size, initial_size,
initial_position,
cell_size, cell_size,
inspector, inspector,
render_inspector, render_inspector,
@ -427,6 +433,11 @@ pub const InitialSize = extern struct {
height: u32, height: u32,
}; };
pub const InitialPosition = extern struct {
x: i32,
y: i32,
};
pub const CellSize = extern struct { pub const CellSize = extern struct {
width: u32, width: u32,
height: u32, height: u32,

View File

@ -178,6 +178,14 @@ pub const App = struct {
), ),
}, },
.initial_position => switch (target) {
.app => {},
.surface => |surface| surface.rt_surface.setInitialWindowPosition(
value.x,
value.y,
),
},
.toggle_fullscreen => self.toggleFullscreen(target), .toggle_fullscreen => self.toggleFullscreen(target),
.open_config => try configpkg.edit.open(self.app.alloc), .open_config => try configpkg.edit.open(self.app.alloc),
@ -663,6 +671,15 @@ pub const Surface = struct {
}); });
} }
/// Set the initial window position. This is called exactly once at
/// surface initialization time. This may be called before "self"
/// is fully initialized.
fn setInitialWindowPosition(self: *const Surface, x: i32, y: i32) void {
log.debug("setting initial window position ({},{})", .{ x, y });
self.window.setPos(.{ .x = x, .y = y });
}
/// Set the size limits of the window. /// Set the size limits of the window.
/// Note: this interface is not good, we should redo it if we plan /// Note: this interface is not good, we should redo it if we plan
/// to use this more. i.e. you can't set max width but no max height, /// to use this more. i.e. you can't set max width but no max height,

View File

@ -786,6 +786,21 @@ fn setInitialSize(
), ),
} }
} }
fn setInitialPosition(
_: *App,
target: apprt.Target,
value: apprt.action.InitialPosition,
) void {
switch (target) {
.app => {},
.surface => |v| v.rt_surface.setInitialWindowPosition(
value.x,
value.y,
),
}
}
fn showDesktopNotification( fn showDesktopNotification(
self: *App, self: *App,
target: apprt.Target, target: apprt.Target,

View File

@ -840,6 +840,12 @@ pub fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void
); );
} }
pub fn setInitialWindowPosition(self: *const Surface, x: i32, y: i32) !void {
// We need the surface's window to set the position.
const window = self.container.window() orelse return;
c.gtk_window_move(@ptrCast(window.window), x, y);
}
pub fn grabFocus(self: *Surface) void { pub fn grabFocus(self: *Surface) void {
if (self.container.tab()) |tab| { if (self.container.tab()) |tab| {
// If any other surface was focused and zoomed in, set it to non zoomed in // If any other surface was focused and zoomed in, set it to non zoomed in

View File

@ -1108,6 +1108,19 @@ keybind: Keybinds = .{},
@"window-height": u32 = 0, @"window-height": u32 = 0,
@"window-width": u32 = 0, @"window-width": u32 = 0,
/// The initial window position. This position is in pixels and is relative
/// to the top-left corner of the screen. Both values must be set to take
/// effect. If only one value is set, it is ignored.
///
/// Note that the window manager may put limits on the position or override
/// the position. For example, a tiling window manager may force the window
/// to be a certain position to fit within the grid. There is nothing Ghostty
/// will do about this, but it will make an effort.
///
/// This will default to the top-left corner of the screen if not set (0, 0).
@"window-position-x": i32 = 0,
@"window-position-y": i32 = 0,
/// Whether to enable saving and restoring window state. Window state includes /// Whether to enable saving and restoring window state. Window state includes
/// their position, size, tabs, splits, etc. Some window state requires shell /// their position, size, tabs, splits, etc. Some window state requires shell
/// integration, such as preserving working directories. See `shell-integration` /// integration, such as preserving working directories. See `shell-integration`