123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- //
- // NSWindow+KMExtension.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2023/10/30.
- //
- import Foundation
- private var _KMWindowPopOverKey = "KMWindowPopOverKey"
- private var _KMWindowPopOverSourcesRectKey = "KMWindowPopOverSourcesRectKey"
- extension NSWindow {
- var popover: NSPopover? {
- get {
- return objc_getAssociatedObject(self, &_KMWindowPopOverKey) as? NSPopover
- }
- set {
- objc_setAssociatedObject(self, &_KMWindowPopOverKey, newValue, .OBJC_ASSOCIATION_RETAIN)
- }
- }
-
- var sourcesRect: NSRect {
- get {
- if let data = objc_getAssociatedObject(self, &_KMWindowPopOverSourcesRectKey) as? NSValue {
- return data.rectValue
- }
- return NSZeroRect
- }
- set {
- objc_setAssociatedObject(self, &_KMWindowPopOverSourcesRectKey, NSValue(rect: newValue), .OBJC_ASSOCIATION_RETAIN)
- }
- }
-
- open override func mouseMoved(with event: NSEvent) {
- super.mouseMoved(with: event)
-
- let point = event.locationInWindow
- var need = true
- if let data = event.window?.isKind(of: NSClassFromString("_NSPopoverWindow")!) {
- // need = !data
- if data {
- need = false
- } else {
- need = true
- }
- } else {
- need = true
- }
- if (need) {
- if (self.sourcesRect.contains(point) == false) {
- if self.popover != nil {
- NotificationCenter.default.post(name: Notification.Name("KMPopOverClosedByWindowNotification"), object: self.popover!)
- self.popover?.close()
- self.popover = nil
- self.sourcesRect = NSRect.null
- }
- }
- }
- }
- }
- extension NSWindow {
- static func currentWindow() -> NSWindow {
- var window = NSApp.mainWindow
- if NSApp.mainWindow?.sheets.first != nil {
- window = NSApp.mainWindow?.sheets.first
- }
- if window == nil {
- window = NSApplication.shared.windows.first
- }
- return window ?? NSWindow()
- }
- }
- @objc extension NSWindow {
- public static let willEnterInteractionModeNotification: NSNotification.Name = .init("KMWillEnterInteractionModeNotificationName")
- public static let didEnterInteractionModeNotification: NSNotification.Name = .init("KMDidEnterInteractionModeNotificationName")
-
- public static let willShowFullScreenNotification: NSNotification.Name = .init("KMWillShowFullScreenNotificationName")
- public static let didShowFullScreenNotification: NSNotification.Name = .init("KMDidShowFullScreenNotificationName")
-
- public static let didAddContentViewNotification: NSNotification.Name = .init("KMDidAddContentViewNotificationName")
-
- struct UserInfo {
- public static let interactionModeKey = "KMInteractionModeKey"
- public static let isSwitchingFullScreenKey = "KMIsSwitchingFullScreenKey"
- public static let wantsPresentationKey = "KMWantsPresentationKey"
- }
-
- private static var interactionModeKey_ = "KMInteractionModeKey"
- var interactionMode: KMInteractionMode {
- get {
- if let win = self.interactionParent { // 从 interactionParent 获取数据
- return win.interactionMode
- }
- if let value = (objc_getAssociatedObject(self, &Self.interactionModeKey_) as? Int) {
- return KMInteractionMode(rawValue: value) ?? .normal
- }
- return .normal
- }
- set {
- objc_setAssociatedObject(self, &Self.interactionModeKey_, newValue.rawValue, .OBJC_ASSOCIATION_ASSIGN)
-
- // interactionParent 设置数据
- self.interactionParent?.interactionMode = newValue
- }
- }
-
- private static var isSwitchingFullScreenKey_ = "KMIsSwitchingFullScreenKey"
- var isSwitchingFullScreen: Bool {
- get {
- if let win = self.interactionParent { // 从 interactionParent 获取数据
- return win.isSwitchingFullScreen
- }
- return (objc_getAssociatedObject(self, &Self.isSwitchingFullScreenKey_) as? Bool) ?? false
- }
- set {
- objc_setAssociatedObject(self, &Self.isSwitchingFullScreenKey_, newValue, .OBJC_ASSOCIATION_ASSIGN)
-
- // interactionParent 设置数据
- self.interactionParent?.isSwitchingFullScreen = newValue
- }
- }
-
- private static var wantsPresentationKey_ = "KMWantsPresentationKey"
- var wantsPresentation: Bool {
- get {
- if let win = self.interactionParent { // 从 interactionParent 获取数据
- return win.wantsPresentation
- }
- return (objc_getAssociatedObject(self, &Self.wantsPresentationKey_) as? Bool) ?? false
- }
- set {
- objc_setAssociatedObject(self, &Self.wantsPresentationKey_, newValue, .OBJC_ASSOCIATION_ASSIGN)
-
- // interactionParent 设置数据
- self.interactionParent?.wantsPresentation = newValue
- }
- }
-
- // sheetParent
- private static var interactionParentKey_ = "KMInteractionParentKey"
- var interactionParent: NSWindow? {
- get {
- return (objc_getAssociatedObject(self, &Self.interactionParentKey_) as? NSWindow)
- }
- set {
- objc_setAssociatedObject(self, &Self.interactionParentKey_, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
-
- // 更新数据
- self.interactionMode = self.interactionParent?.interactionMode ?? .normal
- self.isSwitchingFullScreen = self.interactionParent?.isSwitchingFullScreen ?? false
- self.wantsPresentation = self.interactionParent?.wantsPresentation ?? false
- }
- }
-
- func canEnterPresentation() -> Bool {
- if self.interactionMode == .presentation { // 幻灯片模式下
- return false
- }
- if self.isSwitchingFullScreen { // 正在切换中
- return false
- }
-
- let cnt = self.tabbedWindows?.count ?? 0
- return cnt < 2
- }
-
- func canExitPresentation() -> Bool {
- if self.isSwitchingFullScreen { // 正在切换中
- return false
- }
- if self.interactionMode == .presentation { // 幻灯片模式下
- return true
- }
- return false
- }
-
- func enterPresentation(provider: KMInteractionProviderProtocol? = nil) {
- if self.canEnterPresentation() == false {
- NSSound.beep()
- return
- }
-
- let wasInteractionMode = self.interactionMode
- if wasInteractionMode == .fullScreen { // 是全屏模式,直接退出全屏模式
- self.wantsPresentation = true
- self.toggleFullScreen(nil)
- return
- }
-
- let backgroundColor = NSColor.black
- let level = UserDefaults.standard.bool(forKey: "SKUseNormalLevelForPresentationKey") ? NSWindow.Level.normal : NSWindow.Level.popUpMenu
-
- NotificationCenter.default.post(name: Self.willEnterInteractionModeNotification, object: self, userInfo: [Self.UserInfo.interactionModeKey : KMInteractionMode.presentation])
-
- // 设置切换中标识
- self.isSwitchingFullScreen = true
- // 设置模式标识
- self.interactionMode = .presentation
- if wasInteractionMode == .legacyFullScreen {
- } else {
- NotificationCenter.default.post(name: Self.willShowFullScreenNotification, object: self, userInfo: ["fullScreenWindow" : ""])
- let fsWindow = self.fadeInFullScreenWindow(with: backgroundColor, level: level.rawValue)
- NotificationCenter.default.post(name: Self.didShowFullScreenNotification, object: self, userInfo: ["fullScreenWindow" : ""])
-
- let view = provider?.providerContentView?(fullScreenWindow: fsWindow, inset: 0)
- self.fadeInFullScreenView(fullScreenWindow: fsWindow, with: view, inset: 0)
- }
- // 恢复切换全屏标识
- self.isSwitchingFullScreen = false
- NotificationCenter.default.post(name: Self.didEnterInteractionModeNotification, object: self, userInfo: ["fullScreenWindow" : ""])
- }
-
- func exitFullscreen() {
-
- }
-
- // MARK: - fadeIn & fadeOut [淡入、淡出]
- func fadeInFullScreenWindow(with backgroundColor: NSColor, level: Int) -> KMFullScreenWindow {
- let fullScreenWindow = KMFullScreenWindow(screen: (self.screen ?? NSScreen.main)!, bgColor: backgroundColor, level: NSWindow.Level.popUpMenu.rawValue, isMain: true)
- fullScreenWindow.interactionParent = self
-
- self.delegate = nil
- fullScreenWindow.fadeInBlocking()
- self.windowController?.window = fullScreenWindow
- fullScreenWindow.makeKey()
-
- let sel = NSSelectorFromString("setAnimationBehavior:")
- if self.responds(to: sel){
- self.animationBehavior = .none
- }
- self.orderOut(nil)
- if self.responds(to: sel) {
- self.animationBehavior = .default
- }
- fullScreenWindow.level = NSWindow.Level(rawValue: level)
- fullScreenWindow.orderFront(nil)
-
- return fullScreenWindow
- }
-
- func fadeInFullScreenView(fullScreenWindow: KMFullScreenWindow, with view: NSView?, inset: CGFloat) {
- let fadeWindow = KMFullScreenWindow(screen: fullScreenWindow.screen!, bgColor: fullScreenWindow.backgroundColor, level: fullScreenWindow.level.rawValue, isMain: false)
- fadeWindow.order(.above, relativeTo: fullScreenWindow.windowNumber)
- if let _ = view {
- NotificationCenter.default.post(name: Self.didAddContentViewNotification, object: self)
- }
- fullScreenWindow.makeFirstResponder(view)
- fullScreenWindow.recalculateKeyViewLoop()
- fullScreenWindow.delegate = (fullScreenWindow.windowController as? any NSWindowDelegate)
- fullScreenWindow.display()
- fadeWindow.fadeOut()
- }
- }
|