X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fmacosx.m;h=5fa24a7d0e101ae278fbea7bb76dfa2e6add44d5;hb=2c613666ad3fd4fbadc6e177a044cd2c94cf0e80;hp=271676177ef8285aa56ebe3badbed7547fec86d0;hpb=cfd14b541f8033aad59fb9ec6594bf5eed93743b;p=vlc diff --git a/modules/video_output/macosx.m b/modules/video_output/macosx.m index 271676177e..5fa24a7d0e 100644 --- a/modules/video_output/macosx.m +++ b/modules/video_output/macosx.m @@ -1,32 +1,33 @@ /***************************************************************************** - * voutgl.m: MacOS X OpenGL provider + * macosx.m: MacOS X OpenGL provider ***************************************************************************** - * Copyright (C) 2001-2011 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,34 +49,47 @@ #include #include "opengl.h" +/* 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 (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") vlc_module_end () /** @@ -107,25 +122,32 @@ 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"); + 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 + msg_Dbg (this, "Quartz Extreme acceleration is active"); vd->sys = sys; sys->pool = NULL; @@ -133,13 +155,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)); @@ -153,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; } @@ -178,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; } @@ -198,12 +213,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, NULL, &sys->gl); - if (!sys->vgl) - { + sys->vgl = vout_display_opengl_New (&vd->fmt, &subpicture_chromas, &sys->gl); + if (!sys->vgl) { sys->gl.sys = NULL; goto error; } @@ -211,6 +227,9 @@ static int Open(vlc_object_t *this) /* */ vout_display_info_t info = vd->info; 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; @@ -221,7 +240,6 @@ 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); return VLC_SUCCESS; @@ -232,30 +250,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; [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); } @@ -263,7 +280,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; @@ -273,23 +290,25 @@ 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) @@ -300,63 +319,80 @@ static int Control (vout_display_t *vd, int query, va_list ap) { case VOUT_DISPLAY_CHANGE_FULLSCREEN: { - /* todo */ - return VLC_EGENERIC; + const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *); + if (vout_window_SetFullScreen (sys->embed, cfg->is_fullscreen)) + return VLC_EGENERIC; + + 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; + return vout_window_SetState (sys->embed, state); } case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: - { - [[sys->glView window] performSelectorOnMainThread:@selector(zoom:) withObject: nil waitUntilDone:NO]; - return VLC_SUCCESS; - } - case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: + case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { - NSPoint topleftbase; - NSPoint topleftscreen; - NSRect new_frame; - const vout_display_cfg_t *cfg; + if (!vd->sys) + return VLC_EGENERIC; + + NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; id o_window = [sys->glView window]; if (!o_window) 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; + bool is_forced = false; + + 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 *); + if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE) + is_forced = (bool)va_arg (ap, int); + } - /* 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; + if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE && is_forced + && (cfg->display.width != vd->cfg->display.width + || cfg->display.height != vd->cfg->display.height) + && vout_window_SetSize (sys->embed, cfg->display.width, cfg->display.height)) + return VLC_EGENERIC; + + /* 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; } @@ -384,26 +420,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]; @@ -416,6 +454,7 @@ static void OpenglSwap(vlc_gl_t *gl) #define VLCAssertMainThread() assert([[NSThread currentThread] isMainThread]) + + (void)getNewView:(NSValue *)value { id *ret = [value pointerValue]; @@ -454,36 +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); + 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 (!(NSAppKitVersionNumber >= 1115.2 && [NSApp currentSystemPresentationOptions] == NSApplicationPresentationFullScreen)) - { - 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]]; } /** @@ -497,7 +542,6 @@ static void OpenglSwap(vlc_gl_t *gl) } } - /** * Gets called when the vout will aquire the lock and flush. * (Non main thread). @@ -532,7 +576,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; @@ -544,7 +588,7 @@ static void OpenglSwap(vlc_gl_t *gl) - (void)unlockgl { VLCAssertMainThread(); - CGLUnlockContext([[self openGLContext] CGLContextObj]); + CGLUnlockContext ([[self openGLContext] CGLContextObj]); } /** @@ -565,12 +609,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); + glClear (GL_COLOR_BUFFER_BIT); } /** @@ -580,36 +623,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; - - GLint sarNum = vd->source.i_sar_num; - GLint sarDen = vd->source.i_sar_den; + vout_display_cfg_t cfg_tmp = *(vd->cfg); + cfg_tmp.display.width = bounds.size.width; + cfg_tmp.display.height = bounds.size.height; - 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, vd->cfg->is_fullscreen); } } 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, @@ -665,19 +701,126 @@ 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 +{ + NSPoint ml; + NSRect s_rect; + BOOL b_inside; + + /* 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) { + vout_display_place_t place = vd->sys->place; + + 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 + + (int64_t)((int)s_rect.size.height - (int)ml.y - place.y) * vd->source.i_visible_height / place.height; + + vout_display_SendEventMouseMoved (vd, x, y); + } + } + } + } + + [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