]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VideoView.m
dash: MPDManager: Fixing memory leak
[vlc] / modules / gui / macosx / VideoView.m
1 /*****************************************************************************
2  * VideoView.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2002-2011 VLC authors and VideoLAN
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             {
209                 [[VLCCoreInteraction sharedInstance] play];
210             }
211             else
212             {
213                 val.i_int |= (int)CocoaKeyToVLC( key );
214                 var_Set( p_vout->p_libvlc, "key-pressed", val );
215             }
216             vlc_object_release( p_vout );
217         }
218         else
219             msg_Dbg( VLCIntf, "could not send keyevent to VLC core" );
220     }
221     else
222         [super keyDown: o_event];
223 }
224
225 - (void)mouseDown:(NSEvent *)o_event
226 {
227     vout_thread_t * p_vout = getVout();
228     vlc_value_t val;
229     if( p_vout )
230     {
231         if( ( [o_event type] == NSLeftMouseDown ) &&
232           ( ! ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
233         {
234             if( [o_event clickCount] <= 1 )
235             {
236                 /* single clicking */
237                 var_Get( p_vout, "mouse-button-down", &val );
238                 val.i_int |= 1;
239                 var_Set( p_vout, "mouse-button-down", val );
240             }
241             else
242             {
243                 /* multiple clicking */
244                 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
245             }
246         }
247         else if( ( [o_event type] == NSRightMouseDown ) ||
248                ( ( [o_event type] == NSLeftMouseDown ) &&
249                  ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
250         {
251             msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
252             [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
253         }
254         vlc_object_release( p_vout );
255     }
256
257     [super mouseDown: o_event];
258 }
259
260 - (void)otherMouseDown:(NSEvent *)o_event
261 {
262     if( [o_event type] == NSOtherMouseDown )
263     {
264         vout_thread_t * p_vout = getVout();
265         vlc_value_t val;
266
267         if (p_vout)
268         {
269             var_Get( p_vout, "mouse-button-down", &val );
270             val.i_int |= 2;
271             var_Set( p_vout, "mouse-button-down", val );
272         }
273         vlc_object_release( p_vout );
274     }
275
276     [super mouseDown: o_event];
277 }
278
279 - (void)rightMouseDown:(NSEvent *)o_event
280 {
281     if( [o_event type] == NSRightMouseDown )
282     {
283         vout_thread_t * p_vout = getVout();
284         if (p_vout)
285             [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
286         vlc_object_release( p_vout );
287     }
288
289     [super mouseDown: o_event];
290 }
291
292 - (void)mouseUp:(NSEvent *)o_event
293 {
294     if( [o_event type] == NSLeftMouseUp )
295     {
296         vout_thread_t * p_vout = getVout();
297         if (p_vout)
298         {
299             vlc_value_t val;
300             int x, y;
301
302             var_GetCoords( p_vout, "mouse-moved", &x, &y );
303             var_SetCoords( p_vout, "mouse-clicked", x, y );
304
305             var_Get( p_vout, "mouse-button-down", &val );
306             val.i_int &= ~1;
307             var_Set( p_vout, "mouse-button-down", val );
308             vlc_object_release( p_vout );
309         }
310     }
311
312     [super mouseUp: o_event];
313 }
314
315 - (void)otherMouseUp:(NSEvent *)o_event
316 {
317     if( [o_event type] == NSOtherMouseUp )
318     {
319         vout_thread_t * p_vout = getVout();
320         if (p_vout)
321         {
322             vlc_value_t val;
323             var_Get( p_vout, "mouse-button-down", &val );
324             val.i_int &= ~2;
325             var_Set( p_vout, "mouse-button-down", val );
326             vlc_object_release( p_vout );
327         }
328     }
329
330     [super mouseUp: o_event];
331 }
332
333 - (void)rightMouseUp:(NSEvent *)o_event
334 {
335     if( [o_event type] == NSRightMouseUp )
336     {
337         vout_thread_t * p_vout = getVout();
338         if (p_vout)
339         {
340             [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
341             vlc_object_release( p_vout );
342         }
343     }
344
345     [super mouseUp: o_event];
346 }
347
348 - (void)mouseDragged:(NSEvent *)o_event
349 {
350     [self mouseMoved: o_event];
351 }
352
353 - (void)otherMouseDragged:(NSEvent *)o_event
354 {
355     [self mouseMoved: o_event];
356 }
357
358 - (void)rightMouseDragged:(NSEvent *)o_event
359 {
360     [self mouseMoved: o_event];
361 }
362
363 - (void)mouseMoved:(NSEvent *)o_event
364 {
365     vout_thread_t * p_vout = getVout();
366     if( p_vout )
367     {
368         NSPoint ml;
369         NSRect s_rect;
370         BOOL b_inside;
371
372         s_rect = [o_view bounds];
373         ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
374         b_inside = [o_view mouse: ml inRect: s_rect];
375
376         if( b_inside )
377         {
378             var_SetCoords( p_vout, "mouse-moved", ((int)ml.x), ((int)ml.y) );
379         }
380         vlc_object_release( p_vout );
381         [[VLCMain sharedInstance] showFullscreenController];
382     }
383
384     [super mouseMoved: o_event];
385 }
386
387 - (BOOL)mouseDownCanMoveWindow
388 {
389     return YES;
390 }
391
392 - (BOOL)acceptsFirstResponder
393 {
394     return YES;
395 }
396
397 - (BOOL)becomeFirstResponder
398 {
399     return YES;
400 }
401
402 - (BOOL)resignFirstResponder
403 {
404     /* We need to stay the first responder or we'll miss some
405        events */
406     return NO;
407 }
408
409 - (void)renewGState
410 {
411     [[self window] disableScreenUpdatesUntilFlush];
412
413     [super renewGState];
414 }
415 @end