2 * go-plugin-service.c: Plugin services - reading XML info, activating, etc.
3 * (everything independent of plugin loading method)
5 * Author: Zbigniew Chyla (cyba@gnome.pl)
8 #include <gnumeric-config.h>
10 #include <tools/gnm-solver.h>
12 #include <gnm-plugin.h>
13 #include <gnumeric-conf.h>
14 #include <application.h>
16 #include <goffice/goffice.h>
17 #include <gsf/gsf-impl-utils.h>
18 #include <gsf/gsf-input-stdio.h>
19 #include <gsf/gsf-input-memory.h>
20 #include <glib/gi18n-lib.h>
23 #define CXML2C(s) ((char const *)(s))
24 #define CC2XML(s) ((xmlChar const *)(s))
29 char *dst
= g_strdup (CXML2C (src
));
34 typedef GOPluginServiceSimpleClass GnmPluginServiceFunctionGroupClass
;
35 struct GnmPluginServiceFunctionGroup_
{
36 GOPluginServiceSimple base
;
38 gchar
*category_name
, *translated_category_name
;
39 GSList
*function_name_list
;
41 GnmFuncGroup
*func_group
;
42 GnmPluginServiceFunctionGroupCallbacks cbs
;
47 plugin_service_function_group_finalize (GObject
*obj
)
49 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (obj
);
50 GObjectClass
*parent_class
;
52 g_free (sfg
->category_name
);
53 sfg
->category_name
= NULL
;
55 g_free (sfg
->translated_category_name
);
56 sfg
->translated_category_name
= NULL
;
58 g_slist_free_full (sfg
->function_name_list
, g_free
);
59 sfg
->function_name_list
= NULL
;
61 g_free (sfg
->tdomain
);
64 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
65 parent_class
->finalize (obj
);
69 plugin_service_function_group_read_xml (GOPluginService
*service
, xmlNode
*tree
, GOErrorInfo
**ret_error
)
71 xmlNode
*category_node
, *translated_category_node
, *functions_node
;
72 gchar
*category_name
, *translated_category_name
;
73 GSList
*function_name_list
= NULL
;
74 gchar
*tdomain
= NULL
;
76 GO_INIT_RET_ERROR_INFO (ret_error
);
77 category_node
= go_xml_get_child_by_name_no_lang (tree
, "category");
78 category_name
= category_node
79 ? xml2c (xmlNodeGetContent (category_node
))
82 translated_category_node
= go_xml_get_child_by_name_by_lang (tree
, "category");
83 if (translated_category_node
!= NULL
) {
86 lang
= go_xml_node_get_cstr (translated_category_node
, "lang");
88 translated_category_name
=
89 xml2c (xmlNodeGetContent (translated_category_node
));
92 translated_category_name
= NULL
;
95 translated_category_name
= NULL
;
97 functions_node
= go_xml_get_child_by_name (tree
, CC2XML ("functions"));
98 if (functions_node
!= NULL
) {
101 tdomain
= xml2c (go_xml_node_get_cstr (functions_node
, "textdomain"));
103 for (node
= functions_node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
106 if (strcmp (CXML2C (node
->name
), "function") != 0)
109 func_name
= xml2c (go_xml_node_get_cstr (node
, "name"));
113 GO_SLIST_PREPEND (function_name_list
, func_name
);
115 GO_SLIST_REVERSE (function_name_list
);
117 if (category_name
!= NULL
&& function_name_list
!= NULL
) {
118 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
120 sfg
->category_name
= category_name
;
121 sfg
->translated_category_name
= translated_category_name
;
122 sfg
->function_name_list
= function_name_list
;
123 sfg
->tdomain
= tdomain
;
125 GSList
*error_list
= NULL
;
127 if (category_name
== NULL
) {
128 GO_SLIST_PREPEND (error_list
, go_error_info_new_str (
129 _("Missing function category name.")));
131 if (function_name_list
== NULL
) {
132 GO_SLIST_PREPEND (error_list
, go_error_info_new_str (
133 _("Function group is empty.")));
135 GO_SLIST_REVERSE (error_list
);
136 *ret_error
= go_error_info_new_from_error_list (error_list
);
138 g_free (category_name
);
139 g_free (translated_category_name
);
140 g_slist_free_full (function_name_list
, g_free
);
147 plugin_service_function_group_func_ref_notify (GnmFunc
*fn_def
,
148 G_GNUC_UNUSED GParamSpec
*pspec
,
151 if (gnm_func_get_in_use (fn_def
))
152 go_plugin_use_ref (plugin
);
154 go_plugin_use_unref (plugin
);
158 plugin_service_function_group_func_load_stub (GnmFunc
*fn_def
,
159 GOPluginService
*service
)
161 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
162 GOErrorInfo
*error
= NULL
;
164 g_return_if_fail (fn_def
!= NULL
);
166 go_plugin_service_load (service
, &error
);
168 go_error_info_print (error
);
169 go_error_info_free (error
);
173 if (!sfg
->cbs
.load_stub
) {
174 error
= go_error_info_new_printf (_("No load_stub method.\n"));
175 go_error_info_print (error
);
176 go_error_info_free (error
);
180 sfg
->cbs
.load_stub (service
, fn_def
);
184 delayed_ref_notify (GOPlugin
*plugin
, GnmFunc
*fd
)
186 g_signal_handlers_disconnect_by_func (plugin
,
187 G_CALLBACK (delayed_ref_notify
),
190 /* We cannot do this until after the plugin has been activated. */
191 plugin_service_function_group_func_ref_notify (fd
, NULL
, plugin
);
195 plugin_service_function_group_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
197 GnmPluginServiceFunctionGroup
*sfg
=
198 GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
199 GOPlugin
*plugin
= go_plugin_service_get_plugin (service
);
202 GO_INIT_RET_ERROR_INFO (ret_error
);
203 sfg
->func_group
= gnm_func_group_fetch (sfg
->category_name
,
204 sfg
->translated_category_name
);
205 if (gnm_debug_flag ("plugin-func"))
206 g_printerr ("Activating group %s\n", sfg
->category_name
);
208 for (l
= sfg
->function_name_list
; l
; l
= l
->next
) {
209 const char *fname
= l
->data
;
210 GnmFunc
*fd
= gnm_func_lookup_or_add_placeholder (fname
);
212 gnm_func_set_function_type (fd
, GNM_FUNC_TYPE_STUB
);
213 gnm_func_set_translation_domain (fd
, sfg
->tdomain
);
214 gnm_func_set_function_group (fd
, sfg
->func_group
);
215 // Clear localized_name so we can deduce the proper name.
216 //gnm_func_set_localized_name (fd, NULL);
219 (G_OBJECT (fd
), "notify::in-use",
220 G_CALLBACK (plugin_service_function_group_func_ref_notify
),
224 (G_OBJECT (fd
), "load-stub",
225 G_CALLBACK (plugin_service_function_group_func_load_stub
),
228 if (fd
->usage_count
> 0)
229 g_signal_connect (plugin
,
231 G_CALLBACK (delayed_ref_notify
),
234 service
->is_active
= TRUE
;
238 plugin_service_function_group_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
240 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
243 if (gnm_debug_flag ("plugin-func"))
244 g_printerr ("Deactivating group %s\n", sfg
->category_name
);
246 GO_INIT_RET_ERROR_INFO (ret_error
);
248 for (l
= sfg
->function_name_list
; l
; l
= l
->next
) {
249 const char *fname
= l
->data
;
250 GnmFunc
*func
= gnm_func_lookup (fname
, NULL
);
251 g_object_unref (func
);
253 service
->is_active
= FALSE
;
257 plugin_service_function_group_get_description (GOPluginService
*service
)
259 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
261 char const *category_name
;
263 n_functions
= g_slist_length (sfg
->function_name_list
);
264 category_name
= sfg
->translated_category_name
!= NULL
265 ? sfg
->translated_category_name
266 : sfg
->category_name
;
268 return g_strdup_printf (ngettext (
269 "%d function in category \"%s\"",
270 "Group of %d functions in category \"%s\"",
272 n_functions
, category_name
);
276 plugin_service_function_group_init (GnmPluginServiceFunctionGroup
*s
)
278 GO_PLUGIN_SERVICE (s
)->cbs_ptr
= &s
->cbs
;
279 s
->category_name
= NULL
;
280 s
->translated_category_name
= NULL
;
281 s
->function_name_list
= NULL
;
282 s
->func_group
= NULL
;
287 plugin_service_function_group_class_init (GObjectClass
*gobject_class
)
289 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
291 gobject_class
->finalize
= plugin_service_function_group_finalize
;
292 plugin_service_class
->read_xml
= plugin_service_function_group_read_xml
;
293 plugin_service_class
->activate
= plugin_service_function_group_activate
;
294 plugin_service_class
->deactivate
= plugin_service_function_group_deactivate
;
295 plugin_service_class
->get_description
= plugin_service_function_group_get_description
;
298 GSF_CLASS (GnmPluginServiceFunctionGroup
, gnm_plugin_service_function_group
,
299 plugin_service_function_group_class_init
, plugin_service_function_group_init
,
300 GO_TYPE_PLUGIN_SERVICE_SIMPLE
)
302 /****************************************************************************/
307 typedef GOPluginServiceSimpleClass PluginServiceUIClass
;
308 struct GnmPluginServiceUI_
{
309 GOPluginServiceSimple base
;
315 GnmPluginServiceUICallbacks cbs
;
319 plugin_service_ui_init (PluginServiceUI
*s
)
321 GO_PLUGIN_SERVICE (s
)->cbs_ptr
= &s
->cbs
;
325 s
->cbs
.plugin_func_exec_action
= NULL
;
329 plugin_service_ui_finalize (GObject
*obj
)
331 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (obj
);
332 GObjectClass
*parent_class
;
334 g_free (service_ui
->file_name
);
335 service_ui
->file_name
= NULL
;
336 g_slist_free_full (service_ui
->actions
, (GDestroyNotify
)gnm_action_unref
);
337 service_ui
->actions
= NULL
;
339 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
340 parent_class
->finalize (obj
);
344 cb_ui_service_activate (GnmAction
const *action
, WorkbookControl
*wbc
, GOPluginService
*service
)
346 GOErrorInfo
*load_error
= NULL
;
348 go_plugin_service_load (service
, &load_error
);
349 if (load_error
== NULL
) {
350 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
351 GOErrorInfo
*ignored_error
= NULL
;
353 g_return_if_fail (service_ui
->cbs
.plugin_func_exec_action
!= NULL
);
354 service_ui
->cbs
.plugin_func_exec_action (
355 service
, action
, wbc
, &ignored_error
);
356 if (ignored_error
!= NULL
) {
357 go_error_info_print (ignored_error
);
358 go_error_info_free (ignored_error
);
361 go_error_info_print (load_error
);
362 go_error_info_free (load_error
);
367 plugin_service_ui_read_xml (GOPluginService
*service
, xmlNode
*tree
, GOErrorInfo
**ret_error
)
369 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
372 GSList
*actions
= NULL
;
374 GO_INIT_RET_ERROR_INFO (ret_error
);
375 file_name
= xml2c (go_xml_node_get_cstr (tree
, "file"));
376 if (file_name
== NULL
) {
377 *ret_error
= go_error_info_new_str (
378 _("Missing file name."));
381 verbs_node
= go_xml_get_child_by_name (tree
, "actions");
382 if (verbs_node
!= NULL
) {
383 xmlNode
*ptr
, *label_node
;
384 xmlChar
*name
, *icon
;
386 gboolean always_available
;
389 for (ptr
= verbs_node
->xmlChildrenNode
; ptr
!= NULL
; ptr
= ptr
->next
) {
390 if (xmlIsBlankNode (ptr
) || ptr
->name
== NULL
||
391 strcmp (CXML2C (ptr
->name
), "action"))
393 name
= go_xml_node_get_cstr (ptr
, "name");
394 /* label = go_xml_node_get_cstr (ptr, "label");*/
395 /*****************************************************************************************/
396 label_node
= go_xml_get_child_by_name_no_lang (ptr
, "label");
398 ? xml2c (xmlNodeGetContent (label_node
))
401 label_node
= go_xml_get_child_by_name_by_lang (ptr
, "label");
402 if (label_node
!= NULL
) {
405 lang
= go_xml_node_get_cstr (label_node
, "lang");
407 label
= xml2c (xmlNodeGetContent (label_node
));
411 /*****************************************************************************************/
412 icon
= go_xml_node_get_cstr (ptr
, "icon");
413 if (!go_xml_node_get_bool (ptr
, "always_available", &always_available
))
414 always_available
= FALSE
;
415 action
= gnm_action_new (name
, label
, icon
, always_available
,
416 (GnmActionHandler
) cb_ui_service_activate
,
418 if (NULL
!= name
) xmlFree (name
);
420 if (NULL
!= icon
) xmlFree (icon
);
422 GO_SLIST_PREPEND (actions
, action
);
425 GO_SLIST_REVERSE (actions
);
427 service_ui
->file_name
= file_name
;
428 service_ui
->actions
= actions
;
432 plugin_service_ui_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
434 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
435 const char *uifile
= service_ui
->file_name
;
436 char *xml_ui
, *group_name
;
438 GError
*error
= NULL
;
442 GO_INIT_RET_ERROR_INFO (ret_error
);
444 if (strncmp (uifile
, "res:", 4) == 0) {
446 gconstpointer data
= go_rsm_lookup (uifile
+ 4, &len
);
448 ? gsf_input_memory_new (data
, len
, FALSE
)
450 } else if (strncmp (uifile
, "data:", 5) == 0) {
451 const char *data
= uifile
+ 5;
452 src
= gsf_input_memory_new (data
, strlen (data
), FALSE
);
454 char *full_file_name
= g_path_is_absolute (uifile
)
457 (go_plugin_get_dir_name (service
->plugin
),
460 src
= gsf_input_stdio_new (full_file_name
, &error
);
461 g_free (full_file_name
);
466 src
= gsf_input_uncompress (src
);
467 len
= gsf_input_size (src
);
468 xml_ui
= g_strndup (gsf_input_read (src
, len
, NULL
), len
);
472 tdomain
= go_plugin_get_textdomain (service
->plugin
);
473 group_name
= g_strconcat (go_plugin_get_id (service
->plugin
), service
->id
, NULL
);
474 service_ui
->layout_id
= gnm_app_add_extra_ui (group_name
,
479 g_object_unref (src
);
480 service
->is_active
= TRUE
;
484 *ret_error
= go_error_info_new_printf
485 (_("Cannot read UI description from %s: %s"),
487 error
? error
->message
: "?");
488 g_clear_error (&error
);
490 g_object_unref (src
);
494 plugin_service_ui_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
496 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
498 GO_INIT_RET_ERROR_INFO (ret_error
);
499 gnm_app_remove_extra_ui (service_ui
->layout_id
);
500 service_ui
->layout_id
= NULL
;
501 service
->is_active
= FALSE
;
505 plugin_service_ui_get_description (GOPluginService
*service
)
507 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
510 n_actions
= g_slist_length (service_ui
->actions
);
511 return g_strdup_printf (
513 /* xgettext : %d gives the number of actions. This is input to ngettext. */
514 "User interface with %d action",
515 "User interface with %d actions",
521 plugin_service_ui_class_init (GObjectClass
*gobject_class
)
523 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
525 gobject_class
->finalize
= plugin_service_ui_finalize
;
526 plugin_service_class
->read_xml
= plugin_service_ui_read_xml
;
527 plugin_service_class
->activate
= plugin_service_ui_activate
;
528 plugin_service_class
->deactivate
= plugin_service_ui_deactivate
;
529 plugin_service_class
->get_description
= plugin_service_ui_get_description
;
532 GSF_CLASS (PluginServiceUI
, gnm_plugin_service_ui
,
533 plugin_service_ui_class_init
, plugin_service_ui_init
,
534 GO_TYPE_PLUGIN_SERVICE_SIMPLE
)
536 /****************************************************************************/
539 * PluginServiceSolver
541 typedef GOPluginServiceClass PluginServiceSolverClass
;
542 struct GnmPluginServiceSolver_
{
543 GOPluginService base
;
545 GnmSolverFactory
*factory
;
547 GnmPluginServiceSolverCallbacks cbs
;
551 cb_load_and_create (GnmSolverFactory
*factory
, GnmSolverParameters
*param
,
554 PluginServiceSolver
*ssol
=
555 g_object_get_data (G_OBJECT (factory
), "ssol");
556 GOPluginService
*service
= GO_PLUGIN_SERVICE (ssol
);
557 GOErrorInfo
*ignored_error
= NULL
;
560 go_plugin_service_load (service
, &ignored_error
);
561 if (ignored_error
!= NULL
) {
562 go_error_info_print (ignored_error
);
563 go_error_info_free (ignored_error
);
567 res
= ssol
->cbs
.creator (factory
, param
, data
);
569 go_plugin_use_ref (service
->plugin
);
570 g_object_set_data_full (G_OBJECT (res
),
571 "plugin-use", service
->plugin
,
572 (GDestroyNotify
)go_plugin_use_unref
);
579 cb_load_and_functional (GnmSolverFactory
*factory
,
583 PluginServiceSolver
*ssol
=
584 g_object_get_data (G_OBJECT (factory
), "ssol");
585 GOPluginService
*service
= GO_PLUGIN_SERVICE (ssol
);
586 GOErrorInfo
*ignored_error
= NULL
;
587 GnmSolverFactoryFunctional functional
;
589 go_plugin_service_load (service
, &ignored_error
);
590 if (ignored_error
!= NULL
) {
591 go_error_info_print (ignored_error
);
592 go_error_info_free (ignored_error
);
596 functional
= ssol
->cbs
.functional
;
597 return (functional
== NULL
|| functional (factory
, wbcg
, data
));
601 plugin_service_solver_init (PluginServiceSolver
*ssol
)
603 GO_PLUGIN_SERVICE (ssol
)->cbs_ptr
= &ssol
->cbs
;
604 ssol
->factory
= NULL
;
605 ssol
->cbs
.creator
= NULL
;
609 plugin_service_solver_finalize (GObject
*obj
)
611 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (obj
);
612 GObjectClass
*parent_class
;
615 g_object_unref (ssol
->factory
);
617 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
618 parent_class
->finalize (obj
);
622 plugin_service_solver_read_xml (GOPluginService
*service
, xmlNode
*tree
,
623 GOErrorInfo
**ret_error
)
625 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
626 xmlChar
*s_id
, *s_name
, *s_type
;
627 GnmSolverModelType type
= GNM_SOLVER_LP
;
628 xmlNode
*information_node
;
630 GO_INIT_RET_ERROR_INFO (ret_error
);
632 s_type
= go_xml_node_get_cstr (tree
, "model_type");
633 if (s_type
&& strcmp (CXML2C (s_type
), "mip") == 0)
634 type
= GNM_SOLVER_LP
;
635 else if (s_type
&& strcmp (CXML2C (s_type
), "qp") == 0)
636 type
= GNM_SOLVER_QP
;
637 else if (s_type
&& strcmp (CXML2C (s_type
), "nlp") == 0)
638 type
= GNM_SOLVER_NLP
;
640 *ret_error
= go_error_info_new_str (_("Invalid solver model type."));
645 s_id
= go_xml_node_get_cstr (tree
, "id");
648 information_node
= go_xml_get_child_by_name (tree
, "information");
649 if (information_node
!= NULL
) {
651 go_xml_get_child_by_name_by_lang (information_node
,
654 s_name
= xmlNodeGetContent (node
);
658 if (!s_id
|| !s_name
) {
659 *ret_error
= go_error_info_new_str (_("Missing fields in plugin file"));
661 ssol
->factory
= gnm_solver_factory_new (CXML2C (s_id
),
665 cb_load_and_functional
,
668 g_object_set_data (G_OBJECT (ssol
->factory
), "ssol", ssol
);
679 plugin_service_solver_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
681 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
683 GO_INIT_RET_ERROR_INFO (ret_error
);
684 gnm_solver_db_register (ssol
->factory
);
685 service
->is_active
= TRUE
;
689 plugin_service_solver_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
691 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
693 GO_INIT_RET_ERROR_INFO (ret_error
);
694 gnm_solver_db_unregister (ssol
->factory
);
695 service
->is_active
= FALSE
;
699 plugin_service_solver_get_description (GOPluginService
*service
)
701 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
702 return g_strdup_printf (_("Solver Algorithm %s"),
703 ssol
->factory
->name
);
707 plugin_service_solver_class_init (GObjectClass
*gobject_class
)
709 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
711 gobject_class
->finalize
= plugin_service_solver_finalize
;
712 plugin_service_class
->read_xml
= plugin_service_solver_read_xml
;
713 plugin_service_class
->activate
= plugin_service_solver_activate
;
714 plugin_service_class
->deactivate
= plugin_service_solver_deactivate
;
715 plugin_service_class
->get_description
= plugin_service_solver_get_description
;
718 GSF_CLASS (PluginServiceSolver
, gnm_plugin_service_solver
,
719 plugin_service_solver_class_init
, plugin_service_solver_init
,
720 GO_TYPE_PLUGIN_SERVICE
)
722 /****************************************************************************/
725 typedef GOPluginLoaderModule GnmPluginLoaderModule
;
726 typedef GOPluginLoaderModuleClass GnmPluginLoaderModuleClass
;
729 * Service - function_group
732 GnmFuncDescriptor
*module_fn_info_array
;
733 GHashTable
*function_indices
;
734 } ServiceLoaderDataFunctionGroup
;
737 function_group_loader_data_free (gpointer data
)
739 ServiceLoaderDataFunctionGroup
*ld
= data
;
741 g_hash_table_destroy (ld
->function_indices
);
746 gnm_plugin_loader_module_func_load_stub (GOPluginService
*service
,
749 ServiceLoaderDataFunctionGroup
*loader_data
;
751 GnmFuncDescriptor
*desc
;
754 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
));
755 g_return_if_fail (GNM_IS_FUNC (func
));
757 name
= gnm_func_get_name (func
, FALSE
);
758 loader_data
= g_object_get_data (G_OBJECT (service
), "loader_data");
759 if (!g_hash_table_lookup_extended (loader_data
->function_indices
,
764 desc
= loader_data
->module_fn_info_array
+ GPOINTER_TO_INT (index_ptr
);
766 func
->help
= desc
->help
? desc
->help
: NULL
;
767 func
->impl_status
= desc
->impl_status
;
768 func
->test_status
= desc
->test_status
;
769 func
->flags
= desc
->flags
;
770 if (desc
->fn_args
!= NULL
) {
771 func
->fn
.args
.func
= desc
->fn_args
;
772 func
->fn
.args
.arg_spec
= desc
->arg_spec
;
773 gnm_func_set_function_type (func
, GNM_FUNC_TYPE_ARGS
);
774 } else if (desc
->fn_nodes
!= NULL
) {
775 func
->fn
.nodes
= desc
->fn_nodes
;
776 gnm_func_set_function_type (func
, GNM_FUNC_TYPE_NODES
);
778 g_warning ("Invalid function descriptor with no function");
783 gnm_plugin_loader_module_load_service_function_group (GOPluginLoader
*loader
,
784 GOPluginService
*service
,
785 GOErrorInfo
**ret_error
)
787 GnmPluginLoaderModule
*loader_module
= GNM_PLUGIN_LOADER_MODULE (loader
);
788 gchar
*fn_info_array_name
;
789 GnmFuncDescriptor
*module_fn_info_array
= NULL
;
791 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
));
793 GO_INIT_RET_ERROR_INFO (ret_error
);
794 fn_info_array_name
= g_strconcat (
795 go_plugin_service_get_id (service
), "_functions", NULL
);
796 g_module_symbol (loader_module
->handle
, fn_info_array_name
, (gpointer
) &module_fn_info_array
);
797 if (module_fn_info_array
!= NULL
) {
798 GnmPluginServiceFunctionGroupCallbacks
*cbs
;
799 ServiceLoaderDataFunctionGroup
*loader_data
;
802 cbs
= go_plugin_service_get_cbs (service
);
803 cbs
->load_stub
= &gnm_plugin_loader_module_func_load_stub
;
805 loader_data
= g_new (ServiceLoaderDataFunctionGroup
, 1);
806 loader_data
->module_fn_info_array
= module_fn_info_array
;
807 loader_data
->function_indices
= g_hash_table_new (&g_str_hash
, &g_str_equal
);
808 for (i
= 0; module_fn_info_array
[i
].name
!= NULL
; i
++) {
809 g_hash_table_insert (loader_data
->function_indices
,
810 (gpointer
) module_fn_info_array
[i
].name
,
811 GINT_TO_POINTER (i
));
813 g_object_set_data_full (
814 G_OBJECT (service
), "loader_data", loader_data
, function_group_loader_data_free
);
816 *ret_error
= go_error_info_new_printf (
817 _("Module file \"%s\" has invalid format."),
818 loader_module
->module_file_name
);
819 go_error_info_add_details (*ret_error
,
820 go_error_info_new_printf (
821 _("File doesn't contain \"%s\" array."),
822 fn_info_array_name
));
824 g_free (fn_info_array_name
);
832 GnmModulePluginUIActions
*module_ui_actions_array
;
833 GHashTable
*ui_actions_hash
;
834 } ServiceLoaderDataUI
;
837 ui_loader_data_free (gpointer data
)
839 ServiceLoaderDataUI
*ld
= data
;
841 g_hash_table_destroy (ld
->ui_actions_hash
);
846 gnm_plugin_loader_module_func_exec_action (GOPluginService
*service
,
847 GnmAction
const *action
,
848 WorkbookControl
*wbc
,
849 GOErrorInfo
**ret_error
)
851 ServiceLoaderDataUI
*loader_data
;
852 gpointer action_index_ptr
;
855 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_UI (service
));
857 GO_INIT_RET_ERROR_INFO (ret_error
);
858 loader_data
= g_object_get_data (G_OBJECT (service
), "loader_data");
859 if (!g_hash_table_lookup_extended (loader_data
->ui_actions_hash
, action
->id
,
860 NULL
, &action_index_ptr
)) {
861 *ret_error
= go_error_info_new_printf (_("Unknown action: %s"), action
->id
);
864 action_index
= GPOINTER_TO_INT (action_index_ptr
);
865 if (NULL
!= loader_data
->module_ui_actions_array
[action_index
].handler
)
866 (*loader_data
->module_ui_actions_array
[action_index
].handler
) (action
, wbc
);
870 gnm_plugin_loader_module_load_service_ui (GOPluginLoader
*loader
,
871 GOPluginService
*service
,
872 GOErrorInfo
**ret_error
)
874 GnmPluginLoaderModule
*loader_module
= GNM_PLUGIN_LOADER_MODULE (loader
);
875 char *ui_actions_array_name
;
876 GnmModulePluginUIActions
*module_ui_actions_array
= NULL
;
877 GnmPluginServiceUICallbacks
*cbs
;
878 ServiceLoaderDataUI
*loader_data
;
881 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_UI (service
));
883 GO_INIT_RET_ERROR_INFO (ret_error
);
884 ui_actions_array_name
= g_strconcat (
885 go_plugin_service_get_id (service
), "_ui_actions", NULL
);
886 g_module_symbol (loader_module
->handle
, ui_actions_array_name
, (gpointer
) &module_ui_actions_array
);
887 if (module_ui_actions_array
== NULL
) {
888 *ret_error
= go_error_info_new_printf (
889 _("Module file \"%s\" has invalid format."),
890 loader_module
->module_file_name
);
891 go_error_info_add_details (*ret_error
, go_error_info_new_printf (
892 _("File doesn't contain \"%s\" array."), ui_actions_array_name
));
893 g_free (ui_actions_array_name
);
896 g_free (ui_actions_array_name
);
898 cbs
= go_plugin_service_get_cbs (service
);
899 cbs
->plugin_func_exec_action
= gnm_plugin_loader_module_func_exec_action
;
901 loader_data
= g_new (ServiceLoaderDataUI
, 1);
902 loader_data
->module_ui_actions_array
= module_ui_actions_array
;
903 loader_data
->ui_actions_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
904 for (i
= 0; module_ui_actions_array
[i
].name
!= NULL
; i
++)
905 g_hash_table_insert (loader_data
->ui_actions_hash
,
906 (gpointer
) module_ui_actions_array
[i
].name
,
907 GINT_TO_POINTER (i
));
908 g_object_set_data_full (G_OBJECT (service
),
909 "loader_data", loader_data
, ui_loader_data_free
);
913 gnm_plugin_loader_module_load_service_solver (GOPluginLoader
*loader
,
914 GOPluginService
*service
,
915 GOErrorInfo
**ret_error
)
917 GnmPluginLoaderModule
*loader_module
=
918 GNM_PLUGIN_LOADER_MODULE (loader
);
919 GnmPluginServiceSolverCallbacks
*cbs
;
921 GnmSolverCreator creator
;
922 GnmSolverFactoryFunctional functional
;
924 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_SOLVER (service
));
926 GO_INIT_RET_ERROR_INFO (ret_error
);
928 symname
= g_strconcat (go_plugin_service_get_id (service
),
931 g_module_symbol (loader_module
->handle
, symname
, (gpointer
)&creator
);
934 *ret_error
= go_error_info_new_printf (
935 _("Module file \"%s\" has invalid format."),
936 loader_module
->module_file_name
);
940 symname
= g_strconcat (go_plugin_service_get_id (service
),
941 "_solver_factory_functional",
943 g_module_symbol (loader_module
->handle
, symname
, (gpointer
)&functional
);
946 cbs
= go_plugin_service_get_cbs (service
);
947 cbs
->creator
= creator
;
948 cbs
->functional
= functional
;
952 gplm_service_load (GOPluginLoader
*l
, GOPluginService
*s
, GOErrorInfo
**err
)
954 if (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (s
))
955 gnm_plugin_loader_module_load_service_function_group (l
, s
, err
);
956 else if (GNM_IS_PLUGIN_SERVICE_UI (s
))
957 gnm_plugin_loader_module_load_service_ui (l
, s
, err
);
958 else if (GNM_IS_PLUGIN_SERVICE_SOLVER (s
))
959 gnm_plugin_loader_module_load_service_solver (l
, s
, err
);
966 gplm_service_unload (GOPluginLoader
*l
, GOPluginService
*s
, GOErrorInfo
**err
)
968 if (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (s
)) {
969 GnmPluginServiceFunctionGroupCallbacks
*cbs
= go_plugin_service_get_cbs (s
);
970 cbs
->load_stub
= NULL
;
971 } else if (GNM_IS_PLUGIN_SERVICE_UI (s
)) {
972 GnmPluginServiceUICallbacks
*cbs
= go_plugin_service_get_cbs (s
);
973 cbs
->plugin_func_exec_action
= NULL
;
974 } else if (GNM_IS_PLUGIN_SERVICE_SOLVER (s
)) {
975 GnmPluginServiceSolverCallbacks
*cbs
=
976 go_plugin_service_get_cbs (s
);
978 cbs
->functional
= NULL
;
985 go_plugin_loader_module_iface_init (GOPluginLoaderClass
*iface
)
987 iface
->service_load
= gplm_service_load
;
988 iface
->service_unload
= gplm_service_unload
;
991 GSF_CLASS_FULL (GnmPluginLoaderModule
, gnm_plugin_loader_module
,
992 NULL
, NULL
, NULL
, NULL
,
993 NULL
, GO_TYPE_PLUGIN_LOADER_MODULE
, 0,
994 GSF_INTERFACE (go_plugin_loader_module_iface_init
, GO_TYPE_PLUGIN_LOADER
))
996 /****************************************************************************/
999 * gnm_plugins_service_init: (skip)
1002 gnm_plugins_service_init (void)
1004 go_plugin_service_define ("function_group",
1005 &gnm_plugin_service_function_group_get_type
);
1006 go_plugin_service_define ("ui",
1007 &gnm_plugin_service_ui_get_type
);
1008 go_plugin_service_define ("solver",
1009 &gnm_plugin_service_solver_get_type
);
1010 go_plugin_loader_module_register_version ("gnumeric", GNM_VERSION_FULL
);
1015 gnm_plugins_init (GOCmdContext
*context
)
1017 char const *env_var
;
1018 GSList
*dir_list
= go_slist_create (
1019 g_build_filename (gnm_sys_lib_dir (), PLUGIN_SUBDIR
, NULL
),
1020 g_strdup (gnm_sys_extern_plugin_dir ()),
1021 (gnm_usr_dir (TRUE
) == NULL
? NULL
:
1022 g_build_filename (gnm_usr_dir (TRUE
), PLUGIN_SUBDIR
, NULL
)),
1024 dir_list
= g_slist_concat (dir_list
,
1025 go_string_slist_copy (gnm_conf_get_plugins_extra_dirs ()));
1027 env_var
= g_getenv ("GNUMERIC_PLUGIN_PATH");
1028 if (env_var
!= NULL
)
1029 GO_SLIST_CONCAT (dir_list
, go_strsplit_to_slist (env_var
, G_SEARCHPATH_SEPARATOR
));
1031 go_plugins_init (GO_CMD_CONTEXT (context
),
1032 gnm_conf_get_plugins_file_states (),
1033 gnm_conf_get_plugins_active (),
1035 gnm_conf_get_plugins_activate_newplugins (),
1036 gnm_plugin_loader_module_get_type ());