mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: support initial window size
This commit is contained in:
@ -291,6 +291,15 @@ typedef enum {
|
|||||||
GHOSTTY_BUILD_MODE_RELEASE_SMALL,
|
GHOSTTY_BUILD_MODE_RELEASE_SMALL,
|
||||||
} ghostty_build_mode_e;
|
} ghostty_build_mode_e;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool origin;
|
||||||
|
bool size;
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t w;
|
||||||
|
uint32_t h;
|
||||||
|
} ghostty_rect_s;
|
||||||
|
|
||||||
// Fully defined types. This MUST be kept in sync with equivalent Zig
|
// Fully defined types. This MUST be kept in sync with equivalent Zig
|
||||||
// structs. To find the Zig struct, grep for this type name. The documentation
|
// structs. To find the Zig struct, grep for this type name. The documentation
|
||||||
// for all of these types is available in the Zig source.
|
// for all of these types is available in the Zig source.
|
||||||
@ -380,6 +389,7 @@ ghostty_surface_t ghostty_surface_new(ghostty_app_t, ghostty_surface_config_s*);
|
|||||||
void ghostty_surface_free(ghostty_surface_t);
|
void ghostty_surface_free(ghostty_surface_t);
|
||||||
ghostty_app_t ghostty_surface_app(ghostty_surface_t);
|
ghostty_app_t ghostty_surface_app(ghostty_surface_t);
|
||||||
bool ghostty_surface_transparent(ghostty_surface_t);
|
bool ghostty_surface_transparent(ghostty_surface_t);
|
||||||
|
ghostty_rect_s ghostty_surface_window_frame(ghostty_surface_t);
|
||||||
void ghostty_surface_refresh(ghostty_surface_t);
|
void ghostty_surface_refresh(ghostty_surface_t);
|
||||||
void ghostty_surface_set_content_scale(ghostty_surface_t, double, double);
|
void ghostty_surface_set_content_scale(ghostty_surface_t, double, double);
|
||||||
void ghostty_surface_set_focus(ghostty_surface_t, bool);
|
void ghostty_surface_set_focus(ghostty_surface_t, bool);
|
||||||
|
@ -4,6 +4,9 @@ class PrimaryWindowController: NSWindowController, NSWindowDelegate {
|
|||||||
// This is used to programmatically control tabs.
|
// This is used to programmatically control tabs.
|
||||||
weak var windowManager: PrimaryWindowManager?
|
weak var windowManager: PrimaryWindowManager?
|
||||||
|
|
||||||
|
// This should be set to true once a surface has been initialized once.
|
||||||
|
var didInitializeFromSurface: Bool = false
|
||||||
|
|
||||||
// This is required for the "+" button to show up in the tab bar to add a
|
// This is required for the "+" button to show up in the tab bar to add a
|
||||||
// new tab.
|
// new tab.
|
||||||
override func newWindowForTab(_ sender: Any?) {
|
override func newWindowForTab(_ sender: Any?) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22154" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22154"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
@ -98,6 +98,10 @@ extension Ghostty.Notification {
|
|||||||
|
|
||||||
/// Notification sent to toggle split maximize/unmaximize.
|
/// Notification sent to toggle split maximize/unmaximize.
|
||||||
static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom")
|
static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom")
|
||||||
|
|
||||||
|
/// Notification
|
||||||
|
static let didReceiveInitialWindowFrame = Notification.Name("com.mitchellh.ghostty.didReceiveInitialWindowFrame")
|
||||||
|
static let FrameKey = "com.mitchellh.ghostty.frame"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the input enum hashable.
|
// Make the input enum hashable.
|
||||||
|
@ -71,6 +71,7 @@ extension Ghostty {
|
|||||||
// We use these notifications to determine when the window our surface is
|
// We use these notifications to determine when the window our surface is
|
||||||
// attached to is or is not focused.
|
// attached to is or is not focused.
|
||||||
let pubBecomeFocused = NotificationCenter.default.publisher(for: Notification.didBecomeFocusedSurface, object: surfaceView)
|
let pubBecomeFocused = NotificationCenter.default.publisher(for: Notification.didBecomeFocusedSurface, object: surfaceView)
|
||||||
|
let pubInitialFrame = NotificationCenter.default.publisher(for: Notification.didReceiveInitialWindowFrame, object: surfaceView)
|
||||||
let pubBecomeKey = NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification)
|
let pubBecomeKey = NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification)
|
||||||
let pubResign = NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification)
|
let pubResign = NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification)
|
||||||
|
|
||||||
@ -100,6 +101,26 @@ extension Ghostty {
|
|||||||
surfaceFocus = true
|
surfaceFocus = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onReceive(pubInitialFrame) { notification in
|
||||||
|
// We never set the initial frame if we're a split
|
||||||
|
guard !isSplit else { return }
|
||||||
|
|
||||||
|
// We need a window to set the frame
|
||||||
|
guard let surfaceWindow = surfaceView.window else { return }
|
||||||
|
guard let frameAny = notification.userInfo?[Ghostty.Notification.FrameKey] else { return }
|
||||||
|
guard let frame = frameAny as? NSRect else { return }
|
||||||
|
|
||||||
|
// If we have tabs, then do not change the window size
|
||||||
|
guard let windowControllerRaw = surfaceWindow.windowController else { return }
|
||||||
|
guard let windowController = windowControllerRaw as? PrimaryWindowController else { return }
|
||||||
|
guard !windowController.didInitializeFromSurface else { return }
|
||||||
|
|
||||||
|
// We have no tabs and we are not a split, so set the initial size of the window.
|
||||||
|
surfaceWindow.setFrame(frame, display: true)
|
||||||
|
|
||||||
|
// Note that we did initialize
|
||||||
|
windowController.didInitializeFromSurface = true
|
||||||
|
}
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
// Welcome to the SwiftUI bug house of horrors. On macOS 12 (at least
|
// Welcome to the SwiftUI bug house of horrors. On macOS 12 (at least
|
||||||
// 12.5.1, didn't test other versions), the order in which the view
|
// 12.5.1, didn't test other versions), the order in which the view
|
||||||
@ -407,6 +428,28 @@ extension Ghostty {
|
|||||||
|
|
||||||
// If we have a blur, set the blur
|
// If we have a blur, set the blur
|
||||||
ghostty_set_window_background_blur(surface, Unmanaged.passUnretained(window).toOpaque())
|
ghostty_set_window_background_blur(surface, Unmanaged.passUnretained(window).toOpaque())
|
||||||
|
|
||||||
|
// Set the window size
|
||||||
|
let rect = ghostty_surface_window_frame(surface)
|
||||||
|
if (rect.size || rect.origin) {
|
||||||
|
var frame = window.frame
|
||||||
|
if (rect.origin) {
|
||||||
|
frame.origin.x = Double(rect.x)
|
||||||
|
frame.origin.y = Double(rect.y)
|
||||||
|
}
|
||||||
|
if (rect.size) {
|
||||||
|
frame.size.width = Double(rect.w)
|
||||||
|
frame.size.height = Double(rect.h)
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCenter.default.post(
|
||||||
|
name: Notification.didReceiveInitialWindowFrame,
|
||||||
|
object: self,
|
||||||
|
userInfo: [
|
||||||
|
Notification.FrameKey: frame,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func becomeFirstResponder() -> Bool {
|
override func becomeFirstResponder() -> Bool {
|
||||||
|
@ -757,6 +757,16 @@ pub const Surface = struct {
|
|||||||
pub const CAPI = struct {
|
pub const CAPI = struct {
|
||||||
const global = &@import("../main.zig").state;
|
const global = &@import("../main.zig").state;
|
||||||
|
|
||||||
|
/// ghostty_rect_s
|
||||||
|
const Rect = extern struct {
|
||||||
|
origin: bool = false,
|
||||||
|
size: bool = false,
|
||||||
|
x: u32 = 0,
|
||||||
|
y: u32 = 0,
|
||||||
|
w: u32 = 0,
|
||||||
|
h: u32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/// Create a new app.
|
/// Create a new app.
|
||||||
export fn ghostty_app_new(
|
export fn ghostty_app_new(
|
||||||
opts: *const apprt.runtime.App.Options,
|
opts: *const apprt.runtime.App.Options,
|
||||||
@ -864,6 +874,21 @@ pub const CAPI = struct {
|
|||||||
return surface.app.config.@"background-opacity" < 1.0;
|
return surface.app.config.@"background-opacity" < 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The desired window frame for a new window.
|
||||||
|
export fn ghostty_surface_window_frame(surface: *Surface) Rect {
|
||||||
|
const config = surface.app.config;
|
||||||
|
|
||||||
|
// If the desired height/width isn't configured, return 0.
|
||||||
|
if (config.@"window-height" == 0 or config.@"window-width" == 0) return .{};
|
||||||
|
|
||||||
|
// Return the desired rect
|
||||||
|
return .{
|
||||||
|
.size = true,
|
||||||
|
.h = @max(config.@"window-height" * surface.core_surface.cell_size.height, 480),
|
||||||
|
.w = @max(config.@"window-width" * surface.core_surface.cell_size.width, 640),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Tell the surface that it needs to schedule a render
|
/// Tell the surface that it needs to schedule a render
|
||||||
export fn ghostty_surface_refresh(surface: *Surface) void {
|
export fn ghostty_surface_refresh(surface: *Surface) void {
|
||||||
surface.refresh();
|
surface.refresh();
|
||||||
|
Reference in New Issue
Block a user