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:
Akemi 2016-12-04 22:52:14 +01:00
parent 870a6a11d9
commit a8347eb9ba
10 changed files with 284 additions and 263 deletions

View File

@ -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

View File

@ -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).

View File

@ -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}
};

View File

@ -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;

View File

@ -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;

View File

@ -20,8 +20,6 @@
@interface MpvEventsView : NSView <NSDraggingDestination>
@property(nonatomic, retain) MpvCocoaAdapter *adapter;
- (void)setFullScreen:(BOOL)willBeFullscreen;
- (void)clear;
- (BOOL)canHideCursor;
- (void)signalMousePosition;
@end

View File

@ -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];

View File

@ -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

View File

@ -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 {

View File

@ -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);
}