/* * 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 . */ import Cocoa class TitleBar: NSVisualEffectView { weak var cocoaCB: CocoaCB! = nil var mpv: MPVHelper! { get { return cocoaCB == nil ? nil : cocoaCB.mpv } } var systemBar: NSView { get { return (cocoaCB.window.standardWindowButton(.closeButton)?.superview)! } } static var height: CGFloat { get { return NSWindow.frameRect(forContentRect: CGRect.zero, styleMask: .titled).size.height } } var buttons: [NSButton] { get { return ([.closeButton, .miniaturizeButton, .zoomButton] as [NSWindowButton]).flatMap { cocoaCB.window.standardWindowButton($0) } } } override var material: NSVisualEffectView.Material { get { return super.material } set { super.material = newValue // fix for broken deprecated materials if material == .light || material == .dark { state = .active } else if #available(macOS 10.11, *), material == .mediumLight || material == .ultraDark { state = .active } else { state = .followsWindowActiveState } } } convenience init(frame: NSRect, window: NSWindow, cocoaCB ccb: CocoaCB) { let f = NSMakeRect(0, frame.size.height - TitleBar.height, frame.size.width, TitleBar.height) self.init(frame: f) cocoaCB = ccb alphaValue = 0 blendingMode = .withinWindow autoresizingMask = [.viewWidthSizable, .viewMinYMargin] systemBar.alphaValue = 0 state = .followsWindowActiveState window.contentView!.addSubview(self, positioned: .above, relativeTo: nil) window.titlebarAppearsTransparent = true window.styleMask.insert(.fullSizeContentView) set(appearance: Int(mpv.macOpts!.macos_title_bar_appearance)) set(material: Int(mpv.macOpts!.macos_title_bar_material)) } // catch these events so they are not propagated to the underlying view override func mouseDown(with event: NSEvent) { } override func mouseUp(with event: NSEvent) { if event.clickCount > 1 { let def = UserDefaults.standard var action = def.string(forKey: "AppleActionOnDoubleClick") // macOS 10.10 and earlier if action == nil { action = def.bool(forKey: "AppleMiniaturizeOnDoubleClick") == true ? "Minimize" : "Maximize" } if action == "Minimize" { cocoaCB.window.miniaturize(self) } else if action == "Maximize" { cocoaCB.window.zoom(self) } } } func set(appearance: Any) { if appearance is Int { window!.appearance = appearanceFrom(string: String(appearance as! Int)) } else { window!.appearance = appearanceFrom(string: appearance as! String) } } func set(material: Any) { if material is Int { self.material = materialFrom(string: String(material as! Int)) } else { self.material = materialFrom(string: material as! String) } } func show() { if (!cocoaCB.window.border && !cocoaCB.window.isInFullscreen) { return } let loc = cocoaCB.view.convert(cocoaCB.window.mouseLocationOutsideOfEventStream, from: nil) buttons.forEach { $0.isHidden = false } NSAnimationContext.runAnimationGroup({ (context) -> Void in context.duration = 0.20 systemBar.animator().alphaValue = 1 if !cocoaCB.window.isInFullscreen && !cocoaCB.window.isAnimating { animator().alphaValue = 1 isHidden = false } }, completionHandler: nil ) if loc.y > TitleBar.height { hideDelayed() } else { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(hide), object: nil) } } func hide() { if cocoaCB.window.isInFullscreen && !cocoaCB.window.isAnimating { alphaValue = 0 isHidden = true return } NSAnimationContext.runAnimationGroup({ (context) -> Void in context.duration = 0.20 systemBar.animator().alphaValue = 0 animator().alphaValue = 0 }, completionHandler: { self.buttons.forEach { $0.isHidden = true } self.isHidden = true }) } func hideDelayed() { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(hide), object: nil) perform(#selector(hide), with: nil, afterDelay: 0.5) } func appearanceFrom(string: String) -> NSAppearance? { switch string { case "1", "aqua": return NSAppearance(named: NSAppearanceNameAqua) case "3", "vibrantLight": return NSAppearance(named: NSAppearanceNameVibrantLight) case "4", "vibrantDark": return NSAppearance(named: NSAppearanceNameVibrantDark) default: break } if #available(macOS 10.14, *) { switch string { case "2", "darkAqua": return NSAppearance(named: NSAppearanceNameDarkAqua) case "5", "aquaHighContrast": return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastAqua) case "6", "darkAquaHighContrast": return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastDarkAqua) case "7", "vibrantLightHighContrast": return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastVibrantLight) case "8", "vibrantDarkHighContrast": return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastVibrantDark) case "0", "auto": fallthrough default: return nil } } let style = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") return appearanceFrom(string: style == nil ? "aqua" : "vibrantDark") } func materialFrom(string: String) -> NSVisualEffectView.Material { switch string { case "1", "selection": return .selection case "0", "titlebar": return .titlebar case "14", "dark": return .dark case "15", "light": return .light default: break } if #available(macOS 10.11, *) { switch string { case "2,", "menu": return .menu case "3", "popover": return .popover case "4", "sidebar": return .sidebar case "16", "mediumLight": return .mediumLight case "17", "ultraDark": return .ultraDark default: break } } if #available(macOS 10.14, *) { switch string { case "5,", "headerView": return .headerView case "6", "sheet": return .sheet case "7", "windowBackground": return .windowBackground case "8", "hudWindow": return .hudWindow case "9", "fullScreen": return .fullScreenUI case "10", "toolTip": return .toolTip case "11", "contentBackground": return .contentBackground case "12", "underWindowBackground": return .underWindowBackground case "13", "underPageBackground": return .underPageBackground default: break } } return .titlebar } }