input: avoid printing --input=cmdlist/keylist output twice
[mplayer.git] / libvo / cocoa_common.m
blobd8d8d841e6e3343e1231b76695af7bbec194350d
1 /*
2  * Cocoa OpenGL Backend
3  *
4  * This file is part of mplayer2.
5  *
6  * mplayer2 is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mplayer2 is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with mplayer2.  If not, see <http://www.gnu.org/licenses/>.
18  */
20 #import <Cocoa/Cocoa.h>
21 #import <CoreServices/CoreServices.h> // for CGDisplayHideCursor
22 #import <IOKit/pwr_mgt/IOPMLib.h>
23 #include <dlfcn.h>
25 #include "cocoa_common.h"
27 #include "config.h"
29 #include "options.h"
30 #include "video_out.h"
31 #include "aspect.h"
33 #include "mp_fifo.h"
34 #include "talloc.h"
36 #include "input/input.h"
37 #include "input/keycodes.h"
38 #include "osx_common.h"
39 #include "mp_msg.h"
41 #ifndef NSOpenGLPFAOpenGLProfile
42 #define NSOpenGLPFAOpenGLProfile 99
43 #endif
45 #ifndef NSOpenGLProfileVersionLegacy
46 #define NSOpenGLProfileVersionLegacy 0x1000
47 #endif
49 #ifndef NSOpenGLProfileVersion3_2Core
50 #define NSOpenGLProfileVersion3_2Core 0x3200
51 #endif
53 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
54 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
56 // add methods not available on OSX versions prior to 10.7
57 #ifndef MAC_OS_X_VERSION_10_7
58 @interface NSView (IntroducedInLion)
59 - (NSRect)convertRectToBacking:(NSRect)aRect;
60 - (void)setWantsBestResolutionOpenGLSurface:(BOOL)aBool;
61 @end
62 #endif
64 // add power management assertion not available on OSX versions prior to 10.7
65 #ifndef kIOPMAssertionTypePreventUserIdleDisplaySleep
66 #define kIOPMAssertionTypePreventUserIdleDisplaySleep \
67     CFSTR("PreventUserIdleDisplaySleep")
68 #endif
70 @interface GLMPlayerWindow : NSWindow <NSWindowDelegate> {
71     struct vo *_vo;
73 - (void)setVideoOutput:(struct vo *)vo;
74 - (BOOL)canBecomeKeyWindow;
75 - (BOOL)canBecomeMainWindow;
76 - (void)fullscreen;
77 - (void)mouseEvent:(NSEvent *)theEvent;
78 - (void)mulSize:(float)multiplier;
79 - (void)setContentSize:(NSSize)newSize keepCentered:(BOOL)keepCentered;
80 @end
82 @interface GLMPlayerOpenGLView : NSView
83 @end
85 struct vo_cocoa_state {
86     NSAutoreleasePool *pool;
87     GLMPlayerWindow *window;
88     NSOpenGLContext *glContext;
89     NSOpenGLPixelFormat *pixelFormat;
91     NSSize current_video_size;
92     NSSize previous_video_size;
94     NSRect screen_frame;
95     NSScreen *screen_handle;
96     NSArray *screen_array;
98     NSInteger windowed_mask;
99     NSInteger fullscreen_mask;
101     NSRect windowed_frame;
103     NSString *window_title;
105     NSInteger window_level;
106     NSInteger fullscreen_window_level;
108     int display_cursor;
109     int cursor_timer;
110     int cursor_autohide_delay;
112     bool did_resize;
113     bool out_fs_resize;
115     IOPMAssertionID power_mgmt_assertion;
118 static int _instances = 0;
120 static void create_menu(void);
122 static struct vo_cocoa_state *vo_cocoa_init_state(struct vo *vo)
124     struct vo_cocoa_state *s = talloc_ptrtype(vo, s);
125     *s = (struct vo_cocoa_state){
126         .pool = [[NSAutoreleasePool alloc] init],
127         .did_resize = NO,
128         .current_video_size = {0,0},
129         .previous_video_size = {0,0},
130         .windowed_mask = NSTitledWindowMask|NSClosableWindowMask|
131             NSMiniaturizableWindowMask|NSResizableWindowMask,
132         .fullscreen_mask = NSBorderlessWindowMask,
133         .windowed_frame = {{0,0},{0,0}},
134         .out_fs_resize = NO,
135         .display_cursor = 1,
136         .cursor_autohide_delay = vo->opts->cursor_autohide_delay,
137         .power_mgmt_assertion = kIOPMNullAssertionID,
138     };
139     return s;
142 static bool supports_hidpi(NSView *view)
144     SEL hdpi_selector = @selector(setWantsBestResolutionOpenGLSurface:);
145     return is_osx_version_at_least(10, 7, 0) && view &&
146            [view respondsToSelector:hdpi_selector];
149 bool vo_cocoa_gui_running(void)
151     return _instances > 0;
154 void *vo_cocoa_glgetaddr(const char *s)
156     void *ret = NULL;
157     void *handle = dlopen(
158         "/System/Library/Frameworks/OpenGL.framework/OpenGL",
159         RTLD_LAZY | RTLD_LOCAL);
160     if (!handle)
161         return NULL;
162     ret = dlsym(handle, s);
163     dlclose(handle);
164     return ret;
167 static void enable_power_management(struct vo *vo)
169     struct vo_cocoa_state *s = vo->cocoa;
170     if (!s->power_mgmt_assertion) return;
171     IOPMAssertionRelease(s->power_mgmt_assertion);
172     s->power_mgmt_assertion = kIOPMNullAssertionID;
175 static void disable_power_management(struct vo *vo)
177     struct vo_cocoa_state *s = vo->cocoa;
178     if (s->power_mgmt_assertion) return;
180     CFStringRef assertion_type = kIOPMAssertionTypeNoDisplaySleep;
181     if (is_osx_version_at_least(10, 7, 0))
182         assertion_type = kIOPMAssertionTypePreventUserIdleDisplaySleep;
184     IOPMAssertionCreateWithName(assertion_type, kIOPMAssertionLevelOn,
185         CFSTR("org.mplayer2.power_mgmt"), &s->power_mgmt_assertion);
188 int vo_cocoa_init(struct vo *vo)
190     vo->cocoa = vo_cocoa_init_state(vo);
191     _instances++;
193     NSApplicationLoad();
194     NSApp = [NSApplication sharedApplication];
195     [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
196     disable_power_management(vo);
198     return 1;
201 void vo_cocoa_uninit(struct vo *vo)
203     struct vo_cocoa_state *s = vo->cocoa;
204     CGDisplayShowCursor(kCGDirectMainDisplay);
205     enable_power_management(vo);
206     [NSApp setPresentationOptions:NSApplicationPresentationDefault];
208     [s->window release];
209     s->window = nil;
210     [s->glContext release];
211     s->glContext = nil;
212     [s->pool release];
213     s->pool = nil;
215     _instances--;
218 void vo_cocoa_pause(struct vo *vo)
220     enable_power_management(vo);
223 void vo_cocoa_resume(struct vo *vo)
225     disable_power_management(vo);
228 static int current_screen_has_dock_or_menubar(struct vo *vo)
230     struct vo_cocoa_state *s = vo->cocoa;
231     NSRect f  = s->screen_frame;
232     NSRect vf = [s->screen_handle visibleFrame];
233     return f.size.height > vf.size.height || f.size.width > vf.size.width;
236 static void update_screen_info(struct vo *vo)
238     struct vo_cocoa_state *s = vo->cocoa;
239     s->screen_array = [NSScreen screens];
240     if (xinerama_screen >= (int)[s->screen_array count]) {
241         mp_msg(MSGT_VO, MSGL_INFO, "[cocoa] Device ID %d does not exist, "
242             "falling back to main device\n", xinerama_screen);
243         xinerama_screen = -1;
244     }
246     if (xinerama_screen < 0) { // default behaviour
247         if (! (s->screen_handle = [s->window screen]) )
248             s->screen_handle = [s->screen_array objectAtIndex:0];
249     } else {
250         s->screen_handle = [s->screen_array objectAtIndex:(xinerama_screen)];
251     }
253     s->screen_frame = [s->screen_handle frame];
256 void vo_cocoa_update_xinerama_info(struct vo *vo)
258     struct vo_cocoa_state *s = vo->cocoa;
259     struct MPOpts *opts = vo->opts;
261     update_screen_info(vo);
262     aspect_save_screenres(vo, s->screen_frame.size.width,
263                               s->screen_frame.size.height);
264     opts->vo_screenwidth = s->screen_frame.size.width;
265     opts->vo_screenheight = s->screen_frame.size.height;
266     xinerama_x = s->screen_frame.origin.x;
267     xinerama_y = s->screen_frame.origin.y;
270 int vo_cocoa_change_attributes(struct vo *vo)
272     return 0;
275 static void resize_window(struct vo *vo)
277     struct vo_cocoa_state *s = vo->cocoa;
278     NSView *view = [s->window contentView];
279     NSRect frame;
281     if (supports_hidpi(view)) {
282         frame = [view convertRectToBacking: [view frame]];
283     } else {
284         frame = [view frame];
285     }
287     vo->dwidth  = frame.size.width;
288     vo->dheight = frame.size.height;
289     [s->glContext update];
292 static void vo_set_level(struct vo *vo, int ontop)
294     struct vo_cocoa_state *s = vo->cocoa;
295     if (ontop) {
296         s->window_level = NSNormalWindowLevel + 1;
297     } else {
298         s->window_level = NSNormalWindowLevel;
299     }
301     if (!vo_fs)
302         [s->window setLevel:s->window_level];
305 void vo_cocoa_ontop(struct vo *vo)
307     struct MPOpts *opts = vo->opts;
308     opts->vo_ontop = !opts->vo_ontop;
309     vo_set_level(vo, opts->vo_ontop);
312 static void update_state_sizes(struct vo_cocoa_state *s,
313                                uint32_t d_width, uint32_t d_height)
315     if (s->current_video_size.width > 0 || s->current_video_size.height > 0)
316         s->previous_video_size = s->current_video_size;
317     s->current_video_size = NSMakeSize(d_width, d_height);
320 static int create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
321                          uint32_t flags, int gl3profile)
323     struct vo_cocoa_state *s = vo->cocoa;
324     struct MPOpts *opts = vo->opts;
326     const NSRect window_rect = NSMakeRect(xinerama_x, xinerama_y,
327                                           d_width, d_height);
328     const NSRect glview_rect = NSMakeRect(0, 0, 100, 100);
330     s->window =
331         [[GLMPlayerWindow alloc] initWithContentRect:window_rect
332                                            styleMask:s->windowed_mask
333                                              backing:NSBackingStoreBuffered
334                                                defer:NO];
336     GLMPlayerOpenGLView *glView =
337         [[GLMPlayerOpenGLView alloc] initWithFrame:glview_rect];
339     // check for HiDPI support and enable it (available on 10.7 +)
340     if (supports_hidpi(glView))
341         [glView setWantsBestResolutionOpenGLSurface:YES];
343     int i = 0;
344     NSOpenGLPixelFormatAttribute attr[32];
345     if (is_osx_version_at_least(10, 7, 0)) {
346       attr[i++] = NSOpenGLPFAOpenGLProfile;
347       if (gl3profile) {
348           attr[i++] = NSOpenGLProfileVersion3_2Core;
349       } else {
350           attr[i++] = NSOpenGLProfileVersionLegacy;
351       }
352     } else if(gl3profile) {
353         mp_msg(MSGT_VO, MSGL_ERR,
354             "[cocoa] Invalid pixel format attribute "
355             "(GL3 is not supported on OSX versions prior to 10.7)\n");
356         return -1;
357     }
358     attr[i++] = NSOpenGLPFADoubleBuffer; // double buffered
359     attr[i] = (NSOpenGLPixelFormatAttribute)0;
361     s->pixelFormat =
362         [[[NSOpenGLPixelFormat alloc] initWithAttributes:attr] autorelease];
363     if (!s->pixelFormat) {
364         mp_msg(MSGT_VO, MSGL_ERR,
365             "[cocoa] Invalid pixel format attribute "
366             "(GL3 not supported?)\n");
367         return -1;
368     }
369     s->glContext =
370         [[NSOpenGLContext alloc] initWithFormat:s->pixelFormat
371                                    shareContext:nil];
373     create_menu();
375     [s->window setContentView:glView];
376     [glView release];
377     [s->window setAcceptsMouseMovedEvents:YES];
378     [s->glContext setView:glView];
379     [s->glContext makeCurrentContext];
380     [s->window setVideoOutput:vo];
382     [NSApp setDelegate:s->window];
383     [s->window setDelegate:s->window];
384     [s->window setContentSize:s->current_video_size];
385     [s->window setContentAspectRatio:s->current_video_size];
386     [s->window setFrameOrigin:NSMakePoint(vo->dx, vo->dy)];
388     if (flags & VOFLAG_HIDDEN) {
389         [s->window orderOut:nil];
390     } else {
391         [s->window makeKeyAndOrderFront:nil];
392         [NSApp activateIgnoringOtherApps:YES];
393     }
395     if (flags & VOFLAG_FULLSCREEN)
396         vo_cocoa_fullscreen(vo);
398     vo_set_level(vo, opts->vo_ontop);
400     return 0;
403 static void update_window(struct vo *vo)
405     struct vo_cocoa_state *s = vo->cocoa;
407     if (s->current_video_size.width  != s->previous_video_size.width ||
408         s->current_video_size.height != s->previous_video_size.height) {
409         if (vo_fs) {
410             // we will resize as soon as we get out of fullscreen
411             s->out_fs_resize = YES;
412         } else {
413             // only if we are not in fullscreen and the video size did
414             // change we resize the window and set a new aspect ratio
415             [s->window setContentSize:s->current_video_size
416                          keepCentered:YES];
417             [s->window setContentAspectRatio:s->current_video_size];
418         }
419     }
422 int vo_cocoa_create_window(struct vo *vo, uint32_t d_width,
423                            uint32_t d_height, uint32_t flags,
424                            int gl3profile)
426     struct vo_cocoa_state *s = vo->cocoa;
428     update_state_sizes(s, d_width, d_height);
430     if (!(s->window || s->glContext)) {
431         if (create_window(vo, d_width, d_height, flags, gl3profile) < 0)
432             return -1;
433     } else {
434         update_window(vo);
435     }
437     resize_window(vo);
439     if (s->window_title)
440         [s->window_title release];
442     s->window_title =
443         [[NSString alloc] initWithUTF8String:vo_get_window_title(vo)];
444     [s->window setTitle: s->window_title];
446     return 0;
449 void vo_cocoa_swap_buffers(struct vo *vo)
451     struct vo_cocoa_state *s = vo->cocoa;
452     [s->glContext flushBuffer];
455 static void vo_cocoa_display_cursor(struct vo *vo, int requested_state)
457     struct vo_cocoa_state *s = vo->cocoa;
458     if (requested_state) {
459         if (!vo_fs || s->cursor_autohide_delay > -2) {
460             s->display_cursor = requested_state;
461             CGDisplayShowCursor(kCGDirectMainDisplay);
462         }
463     } else {
464         if (s->cursor_autohide_delay != -1) {
465             s->display_cursor = requested_state;
466             CGDisplayHideCursor(kCGDirectMainDisplay);
467         }
468     }
471 int vo_cocoa_check_events(struct vo *vo)
473     struct vo_cocoa_state *s = vo->cocoa;
474     NSEvent *event;
475     int ms_time = (int) ([[NSProcessInfo processInfo] systemUptime] * 1000);
477     // automatically hide mouse cursor
478     if (vo_fs && s->display_cursor &&
479         (ms_time - s->cursor_timer >= s->cursor_autohide_delay)) {
480         vo_cocoa_display_cursor(vo, 0);
481         s->cursor_timer = ms_time;
482     }
484     event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
485                    inMode:NSEventTrackingRunLoopMode dequeue:YES];
486     if (event == nil)
487         return 0;
488     [NSApp sendEvent:event];
490     if (s->did_resize) {
491         s->did_resize = NO;
492         resize_window(vo);
493         return VO_EVENT_RESIZE;
494     }
495     // Without SDL's bootstrap code (include SDL.h in mplayer.c),
496     // on Leopard, we have trouble to get the play window automatically focused
497     // when the app is actived. The Following code fix this problem.
498 #ifndef CONFIG_SDL
499     if ([event type] == NSAppKitDefined
500             && [event subtype] == NSApplicationActivatedEventType) {
501         [s->window makeMainWindow];
502         [s->window makeKeyAndOrderFront:nil];
503     }
504 #endif
505     return 0;
508 void vo_cocoa_fullscreen(struct vo *vo)
510     struct vo_cocoa_state *s = vo->cocoa;
511     [s->window fullscreen];
512     resize_window(vo);
515 int vo_cocoa_swap_interval(int enabled)
517     [[NSOpenGLContext currentContext] setValues:&enabled
518                                    forParameter:NSOpenGLCPSwapInterval];
519     return 0;
522 void *vo_cocoa_cgl_context(struct vo *vo)
524     struct vo_cocoa_state *s = vo->cocoa;
525     return [s->glContext CGLContextObj];
528 void *vo_cocoa_cgl_pixel_format(struct vo *vo)
530     return CGLGetPixelFormat(vo_cocoa_cgl_context(vo));
533 int vo_cocoa_cgl_color_size(struct vo *vo)
535     GLint value;
536     CGLDescribePixelFormat(vo_cocoa_cgl_pixel_format(vo), 0,
537                            kCGLPFAColorSize, &value);
538     switch (value) {
539         case 32:
540         case 24:
541             return 8;
542         case 16:
543             return 5;
544     }
546     return 8;
549 static NSMenuItem *new_menu_item(NSMenu *parent_menu, NSString *title,
550                                  SEL action, NSString *key_equivalent)
552     NSMenuItem *new_item =
553         [[NSMenuItem alloc] initWithTitle:title action:action
554                                          keyEquivalent:key_equivalent];
555     [parent_menu addItem:new_item];
556     return [new_item autorelease];
559 static NSMenuItem *new_main_menu_item(NSMenu *parent_menu, NSMenu *child_menu,
560                                       NSString *title)
562     NSMenuItem *new_item =
563         [[NSMenuItem alloc] initWithTitle:title action:nil
564                                          keyEquivalent:@""];
565     [new_item setSubmenu:child_menu];
566     [parent_menu addItem:new_item];
567     return [new_item autorelease];
570 void create_menu()
572     NSAutoreleasePool *pool = [NSAutoreleasePool new];
573     NSMenu *main_menu, *m_menu, *w_menu;
574     NSMenuItem *app_menu_item;
576     main_menu = [[NSMenu new] autorelease];
577     app_menu_item = [[NSMenuItem new] autorelease];
578     [main_menu addItem:app_menu_item];
579     [NSApp setMainMenu: main_menu];
581     m_menu = [[[NSMenu alloc] initWithTitle:@"Movie"] autorelease];
582     new_menu_item(m_menu, @"Half Size", @selector(halfSize), @"0");
583     new_menu_item(m_menu, @"Normal Size", @selector(normalSize), @"1");
584     new_menu_item(m_menu, @"Double Size", @selector(doubleSize), @"2");
586     new_main_menu_item(main_menu, m_menu, @"Movie");
588     w_menu = [[[NSMenu alloc] initWithTitle:@"Window"] autorelease];
589     new_menu_item(w_menu, @"Minimize", @selector(performMiniaturize:), @"m");
590     new_menu_item(w_menu, @"Zoom", @selector(performZoom:), @"z");
592     new_main_menu_item(main_menu, w_menu, @"Window");
593     [pool release];
596 @implementation GLMPlayerWindow
597 - (void)setVideoOutput:(struct vo *)vo
599     _vo = vo;
602 - (void)windowDidResize:(NSNotification *) notification
604     if (_vo) {
605         struct vo_cocoa_state *s = _vo->cocoa;
606         s->did_resize = YES;
607     }
610 - (void)fullscreen
612     struct vo_cocoa_state *s = _vo->cocoa;
613     if (!vo_fs) {
614         update_screen_info(_vo);
615         if (current_screen_has_dock_or_menubar(_vo))
616             [NSApp setPresentationOptions:NSApplicationPresentationHideDock|
617                 NSApplicationPresentationHideMenuBar];
618         s->windowed_frame = [self frame];
619         [self setHasShadow:NO];
620         [self setStyleMask:s->fullscreen_mask];
621         [self setFrame:s->screen_frame display:YES animate:NO];
622         vo_fs = VO_TRUE;
623         vo_cocoa_display_cursor(_vo, 0);
624         [self setMovableByWindowBackground: NO];
625     } else {
626         [NSApp setPresentationOptions:NSApplicationPresentationDefault];
627         [self setHasShadow:YES];
628         [self setStyleMask:s->windowed_mask];
629         [self setTitle:s->window_title];
630         [self setFrame:s->windowed_frame display:YES animate:NO];
631         if (s->out_fs_resize) {
632             [self setContentSize:s->current_video_size keepCentered:YES];
633             s->out_fs_resize = NO;
634         }
635         [self setContentAspectRatio:s->current_video_size];
636         vo_fs = VO_FALSE;
637         vo_cocoa_display_cursor(_vo, 1);
638         [self setMovableByWindowBackground: YES];
639     }
642 - (BOOL)canBecomeMainWindow { return YES; }
643 - (BOOL)canBecomeKeyWindow { return YES; }
644 - (BOOL)acceptsFirstResponder { return YES; }
645 - (BOOL)becomeFirstResponder { return YES; }
646 - (BOOL)resignFirstResponder { return YES; }
647 - (BOOL)windowShouldClose:(id)sender
649     mplayer_put_key(_vo->key_fifo, KEY_CLOSE_WIN);
650     // We have to wait for MPlayer to handle this,
651     // otherwise we are in trouble if the
652     // KEY_CLOSE_WIN handler is disabled
653     return NO;
656 - (BOOL)isMovableByWindowBackground
658     // this is only valid as a starting value. it will be rewritten in the
659     // -fullscreen method.
660     return !vo_fs;
663 - (void)handleQuitEvent:(NSAppleEventDescriptor*)e
664          withReplyEvent:(NSAppleEventDescriptor*)r
666     mplayer_put_key(_vo->key_fifo, KEY_CLOSE_WIN);
669 - (void)keyDown:(NSEvent *)theEvent
671     unsigned char charcode;
672     if (([theEvent modifierFlags] & NSRightAlternateKeyMask) ==
673             NSRightAlternateKeyMask)
674         charcode = *[[theEvent characters] UTF8String];
675     else
676         charcode = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
678     int key = convert_key([theEvent keyCode], charcode);
680     if (key > -1) {
681         if ([theEvent modifierFlags] & NSShiftKeyMask)
682             key |= KEY_MODIFIER_SHIFT;
683         if ([theEvent modifierFlags] & NSControlKeyMask)
684             key |= KEY_MODIFIER_CTRL;
685         if (([theEvent modifierFlags] & NSLeftAlternateKeyMask) ==
686                 NSLeftAlternateKeyMask)
687             key |= KEY_MODIFIER_ALT;
688         if ([theEvent modifierFlags] & NSCommandKeyMask)
689             key |= KEY_MODIFIER_META;
690         mplayer_put_key(_vo->key_fifo, key);
691     }
694 - (void)mouseMoved: (NSEvent *) theEvent
696     if (vo_fs)
697         vo_cocoa_display_cursor(_vo, 1);
700 - (void)mouseDragged:(NSEvent *)theEvent
702     [self mouseEvent: theEvent];
705 - (void)mouseDown:(NSEvent *)theEvent
707     [self mouseEvent: theEvent];
710 - (void)mouseUp:(NSEvent *)theEvent
712     [self mouseEvent: theEvent];
715 - (void)rightMouseDown:(NSEvent *)theEvent
717     [self mouseEvent: theEvent];
720 - (void)rightMouseUp:(NSEvent *)theEvent
722     [self mouseEvent: theEvent];
725 - (void)otherMouseDown:(NSEvent *)theEvent
727     [self mouseEvent: theEvent];
730 - (void)otherMouseUp:(NSEvent *)theEvent
732     [self mouseEvent: theEvent];
735 - (void)scrollWheel:(NSEvent *)theEvent
737     if ([theEvent deltaY] > 0)
738         mplayer_put_key(_vo->key_fifo, MOUSE_BTN3);
739     else
740         mplayer_put_key(_vo->key_fifo, MOUSE_BTN4);
743 - (void)mouseEvent:(NSEvent *)theEvent
745     if ([theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9) {
746         int buttonNumber = [theEvent buttonNumber];
747         // Fix to mplayer defined button order: left, middle, right
748         if (buttonNumber == 1)  buttonNumber = 2;
749         else if (buttonNumber == 2) buttonNumber = 1;
750         switch ([theEvent type]) {
751             case NSLeftMouseDown:
752             case NSRightMouseDown:
753             case NSOtherMouseDown:
754                 mplayer_put_key(_vo->key_fifo,
755                                 (MOUSE_BTN0 + buttonNumber) | MP_KEY_DOWN);
756                 // Looks like Cocoa doesn't create MouseUp events when we are
757                 // doing the second click in a double click. Put in the key_fifo
758                 // the key that would be put from the MouseUp handling code.
759                 if([theEvent clickCount] == 2)
760                    mplayer_put_key(_vo->key_fifo, MOUSE_BTN0 + buttonNumber);
761                 break;
762             case NSLeftMouseUp:
763             case NSRightMouseUp:
764             case NSOtherMouseUp:
765                 mplayer_put_key(_vo->key_fifo, MOUSE_BTN0 + buttonNumber);
766                 break;
767         }
768     }
771 - (void)applicationWillBecomeActive:(NSNotification *)aNotification
773     if (vo_fs && current_screen_has_dock_or_menubar(_vo)) {
774         [NSApp setPresentationOptions:NSApplicationPresentationHideDock|
775                                       NSApplicationPresentationHideMenuBar];
776     }
779 - (void)applicationWillResignActive:(NSNotification *)aNotification
781     if (vo_fs) {
782         [NSApp setPresentationOptions:NSApplicationPresentationDefault];
783     }
786 - (void)applicationDidFinishLaunching:(NSNotification*)notification
788     // Install an event handler so the Quit menu entry works
789     // The proper way using NSApp setDelegate: and
790     // applicationShouldTerminate: does not work,
791     // probably NSApplication never installs its handler.
792     [[NSAppleEventManager sharedAppleEventManager]
793         setEventHandler:self
794         andSelector:@selector(handleQuitEvent:withReplyEvent:)
795         forEventClass:kCoreEventClass
796         andEventID:kAEQuitApplication];
799 - (void)normalSize
801     struct vo_cocoa_state *s = _vo->cocoa;
802     if (!vo_fs)
803         [self setContentSize:s->current_video_size keepCentered:YES];
806 - (void)halfSize { [self mulSize:0.5f];}
808 - (void)doubleSize { [self mulSize:2.0f];}
810 - (void)mulSize:(float)multiplier
812     if (!vo_fs) {
813         struct vo_cocoa_state *s = _vo->cocoa;
814         NSSize size = [[self contentView] frame].size;
815         size.width  = s->current_video_size.width  * (multiplier);
816         size.height = s->current_video_size.height * (multiplier);
817         [self setContentSize:size keepCentered:YES];
818     }
821 - (void)setCenteredContentSize:(NSSize)ns
823     NSRect nf = [self frame];
824     NSRect vf = [[self screen] visibleFrame];
825     NSRect cb = [[self contentView] bounds];
826     int title_height = nf.size.height - cb.size.height;
827     double ratio = (double)ns.width / (double)ns.height;
829     // clip the new size to the visibleFrame's size if needed
830     if (ns.width > vf.size.width || ns.height + title_height > vf.size.height) {
831         ns = vf.size;
832         ns.height -= title_height; // make space for the title bar
834         if (ns.width > ns.height) {
835             ns.height = ((double)ns.width * 1/ratio + 0.5);
836         } else {
837             ns.width = ((double)ns.height * ratio + 0.5);
838         }
839     }
841     int dw = nf.size.width - ns.width;
842     int dh = nf.size.height - ns.height - title_height;
844     nf.origin.x += dw / 2;
845     nf.origin.y += dh / 2;
847     NSRect new_frame =
848         NSMakeRect(nf.origin.x, nf.origin.y, ns.width, ns.height + title_height);
849     [self setFrame:new_frame display:YES animate:NO];
852 - (void)setContentSize:(NSSize)ns keepCentered:(BOOL)keepCentered
854     if (keepCentered) {
855         [self setCenteredContentSize:ns];
856     } else {
857         [self setContentSize:ns];
858     }
860 @end
862 @implementation GLMPlayerOpenGLView
863 - (void)drawRect: (NSRect)rect
865     [[NSColor clearColor] set];
866     NSRectFill([self bounds]);
868 @end