mirror of
https://github.com/mpv-player/mpv
synced 2025-02-16 12:17:12 +00:00
by default utilises the color space of the screen on which the window is located. if a specific value is defined, it will instead be utilised. depending on the chosen color space the macOS EDR (HDR) support is activated and that OS's transformation (tone mapping) is used. Fixes #7341
219 lines
7.1 KiB
Swift
219 lines
7.1 KiB
Swift
/*
|
|
* This file is part of mpv.
|
|
*
|
|
* mpv is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* mpv is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import Cocoa
|
|
|
|
class View: NSView, CALayerDelegate {
|
|
unowned var common: Common
|
|
var input: InputHelper? { return common.input }
|
|
|
|
var tracker: NSTrackingArea?
|
|
var hasMouseDown: Bool = false
|
|
|
|
override var isFlipped: Bool { return true }
|
|
override var acceptsFirstResponder: Bool { return true }
|
|
|
|
init(frame: NSRect, common com: Common) {
|
|
common = com
|
|
super.init(frame: frame)
|
|
autoresizingMask = [.width, .height]
|
|
wantsBestResolutionOpenGLSurface = true
|
|
wantsExtendedDynamicRangeOpenGLSurface = true
|
|
registerForDraggedTypes([ .fileURL, .URL, .string ])
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func updateTrackingAreas() {
|
|
if let tracker = self.tracker {
|
|
removeTrackingArea(tracker)
|
|
}
|
|
|
|
tracker = NSTrackingArea(rect: bounds,
|
|
options: [.activeAlways, .mouseEnteredAndExited, .mouseMoved, .enabledDuringMouseDrag],
|
|
owner: self, userInfo: nil)
|
|
// here tracker is guaranteed to be none-nil
|
|
addTrackingArea(tracker!)
|
|
|
|
if containsMouseLocation() {
|
|
input?.put(key: SWIFT_KEY_MOUSE_LEAVE)
|
|
}
|
|
}
|
|
|
|
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
|
|
guard let types = sender.draggingPasteboard.types else { return [] }
|
|
if types.contains(.fileURL) || types.contains(.URL) || types.contains(.string) {
|
|
return .copy
|
|
}
|
|
return []
|
|
}
|
|
|
|
func isURL(_ str: String) -> Bool {
|
|
guard let regex = try? NSRegularExpression(pattern: "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$",
|
|
options: .caseInsensitive) else {
|
|
return false
|
|
}
|
|
let isURL = regex.numberOfMatches(in: str,
|
|
options: [],
|
|
range: NSRange(location: 0, length: str.count))
|
|
return isURL > 0
|
|
}
|
|
|
|
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
|
|
let pb = sender.draggingPasteboard
|
|
guard let types = pb.types else { return false }
|
|
var files: [String] = []
|
|
|
|
if types.contains(.fileURL) || types.contains(.URL) {
|
|
guard let urls = pb.readObjects(forClasses: [NSURL.self]) as? [URL] else { return false }
|
|
files = urls.map { $0.absoluteString }
|
|
} else if types.contains(.string) {
|
|
guard let str = pb.string(forType: .string) else { return false }
|
|
files = str.components(separatedBy: "\n").compactMap {
|
|
let url = $0.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let path = (url as NSString).expandingTildeInPath
|
|
if isURL(url) { return url }
|
|
if path.starts(with: "/") { return path }
|
|
return nil
|
|
}
|
|
}
|
|
if files.isEmpty { return false }
|
|
input?.open(files: files)
|
|
return true
|
|
}
|
|
|
|
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
|
|
return true
|
|
}
|
|
|
|
override func becomeFirstResponder() -> Bool {
|
|
return true
|
|
}
|
|
|
|
override func resignFirstResponder() -> Bool {
|
|
return true
|
|
}
|
|
|
|
override func mouseEntered(with event: NSEvent) {
|
|
if input?.mouseEnabled() ?? true {
|
|
input?.put(key: SWIFT_KEY_MOUSE_ENTER)
|
|
}
|
|
common.updateCursorVisibility()
|
|
}
|
|
|
|
override func mouseExited(with event: NSEvent) {
|
|
if input?.mouseEnabled() ?? true {
|
|
input?.put(key: SWIFT_KEY_MOUSE_LEAVE)
|
|
}
|
|
common.titleBar?.hide()
|
|
common.setCursorVisibility(true)
|
|
}
|
|
|
|
override func mouseMoved(with event: NSEvent) {
|
|
signalMouseMovement(event)
|
|
common.titleBar?.show()
|
|
}
|
|
|
|
override func mouseDragged(with event: NSEvent) {
|
|
signalMouseMovement(event)
|
|
}
|
|
|
|
override func mouseDown(with event: NSEvent) {
|
|
hasMouseDown = event.clickCount <= 1
|
|
input?.processMouse(event: event)
|
|
}
|
|
|
|
override func mouseUp(with event: NSEvent) {
|
|
hasMouseDown = false
|
|
common.window?.isMoving = false
|
|
input?.processMouse(event: event)
|
|
}
|
|
|
|
override func rightMouseDown(with event: NSEvent) {
|
|
hasMouseDown = event.clickCount <= 1
|
|
input?.processMouse(event: event)
|
|
}
|
|
|
|
override func rightMouseUp(with event: NSEvent) {
|
|
hasMouseDown = false
|
|
input?.processMouse(event: event)
|
|
}
|
|
|
|
override func otherMouseDown(with event: NSEvent) {
|
|
hasMouseDown = event.clickCount <= 1
|
|
input?.processMouse(event: event)
|
|
}
|
|
|
|
override func otherMouseUp(with event: NSEvent) {
|
|
hasMouseDown = false
|
|
input?.processMouse(event: event)
|
|
}
|
|
|
|
override func magnify(with event: NSEvent) {
|
|
common.window?.isAnimating = event.phase != .ended
|
|
event.phase == .ended ? common.windowDidEndLiveResize() : common.windowWillStartLiveResize()
|
|
common.window?.addWindowScale(Double(event.magnification))
|
|
}
|
|
|
|
func signalMouseMovement(_ event: NSEvent) {
|
|
var point = convert(event.locationInWindow, from: nil)
|
|
point = convertToBacking(point)
|
|
point.y = -point.y
|
|
|
|
common.window?.updateMovableBackground(point)
|
|
if !(common.window?.isMoving ?? false) {
|
|
input?.setMouse(position: point)
|
|
}
|
|
}
|
|
|
|
override func scrollWheel(with event: NSEvent) {
|
|
input?.processWheel(event: event)
|
|
}
|
|
|
|
func containsMouseLocation() -> Bool {
|
|
var topMargin: CGFloat = 0.0
|
|
let menuBarHeight = NSApp.mainMenu?.menuBarHeight ?? 23.0
|
|
|
|
guard let window = common.window else { return false }
|
|
guard var vF = window.screen?.frame else { return false }
|
|
|
|
if window.isInFullscreen && (menuBarHeight > 0) {
|
|
topMargin = TitleBar.height + 1 + menuBarHeight
|
|
}
|
|
|
|
vF.size.height -= topMargin
|
|
|
|
let vFW = window.convertFromScreen(vF)
|
|
let vFV = convert(vFW, from: nil)
|
|
let pt = convert(window.mouseLocationOutsideOfEventStream, from: nil)
|
|
|
|
var clippedBounds = bounds.intersection(vFV)
|
|
if !window.isInFullscreen {
|
|
clippedBounds.origin.y += TitleBar.height
|
|
clippedBounds.size.height -= TitleBar.height
|
|
}
|
|
return clippedBounds.contains(pt)
|
|
}
|
|
|
|
func canHideCursor() -> Bool {
|
|
guard let window = common.window else { return false }
|
|
return !hasMouseDown && containsMouseLocation() && window.isKeyWindow
|
|
}
|
|
}
|