mirror of https://github.com/mpv-player/mpv
cocoa-cb: change border and borderless window styling
the title bar is now within the window bounds instead of outside. same as QuickTime Player. it supports several standard styles, two dark and two light ones. additionally we have properly rounded corners now and the borderless window also has the proper window shadow. Also make the earliest supported macOS version 10.10. Fixes #4789, #3944
This commit is contained in:
parent
a4c436bac2
commit
938ad6ebc0
|
@ -4852,6 +4852,18 @@ The following video options are currently all specific to ``--vo=gpu`` and
|
|||
|
||||
OS X only.
|
||||
|
||||
``--macos-title-bar-style=<dark|ultradark|light|mediumlight|auto>``
|
||||
Sets the styling of the title bar (default: dark).
|
||||
OS X and cocoa-cb only
|
||||
|
||||
:dark: Dark title bar with vibrancy, a subtle blurring effect that
|
||||
dynamically blends the background (Video) into the title bar.
|
||||
:ultradark: Darker title bar with vibrancy (like QuickTime Player).
|
||||
:light: Bright title bar with vibrancy.
|
||||
:mediumlight: Less bright title bar with vibrancy.
|
||||
:auto: Detects the system settings and sets the title bar styling
|
||||
appropriately, either ultradark or mediumlight.
|
||||
|
||||
``--android-surface-size=<WxH>``
|
||||
Set dimensions of the rendering surface used by the Android gpu context.
|
||||
Needs to be set by the embedding application if the dimensions change during
|
||||
|
|
|
@ -87,6 +87,7 @@ extern const struct m_sub_options d3d11_conf;
|
|||
extern const struct m_sub_options d3d11va_conf;
|
||||
extern const struct m_sub_options angle_conf;
|
||||
extern const struct m_sub_options cocoa_conf;
|
||||
extern const struct m_sub_options macos_conf;
|
||||
extern const struct m_sub_options android_conf;
|
||||
|
||||
static const struct m_sub_options screenshot_conf = {
|
||||
|
@ -735,6 +736,10 @@ const m_option_t mp_opts[] = {
|
|||
OPT_SUBSTRUCT("", cocoa_opts, cocoa_conf, 0),
|
||||
#endif
|
||||
|
||||
#if HAVE_MACOS_COCOA_CB
|
||||
OPT_SUBSTRUCT("", macos_opts, macos_conf, 0),
|
||||
#endif
|
||||
|
||||
#if HAVE_ANDROID
|
||||
OPT_SUBSTRUCT("", android_opts, android_conf, 0),
|
||||
#endif
|
||||
|
|
|
@ -341,6 +341,7 @@ typedef struct MPOpts {
|
|||
struct d3d11_opts *d3d11_opts;
|
||||
struct d3d11va_opts *d3d11va_opts;
|
||||
struct cocoa_opts *cocoa_opts;
|
||||
struct macos_opts *macos_opts;
|
||||
struct android_opts *android_opts;
|
||||
struct dvd_opts *dvd_opts;
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ class MPVHelper: NSObject {
|
|||
mpv_observe_property(mpvHandle, 0, "ontop", MPV_FORMAT_FLAG)
|
||||
mpv_observe_property(mpvHandle, 0, "border", MPV_FORMAT_FLAG)
|
||||
mpv_observe_property(mpvHandle, 0, "keepaspect-window", MPV_FORMAT_FLAG)
|
||||
mpv_observe_property(mpvHandle, 0, "macos-title-bar-style", MPV_FORMAT_STRING)
|
||||
}
|
||||
|
||||
func setGLCB() {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "common/msg.h"
|
||||
#include "input/input.h"
|
||||
#include "player/client.h"
|
||||
#include "options/m_config.h"
|
||||
|
||||
#import "osdep/macosx_application_objc.h"
|
||||
#include "osdep/macosx_compat.h"
|
||||
|
@ -39,6 +40,21 @@
|
|||
|
||||
#define MPV_PROTOCOL @"mpv://"
|
||||
|
||||
struct macos_opts {
|
||||
int macos_title_bar_style;
|
||||
};
|
||||
|
||||
#define OPT_BASE_STRUCT struct macos_opts
|
||||
const struct m_sub_options macos_conf = {
|
||||
.opts = (const struct m_option[]) {
|
||||
OPT_CHOICE("macos-title-bar-style", macos_title_bar_style, 0,
|
||||
({"dark", 0}, {"ultradark", 1}, {"light", 2},
|
||||
{"mediumlight", 3}, {"auto", 4})),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct macos_opts),
|
||||
};
|
||||
|
||||
// Whether the NSApplication singleton was created. If this is false, we are
|
||||
// running in libmpv mode, and cocoa_main() was never called.
|
||||
static bool application_instantiated;
|
||||
|
|
|
@ -110,12 +110,14 @@ class EventsView: NSView {
|
|||
if mpv.getBoolProperty("input-cursor") {
|
||||
cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0)
|
||||
}
|
||||
cocoaCB.window.hideTitleBar()
|
||||
}
|
||||
|
||||
override func mouseMoved(with event: NSEvent) {
|
||||
if mpv != nil && mpv.getBoolProperty("input-cursor") {
|
||||
signalMouseMovement(event)
|
||||
}
|
||||
cocoaCB.window.showTitleBar()
|
||||
}
|
||||
|
||||
override func mouseDragged(with event: NSEvent) {
|
||||
|
@ -233,8 +235,7 @@ class EventsView: NSView {
|
|||
let menuBarHeight = NSApp.mainMenu!.menuBarHeight
|
||||
|
||||
if cocoaCB.window.isInFullscreen && (menuBarHeight > 0) {
|
||||
let titleBar = NSWindow.frameRect(forContentRect: CGRect.zero, styleMask: .titled)
|
||||
topMargin = titleBar.size.height + 1 + menuBarHeight
|
||||
topMargin = cocoaCB.window.titleBarHeight + 1 + menuBarHeight
|
||||
}
|
||||
|
||||
var vF = window!.screen!.frame
|
||||
|
@ -244,7 +245,11 @@ class EventsView: NSView {
|
|||
let vFV = convert(vFW, from: nil)
|
||||
let pt = convert(window!.mouseLocationOutsideOfEventStream, from: nil)
|
||||
|
||||
let clippedBounds = bounds.intersection(vFV)
|
||||
var clippedBounds = bounds.intersection(vFV)
|
||||
if !cocoaCB.window.isInFullscreen {
|
||||
clippedBounds.origin.y += cocoaCB.window.titleBarHeight
|
||||
clippedBounds.size.height -= cocoaCB.window.titleBarHeight
|
||||
}
|
||||
return clippedBounds.contains(pt)
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,21 @@ class Window: NSWindow, NSWindowDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
var border: Bool = true {
|
||||
didSet { if !border { hideTitleBar() } }
|
||||
}
|
||||
|
||||
var titleBarEffect: NSVisualEffectView?
|
||||
var titleBar: NSView {
|
||||
get { return (standardWindowButton(.closeButton)?.superview)! }
|
||||
}
|
||||
var titleBarHeight: CGFloat {
|
||||
get { return NSWindow.frameRect(forContentRect: CGRect.zero, styleMask: .titled).size.height }
|
||||
}
|
||||
var titleButtons: [NSButton] {
|
||||
get { return ([.closeButton, .miniaturizeButton, .zoomButton] as [NSWindow.ButtonType]).flatMap { standardWindowButton($0) } }
|
||||
}
|
||||
|
||||
override var canBecomeKey: Bool { return true }
|
||||
override var canBecomeMain: Bool { return true }
|
||||
|
||||
|
@ -95,6 +110,94 @@ class Window: NSWindow, NSWindowDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
func initTitleBar() {
|
||||
var f = contentView!.bounds
|
||||
f.origin.y = f.size.height - titleBarHeight
|
||||
f.size.height = titleBarHeight
|
||||
|
||||
styleMask.insert(.fullSizeContentView)
|
||||
titleBar.alphaValue = 0
|
||||
titlebarAppearsTransparent = true
|
||||
titleBarEffect = NSVisualEffectView(frame: f)
|
||||
titleBarEffect!.alphaValue = 0
|
||||
titleBarEffect!.blendingMode = .withinWindow
|
||||
titleBarEffect!.autoresizingMask = [.viewWidthSizable, .viewMinYMargin]
|
||||
|
||||
setTitleBarStyle(mpv.getStringProperty("macos-title-bar-style") ?? "dark")
|
||||
contentView!.addSubview(titleBarEffect!, positioned: .above, relativeTo: nil)
|
||||
|
||||
border = mpv.getBoolProperty("border")
|
||||
}
|
||||
|
||||
func setTitleBarStyle(_ style: String) {
|
||||
var effect = style
|
||||
if effect == "auto" {
|
||||
let systemStyle = UserDefaults.standard.string(forKey: "AppleInterfaceStyle")
|
||||
effect = systemStyle == nil ? "mediumlight" : "ultradark"
|
||||
}
|
||||
|
||||
switch effect {
|
||||
case "mediumlight":
|
||||
appearance = NSAppearance(named: NSAppearanceNameVibrantLight)
|
||||
titleBarEffect!.material = .titlebar
|
||||
titleBarEffect!.state = .followsWindowActiveState
|
||||
case "light":
|
||||
appearance = NSAppearance(named: NSAppearanceNameVibrantLight)
|
||||
titleBarEffect!.material = .light
|
||||
titleBarEffect!.state = .active
|
||||
case "ultradark":
|
||||
appearance = NSAppearance(named: NSAppearanceNameVibrantDark)
|
||||
titleBarEffect!.material = .titlebar
|
||||
titleBarEffect!.state = .followsWindowActiveState
|
||||
case "dark": fallthrough
|
||||
default:
|
||||
appearance = NSAppearance(named: NSAppearanceNameVibrantDark)
|
||||
titleBarEffect!.material = .dark
|
||||
titleBarEffect!.state = .active
|
||||
}
|
||||
}
|
||||
|
||||
func showTitleBar() {
|
||||
if !border && !isInFullscreen { return }
|
||||
let loc = cocoaCB.view.convert(mouseLocationOutsideOfEventStream, from: nil)
|
||||
|
||||
titleButtons.forEach { $0.isHidden = false }
|
||||
NSAnimationContext.runAnimationGroup({ (context) -> Void in
|
||||
context.duration = 0.20
|
||||
titleBar.animator().alphaValue = 1
|
||||
if !isInFullscreen && !isAnimating {
|
||||
titleBarEffect!.animator().alphaValue = 1
|
||||
}
|
||||
}, completionHandler: nil )
|
||||
|
||||
if loc.y > titleBarHeight {
|
||||
hideTitleBarDelayed()
|
||||
} else {
|
||||
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(hideTitleBar), object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func hideTitleBar() {
|
||||
if isInFullscreen && !isAnimating {
|
||||
titleBarEffect!.alphaValue = 0
|
||||
return
|
||||
}
|
||||
NSAnimationContext.runAnimationGroup({ (context) -> Void in
|
||||
context.duration = 0.20
|
||||
titleBar.animator().alphaValue = 0
|
||||
titleBarEffect!.animator().alphaValue = 0
|
||||
}, completionHandler: {
|
||||
self.titleButtons.forEach { $0.isHidden = true }
|
||||
})
|
||||
}
|
||||
|
||||
func hideTitleBarDelayed() {
|
||||
NSObject.cancelPreviousPerformRequests(withTarget: self,
|
||||
selector: #selector(hideTitleBar),
|
||||
object: nil)
|
||||
perform(#selector(hideTitleBar), with: nil, afterDelay: 0.5)
|
||||
}
|
||||
|
||||
override func toggleFullScreen(_ sender: Any?) {
|
||||
if isAnimating {
|
||||
return
|
||||
|
@ -146,6 +249,7 @@ class Window: NSWindow, NSWindowDelegate {
|
|||
let cRect = contentRect(forFrameRect: frame)
|
||||
var intermediateFrame = aspectFit(rect: cRect, in: targetScreen!.frame)
|
||||
intermediateFrame = frameRect(forContentRect: intermediateFrame)
|
||||
hideTitleBar()
|
||||
|
||||
NSAnimationContext.runAnimationGroup({ (context) -> Void in
|
||||
context.duration = duration - 0.05
|
||||
|
@ -156,6 +260,7 @@ class Window: NSWindow, NSWindowDelegate {
|
|||
func window(_ window: NSWindow, startCustomAnimationToExitFullScreenWithDuration duration: TimeInterval) {
|
||||
let newFrame = calculateWindowPosition(for: targetScreen!, withoutBounds: targetScreen == screen)
|
||||
let intermediateFrame = aspectFit(rect: newFrame, in: screen!.frame)
|
||||
hideTitleBar()
|
||||
setFrame(intermediateFrame, display: true)
|
||||
|
||||
NSAnimationContext.runAnimationGroup({ (context) -> Void in
|
||||
|
@ -169,6 +274,7 @@ class Window: NSWindow, NSWindowDelegate {
|
|||
cocoaCB.flagEvents(VO_EVENT_FULLSCREEN_STATE)
|
||||
cocoaCB.updateCusorVisibility()
|
||||
endAnimation(frame)
|
||||
showTitleBar()
|
||||
}
|
||||
|
||||
func windowDidExitFullScreen(_ notification: Notification) {
|
||||
|
@ -222,18 +328,6 @@ class Window: NSWindow, NSWindowDelegate {
|
|||
cocoaCB.layer.neededFlips += 1
|
||||
}
|
||||
|
||||
func setBorder(_ state: Bool) {
|
||||
if styleMask.contains(.titled) != state {
|
||||
if state {
|
||||
styleMask.remove(.borderless)
|
||||
styleMask.insert(.titled)
|
||||
} else {
|
||||
styleMask.remove(.titled)
|
||||
styleMask.insert(.borderless)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setOnTop(_ state: Bool) {
|
||||
if state {
|
||||
let ontopLevel = mpv.getStringProperty("ontop-level") ?? "window"
|
||||
|
|
|
@ -99,12 +99,12 @@ class CocoaCB: NSObject {
|
|||
screen: targetScreen, cocoaCB: self)
|
||||
win.title = window.title
|
||||
win.setOnTop(mpv.getBoolProperty("ontop"))
|
||||
win.setBorder(mpv.getBoolProperty("border"))
|
||||
win.keepAspect = mpv.getBoolProperty("keepaspect-window")
|
||||
window.close()
|
||||
window = win
|
||||
window.contentView!.addSubview(view)
|
||||
view.frame = window.contentView!.frame
|
||||
window.initTitleBar()
|
||||
|
||||
setAppIcon()
|
||||
window.isRestorable = false
|
||||
|
@ -486,7 +486,7 @@ class CocoaCB: NSObject {
|
|||
switch String(cString: property.name) {
|
||||
case "border":
|
||||
if let data = MPVHelper.mpvFlagToBool(property.data) {
|
||||
window.setBorder(data)
|
||||
window.border = data
|
||||
}
|
||||
case "ontop":
|
||||
if let data = MPVHelper.mpvFlagToBool(property.data) {
|
||||
|
@ -496,6 +496,10 @@ class CocoaCB: NSObject {
|
|||
if let data = MPVHelper.mpvFlagToBool(property.data) {
|
||||
window.keepAspect = data
|
||||
}
|
||||
case "macos-title-bar-style":
|
||||
if let data = MPVHelper.mpvStringArrayToString(property.data) {
|
||||
window.setTitleBarStyle(data)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ def __run(cmd):
|
|||
return ""
|
||||
|
||||
def __add_swift_flags(ctx):
|
||||
ctx.env.SWIFT_FLAGS = ('-frontend -c -sdk %s -enable-objc-interop -emit-objc-header'
|
||||
' -emit-module -parse-as-library') % (ctx.env.MACOS_SDK)
|
||||
ctx.env.SWIFT_FLAGS = ('-frontend -c -sdk %s -enable-objc-interop'
|
||||
' -emit-objc-header -parse-as-library'
|
||||
' -target x86_64-apple-macosx10.10') % (ctx.env.MACOS_SDK)
|
||||
swift_version = __run([ctx.env.SWIFT, '-version']).split(' ')[3].split('.')[:2]
|
||||
major, minor = [int(n) for n in swift_version]
|
||||
|
||||
|
@ -31,7 +32,6 @@ def __find_swift_library(ctx):
|
|||
'Toolchains/XcodeDefault.xctoolchain/usr/lib/swift_static/macosx',
|
||||
'usr/lib/swift_static/macosx'
|
||||
]
|
||||
dev_path = __run('xcode-select -p')[1:]
|
||||
dev_path = __run(['xcode-select', '-p'])[1:]
|
||||
|
||||
ctx.start_msg('Checking for Swift Library')
|
||||
|
|
Loading…
Reference in New Issue