mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 17:26:09 +03:00
renderer/metal: API to handle macOS display ID changing
This commit is contained in:
@ -542,6 +542,10 @@ uintptr_t ghostty_surface_pwd(ghostty_surface_t, char*, uintptr_t);
|
|||||||
bool ghostty_surface_has_selection(ghostty_surface_t);
|
bool ghostty_surface_has_selection(ghostty_surface_t);
|
||||||
uintptr_t ghostty_surface_selection(ghostty_surface_t, char*, uintptr_t);
|
uintptr_t ghostty_surface_selection(ghostty_surface_t, char*, uintptr_t);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
void ghostty_surface_set_display_id(ghostty_surface_t, uint32_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
ghostty_inspector_t ghostty_surface_inspector(ghostty_surface_t);
|
ghostty_inspector_t ghostty_surface_inspector(ghostty_surface_t);
|
||||||
void ghostty_inspector_free(ghostty_surface_t);
|
void ghostty_inspector_free(ghostty_surface_t);
|
||||||
void ghostty_inspector_set_focus(ghostty_inspector_t, bool);
|
void ghostty_inspector_set_focus(ghostty_inspector_t, bool);
|
||||||
|
@ -112,6 +112,11 @@ extension Ghostty {
|
|||||||
selector: #selector(onUpdateRendererHealth),
|
selector: #selector(onUpdateRendererHealth),
|
||||||
name: Ghostty.Notification.didUpdateRendererHealth,
|
name: Ghostty.Notification.didUpdateRendererHealth,
|
||||||
object: self)
|
object: self)
|
||||||
|
center.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(windowDidChangeScreen),
|
||||||
|
name: NSWindow.didChangeScreenNotification,
|
||||||
|
object: nil)
|
||||||
|
|
||||||
// Setup our surface. This will also initialize all the terminal IO.
|
// Setup our surface. This will also initialize all the terminal IO.
|
||||||
let surface_cfg = baseConfig ?? SurfaceConfiguration()
|
let surface_cfg = baseConfig ?? SurfaceConfiguration()
|
||||||
@ -322,6 +327,19 @@ extension Ghostty {
|
|||||||
healthy = health == GHOSTTY_RENDERER_HEALTH_OK
|
healthy = health == GHOSTTY_RENDERER_HEALTH_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func windowDidChangeScreen(notification: SwiftUI.Notification) {
|
||||||
|
guard let window = self.window else { return }
|
||||||
|
guard let object = notification.object as? NSWindow, window == object else { return }
|
||||||
|
guard let screen = window.screen else { return }
|
||||||
|
guard let surface = self.surface else { return }
|
||||||
|
|
||||||
|
// When the window changes screens, we need to update libghostty with the screen
|
||||||
|
// ID. If vsync is enabled, this will be used with the CVDisplayLink to ensure
|
||||||
|
// the proper refresh rate is going.
|
||||||
|
let id = (screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as! NSNumber).uint32Value
|
||||||
|
ghostty_surface_set_display_id(surface, id)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - NSView
|
// MARK: - NSView
|
||||||
|
|
||||||
override func viewDidMoveToWindow() {
|
override func viewDidMoveToWindow() {
|
||||||
|
@ -1737,6 +1737,15 @@ pub const CAPI = struct {
|
|||||||
|
|
||||||
// Inspector Metal APIs are only available on Apple systems
|
// Inspector Metal APIs are only available on Apple systems
|
||||||
usingnamespace if (builtin.target.isDarwin()) struct {
|
usingnamespace if (builtin.target.isDarwin()) struct {
|
||||||
|
export fn ghostty_surface_set_display_id(ptr: *Surface, display_id: u32) void {
|
||||||
|
const surface = &ptr.core_surface;
|
||||||
|
_ = surface.renderer_thread.mailbox.push(
|
||||||
|
.{ .macos_display_id = display_id },
|
||||||
|
.{ .forever = {} },
|
||||||
|
);
|
||||||
|
surface.renderer_thread.wakeup.notify() catch {};
|
||||||
|
}
|
||||||
|
|
||||||
export fn ghostty_inspector_metal_init(ptr: *Inspector, device: objc.c.id) bool {
|
export fn ghostty_inspector_metal_init(ptr: *Inspector, device: objc.c.id) bool {
|
||||||
return ptr.initMetal(objc.Object.fromId(device));
|
return ptr.initMetal(objc.Object.fromId(device));
|
||||||
}
|
}
|
||||||
|
@ -561,10 +561,14 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
var cells = try mtl_cell.Contents.init(alloc);
|
var cells = try mtl_cell.Contents.init(alloc);
|
||||||
errdefer cells.deinit(alloc);
|
errdefer cells.deinit(alloc);
|
||||||
|
|
||||||
const display_link: ?DisplayLink = switch (builtin.os.tag) {
|
const display_link: ?DisplayLink = null;
|
||||||
.macos => try macos.video.DisplayLink.createWithActiveCGDisplays(),
|
// Note(mitchellh): if/when we ever want to add vsync, we can use this
|
||||||
else => null,
|
// display link to trigger rendering. We don't need this if vsync is off
|
||||||
};
|
// because any change will trigger a redraw immediately.
|
||||||
|
// const display_link: ?DisplayLink = switch (builtin.os.tag) {
|
||||||
|
// .macos => try macos.video.DisplayLink.createWithActiveCGDisplays(),
|
||||||
|
// else => null,
|
||||||
|
// };
|
||||||
errdefer if (display_link) |v| v.release();
|
errdefer if (display_link) |v| v.release();
|
||||||
|
|
||||||
return Metal{
|
return Metal{
|
||||||
@ -701,6 +705,16 @@ fn displayLinkCallback(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called when we get an updated display ID for our display link.
|
||||||
|
pub fn setMacOSDisplayID(self: *Metal, id: u32) !void {
|
||||||
|
if (comptime DisplayLink == void) return;
|
||||||
|
const display_link = self.display_link orelse return;
|
||||||
|
log.info("updating display link display id={}", .{id});
|
||||||
|
display_link.setCurrentCGDisplay(id) catch |err| {
|
||||||
|
log.warn("error setting display link display id err={}", .{err});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// True if our renderer has animations so that a higher frequency
|
/// True if our renderer has animations so that a higher frequency
|
||||||
/// timer is used.
|
/// timer is used.
|
||||||
pub fn hasAnimations(self: *const Metal) bool {
|
pub fn hasAnimations(self: *const Metal) bool {
|
||||||
|
@ -375,6 +375,12 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.inspector => |v| self.flags.has_inspector = v,
|
.inspector => |v| self.flags.has_inspector = v,
|
||||||
|
|
||||||
|
.macos_display_id => |v| {
|
||||||
|
if (@hasDecl(renderer.Renderer, "setMacOSDisplayID")) {
|
||||||
|
try self.renderer.setMacOSDisplayID(v);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,9 @@ pub const Message = union(enum) {
|
|||||||
/// Activate or deactivate the inspector.
|
/// Activate or deactivate the inspector.
|
||||||
inspector: bool,
|
inspector: bool,
|
||||||
|
|
||||||
|
/// The macOS display ID has changed for the window.
|
||||||
|
macos_display_id: u32,
|
||||||
|
|
||||||
/// Initialize a change_config message.
|
/// Initialize a change_config message.
|
||||||
pub fn initChangeConfig(alloc: Allocator, config: *const configpkg.Config) !Message {
|
pub fn initChangeConfig(alloc: Allocator, config: *const configpkg.Config) !Message {
|
||||||
const thread_ptr = try alloc.create(renderer.Thread.DerivedConfig);
|
const thread_ptr = try alloc.create(renderer.Thread.DerivedConfig);
|
||||||
|
Reference in New Issue
Block a user