diff --git a/DynamicIsland/DynamicIslandApp.swift b/DynamicIsland/DynamicIslandApp.swift index e23cd9c..dbac59e 100644 --- a/DynamicIsland/DynamicIslandApp.swift +++ b/DynamicIsland/DynamicIslandApp.swift @@ -369,10 +369,13 @@ class AppDelegate: NSObject, NSApplicationDelegate { private func resizeWindow(_ window: NSWindow, on screen: NSScreen, to size: CGSize, animated: Bool) { let screenFrame = screen.frame + // Clamp width to screen width so the notch never extends beyond screen edges on scaled displays + let clampedWidth = min(size.width, screenFrame.width) + let clampedHeight = min(size.height, screenFrame.height) let centerX = screenFrame.midX - let newX = centerX - (size.width / 2) - let newY = screenFrame.origin.y + screenFrame.height - size.height - let targetFrame = NSRect(x: newX, y: newY, width: size.width, height: size.height) + let newX = centerX - (clampedWidth / 2) + let newY = screenFrame.origin.y + screenFrame.height - clampedHeight + let targetFrame = NSRect(x: newX, y: newY, width: clampedWidth, height: clampedHeight) window.setFrame(targetFrame, display: true) } diff --git a/DynamicIsland/components/Notch/DynamicIslandHeader.swift b/DynamicIsland/components/Notch/DynamicIslandHeader.swift index 860ce23..34e4610 100644 --- a/DynamicIsland/components/Notch/DynamicIslandHeader.swift +++ b/DynamicIsland/components/Notch/DynamicIslandHeader.swift @@ -53,10 +53,11 @@ struct DynamicIslandHeader: View { } if vm.notchState == .open && !Defaults[.enableMinimalisticUI] { + let spacerWidth = min(vm.closedNotchSize.width, 300) Rectangle() .fill(NSScreen.screens .first(where: { $0.localizedName == coordinator.selectedScreen })?.safeAreaInsets.top ?? 0 > 0 ? .black : .clear) - .frame(width: vm.closedNotchSize.width) + .frame(width: spacerWidth) .mask { NotchShape() } diff --git a/DynamicIsland/components/Notch/NotchHomeView.swift b/DynamicIsland/components/Notch/NotchHomeView.swift index f8603a6..7de0d23 100644 --- a/DynamicIsland/components/Notch/NotchHomeView.swift +++ b/DynamicIsland/components/Notch/NotchHomeView.swift @@ -32,7 +32,8 @@ struct MusicPlayerView: View { var body: some View { HStack(alignment: .top, spacing: 12) { - AlbumArtView(vm: vm, albumArtNamespace: albumArtNamespace).padding(.all, 5) + AlbumArtView(vm: vm, albumArtNamespace: albumArtNamespace) + .padding(.all, 5) MusicControlsView() .frame(maxWidth: .infinity, alignment: .leading) .drawingGroup() diff --git a/DynamicIsland/components/Settings/SettingsView.swift b/DynamicIsland/components/Settings/SettingsView.swift index eceac92..9bd3df3 100644 --- a/DynamicIsland/components/Settings/SettingsView.swift +++ b/DynamicIsland/components/Settings/SettingsView.swift @@ -3469,7 +3469,9 @@ struct Appearance: View { @State private var speed: CGFloat = 1.0 private var notchWidthRange: ClosedRange { - Double(currentRecommendedMinimumNotchWidth())...900 + let minW = Double(currentRecommendedMinimumNotchWidth()) + let maxW = min(900, Double(maxAllowedNotchWidth())) + return minW...max(minW, maxW) } private var defaultOpenNotchWidth: CGFloat { currentRecommendedMinimumNotchWidth() diff --git a/DynamicIsland/sizing/matters.swift b/DynamicIsland/sizing/matters.swift index d972b3d..b9418b2 100644 --- a/DynamicIsland/sizing/matters.swift +++ b/DynamicIsland/sizing/matters.swift @@ -30,10 +30,31 @@ let batterySneakSize: CGSize = .init(width: 160, height: 1) var openNotchSize: CGSize { let storedWidth = Defaults[.openNotchWidth] let minWidth = currentRecommendedMinimumNotchWidth() - let width = max(storedWidth, minWidth) + let maxWidth = maxAllowedNotchWidth() + let width = min(max(storedWidth, minWidth), maxWidth) return .init(width: width, height: 200) } +/// Maximum notch width based on the current screen's point width. +/// Prevents the notch from extending beyond the screen on scaled displays. +func maxAllowedNotchWidth(for screenName: String? = nil) -> CGFloat { + let screen: NSScreen? + if let screenName { + screen = NSScreen.screens.first { $0.localizedName == screenName } + } else { + screen = NSScreen.main + } + guard let screenWidth = screen?.frame.width, screenWidth > 0 else { + return 900 + } + return max(screenWidth - 60, 400) +} + +/// Convenience for the main screen. +func maxAllowedNotchWidth() -> CGFloat { + maxAllowedNotchWidth(for: nil) +} + // MARK: - Tab-Based Notch Width /// Counts the number of currently enabled standard notch tabs. @@ -87,12 +108,17 @@ func currentRecommendedMinimumNotchWidth() -> CGFloat { } /// Enforces the minimum notch width based on current tab count. +/// Also clamps to screen width so the notch never exceeds the display. /// Only adjusts when not in minimalistic mode. func enforceMinimumNotchWidth() { guard !Defaults[.enableMinimalisticUI] else { return } let minWidth = currentRecommendedMinimumNotchWidth() - if Defaults[.openNotchWidth] < minWidth { - Defaults[.openNotchWidth] = minWidth + let maxWidth = maxAllowedNotchWidth() + var width = Defaults[.openNotchWidth] + if width < minWidth { width = minWidth } + if width > maxWidth { width = maxWidth } + if Defaults[.openNotchWidth] != width { + Defaults[.openNotchWidth] = width } } private let minimalisticBaseOpenNotchSize: CGSize = .init(width: 420, height: 180)