From a8347eb9ba9e09177da50592fde7f3ae7261ce59 Mon Sep 17 00:00:00 2001 From: Akemi Date: Sun, 4 Dec 2016 22:52:14 +0100 Subject: 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 --- video/out/cocoa/events_view.h | 2 - video/out/cocoa/events_view.m | 71 ----------- video/out/cocoa/mpvadapter.h | 6 +- video/out/cocoa/window.m | 173 ++++++++++++++++++++++++-- video/out/cocoa_common.m | 280 +++++++++++++++++------------------------- 5 files changed, 278 insertions(+), 254 deletions(-) (limited to 'video') diff --git a/video/out/cocoa/events_view.h b/video/out/cocoa/events_view.h index 3429563b4d..6ad51cc133 100644 --- a/video/out/cocoa/events_view.h +++ b/video/out/cocoa/events_view.h @@ -20,8 +20,6 @@ @interface MpvEventsView : NSView @property(nonatomic, retain) MpvCocoaAdapter *adapter; -- (void)setFullScreen:(BOOL)willBeFullscreen; -- (void)clear; - (BOOL)canHideCursor; - (void)signalMousePosition; @end diff --git a/video/out/cocoa/events_view.m b/video/out/cocoa/events_view.m index 5de4a99eec..53d1da86ff 100644 --- a/video/out/cocoa/events_view.m +++ b/video/out/cocoa/events_view.m @@ -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]; diff --git a/video/out/cocoa/mpvadapter.h b/video/out/cocoa/mpvadapter.h index 5b87e89d04..e547708e17 100644 --- a/video/out/cocoa/mpvadapter.h +++ b/video/out/cocoa/mpvadapter.h @@ -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 diff --git a/video/out/cocoa/window.m b/video/out/cocoa/window.m index d89e296b40..6d63263cb4 100644 --- a/video/out/cocoa/window.m +++ b/video/out/cocoa/window.m @@ -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 { diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m index 719169df48..c1a65ef2ee 100644 --- a/video/out/cocoa_common.m +++ b/video/out/cocoa_common.m @@ -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 win = (id) 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 win = (id) 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; +- (BOOL)isInFullScreenMode +{ + return self.vout->cocoa->fullscreen; } -- (NSScreen *)fsScreen { +- (NSScreen *)getTargetScreen +{ struct vo_cocoa_state *s = self.vout->cocoa; - return s->fs_screen; -} + struct mp_vo_opts *opts = self.vout->opts; -- (BOOL)fsModeAllScreens -{ - return self.vout->opts->fs_black_out_screens; + 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); } -- cgit v1.2.3