From 1c25c6bd306cb7ec6b068c433c414b684c5f5a8a Mon Sep 17 00:00:00 2001 From: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Date: Tue, 10 Mar 2026 21:41:01 -0700 Subject: [PATCH] Keep internal tab drags out of Finder --- Resources/Info.plist | 14 +----------- Sources/ContentView.swift | 35 ++++++++++++++++++++++++++++++ Sources/WorkspaceContentView.swift | 1 + 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Resources/Info.plist b/Resources/Info.plist index f1beb4f9..48d4f800 100644 --- a/Resources/Info.plist +++ b/Resources/Info.plist @@ -93,27 +93,15 @@ - UTExportedTypeDeclarations + UTImportedTypeDeclarations UTTypeIdentifier com.splittabbar.tabtransfer - UTTypeDescription - Bonsplit Tab Transfer - UTTypeConformsTo - - public.data - UTTypeIdentifier com.cmux.sidebar-tab-reorder - UTTypeDescription - cmux Sidebar Tab Reorder - UTTypeConformsTo - - public.data - NSAppTransportSecurity diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 6c03b213..01adb67d 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -82,6 +82,40 @@ func sidebarSelectedWorkspaceForegroundNSColor(opacity: CGFloat) -> NSColor { let clampedOpacity = max(0, min(opacity, 1)) return NSColor.white.withAlphaComponent(clampedOpacity) } + +#if compiler(>=6.2) +@available(macOS 26.0, *) +enum InternalTabDragConfigurationProvider { + // These drags only make sense inside cmux. Outside the app, Finder should + // reject them instead of materializing placeholder files from the payload. + static let value = DragConfiguration( + operationsWithinApp: .init(allowCopy: false, allowMove: true, allowDelete: false), + operationsOutsideApp: .init(allowCopy: false, allowMove: false, allowDelete: false) + ) +} +#endif + +private struct InternalTabDragConfigurationModifier: ViewModifier { + @ViewBuilder + func body(content: Content) -> some View { + #if compiler(>=6.2) + if #available(macOS 26.0, *) { + content.dragConfiguration(InternalTabDragConfigurationProvider.value) + } else { + content + } + #else + content + #endif + } +} + +extension View { + func internalOnlyTabDrag() -> some View { + modifier(InternalTabDragConfigurationModifier()) + } +} + struct ShortcutHintPillBackground: View { var emphasis: Double = 1.0 @@ -9662,6 +9696,7 @@ private struct TabItemView: View { dropIndicator = nil return SidebarTabDragPayload.provider(for: tab.id) } + .internalOnlyTabDrag() .onDrop(of: SidebarTabDragPayload.dropContentTypes, delegate: SidebarTabDropDelegate( targetTabId: tab.id, tabManager: tabManager, diff --git a/Sources/WorkspaceContentView.swift b/Sources/WorkspaceContentView.swift index 700e65c0..0b955943 100644 --- a/Sources/WorkspaceContentView.swift +++ b/Sources/WorkspaceContentView.swift @@ -106,6 +106,7 @@ struct WorkspaceContentView: View { workspace.bonsplitController.focusPane(paneId) } } + .internalOnlyTabDrag() // Split zoom swaps Bonsplit between the full split tree and a single pane view. // Recreate the Bonsplit subtree on zoom enter/exit so stale pre-zoom pane chrome // cannot remain stacked above portal-hosted browser content.