]> git.sesse.net Git - vlc/blobdiff - modules/video_output/macosx.m
Revert "Helpers to emit asynchronous key press events (refs #3661)"
[vlc] / modules / video_output / macosx.m
index 4f4f9be5935ca584844bd81188158650432657fb..0fdcaf41cc0ade3a2b40b24d6675300f27163528 100644 (file)
@@ -87,10 +87,12 @@ vlc_module_end ()
 @interface VLCOpenGLVideoView : NSOpenGLView
 {
     vout_display_t *vd;
+    BOOL _hasPendingReshape;
 }
 - (void)setVoutDisplay:(vout_display_t *)vd;
+- (void)setVoutFlushing:(BOOL)flushing;
 @end
+
 
 struct vout_display_sys_t
 {
@@ -99,7 +101,7 @@ struct vout_display_sys_t
 
     vout_opengl_t gl;
     vout_display_opengl_t vgl;
-    
+
     picture_pool_t *pool;
     picture_t *current;
     bool has_first_frame;
@@ -117,7 +119,7 @@ static int Open(vlc_object_t *this)
     vd->sys = sys;
     sys->pool = NULL;
     sys->gl.sys = NULL;
-    
+
     /* Get the drawable object */
     id container = var_CreateGetAddress(vd, "drawable-nsobject");
     if (!container)
@@ -125,6 +127,7 @@ static int Open(vlc_object_t *this)
         msg_Dbg(vd, "No drawable-nsobject, passing over.");
         goto error;
     }
+    vout_display_DeleteWindow(vd, NULL);
 
     /* This will be released in Close(), on
      * main thread, after we are done using it. */
@@ -132,7 +135,7 @@ static int Open(vlc_object_t *this)
 
     /* Get our main view*/
     nsPool = [[NSAutoreleasePool alloc] init];
-    
+
     [VLCOpenGLVideoView performSelectorOnMainThread:@selector(getNewView:) withObject:[NSValue valueWithPointer:&sys->glView] waitUntilDone:YES];
     if (!sys->glView)
         goto error;
@@ -142,7 +145,21 @@ static int Open(vlc_object_t *this)
     /* We don't wait, that means that we'll have to be careful about releasing
      * container.
      * That's why we'll release on main thread in Close(). */
