1 /*****************************************************************************
2 * extensions_manager.cpp: Extensions manager for Cocoa
3 ****************************************************************************
4 * Copyright (C) 2009-2012 VideoLAN and authors
7 * Authors: Brendon Justin <brendonjustin@gmail.com>,
8 * Jean-Philippe André < jpeg # videolan.org >
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.
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.
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 *****************************************************************************/
25 #import "ExtensionsManager.h"
27 #import "ExtensionsDialogProvider.h"
29 #import <vlc_modules.h>
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))
36 @implementation ExtensionsManager
38 static ExtensionsManager* instance = nil;
40 @synthesize isUnloading = b_unloading;
42 + (ExtensionsManager *)getInstance:(intf_thread_t *)_p_intf
45 instance = [[[ExtensionsManager alloc] initWithIntf:_p_intf] autorelease];
49 - (id)initWithIntf:(intf_thread_t *)_p_intf
51 if ((self = [super init])) {
53 p_extensions_manager = NULL;
56 p_extDict = [[NSMutableDictionary alloc] init];
67 /** Get the extensions_manager_t if it is loaded and hold the object */
68 - (extensions_manager_t *)getManager
70 if (!p_extensions_manager)
73 vlc_object_hold(p_extensions_manager);
74 return p_extensions_manager;
77 - (void)buildMenu:(NSMenu *)extMenu
79 assert(extMenu != nil);
81 // This case can happen: do nothing
84 vlc_mutex_lock(&p_extensions_manager->lock);
86 extension_t *p_ext = NULL;
88 FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
89 bool b_Active = extension_IsActivated(p_extensions_manager, p_ext);
91 NSString *titleString = [NSString stringWithCString:p_ext->psz_title
92 encoding:NSUTF8StringEncoding];
94 if (b_Active && extension_HasMenu(p_extensions_manager, p_ext)) {
95 NSMenu *submenu = [[NSMenu alloc] initWithTitle:titleString];
96 NSMenuItem *submenuItem = [extMenu addItemWithTitle:titleString
100 [extMenu setSubmenu:submenu forItem:submenuItem];
103 char **ppsz_titles = NULL;
104 uint16_t *pi_ids = NULL;
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) {
111 titleString = [NSString stringWithCString:ppsz_titles[i]
112 encoding:NSUTF8StringEncoding];
113 NSMenuItem *menuItem = [submenu addItemWithTitle:titleString
114 action:@selector(triggerMenu:)
116 [menuItem setTarget:self];
117 menuItem.tag = MENU_MAP(pi_ids[i], i_ext);
119 free(ppsz_titles[i]);
122 NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
123 action:@selector(triggerMenu:)
125 [menuItem setEnabled:NO];
130 msg_Warn(p_intf, "Could not get menu for extension '%s'",
132 NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
133 action:@selector(triggerMenu:)
135 [menuItem setEnabled:NO];
138 [submenu addItem:[NSMenuItem separatorItem]];
140 NSMenuItem *deactivateItem = [submenu addItemWithTitle:@"Deactivate"
141 action:@selector(triggerMenu:)
143 [deactivateItem setTarget:self];
144 deactivateItem.tag = MENU_MAP(0, i_ext);
148 NSMenuItem *menuItem = [extMenu addItemWithTitle:titleString
149 action:@selector(triggerMenu:)
151 [menuItem setTarget:self];
153 if (!extension_TriggerOnly(p_extensions_manager, p_ext)) {
155 [menuItem setState:NSOnState];
157 menuItem.tag = MENU_MAP(0, i_ext);
163 vlc_mutex_unlock(&p_extensions_manager->lock);
166 - (BOOL)loadExtensions
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) {
173 [delegate extensionsUpdated];
177 p_extensions_manager->p_module =
178 module_need(p_extensions_manager, "extension", NULL, false);
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;
185 [delegate extensionsUpdated];
189 /* Initialize dialog provider */
190 p_edp = [ExtensionsDialogProvider sharedInstance:p_intf];
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;
200 [delegate extensionsUpdated];
206 [delegate extensionsUpdated];
210 - (void)unloadExtensions
212 if (!p_extensions_manager)
216 module_unneed(p_extensions_manager, p_extensions_manager->p_module);
217 vlc_object_release(p_extensions_manager);
218 p_extensions_manager = NULL;
221 - (void)reloadExtensions
223 [self unloadExtensions];
224 [self loadExtensions];
227 [delegate extensionsUpdated];
230 - (void)triggerMenu:(id)sender
232 uint32_t identifier = [(NSMenuItem *)sender tag];
234 uint16_t i_ext = MENU_GET_EXTENSION(identifier);
235 uint16_t i_action = MENU_GET_ACTION(identifier);
237 vlc_mutex_lock(&p_extensions_manager->lock);
239 if ((int) i_ext > p_extensions_manager->extensions.i_size) {
240 msg_Dbg(p_intf, "can't trigger extension with wrong id %d",
245 extension_t *p_ext = ARRAY_VAL(p_extensions_manager->extensions, i_ext);
246 assert(p_ext != NULL);
248 vlc_mutex_unlock(&p_extensions_manager->lock);
251 msg_Dbg(p_intf, "activating or triggering extension '%s', id %d",
252 p_ext->psz_title, i_ext);
254 if (extension_TriggerOnly(p_extensions_manager, p_ext)) {
255 extension_Trigger(p_extensions_manager, p_ext);
257 if (!extension_IsActivated(p_extensions_manager, p_ext))
258 extension_Activate(p_extensions_manager, p_ext);
260 extension_Deactivate(p_extensions_manager, p_ext);
265 msg_Dbg(p_intf, "triggering extension '%s', on menu with id = 0x%x",
266 p_ext->psz_title, i_action);
268 extension_TriggerMenu(p_extensions_manager, p_ext, i_action);
272 - (void)inputChanged:(input_thread_t *)p_input
274 //This is unlikely, but can happen if no extension modules can be loaded.
275 if (p_extensions_manager == NULL)
277 vlc_mutex_lock(&p_extensions_manager->lock);
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);
286 vlc_mutex_unlock(&p_extensions_manager->lock);
289 - (void)playingChanged:(int)state
291 //This is unlikely, but can happen if no extension modules can be loaded.
292 if (p_extensions_manager == NULL)
294 vlc_mutex_lock(&p_extensions_manager->lock);
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);
303 vlc_mutex_unlock(&p_extensions_manager->lock);
306 - (void)metaChanged:(input_item_t *)p_input
308 //This is unlikely, but can happen if no extension modules can be loaded.
309 if (p_extensions_manager == NULL)
311 vlc_mutex_lock(&p_extensions_manager->lock);
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);
318 vlc_mutex_unlock(&p_extensions_manager->lock);
323 msg_Dbg(p_intf, "Killing extension dialog provider");
324 [ExtensionsDialogProvider killInstance];
326 if (p_extensions_manager)
327 vlc_object_release(p_extensions_manager);
336 return p_extensions_manager != NULL;
341 return b_unloading || b_failed;