1 /*****************************************************************************
2 * VLCExtensionsManager.m: 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 "VLCExtensionsManager.h"
27 #import "VLCExtensionsDialogProvider.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 @interface VLCExtensionsManager()
38 extensions_manager_t *p_extensions_manager;
39 VLCExtensionsDialogProvider *_extensionDialogProvider;
41 NSMutableDictionary *p_extDict;
43 BOOL b_failed; ///< Flag set to true if we could not load the module
47 @implementation VLCExtensionsManager
54 p_extensions_manager = NULL;
55 _extensionDialogProvider = [[VLCExtensionsDialogProvider alloc] init];
57 p_extDict = [[NSMutableDictionary alloc] init];
66 - (void)buildMenu:(NSMenu *)extMenu
68 assert(extMenu != nil);
70 /* check if stuff was loaded, which can fail */
71 if (![self isLoaded]) {
72 BOOL b_ret = [self loadExtensions];
76 intf_thread_t *p_intf = getIntf();
78 vlc_mutex_lock(&p_extensions_manager->lock);
80 extension_t *p_ext = NULL;
83 FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
84 bool b_Active = extension_IsActivated(p_extensions_manager, p_ext);
86 NSString *titleString = toNSStr(p_ext->psz_title);
88 if (b_Active && extension_HasMenu(p_extensions_manager, p_ext)) {
89 NSMenu *submenu = [[NSMenu alloc] initWithTitle:titleString];
90 NSMenuItem *submenuItem = [extMenu addItemWithTitle:titleString
94 [extMenu setSubmenu:submenu forItem:submenuItem];
96 char **ppsz_titles = NULL;
97 uint16_t *pi_ids = NULL;
100 if (extension_GetMenu(p_extensions_manager, p_ext, &ppsz_titles, &pi_ids) == VLC_SUCCESS) {
101 for (int i = 0; ppsz_titles[i] != NULL; ++i) {
103 titleString = toNSStr(ppsz_titles[i]);
104 NSMenuItem *menuItem = [submenu addItemWithTitle:titleString
105 action:@selector(triggerMenu:)
107 [menuItem setTarget:self];
108 menuItem.tag = MENU_MAP(pi_ids[i], i_ext);
110 free(ppsz_titles[i]);
113 NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
114 action:@selector(triggerMenu:)
116 [menuItem setEnabled:NO];
121 msg_Warn(p_intf, "Could not get menu for extension '%s'",
123 NSMenuItem *menuItem = [submenu addItemWithTitle:@"Empty"
124 action:@selector(triggerMenu:)
126 [menuItem setEnabled:NO];
129 [submenu addItem:[NSMenuItem separatorItem]];
131 NSMenuItem *deactivateItem = [submenu addItemWithTitle:@"Deactivate"
132 action:@selector(triggerMenu:)
134 [deactivateItem setTarget:self];
135 deactivateItem.tag = MENU_MAP(0, i_ext);
139 NSMenuItem *menuItem = [extMenu addItemWithTitle:titleString
140 action:@selector(triggerMenu:)
142 [menuItem setTarget:self];
144 if (!extension_TriggerOnly(p_extensions_manager, p_ext)) {
146 [menuItem setState:NSOnState];
148 menuItem.tag = MENU_MAP(0, i_ext);
154 vlc_mutex_unlock(&p_extensions_manager->lock);
157 - (BOOL)loadExtensions
159 intf_thread_t *p_intf = getIntf();
160 if (!p_extensions_manager) {
161 p_extensions_manager = (extensions_manager_t*)vlc_object_create(p_intf, sizeof(extensions_manager_t));
162 if (!p_extensions_manager) {
167 p_extensions_manager->p_module = module_need(p_extensions_manager, "extension", NULL, false);
169 if (!p_extensions_manager->p_module) {
170 msg_Err(p_intf, "Unable to load extensions module");
171 vlc_object_release(p_extensions_manager);
172 p_extensions_manager = NULL;
177 _isUnloading = false;
183 - (void)unloadExtensions
185 if (!p_extensions_manager)
189 module_unneed(p_extensions_manager, p_extensions_manager->p_module);
190 vlc_object_release(p_extensions_manager);
191 p_extensions_manager = NULL;
194 - (void)reloadExtensions
196 [self unloadExtensions];
197 [self loadExtensions];
200 - (void)triggerMenu:(id)sender
202 intf_thread_t *p_intf = getIntf();
203 uint32_t identifier = (unsigned int)[(NSMenuItem *)sender tag];
205 uint16_t i_ext = MENU_GET_EXTENSION(identifier);
206 uint16_t i_action = MENU_GET_ACTION(identifier);
208 vlc_mutex_lock(&p_extensions_manager->lock);
210 if ((int) i_ext > p_extensions_manager->extensions.i_size) {
211 msg_Dbg(p_intf, "can't trigger extension with wrong id %d",
216 extension_t *p_ext = ARRAY_VAL(p_extensions_manager->extensions, i_ext);
217 assert(p_ext != NULL);
219 vlc_mutex_unlock(&p_extensions_manager->lock);
222 msg_Dbg(p_intf, "activating or triggering extension '%s', id %d",
223 p_ext->psz_title, i_ext);
225 if (extension_TriggerOnly(p_extensions_manager, p_ext)) {
226 extension_Trigger(p_extensions_manager, p_ext);
228 if (!extension_IsActivated(p_extensions_manager, p_ext))
229 extension_Activate(p_extensions_manager, p_ext);
231 extension_Deactivate(p_extensions_manager, p_ext);
236 msg_Dbg(p_intf, "triggering extension '%s', on menu with id = 0x%x",
237 p_ext->psz_title, i_action);
239 extension_TriggerMenu(p_extensions_manager, p_ext, i_action);
243 - (void)inputChanged:(input_thread_t *)p_input
245 //This is unlikely, but can happen if no extension modules can be loaded.
246 if (p_extensions_manager == NULL)
248 vlc_mutex_lock(&p_extensions_manager->lock);
251 FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
252 if (extension_IsActivated(p_extensions_manager, p_ext))
253 extension_SetInput(p_extensions_manager, p_ext, p_input);
257 vlc_mutex_unlock(&p_extensions_manager->lock);
260 - (void)playingChanged:(int)state
262 //This is unlikely, but can happen if no extension modules can be loaded.
263 if (p_extensions_manager == NULL)
265 vlc_mutex_lock(&p_extensions_manager->lock);
268 FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
269 if (extension_IsActivated(p_extensions_manager, p_ext))
270 extension_PlayingChanged(p_extensions_manager, p_ext, state);
274 vlc_mutex_unlock(&p_extensions_manager->lock);
277 - (void)metaChanged:(input_item_t *)p_input
279 //This is unlikely, but can happen if no extension modules can be loaded.
280 if (p_extensions_manager == NULL)
282 vlc_mutex_lock(&p_extensions_manager->lock);
284 FOREACH_ARRAY(p_ext, p_extensions_manager->extensions) {
285 if (extension_IsActivated(p_extensions_manager, p_ext))
286 extension_MetaChanged(p_extensions_manager, p_ext);
289 vlc_mutex_unlock(&p_extensions_manager->lock);
294 intf_thread_t *p_intf = getIntf();
295 msg_Dbg(p_intf, "Deinitializing extensions manager");
297 _extensionDialogProvider = nil;
298 if (p_extensions_manager)
299 vlc_object_release(p_extensions_manager);
304 return p_extensions_manager != NULL;
309 return self.isUnloading || b_failed;