1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2003 VideoLAN
7 * Authors: Colin Delacroix <colin@zoy.org>
8 * Florian G. Pflug <fgp@phlo.org>
9 * Jon Lech Johansen <jon-vl@nanocrew.net>
10 * Derk-Jan Hartman <hartman at videolan dot org>
11 * Eric Petit <titer@m0k.org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
33 #include <string.h> /* strerror() */
35 /* BeginFullScreen, EndFullScreen */
36 #include <QuickTime/QuickTime.h>
43 /*****************************************************************************
44 * VLCWindow implementation
45 *****************************************************************************/
46 @implementation VLCWindow
48 - (id)initWithVout:(vout_thread_t *)_p_vout frame:(NSRect *)s_frame
50 [self setReleasedWhenClosed: YES];
54 /* p_real_vout: the vout we have to use to check for video-on-top
55 and a few other things. If we are the QuickTime output, it's us.
56 It we are the OpenGL provider, it is our parent. */
57 if( p_vout->i_object_type == VLC_OBJECT_OPENGL )
59 p_real_vout = (vout_thread_t *) p_vout->p_parent;
66 p_fullscreen_state = NULL;
67 i_time_mouse_last_moved = mdate();
70 vlc_bool_t b_main_screen;
72 /* Find out on which screen to open the window */
73 int i_device = var_GetInteger( p_vout, "video-device" );
76 /* No preference specified. Use the main screen */
77 o_screen = [NSScreen mainScreen];
82 NSArray *o_screens = [NSScreen screens];
84 if( [o_screens count] < (unsigned) i_device )
86 o_screen = [NSScreen mainScreen];
92 o_screen = [o_screens objectAtIndex: i_device];
93 var_SetInteger( p_vout, "macosx-vdev", i_device );
94 b_main_screen = ( i_device == 0 );
98 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
100 if( p_vout->b_fullscreen )
102 NSRect screen_rect = [o_screen frame];
103 screen_rect.origin.x = screen_rect.origin.y = 0;
105 /* Creates a window with size: screen_rect on o_screen */
106 [self initWithContentRect: screen_rect
107 styleMask: NSBorderlessWindowMask
108 backing: NSBackingStoreBuffered
109 defer: YES screen: o_screen];
113 BeginFullScreen( &p_fullscreen_state, NULL, 0, 0,
114 NULL, NULL, fullScreenAllowEvents );
119 unsigned int i_stylemask = NSTitledWindowMask |
120 NSMiniaturizableWindowMask |
121 NSClosableWindowMask |
122 NSResizableWindowMask;
127 s_rect.size.width = p_vout->i_window_width;
128 s_rect.size.height = p_vout->i_window_height;
135 [self initWithContentRect: s_rect
136 styleMask: i_stylemask
137 backing: NSBackingStoreBuffered
138 defer: YES screen: o_screen];
140 [self setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
142 if( var_GetBool( p_real_vout, "video-on-top" ) )
144 [self setLevel: NSStatusWindowLevel];
154 [self makeKeyAndOrderFront: nil];
156 /* We'll catch mouse events */
157 [self setAcceptsMouseMovedEvents: YES];
158 [self makeFirstResponder: self];
166 if( p_fullscreen_state )
168 EndFullScreen( p_fullscreen_state, NULL );
173 - (void)setOnTop:(bool)b_on_top
177 [self setLevel: NSStatusWindowLevel];
181 [self setLevel: NSNormalWindowLevel];
185 - (void)hideMouse:(bool)b_hide
189 NSView *o_contents = [self contentView];
191 ml = [self convertScreenToBase:[NSEvent mouseLocation]];
192 ml = [o_contents convertPoint:ml fromView:nil];
193 b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
195 if( b_hide && b_inside )
197 [NSCursor setHiddenUntilMouseMoves: YES];
201 [NSCursor setHiddenUntilMouseMoves: NO];
207 if( p_fullscreen_state )
209 if( mdate() - i_time_mouse_last_moved > 3000000 )
211 [self hideMouse: YES];
216 [self hideMouse: NO];
219 /* Disable screensaver */
220 UpdateSystemActivity( UsrActivity );
223 - (void)scaleWindowWithFactor: (float)factor
226 int i_corrected_height, i_corrected_width;
228 NSPoint topleftscreen;
230 if ( !p_vout->b_fullscreen )
233 topleftbase.y = [self frame].size.height;
234 topleftscreen = [self convertBaseToScreen: topleftbase];
236 if( p_vout->render.i_height * p_vout->render.i_aspect >
237 p_vout->render.i_width * VOUT_ASPECT_FACTOR )
239 i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
241 newsize.width = (int) ( i_corrected_width * factor );
242 newsize.height = (int) ( p_vout->render.i_height * factor );
246 i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
247 p_vout->render.i_aspect;
248 newsize.width = (int) ( p_vout->render.i_width * factor );
249 newsize.height = (int) ( i_corrected_height * factor );
252 [self setContentSize: newsize];
254 [self setFrameTopLeftPoint: topleftscreen];
255 p_vout->i_changes |= VOUT_SIZE_CHANGE;
259 - (void)toggleFloatOnTop
262 if( var_Get( p_vout, "video-on-top", &val )>=0 && val.b_bool)
264 val.b_bool = VLC_FALSE;
265 var_Set( p_vout, "video-on-top", val );
269 val.b_bool = VLC_TRUE;
270 var_Set( p_vout, "video-on-top", val );
274 - (void)toggleFullscreen
277 val.b_bool = !p_real_vout->b_fullscreen;
278 var_Set( p_real_vout, "fullscreen", val );
283 return( p_vout->b_fullscreen );
286 - (BOOL)canBecomeKeyWindow
291 /* Sometimes crashes VLC....
292 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
294 return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
297 - (void)keyDown:(NSEvent *)o_event
301 unsigned int i_pressed_modifiers = 0;
304 i_pressed_modifiers = [o_event modifierFlags];
306 if( i_pressed_modifiers & NSShiftKeyMask )
307 val.i_int |= KEY_MODIFIER_SHIFT;
308 if( i_pressed_modifiers & NSControlKeyMask )
309 val.i_int |= KEY_MODIFIER_CTRL;
310 if( i_pressed_modifiers & NSAlternateKeyMask )
311 val.i_int |= KEY_MODIFIER_ALT;
312 if( i_pressed_modifiers & NSCommandKeyMask )
313 val.i_int |= KEY_MODIFIER_COMMAND;
315 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
319 /* Escape should always get you out of fullscreen */
320 if( key == (unichar) 0x1b )
322 if( [self isFullscreen] )
324 [self toggleFullscreen];
327 else if ( key == ' ' )
330 val.i_int = config_GetInt( p_vout, "key-play-pause" );
331 var_Set( p_vout->p_vlc, "key-pressed", val );
335 val.i_int |= CocoaKeyToVLC( key );
336 var_Set( p_vout->p_vlc, "key-pressed", val );
341 [super keyDown: o_event];
347 NSMutableString * o_title;
348 playlist_t * p_playlist;
355 p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
358 if( p_playlist == NULL )
363 vlc_mutex_lock( &p_playlist->object_lock );
364 o_title = [NSMutableString stringWithUTF8String:
365 p_playlist->status.p_item->input.psz_uri];
366 vlc_mutex_unlock( &p_playlist->object_lock );
367 vlc_object_release( p_playlist );
371 NSRange prefix_range = [o_title rangeOfString: @"file:"];
372 if( prefix_range.location != NSNotFound )
374 [o_title deleteCharactersInRange: prefix_range];
377 [self setTitleWithRepresentedFilename: o_title];
381 [self setTitle: [NSString stringWithCString: VOUT_TITLE]];
385 /* This is actually the same as VLCControls::stop. */
386 - (BOOL)windowShouldClose:(id)sender
388 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
390 if( p_playlist == NULL )
395 playlist_Stop( p_playlist );
396 vlc_object_release( p_playlist );
398 /* The window will be closed by the intf later. */
402 - (BOOL)acceptsFirstResponder
407 - (BOOL)becomeFirstResponder
412 - (BOOL)resignFirstResponder
414 /* We need to stay the first responder or we'll miss some
419 - (void)mouseDown:(NSEvent *)o_event
423 switch( [o_event type] )
425 case NSLeftMouseDown:
427 var_Get( p_vout, "mouse-button-down", &val );
429 var_Set( p_vout, "mouse-button-down", val );
434 [super mouseDown: o_event];
439 - (void)otherMouseDown:(NSEvent *)o_event
443 switch( [o_event type] )
445 case NSOtherMouseDown:
447 var_Get( p_vout, "mouse-button-down", &val );
449 var_Set( p_vout, "mouse-button-down", val );
454 [super mouseDown: o_event];
459 - (void)rightMouseDown:(NSEvent *)o_event
463 switch( [o_event type] )
465 case NSRightMouseDown:
467 var_Get( p_vout, "mouse-button-down", &val );
469 var_Set( p_vout, "mouse-button-down", val );
474 [super mouseDown: o_event];
479 - (void)mouseUp:(NSEvent *)o_event
483 switch( [o_event type] )
488 b_val.b_bool = VLC_TRUE;
489 var_Set( p_vout, "mouse-clicked", b_val );
491 var_Get( p_vout, "mouse-button-down", &val );
493 var_Set( p_vout, "mouse-button-down", val );
498 [super mouseUp: o_event];
503 - (void)otherMouseUp:(NSEvent *)o_event
507 switch( [o_event type] )
511 var_Get( p_vout, "mouse-button-down", &val );
513 var_Set( p_vout, "mouse-button-down", val );
518 [super mouseUp: o_event];
523 - (void)rightMouseUp:(NSEvent *)o_event
527 switch( [o_event type] )
531 var_Get( p_vout, "mouse-button-down", &val );
533 var_Set( p_vout, "mouse-button-down", val );
538 [super mouseUp: o_event];
543 - (void)mouseDragged:(NSEvent *)o_event
545 [self mouseMoved: o_event];
548 - (void)otherMouseDragged:(NSEvent *)o_event
550 [self mouseMoved: o_event];
553 - (void)rightMouseDragged:(NSEvent *)o_event
555 [self mouseMoved: o_event];
558 - (void)mouseMoved:(NSEvent *)o_event
565 i_time_mouse_last_moved = mdate();
567 o_view = [self contentView];
568 s_rect = [o_view bounds];
569 ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
570 b_inside = [o_view mouse: ml inRect: s_rect];
575 int i_width, i_height, i_x, i_y;
577 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
578 (unsigned int)s_rect.size.height,
579 &i_x, &i_y, &i_width, &i_height );
581 val.i_int = ( ((int)ml.x) - i_x ) *
582 p_vout->render.i_width / i_width;
583 var_Set( p_vout, "mouse-x", val );
585 if( [[o_view className] isEqualToString: @"VLCGLView"] )
587 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
588 p_vout->render.i_height / i_height;
592 val.i_int = ( ((int)ml.y) - i_y ) *
593 p_vout->render.i_height / i_height;
595 var_Set( p_vout, "mouse-y", val );
597 val.b_bool = VLC_TRUE;
598 var_Set( p_vout, "mouse-moved", val );
601 [super mouseMoved: o_event];