Files
2024-07-01 15:20:43 -03:00

1046 lines
36 KiB
Swift

//
// Window.swift
// TGUIKit
//
// Created by keepcoder on 16/10/2016.
// Copyright © 2016 Telegram. All rights reserved.
//
import Cocoa
import SwiftSignalKit
import KeyboardKey
public class AppWindow : Window {
public enum ButtonPoint {
case app
case system
var point: NSPoint {
switch self {
case .app:
return NSMakePoint(20, 5)
case .system:
return NSMakePoint(9, 15)
}
}
}
public var initialButtonPoint: ButtonPoint = .app {
didSet {
updateButtons()
}
}
private func updateButtons() {
// if !isFullScreen {
// var point: NSPoint = initialButtonPoint.point
// self.standardWindowButton(.closeButton)?.setFrameOrigin(point)
// point.x += 20
// self.standardWindowButton(.miniaturizeButton)?.setFrameOrigin(point)
// point.x += 20
// self.standardWindowButton(.zoomButton)?.setFrameOrigin(point)
// }
}
public override func layoutIfNeeded() {
super.layoutIfNeeded()
// toolbar?.isVisible = !isFullScreen
//updateButtons()
}
}
public class ObervableView: NSView {
private var listeners:[WeakReference<NSObject>] = []
func add(listener: NSObject) {
listeners.append(WeakReference(value: listener))
}
func remove(listener: NSObject) {
let index = listeners.firstIndex(where: { (weakValue) -> Bool in
return listener == weakValue.value
})
if let index = index {
listeners.remove(at: index)
}
}
override public func didAddSubview(_ subview: NSView) {
super.didAddSubview(subview)
for listener in listeners {
if let listener = listener.value as? ObservableViewDelegate {
listener.observableView(self, didAddSubview: subview)
}
}
}
override public func willRemoveSubview(_ subview: NSView) {
super.willRemoveSubview(subview)
for listener in listeners {
if let listener = listener.value as? ObservableViewDelegate {
listener.observableview(self, willRemoveSubview: subview)
}
}
}
}
protocol ObservableViewDelegate : class {
func observableView(_ view: NSView, didAddSubview: NSView)
func observableview(_ view: NSView, willRemoveSubview: NSView)
}
public enum HandlerPriority: Int, Comparable {
case low = 0
case medium = 1
case high = 2
case modal = 3
case supreme = 4
}
public func <(lhs: HandlerPriority, rhs: HandlerPriority) -> Bool {
return lhs.rawValue < rhs.rawValue
}
class KeyHandler : Comparable {
let handler:(NSEvent)->KeyHandlerResult
let object:WeakReference<NSObject>
let priority:HandlerPriority
let modifierFlags:NSEvent.ModifierFlags?
let date: TimeInterval
init(_ handler:@escaping(NSEvent)->KeyHandlerResult, _ object:NSObject?, _ priority:HandlerPriority, _ flags:NSEvent.ModifierFlags?) {
self.handler = handler
self.object = WeakReference(value: object)
self.priority = priority
self.modifierFlags = flags
self.date = Date().timeIntervalSince1970
}
}
func ==(lhs: KeyHandler, rhs: KeyHandler) -> Bool {
return lhs.priority == rhs.priority
}
func <(lhs: KeyHandler, rhs: KeyHandler) -> Bool {
if lhs.priority == rhs.priority {
return lhs.date < rhs.date
}
return lhs.priority < rhs.priority
}
public enum SwipeType{
case left,right,none
}
public enum SwipeState {
case start(controller: ViewController)
case swiping(delta: CGFloat, controller: ViewController)
case success(delta: CGFloat, controller: ViewController)
case failed(delta: CGFloat, controller: ViewController)
public var delta: CGFloat {
switch self {
case let .swiping(delta, _), let .success(delta, _), let .failed(delta, _):
return delta
default:
return 0
}
}
public func withAlwaysSuccess() -> SwipeState {
switch self {
case let .failed(delta, controller):
return .success(delta: delta, controller: controller)
default:
return self
}
}
public func withAlwaysFailed() -> SwipeState {
switch self {
case let .success(delta, controller):
return .failed(delta: delta, controller: controller)
default:
return self
}
}
var controller: ViewController {
switch self {
case let .start(controller):
return controller
case let .success(_, controller), let .failed(_, controller), let .swiping(_, controller):
return controller
}
}
}
public enum SwipeDirection {
case left(SwipeState)
case right(SwipeState)
case none
func withAdditionalDelta(_ deltaX: CGFloat, _ force: Bool = false) -> SwipeDirection {
switch self {
case let .left(state):
switch state {
case let .swiping(delta, controller):
return .left(.swiping(delta: force ? deltaX : delta + deltaX, controller: controller))
case let .start(controller):
return .left(.swiping(delta: 0, controller: controller))
default:
return self
}
case let .right(state):
switch state {
case let .swiping(delta, controller):
return .right(.swiping(delta: force ? deltaX : delta - deltaX, controller: controller))
case let .start(controller):
return .right(.swiping(delta: 0, controller: controller))
default:
return self
}
default:
return self
}
}
public var delta: CGFloat {
switch self {
case let .left(state), let .right(state):
return state.delta
case .none:
return 0
}
}
func withUpdatedSuccessOrFail(_ width: CGFloat) -> SwipeDirection {
switch self {
case let .left(state):
return .left(abs(state.delta) > width / 4 ? .success(delta: state.delta, controller: state.controller) : .failed(delta: state.delta, controller: state.controller))
case let .right(state):
return .right(abs(state.delta) > width / 4 ? .success(delta: state.delta, controller: state.controller) : .failed(delta: state.delta, controller: state.controller))
default:
return self
}
}
}
public enum SwipeHandlerResult {
case success(ViewController)
case failed
case nothing
case deltaUpdated(available: CGFloat)
}
class SwipeHandler : Comparable {
let handler:(SwipeDirection, Bool)->SwipeHandlerResult
let object:WeakReference<NSView>
let priority:HandlerPriority
init(_ handler:@escaping(SwipeDirection, Bool)->SwipeHandlerResult, _ object:NSView, _ priority:HandlerPriority) {
self.handler = handler
self.object = WeakReference(value: object)
self.priority = priority
}
}
func ==(lhs: SwipeHandler, rhs: SwipeHandler) -> Bool {
return lhs.priority == rhs.priority
}
func <(lhs: SwipeHandler, rhs: SwipeHandler) -> Bool {
return lhs.priority < rhs.priority
}
class ResponderObserver : Comparable {
let handler:()->NSResponder?
let ignoreKeys:[KeyboardKey]
let object:WeakReference<NSObject>
let priority:HandlerPriority
let date: TimeInterval
init(_ handler:@escaping()->NSResponder?, _ object:NSObject?, _ priority:HandlerPriority, _ ignoreKeys: [KeyboardKey]) {
self.handler = handler
self.ignoreKeys = ignoreKeys
self.object = WeakReference(value: object)
self.priority = priority
self.date = Date().timeIntervalSince1970
}
}
func ==(lhs: ResponderObserver, rhs: ResponderObserver) -> Bool {
return lhs.priority == rhs.priority
}
func <(lhs: ResponderObserver, rhs: ResponderObserver) -> Bool {
if lhs.priority == rhs.priority {
return lhs.date < rhs.date
}
return lhs.priority < rhs.priority
}
class MouseObserver : Comparable {
let handler:(NSEvent)->KeyHandlerResult
let object:WeakReference<NSObject>
let priority:HandlerPriority
let type:NSEvent.EventType?
let date: TimeInterval
init(_ handler:@escaping(NSEvent)->KeyHandlerResult, _ object:NSObject?, _ priority:HandlerPriority, _ type:NSEvent.EventType) {
self.handler = handler
self.object = WeakReference(value: object)
self.priority = priority
self.type = type
self.date = Date().timeIntervalSince1970
}
}
func ==(lhs: MouseObserver, rhs: MouseObserver) -> Bool {
return lhs.priority == rhs.priority
}
func <(lhs: MouseObserver, rhs: MouseObserver) -> Bool {
if lhs.priority == rhs.priority {
return lhs.date < rhs.date
}
return lhs.priority < rhs.priority
}
public typealias SwipeIdentifier = String
public enum KeyHandlerResult {
case invoked // invoke and return
case rejected // can invoke next priority event
case invokeNext // invoke and send global event
}
open class Window: NSWindow {
public var name: String = "TGUIKit.Window"
private var keyHandlers:[KeyboardKey:[KeyHandler]] = [:]
private var swipeHandlers:[SwipeIdentifier: SwipeHandler] = [:]
private var swipeState:[SwipeIdentifier: SwipeDirection] = [:]
public var keyUpHandler:((NSEvent)->Void)?
private var responders:[ResponderObserver] = []
private var mouseHandlers:[UInt:[MouseObserver]] = [:]
private var swipePoints:[NSPoint] = []
private var saver:WindowSaver?
public var initFromSaver:Bool = false
public var copyhandler:(()->Void)? = nil
public var pastehandler:(()->Void)? = nil
public var masterCopyhandler:(()->Void)? = nil
public var closeInterceptor:(()->Bool)? = nil
public var orderOutHandler:(()->Void)? = nil
public weak var rootViewController: ViewController?
public var firstResponderFilter:(NSResponder?)->NSResponder? = { $0 }
public var onToggleFullScreen:((Bool)->Void)? = nil
public var isPushToTalkEquaivalent:((NSEvent)->Bool)?
private let visibleObserver: ValuePromise<Bool> = ValuePromise(true, ignoreRepeated: true)
public var acceptFirstMouse: Bool = true
public static var controlsInset: CGFloat {
return 70
}
private let isKeyWindowValue: ValuePromise<Bool> = ValuePromise(false, ignoreRepeated: true)
public var keyWindowUpdater: Signal<Bool, NoError> {
return self.isKeyWindowValue.get()
}
private let isFullScreenValue: ValuePromise<Bool> = ValuePromise(false, ignoreRepeated: true)
public var fullScreen: Signal<Bool, NoError> {
return self.isFullScreenValue.get()
}
private let occlusionStateValue: ValuePromise<NSWindow.OcclusionState> = ValuePromise(NSWindow.OcclusionState.visible, ignoreRepeated: true)
public var takeOcclusionState: Signal<NSWindow.OcclusionState, NoError> {
return occlusionStateValue.get()
}
public var visibility: Signal<Bool, NoError> {
return visibleObserver.get()
}
open override func setIsVisible(_ flag: Bool) {
super.setIsVisible(flag)
self.visibleObserver.set(flag)
}
public func set(responder:@escaping() -> NSResponder?, with object:NSObject?, priority:HandlerPriority, ignoreKeys: [KeyboardKey] = []) {
responders.append(ResponderObserver(responder, object, priority, ignoreKeys + [.Escape, .LeftArrow, .RightArrow, .Tab, .UpArrow, .DownArrow, .Space]))
}
public func removeObserver(for object:NSObject) {
var copy:[ResponderObserver] = []
for observer in responders {
copy.append(observer)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if copy[i].object.value == object || copy[i].object.value == nil {
responders.remove(at: i)
}
}
}
public func set(handler:@escaping(NSEvent) -> KeyHandlerResult, with object:NSObject, for key:KeyboardKey, priority:HandlerPriority = .low, modifierFlags:NSEvent.ModifierFlags? = nil) -> Void {
var handlers:[KeyHandler]? = keyHandlers[key]
if handlers == nil {
handlers = []
keyHandlers[key] = handlers
}
keyHandlers[key]?.append(KeyHandler(handler, object, priority, modifierFlags))
if key == .Return {
set(handler: handler, with: self, for: .KeypadEnter, priority: priority, modifierFlags: modifierFlags)
}
}
public func add(swipe handler:@escaping(SwipeDirection, Bool) -> SwipeHandlerResult, with object:NSView, identifier: SwipeIdentifier, priority:HandlerPriority = .low) -> Void {
swipeHandlers[identifier] = SwipeHandler(handler, object, priority)
}
public func removeAllHandlers(for object:NSObject) {
var newKeyHandlers:[KeyboardKey:[KeyHandler]] = [:]
for (key, handlers) in keyHandlers {
newKeyHandlers[key] = handlers
}
for (key, handlers) in keyHandlers {
var copy:[KeyHandler] = []
for handle in handlers {
copy.append(handle)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if copy[i].object.value === object {
newKeyHandlers[key]?.remove(at: i)
}
}
}
self.keyHandlers = newKeyHandlers
var newMouseHandlers:[UInt:[MouseObserver]] = [:]
for (key, handlers) in mouseHandlers {
newMouseHandlers[key] = handlers
}
for (key, handlers) in mouseHandlers {
var copy:[MouseObserver] = []
for handle in handlers {
copy.append(handle)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if copy[i].object.value === object {
newMouseHandlers[key]?.remove(at: i)
}
}
}
self.mouseHandlers = newMouseHandlers
self.swipeHandlers = self.swipeHandlers.filter { key, value in
return value.object.value !== object && value.object.value != nil
}
self.responders = responders.filter {
$0.object.value !== object
}
}
public func remove(object:NSObject, for key:KeyboardKey, modifierFlags: NSEvent.ModifierFlags? = nil, forceCheckFlags: Bool = false) {
let handlers = keyHandlers[key]
if let handlers = handlers {
var copy:[KeyHandler] = []
for handle in handlers {
copy.append(handle)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if (copy[i].object.value == object || copy[i].object.value == nil) && ((forceCheckFlags || modifierFlags == nil) && modifierFlags == copy[i].modifierFlags) {
keyHandlers[key]?.remove(at: i)
}
}
}
if key == .Return {
self.remove(object: object, for: .KeypadEnter, modifierFlags: modifierFlags, forceCheckFlags: forceCheckFlags)
}
}
private func cleanUndefinedHandlers() {
var newKeyHandlers:[KeyboardKey:[KeyHandler]] = [:]
for (key, handlers) in keyHandlers {
newKeyHandlers[key] = handlers
}
for (key, handlers) in keyHandlers {
var copy:[KeyHandler] = []
for handle in handlers {
copy.append(handle)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if copy[i].object.value == nil {
newKeyHandlers[key]?.remove(at: i)
}
}
}
self.keyHandlers = newKeyHandlers
var newMouseHandlers:[UInt:[MouseObserver]] = [:]
for (key, handlers) in mouseHandlers {
newMouseHandlers[key] = handlers
}
for (key, handlers) in mouseHandlers {
var copy:[MouseObserver] = []
for handle in handlers {
copy.append(handle)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if copy[i].object.value == nil {
newMouseHandlers[key]?.remove(at: i)
}
}
}
self.mouseHandlers = newMouseHandlers
self.swipeHandlers = self.swipeHandlers.filter { key, value in
return value.object.value != nil
}
}
public func set(mouseHandler:@escaping(NSEvent) -> KeyHandlerResult, with object:NSObject, for type:NSEvent.EventType, priority:HandlerPriority = .low) -> Void {
var handlers:[MouseObserver]? = mouseHandlers[type.rawValue]
if handlers == nil {
handlers = []
mouseHandlers[type.rawValue] = handlers
}
mouseHandlers[type.rawValue]?.append(MouseObserver(mouseHandler, object, priority, type))
}
public func remove(object:NSObject, for type:NSEvent.EventType) {
let handlers = mouseHandlers[type.rawValue]
if let handlers = handlers {
var copy:[MouseObserver] = []
for handle in handlers {
copy.append(handle)
}
for i in stride(from: copy.count - 1, to: -1, by: -1) {
if copy[i].object.value == object || copy[i].object.value == nil {
mouseHandlers[type.rawValue]?.remove(at: i)
}
}
}
}
public func applyResponderIfNeeded(_ event: NSEvent? = nil) ->Void {
let sorted = responders.sorted(by: >)
if let event = event, event.modifierFlags.contains(.option) || event.modifierFlags.contains(.command)
|| event.modifierFlags.contains(.control) {
return
}
for observer in sorted {
if let event = event, let code = KeyboardKey(rawValue: event.keyCode), observer.ignoreKeys.contains(code) {
continue
}
if observer.object.value == nil {
continue
}
if let responder = observer.handler() {
if self.firstResponder != responder {
let _ = self.resignFirstResponder()
if responder.responds(to: NSSelectorFromString("window")) {
let window:NSWindow? = responder.value(forKey: "window") as? NSWindow
if window != self {
continue
}
}
_ = self.makeFirstResponder(responder)
if let responder = responder as? NSTextField {
responder.setCursorToEnd()
}
}
}
break
}
}
open override func keyDown(with event: NSEvent) {
}
open override func keyUp(with event: NSEvent) {
}
open override func flagsChanged(with event: NSEvent) {
}
open override func performKeyEquivalent(with event: NSEvent) -> Bool {
return self.isPushToTalkEquaivalent?(event) ?? super.performKeyEquivalent(with: event)
}
open override func makeFirstResponder(_ responder: NSResponder?) -> Bool {
if let responder = responder, responder.responds(to: NSSelectorFromString("window")) {
let window:NSWindow? = responder.value(forKey: "window") as? NSWindow
if window != self {
return false
}
}
return super.makeFirstResponder(self.firstResponderFilter(responder))
}
open override func becomeFirstResponder() -> Bool {
return false
}
public func sendKeyEvent(_ key: KeyboardKey, modifierFlags: NSEvent.ModifierFlags) {
guard let event = NSEvent.keyEvent(with: .keyDown, location: mouseLocationOutsideOfEventStream, modifierFlags: modifierFlags, timestamp: Date().timeIntervalSince1970, windowNumber: windowNumber, context: graphicsContext, characters: "", charactersIgnoringModifiers: "", isARepeat: false, keyCode: key.rawValue) else {return}
sendEvent(event)
}
open override func makeKeyAndOrderFront(_ sender: Any?) {
super.makeKeyAndOrderFront(sender)
self.visibleObserver.set(self.isVisible)
}
open override func orderOut(_ sender: Any?) {
super.orderOut(sender)
orderOutHandler?()
self.visibleObserver.set(self.isVisible)
}
public func enumerateAllSubviews(callback: (NSView) -> Void) {
if let contentView = contentView {
enumerateAllSubviews(callback: callback, superview: contentView)
}
}
private func enumerateAllSubviews(callback: (NSView) -> Void, superview: NSView) {
for view in superview.subviews {
callback(view)
if !view.subviews.isEmpty {
enumerateAllSubviews(callback: callback, superview: view)
}
}
}
open override func close() {
if let closeInterceptor = closeInterceptor, closeInterceptor() {
return
}
if isReleasedWhenClosed {
closeAllModals(window: self)
super.close()
} else {
super.close()
}
self.visibleObserver.set(self.isVisible)
}
private func scrollDeltaXAfterInvertion(_ value: CGFloat) -> CGFloat {
var deltaX: CGFloat = 0
let isInverted: Bool = System.isScrollInverted
if !isInverted {
deltaX = -value
} else {
deltaX = value
}
return deltaX
}
private func startSwiping(_ event: NSEvent) {
if event.scrollingDeltaY == 0 && event.scrollingDeltaX != 0 {
for (key, swipe) in swipeHandlers.sorted(by: { $0.value.priority > $1.value.priority }) {
if let view = swipe.object.value, view._mouseInside() {
if scrollDeltaXAfterInvertion(event.scrollingDeltaX) > 0 {
let result = swipe.handler(.left(.start(controller: ViewController())), true)
switch result {
case let .success(controller):
swipeState[key] = .left(.start(controller: controller))
break
default:
break
}
} else {
let result = swipe.handler(.right(.start(controller: ViewController())), true)
switch result {
case let .success(controller):
swipeState[key] = .right(.start(controller: controller))
break
default:
break
}
}
}
}
}
}
private func stopSwiping(_ event: NSEvent) {
for (key, swipe) in swipeState {
if let handler = swipeHandlers[key], let view = handler.object.value {
_ = handler.handler(swipe.withUpdatedSuccessOrFail(view.frame.width), true)
}
}
swipeState.removeAll()
}
private func proccessSwiping(_ event: NSEvent) -> Void {
let copy = self.swipeState
for (key, swipe) in copy {
if let handler = swipeHandlers[key], let value = handler.object.value, value._mouseInside() {
let deltaX: CGFloat = scrollDeltaXAfterInvertion(event.scrollingDeltaX)
let newState = swipe.withAdditionalDelta(deltaX)
let result = handler.handler(newState, true)
switch result {
case let .deltaUpdated(available):
swipeState[key] = swipe.withAdditionalDelta(available, true)
default:
swipeState[key] = newState
}
break
}
}
}
public func abortSwiping() -> Void {
let copy = self.swipeState
for (key, swipe) in copy {
switch swipe {
case let .left(state):
let swipe: SwipeDirection = .left(.failed(delta: state.delta, controller: state.controller))
if let handler = swipeHandlers[key] {
_ = handler.handler(swipe, false)
}
self.swipeState.removeValue(forKey: key)
case let .right(state):
let swipe: SwipeDirection = .right(.failed(delta: state.delta, controller: state.controller))
if let handler = swipeHandlers[key] {
_ = handler.handler(swipe, false)
}
default:
break
}
}
self.swipeState.removeAll()
}
public var inLiveSwiping: Bool {
return !swipeState.isEmpty
}
@objc public func pasteToFirstResponder(_ sender: Any) {
if let pastehandler = pastehandler {
pastehandler()
} else {
applyResponderIfNeeded()
if let firstResponder = firstResponder, firstResponder.responds(to: NSSelectorFromString("paste:")) {
firstResponder.performSelector(onMainThread: NSSelectorFromString("paste:"), with: sender, waitUntilDone: false)
}
}
}
@objc public func copyFromFirstResponder(_ sender: Any) {
if let copyhandler = copyhandler {
copyhandler()
} else {
if let firstResponder = firstResponder, firstResponder.responds(to: NSSelectorFromString("copy:")) {
firstResponder.performSelector(onMainThread: NSSelectorFromString("copy:"), with: sender, waitUntilDone: false)
}
}
}
open override func sendEvent(_ event: NSEvent) {
// let testEvent = NSEvent.EventType.init(rawValue: 36)!
//
// if event.type.rawValue == 29 {
// NSLog("\(event.modifierFlags.rawValue)")
// var bp:Int = 0
// bp += 1
// }
if event.type == .keyUp {
self.keyUpHandler?(event)
}
let eventType = event.type
if sheets.isEmpty {
if eventType == .keyDown {
applyResponderIfNeeded(event)
cleanUndefinedHandlers()
if let globalHandlers = keyHandlers[.All]?.sorted(by: >), let keyCode = KeyboardKey(rawValue:event.keyCode) {
for globalHandler in globalHandlers {
let handle = keyHandlers[keyCode]?.sorted(by: >).first
if handle == nil || globalHandler.priority > handle!.priority {
if (handle?.modifierFlags == nil || !event.modifierFlags.contains(handle!.modifierFlags!)) || globalHandler.priority == .supreme {
switch globalHandler.handler(event) {
case .invoked:
return
case .rejected:
break
case .invokeNext:
super.sendEvent(event)
return
}
}
}
}
}
if let keyCode = KeyboardKey(rawValue:event.keyCode), let handlers = keyHandlers[keyCode]?.sorted(by: >) {
loop: for handle in handlers {
if (handle.modifierFlags == nil || event.modifierFlags.contains(handle.modifierFlags!)), event.window?.isKeyWindow == true {
switch handle.handler(event) {
case .invoked:
return
case .rejected:
continue
case .invokeNext:
break loop
}
}
}
}
} else if eventType == .scrollWheel, !swipeHandlers.isEmpty {
if let handlers = mouseHandlers[eventType.rawValue] {
let sorted = handlers.sorted(by: >)
loop: for handle in sorted {
switch handle.handler(event) {
case .invoked:
return
case .rejected:
continue
case .invokeNext:
break loop
}
}
}
switch event.phase {
case NSEvent.Phase.began:
startSwiping(event)
case NSEvent.Phase.stationary:
break
case NSEvent.Phase.changed:
proccessSwiping(event)
case NSEvent.Phase.ended:
stopSwiping(event)
case NSEvent.Phase.cancelled:
stopSwiping(event)
case NSEvent.Phase.mayBegin:
break
default:
break
}
} else if let handlers = mouseHandlers[eventType.rawValue] {
let sorted = handlers.sorted(by: >)
loop: for handle in sorted {
switch handle.handler(event) {
case .invoked:
return
case .rejected:
continue
case .invokeNext:
break loop
}
}
}
if eventType == .rightMouseDown {
if !swipeState.isEmpty {
stopSwiping(event)
}
}
super.sendEvent(event)
} else {
//super.sendEvent(event)
}
}
open override func swipe(with event: NSEvent) {
super.swipe(with: event)
}
// public func set(copy handler:@escaping()->Void) -> (()-> Void,NSEventModifierFlags?)? {
// return self.set(handler: handler, for: .C, priority:.low, modifierFlags: [.command])
// }
//
// public func set(paste handler:@escaping()->Void) -> (()-> Void,NSEventModifierFlags?)? {
// return self.set(handler: handler, for: .V, modifierFlags: [.command])
// }
public func set(escape handler:@escaping(NSEvent) -> KeyHandlerResult, with object:NSObject, priority:HandlerPriority = .low, modifierFlags:NSEvent.ModifierFlags? = nil) -> Void {
set(handler: handler, with: object, for: .Escape, priority:priority, modifierFlags:modifierFlags)
}
open override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
}
public var _canBecomeKey = true
open override var canBecomeKey: Bool {
return _canBecomeKey
}
public var _canBecomeMain = true
open override var canBecomeMain: Bool {
return _canBecomeMain
}
open override func deminiaturize(_ sender: Any?) {
super.deminiaturize(sender)
}
public var isFullScreen: Bool {
return styleMask.contains(.fullScreen)
}
@discardableResult public func initSaver() -> Bool {
self.initFromSaver = true
self.saver = .find(for: self)
if let saver = saver {
self.setFrame(saver.rect, display: true)
if saver.isFullScreen {
toggleFullScreen(self)
}
return true
}
return false
}
public var processFullScreen:((Bool, @escaping(Bool)->Void)->Void)?
private func invokeFullScreen(_ sender: Any?) {
CATransaction.begin()
super.toggleFullScreen(sender)
CATransaction.commit()
saver?.isFullScreen = isFullScreen
}
open override func toggleFullScreen(_ sender: Any?) {
let newValue = !isFullScreen
self.onToggleFullScreen?(newValue)
if let process = processFullScreen {
process(newValue, { [weak self] value in
self?.invokeFullScreen(nil)
self?.onToggleFullScreen?(newValue)
})
} else {
invokeFullScreen(nil)
DispatchQueue.main.async {
self.isFullScreenValue.set(newValue)
}
}
}
public var _windowDidExitFullScreen:(()->Void)?
@objc func windowDidExitFullScreen(_ notification: Notification) {
_windowDidExitFullScreen?()
_windowDidExitFullScreen = nil
}
@objc func windowDidNeedSaveState(_ notification: Notification) {
guard let saver = saver, !saver.isFullScreen && !isFullScreen else {
self.saver?.save()
return
}
saver.rect = frame
saver.save()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
public func windowImageShot() -> CGImage? {
if windowNumber >= 0 {
return CGWindowListCreateImage(CGRect.null, [.optionIncludingWindow], CGWindowID(windowNumber), [.boundsIgnoreFraming])
} else {
return nil
}
}
@objc open func windowDidBecomeKey() {
isKeyWindowValue.set(true)
}
@objc open func windowDidResignKey() {
isKeyWindowValue.set(false)
}
/*
- (void)windowDidChangeOcclusionState:(NSNotification *)notification
{
if ([[notification object] occlusionState] & NSWindowOcclusionStateVisible) {
// visible
} else {
// occluded
}
}
*/
@objc func windowDidChangeOcclusionState() {
occlusionStateValue.set(self.occlusionState)
}
open override func updateConstraintsIfNeeded() {
}
public override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing bufferingType: NSWindow.BackingStoreType, defer flag: Bool) {
super.init(contentRect: contentRect, styleMask: style, backing: bufferingType, defer: flag)
self.acceptsMouseMovedEvents = true
occlusionStateValue.set(self.occlusionState)
isOpaque = true
self.contentView?.allowedTouchTypes = [.direct]
NotificationCenter.default.addObserver(self, selector: #selector(windowDidNeedSaveState(_:)), name: NSWindow.didMoveNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(windowDidNeedSaveState(_:)), name: NSWindow.didResizeNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(windowDidBecomeKey), name: NSWindow.didBecomeKeyNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(windowDidResignKey), name: NSWindow.didResignKeyNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(windowDidExitFullScreen(_:)), name: NSWindow.didExitFullScreenNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(windowDidChangeOcclusionState), name: NSWindow.didChangeOcclusionStateNotification, object: self)
}
public static var statusBarHeight: CGFloat {
return 22
}
}