X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fmacosx.m;h=aab54cb29067f867d830aa827e348a4f55ca3d07;hb=9b24bfb5b3b9f07c3cc0e54480ba0bc12a92748f;hp=0c9072ff1a6e040f684a5f44c2ddc417a752a6c2;hpb=546bfa6bab387cdc783b7cd6fb4f003af5e280f3;p=vlc diff --git a/modules/video_output/macosx.m b/modules/video_output/macosx.m index 0c9072ff1a..aab54cb290 100644 --- a/modules/video_output/macosx.m +++ b/modules/video_output/macosx.m @@ -1,32 +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. *****************************************************************************/ /***************************************************************************** @@ -35,6 +36,7 @@ #import #import +#import #ifdef HAVE_CONFIG_H # include "config.h" @@ -47,38 +49,47 @@ #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 */ -static int Open(vlc_object_t *); -static void Close(vlc_object_t *); +static int Open (vlc_object_t *); +static void Close (vlc_object_t *); -static picture_pool_t *Pool(vout_display_t *vd, unsigned requested_count); -static void PictureRender(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture); -static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture); +static picture_pool_t *Pool (vout_display_t *vd, unsigned requested_count); +static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture); +static void PictureDisplay (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture); static int Control (vout_display_t *vd, int query, va_list ap); -static int OpenglLock(vlc_gl_t *gl); -static void OpenglUnlock(vlc_gl_t *gl); -static void OpenglSwap(vlc_gl_t *gl); +static void *OurGetProcAddress(vlc_gl_t *, const char *); + +static int OpenglLock (vlc_gl_t *gl); +static void OpenglUnlock (vlc_gl_t *gl); +static void OpenglSwap (vlc_gl_t *gl); /** * Module declaration */ vlc_module_begin () /* Will be loaded even without interface module. see voutgl.m */ - 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_capability("vout display", 300) - set_callbacks(Open, Close) - - add_shortcut("macosx", "vout_macosx") + set_shortname ("Mac OS X") + set_description (N_("Mac OS X OpenGL video output")) + set_category (CAT_VIDEO) + set_subcategory (SUBCAT_VIDEO_VOUT) + set_capability ("vout display", 300) + set_callbacks (Open, Close) + + add_shortcut ("macosx", "vout_macosx") vlc_module_end () /** @@ -95,7 +106,6 @@ vlc_module_end () BOOL _hasPendingReshape; } - (void)setVoutDisplay:(vout_display_t *)vd; -- (vout_display_t *)voutDisplay; - (void)setVoutFlushing:(BOOL)flushing; @end @@ -112,25 +122,29 @@ struct vout_display_sys_t picture_pool_t *pool; picture_t *current; bool has_first_frame; + + vout_display_place_t place; }; -static int Open(vlc_object_t *this) + +static void *OurGetProcAddress(vlc_gl_t *gl, const char *name) +{ + VLC_UNUSED(gl); + + return dlsym(RTLD_DEFAULT, name); +} + +static int Open (vlc_object_t *this) { vout_display_t *vd = (vout_display_t *)this; - vout_display_sys_t *sys = calloc(1, sizeof(*sys)); + vout_display_sys_t *sys = calloc (1, sizeof(*sys)); NSAutoreleasePool *nsPool = nil; if (!sys) return VLC_ENOMEM; - if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) ) - { - msg_Err( this, "no OpenGL hardware acceleration found, video output will fail" ); - dialog_Fatal( this, _("Video output is not supported"), _("Your Mac lacks Quartz Extreme acceleration, which is required for video output.") ); - return VLC_EGENERIC; - } - else - msg_Dbg( this, "Quartz Extreme acceleration is active" ); + if (!CGDisplayUsesOpenGLAcceleration (kCGDirectMainDisplay)) + msg_Err (this, "no OpenGL hardware acceleration found. this can lead to slow output and unexpected results"); vd->sys = sys; sys->pool = NULL; @@ -138,13 +152,10 @@ static int Open(vlc_object_t *this) sys->embed = NULL; /* Get the drawable object */ - id container = var_CreateGetAddress(vd, "drawable-nsobject"); + id container = var_CreateGetAddress (vd, "drawable-nsobject"); if (container) - { - vout_display_DeleteWindow(vd, NULL); - } - else - { + vout_display_DeleteWindow (vd, NULL); + else { vout_window_cfg_t wnd_cfg; memset (&wnd_cfg, 0, sizeof (wnd_cfg)); @@ -158,9 +169,8 @@ static int Open(vlc_object_t *this) if (sys->embed) container = sys->embed->handle.nsobject; - if (!container) - { - msg_Dbg(vd, "No drawable-nsobject nor vout_window_t found, passing over."); + if (!container) { + msg_Err(vd, "No drawable-nsobject nor vout_window_t found, passing over."); goto error; } } @@ -173,8 +183,10 @@ static int Open(vlc_object_t *this) nsPool = [[NSAutoreleasePool alloc] init]; [VLCOpenGLVideoView performSelectorOnMainThread:@selector(getNewView:) withObject:[NSValue valueWithPointer:&sys->glView] waitUntilDone:YES]; - if (!sys->glView) + if (!sys->glView) { + msg_Err(vd, "Initialization of open gl view failed"); goto error; + } [sys->glView setVoutDisplay:vd]; @@ -183,14 +195,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; } @@ -203,14 +212,13 @@ static int Open(vlc_object_t *this) sys->gl.lock = OpenglLock; sys->gl.unlock = OpenglUnlock; sys->gl.swap = OpenglSwap; - sys->gl.getProcAddress = NULL; + sys->gl.getProcAddress = OurGetProcAddress; sys->gl.sys = sys; const vlc_fourcc_t *subpicture_chromas; - video_format_t fmt = vd->fmt; - sys->vgl = vout_display_opengl_New(&vd->fmt, &subpicture_chromas, &sys->gl); - if (!sys->vgl) - { + sys->vgl = vout_display_opengl_New (&vd->fmt, &subpicture_chromas, &sys->gl); + if (!sys->vgl) { + msg_Err(vd, "Error while initializing opengl display."); sys->gl.sys = NULL; goto error; } @@ -220,6 +228,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; @@ -230,8 +239,7 @@ static int Open(vlc_object_t *this) vd->control = Control; /* */ - vout_display_SendEventFullscreen (vd, false); - vout_display_SendEventDisplaySize (vd, vd->source.i_visible_width, vd->source.i_visible_height, false); + vout_display_SendEventDisplaySize (vd, vd->fmt.i_visible_width, vd->fmt.i_visible_height); return VLC_SUCCESS; @@ -241,33 +249,29 @@ error: return VLC_EGENERIC; } -void Close(vlc_object_t *this) +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"); + 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); + vout_display_opengl_Delete (sys->vgl); + + [sys->glView release]; if (sys->embed) - vout_display_DeleteWindow(vd, sys->embed); + vout_display_DeleteWindow (vd, sys->embed); free (sys); } @@ -275,7 +279,7 @@ void Close(vlc_object_t *this) * vout display callbacks *****************************************************************************/ -static picture_pool_t *Pool(vout_display_t *vd, unsigned requested_count) +static picture_pool_t *Pool (vout_display_t *vd, unsigned requested_count) { vout_display_sys_t *sys = vd->sys; @@ -285,99 +289,91 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned requested_count) return sys->pool; } -static void PictureRender(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture) +static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture) { vout_display_sys_t *sys = vd->sys; - vout_display_opengl_Prepare( sys->vgl, pic, subpicture ); + vout_display_opengl_Prepare (sys->vgl, pic, subpicture); } -static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture) +static void PictureDisplay (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture) { vout_display_sys_t *sys = vd->sys; [sys->glView setVoutFlushing:YES]; - vout_display_opengl_Display(sys->vgl, &vd->fmt ); + vout_display_opengl_Display (sys->vgl, &vd->source); [sys->glView setVoutFlushing:NO]; picture_Release (pic); sys->has_first_frame = true; - (void)subpicture; + + if (subpicture) + subpicture_Delete(subpicture); } static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; + if (!vd->sys) + return VLC_EGENERIC; + + if (!sys->embed) + return VLC_EGENERIC; + switch (query) { - case VOUT_DISPLAY_CHANGE_FULLSCREEN: - { - NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; - [[sys->glView window] performSelectorOnMainThread:@selector(fullscreen:) withObject: nil waitUntilDone:NO]; - [o_pool release]; - return VLC_SUCCESS; - } - case VOUT_DISPLAY_CHANGE_WINDOW_STATE: - { - unsigned state = va_arg (ap, unsigned); - if( (state & VOUT_WINDOW_STATE_ABOVE) != 0) - [[sys->glView window] setLevel: NSStatusWindowLevel]; - else - [[sys->glView window] setLevel: NSNormalWindowLevel]; - return VLC_SUCCESS; - } case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: - { - [[sys->glView window] performSelectorOnMainThread:@selector(performZoom:) withObject: nil waitUntilDone:NO]; - return VLC_SUCCESS; - } case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: - return VLC_SUCCESS; case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { - if (!config_GetInt( vd, "macosx-video-autoresize" )) - return VLC_SUCCESS; - - [sys->glView performSelectorOnMainThread:@selector(reshapeView:) withObject:nil waitUntilDone:NO]; - NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; - NSPoint topleftbase; - NSPoint topleftscreen; - NSRect new_frame; - const vout_display_cfg_t *cfg; id o_window = [sys->glView window]; - if (!o_window) + if (!o_window) { + [o_pool release]; return VLC_SUCCESS; // this is okay, since the event will occur again when we have a window - NSRect windowFrame = [o_window frame]; - NSRect glViewFrame = [sys->glView frame]; + } + NSSize windowMinSize = [o_window minSize]; - topleftbase.x = 0; - topleftbase.y = windowFrame.size.height; - topleftscreen = [o_window convertBaseToScreen: topleftbase]; - cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); - int i_width = cfg->display.width; - int i_height = cfg->display.height; + const vout_display_cfg_t *cfg; + const video_format_t *source; + + 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 { + source = &vd->source; + cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); + } - /* Calculate the window's new size, if it is larger than our minimal size */ - if (i_width < windowMinSize.width) - i_width = windowMinSize.width; - if (i_height < windowMinSize.height) - i_height = windowMinSize.height; + /* 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; + 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) { + sys->place = place; + } - if( i_height != glViewFrame.size.height || i_width != glViewFrame.size.width ) - { - new_frame.size.width = windowFrame.size.width - glViewFrame.size.width + i_width; - new_frame.size.height = windowFrame.size.height - glViewFrame.size.height + i_height; + /* 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); - new_frame.origin.x = topleftscreen.x; - new_frame.origin.y = topleftscreen.y - new_frame.size.height; - [sys->glView performSelectorOnMainThread:@selector(setWindowFrameWithValue:) withObject:[NSValue valueWithRect:new_frame] waitUntilDone:NO]; - } [o_pool release]; return VLC_SUCCESS; } @@ -388,13 +384,6 @@ static int Control (vout_display_t *vd, int query, va_list ap) return VLC_SUCCESS; } - case VOUT_DISPLAY_GET_OPENGL: - { - vlc_gl_t **gl = va_arg (ap, vlc_gl_t **); - *gl = &sys->gl; - return VLC_SUCCESS; - } - case VOUT_DISPLAY_RESET_PICTURES: assert (0); default: @@ -406,26 +395,28 @@ static int Control (vout_display_t *vd, int query, va_list ap) /***************************************************************************** * vout opengl callbacks *****************************************************************************/ -static int OpenglLock(vlc_gl_t *gl) +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) - { + CGLError err = CGLLockContext ([context CGLContextObj]); + if (kCGLNoError == err) { [context makeCurrentContext]; return 0; } return 1; } -static void OpenglUnlock(vlc_gl_t *gl) +static void OpenglUnlock (vlc_gl_t *gl) { vout_display_sys_t *sys = (vout_display_sys_t *)gl->sys; - CGLUnlockContext([[sys->glView openGLContext] CGLContextObj]); + CGLUnlockContext ([[sys->glView openGLContext] CGLContextObj]); } -static void OpenglSwap(vlc_gl_t *gl) +static void OpenglSwap (vlc_gl_t *gl) { vout_display_sys_t *sys = (vout_display_sys_t *)gl->sys; [[sys->glView openGLContext] flushBuffer]; @@ -438,6 +429,7 @@ static void OpenglSwap(vlc_gl_t *gl) #define VLCAssertMainThread() assert([[NSThread currentThread] isMainThread]) + + (void)getNewView:(NSValue *)value { id *ret = [value pointerValue]; @@ -462,6 +454,7 @@ static void OpenglSwap(vlc_gl_t *gl) NSOpenGLPFAAlphaSize, 8, NSOpenGLPFADepthSize, 24, NSOpenGLPFAWindow, + NSOpenGLPFAAllowOfflineRenderers, 0 }; @@ -476,36 +469,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); + 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; } -/** - * Gets called by the Open() method. - */ -- (void)setFrameWithValue:(NSValue *)value +- (void)dealloc { - [self setFrame:[value rectValue]]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; } /** - * Gets called by Control() to make sure that we're performing on the main thread + * Gets called by the Open() method. */ -- (void)setWindowFrameWithValue:(NSValue *)value +- (void)setFrameToBoundsOfView:(NSValue *)value { - if (![[self window] isFullscreen]) - { - NSRect frame = [value rectValue]; - if (frame.origin.x <= 0.0 && frame.origin.y <= 0.0) - [[self window] center]; - [[self window] setFrame:frame display:YES animate: YES]; - } + NSView *parentView = [value pointerValue]; + [self setFrame:[parentView bounds]]; } /** @@ -519,11 +518,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). @@ -558,7 +552,7 @@ static void OpenglSwap(vlc_gl_t *gl) { VLCAssertMainThread(); NSOpenGLContext *context = [self openGLContext]; - CGLError err = CGLLockContext([context CGLContextObj]); + CGLError err = CGLLockContext ([context CGLContextObj]); if (err == kCGLNoError) [context makeCurrentContext]; return err == kCGLNoError; @@ -570,7 +564,7 @@ static void OpenglSwap(vlc_gl_t *gl) - (void)unlockgl { VLCAssertMainThread(); - CGLUnlockContext([[self openGLContext] CGLContextObj]); + CGLUnlockContext ([[self openGLContext] CGLContextObj]); } /** @@ -591,17 +585,11 @@ 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 ); - } + vout_display_opengl_Display (vd->sys->vgl, &vd->source); else - glClear(GL_COLOR_BUFFER_BIT); -} - -- (void)reshapeView:(id)sender -{ - [self reshape]; + glClear (GL_COLOR_BUFFER_BIT); } /** @@ -611,36 +599,29 @@ static void OpenglSwap(vlc_gl_t *gl) { VLCAssertMainThread(); - NSRect bounds = [self bounds]; - - CGFloat height = bounds.size.height; - CGFloat width = bounds.size.width; - - GLint x = width, y = height; + 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) { if (vd) { - CGFloat videoHeight = vd->source.i_visible_height; - CGFloat videoWidth = vd->source.i_visible_width; + vout_display_cfg_t cfg_tmp = *(vd->cfg); + cfg_tmp.display.width = bounds.size.width; + cfg_tmp.display.height = bounds.size.height; - 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); - y = height; - } - else - { - x = width; - y = (width * videoHeight * sarDen) / (videoWidth * sarNum); - } + vout_display_PlacePicture (&place, &vd->source, &cfg_tmp, false); + vd->sys->place = place; + vout_display_SendEventDisplaySize (vd, bounds.size.width, bounds.size.height); } } if ([self lockgl]) { - glViewport((width - x) / 2, (height - y) / 2, x, y); + // x / y are top left corner, but we need the lower left one + glViewport (place.x, bounds.size.height - (place.y + place.height), place.width, place.height); @synchronized(self) { // This may be cleared before -drawRect is being called, @@ -696,19 +677,117 @@ static void OpenglSwap(vlc_gl_t *gl) NSWindow *window = [self window]; // Remove flashes with splitter view. - if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)]) - [window disableScreenUpdatesUntilFlush]; + if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)]) + [window disableScreenUpdatesUntilFlush]; [super renewGState]; } -- (BOOL)mouseDownCanMoveWindow +- (BOOL)isOpaque { return YES; } -- (BOOL)isOpaque +#pragma mark - +#pragma mark Mouse handling + +- (void)mouseDown:(NSEvent *)o_event +{ + @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]; +} + +- (void)otherMouseDown:(NSEvent *)o_event +{ + @synchronized (self) { + if (vd) + vout_display_SendEventMousePressed (vd, MOUSE_BUTTON_CENTER); + } + + [super otherMouseDown: o_event]; +} + +- (void)mouseUp:(NSEvent *)o_event +{ + @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 +{ + @synchronized (self) { + if (vd) + vout_display_SendEventMouseReleased (vd, MOUSE_BUTTON_CENTER); + } + + [super otherMouseUp: o_event]; +} + +- (void)mouseMoved:(NSEvent *)o_event +{ + /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */ + NSPoint ml = [self convertPoint: [o_event locationInWindow] fromView: nil]; + NSRect videoRect = [self bounds]; + BOOL b_inside = [self mouse: ml inRect: videoRect]; + + if (OSX_LION) { + ml = [self convertPointToBacking: ml]; + videoRect = [self convertRectToBacking: videoRect]; + } + + if (b_inside) { + @synchronized (self) { + if (vd) { + vout_display_SendMouseMovedDisplayCoordinates(vd, ORIENT_NORMAL, + (int)ml.x, videoRect.size.height - (int)ml.y, + &vd->sys->place); + } + } + } + + [super mouseMoved: o_event]; +} + +- (void)mouseDragged:(NSEvent *)o_event +{ + [self mouseMoved: o_event]; + [super mouseDragged: o_event]; +} + +- (void)otherMouseDragged:(NSEvent *)o_event +{ + [self mouseMoved: o_event]; + [super otherMouseDragged: o_event]; +} + +- (void)rightMouseDragged:(NSEvent *)o_event +{ + [self mouseMoved: o_event]; + [super rightMouseDragged: o_event]; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)mouseDownCanMoveWindow { return YES; } + @end