]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VideoView.m
86e9b05433f83fbdb056416d2bdf562f4c0069e7
[vlc] / modules / gui / macosx / VideoView.m
1 /*****************************************************************************
2  * VideoView.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2002-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          Eric Petit <titer@m0k.org>
9  *          Benjamin Pracht <bigben at videolan dot org>
10  *          Pierre d'Herbemont <pdherbemont # videolan org>
11  *          Felix Paul Kühne <fkuehne at videolan dot org>
12  *
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.
17  * 
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.
22  *
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #import <stdlib.h>                                                 /* free() */
32 #import <string.h>
33
34 #import "intf.h"
35 #import "VideoView.h"
36 #import "CoreInteraction.h"
37 #import "MainMenu.h"
38 #import "MainWindow.h"
39
40 #import <vlc_common.h>
41 #import <vlc_vout_window.h>
42 #import <vlc_vout_display.h>
43 #import <vlc_keys.h>
44 /*****************************************************************************
45  * DeviceCallback: Callback triggered when the video-device variable is changed
46  *****************************************************************************/
47 int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
48                      vlc_value_t old_val, vlc_value_t new_val, void *param )
49 {
50     vlc_value_t val;
51     vout_thread_t *p_vout = (vout_thread_t *)p_this;
52
53     msg_Dbg( p_vout, "set %"PRId64, new_val.i_int );
54     var_Create( p_vout->p_libvlc, "video-device", VLC_VAR_INTEGER );
55     var_Set( p_vout->p_libvlc, "video-device", new_val );
56
57     val.b_bool = true;
58     var_Set( p_vout, "intf-change", val );
59     return VLC_SUCCESS;
60 }
61
62 /*****************************************************************************
63  * VLCVoutView implementation
64  *****************************************************************************/
65 @implementation VLCVoutView
66 - (void)setVoutView:(id)theView
67 {
68     vout_thread_t * p_vout = getVout();
69     if( !p_vout )
70         return;
71
72     int i_device;
73     NSArray *o_screens = [NSScreen screens];
74     if( [o_screens count] <= 0 )
75     {
76         msg_Err( VLCIntf, "no OSX screens available" );
77         return;
78     }
79
80     /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
81     if( var_Type( p_vout->p_libvlc, "video-device" ) == 0 )
82     {
83         i_device = var_GetInteger( p_vout, "macosx-vdev" );
84     }
85     else
86     {
87         i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
88     }
89
90     /* Setup the menuitem for the multiple displays. */
91     if( var_Type( p_vout, "video-device" ) == 0 )
92     {
93         int i = 1;
94         vlc_value_t val2, text;
95         NSScreen * o_screen;
96
97         var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
98                    VLC_VAR_HASCHOICE );
99         text.psz_string = _("Fullscreen Video Device");
100         var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
101
102         NSEnumerator * o_enumerator = [o_screens objectEnumerator];
103
104         val2.i_int = 0;
105         text.psz_string = _("Default");
106         var_Change( p_vout, "video-device", VLC_VAR_ADDCHOICE, &val2, &text );
107         var_Set( p_vout, "video-device", val2 );
108
109         while( (o_screen = [o_enumerator nextObject]) != NULL )
110         {
111             char psz_temp[255];
112             NSRect s_rect = [o_screen frame];
113
114             snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1, "%s %d (%dx%d)", _("Screen"), i, (int)s_rect.size.width, (int)s_rect.size.height );
115
116             text.psz_string = psz_temp;
117             val2.i_int = (int)[o_screen displayID];
118             var_Change( p_vout, "video-device", VLC_VAR_ADDCHOICE, &val2, &text );
119             if( (int)[o_screen displayID] == i_device )
120             {
121                 var_Set( p_vout, "video-device", val2 );
122             }
123             i++;
124         }
125
126         var_AddCallback( p_vout, "video-device", DeviceCallback,
127                         NULL );
128
129         val2.b_bool = true;
130         var_Set( p_vout, "intf-change", val2 );
131     }
132
133     /* Add the view. It's automatically resized to fit the window */
134     if (o_view) {
135         [o_view removeFromSuperview];
136         [o_view release];
137     }
138     o_view = theView;
139     [o_view retain];
140     [self addSubview: o_view];
141     [self setAutoresizesSubviews: YES];
142
143     /* make sure that we look alright */
144     [[self window] setAlphaValue: var_CreateGetFloat( p_vout, "macosx-opaqueness" )];
145     vlc_object_release( p_vout );
146 }
147
148 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
149 {
150     [super resizeSubviewsWithOldSize: oldBoundsSize];
151     [o_view setFrameSize: [self frame].size];
152 }
153
154 - (void)closeVout
155 {
156     vout_thread_t * p_vout = getVout();
157     if( !p_vout )
158     {
159         var_DelCallback( p_vout, "video-device", DeviceCallback, NULL );
160         vlc_object_release( p_vout );
161     }
162
163     /* Make sure we don't see a white flash */
164     [o_view removeFromSuperview];
165     [o_view release];
166     o_view = nil;
167 }
168
169 - (void)scrollWheel:(NSEvent *)theEvent
170 {
171     VLCControls * o_controls = (VLCControls *)[[NSApp delegate] controls];
172     [o_controls scrollWheel: theEvent];
173 }
174
175 - (void)keyDown:(NSEvent *)o_event
176 {
177     unichar key = 0;
178     vlc_value_t val;
179     unsigned int i_pressed_modifiers = 0;
180     val.i_int = 0;
181
182     i_pressed_modifiers = [o_event modifierFlags];
183
184     if( i_pressed_modifiers & NSShiftKeyMask )
185         val.i_int |= KEY_MODIFIER_SHIFT;
186     if( i_pressed_modifiers & NSControlKeyMask )
187         val.i_int |= KEY_MODIFIER_CTRL;
188     if( i_pressed_modifiers & NSAlternateKeyMask )
189         val.i_int |= KEY_MODIFIER_ALT;
190     if( i_pressed_modifiers & NSCommandKeyMask )
191         val.i_int |= KEY_MODIFIER_COMMAND;
192
193     key = [[[o_event charactersIgnoringModifiers] lowercaseString] characterAtIndex: 0];
194
195     if( key )
196     {
197         vout_thread_t * p_vout = getVout();
198         /* Escape should always get you out of fullscreen */
199         if( key == (unichar) 0x1b )
200         {
201             playlist_t * p_playlist = pl_Get( VLCIntf );
202              if( var_GetBool( p_playlist, "fullscreen") )
203                  [[VLCCoreInteraction sharedInstance] toggleFullscreen];
204         }
205         else if ( p_vout )
206         {
207             if( key == ' ')
208                 val.i_int = config_GetInt( p_vout, "key-play-pause" );
209             else
210                 val.i_int |= (int)CocoaKeyToVLC( key );
211             var_Set( p_vout->p_libvlc, "key-pressed", val );
212             vlc_object_release( p_vout );
213         }
214         else
215             msg_Dbg( VLCIntf, "could not send keyevent to VLC core" );
216     }
217     else
218         [super keyDown: o_event];
219 }
220
221 - (void)mouseDown:(NSEvent *)o_event
222 {
223     vout_thread_t * p_vout = getVout();
224     vlc_value_t val;
225     if( p_vout )
226     {
227         if( ( [o_event type] == NSLeftMouseDown ) &&
228           ( ! ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
229         {
230             if( [o_event clickCount] <= 1 )
231             {
232                 /* single clicking */
233                 var_Get( p_vout, "mouse-button-down", &val );
234                 val.i_int |= 1;
235                 var_Set( p_vout, "mouse-button-down", val );
236             }
237             else
238             {
239                 /* multiple clicking */
240                 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
241             }
242         }
243         else if( ( [o_event type] == NSRightMouseDown ) ||
244                ( ( [o_event type] == NSLeftMouseDown ) &&
245                  ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
246         {
247             msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
248             [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
249         }
250         vlc_object_release( p_vout );
251     }
252
253     [super mouseDown: o_event];
254 }
255
256 - (void)otherMouseDown:(NSEvent *)o_event
257 {
258     if( [o_event type] == NSOtherMouseDown )
259     {
260         vout_thread_t * p_vout = getVout();
261         vlc_value_t val;
262
263         if (p_vout)
264         {
265             var_Get( p_vout, "mouse-button-down", &val );
266             val.i_int |= 2;
267             var_Set( p_vout, "mouse-button-down", val );
268         }
269         vlc_object_release( p_vout );
270     }
271
272     [super mouseDown: o_event];
273 }
274
275 - (void)rightMouseDown:(NSEvent *)o_event
276 {
277     if( [o_event type] == NSRightMouseDown )
278     {
279         vout_thread_t * p_vout = getVout();
280         if (p_vout)
281             [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
282         vlc_object_release( p_vout );
283     }
284
285     [super mouseDown: o_event];
286 }
287
288 - (void)mouseUp:(NSEvent *)o_event
289 {
290     if( [o_event type] == NSLeftMouseUp )
291     {
292         vout_thread_t * p_vout = getVout();
293         if (p_vout)
294         {
295             vlc_value_t val;
296             int x, y;
297
298             var_GetCoords( p_vout, "mouse-moved", &x, &y );
299             var_SetCoords( p_vout, "mouse-clicked", x, y );
300
301             var_Get( p_vout, "mouse-button-down", &val );
302             val.i_int &= ~1;
303             var_Set( p_vout, "mouse-button-down", val );
304             vlc_object_release( p_vout );
305         }
306     }
307
308     [super mouseUp: o_event];
309 }
310
311 - (void)otherMouseUp:(NSEvent *)o_event
312 {
313     if( [o_event type] == NSOtherMouseUp )
314     {
315         vout_thread_t * p_vout = getVout();
316         if (p_vout)
317         {
318             vlc_value_t val;
319             var_Get( p_vout, "mouse-button-down", &val );
320             val.i_int &= ~2;
321             var_Set( p_vout, "mouse-button-down", val );
322             vlc_object_release( p_vout );
323         }
324     }
325
326     [super mouseUp: o_event];
327 }
328
329 - (void)rightMouseUp:(NSEvent *)o_event
330 {
331     if( [o_event type] == NSRightMouseUp )
332     {
333         vout_thread_t * p_vout = getVout();
334         if (p_vout)
335         {
336             [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
337             vlc_object_release( p_vout );
338         }
339     }
340
341     [super mouseUp: o_event];
342 }
343
344 - (void)mouseDragged:(NSEvent *)o_event
345 {
346     [self mouseMoved: o_event];
347 }
348
349 - (void)otherMouseDragged:(NSEvent *)o_event
350 {
351     [self mouseMoved: o_event];
352 }
353
354 - (void)rightMouseDragged:(NSEvent *)o_event
355 {
356     [self mouseMoved: o_event];
357 }
358
359 - (void)mouseMoved:(NSEvent *)o_event
360 {
361     vout_thread_t * p_vout = getVout();
362     if( p_vout )
363     {
364         NSPoint ml;
365         NSRect s_rect;
366         BOOL b_inside;
367
368         s_rect = [o_view bounds];
369         ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
370         b_inside = [o_view mouse: ml inRect: s_rect];
371
372         if( b_inside )
373         {
374             var_SetCoords( p_vout, "mouse-moved", ((int)ml.x), ((int)ml.y) );
375         }
376         vlc_object_release( p_vout );
377         [[VLCMain sharedInstance] showFullscreenController];
378     }
379
380     [super mouseMoved: o_event];
381 }
382
383 - (BOOL)mouseDownCanMoveWindow
384 {
385     return YES;
386 }
387
388 - (BOOL)acceptsFirstResponder
389 {
390     return YES;
391 }
392
393 - (BOOL)becomeFirstResponder
394 {
395     return YES;
396 }
397
398 - (BOOL)resignFirstResponder
399 {
400     /* We need to stay the first responder or we'll miss some
401        events */
402     return NO;
403 }
404
405 - (void)renewGState
406 {
407     [[self window] disableScreenUpdatesUntilFlush];
408
409     [super renewGState];
410 }
411 @end