From 22b8809858088d8760c5601e4ec1658d6be964d4 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 12 Dec 2025 14:01:35 -0800 Subject: [PATCH] macos: add a popover to the readonly badge with info --- macos/Sources/Ghostty/SurfaceView.swift | 54 ++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index c027162ab..3bdcaafe6 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -106,7 +106,9 @@ extension Ghostty { // Readonly indicator badge if surfaceView.readonly { - ReadonlyBadge() + ReadonlyBadge { + surfaceView.toggleReadonly(nil) + } } // Progress report @@ -767,6 +769,10 @@ extension Ghostty { /// A badge overlay that indicates a surface is in readonly mode. /// Positioned in the top-right corner and styled to be noticeable but unobtrusive. struct ReadonlyBadge: View { + let onDisable: () -> Void + + @State private var showingPopover = false + private let badgeColor = Color(hue: 0.08, saturation: 0.5, brightness: 0.8) var body: some View { @@ -784,12 +790,18 @@ extension Ghostty { .padding(.vertical, 4) .background(badgeBackground) .foregroundStyle(badgeColor) + .onTapGesture { + showingPopover = true + } + .backport.pointerStyle(.link) + .popover(isPresented: $showingPopover, arrowEdge: .bottom) { + ReadonlyPopoverView(onDisable: onDisable, isPresented: $showingPopover) + } } .padding(8) Spacer() } - .allowsHitTesting(false) .accessibilityElement(children: .ignore) .accessibilityLabel("Read-only terminal") } @@ -803,6 +815,44 @@ extension Ghostty { ) } } + + struct ReadonlyPopoverView: View { + let onDisable: () -> Void + @Binding var isPresented: Bool + + var body: some View { + VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .leading, spacing: 8) { + HStack(spacing: 8) { + Image(systemName: "eye.fill") + .foregroundColor(.orange) + .font(.system(size: 13)) + Text("Read-Only Mode") + .font(.system(size: 13, weight: .semibold)) + } + + Text("This terminal is in read-only mode. You can still view, select, and scroll through the content, but no input events will be sent to the running application.") + .font(.system(size: 11)) + .foregroundColor(.secondary) + .fixedSize(horizontal: false, vertical: true) + } + + HStack { + Spacer() + + Button("Disable") { + onDisable() + isPresented = false + } + .keyboardShortcut(.defaultAction) + .buttonStyle(.borderedProminent) + .controlSize(.small) + } + } + .padding(16) + .frame(width: 280) + } + } #if canImport(AppKit) /// When changing the split state, or going full screen (native or non), the terminal view