9 extern struct Preferences
*PREFS
;
12 const int _hook_recursion_soft_limit
= 50;
13 const int _hook_recursion_hard_limit
= 99;
19 PluginEngineInitializer init
;
20 PluginEngineTerminator term
;
21 PluginEngineFileChecker check_file
;
22 PluginMetadataReader read_metadata
;
23 PluginLoader load_plugin
;
24 PluginUnloader unload_plugin
;
25 PluginExecutor execute
;
26 PluginHookCaller call_hook
;
30 static GList
* _engine_list
= NULL
;
31 static GHashTable
* _loaded_plugins
= NULL
;
34 void ext_init(int* argc
, char** argv
[], char** env
[])
36 GList
*list
= g_list_first(_engine_list
);
39 struct PluginEngine
* engine
= list
->data
;
40 engine
->init(argc
, argv
, env
);
41 list
= g_list_next(list
);
43 if (!_loaded_plugins
) {
44 _loaded_plugins
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
50 GList
*list
= g_list_first(_engine_list
);
53 struct PluginEngine
* engine
= list
->data
;
55 list
= g_list_next(list
);
57 g_list_free(_engine_list
);
60 if (_loaded_plugins
) {
61 g_hash_table_unref(_loaded_plugins
);
62 _loaded_plugins
= NULL
;
66 void ext_register(const gchar
* type
,
67 PluginEngineInitializer init
,
68 PluginEngineTerminator term
,
69 PluginEngineFileChecker check_file
,
70 PluginMetadataReader read_metadata
,
71 PluginLoader load_plugin
,
72 PluginUnloader unload_plugin
,
73 PluginExecutor execute
,
74 PluginHookCaller call_hook
)
76 struct PluginEngine
* engine
= g_malloc0(sizeof(struct PluginEngine
));
80 engine
->check_file
= check_file
;
81 engine
->read_metadata
= read_metadata
;
82 engine
->load_plugin
= load_plugin
;
83 engine
->unload_plugin
= unload_plugin
;
84 engine
->execute
= execute
;
85 engine
->call_hook
= call_hook
;
86 _engine_list
= g_list_append(_engine_list
, engine
);
90 static struct PluginEngine
* _get_engine_for_plugin(const gchar
* plugin_filename
)
92 if (!plugin_filename
) {
96 GList
*list
= g_list_first(_engine_list
);
98 struct PluginEngine
* engine
= list
->data
;
99 if (engine
->check_file(plugin_filename
)) {
102 list
= g_list_next(list
);
107 static void _read_directory(const gchar
* directory
, GHashTable
* hash
)
109 GDir
* dir
= g_dir_open(directory
, 0, NULL
);
112 const gchar
* filename
;
113 while ((filename
= g_dir_read_name(dir
))) {
114 gchar
* full
= g_build_filename(directory
, filename
, NULL
);
115 if (g_file_test(full
, G_FILE_TEST_IS_REGULAR
) && _get_engine_for_plugin(filename
)) {
116 g_hash_table_insert(hash
, g_strdup(filename
), NULL
);
123 gchar
** ext_list_plugins()
125 GHashTable
* hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
128 for (it
= PREFS
->ext_path
; it
&& *it
; ++it
) {
129 _read_directory(*it
, hash
);
132 GList
* list
= g_list_sort(g_hash_table_get_keys(hash
), (GCompareFunc
)g_utf8_collate
);
133 g_hash_table_unref(hash
);
135 guint len
= g_list_length(list
);
136 gchar
** strv
= g_new0(gchar
**, len
+ 1);
138 for (i
= 0; i
< len
; ++i
) {
139 strv
[i
] = g_list_nth_data(list
, i
);
146 gchar
* ext_find_plugin(const gchar
* plugin_filename
)
148 if (!plugin_filename
) return NULL
;
151 for (it
= PREFS
->ext_path
; *it
; ++it
) {
152 if (!g_path_is_absolute(*it
)) continue;
154 gchar
* full
= g_build_filename(*it
, plugin_filename
, NULL
);
155 if (g_file_test(full
, G_FILE_TEST_IS_REGULAR
)) {
164 GHashTable
* ext_read_plugin_metadata(const gchar
* plugin_filename
)
166 gchar
* full
= ext_find_plugin(plugin_filename
);
167 if (!full
) return NULL
;
169 GHashTable
* ret
= NULL
;
171 struct PluginEngine
* engine
= _get_engine_for_plugin(plugin_filename
);
172 if (engine
&& engine
->read_metadata
) {
173 ret
= engine
->read_metadata(full
);
180 gint
ext_load_plugin(const gchar
* plugin_filename
)
182 gchar
* full
= ext_find_plugin(plugin_filename
);
183 if (!full
) return -1;
187 struct PluginEngine
* engine
= _get_engine_for_plugin(plugin_filename
);
188 if (engine
&& engine
->load_plugin
&& engine
->load_plugin(full
) == 0) {
189 g_hash_table_insert(_loaded_plugins
, g_strdup(plugin_filename
), NULL
);
197 void ext_unload_plugin(const gchar
* plugin_filename
)
199 gchar
* full
= ext_find_plugin(plugin_filename
);
202 struct PluginEngine
* engine
= _get_engine_for_plugin(plugin_filename
);
203 if (engine
&& engine
->unload_plugin
) {
204 engine
->unload_plugin(full
);
208 g_hash_table_remove(_loaded_plugins
, plugin_filename
);
211 gboolean
ext_is_plugin_loaded(const gchar
* plugin_filename
)
213 return g_hash_table_contains(_loaded_plugins
, plugin_filename
);
216 void ext_execute_action(const gchar
* plugin_filename
)
218 gchar
* full
= ext_find_plugin(plugin_filename
);
221 struct PluginEngine
* engine
= _get_engine_for_plugin(plugin_filename
);
222 if (engine
&& engine
->execute
) {
223 engine
->execute(full
);
229 void ext_hook(const gchar
* hook_id
, ...)
234 va_start(ap
, hook_id
);
236 GValue
* val
= (GValue
*)va_arg(ap
, GValue
*);
238 list
= g_list_append(list
, val
);
242 ext_vhook(hook_id
, list
);
246 void ext_vhook(const gchar
* hook_id
, GList
* args
)
248 static int recursion_level
= 0;
250 if (_hook_recursion_hard_limit
<= recursion_level
) {
252 } else if (_hook_recursion_soft_limit
<= recursion_level
) {
253 int level
= recursion_level
;
254 recursion_level
= -1;
255 GValue val_level
= G_VALUE_INIT
;
256 ext_hook("deep_hook_recursion", EXT_INT(&val_level
, level
), NULL
);
257 recursion_level
= level
;
262 g_print("ext_hook: %s (level %d)\n", hook_id
, recursion_level
);
263 GList
*list
= g_list_first(_engine_list
);
266 struct PluginEngine
* engine
= list
->data
;
267 engine
->call_hook(hook_id
, args
);
268 list
= g_list_next(list
);
274 gboolean
ext_has(const gchar
* feature
)
277 if (0 == g_utf8_collate(feature
, "libofx")) {
282 if (0 == g_utf8_collate(feature
, "perl")) {
290 void* ext_symbol_lookup(const gchar
* symbol
)
292 static GModule
* module = NULL
;
293 if (!module) module = g_module_open(NULL
, 0);
296 if (module && g_module_symbol(module, symbol
, &ptr
)) {
304 void ext_run_modal(const gchar
* title
, const gchar
* text
, const gchar
* type
)
306 GtkMessageType t
= GTK_MESSAGE_INFO
;
307 if (0 == g_utf8_collate(type
, "error")) {
308 t
= GTK_MESSAGE_ERROR
;
310 if (0 == g_utf8_collate(type
, "warn")) {
311 t
= GTK_MESSAGE_WARNING
;
313 if (0 == g_utf8_collate(type
, "question")) {
314 t
= GTK_MESSAGE_QUESTION
;
317 GtkWidget
* dialog
= gtk_message_dialog_new(NULL
,
318 GTK_DIALOG_DESTROY_WITH_PARENT
, t
,
319 GTK_BUTTONS_CLOSE
, "%s", text
);
321 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
324 gtk_dialog_run(GTK_DIALOG(dialog
));
325 gtk_widget_destroy(dialog
);