From 074664398a1c30f1f75bb8f363a86234b927150c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 17 Feb 2023 21:45:52 -0800 Subject: [PATCH] macos: correct scale factor propagated --- include/ghostty.h | 2 ++ macos/Sources/TerminalSurfaceView.swift | 36 +++++++++++++++++++++++-- src/App.zig | 10 +++++++ src/apprt/embedded.zig | 24 ++++++++++++++--- src/renderer/Metal.zig | 2 +- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 796f9200b..5bf1fd588 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -53,6 +53,8 @@ int ghostty_app_tick(ghostty_app_t); ghostty_surface_t ghostty_surface_new(ghostty_app_t, ghostty_surface_config_s*); void ghostty_surface_free(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_size(ghostty_surface_t, uint32_t, uint32_t); #ifdef __cplusplus diff --git a/macos/Sources/TerminalSurfaceView.swift b/macos/Sources/TerminalSurfaceView.swift index 498ac9c30..822c2beff 100644 --- a/macos/Sources/TerminalSurfaceView.swift +++ b/macos/Sources/TerminalSurfaceView.swift @@ -33,6 +33,10 @@ class TerminalSurfaceView_Real: NSView, ObservableObject { // We need to support being a first responder so that we can get input events override var acceptsFirstResponder: Bool { return true } + // I don't thikn we need this but this lets us know we should redraw our layer + // so we'll use that to tell ghostty to refresh. + override var wantsUpdateLayer: Bool { return true } + private var surface: ghostty_surface_t? = nil private var error: Error? = nil @@ -45,7 +49,7 @@ class TerminalSurfaceView_Real: NSView, ObservableObject { // Setup our surface. This will also initialize all the terminal IO. var surface_cfg = ghostty_surface_config_s( nsview: Unmanaged.passUnretained(self).toOpaque(), - scale_factor: 1.0) + scale_factor: NSScreen.main!.backingScaleFactor) guard let surface = ghostty_surface_new(app, &surface_cfg) else { self.error = AppError.surfaceCreateError return @@ -62,16 +66,44 @@ class TerminalSurfaceView_Real: NSView, ObservableObject { super.resize(withOldSuperviewSize: oldSize) if let surface = self.surface { - ghostty_surface_set_size(surface, UInt32(self.bounds.size.width), UInt32(self.bounds.size.height)) + // Ghostty wants to know the actual framebuffer size... + let fbFrame = self.convertToBacking(self.frame); + ghostty_surface_set_size(surface, UInt32(fbFrame.size.width), UInt32(fbFrame.size.height)) } } + override func viewDidChangeBackingProperties() { + guard let surface = self.surface else { return } + + // Detect our X/Y scale factor so we can update our surface + let fbFrame = self.convertToBacking(self.frame) + let xScale = fbFrame.size.width / self.frame.size.width + let yScale = fbFrame.size.height / self.frame.size.height + ghostty_surface_set_content_scale(surface, xScale, yScale) + + // When our scale factor changes, so does our fb size so we send that too + ghostty_surface_set_size(surface, UInt32(fbFrame.size.width), UInt32(fbFrame.size.height)) + } + + override func updateLayer() { + guard let surface = self.surface else { return } + ghostty_surface_refresh(surface); + } + override func mouseDown(with event: NSEvent) { print("Mouse down: \(event)") } override func keyDown(with event: NSEvent) { print("Key down: \(event)") + self.interpretKeyEvents([event]) + } + + override func doCommand(by selector: Selector) { + // This currently just prevents NSBeep from interpretKeyEvents but in the future + // we may want to make some of this work. + + // print("SEL: \(selector)") } } diff --git a/src/App.zig b/src/App.zig index 982deb6b0..71793666c 100644 --- a/src/App.zig +++ b/src/App.zig @@ -397,9 +397,19 @@ pub const CAPI = struct { if (ptr) |v| v.app.closeWindow(v); } + /// Tell the surface that it needs to schedule a render + export fn ghostty_surface_refresh(win: *Window) void { + win.window.refresh(); + } + /// Update the size of a surface. This will trigger resize notifications /// to the pty and the renderer. export fn ghostty_surface_set_size(win: *Window, w: u32, h: u32) void { win.window.updateSize(w, h); } + + /// Update the content scale of the surface. + export fn ghostty_surface_set_content_scale(win: *Window, x: f64, y: f64) void { + win.window.updateContentScale(x, y); + } }; diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index aafc95b4a..d53b4a80d 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -49,8 +49,8 @@ pub const App = struct { pub const Window = struct { nsview: objc.Object, - scale_factor: f64, core_win: *CoreWindow, + content_scale: apprt.ContentScale, size: apprt.WindowSize, pub const Options = extern struct { @@ -67,7 +67,10 @@ pub const Window = struct { return .{ .core_win = core_win, .nsview = objc.Object.fromId(opts.nsview), - .scale_factor = opts.scale_factor, + .content_scale = .{ + .x = @floatCast(f32, opts.scale_factor), + .y = @floatCast(f32, opts.scale_factor), + }, .size = .{ .width = 800, .height = 600 }, }; } @@ -77,8 +80,7 @@ pub const Window = struct { } pub fn getContentScale(self: *const Window) !apprt.ContentScale { - _ = self; - return apprt.ContentScale{ .x = 1, .y = 1 }; + return self.content_scale; } pub fn getSize(self: *const Window) !apprt.WindowSize { @@ -115,6 +117,20 @@ pub const Window = struct { return false; } + pub fn refresh(self: *Window) void { + self.core_win.refreshCallback() catch |err| { + log.err("error in refresh callback err={}", .{err}); + return; + }; + } + + pub fn updateContentScale(self: *Window, x: f64, y: f64) void { + self.content_scale = .{ + .x = @floatCast(f32, x), + .y = @floatCast(f32, y), + }; + } + pub fn updateSize(self: *Window, width: u32, height: u32) void { self.size = .{ .width = width, diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 77c269e48..abd8ad06a 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -326,7 +326,7 @@ pub fn finalizeWindowInit(self: *const Metal, win: apprt.runtime.Window) !void { apprt.embedded => .{ .view = win.nsview, - .scaleFactor = win.scale_factor, + .scaleFactor = @floatCast(f64, win.content_scale.x), }, else => @compileError("unsupported apprt for metal"),