mirror of https://github.com/mpv-player/mpv
cocoa: fullscreen refactoring
this replaces the old fullscreen with the native macOS fullscreen. additional the --fs-black-out-screens was removed since the new API doesn't support it in a way the old one did. it can possibly be re-added if done manually. Fixes #2857 #3272 #1352 #2062 #3864
This commit is contained in:
parent
870a6a11d9
commit
a8347eb9ba
|
@ -42,6 +42,7 @@ Interface changes
|
|||
been compiled-in)
|
||||
- --sub-codepage=<codepage> does not force the codepage anymore
|
||||
(this requires different and new syntax)
|
||||
- remove --fs-black-out-screens option for macOS
|
||||
--- mpv 0.22.0 ---
|
||||
- the "audio-device-list" property now sets empty device description to the
|
||||
device name as a fallback
|
||||
|
|
|
@ -2026,10 +2026,6 @@ Window
|
|||
|
||||
See also ``--screen``.
|
||||
|
||||
``--fs-black-out-screens``
|
||||
|
||||
OS X only. Black out other displays when going fullscreen.
|
||||
|
||||
``--keep-open=<yes|no|always>``
|
||||
Do not terminate when playing or seeking beyond the end of the file, and
|
||||
there is not next file to be played (and ``--loop`` is not used).
|
||||
|
|
|
@ -182,7 +182,6 @@ static const m_option_t mp_vo_opt_list[] = {
|
|||
({"default", -1})),
|
||||
OPT_CHOICE_OR_INT("fs-screen", fsscreen_id, 0, 0, 32,
|
||||
({"all", -2}, {"current", -1})),
|
||||
OPT_FLAG("fs-black-out-screens", fs_black_out_screens, 0),
|
||||
OPT_FLAG("keepaspect", keepaspect, UPDATE_VIDEOPOS),
|
||||
OPT_FLAG("keepaspect-window", keepaspect_window, 0),
|
||||
OPT_FLAG("hidpi-window-scale", hidpi_window_scale, 0),
|
||||
|
@ -796,6 +795,7 @@ const m_option_t mp_opts[] = {
|
|||
OPT_REPLACED("ass-shaper", "sub-ass-shaper"),
|
||||
OPT_REPLACED("ass-style-override", "sub-ass-style-override"),
|
||||
OPT_REPLACED("ass-scale-with-window", "sub-ass-scale-with-window"),
|
||||
OPT_REMOVED("fs-black-out-screens", NULL),
|
||||
|
||||
{0}
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@ typedef struct mp_vo_opts {
|
|||
|
||||
int screen_id;
|
||||
int fsscreen_id;
|
||||
int fs_black_out_screens;
|
||||
char *winname;
|
||||
int x11_netwm;
|
||||
int x11_bypass_compositor;
|
||||
|
|
|
@ -31,6 +31,7 @@ static const NSWindowStyleMask NSWindowStyleMaskTitled = NSTitledWindowMask;
|
|||
static const NSWindowStyleMask NSWindowStyleMaskMiniaturizable = NSMiniaturizableWindowMask;
|
||||
static const NSWindowStyleMask NSWindowStyleMaskResizable = NSResizableWindowMask;
|
||||
static const NSWindowStyleMask NSWindowStyleMaskBorderless = NSBorderlessWindowMask;
|
||||
static const NSWindowStyleMask NSWindowStyleMaskFullScreen = NSFullScreenWindowMask;
|
||||
|
||||
static const NSEventType NSEventTypeSystemDefined = NSSystemDefined;
|
||||
static const NSEventType NSEventTypeKeyDown = NSKeyDown;
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
@interface MpvEventsView : NSView <NSDraggingDestination>
|
||||
@property(nonatomic, retain) MpvCocoaAdapter *adapter;
|
||||
- (void)setFullScreen:(BOOL)willBeFullscreen;
|
||||
- (void)clear;
|
||||
- (BOOL)canHideCursor;
|
||||
- (void)signalMousePosition;
|
||||
@end
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
@property(nonatomic, assign) BOOL clearing;
|
||||
@property(nonatomic, assign) BOOL hasMouseDown;
|
||||
@property(nonatomic, retain) NSTrackingArea *tracker;
|
||||
- (BOOL)hasDock:(NSScreen*)screen;
|
||||
- (BOOL)hasMenubar:(NSScreen*)screen;
|
||||
- (int)mpvButtonNumber:(NSEvent*)event;
|
||||
- (void)mouseDownEvent:(NSEvent *)event;
|
||||
- (void)mouseUpEvent:(NSEvent *)event;
|
||||
|
@ -51,54 +49,6 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)setFullScreen:(BOOL)willBeFullscreen
|
||||
{
|
||||
if (willBeFullscreen && ![self isInFullScreenMode]) {
|
||||
NSApplicationPresentationOptions popts =
|
||||
NSApplicationPresentationDefault;
|
||||
|
||||
if ([self hasMenubar:[self.adapter fsScreen]])
|
||||
// Cocoa raises an exception when autohiding the menubar but
|
||||
// not the dock. They probably got bored while programming the
|
||||
// multi screen support and took some shortcuts (tested on 10.8).
|
||||
popts |= NSApplicationPresentationAutoHideMenuBar |
|
||||
NSApplicationPresentationAutoHideDock;
|
||||
|
||||
if ([self hasDock:[self.adapter fsScreen]])
|
||||
popts |= NSApplicationPresentationAutoHideDock;
|
||||
|
||||
NSDictionary *fsopts = @{
|
||||
NSFullScreenModeAllScreens : @([self.adapter fsModeAllScreens]),
|
||||
NSFullScreenModeApplicationPresentationOptions : @(popts)
|
||||
};
|
||||
|
||||
// The original "windowed" window will stay around since sending a
|
||||
// view fullscreen wraps it in another window. This is noticeable when
|
||||
// sending the View fullscreen to another screen. Make it go away
|
||||
// manually.
|
||||
[self.window orderOut:self];
|
||||
|
||||
[self enterFullScreenMode:[self.adapter fsScreen]
|
||||
withOptions:fsopts];
|
||||
}
|
||||
|
||||
if (!willBeFullscreen && [self isInFullScreenMode]) {
|
||||
[self exitFullScreenModeWithOptions:nil];
|
||||
|
||||
// Show the "windowed" window again.
|
||||
[self.window makeKeyAndOrderFront:self];
|
||||
[self.window makeFirstResponder:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clear
|
||||
{
|
||||
if ([self isInFullScreenMode]) {
|
||||
self.clearing = YES;
|
||||
[self exitFullScreenModeWithOptions:nil];
|
||||
}
|
||||
}
|
||||
|
||||
// mpv uses flipped coordinates, because X11 uses those. So let's just use them
|
||||
// as well without having to do any coordinate conversion of mouse positions.
|
||||
- (BOOL)isFlipped { return YES; }
|
||||
|
@ -379,27 +329,6 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)hasDock:(NSScreen*)screen
|
||||
{
|
||||
NSRect vF = [screen visibleFrame];
|
||||
NSRect f = [screen frame];
|
||||
return
|
||||
// The visible frame's width is smaller: dock is on left or right end
|
||||
// of this method's receiver.
|
||||
vF.size.width < f.size.width ||
|
||||
// The visible frame's veritical origin is bigger: dock is
|
||||
// on the bottom of this method's receiver.
|
||||
vF.origin.y > f.origin.y;
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)hasMenubar:(NSScreen*)screen
|
||||
{
|
||||
NSRect vF = [screen visibleFrame];
|
||||
NSRect f = [screen frame];
|
||||
return f.size.height + f.origin.y > vF.size.height + vF.origin.y;
|
||||
}
|
||||
|
||||
- (int)mpvButtonNumber:(NSEvent*)event
|
||||
{
|
||||
int buttonNumber = [event buttonNumber];
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
- (void)putAxis:(int)mpkey delta:(float)delta;
|
||||
- (void)putCommand:(char*)cmd;
|
||||
- (void)handleFilesArray:(NSArray *)files;
|
||||
- (void)didChangeWindowedScreenProfile:(NSScreen *)screen;
|
||||
- (void)didChangeWindowedScreenProfile:(NSNotification *)notification;
|
||||
- (void)performAsyncResize:(NSSize)size;
|
||||
- (void)didChangeMousePosition;
|
||||
|
||||
- (BOOL)isInFullScreenMode;
|
||||
- (BOOL)keyboardEnabled;
|
||||
- (BOOL)mouseEnabled;
|
||||
- (NSScreen *)fsScreen;
|
||||
- (BOOL)fsModeAllScreens;
|
||||
|
||||
- (NSScreen *)getTargetScreen;
|
||||
@property(nonatomic, assign) struct vo *vout;
|
||||
@end
|
||||
|
|
|
@ -26,15 +26,25 @@
|
|||
#include "window.h"
|
||||
|
||||
@interface MpvVideoWindow()
|
||||
@property(nonatomic, retain) NSScreen *targetScreen;
|
||||
@property(nonatomic, retain) NSScreen *previousScreen;
|
||||
@property(nonatomic, retain) NSScreen *currentScreen;
|
||||
|
||||
- (NSRect)frameRect:(NSRect)frameRect forCenteredContentSize:(NSSize)newSize;
|
||||
- (void)setCenteredContentSize:(NSSize)newSize;
|
||||
@end
|
||||
|
||||
@implementation MpvVideoWindow {
|
||||
NSSize _queued_video_size;
|
||||
NSRect _unfs_content_frame;
|
||||
NSRect _unfs_screen_frame;
|
||||
int _is_animating;
|
||||
}
|
||||
|
||||
@synthesize adapter = _adapter;
|
||||
@synthesize targetScreen = _target_screen;
|
||||
@synthesize previousScreen = _previous_screen;
|
||||
@synthesize currentScreen = _current_screen;
|
||||
- (id)initWithContentRect:(NSRect)content_rect
|
||||
styleMask:(NSUInteger)style_mask
|
||||
backing:(NSBackingStoreType)buffering_type
|
||||
|
@ -46,10 +56,96 @@
|
|||
defer:flag]) {
|
||||
[self setBackgroundColor:[NSColor blackColor]];
|
||||
[self setMinSize:NSMakeSize(50,50)];
|
||||
[self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
self.targetScreen = [self screen];
|
||||
self.currentScreen = [self screen];
|
||||
_is_animating = 0;
|
||||
_unfs_content_frame = [self convertRectToScreen:[[self contentView] frame]];
|
||||
_unfs_screen_frame = [[self screen] frame];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)toggleFullScreen:(id)sender
|
||||
{
|
||||
if (_is_animating)
|
||||
return;
|
||||
|
||||
_is_animating = 1;
|
||||
|
||||
self.targetScreen = [self.adapter getTargetScreen];
|
||||
if(![self targetScreen] && ![self previousScreen]) {
|
||||
self.targetScreen = [self screen];
|
||||
} else if (![self targetScreen]) {
|
||||
self.targetScreen = self.previousScreen;
|
||||
self.previousScreen = nil;
|
||||
} else {
|
||||
self.previousScreen = [self screen];
|
||||
}
|
||||
|
||||
if (![self.adapter isInFullScreenMode]) {
|
||||
_unfs_content_frame = [self convertRectToScreen:[[self contentView] frame]];
|
||||
_unfs_screen_frame = [[self screen] frame];
|
||||
}
|
||||
|
||||
//move window to target screen when going to fullscreen
|
||||
if (![self.adapter isInFullScreenMode] && ![[self targetScreen] isEqual:[self screen]]) {
|
||||
[self setFrame:[self calculateWindowPositionForScreen:[self targetScreen]] display:YES];
|
||||
}
|
||||
|
||||
[super toggleFullScreen:sender];
|
||||
|
||||
if (![self.adapter isInFullScreenMode]) {
|
||||
[self setStyleMask:([self styleMask] | NSWindowStyleMaskFullScreen)];
|
||||
NSRect frame = [[self targetScreen] frame];
|
||||
[self setFrame:frame display:YES];
|
||||
} else {
|
||||
[self setStyleMask:([self styleMask] & ~NSWindowStyleMaskFullScreen)];
|
||||
NSRect frame = [self calculateWindowPositionForScreen:[self targetScreen]];
|
||||
[self setFrame:frame display:YES];
|
||||
[self setContentAspectRatio:_unfs_content_frame.size];
|
||||
[self setCenteredContentSize:_unfs_content_frame.size];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window
|
||||
{
|
||||
return [NSArray arrayWithObject:window];
|
||||
}
|
||||
|
||||
- (NSArray*)customWindowsToExitFullScreenForWindow:(NSWindow*)window
|
||||
{
|
||||
return [NSArray arrayWithObject:window];
|
||||
}
|
||||
|
||||
// we still need to keep those around or it will use the standard animation
|
||||
- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration {}
|
||||
|
||||
- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration {}
|
||||
|
||||
- (void)windowDidEnterFullScreen:(NSNotification *)notification
|
||||
{
|
||||
_is_animating = 0;
|
||||
[self.adapter windowDidEnterFullScreen:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification *)notification
|
||||
{
|
||||
_is_animating = 0;
|
||||
[self.adapter windowDidExitFullScreen:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidFailToEnterFullScreen:(NSWindow *)window
|
||||
{
|
||||
_is_animating = 0;
|
||||
}
|
||||
|
||||
- (void)windowDidFailToExitFullScreen:(NSWindow *)window
|
||||
{
|
||||
_is_animating = 0;
|
||||
}
|
||||
|
||||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
|
||||
{
|
||||
// XXX: we maybe only need expose for this
|
||||
|
@ -58,12 +154,18 @@
|
|||
|
||||
- (void)windowDidChangeScreen:(NSNotification *)notification
|
||||
{
|
||||
//this event doesn't exclusively trigger on screen change
|
||||
//examples: screen reconfigure, toggling fullscreen
|
||||
if (!_is_animating && ![[self currentScreen] isEqual:[self screen]]) {
|
||||
self.previousScreen = [self screen];
|
||||
}
|
||||
self.currentScreen = [self screen];
|
||||
[self.adapter windowDidChangeScreen:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidChangeScreenProfile:(NSNotification *)notification
|
||||
{
|
||||
[self.adapter didChangeWindowedScreenProfile:[self screen]];
|
||||
[self.adapter didChangeWindowedScreenProfile:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
|
@ -125,8 +227,41 @@
|
|||
animate:NO];
|
||||
}
|
||||
|
||||
- (NSRect)calculateWindowPositionForScreen:(NSScreen *)screen
|
||||
{
|
||||
NSRect frame = [self frameRectForContentRect:_unfs_content_frame];
|
||||
NSRect targetFrame = [screen frame];
|
||||
|
||||
CGFloat x_per = (_unfs_screen_frame.size.width - frame.size.width);
|
||||
CGFloat y_per = (_unfs_screen_frame.size.height - frame.size.height);
|
||||
if (x_per > 0) x_per = (frame.origin.x - _unfs_screen_frame.origin.x)/x_per;
|
||||
if (y_per > 0) y_per = (frame.origin.y - _unfs_screen_frame.origin.y)/y_per;
|
||||
|
||||
frame.origin.x = targetFrame.origin.x +
|
||||
(targetFrame.size.width - frame.size.width)*x_per;
|
||||
frame.origin.y = targetFrame.origin.y +
|
||||
(targetFrame.size.height - frame.size.height)*y_per;
|
||||
|
||||
//screen bounds right and left
|
||||
if (frame.origin.x + frame.size.width > targetFrame.origin.x + targetFrame.size.width)
|
||||
frame.origin.x = targetFrame.origin.x + targetFrame.size.width - frame.size.width;
|
||||
if (frame.origin.x < targetFrame.origin.x)
|
||||
frame.origin.x = targetFrame.origin.x;
|
||||
|
||||
//screen bounds top and bottom
|
||||
if (frame.origin.y + frame.size.height > targetFrame.origin.y + targetFrame.size.height)
|
||||
frame.origin.y = targetFrame.origin.y + targetFrame.size.height - frame.size.height;
|
||||
if (frame.origin.y < targetFrame.origin.y)
|
||||
frame.origin.y = targetFrame.origin.y;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (NSRect)constrainFrameRect:(NSRect)nf toScreen:(NSScreen *)screen
|
||||
{
|
||||
if (_is_animating)
|
||||
screen = [self targetScreen];
|
||||
|
||||
NSRect of = [self frame];
|
||||
NSRect vf = [screen ?: self.screen ?: [NSScreen mainScreen] visibleFrame];
|
||||
NSRect ncf = [self contentRectForFrameRect:nf];
|
||||
|
@ -136,7 +271,7 @@
|
|||
if (NSMaxY(nf) > NSMaxY(vf))
|
||||
nf.origin.y = NSMaxY(vf) - NSHeight(nf);
|
||||
|
||||
// Prevent the window's titlebar from exiting the screen on the top edge.
|
||||
// Prevent the window's titlebar from exiting the screen on the bottom edge.
|
||||
if (NSMaxY(ncf) < NSMinY(vf))
|
||||
nf.origin.y = NSMinY(vf) + NSMinY(ncf) - NSMaxY(ncf);
|
||||
|
||||
|
@ -157,30 +292,42 @@
|
|||
return nf;
|
||||
}
|
||||
|
||||
- (void)windowWillStartLiveResize:(NSNotification *)notification
|
||||
{
|
||||
[self.adapter windowWillStartLiveResize:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidEndLiveResize:(NSNotification *)notification
|
||||
{
|
||||
[self.adapter windowDidEndLiveResize:notification];
|
||||
[self setFrame:[self constrainFrameRect:self.frame toScreen:self.screen]
|
||||
display:NO];
|
||||
}
|
||||
|
||||
- (void)updateWindowFrame:(NSSize)newSize
|
||||
{
|
||||
_unfs_content_frame = [self frameRect:_unfs_content_frame forCenteredContentSize:newSize];
|
||||
}
|
||||
|
||||
- (void)tryDequeueSize {
|
||||
if (_queued_video_size.width <= 0.0 || _queued_video_size.height <= 0.0)
|
||||
return;
|
||||
|
||||
// XXX find a way to kill this state
|
||||
if (![self.adapter isInFullScreenMode]) {
|
||||
[self setContentAspectRatio:_queued_video_size];
|
||||
[self setCenteredContentSize:_queued_video_size];
|
||||
_queued_video_size = NSZeroSize;
|
||||
}
|
||||
[self setContentAspectRatio:_queued_video_size];
|
||||
[self setCenteredContentSize:_queued_video_size];
|
||||
_queued_video_size = NSZeroSize;
|
||||
}
|
||||
|
||||
- (void)queueNewVideoSize:(NSSize)new_size
|
||||
- (void)queueNewVideoSize:(NSSize)newSize
|
||||
{
|
||||
if (NSEqualSizes(_queued_video_size, new_size))
|
||||
return;
|
||||
_queued_video_size = new_size;
|
||||
[self tryDequeueSize];
|
||||
if ([self.adapter isInFullScreenMode]) {
|
||||
[self updateWindowFrame:newSize];
|
||||
} else {
|
||||
if (NSEqualSizes(_queued_video_size, newSize))
|
||||
return;
|
||||
_queued_video_size = newSize;
|
||||
[self tryDequeueSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeMain:(NSNotification *)notification {
|
||||
|
|
|
@ -49,11 +49,10 @@
|
|||
|
||||
#include "common/msg.h"
|
||||
|
||||
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
|
||||
const CVTimeStamp* outputTime, CVOptionFlags flagsIn,
|
||||
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
|
||||
const CVTimeStamp* outputTime, CVOptionFlags flagsIn,
|
||||
CVOptionFlags* flagsOut, void* displayLinkContext);
|
||||
static int vo_cocoa_fullscreen(struct vo *vo);
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s);
|
||||
static void cocoa_add_screen_reconfiguration_observer(struct vo *vo);
|
||||
static void cocoa_rm_screen_reconfiguration_observer(struct vo *vo);
|
||||
|
||||
|
@ -70,15 +69,13 @@ struct vo_cocoa_state {
|
|||
NSOpenGLContext *nsgl_ctx;
|
||||
|
||||
NSScreen *current_screen;
|
||||
NSScreen *fs_screen;
|
||||
double screen_fps;
|
||||
|
||||
NSInteger window_level;
|
||||
int fullscreen;
|
||||
|
||||
bool embedded; // wether we are embedding in another GUI
|
||||
|
||||
atomic_bool waiting_frame;
|
||||
|
||||
IOPMAssertionID power_mgmt_assertion;
|
||||
io_connect_t light_sensor;
|
||||
uint64_t last_lmuvalue;
|
||||
|
@ -90,8 +87,6 @@ struct vo_cocoa_state {
|
|||
uint32_t old_dwidth;
|
||||
uint32_t old_dheight;
|
||||
|
||||
id fs_icc_changed_ns_observer;
|
||||
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t wakeup;
|
||||
|
||||
|
@ -122,14 +117,11 @@ static void queue_new_video_size(struct vo *vo, int w, int h)
|
|||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
if ([s->window conformsToProtocol: @protocol(MpvSizing)]) {
|
||||
id<MpvSizing> win = (id<MpvSizing>) s->window;
|
||||
NSRect r = NSMakeRect(0, 0, w, h);
|
||||
if(!opts->hidpi_window_scale) {
|
||||
r = [s->current_screen convertRectFromBacking:r];
|
||||
}
|
||||
[win queueNewVideoSize:NSMakeSize(r.size.width, r.size.height)];
|
||||
}
|
||||
id<MpvSizing> win = (id<MpvSizing>) s->window;
|
||||
NSRect r = NSMakeRect(0, 0, w, h);
|
||||
if(!opts->hidpi_window_scale)
|
||||
r = [s->current_screen convertRectFromBacking:r];
|
||||
[win queueNewVideoSize:NSMakeSize(r.size.width, r.size.height)];
|
||||
}
|
||||
|
||||
static void flag_events(struct vo *vo, int events)
|
||||
|
@ -258,6 +250,39 @@ static void cocoa_uninit_light_sensor(struct vo_cocoa_state *s)
|
|||
}
|
||||
}
|
||||
|
||||
static NSScreen *get_screen_by_id(struct vo *vo, int screen_id)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
||||
NSArray *screens = [NSScreen screens];
|
||||
int n_of_displays = [screens count];
|
||||
if (screen_id >= n_of_displays) {
|
||||
MP_INFO(s, "Screen ID %d does not exist, falling back to main "
|
||||
"device\n", screen_id);
|
||||
return nil;
|
||||
} else if (screen_id < 0) {
|
||||
return nil;
|
||||
}
|
||||
return [screens objectAtIndex:(screen_id)];
|
||||
}
|
||||
|
||||
static void vo_cocoa_update_screen_info(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
if (s->embedded)
|
||||
return;
|
||||
|
||||
if (s->current_screen && s->window) {
|
||||
s->current_screen = [s->window screen];
|
||||
} else if (!s->current_screen) {
|
||||
s->current_screen = get_screen_by_id(vo, opts->screen_id);
|
||||
if (!s->current_screen)
|
||||
s->current_screen = [NSScreen mainScreen];
|
||||
}
|
||||
}
|
||||
|
||||
void vo_cocoa_init(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state);
|
||||
|
@ -265,6 +290,7 @@ void vo_cocoa_init(struct vo *vo)
|
|||
.power_mgmt_assertion = kIOPMNullAssertionID,
|
||||
.log = mp_log_new(s, vo->log, "cocoa"),
|
||||
.embedded = vo->opts->WinID >= 0,
|
||||
.fullscreen = 0,
|
||||
};
|
||||
if (!s->embedded) {
|
||||
NSImage* blankImage = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
|
||||
|
@ -274,6 +300,7 @@ void vo_cocoa_init(struct vo *vo)
|
|||
pthread_mutex_init(&s->lock, NULL);
|
||||
pthread_cond_init(&s->wakeup, NULL);
|
||||
vo->cocoa = s;
|
||||
vo_cocoa_update_screen_info(vo);
|
||||
cocoa_init_light_sensor(vo);
|
||||
cocoa_add_screen_reconfiguration_observer(vo);
|
||||
if (!s->embedded) {
|
||||
|
@ -314,7 +341,6 @@ void vo_cocoa_uninit(struct vo *vo)
|
|||
run_on_main_thread(vo, ^{
|
||||
enable_power_management(s);
|
||||
cocoa_uninit_light_sensor(s);
|
||||
cocoa_rm_fs_screen_profile_observer(s);
|
||||
cocoa_rm_screen_reconfiguration_observer(vo);
|
||||
|
||||
[s->nsgl_ctx release];
|
||||
|
@ -325,12 +351,13 @@ void vo_cocoa_uninit(struct vo *vo)
|
|||
[s->video removeFromSuperview];
|
||||
|
||||
[s->view removeFromSuperview];
|
||||
[(MpvEventsView *)s->view clear];
|
||||
[s->view release];
|
||||
|
||||
// if using --wid + libmpv there's no window to release
|
||||
if (s->window)
|
||||
[s->window release];
|
||||
if (s->window) {
|
||||
[s->window setDelegate:nil];
|
||||
[s->window close];
|
||||
}
|
||||
|
||||
if (!s->embedded)
|
||||
[s->blankCursor release];
|
||||
|
@ -341,44 +368,11 @@ void vo_cocoa_uninit(struct vo *vo)
|
|||
});
|
||||
}
|
||||
|
||||
static int get_screen_handle(struct vo *vo, int identifier, NSWindow *window,
|
||||
NSScreen **screen) {
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
NSArray *screens = [NSScreen screens];
|
||||
int n_of_displays = [screens count];
|
||||
|
||||
if (identifier >= n_of_displays) { // check if the identifier is out of bounds
|
||||
MP_INFO(s, "Screen ID %d does not exist, falling back to main "
|
||||
"device\n", identifier);
|
||||
identifier = -1;
|
||||
}
|
||||
|
||||
if (identifier < 0) {
|
||||
// default behaviour gets either the window screen or the main screen
|
||||
// if window is not available
|
||||
if (! (*screen = [window screen]) )
|
||||
*screen = [screens objectAtIndex:0];
|
||||
return 0;
|
||||
} else {
|
||||
*screen = [screens objectAtIndex:(identifier)];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void vo_cocoa_update_screens_pointers(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
get_screen_handle(vo, opts->screen_id, s->window, &s->current_screen);
|
||||
get_screen_handle(vo, opts->fsscreen_id, s->window, &s->fs_screen);
|
||||
}
|
||||
|
||||
static void vo_cocoa_update_screen_fps(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
||||
NSScreen *screen = vo->opts->fullscreen ? s->fs_screen : s->current_screen;
|
||||
NSDictionary* sinfo = [screen deviceDescription];
|
||||
NSDictionary* sinfo = [s->current_screen deviceDescription];
|
||||
NSNumber* sid = [sinfo objectForKey:@"NSScreenNumber"];
|
||||
CGDirectDisplayID did = [sid longValue];
|
||||
|
||||
|
@ -416,21 +410,6 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
static void vo_cocoa_update_screen_info(struct vo *vo, struct mp_rect *out_rc)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
||||
if (s->embedded)
|
||||
return;
|
||||
|
||||
vo_cocoa_update_screens_pointers(vo);
|
||||
|
||||
if (out_rc) {
|
||||
NSRect r = [s->current_screen frame];
|
||||
*out_rc = (struct mp_rect){0, 0, r.size.width, r.size.height};
|
||||
}
|
||||
}
|
||||
|
||||
static void vo_set_level(struct vo *vo, int ontop)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
@ -553,40 +532,12 @@ static int cocoa_set_window_title(struct vo *vo)
|
|||
return VO_TRUE;
|
||||
}
|
||||
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:s->fs_icc_changed_ns_observer];
|
||||
}
|
||||
|
||||
static void cocoa_add_fs_screen_profile_observer(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
||||
if (s->fs_icc_changed_ns_observer)
|
||||
cocoa_rm_fs_screen_profile_observer(s);
|
||||
|
||||
if (vo->opts->fsscreen_id < 0)
|
||||
return;
|
||||
|
||||
void (^nblock)(NSNotification *n) = ^(NSNotification *n) {
|
||||
flag_events(vo, VO_EVENT_ICC_PROFILE_CHANGED);
|
||||
};
|
||||
|
||||
s->fs_icc_changed_ns_observer = [[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:NSScreenColorSpaceDidChangeNotification
|
||||
object:s->fs_screen
|
||||
queue:nil
|
||||
usingBlock:nblock];
|
||||
}
|
||||
|
||||
static void cocoa_screen_reconfiguration_observer(
|
||||
CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *ctx)
|
||||
{
|
||||
if (flags & kCGDisplaySetModeFlag) {
|
||||
struct vo *vo = ctx;
|
||||
MP_WARN(vo, "detected display mode change, updating screen info\n");
|
||||
vo_cocoa_update_screen_info(vo, NULL);
|
||||
vo_cocoa_update_screen_fps(vo);
|
||||
}
|
||||
}
|
||||
|
@ -615,11 +566,13 @@ void vo_cocoa_set_opengl_ctx(struct vo *vo, CGLContextObj ctx)
|
|||
int vo_cocoa_config_window(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
run_on_main_thread(vo, ^{
|
||||
struct mp_rect screenrc;
|
||||
vo_cocoa_update_screen_info(vo, &screenrc);
|
||||
vo_cocoa_update_screen_fps(vo);
|
||||
|
||||
NSRect r = [s->current_screen frame];
|
||||
struct mp_rect screenrc = {0, 0, r.size.width, r.size.height};
|
||||
struct vo_win_geometry geo;
|
||||
vo_calc_window_geometry(vo, &screenrc, &geo);
|
||||
vo_apply_window_geometry(vo, &geo);
|
||||
|
@ -638,10 +591,10 @@ int vo_cocoa_config_window(struct vo *vo)
|
|||
if (!s->embedded && s->window) {
|
||||
if (reset_size)
|
||||
queue_new_video_size(vo, width, height);
|
||||
vo_cocoa_fullscreen(vo);
|
||||
cocoa_add_fs_screen_profile_observer(vo);
|
||||
if (opts->fullscreen && !s->fullscreen)
|
||||
vo_cocoa_fullscreen(vo);
|
||||
cocoa_set_window_title(vo);
|
||||
vo_set_level(vo, vo->opts->ontop);
|
||||
vo_set_level(vo, opts->ontop);
|
||||
|
||||
GLint o;
|
||||
if (!CGLGetParameter(s->cgl_ctx, kCGLCPSurfaceOpacity, &o) && !o) {
|
||||
|
@ -691,9 +644,6 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height)
|
|||
|
||||
pthread_mutex_lock(&s->lock);
|
||||
|
||||
// Make vo.c not do video timing, which would slow down resizing.
|
||||
vo_event(vo, VO_EVENT_LIVE_RESIZING);
|
||||
|
||||
// Wait until a new frame with the new size was rendered. For some reason,
|
||||
// Cocoa requires this to be done before drawRect() returns.
|
||||
struct timespec e = mp_time_us_to_timespec(mp_add_timeout(mp_time_us(), 0.1));
|
||||
|
@ -702,18 +652,9 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height)
|
|||
break;
|
||||
}
|
||||
|
||||
vo_query_and_reset_events(vo, VO_EVENT_LIVE_RESIZING);
|
||||
|
||||
pthread_mutex_unlock(&s->lock);
|
||||
}
|
||||
|
||||
static void draw_changes_after_next_frame(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
if (atomic_compare_exchange_strong(&s->waiting_frame, &(bool){false}, true))
|
||||
NSDisableScreenUpdates();
|
||||
}
|
||||
|
||||
void vo_cocoa_swap_buffers(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
@ -730,9 +671,6 @@ void vo_cocoa_swap_buffers(struct vo *vo)
|
|||
s->frame_h = vo->dheight;
|
||||
pthread_cond_signal(&s->wakeup);
|
||||
pthread_mutex_unlock(&s->lock);
|
||||
|
||||
if (atomic_compare_exchange_strong(&s->waiting_frame, &(bool){true}, false))
|
||||
NSEnableScreenUpdates();
|
||||
}
|
||||
|
||||
static int vo_cocoa_check_events(struct vo *vo)
|
||||
|
@ -754,25 +692,14 @@ static int vo_cocoa_check_events(struct vo *vo)
|
|||
static int vo_cocoa_fullscreen(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
if (s->embedded)
|
||||
return VO_NOTIMPL;
|
||||
|
||||
vo_cocoa_update_screen_info(vo, NULL);
|
||||
|
||||
draw_changes_after_next_frame(vo);
|
||||
[(MpvEventsView *)s->view setFullScreen:opts->fullscreen];
|
||||
|
||||
if ([s->view window] != s->window) {
|
||||
// cocoa implements fullscreen views by moving the view to a fullscreen
|
||||
// window. Set that window delegate to the cocoa adapter to trigger
|
||||
// calls to -windowDidResignKey: and -windowDidBecomeKey:
|
||||
[[s->view window] setDelegate:s->adapter];
|
||||
}
|
||||
|
||||
flag_events(vo, VO_EVENT_ICC_PROFILE_CHANGED);
|
||||
resize_event(vo);
|
||||
[s->window toggleFullScreen:nil];
|
||||
// for whatever reason sometimes cocoa doesn't create an up event on
|
||||
// the fullscreen input key
|
||||
cocoa_put_key(MP_INPUT_RELEASE_ALL);
|
||||
|
||||
return VO_TRUE;
|
||||
}
|
||||
|
@ -782,10 +709,7 @@ static void vo_cocoa_control_get_icc_profile(struct vo *vo, void *arg)
|
|||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
bstr *p = arg;
|
||||
|
||||
vo_cocoa_update_screen_info(vo, NULL);
|
||||
|
||||
NSScreen *screen = vo->opts->fullscreen ? s->fs_screen : s->current_screen;
|
||||
NSData *profile = [[screen colorSpace] ICCProfileData];
|
||||
NSData *profile = [[s->current_screen colorSpace] ICCProfileData];
|
||||
|
||||
p->start = talloc_memdup(NULL, (void *)[profile bytes], [profile length]);
|
||||
p->len = [profile length];
|
||||
|
@ -793,59 +717,61 @@ static void vo_cocoa_control_get_icc_profile(struct vo *vo, void *arg)
|
|||
|
||||
static int vo_cocoa_control_on_main_thread(struct vo *vo, int request, void *arg)
|
||||
{
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
||||
switch (request) {
|
||||
case VOCTRL_FULLSCREEN:
|
||||
return vo_cocoa_fullscreen(vo);
|
||||
case VOCTRL_GET_FULLSCREEN:
|
||||
*(int *)arg = s->fullscreen;
|
||||
return VO_TRUE;
|
||||
case VOCTRL_ONTOP:
|
||||
return vo_cocoa_ontop(vo);
|
||||
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
|
||||
int *s = arg;
|
||||
NSSize size = [vo->cocoa->view frame].size;
|
||||
s[0] = size.width;
|
||||
s[1] = size.height;
|
||||
int *sz = arg;
|
||||
NSSize size = [s->view frame].size;
|
||||
sz[0] = size.width;
|
||||
sz[1] = size.height;
|
||||
return VO_TRUE;
|
||||
}
|
||||
case VOCTRL_SET_UNFS_WINDOW_SIZE: {
|
||||
int *s = arg;
|
||||
int *sz = arg;
|
||||
int w, h;
|
||||
w = s[0];
|
||||
h = s[1];
|
||||
w = sz[0];
|
||||
h = sz[1];
|
||||
queue_new_video_size(vo, w, h);
|
||||
return VO_TRUE;
|
||||
}
|
||||
case VOCTRL_GET_WIN_STATE: {
|
||||
const bool minimized = [[vo->cocoa->view window] isMiniaturized];
|
||||
const bool minimized = [[s->view window] isMiniaturized];
|
||||
*(int *)arg = minimized ? VO_WIN_STATE_MINIMIZED : 0;
|
||||
return VO_TRUE;
|
||||
}
|
||||
case VOCTRL_SET_CURSOR_VISIBILITY:
|
||||
return vo_cocoa_set_cursor_visibility(vo, arg);
|
||||
case VOCTRL_UPDATE_WINDOW_TITLE: {
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
talloc_free(s->window_title);
|
||||
s->window_title = talloc_strdup(s, (char *) arg);
|
||||
return cocoa_set_window_title(vo);
|
||||
}
|
||||
case VOCTRL_RESTORE_SCREENSAVER:
|
||||
enable_power_management(vo->cocoa);
|
||||
enable_power_management(s);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_KILL_SCREENSAVER:
|
||||
disable_power_management(vo->cocoa);
|
||||
disable_power_management(s);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_GET_ICC_PROFILE:
|
||||
vo_cocoa_control_get_icc_profile(vo, arg);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_GET_DISPLAY_FPS:
|
||||
if (vo->cocoa->screen_fps > 0.0) {
|
||||
*(double *)arg = vo->cocoa->screen_fps;
|
||||
if (s->screen_fps > 0.0) {
|
||||
*(double *)arg = s->screen_fps;
|
||||
return VO_TRUE;
|
||||
}
|
||||
break;
|
||||
case VOCTRL_GET_AMBIENT_LUX:
|
||||
if (vo->cocoa->light_sensor != IO_OBJECT_NULL) {
|
||||
*(int *)arg = vo->cocoa->last_lux;
|
||||
if (s->light_sensor != IO_OBJECT_NULL) {
|
||||
*(int *)arg = s->last_lux;
|
||||
return VO_TRUE;
|
||||
}
|
||||
break;
|
||||
|
@ -879,8 +805,7 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
|||
|
||||
- (void)performAsyncResize:(NSSize)size {
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
if (!atomic_load(&s->waiting_frame))
|
||||
vo_cocoa_resize_redraw(self.vout, size.width, size.height);
|
||||
vo_cocoa_resize_redraw(self.vout, size.width, size.height);
|
||||
}
|
||||
|
||||
- (BOOL)keyboardEnabled {
|
||||
|
@ -898,7 +823,7 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
|||
- (void)recalcMovableByWindowBackground:(NSPoint)p
|
||||
{
|
||||
BOOL movable = NO;
|
||||
if (![self isInFullScreenMode]) {
|
||||
if (!self.vout->cocoa->fullscreen) {
|
||||
movable = !mp_input_test_dragging(self.vout->input_ctx, p.x, p.y);
|
||||
}
|
||||
|
||||
|
@ -933,18 +858,18 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
|||
ta_free(cmd_);
|
||||
}
|
||||
|
||||
- (BOOL)isInFullScreenMode {
|
||||
return self.vout->opts->fullscreen;
|
||||
}
|
||||
|
||||
- (NSScreen *)fsScreen {
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
return s->fs_screen;
|
||||
}
|
||||
|
||||
- (BOOL)fsModeAllScreens
|
||||
- (BOOL)isInFullScreenMode
|
||||
{
|
||||
return self.vout->opts->fs_black_out_screens;
|
||||
return self.vout->cocoa->fullscreen;
|
||||
}
|
||||
|
||||
- (NSScreen *)getTargetScreen
|
||||
{
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
struct mp_vo_opts *opts = self.vout->opts;
|
||||
|
||||
int screen_id = s->fullscreen ? opts->screen_id : opts->fsscreen_id;
|
||||
return get_screen_by_id(self.vout, screen_id);
|
||||
}
|
||||
|
||||
- (void)handleFilesArray:(NSArray *)files
|
||||
|
@ -954,11 +879,36 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
|||
|
||||
- (void)windowDidChangeScreen:(NSNotification *)notification
|
||||
{
|
||||
vo_cocoa_update_screen_info(self.vout, NULL);
|
||||
vo_cocoa_update_screen_info(self.vout);
|
||||
vo_cocoa_update_screen_fps(self.vout);
|
||||
}
|
||||
|
||||
- (void)didChangeWindowedScreenProfile:(NSScreen *)screen
|
||||
- (void)windowDidEnterFullScreen:(NSNotification *)notification
|
||||
{
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
s->fullscreen = 1;
|
||||
s->pending_events |= VO_EVENT_FULLSCREEN_STATE;
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification *)notification
|
||||
{
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
s->fullscreen = 0;
|
||||
s->pending_events |= VO_EVENT_FULLSCREEN_STATE;
|
||||
}
|
||||
|
||||
- (void)windowWillStartLiveResize:(NSNotification *)notification
|
||||
{
|
||||
// Make vo.c not do video timing, which would slow down resizing.
|
||||
vo_event(self.vout, VO_EVENT_LIVE_RESIZING);
|
||||
}
|
||||
|
||||
- (void)windowDidEndLiveResize:(NSNotification *)notification
|
||||
{
|
||||
vo_query_and_reset_events(self.vout, VO_EVENT_LIVE_RESIZING);
|
||||
}
|
||||
|
||||
- (void)didChangeWindowedScreenProfile:(NSNotification *)notification
|
||||
{
|
||||
flag_events(self.vout, VO_EVENT_ICC_PROFILE_CHANGED);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue