From 781159af7d3b21f0b4d884ecaea94f0364b9358a Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Mon, 6 Jan 2025 14:53:57 +0100 Subject: [PATCH 1/4] don't error if gtk4 pkg-config configuration could not be found this prevents issues with people running `zig build --help` without gtk4 installed same as #4546 --- build.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/build.zig b/build.zig index 6f80a8961..7f0bf84c5 100644 --- a/build.zig +++ b/build.zig @@ -145,7 +145,6 @@ pub fn build(b: *std.Build) !void { if (std.mem.indexOf(u8, stdout.items, "wayland")) |_| wayland = true; } else { std.log.warn("pkg-config: {s} with code {d}", .{ @tagName(term), code }); - return error.Unexpected; } }, inline else => |code| { From 63a47d0ba573fea37a6d96630aba1a7e466f9e93 Mon Sep 17 00:00:00 2001 From: yonihemi <2340723+yonihemi@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:01:41 +0800 Subject: [PATCH 2/4] iOS: Fix crash on device --- src/renderer/Metal.zig | 35 +++++++++++++++++++++++------------ src/renderer/metal/api.zig | 4 ++++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 75e61ebc0..5ad45da8e 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -209,20 +209,31 @@ pub const GPUState = struct { } fn chooseDevice() error{NoMetalDevice}!objc.Object { - const devices = objc.Object.fromId(mtl.MTLCopyAllDevices()); - defer devices.release(); var chosen_device: ?objc.Object = null; - var iter = devices.iterate(); - while (iter.next()) |device| { - // We want a GPU that’s connected to a display. - if (device.getProperty(bool, "isHeadless")) continue; - chosen_device = device; - // If the user has an eGPU plugged in, they probably want - // to use it. Otherwise, integrated GPUs are better for - // battery life and thermals. - if (device.getProperty(bool, "isRemovable") or - device.getProperty(bool, "isLowPower")) break; + + switch (comptime builtin.os.tag) { + .macos => { + const devices = objc.Object.fromId(mtl.MTLCopyAllDevices()); + defer devices.release(); + + var iter = devices.iterate(); + while (iter.next()) |device| { + // We want a GPU that’s connected to a display. + if (device.getProperty(bool, "isHeadless")) continue; + chosen_device = device; + // If the user has an eGPU plugged in, they probably want + // to use it. Otherwise, integrated GPUs are better for + // battery life and thermals. + if (device.getProperty(bool, "isRemovable") or + device.getProperty(bool, "isLowPower")) break; + } + }, + .ios => { + chosen_device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice()); + }, + else => @compileError("unsupported target for Metal"), } + const device = chosen_device orelse return error.NoMetalDevice; return device.retain(); } diff --git a/src/renderer/metal/api.zig b/src/renderer/metal/api.zig index bd4f407cd..48056ae5e 100644 --- a/src/renderer/metal/api.zig +++ b/src/renderer/metal/api.zig @@ -175,4 +175,8 @@ pub const MTLSize = extern struct { depth: c_ulong, }; +/// https://developer.apple.com/documentation/metal/1433367-mtlcopyalldevices pub extern "c" fn MTLCopyAllDevices() ?*anyopaque; + +/// https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice +pub extern "c" fn MTLCreateSystemDefaultDevice() ?*anyopaque; From f0c2d3d75a59004457e7c18e0075bd4df7b19d6a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 6 Jan 2025 07:01:44 -0800 Subject: [PATCH 3/4] macos: fix retain cycle preventing window from freeing --- macos/Sources/App/macOS/AppDelegate.swift | 16 ++++++++-------- .../Features/Terminal/TerminalWindow.swift | 6 +++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift index 70873236a..1a23eca90 100644 --- a/macos/Sources/App/macOS/AppDelegate.swift +++ b/macos/Sources/App/macOS/AppDelegate.swift @@ -424,35 +424,35 @@ class AppDelegate: NSObject, // If we have a main window then we don't process any of the keys // because we let it capture and propagate. guard NSApp.mainWindow == nil else { return event } - + // If this event as-is would result in a key binding then we send it. if let app = ghostty.app, ghostty_app_key_is_binding( - app, - event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS)) { + app, + event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS)) { ghostty_app_key(app, event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS)) return nil } - + // If this event would be handled by our menu then we do nothing. if let mainMenu = NSApp.mainMenu, mainMenu.performKeyEquivalent(with: event) { return nil } - + // If we reach this point then we try to process the key event // through the Ghostty key mechanism. - + // Ghostty must be loaded guard let ghostty = self.ghostty.app else { return event } - + // Build our event input and call ghostty if (ghostty_app_key(ghostty, event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS))) { // The key was used so we want to stop it from going to our Mac app Ghostty.logger.debug("local key event handled event=\(event)") return nil } - + return event } diff --git a/macos/Sources/Features/Terminal/TerminalWindow.swift b/macos/Sources/Features/Terminal/TerminalWindow.swift index 35f629bfd..0eb8daeeb 100644 --- a/macos/Sources/Features/Terminal/TerminalWindow.swift +++ b/macos/Sources/Features/Terminal/TerminalWindow.swift @@ -667,12 +667,16 @@ fileprivate class WindowDragView: NSView { // A view that matches the color of selected and unselected tabs in the adjacent tab bar. fileprivate class WindowButtonsBackdropView: NSView { - private let terminalWindow: TerminalWindow + // This must be weak because the window has this view. Otherwise + // a retain cycle occurs. + private weak var terminalWindow: TerminalWindow? private let isLightTheme: Bool private let overlayLayer = VibrantLayer() var isHighlighted: Bool = true { didSet { + guard let terminalWindow else { return } + if isLightTheme { overlayLayer.isHidden = isHighlighted layer?.backgroundColor = .clear From ae0c4d927a6a9d2cc19065c6e653da17403d7a2a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 6 Jan 2025 07:13:40 -0800 Subject: [PATCH 4/4] macos: halt NSEvent processing at app scope only if event is handled Fixes #4677 --- macos/Sources/App/macOS/AppDelegate.swift | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift index 1a23eca90..e3518cd2b 100644 --- a/macos/Sources/App/macOS/AppDelegate.swift +++ b/macos/Sources/App/macOS/AppDelegate.swift @@ -430,8 +430,15 @@ class AppDelegate: NSObject, ghostty_app_key_is_binding( app, event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS)) { - ghostty_app_key(app, event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS)) - return nil + // If the key was handled by Ghostty we stop the event chain. If + // the key wasn't handled then we let it fall through and continue + // processing. This is important because some bindings may have no + // affect at this scope. + if (ghostty_app_key( + app, + event.ghosttyKeyEvent(GHOSTTY_ACTION_PRESS))) { + return nil + } } // If this event would be handled by our menu then we do nothing.