-    [(id)container performSelectorOnMainThread:@selector(addVoutSubview:) withObject:sys->glView waitUntilDone:NO];
+    if ([(id)container respondsToSelector:@selector(addVoutSubview:)])
+        [(id)container performSelectorOnMainThread:@selector(addVoutSubview:) withObject:sys->glView waitUntilDone:NO];
+    else if ([container isKindOfClass:[NSView class]])
+    {
+        NSView *parentView = container;
+        [parentView performSelectorOnMainThread:@selector(addSubview:) withObject:sys->glView waitUntilDone:NO];
+        [sys->glView performSelectorOnMainThread:@selector(setFrame:) withObject:[NSValue valueWithRect:[parentView bounds]] 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;
+    }
+
+
     [nsPool release];
     nsPool = nil;
 
@@ -151,7 +168,7 @@ static int Open(vlc_object_t *this)
     sys->gl.unlock = OpenglUnlock;
     sys->gl.swap = OpenglSwap;
     sys->gl.sys = sys;
-    
+
     if (vout_display_opengl_Init(&sys->vgl, &vd->fmt, &sys->gl))
     {
         sys->gl.sys = NULL;
@@ -161,10 +178,10 @@ static int Open(vlc_object_t *this)
     /* */
     vout_display_info_t info = vd->info;
     info.has_pictures_invalid = false;
-    
+
     /* Setup vout_display_t once everything is fine */
     vd->info = info;
-    
+
     vd->pool = Pool;
     vd->prepare = PictureRender;
     vd->display = PictureDisplay;
@@ -190,12 +207,15 @@ void Close(vlc_object_t *this)
     [sys->glView setVoutDisplay:nil];
 
     var_Destroy(vd, "drawable-nsobject");
-    /* This will retain sys->glView */
-    [(id)sys->container performSelectorOnMainThread:@selector(removeVoutSubview:) withObject:sys->glView waitUntilDone:NO];
+    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)
@@ -223,14 +243,16 @@ static void PictureRender(vout_display_t *vd, picture_t *pic)
 {
 
     vout_display_sys_t *sys = vd->sys;
-    
+
     vout_display_opengl_Prepare( &sys->vgl, pic );
 }
 
 static void PictureDisplay(vout_display_t *vd, picture_t *pic)
 {
     vout_display_sys_t *sys = vd->sys;
+    [sys->glView setVoutFlushing:YES];
     vout_display_opengl_Display(&sys->vgl, &vd->fmt );
+    [sys->glView setVoutFlushing:NO];
     picture_Release (pic);
     sys->has_first_frame = true;
 }
@@ -238,10 +260,10 @@ static void PictureDisplay(vout_display_t *vd, picture_t *pic)
 static int Control (vout_display_t *vd, int query, va_list ap)
 {
     vout_display_sys_t *sys = vd->sys;
-    
+
     switch (query)
     {
-        case VOUT_DISPLAY_CHANGE_FULLSCREEN:            
+        case VOUT_DISPLAY_CHANGE_FULLSCREEN:
         case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
         case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
         case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
@@ -254,21 +276,20 @@ static int Control (vout_display_t *vd, int query, va_list ap)
         }
         case VOUT_DISPLAY_HIDE_MOUSE:
             return VLC_SUCCESS;
-            
+
         case VOUT_DISPLAY_GET_OPENGL:
         {
             vout_opengl_t **gl = va_arg (ap, vout_opengl_t **);
             *gl = &sys->gl;
             return VLC_SUCCESS;
         }
-            
+
         case VOUT_DISPLAY_RESET_PICTURES:
             assert (0);
         default:
             msg_Err (vd, "Unknown request in Mac OS X vout display");
             return VLC_EGENERIC;
     }
-    printf("query %d\n", query);
 }
 
 /*****************************************************************************
@@ -284,7 +305,7 @@ static int OpenglLock(vout_opengl_t *gl)
         [context makeCurrentContext];
         return 0;
     }
-    return 1;    
+    return 1;
 }
 
 static void OpenglUnlock(vout_opengl_t *gl)
@@ -332,13 +353,15 @@ static void OpenglSwap(vout_opengl_t *gl)
         NSOpenGLPFAWindow,
         0
     };
-    
+
     NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
-    
+
     if (!fmt)
         return nil;
 
     self = [super initWithFrame:NSMakeRect(0,0,10,10) pixelFormat:fmt];
+    [fmt release];
+
     if (!self)
         return nil;
 
@@ -348,6 +371,7 @@ static void OpenglSwap(vout_opengl_t *gl)
     GLint params[] = { 1 };
     CGLSetParameter([[self openGLContext] CGLContextObj], kCGLCPSwapInterval, params);
 
+    [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     return self;
 }
 
@@ -362,13 +386,44 @@ static void OpenglSwap(vout_opengl_t *gl)
     }
 }
 
+
+/**
+ * Gets called when the vout will aquire the lock and flush.
+ * (Non main thread).
+ */
+- (void)setVoutFlushing:(BOOL)flushing
+{
+    if (!flushing)
+        return;
+    @synchronized(self) {
+        _hasPendingReshape = NO;
+    }
+}
+
+/**
+ * Can -drawRect skip rendering?.
+ */
+- (BOOL)canSkipRendering
+{
+    VLCAssertMainThread();
+
+    @synchronized(self) {
+        BOOL hasFirstFrame = vd && vd->sys->has_first_frame;
+        return !_hasPendingReshape && hasFirstFrame;
+    }
+}
+
+
 /**
  * Local method that locks the gl context.
  */
 - (BOOL)lockgl
 {
     VLCAssertMainThread();
-    CGLError err = CGLLockContext([[self openGLContext] CGLContextObj]);
+    NSOpenGLContext *context = [self openGLContext];
+    CGLError err = CGLLockContext([context CGLContextObj]);
+    if (err == kCGLNoError)
+        [context makeCurrentContext];
     return err == kCGLNoError;
 }
 
