]> git.sesse.net Git - vlc/blobdiff - modules/video_output/macosx.m
Fix alignment and appearance of ISO standard equalizer centers in Qt GUI
[vlc] / modules / video_output / macosx.m
index 0fe6041e206bae16e05a8b8871ec22eb756c2fc1..5fa24a7d0e101ae278fbea7bb76dfa2e6add44d5 100644 (file)
@@ -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 <colin@zoy.org>
- *          Florian G. Pflug <fgp@phlo.org>
- *          Jon Lech Johansen <jon-vl@nanocrew.net>
- *          Derk-Jan Hartman <hartman at videolan dot org>
+ * Authors: Derk-Jan Hartman <hartman at videolan dot org>
  *          Eric Petit <titer@m0k.org>
  *          Benjamin Pracht <bigben at videolan dot org>
  *          Damien Fouilleul <damienf at videolan dot org>
  *          Pierre d'Herbemont <pdherbemont at videolan dot org>
  *          Felix Paul Kühne <fkuehne at videolan dot org>
  *          David Fuhrmann <david dot fuhrmann at googlemail dot com>
+ *          Rémi Denis-Courmont
+ *          Juho Vähä-Herttua <juhovh at iki dot fi>
+ *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
  *
- * 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.
  *****************************************************************************/
 
 /*****************************************************************************
 #include <vlc_dialog.h>
 #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)
 
@@ -136,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;
@@ -152,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));
@@ -170,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;
         }
@@ -195,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(setFrameToBoundsOfView:) withObject:[NSValue valueWithPointer:parentView] waitUntilDone:NO];
-    }
-    else
-    {
+    } else {
         msg_Err(vd, "Invalid drawable-nsobject object. drawable-nsobject must either be an NSView or comply to the @protocol VLCOpenGLVideoViewEmbedding.");
         goto error;
     }
@@ -221,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;
     }
@@ -232,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;
@@ -257,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);
@@ -333,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:
@@ -360,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)
@@ -379,25 +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;
-                /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */
-                if ([sys->glView respondsToSelector:@selector(convertRectToBacking:)])
-                    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;
-            }
+            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) {
@@ -407,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;
@@ -443,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;
     }
@@ -512,7 +494,7 @@ static void OpenglSwap (vlc_gl_t *gl)
         return nil;
 
     /* enable HiDPI support on OS X 10.7 and later */
-    if ([self respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)])
+    if (OSX_LION)
         [self setWantsBestResolutionOpenGLSurface:YES];
 
     /* Swap buffers only during the vertical retrace of the monitor.
@@ -521,23 +503,32 @@ static void OpenglSwap (vlc_gl_t *gl)
     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)setFrameToBoundsOfView:(NSValue *)value
 {
     NSView *parentView = [value pointerValue];
-    NSRect frame;
-    /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */
-    if ([parentView respondsToSelector:@selector(convertRectToBacking:)])
-        frame = [parentView convertRectToBacking:[parentView bounds]];
-    else
-        frame = [parentView bounds];
-    [self setFrame:frame];
+    [self setFrame:[parentView bounds]];
 }
 
 /**
@@ -618,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);
 }
@@ -635,7 +625,7 @@ static void OpenglSwap (vlc_gl_t *gl)
 
     NSRect bounds;
     /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */
-    if ([self respondsToSelector:@selector(convertRectToBacking:)])
+    if (OSX_LION)
         bounds = [self convertRectToBacking:[self bounds]];
     else
         bounds = [self bounds];
@@ -722,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];
@@ -746,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];
 }
@@ -773,23 +768,19 @@ static void OpenglSwap (vlc_gl_t *gl)
     BOOL b_inside;
 
     /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */
-    if ([self respondsToSelector:@selector(convertRectToBacking:)])
+    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 +