import CoreGraphics
|
import Foundation
|
|
public struct OverlayScreenSpaceState: Equatable, Sendable {
|
public static let unknown = OverlayScreenSpaceState(isFullscreenSpace: false, isSplitViewSpace: false)
|
|
public let isFullscreenSpace: Bool
|
public let isSplitViewSpace: Bool
|
|
public init(isFullscreenSpace: Bool = false, isSplitViewSpace: Bool = false) {
|
self.isFullscreenSpace = isFullscreenSpace
|
self.isSplitViewSpace = isSplitViewSpace
|
}
|
}
|
|
public struct OverlayScreenRecord: Equatable, Sendable {
|
public let displayUUID: String
|
public let frame: CGRect
|
public let visibleFrame: CGRect
|
public let isFullscreenSpace: Bool
|
public let isSplitViewSpace: Bool
|
|
public init(
|
displayUUID: String,
|
frame: CGRect,
|
visibleFrame: CGRect,
|
isFullscreenSpace: Bool = false,
|
isSplitViewSpace: Bool = false
|
) {
|
self.displayUUID = displayUUID
|
self.frame = frame
|
self.visibleFrame = visibleFrame
|
self.isFullscreenSpace = isFullscreenSpace
|
self.isSplitViewSpace = isSplitViewSpace
|
}
|
|
public init(
|
displayUUID: String,
|
frame: CGRect,
|
visibleFrame: CGRect,
|
spaceState: OverlayScreenSpaceState
|
) {
|
self.init(
|
displayUUID: displayUUID,
|
frame: frame,
|
visibleFrame: visibleFrame,
|
isFullscreenSpace: spaceState.isFullscreenSpace,
|
isSplitViewSpace: spaceState.isSplitViewSpace
|
)
|
}
|
}
|
|
public struct OverlayPlacementContext: Equatable, Sendable {
|
public let targetDisplayUUID: String?
|
public let targetFrame: CGRect?
|
public let mouseLocation: CGPoint
|
public let coverFullscreenSpace: Bool
|
public let isFullscreenSpace: Bool
|
public let isSplitViewSpace: Bool
|
public let avoidSpaceSwitch: Bool
|
|
public init(
|
targetDisplayUUID: String?,
|
targetFrame: CGRect?,
|
mouseLocation: CGPoint,
|
coverFullscreenSpace: Bool = true,
|
isFullscreenSpace: Bool = false,
|
isSplitViewSpace: Bool = false,
|
avoidSpaceSwitch: Bool = true
|
) {
|
self.targetDisplayUUID = targetDisplayUUID
|
self.targetFrame = targetFrame
|
self.mouseLocation = mouseLocation
|
self.coverFullscreenSpace = coverFullscreenSpace
|
self.isFullscreenSpace = isFullscreenSpace
|
self.isSplitViewSpace = isSplitViewSpace
|
self.avoidSpaceSwitch = avoidSpaceSwitch
|
}
|
|
public var overlayContext: OverlayContext {
|
OverlayContext(
|
entryPoint: .quickSwitch,
|
spacePolicy: SpacePolicy(isFullscreenSpace: isFullscreenSpace, avoidSpaceSwitch: avoidSpaceSwitch),
|
targetDisplayUUID: targetDisplayUUID
|
)
|
}
|
}
|
|
public enum OverlayPlacementPolicy {
|
public static func placement(
|
forMouseLocation mouseLocation: CGPoint,
|
screens: [OverlayScreenRecord]
|
) -> OverlayPlacementContext {
|
let targetScreen = screen(containing: mouseLocation, screens: screens) ?? screens.first
|
|
return OverlayPlacementContext(
|
targetDisplayUUID: targetScreen?.displayUUID,
|
targetFrame: targetScreen?.frame,
|
mouseLocation: mouseLocation,
|
coverFullscreenSpace: true,
|
isFullscreenSpace: targetScreen?.isFullscreenSpace ?? false,
|
isSplitViewSpace: targetScreen?.isSplitViewSpace ?? false,
|
avoidSpaceSwitch: true
|
)
|
}
|
|
private static func screen(
|
containing point: CGPoint,
|
screens: [OverlayScreenRecord]
|
) -> OverlayScreenRecord? {
|
screens.first { screen in
|
screen.frame.contains(point)
|
}
|
}
|
}
|