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_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
|
||||
// structs. To find the Zig struct, grep for this type name. The documentation
|
||||
// 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);
|
||||
ghostty_app_t ghostty_surface_app(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_set_content_scale(ghostty_surface_t, double, double);
|
||||
void ghostty_surface_set_focus(ghostty_surface_t, bool);
|
||||
|
@ -4,6 +4,9 @@ class PrimaryWindowController: NSWindowController, NSWindowDelegate {
|
||||
// This is used to programmatically control tabs.
|
||||
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
|
||||
// new tab.
|
||||
override func newWindowForTab(_ sender: Any?) {
|
||||
|
@ -1,8 +1,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>
|
||||
<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"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -98,6 +98,10 @@ extension Ghostty.Notification {
|
||||
|
||||
/// Notification sent to toggle split maximize/unmaximize.
|
||||
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.
|
||||
|
@ -71,6 +71,7 @@ extension Ghostty {
|
||||
// We use these notifications to determine when the window our surface is
|
||||
// attached to is or is not focused.
|
||||
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 pubResign = NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification)
|
||||
|
||||
@ -100,6 +101,26 @@ extension Ghostty {
|
||||
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() {
|
||||
// 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
|
||||
@ -191,7 +212,7 @@ extension Ghostty {
|
||||
// changed with escape codes. This is public because the callbacks go
|
||||
// to the app level and it is set from there.
|
||||
@Published var title: String = "👻"
|
||||
|
||||
|
||||
private(set) var surface: ghostty_surface_t?
|
||||
var error: Error? = nil
|
||||
|
||||
@ -407,6 +428,28 @@ extension Ghostty {
|
||||
|
||||
// If we have a blur, set the blur
|
||||
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 {
|
||||
|
@ -757,6 +757,16 @@ pub const Surface = struct {
|
||||
pub const CAPI = struct {
|
||||
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.
|
||||
export fn ghostty_app_new(
|
||||
opts: *const apprt.runtime.App.Options,
|
||||
@ -864,6 +874,21 @@ pub const CAPI = struct {
|
||||
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
|
||||
export fn ghostty_surface_refresh(surface: *Surface) void {
|
||||
surface.refresh();
|
||||
|
Reference in New Issue
Block a user