]> git.sesse.net Git - vlc/blob - modules/gui/macosx/ExtensionsManager.m
macosx: cosmetics
[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         p_intf = _p_intf;
53         p_extensions_manager = NULL;
54         p_edp = NULL;
55
56         p_extDict = [[NSMutableDictionary alloc] init];
57
58         b_unloading = false;
59         b_failed = false;
60
61         delegate = nil;
62     }
63
64     return self;
65 }
66
67 /** Get the extensions_manager_t if it is loaded and hold the object */
68 - (extensions_manager_t *)getManager
69 {
70     if (!p_extensions_manager)
71         return NULL;
72
73     vlc_object_hold(p_extensions_manager);
74     return p_extensions_manager;
75 }
76
77 - (void)buildMenu:(NSMenu *)extMenu
78 {
79     assert(extMenu != nil);
80     if (![self isLoaded])
81         // This case can happen: do nothing
82         return;
83
84     vlc_mutex_lock(&p_extensions_manager->lock);
85
86     extension_t *p_ext = NULL;
87     int i_ext = 0;
88     FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
89         bool b_Active = extension_IsActivated(p_extensions_manager, p_ext);
90
91         NSString *titleString = [NSString stringWithCString:p_ext->psz_title
92                                                    encoding:NSUTF8StringEncoding];
93
94         if (b_Active && extension_HasMenu(p_extensions_manager, p_ext)) {
95             NSMenu *submenu = [[NSMenu alloc] initWithTitle:titleString];
96             NSMenuItem *submenuItem = [extMenu addItemWithTitle:titleString
97                                                          action:nil
98                                                   keyEquivalent:@""];
99
100             [extMenu setSubmenu:submenu forItem:submenuItem];
101             [submenu release];
102
103             char **ppsz_titles = NULL;
104             uint16_t *pi_ids = NULL;
105             size_t i_num = 0;
106
107             if (extension_GetMenu(p_extensions_manager, p_ext,
108                                    &ppsz_titles, &pi_ids) == VLC_SUCCESS) {
109                 for (int i = 0; ppsz_titles[i] != NULL; ++i) {
110                     ++i_num;
111                     titleString = [NSString stringWithCString:ppsz_titles[i]
112                                                      encoding:NSUTF8StringEncoding];
113                     NSMenuItem *menuItem = [submenu addItemWithTitle:titleString
114                                                               action:@selector(triggerMenu:)
115                                                        keyEquivalent:@""];
116                     [menuItem setTarget:self];
117                     menuItem.tag = MENU_MAP(pi_ids[i], i_ext);
118
119                     free(ppsz_titles[i]);
120                 }
121                 if (!i_num) {
122                     NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
123                                                               action:@selector(triggerMenu:)
124                                                        keyEquivalent:@""];
125                     [menuItem setEnabled:NO];
126                 }
127                 free(ppsz_titles);
128                 free(pi_ids);
129             } else {
130                 msg_Warn(p_intf, "Could not get menu for extension '%s'",
131                           p_ext->psz_title);
132                 NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
133                                                           action:@selector(triggerMenu:)
134                                                    keyEquivalent:@""];
135                 [menuItem setEnabled:NO];
136             }
137
138             [submenu addItem:[NSMenuItem separatorItem]];
139
140             NSMenuItem *deactivateItem = [submenu addItemWithTitle:@"Deactivate"
141                                                             action:@selector(triggerMenu:)
142                                                      keyEquivalent:@""];
143             [deactivateItem setTarget:self];
144             deactivateItem.tag = MENU_MAP(0, i_ext);
145         }
146         else
147         {
148             NSMenuItem *menuItem = [extMenu addItemWithTitle:titleString
149                                                      action:@selector(triggerMenu:)
150                                               keyEquivalent:@""];
151             [menuItem setTarget:self];
152
153             if (!extension_TriggerOnly(p_extensions_manager, p_ext)) {
154                 if (b_Active)
155                     [menuItem setState:NSOnState];
156             }
157             menuItem.tag = MENU_MAP(0, i_ext);
158         }
159         i_ext++;
160     }
161     FOREACH_END()
162
163     vlc_mutex_unlock(&p_extensions_manager->lock);
164 }
165
166 - (BOOL)loadExtensions
167 {
168     if (!p_extensions_manager) {
169         p_extensions_manager = (extensions_manager_t*)
170                     vlc_object_create(p_intf, sizeof(extensions_manager_t));
171         if (!p_extensions_manager) {
172             b_failed = true;
173             [delegate extensionsUpdated];
174             return false;
175         }
176
177         p_extensions_manager->p_module =
178                 module_need(p_extensions_manager, "extension", NULL, false);
179
180         if (!p_extensions_manager->p_module) {
181             msg_Err(p_intf, "Unable to load extensions module");
182             vlc_object_release(p_extensions_manager);
183             p_extensions_manager = NULL;
184             b_failed = true;
185             [delegate extensionsUpdated];
186             return false;
187         }
188
189         /* Initialize dialog provider */
190         p_edp = [ExtensionsDialogProvider sharedInstance:p_intf];
191         [p_edp retain];
192
193         if (!p_edp) {
194             msg_Err(p_intf, "Unable to create dialogs provider for extensions");
195             module_unneed(p_extensions_manager,
196                            p_extensions_manager->p_module);
197             vlc_object_release(p_extensions_manager);
198             p_extensions_manager = NULL;
199             b_failed = true;
200             [delegate extensionsUpdated];
201             return false;
202         }
203         b_unloading = false;
204     }
205     b_failed = false;
206     [delegate extensionsUpdated];
207     return true;
208 }
209
210 - (void)unloadExtensions
211 {
212     if (!p_extensions_manager)
213         return;
214     b_unloading = true;
215     [p_edp release];
216     module_unneed(p_extensions_manager, p_extensions_manager->p_module);
217     vlc_object_release(p_extensions_manager);
218     p_extensions_manager = NULL;
219 }
220
221 - (void)reloadExtensions
222 {
223     [self unloadExtensions];
224     [self loadExtensions];
225
226     if (delegate)
227         [delegate extensionsUpdated];
228 }
229
230 - (void)triggerMenu:(id)sender
231 {
232     uint32_t identifier = [(NSMenuItem *)sender tag];
233
234     uint16_t i_ext = MENU_GET_EXTENSION(identifier);
235     uint16_t i_action = MENU_GET_ACTION(identifier);
236
237     vlc_mutex_lock(&p_extensions_manager->lock);
238
239     if ((int) i_ext > p_extensions_manager->extensions.i_size) {
240         msg_Dbg(p_intf, "can't trigger extension with wrong id %d",
241                  (int) i_ext);
242         return;
243     }
244
245     extension_t *p_ext = ARRAY_VAL(p_extensions_manager->extensions, i_ext);
246     assert(p_ext != NULL);
247
248     vlc_mutex_unlock(&p_extensions_manager->lock);
249
250     if (i_action == 0) {
251         msg_Dbg(p_intf, "activating or triggering extension '%s', id %d",
252                  p_ext->psz_title, i_ext);
253
254         if (extension_TriggerOnly(p_extensions_manager, p_ext)) {
255             extension_Trigger(p_extensions_manager, p_ext);
256         } else {
257             if (!extension_IsActivated(p_extensions_manager, p_ext))
258                 extension_Activate(p_extensions_manager, p_ext);
259             else
260                 extension_Deactivate(p_extensions_manager, p_ext);
261         }
262     }
263     else
264     {
265         msg_Dbg(p_intf, "triggering extension '%s', on menu with id = 0x%x",
266                  p_ext->psz_title, i_action);
267
268         extension_TriggerMenu(p_extensions_manager, p_ext, i_action);
269     }
270 }
271
272 - (void)inputChanged:(input_thread_t *)p_input
273 {
274     //This is unlikely, but can happen if no extension modules can be loaded.
275     if (p_extensions_manager == NULL)
276         return;
277     vlc_mutex_lock(&p_extensions_manager->lock);
278
279     extension_t *p_ext;
280     FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
281         if (extension_IsActivated(p_extensions_manager, p_ext))
282             extension_SetInput(p_extensions_manager, p_ext, p_input);
283     }
284     FOREACH_END()
285
286     vlc_mutex_unlock(&p_extensions_manager->lock);
287 }
288
289 - (void)playingChanged:(int)state
290 {
291     //This is unlikely, but can happen if no extension modules can be loaded.
292     if (p_extensions_manager == NULL)
293         return;
294     vlc_mutex_lock(&p_extensions_manager->lock);
295
296     extension_t *p_ext;
297     FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
298         if (extension_IsActivated(p_extensions_manager, p_ext))
299             extension_PlayingChanged(p_extensions_manager, p_ext, state);
300     }
301     FOREACH_END()
302
303     vlc_mutex_unlock(&p_extensions_manager->lock);
304 }
305
306 - (void)metaChanged:(input_item_t *)p_input
307 {
308     //This is unlikely, but can happen if no extension modules can be loaded.
309     if (p_extensions_manager == NULL)
310         return;
311     vlc_mutex_lock(&p_extensions_manager->lock);
312     extension_t *p_ext;
313     FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
314         if (extension_IsActivated(p_extensions_manager, p_ext))
315             extension_MetaChanged(p_extensions_manager, p_ext);
316     }
317     FOREACH_END()
318     vlc_mutex_unlock(&p_extensions_manager->lock);
319 }
320
321 - (void)dealloc
322 {
323     msg_Dbg(p_intf, "Killing extension dialog provider");
324     [ExtensionsDialogProvider killInstance];
325
326     if (p_extensions_manager)
327         vlc_object_release(p_extensions_manager);
328
329     [p_extDict release];
330
331     [super dealloc];
332 }
333
334 - (BOOL)isLoaded
335 {
336     return p_extensions_manager != NULL;
337 }
338
339 - (BOOL)cannotLoad
340 {
341     return b_unloading || b_failed;
342 }
343
344 @end