From 839bfffb75b16010aaac30e48072152c04d25c16 Mon Sep 17 00:00:00 2001 From: Bryan Lee <38807139+liby@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:58:51 +0800 Subject: [PATCH] Add `toggle_background_opacity` action for macOS --- include/ghostty.h | 1 + macos/Sources/Ghostty/Ghostty.App.swift | 23 ++++++++++++++- macos/Sources/Ghostty/Package.swift | 3 ++ .../Sources/Ghostty/SurfaceView_AppKit.swift | 29 +++++++++++++++++++ src/Surface.zig | 6 ++++ src/apprt/action.zig | 4 +++ src/apprt/glfw.zig | 1 + src/input/Binding.zig | 4 +++ 8 files changed, 70 insertions(+), 1 deletion(-) diff --git a/include/ghostty.h b/include/ghostty.h index 246fb9ed35..4ce91664a2 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -569,6 +569,7 @@ typedef enum { GHOSTTY_ACTION_TOGGLE_FULLSCREEN, GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW, GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS, + GHOSTTY_ACTION_TOGGLE_BACKGROUND_OPACITY, GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL, GHOSTTY_ACTION_TOGGLE_VISIBILITY, GHOSTTY_ACTION_MOVE_TAB, diff --git a/macos/Sources/Ghostty/Ghostty.App.swift b/macos/Sources/Ghostty/Ghostty.App.swift index 43c0f245aa..af7d1081d4 100644 --- a/macos/Sources/Ghostty/Ghostty.App.swift +++ b/macos/Sources/Ghostty/Ghostty.App.swift @@ -107,7 +107,7 @@ extension Ghostty { deinit { // This will force the didSet callbacks to run which free. self.app = nil - + #if os(macOS) NotificationCenter.default.removeObserver(self) #endif @@ -529,6 +529,9 @@ extension Ghostty { case GHOSTTY_ACTION_COLOR_CHANGE: colorChange(app, target: target, change: action.action.color_change) + case GHOSTTY_ACTION_TOGGLE_BACKGROUND_OPACITY: + toggleBackgroundOpacity(app, target: target) + case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS: fallthrough case GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW: @@ -1291,6 +1294,24 @@ extension Ghostty { } } + private static func toggleBackgroundOpacity(_ app: ghostty_app_t, target: ghostty_target_s) { + switch (target.tag) { + case GHOSTTY_TARGET_APP: + Ghostty.logger.warning("toggle_background_opacity does nothing with an app target") + return + + case GHOSTTY_TARGET_SURFACE: + guard let surface = target.target.surface, + let surfaceView = self.surfaceView(from: surface) else { return } + NotificationCenter.default.post( + name: .ghosttyBackgroundOpacityDidToggle, + object: surfaceView + ) + + default: + assertionFailure() + } + } // MARK: User Notifications diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index 71fac4a993..ded545f416 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -233,6 +233,9 @@ extension Notification.Name { static let ghosttyColorDidChange = Notification.Name("com.mitchellh.ghostty.ghosttyColorDidChange") static let GhosttyColorChangeKey = ghosttyColorDidChange.rawValue + /// Background opacity toggle event + static let ghosttyBackgroundOpacityDidToggle = Notification.Name("com.mitchellh.ghostty.backgroundOpacityDidToggle") + /// Goto tab. Has tab index in the userinfo. static let ghosttyMoveTab = Notification.Name("com.mitchellh.ghostty.moveTab") static let GhosttyMoveTabKey = ghosttyMoveTab.rawValue diff --git a/macos/Sources/Ghostty/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/SurfaceView_AppKit.swift index f5cb93580d..39be980968 100644 --- a/macos/Sources/Ghostty/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/SurfaceView_AppKit.swift @@ -190,6 +190,11 @@ extension Ghostty { selector: #selector(windowDidChangeScreen), name: NSWindow.didChangeScreenNotification, object: nil) + center.addObserver( + self, + selector: #selector(ghosttyBackgroundOpacityDidToggle), + name: .ghosttyBackgroundOpacityDidToggle, + object: self) // Listen for local events that we need to know of outside of // single surface handlers. @@ -490,6 +495,30 @@ extension Ghostty { } } + @objc private func ghosttyBackgroundOpacityDidToggle() { + guard self.derivedConfig.backgroundOpacity < 1 else { return } + + // Toggle the window's background opacity + if let window = self.window as? TerminalWindow { + let newOpaque = !window.isOpaque + window.isOpaque = newOpaque + + // Update the window background color based on opacity state + if newOpaque { + window.backgroundColor = NSColor(self.derivedConfig.backgroundColor) + } else { + // Use a very small alpha component to match Terminal.app's look + window.backgroundColor = .white.withAlphaComponent(0.001) + // Apply background blur + if let app = (NSApplication.shared.delegate as? AppDelegate)?.ghostty.app { + ghostty_set_window_background_blur(app, Unmanaged.passUnretained(window).toOpaque()) + } + } + } else { + Ghostty.logger.warning("toggle background opacity: no terminal window found") + } + } + // MARK: - NSView override func becomeFirstResponder() -> Bool { diff --git a/src/Surface.zig b/src/Surface.zig index 5a1d8c01d4..287ea4d360 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -4199,6 +4199,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool {}, ), + .toggle_background_opacity => try self.rt_app.performAction( + .{ .surface = self }, + .toggle_background_opacity, + {}, + ), + .toggle_tab_overview => try self.rt_app.performAction( .{ .surface = self }, .toggle_tab_overview, diff --git a/src/apprt/action.zig b/src/apprt/action.zig index fe2039e523..a0a5994fec 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -104,6 +104,9 @@ pub const Action = union(Key) { /// Toggle whether window directions are shown. toggle_window_decorations, + /// Toggle the background opacity of the target terminal. + toggle_background_opacity, + /// Toggle the quick terminal in or out. toggle_quick_terminal, @@ -238,6 +241,7 @@ pub const Action = union(Key) { toggle_fullscreen, toggle_tab_overview, toggle_window_decorations, + toggle_background_opacity, toggle_quick_terminal, toggle_visibility, move_tab, diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 686a70ddb6..6473ecd4e1 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -221,6 +221,7 @@ pub const App = struct { .close_tab, .toggle_tab_overview, .toggle_window_decorations, + .toggle_background_opacity, .toggle_quick_terminal, .toggle_visibility, .goto_tab, diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 48725fb13e..8646ac8212 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -400,6 +400,9 @@ pub const Action = union(enum) { /// Toggle window decorations on and off. This only works on Linux. toggle_window_decorations: void, + /// Toggle background opacity of window. + toggle_background_opacity: void, + /// Toggle secure input mode on or off. This is used to prevent apps /// that monitor input from seeing what you type. This is useful for /// entering passwords or other sensitive information. @@ -743,6 +746,7 @@ pub const Action = union(enum) { .toggle_maximize, .toggle_fullscreen, .toggle_window_decorations, + .toggle_background_opacity, .toggle_secure_input, .crash, => .surface,