]> git.sesse.net Git - vlc/blob - modules/gui/macosx/ExtensionsManager.m
macosx: CAS: re-write the destination section's appearance to make it less cluttered
[vlc] / modules / gui / macosx / ExtensionsManager.m
1 /*****************************************************************************
2  * extensions_manager.cpp: Extensions manager for Cocoa
3  ****************************************************************************
4  * Copyright (C) 2009-2012 VideoLAN and authors
5  * $Id$
6  *
7  * Authors: Brendon Justin <brendonjustin@gmail.com>,
8  *          Jean-Philippe AndrĂ© < jpeg # videolan.org >
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "ExtensionsManager.h"
26
27 #import "ExtensionsDialogProvider.h"
28
29 #import <vlc_modules.h>
30 #import "assert.h"
31
32 #define MENU_MAP(a,e) ((uint32_t)( (((uint16_t)a) << 16) | ((uint16_t)e) ))
33 #define MENU_GET_ACTION(a) ( (uint16_t)( ((uint32_t)a) >> 16 ) )
34 #define MENU_GET_EXTENSION(a) ( (uint16_t)( ((uint32_t)a) & 0xFFFF ) )
35
36 @implementation ExtensionsManager
37
38 static ExtensionsManager* instance = nil;
39
40 @synthesize isUnloading = b_unloading;
41
42 + (ExtensionsManager *)getInstance:( intf_thread_t *)_p_intf
43 {
44     if( !instance )
45         instance = [[[ExtensionsManager alloc] initWithIntf:_p_intf] autorelease];
46     return instance;
47 }
48
49 - (id)initWithIntf:(intf_thread_t *)_p_intf
50 {
51     if ((self = [super init]))
52     {
53         p_intf = _p_intf;
54         p_extensions_manager = NULL;
55         p_edp = NULL;
56
57         p_extDict = [[NSMutableDictionary alloc] init];
58
59         b_unloading = false;
60         b_failed = false;
61
62         delegate = nil;
63     }
64
65     return self;
66 }
67
68 /** Get the extensions_manager_t if it is loaded and hold the object */
69 - (extensions_manager_t *)getManager
70 {
71     if( !p_extensions_manager )
72         return NULL;
73
74     vlc_object_hold( p_extensions_manager );
75     return p_extensions_manager;
76 }
77
78 - (void)buildMenu:(NSMenu *)extMenu
79 {
80     assert( extMenu != nil );
81     if( ![self isLoaded] )
82     {
83         // This case can happen: do nothing
84         return;
85     }
86
87     vlc_mutex_lock( &p_extensions_manager->lock );
88
89     extension_t *p_ext = NULL;
90     int i_ext = 0;
91     FOREACH_ARRAY( p_ext, p_extensions_manager->extensions )
92     {
93         bool b_Active = extension_IsActivated( p_extensions_manager, p_ext );
94
95         NSString *titleString = [NSString stringWithCString:p_ext->psz_title
96                                                    encoding:NSUTF8StringEncoding];
97
98         if( b_Active && extension_HasMenu( p_extensions_manager, p_ext ) )
99         {
100             NSMenu *submenu = [[NSMenu alloc] initWithTitle:titleString];
101             NSMenuItem *submenuItem = [extMenu addItemWithTitle:titleString
102                                                          action:nil
103                                                   keyEquivalent:@""];
104
105             [extMenu setSubmenu:submenu forItem:submenuItem];
106             [submenu release];
107
108             char **ppsz_titles = NULL;
109             uint16_t *pi_ids = NULL;
110             size_t i_num = 0;
111
112             if( extension_GetMenu( p_extensions_manager, p_ext,
113                                    &ppsz_titles, &pi_ids ) == VLC_SUCCESS )
114             {
115                 for( int i = 0; ppsz_titles[i] != NULL; ++i )
116                 {
117                     ++i_num;
118                     titleString = [NSString stringWithCString:ppsz_titles[i]
119                                                      encoding:NSUTF8StringEncoding];
120                     NSMenuItem *menuItem = [submenu addItemWithTitle:titleString
121                                                               action:@selector(triggerMenu:)
122                                                        keyEquivalent:@""];
123                     [menuItem setTarget:self];
124                     menuItem.tag = MENU_MAP(pi_ids[i], i_ext);
125
126                     free( ppsz_titles[i] );
127                 }
128                 if( !i_num )
129                 {
130                     NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
131                                                               action:@selector(triggerMenu:)
132                                                        keyEquivalent:@""];
133                     [menuItem setEnabled:NO];
134                 }
135                 free( ppsz_titles );
136                 free( pi_ids );
137             }
138             else
139             {
140                 msg_Warn( p_intf, "Could not get menu for extension '%s'",
141                           p_ext->psz_title );
142                 NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
143                                                           action:@selector(triggerMenu:)
144                                                    keyEquivalent:@""];
145                 [menuItem setEnabled:NO];
146             }
147
148             [submenu addItem:[NSMenuItem separatorItem]];
149
150             NSMenuItem *deactivateItem = [submenu addItemWithTitle:@"Deactivate"
151                                                             action:@selector(triggerMenu:)
152                                                      keyEquivalent:@""];
153             [deactivateItem setTarget:self];
154             deactivateItem.tag = MENU_MAP(0, i_ext);
155         }
156         else
157         {
158             NSMenuItem *menuItem = [extMenu addItemWithTitle:titleString
159                                                      action:@selector(triggerMenu:)
160                                               keyEquivalent:@""];
161             [menuItem setTarget:self];
162
163             if( !extension_TriggerOnly( p_extensions_manager, p_ext ) )
164             {
165                 if ( b_Active )
166                     [menuItem setState:NSOnState];
167             }
168             menuItem.tag = MENU_MAP(0, i_ext);
169         }
170         i_ext++;
171     }
172     FOREACH_END()
173
174     vlc_mutex_unlock( &p_extensions_manager->lock );
175 }
176
177 - (BOOL)loadExtensions
178 {
179     if( !p_extensions_manager )
180     {
181         p_extensions_manager = ( extensions_manager_t* )
182                     vlc_object_create( p_intf, sizeof( extensions_manager_t ) );
183         if( !p_extensions_manager )
184         {
185             b_failed = true;
186             [delegate extensionsUpdated];
187             return false;
188         }
189
190         p_extensions_manager->p_module =
191                 module_need( p_extensions_manager, "extension", NULL, false );
192
193         if( !p_extensions_manager->p_module )
194         {
195             msg_Err( p_intf, "Unable to load extensions module" );
196             vlc_object_release( p_extensions_manager );
197             p_extensions_manager = NULL;
198             b_failed = true;
199             [delegate extensionsUpdated];
200             return false;
201         }
202
203         /* Initialize dialog provider */
204         p_edp = [ExtensionsDialogProvider sharedInstance:p_intf];
205         [p_edp retain];
206
207         if( !p_edp )
208         {
209             msg_Err( p_intf, "Unable to create dialogs provider for extensions" );
210             module_unneed( p_extensions_manager,
211                            p_extensions_manager->p_module );
212             vlc_object_release( p_extensions_manager );
213             p_extensions_manager = NULL;
214             b_failed = true;
215             [delegate extensionsUpdated];
216             return false;
217         }
218         b_unloading = false;
219     }
220     b_failed = false;
221     [delegate extensionsUpdated];
222     return true;
223 }
224
225 - (void)unloadExtensions
226 {
227     if( !p_extensions_manager )
228         return;
229     b_unloading = true;
230     [p_edp release];
231     module_unneed( p_extensions_manager, p_extensions_manager->p_module );
232     vlc_object_release( p_extensions_manager );
233     p_extensions_manager = NULL;
234 }
235
236 - (void)reloadExtensions
237 {
238     [self unloadExtensions];
239     [self loadExtensions];
240
241     if (delegate)
242         [delegate extensionsUpdated];
243 }
244
245 - (void)triggerMenu:(id)sender
246 {
247     uint32_t identifier = [(NSMenuItem *)sender tag];
248
249     uint16_t i_ext = MENU_GET_EXTENSION( identifier );
250     uint16_t i_action = MENU_GET_ACTION( identifier );
251
252     vlc_mutex_lock( &p_extensions_manager->lock );
253
254     if( (int) i_ext > p_extensions_manager->extensions.i_size )
255     {
256         msg_Dbg( p_intf, "can't trigger extension with wrong id %d",
257                  (int) i_ext );
258         return;
259     }
260
261     extension_t *p_ext = ARRAY_VAL( p_extensions_manager->extensions, i_ext );
262     assert( p_ext != NULL);
263
264     vlc_mutex_unlock( &p_extensions_manager->lock );
265
266     if( i_action == 0 )
267     {
268         msg_Dbg( p_intf, "activating or triggering extension '%s', id %d",
269                  p_ext->psz_title, i_ext );
270
271         if( extension_TriggerOnly( p_extensions_manager, p_ext ) )
272         {
273             extension_Trigger( p_extensions_manager, p_ext );
274         }
275         else
276         {
277             if( !extension_IsActivated( p_extensions_manager, p_ext ) )
278                 extension_Activate( p_extensions_manager, p_ext );
279             else
280                 extension_Deactivate( p_extensions_manager, p_ext );
281         }
282     }
283     else
284     {
285         msg_Dbg( p_intf, "triggering extension '%s', on menu with id = 0x%x",
286                  p_ext->psz_title, i_action );
287
288         extension_TriggerMenu( p_extensions_manager, p_ext, i_action );
289     }
290 }
291
292 - (void)inputChanged:(input_thread_t *)p_input
293 {
294     //This is unlikely, but can happen if no extension modules can be loaded.
295     if ( p_extensions_manager == NULL )
296         return ;
297     vlc_mutex_lock( &p_extensions_manager->lock );
298
299     extension_t *p_ext;
300     FOREACH_ARRAY( p_ext, p_extensions_manager->extensions )
301     {
302         if( extension_IsActivated( p_extensions_manager, p_ext ) )
303         {
304             extension_SetInput( p_extensions_manager, p_ext, p_input );
305         }
306     }
307     FOREACH_END()
308
309     vlc_mutex_unlock( &p_extensions_manager->lock );
310 }
311
312 - (void)playingChanged:(int)state
313 {
314     //This is unlikely, but can happen if no extension modules can be loaded.
315     if ( p_extensions_manager == NULL )
316         return ;
317     vlc_mutex_lock( &p_extensions_manager->lock );
318
319     extension_t *p_ext;
320     FOREACH_ARRAY( p_ext, p_extensions_manager->extensions )
321     {
322         if( extension_IsActivated( p_extensions_manager, p_ext ) )
323         {
324             extension_PlayingChanged( p_extensions_manager, p_ext, state );
325         }
326     }
327     FOREACH_END()
328
329     vlc_mutex_unlock( &p_extensions_manager->lock );
330 }
331
332 - (void)metaChanged:(input_item_t *)p_input
333 {
334     //This is unlikely, but can happen if no extension modules can be loaded.
335     if ( p_extensions_manager == NULL )
336         return ;
337     vlc_mutex_lock( &p_extensions_manager->lock );
338     extension_t *p_ext;
339     FOREACH_ARRAY( p_ext, p_extensions_manager->extensions )
340     {
341         if( extension_IsActivated( p_extensions_manager, p_ext ) )
342         {
343             extension_MetaChanged( p_extensions_manager, p_ext );
344         }
345     }
346     FOREACH_END()
347     vlc_mutex_unlock( &p_extensions_manager->lock );
348 }
349
350 - (void)dealloc
351 {
352     msg_Dbg( p_intf, "Killing extension dialog provider" );
353     [ExtensionsDialogProvider killInstance];
354
355     if( p_extensions_manager )
356         vlc_object_release( p_extensions_manager );
357
358     [p_extDict release];
359
360     [super dealloc];
361 }
362
363 - (BOOL)isLoaded
364 {
365     return p_extensions_manager != NULL;
366 }
367
368 - (BOOL)cannotLoad
369 {
370     return b_unloading || b_failed;
371 }
372
373 @end