Something went wrong. Try again.
🎥 Command line media player
Something went wrong. Try again.
Swift
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220/* * 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 var lastMouseDownEvent: NSEvent?
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) lastMouseDownEvent = 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
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 }}