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