X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fmacosx.m;h=5fa24a7d0e101ae278fbea7bb76dfa2e6add44d5;hb=2c613666ad3fd4fbadc6e177a044cd2c94cf0e80;hp=3d475eff026e3ff5df15a77747f10372ea11a649;hpb=3d649ef6e18e0d13faf8deaf28eb17de55be5df4;p=vlc diff --git a/modules/video_output/macosx.m b/modules/video_output/macosx.m index 3d475eff02..5fa24a7d0e 100644 --- a/modules/video_output/macosx.m +++ b/modules/video_output/macosx.m @@ -1,33 +1,33 @@ /***************************************************************************** * macosx.m: MacOS X OpenGL provider ***************************************************************************** - * Copyright (C) 2001-2012 the VideoLAN team + * Copyright (C) 2001-2013 VLC authors and VideoLAN * $Id$ * - * Authors: Colin Delacroix - * Florian G. Pflug - * Jon Lech Johansen - * Derk-Jan Hartman + * Authors: Derk-Jan Hartman * Eric Petit * Benjamin Pracht * Damien Fouilleul * Pierre d'Herbemont * Felix Paul Kühne * David Fuhrmann + * Rémi Denis-Courmont + * Juho Vähä-Herttua + * Laurent Aimar * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -49,10 +49,17 @@ #include #include "opengl.h" -@interface NSWindow (VLCCustomCode) -- (BOOL)isFullscreen; +/* compilation support for 10.5 and 10.6 */ +#define OSX_LION NSAppKitVersionNumber >= 1115.2 +#ifndef MAC_OS_X_VERSION_10_7 + +@interface NSView (IntroducedInLion) +- (NSRect)convertRectToBacking:(NSRect)aRect; +- (void)setWantsBestResolutionOpenGLSurface:(BOOL)aBool; @end +#endif + /** * Forward declarations */ @@ -78,7 +85,7 @@ vlc_module_begin () set_shortname ("Mac OS X") set_description (N_("Mac OS X OpenGL video output (requires drawable-nsobject)")) set_category (CAT_VIDEO) - set_subcategory (SUBCAT_VIDEO_VOUT ) + set_subcategory (SUBCAT_VIDEO_VOUT) set_capability ("vout display", 300) set_callbacks (Open, Close) @@ -99,7 +106,6 @@ vlc_module_end () BOOL _hasPendingReshape; } - (void)setVoutDisplay:(vout_display_t *)vd; -- (vout_display_t *)voutDisplay; - (void)setVoutFlushing:(BOOL)flushing; @end @@ -137,12 +143,10 @@ static int Open (vlc_object_t *this) if (!sys) return VLC_ENOMEM; - if (!CGDisplayUsesOpenGLAcceleration (kCGDirectMainDisplay)) - { + if (!CGDisplayUsesOpenGLAcceleration (kCGDirectMainDisplay)) { msg_Err (this, "no OpenGL hardware acceleration found. this can lead to slow output and unexpected results"); dialog_Fatal (this, _("OpenGL acceleration is not supported on your Mac"), _("Your Mac lacks Quartz Extreme acceleration, which is required for video output. It will still work, but much slower and with possibly unexpected results.")); - } - else + } else msg_Dbg (this, "Quartz Extreme acceleration is active"); vd->sys = sys; @@ -153,11 +157,8 @@ static int Open (vlc_object_t *this) /* Get the drawable object */ id container = var_CreateGetAddress (vd, "drawable-nsobject"); if (container) - { vout_display_DeleteWindow (vd, NULL); - } - else - { + else { vout_window_cfg_t wnd_cfg; memset (&wnd_cfg, 0, sizeof (wnd_cfg)); @@ -171,8 +172,7 @@ static int Open (vlc_object_t *this) if (sys->embed) container = sys->embed->handle.nsobject; - if (!container) - { + if (!container) { msg_Dbg(vd, "No drawable-nsobject nor vout_window_t found, passing over."); goto error; } @@ -196,14 +196,11 @@ static int Open (vlc_object_t *this) * That's why we'll release on main thread in Close(). */ if ([(id)container respondsToSelector:@selector(addVoutSubview:)]) [(id)container performSelectorOnMainThread:@selector(addVoutSubview:) withObject:sys->glView waitUntilDone:NO]; - else if ([container isKindOfClass:[NSView class]]) - { + else if ([container isKindOfClass:[NSView class]]) { NSView *parentView = container; [parentView performSelectorOnMainThread:@selector(addSubview:) withObject:sys->glView waitUntilDone:NO]; - [sys->glView performSelectorOnMainThread:@selector(setFrameWithValue:) withObject:[NSValue valueWithRect:[parentView bounds]] waitUntilDone:NO]; - } - else - { + [sys->glView performSelectorOnMainThread:@selector(setFrameToBoundsOfView:) withObject:[NSValue valueWithPointer:parentView] waitUntilDone:NO]; + } else { msg_Err(vd, "Invalid drawable-nsobject object. drawable-nsobject must either be an NSView or comply to the @protocol VLCOpenGLVideoViewEmbedding."); goto error; } @@ -222,8 +219,7 @@ static int Open (vlc_object_t *this) video_format_t fmt = vd->fmt; sys->vgl = vout_display_opengl_New (&vd->fmt, &subpicture_chromas, &sys->gl); - if (!sys->vgl) - { + if (!sys->vgl) { sys->gl.sys = NULL; goto error; } @@ -233,6 +229,7 @@ static int Open (vlc_object_t *this) info.has_pictures_invalid = false; info.has_event_thread = true; info.subpicture_chromas = subpicture_chromas; + info.has_hide_mouse = true; /* Setup vout_display_t once everything is fine */ vd->info = info; @@ -258,26 +255,22 @@ void Close (vlc_object_t *this) vout_display_t *vd = (vout_display_t *)this; vout_display_sys_t *sys = vd->sys; - if ([[sys->glView window] level] != NSNormalWindowLevel) - [[sys->glView window] setLevel: NSNormalWindowLevel]; - [sys->glView setVoutDisplay:nil]; var_Destroy (vd, "drawable-nsobject"); if ([(id)sys->container respondsToSelector:@selector(removeVoutSubview:)]) - { /* This will retain sys->glView */ [(id)sys->container performSelectorOnMainThread:@selector(removeVoutSubview:) withObject:sys->glView waitUntilDone:NO]; - } + /* release on main thread as explained in Open() */ [(id)sys->container performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; [sys->glView performSelectorOnMainThread:@selector(removeFromSuperview) withObject:nil waitUntilDone:NO]; - [sys->glView release]; - if (sys->gl.sys != NULL) vout_display_opengl_Delete (sys->vgl); + [sys->glView release]; + if (sys->embed) vout_display_DeleteWindow (vd, sys->embed); free (sys); @@ -334,11 +327,8 @@ static int Control (vout_display_t *vd, int query, va_list ap) } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { - NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; unsigned state = va_arg (ap, unsigned); - [sys->glView performSelectorOnMainThread:@selector(setWindowLevel:) withObject:[NSNumber numberWithUnsignedInt:state] waitUntilDone:NO]; - [o_pool release]; - return VLC_SUCCESS; + return vout_window_SetState (sys->embed, state); } case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_ZOOM: @@ -361,13 +351,10 @@ static int Control (vout_display_t *vd, int query, va_list ap) const video_format_t *source; bool is_forced = false; - if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT || query == VOUT_DISPLAY_CHANGE_SOURCE_CROP) - { + if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT || query == VOUT_DISPLAY_CHANGE_SOURCE_CROP) { source = (const video_format_t *)va_arg (ap, const video_format_t *); cfg = vd->cfg; - } - else - { + } else { source = &vd->source; cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE) @@ -380,20 +367,18 @@ static int Control (vout_display_t *vd, int query, va_list ap) && vout_window_SetSize (sys->embed, cfg->display.width, cfg->display.height)) return VLC_EGENERIC; - /* for the case that the core wants to resize below minimum window size we correct the size here - to ensure a centered picture */ + /* we always use our current frame here, because we have some size constraints + in the ui vout provider */ vout_display_cfg_t cfg_tmp = *cfg; - if (cfg_tmp.display.width < windowMinSize.width) - cfg_tmp.display.width = windowMinSize.width; - if (cfg_tmp.display.height < 70) - cfg_tmp.display.height = 70; - - if (!config_GetInt(vd, "macosx-video-autoresize")) - { - NSRect bounds = [sys->glView bounds]; - cfg_tmp.display.width = bounds.size.width; - cfg_tmp.display.height = bounds.size.height; - } + NSRect bounds; + /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */ + if (OSX_LION) + bounds = [sys->glView convertRectToBacking:[sys->glView bounds]]; + else + bounds = [sys->glView bounds]; + cfg_tmp.display.width = bounds.size.width; + cfg_tmp.display.height = bounds.size.height; + vout_display_place_t place; vout_display_PlacePicture (&place, source, &cfg_tmp, false); @synchronized (sys->glView) { @@ -403,10 +388,9 @@ static int Control (vout_display_t *vd, int query, va_list ap) /* For resize, we call glViewport in reshape and not here. This has the positive side effect that we avoid erratic sizing as we animate every resize. */ if (query != VOUT_DISPLAY_CHANGE_DISPLAY_SIZE) - { // x / y are top left corner, but we need the lower left one glViewport (place.x, cfg_tmp.display.height - (place.y + place.height), place.width, place.height); - } + [o_pool release]; return VLC_SUCCESS; @@ -439,10 +423,12 @@ static int Control (vout_display_t *vd, int query, va_list ap) static int OpenglLock (vlc_gl_t *gl) { vout_display_sys_t *sys = (vout_display_sys_t *)gl->sys; + if (!sys->glView || ![sys->glView respondsToSelector:@selector(openGLContext)]) + return 1; + NSOpenGLContext *context = [sys->glView openGLContext]; CGLError err = CGLLockContext ([context CGLContextObj]); - if (kCGLNoError == err) - { + if (kCGLNoError == err) { [context makeCurrentContext]; return 0; } @@ -507,22 +493,42 @@ static void OpenglSwap (vlc_gl_t *gl) if (!self) return nil; + /* enable HiDPI support on OS X 10.7 and later */ + if (OSX_LION) + [self setWantsBestResolutionOpenGLSurface:YES]; + /* Swap buffers only during the vertical retrace of the monitor. http://developer.apple.com/documentation/GraphicsImaging/ Conceptual/OpenGL/chap5/chapter_5_section_44.html */ GLint params[] = { 1 }; CGLSetParameter ([[self openGLContext] CGLContextObj], kCGLCPSwapInterval, params); + [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidChangeScreenParametersNotification + object:[NSApplication sharedApplication] + queue:nil + usingBlock:^(NSNotification *notification) { + [self performSelectorOnMainThread:@selector(reshape) + withObject:nil + waitUntilDone:NO]; + }]; + [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; return self; } +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + /** * Gets called by the Open() method. */ -- (void)setFrameWithValue:(NSValue *)value +- (void)setFrameToBoundsOfView:(NSValue *)value { - [self setFrame:[value rectValue]]; + NSView *parentView = [value pointerValue]; + [self setFrame:[parentView bounds]]; } /** @@ -536,11 +542,6 @@ static void OpenglSwap (vlc_gl_t *gl) } } -- (vout_display_t *)voutDisplay -{ - return vd; -} - /** * Gets called when the vout will aquire the lock and flush. * (Non main thread). @@ -608,10 +609,9 @@ static void OpenglSwap (vlc_gl_t *gl) hasFirstFrame = vd && vd->sys->has_first_frame; } - if (hasFirstFrame) { + if (hasFirstFrame) // This will lock gl. vout_display_opengl_Display (vd->sys->vgl, &vd->source); - } else glClear (GL_COLOR_BUFFER_BIT); } @@ -623,7 +623,12 @@ static void OpenglSwap (vlc_gl_t *gl) { VLCAssertMainThread(); - NSRect bounds = [self bounds]; + NSRect bounds; + /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */ + if (OSX_LION) + bounds = [self convertRectToBacking:[self bounds]]; + else + bounds = [self bounds]; vout_display_place_t place; @synchronized(self) { @@ -707,23 +712,18 @@ static void OpenglSwap (vlc_gl_t *gl) return YES; } -- (void)setWindowLevel:(NSNumber*)state -{ - if ([state unsignedIntValue] & VOUT_WINDOW_STATE_ABOVE) - [[self window] setLevel: NSStatusWindowLevel]; - else - [[self window] setLevel: NSNormalWindowLevel]; -} - #pragma mark - #pragma mark Mouse handling - (void)mouseDown:(NSEvent *)o_event { - if ([o_event type] == NSLeftMouseDown && !([o_event modifierFlags] & NSControlKeyMask)) - { - if ([o_event clickCount] <= 1) - vout_display_SendEventMousePressed (vd, MOUSE_BUTTON_LEFT); + @synchronized (self) { + if (vd) { + if ([o_event type] == NSLeftMouseDown && !([o_event modifierFlags] & NSControlKeyMask)) { + if ([o_event clickCount] <= 1) + vout_display_SendEventMousePressed (vd, MOUSE_BUTTON_LEFT); + } + } } [super mouseDown:o_event]; @@ -731,22 +731,32 @@ static void OpenglSwap (vlc_gl_t *gl) - (void)otherMouseDown:(NSEvent *)o_event { - vout_display_SendEventMousePressed (vd, MOUSE_BUTTON_CENTER); + @synchronized (self) { + if (vd) + vout_display_SendEventMousePressed (vd, MOUSE_BUTTON_CENTER); + } [super otherMouseDown: o_event]; } - (void)mouseUp:(NSEvent *)o_event { - if ([o_event type] == NSLeftMouseUp) - vout_display_SendEventMouseReleased (vd, MOUSE_BUTTON_LEFT); + @synchronized (self) { + if (vd) { + if ([o_event type] == NSLeftMouseUp) + vout_display_SendEventMouseReleased (vd, MOUSE_BUTTON_LEFT); + } + } [super mouseUp: o_event]; } - (void)otherMouseUp:(NSEvent *)o_event { - vout_display_SendEventMouseReleased (vd, MOUSE_BUTTON_CENTER); + @synchronized (self) { + if (vd) + vout_display_SendEventMouseReleased (vd, MOUSE_BUTTON_CENTER); + } [super otherMouseUp: o_event]; } @@ -757,20 +767,20 @@ static void OpenglSwap (vlc_gl_t *gl) NSRect s_rect; BOOL b_inside; - s_rect = [self bounds]; + /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */ + if (OSX_LION) + s_rect = [self convertRectToBacking:[self bounds]]; + else + s_rect = [self bounds]; ml = [self convertPoint: [o_event locationInWindow] fromView: nil]; b_inside = [self mouse: ml inRect: s_rect]; - if (b_inside) - { - @synchronized (self) - { - if (vd) - { + if (b_inside) { + @synchronized (self) { + if (vd) { vout_display_place_t place = vd->sys->place; - if (place.width > 0 && place.height > 0) - { + if (place.width > 0 && place.height > 0) { const int x = vd->source.i_x_offset + (int64_t)(ml.x - place.x) * vd->source.i_visible_width / place.width; const int y = vd->source.i_y_offset +