Mercurial > audlegacy
annotate audacious/pluginenum.c @ 1938:1d9c1026d9f8 trunk
[svn] - DoubleSize support.
This has bugs, the most notable one being that DoubleSize only works
right if you restart the player.
The second bug is rather obvious too. No osmosis skinengine. No
TinyPlayer. Classic-esque skinengine only. This is because the
doublesize algorithm hates you and wants you to go die in a fire.
author | nenolod |
---|---|
date | Sun, 05 Nov 2006 04:43:16 -0800 |
parents | a6e6d3500c13 |
children | 94a720c9bfef |
rev | line source |
---|---|
0 | 1 /* BMP - Cross-platform multimedia player |
2 * Copyright (C) 2003-2004 BMP development team. | |
3 * | |
4 * Based on XMMS: | |
5 * Copyright (C) 1998-2003 XMMS development team. | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
1460 | 8 * it under the terms of the GNU General Public License as published by |
0 | 9 * the Free Software Foundation; either version 2 of the License, or |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
1459 | 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
0 | 20 */ |
21 | |
22 #ifdef HAVE_CONFIG_H | |
23 # include "config.h" | |
24 #endif | |
25 | |
1631 | 26 #ifndef SHARED_SUFFIX |
27 # define SHARED_SUFFIX G_MODULE_SUFFIX | |
28 #endif | |
29 | |
0 | 30 #include "pluginenum.h" |
31 | |
32 #include <glib.h> | |
33 #include <gmodule.h> | |
34 #include <glib/gprintf.h> | |
35 #include <string.h> | |
36 | |
37 #include "controlsocket.h" | |
38 #include "main.h" | |
1653 | 39 #include "mainwin.h" |
538
e4e897d20791
[svn] remove libaudcore, we never did anything with it
nenolod
parents:
380
diff
changeset
|
40 #include "playback.h" |
0 | 41 #include "playlist.h" |
42 #include "util.h" | |
43 | |
44 #include "effect.h" | |
45 #include "general.h" | |
46 #include "input.h" | |
47 #include "output.h" | |
48 #include "visualization.h" | |
49 | |
50 const gchar *plugin_dir_list[] = { | |
51 PLUGINSUBS, | |
52 NULL | |
53 }; | |
54 | |
55 GHashTable *plugin_matrix = NULL; | |
1563 | 56 GList *lowlevel_list = NULL; |
0 | 57 |
58 static gint | |
59 inputlist_compare_func(gconstpointer a, gconstpointer b) | |
60 { | |
61 const InputPlugin *ap = a, *bp = b; | |
62 return strcasecmp(ap->description, bp->description); | |
63 } | |
64 | |
65 static gint | |
66 outputlist_compare_func(gconstpointer a, gconstpointer b) | |
67 { | |
68 const OutputPlugin *ap = a, *bp = b; | |
69 return strcasecmp(ap->description, bp->description); | |
70 } | |
71 | |
72 static gint | |
73 effectlist_compare_func(gconstpointer a, gconstpointer b) | |
74 { | |
75 const EffectPlugin *ap = a, *bp = b; | |
76 return strcasecmp(ap->description, bp->description); | |
77 } | |
78 | |
79 static gint | |
80 generallist_compare_func(gconstpointer a, gconstpointer b) | |
81 { | |
82 const GeneralPlugin *ap = a, *bp = b; | |
83 return strcasecmp(ap->description, bp->description); | |
84 } | |
85 | |
86 static gint | |
87 vislist_compare_func(gconstpointer a, gconstpointer b) | |
88 { | |
89 const VisPlugin *ap = a, *bp = b; | |
90 return strcasecmp(ap->description, bp->description); | |
91 } | |
92 | |
93 static gboolean | |
94 plugin_is_duplicate(const gchar * filename) | |
95 { | |
96 GList *l; | |
97 const gchar *basename = g_basename(filename); | |
98 | |
99 /* FIXME: messy stuff */ | |
100 | |
101 for (l = ip_data.input_list; l; l = g_list_next(l)) | |
102 if (!strcmp(basename, g_basename(INPUT_PLUGIN(l->data)->filename))) | |
103 return TRUE; | |
104 | |
105 for (l = op_data.output_list; l; l = g_list_next(l)) | |
106 if (!strcmp(basename, g_basename(OUTPUT_PLUGIN(l->data)->filename))) | |
107 return TRUE; | |
108 | |
109 for (l = ep_data.effect_list; l; l = g_list_next(l)) | |
110 if (!strcmp(basename, g_basename(EFFECT_PLUGIN(l->data)->filename))) | |
111 return TRUE; | |
112 | |
113 for (l = gp_data.general_list; l; l = g_list_next(l)) | |
114 if (!strcmp(basename, g_basename(GENERAL_PLUGIN(l->data)->filename))) | |
115 return TRUE; | |
116 | |
117 for (l = vp_data.vis_list; l; l = g_list_next(l)) | |
118 if (!strcmp(basename, g_basename(VIS_PLUGIN(l->data)->filename))) | |
119 return TRUE; | |
120 | |
1563 | 121 for (l = lowlevel_list; l; l = g_list_next(l)) |
122 if (!strcmp(basename, g_basename(VIS_PLUGIN(l->data)->filename))) | |
123 return TRUE; | |
124 | |
0 | 125 return FALSE; |
126 } | |
127 | |
128 | |
129 #define PLUGIN_GET_INFO(x) ((PluginGetInfoFunc)(x))() | |
130 typedef Plugin * (*PluginGetInfoFunc) (void); | |
131 | |
132 static void | |
133 input_plugin_init(Plugin * plugin) | |
134 { | |
135 InputPlugin *p = INPUT_PLUGIN(plugin); | |
136 | |
137 p->get_vis_type = input_get_vis_type; | |
138 p->add_vis_pcm = input_add_vis_pcm; | |
139 | |
140 /* Pretty const casts courtesy of XMMS's plugin.h legacy. Anyone | |
141 else thinks we could use a CONST macro to solve the warnings? | |
142 - descender */ | |
143 p->set_info = (void (*)(gchar *, gint, gint, gint, gint)) playlist_set_info; | |
144 p->set_info_text = (void (*)(gchar *)) input_set_info_text; | |
1273
3b990c26fc46
[svn] - Support for the buffer indicator in playpaus.png that was apparently
nhjm449
parents:
906
diff
changeset
|
145 p->set_status_buffering = (void (*)(gboolean)) input_set_status_buffering; |
3b990c26fc46
[svn] - Support for the buffer indicator in playpaus.png that was apparently
nhjm449
parents:
906
diff
changeset
|
146 |
0 | 147 ip_data.input_list = g_list_append(ip_data.input_list, p); |
148 | |
149 g_hash_table_replace(plugin_matrix, g_path_get_basename(p->filename), | |
150 GINT_TO_POINTER(1)); | |
151 } | |
152 | |
153 static void | |
154 output_plugin_init(Plugin * plugin) | |
155 { | |
156 OutputPlugin *p = OUTPUT_PLUGIN(plugin); | |
157 op_data.output_list = g_list_append(op_data.output_list, p); | |
158 } | |
159 | |
160 static void | |
161 effect_plugin_init(Plugin * plugin) | |
162 { | |
163 EffectPlugin *p = EFFECT_PLUGIN(plugin); | |
164 ep_data.effect_list = g_list_append(ep_data.effect_list, p); | |
165 } | |
166 | |
167 static void | |
168 general_plugin_init(Plugin * plugin) | |
169 { | |
170 GeneralPlugin *p = GENERAL_PLUGIN(plugin); | |
171 p->xmms_session = ctrlsocket_get_session_id(); | |
172 gp_data.general_list = g_list_append(gp_data.general_list, p); | |
173 } | |
174 | |
175 static void | |
176 vis_plugin_init(Plugin * plugin) | |
177 { | |
178 VisPlugin *p = VIS_PLUGIN(plugin); | |
179 p->xmms_session = ctrlsocket_get_session_id(); | |
180 p->disable_plugin = vis_disable_plugin; | |
181 vp_data.vis_list = g_list_append(vp_data.vis_list, p); | |
182 } | |
183 | |
1563 | 184 static void |
185 lowlevel_plugin_init(Plugin * plugin) | |
186 { | |
187 LowlevelPlugin *p = LOWLEVEL_PLUGIN(plugin); | |
188 lowlevel_list = g_list_append(lowlevel_list, p); | |
189 } | |
0 | 190 |
191 /* FIXME: Placed here (hopefully) temporarily - descender */ | |
192 | |
193 typedef struct { | |
194 const gchar *name; | |
195 const gchar *id; | |
196 void (*init)(Plugin *); | |
197 } PluginType; | |
198 | |
199 static PluginType plugin_types[] = { | |
200 { "input" , "get_iplugin_info", input_plugin_init }, | |
201 { "output" , "get_oplugin_info", output_plugin_init }, | |
202 { "effect" , "get_eplugin_info", effect_plugin_init }, | |
203 { "general" , "get_gplugin_info", general_plugin_init }, | |
204 { "visualization", "get_vplugin_info", vis_plugin_init }, | |
1563 | 205 { "lowlevel" , "get_lplugin_info", lowlevel_plugin_init }, |
0 | 206 { NULL, NULL, NULL } |
207 }; | |
208 | |
209 static void | |
210 add_plugin(const gchar * filename) | |
211 { | |
212 PluginType *type; | |
213 GModule *module; | |
214 gpointer func; | |
215 | |
216 if (plugin_is_duplicate(filename)) | |
217 return; | |
218 | |
834 | 219 if (!(module = g_module_open(filename, 0))) { |
12 | 220 printf("Failed to load plugin (%s): %s\n", |
0 | 221 filename, g_module_error()); |
222 return; | |
223 } | |
224 | |
225 for (type = plugin_types; type->name; type++) | |
226 { | |
227 if (g_module_symbol(module, type->id, &func)) { | |
228 Plugin *plugin = PLUGIN_GET_INFO(func); | |
229 | |
230 plugin->handle = module; | |
231 plugin->filename = g_strdup(filename); | |
232 type->init(PLUGIN_GET_INFO(func)); | |
233 | |
234 return; | |
235 } | |
236 } | |
237 | |
12 | 238 printf("Invalid plugin (%s)\n", filename); |
0 | 239 g_module_close(module); |
240 } | |
241 | |
242 static gboolean | |
243 scan_plugin_func(const gchar * path, const gchar * basename, gpointer data) | |
244 { | |
1631 | 245 if (!str_has_suffix_nocase(basename, SHARED_SUFFIX)) |
0 | 246 return FALSE; |
247 | |
248 if (!g_file_test(path, G_FILE_TEST_IS_REGULAR)) | |
249 return FALSE; | |
250 | |
251 add_plugin(path); | |
252 | |
253 return FALSE; | |
254 } | |
255 | |
256 static void | |
257 scan_plugins(const gchar * path) | |
258 { | |
259 dir_foreach(path, scan_plugin_func, NULL, NULL); | |
260 } | |
261 | |
262 void | |
263 plugin_system_init(void) | |
264 { | |
265 gchar *dir, **disabled; | |
266 GList *node; | |
267 OutputPlugin *op; | |
268 InputPlugin *ip; | |
1566 | 269 LowlevelPlugin *lp; |
0 | 270 gint dirsel = 0, i = 0; |
271 | |
272 if (!g_module_supported()) { | |
781
12c47704b4b5
[svn] Add error reporting for many places, patch by external contributor Derek
nenolod
parents:
687
diff
changeset
|
273 report_error("Module loading not supported! Plugins will not be loaded.\n"); |
0 | 274 return; |
275 } | |
276 | |
277 plugin_matrix = g_hash_table_new_full(g_str_hash, g_int_equal, g_free, | |
278 NULL); | |
279 | |
280 #ifndef DISABLE_USER_PLUGIN_DIR | |
281 scan_plugins(bmp_paths[BMP_PATH_USER_PLUGIN_DIR]); | |
282 /* | |
283 * This is in a separate loop so if the user puts them in the | |
284 * wrong dir we'll still get them in the right order (home dir | |
285 * first) - Zinx | |
286 */ | |
287 while (plugin_dir_list[dirsel]) { | |
288 dir = g_build_filename(bmp_paths[BMP_PATH_USER_PLUGIN_DIR], | |
289 plugin_dir_list[dirsel++], NULL); | |
290 scan_plugins(dir); | |
291 g_free(dir); | |
292 } | |
293 dirsel = 0; | |
294 #endif | |
295 | |
296 while (plugin_dir_list[dirsel]) { | |
297 dir = g_build_filename(PLUGIN_DIR, plugin_dir_list[dirsel++], NULL); | |
298 scan_plugins(dir); | |
299 g_free(dir); | |
300 } | |
301 | |
302 op_data.output_list = g_list_sort(op_data.output_list, outputlist_compare_func); | |
303 if (!op_data.current_output_plugin | |
304 && g_list_length(op_data.output_list)) { | |
305 op_data.current_output_plugin = op_data.output_list->data; | |
306 } | |
307 | |
308 ip_data.input_list = g_list_sort(ip_data.input_list, inputlist_compare_func); | |
309 | |
310 ep_data.effect_list = g_list_sort(ep_data.effect_list, effectlist_compare_func); | |
311 ep_data.enabled_list = NULL; | |
312 | |
313 gp_data.general_list = g_list_sort(gp_data.general_list, generallist_compare_func); | |
314 gp_data.enabled_list = NULL; | |
315 | |
316 vp_data.vis_list = g_list_sort(vp_data.vis_list, vislist_compare_func); | |
317 vp_data.enabled_list = NULL; | |
318 | |
319 general_enable_from_stringified_list(cfg.enabled_gplugins); | |
320 vis_enable_from_stringified_list(cfg.enabled_vplugins); | |
321 effect_enable_from_stringified_list(cfg.enabled_eplugins); | |
322 | |
323 g_free(cfg.enabled_gplugins); | |
324 cfg.enabled_gplugins = NULL; | |
325 | |
326 g_free(cfg.enabled_vplugins); | |
327 cfg.enabled_vplugins = NULL; | |
328 | |
329 g_free(cfg.enabled_eplugins); | |
330 cfg.enabled_eplugins = NULL; | |
331 | |
332 for (node = op_data.output_list; node; node = g_list_next(node)) { | |
333 op = OUTPUT_PLUGIN(node->data); | |
334 /* | |
335 * Only test basename to avoid problems when changing | |
336 * prefix. We will only see one plugin with the same | |
337 * basename, so this is usually what the user want. | |
338 */ | |
339 if (!strcmp(g_basename(cfg.outputplugin), g_basename(op->filename))) | |
340 op_data.current_output_plugin = op; | |
341 if (op->init) | |
342 op->init(); | |
343 } | |
344 | |
345 for (node = ip_data.input_list; node; node = g_list_next(node)) { | |
346 ip = INPUT_PLUGIN(node->data); | |
347 if (ip->init) | |
348 ip->init(); | |
349 } | |
350 | |
1566 | 351 for (node = lowlevel_list; node; node = g_list_next(node)) { |
352 lp = LOWLEVEL_PLUGIN(node->data); | |
353 if (lp->init) | |
354 lp->init(); | |
355 } | |
356 | |
0 | 357 if (cfg.disabled_iplugins) { |
358 disabled = g_strsplit(cfg.disabled_iplugins, ":", 0); | |
359 while (disabled[i]) { | |
360 g_hash_table_replace(plugin_matrix, disabled[i], | |
361 GINT_TO_POINTER(FALSE)); | |
362 i++; | |
363 } | |
364 | |
365 g_free(disabled); | |
366 | |
367 g_free(cfg.disabled_iplugins); | |
368 cfg.disabled_iplugins = NULL; | |
369 } | |
370 } | |
371 | |
372 void | |
373 plugin_system_cleanup(void) | |
374 { | |
375 InputPlugin *ip; | |
376 OutputPlugin *op; | |
377 EffectPlugin *ep; | |
378 GeneralPlugin *gp; | |
379 VisPlugin *vp; | |
1563 | 380 LowlevelPlugin *lp; |
0 | 381 GList *node; |
382 | |
383 g_message("Shutting down plugin system"); | |
384 | |
906 | 385 if (bmp_playback_get_playing()) { |
386 ip_data.stop = TRUE; | |
0 | 387 bmp_playback_stop(); |
906 | 388 ip_data.stop = FALSE; |
389 } | |
0 | 390 |
391 for (node = get_input_list(); node; node = g_list_next(node)) { | |
392 ip = INPUT_PLUGIN(node->data); | |
393 if (ip && ip->cleanup) { | |
394 ip->cleanup(); | |
395 GDK_THREADS_LEAVE(); | |
396 while (g_main_iteration(FALSE)); | |
397 GDK_THREADS_ENTER(); | |
398 } | |
399 g_module_close(ip->handle); | |
400 } | |
401 | |
402 if (ip_data.input_list) | |
403 g_list_free(ip_data.input_list); | |
404 | |
405 for (node = get_output_list(); node; node = g_list_next(node)) { | |
406 op = OUTPUT_PLUGIN(node->data); | |
309 | 407 if (op && op->cleanup) { |
408 op->cleanup(); | |
409 GDK_THREADS_LEAVE(); | |
410 while (g_main_iteration(FALSE)); | |
411 GDK_THREADS_ENTER(); | |
412 } | |
0 | 413 g_module_close(op->handle); |
414 } | |
415 | |
416 if (op_data.output_list) | |
417 g_list_free(op_data.output_list); | |
418 | |
419 for (node = get_effect_list(); node; node = g_list_next(node)) { | |
420 ep = EFFECT_PLUGIN(node->data); | |
421 if (ep && ep->cleanup) { | |
422 ep->cleanup(); | |
423 GDK_THREADS_LEAVE(); | |
424 while (g_main_iteration(FALSE)); | |
425 GDK_THREADS_ENTER(); | |
426 } | |
427 g_module_close(ep->handle); | |
428 } | |
429 | |
430 if (ep_data.effect_list) | |
431 g_list_free(ep_data.effect_list); | |
432 | |
433 for (node = get_general_enabled_list(); node; node = g_list_next(node)) { | |
434 gp = GENERAL_PLUGIN(node->data); | |
435 enable_general_plugin(g_list_index(gp_data.general_list, gp), FALSE); | |
436 } | |
437 | |
438 if (gp_data.enabled_list) | |
439 g_list_free(gp_data.enabled_list); | |
440 | |
441 GDK_THREADS_LEAVE(); | |
442 while (g_main_iteration(FALSE)); | |
443 GDK_THREADS_ENTER(); | |
444 | |
445 for (node = get_general_list(); node; node = g_list_next(node)) { | |
446 gp = GENERAL_PLUGIN(node->data); | |
650
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
447 if (gp && gp->cleanup) { |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
448 gp->cleanup(); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
449 GDK_THREADS_LEAVE(); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
450 while (g_main_iteration(FALSE)); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
451 GDK_THREADS_ENTER(); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
452 } |
0 | 453 g_module_close(gp->handle); |
454 } | |
455 | |
456 if (gp_data.general_list) | |
457 g_list_free(gp_data.general_list); | |
458 | |
459 for (node = get_vis_enabled_list(); node; node = g_list_next(node)) { | |
460 vp = VIS_PLUGIN(node->data); | |
461 enable_vis_plugin(g_list_index(vp_data.vis_list, vp), FALSE); | |
462 } | |
463 | |
464 if (vp_data.enabled_list) | |
465 g_list_free(vp_data.enabled_list); | |
466 | |
467 GDK_THREADS_LEAVE(); | |
468 while (g_main_iteration(FALSE)); | |
469 GDK_THREADS_ENTER(); | |
470 | |
471 for (node = get_vis_list(); node; node = g_list_next(node)) { | |
472 vp = VIS_PLUGIN(node->data); | |
650
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
473 if (vp && vp->cleanup) { |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
474 vp->cleanup(); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
475 GDK_THREADS_LEAVE(); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
476 while (g_main_iteration(FALSE)); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
477 GDK_THREADS_ENTER(); |
980d651da2fc
[svn] Actually use the cleanup hooks on general & visualization plugins.
chainsaw
parents:
538
diff
changeset
|
478 } |
0 | 479 g_module_close(vp->handle); |
480 } | |
481 | |
482 if (vp_data.vis_list) | |
483 g_list_free(vp_data.vis_list); | |
1563 | 484 |
485 for (node = lowlevel_list; node; node = g_list_next(node)) { | |
486 lp = LOWLEVEL_PLUGIN(node->data); | |
487 if (lp && lp->cleanup) { | |
488 lp->cleanup(); | |
489 GDK_THREADS_LEAVE(); | |
490 while (g_main_iteration(FALSE)); | |
491 GDK_THREADS_ENTER(); | |
492 } | |
493 g_module_close(lp->handle); | |
494 } | |
495 | |
496 if (lowlevel_list) | |
497 g_list_free(lowlevel_list); | |
0 | 498 } |