From 938ad6ebc037ebb32b41619a31b15f8ade712867 Mon Sep 17 00:00:00 2001 From: Akemi Date: Fri, 16 Feb 2018 13:07:15 +0100 Subject: 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 --- DOCS/man/options.rst | 12 ++++ options/options.c | 5 ++ options/options.h | 1 + osdep/macOS_mpv_helper.swift | 1 + osdep/macosx_application.m | 16 +++++ video/out/cocoa-cb/events_view.swift | 11 +++- video/out/cocoa-cb/window.swift | 118 ++++++++++++++++++++++++++++++---- video/out/cocoa_cb_common.swift | 8 ++- waftools/detections/compiler_swift.py | 6 +- 9 files changed, 158 insertions(+), 20 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 1a5af8121a..2a2ca665c3 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4852,6 +4852,18 @@ The following video options are currently all specific to ``--vo=gpu`` and OS X only. +``--macos-title-bar-style=`` + 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=`` 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 diff --git a/options/options.c b/options/options.c index 2f4116299d..878f7be12f 100644 --- a/options/options.c +++ b/options/options.c @@ -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 diff --git a/options/options.h b/options/options.h index db5b92b86a..e76aa03db4 100644 --- a/options/options.h +++ b/options/options.h @@ -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; diff --git a/osdep/macOS_mpv_helper.swift b/osdep/macOS_mpv_helper.swift index 15081d0133..c8b9771ba6 100644 --- a/osdep/macOS_mpv_helper.swift +++ b/osdep/macOS_mpv_helper.swift @@ -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() { diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m index a65910ec9e..fe117f7a1c 100644 --- a/osdep/macosx_application.m +++ b/osdep/macosx_application.m @@ -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; diff --git a/video/out/cocoa-cb/events_view.swift b/video/out/cocoa-cb/events_view.swift index 4cb154c64a..e2da8345f1 100644 --- a/video/out/cocoa-cb/events_view.swift +++ b/video/out/cocoa-cb/events_view.swift @@ -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) } diff --git a/video/out/cocoa-cb/window.swift b/video/out/cocoa-cb/window.swift index 869bfb8be6..bd94330dcb 100644 --- a/video/out/cocoa-cb/window.swift +++ b/video/out/cocoa-cb/window.swift @@ -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" diff --git a/video/out/cocoa_cb_common.swift b/video/out/cocoa_cb_common.swift index cd43195a3e..c18bb29971 100644 --- a/video/out/cocoa_cb_common.swift +++ b/video/out/cocoa_cb_common.swift @@ -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 } diff --git a/waftools/detections/compiler_swift.py b/waftools/detections/compiler_swift.py index 81c71415f7..2e24362ecf 100644 --- a/waftools/detections/compiler_swift.py +++ b/waftools/detections/compiler_swift.py @@ -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') -- cgit v1.2.3