@@ -389,17 +444,22 @@ static void OpenglSwap(vout_opengl_t *gl)
 {
     VLCAssertMainThread();
 
+    // We may have taken some times to take the opengl Lock.
+    // Check here to see if we can just skip the frame as well.
+    if ([self canSkipRendering])
+        return;
+
+    BOOL hasFirstFrame;
     @synchronized(self) { // vd can be accessed from multiple threads
-        if (vd && vd->sys->has_first_frame)
-        {
-            // This will lock gl.
-            vout_display_opengl_Display( &vd->sys->vgl, &vd->source );
-        }
-        else {
-            glClear(GL_COLOR_BUFFER_BIT);
-        }
-        
-    }    
+        hasFirstFrame = vd && vd->sys->has_first_frame;
+    }
+
+    if (hasFirstFrame) {
+        // This will lock gl.
+        vout_display_opengl_Display( &vd->sys->vgl, &vd->source );
+    }
+    else
+        glClear(GL_COLOR_BUFFER_BIT);
 }
 
 /**
@@ -408,7 +468,7 @@ static void OpenglSwap(vout_opengl_t *gl)
 - (void)reshape
 {
     VLCAssertMainThread();
-    
+
     NSRect bounds = [self bounds];
 
     CGFloat height = bounds.size.height;
@@ -420,10 +480,10 @@ static void OpenglSwap(vout_opengl_t *gl)
         if (vd) {
             CGFloat videoHeight = vd->source.i_visible_height;
             CGFloat videoWidth = vd->source.i_visible_width;
-            
+
             GLint sarNum = vd->source.i_sar_num;
             GLint sarDen = vd->source.i_sar_den;
-            
+
             if (height * videoWidth * sarNum < width * videoHeight * sarDen)
             {
                 x = (height * videoWidth * sarNum) / (videoHeight * sarDen);
@@ -433,16 +493,25 @@ static void OpenglSwap(vout_opengl_t *gl)
             {
                 x = width;
                 y = (width * videoHeight * sarDen) / (videoWidth * sarNum);
-            }            
+            }
         }
     }
-    
-    [self lockgl];
-    glClearColor(0, 0, 0, 1);
-    glViewport((width - x) / 2, (height - y) / 2, x, y);
-    [self unlockgl];
 
-    [super reshape];
+    if ([self lockgl]) {
+        glViewport((width - x) / 2, (height - y) / 2, x, y);
+
+        @synchronized(self) {
+            // This may be cleared before -drawRect is being called,
+            // in this case we'll skip the rendering.
+            // This will save us for rendering two frames (or more) for nothing
+            // (one by the vout, one (or more) by drawRect)
+            _hasPendingReshape = YES;
+        }
+
+        [self unlockgl];
+
+        [super reshape];
+    }
 }
 
 /**
@@ -467,6 +536,10 @@ static void OpenglSwap(vout_opengl_t *gl)
 - (void)drawRect:(NSRect) rect
 {
     VLCAssertMainThread();
+
+    if ([self canSkipRendering])
+        return;
+
     BOOL success = [self lockgl];
     if (!success)
         return;
@@ -476,8 +549,24 @@ static void OpenglSwap(vout_opengl_t *gl)
     [self unlockgl];
 }
 
+- (void)renewGState
+{
+    NSWindow *window = [self window];
+
+    // Remove flashes with splitter view.
+       if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)])
+               [window disableScreenUpdatesUntilFlush];
+
+    [super renewGState];
+}
+
 - (BOOL)mouseDownCanMoveWindow
 {
     return YES;
 }
+
+- (BOOL)isOpaque
+{
+    return YES;
+}
 @end