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
*func
= gnm_func_lookup_or_add_placeholder (fname
);
212 gnm_func_set_stub (func
);
213 gnm_func_set_translation_domain (func
, sfg
->tdomain
);
214 gnm_func_set_function_group (func
, sfg
->func_group
);
215 // Clear localized_name so we can deduce the proper name.
216 //gnm_func_set_localized_name (func, NULL);
219 (func
, "notify::in-use",
220 G_CALLBACK (plugin_service_function_group_func_ref_notify
),
225 G_CALLBACK (plugin_service_function_group_func_load_stub
),
228 if (gnm_func_get_in_use (func
))
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
);
241 GOPlugin
*plugin
= go_plugin_service_get_plugin (service
);
244 if (gnm_debug_flag ("plugin-func"))
245 g_printerr ("Deactivating group %s\n", sfg
->category_name
);
247 GO_INIT_RET_ERROR_INFO (ret_error
);
249 for (l
= sfg
->function_name_list
; l
; l
= l
->next
) {
250 const char *fname
= l
->data
;
251 GnmFunc
*func
= gnm_func_lookup (fname
, NULL
);
253 // This should not happen, but if it were to, having a handler
254 // of some other object is not going to be good.
255 if (gnm_func_get_in_use (func
))
256 g_signal_handlers_disconnect_by_func
257 (plugin
, G_CALLBACK (delayed_ref_notify
), func
);
259 // Someone else might hold a ref so make sure the object
260 // becomes inaccessible via gnm_func_lookup
261 gnm_func_dispose (func
);
263 g_object_unref (func
);
265 service
->is_active
= FALSE
;
269 plugin_service_function_group_get_description (GOPluginService
*service
)
271 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
273 char const *category_name
;
275 n_functions
= g_slist_length (sfg
->function_name_list
);
276 category_name
= sfg
->translated_category_name
!= NULL
277 ? sfg
->translated_category_name
278 : sfg
->category_name
;
280 return g_strdup_printf (ngettext (
281 "%d function in category \"%s\"",
282 "Group of %d functions in category \"%s\"",
284 n_functions
, category_name
);
288 plugin_service_function_group_init (GnmPluginServiceFunctionGroup
*s
)
290 GO_PLUGIN_SERVICE (s
)->cbs_ptr
= &s
->cbs
;
291 s
->category_name
= NULL
;
292 s
->translated_category_name
= NULL
;
293 s
->function_name_list
= NULL
;
294 s
->func_group
= NULL
;
299 plugin_service_function_group_class_init (GObjectClass
*gobject_class
)
301 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
303 gobject_class
->finalize
= plugin_service_function_group_finalize
;
304 plugin_service_class
->read_xml
= plugin_service_function_group_read_xml
;
305 plugin_service_class
->activate
= plugin_service_function_group_activate
;
306 plugin_service_class
->deactivate
= plugin_service_function_group_deactivate
;
307 plugin_service_class
->get_description
= plugin_service_function_group_get_description
;
310 GSF_CLASS (GnmPluginServiceFunctionGroup
, gnm_plugin_service_function_group
,
311 plugin_service_function_group_class_init
, plugin_service_function_group_init
,
312 GO_TYPE_PLUGIN_SERVICE_SIMPLE
)
314 /****************************************************************************/
319 typedef GOPluginServiceSimpleClass PluginServiceUIClass
;
320 struct GnmPluginServiceUI_
{
321 GOPluginServiceSimple base
;
327 GnmPluginServiceUICallbacks cbs
;
331 plugin_service_ui_init (PluginServiceUI
*s
)
333 GO_PLUGIN_SERVICE (s
)->cbs_ptr
= &s
->cbs
;
337 s
->cbs
.plugin_func_exec_action
= NULL
;
341 plugin_service_ui_finalize (GObject
*obj
)
343 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (obj
);
344 GObjectClass
*parent_class
;
346 g_free (service_ui
->file_name
);
347 service_ui
->file_name
= NULL
;
348 g_slist_free_full (service_ui
->actions
, (GDestroyNotify
)gnm_action_unref
);
349 service_ui
->actions
= NULL
;
351 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
352 parent_class
->finalize (obj
);
356 cb_ui_service_activate (GnmAction
const *action
, WorkbookControl
*wbc
, GOPluginService
*service
)
358 GOErrorInfo
*load_error
= NULL
;
360 go_plugin_service_load (service
, &load_error
);
361 if (load_error
== NULL
) {
362 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
363 GOErrorInfo
*ignored_error
= NULL
;
365 g_return_if_fail (service_ui
->cbs
.plugin_func_exec_action
!= NULL
);
366 service_ui
->cbs
.plugin_func_exec_action (
367 service
, action
, wbc
, &ignored_error
);
368 if (ignored_error
!= NULL
) {
369 go_error_info_print (ignored_error
);
370 go_error_info_free (ignored_error
);
373 go_error_info_print (load_error
);
374 go_error_info_free (load_error
);
379 plugin_service_ui_read_xml (GOPluginService
*service
, xmlNode
*tree
, GOErrorInfo
**ret_error
)
381 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
384 GSList
*actions
= NULL
;
386 GO_INIT_RET_ERROR_INFO (ret_error
);
387 file_name
= xml2c (go_xml_node_get_cstr (tree
, "file"));
388 if (file_name
== NULL
) {
389 *ret_error
= go_error_info_new_str (
390 _("Missing file name."));
393 verbs_node
= go_xml_get_child_by_name (tree
, "actions");
394 if (verbs_node
!= NULL
) {
395 xmlNode
*ptr
, *label_node
;
396 xmlChar
*name
, *icon
;
398 gboolean always_available
;
401 for (ptr
= verbs_node
->xmlChildrenNode
; ptr
!= NULL
; ptr
= ptr
->next
) {
402 if (xmlIsBlankNode (ptr
) || ptr
->name
== NULL
||
403 strcmp (CXML2C (ptr
->name
), "action"))
405 name
= go_xml_node_get_cstr (ptr
, "name");
406 /* label = go_xml_node_get_cstr (ptr, "label");*/
407 /*****************************************************************************************/
408 label_node
= go_xml_get_child_by_name_no_lang (ptr
, "label");
410 ? xml2c (xmlNodeGetContent (label_node
))
413 label_node
= go_xml_get_child_by_name_by_lang (ptr
, "label");
414 if (label_node
!= NULL
) {
417 lang
= go_xml_node_get_cstr (label_node
, "lang");
419 label
= xml2c (xmlNodeGetContent (label_node
));
423 /*****************************************************************************************/
424 icon
= go_xml_node_get_cstr (ptr
, "icon");
425 if (!go_xml_node_get_bool (ptr
, "always_available", &always_available
))
426 always_available
= FALSE
;
427 action
= gnm_action_new (name
, label
, icon
, always_available
,
428 (GnmActionHandler
) cb_ui_service_activate
,
430 if (NULL
!= name
) xmlFree (name
);
432 if (NULL
!= icon
) xmlFree (icon
);
434 GO_SLIST_PREPEND (actions
, action
);
437 GO_SLIST_REVERSE (actions
);
439 service_ui
->file_name
= file_name
;
440 service_ui
->actions
= actions
;
444 plugin_service_ui_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
446 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
447 const char *uifile
= service_ui
->file_name
;
448 char *xml_ui
, *group_name
;
450 GError
*error
= NULL
;
454 GO_INIT_RET_ERROR_INFO (ret_error
);
456 if (strncmp (uifile
, "res:", 4) == 0) {
458 gconstpointer data
= go_rsm_lookup (uifile
+ 4, &len
);
460 ? gsf_input_memory_new (data
, len
, FALSE
)
462 } else if (strncmp (uifile
, "data:", 5) == 0) {
463 const char *data
= uifile
+ 5;
464 src
= gsf_input_memory_new (data
, strlen (data
), FALSE
);
466 char *full_file_name
= g_path_is_absolute (uifile
)
469 (go_plugin_get_dir_name (service
->plugin
),
472 src
= gsf_input_stdio_new (full_file_name
, &error
);
473 g_free (full_file_name
);
478 src
= gsf_input_uncompress (src
);
479 len
= gsf_input_size (src
);
480 xml_ui
= g_strndup (gsf_input_read (src
, len
, NULL
), len
);
484 tdomain
= go_plugin_get_textdomain (service
->plugin
);
485 group_name
= g_strconcat (go_plugin_get_id (service
->plugin
), service
->id
, NULL
);
486 service_ui
->layout_id
= gnm_app_add_extra_ui (group_name
,
491 g_object_unref (src
);
492 service
->is_active
= TRUE
;
496 *ret_error
= go_error_info_new_printf
497 (_("Cannot read UI description from %s: %s"),
499 error
? error
->message
: "?");
500 g_clear_error (&error
);
502 g_object_unref (src
);
506 plugin_service_ui_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
508 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
510 GO_INIT_RET_ERROR_INFO (ret_error
);
511 gnm_app_remove_extra_ui (service_ui
->layout_id
);
512 service_ui
->layout_id
= NULL
;
513 service
->is_active
= FALSE
;
517 plugin_service_ui_get_description (GOPluginService
*service
)
519 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
522 n_actions
= g_slist_length (service_ui
->actions
);
523 return g_strdup_printf (
525 /* xgettext : %d gives the number of actions. This is input to ngettext. */
526 "User interface with %d action",
527 "User interface with %d actions",
533 plugin_service_ui_class_init (GObjectClass
*gobject_class
)
535 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
537 gobject_class
->finalize
= plugin_service_ui_finalize
;
538 plugin_service_class
->read_xml
= plugin_service_ui_read_xml
;
539 plugin_service_class
->activate
= plugin_service_ui_activate
;
540 plugin_service_class
->deactivate
= plugin_service_ui_deactivate
;
541 plugin_service_class
->get_description
= plugin_service_ui_get_description
;
544 GSF_CLASS (PluginServiceUI
, gnm_plugin_service_ui
,
545 plugin_service_ui_class_init
, plugin_service_ui_init
,
546 GO_TYPE_PLUGIN_SERVICE_SIMPLE
)
548 /****************************************************************************/
551 * PluginServiceSolver
553 typedef GOPluginServiceClass PluginServiceSolverClass
;
554 struct GnmPluginServiceSolver_
{
555 GOPluginService base
;
557 GnmSolverFactory
*factory
;
559 GnmPluginServiceSolverCallbacks cbs
;
563 cb_load_and_create (GnmSolverFactory
*factory
, GnmSolverParameters
*param
,
566 PluginServiceSolver
*ssol
=
567 g_object_get_data (G_OBJECT (factory
), "ssol");
568 GOPluginService
*service
= GO_PLUGIN_SERVICE (ssol
);
569 GOErrorInfo
*ignored_error
= NULL
;
572 go_plugin_service_load (service
, &ignored_error
);
573 if (ignored_error
!= NULL
) {
574 go_error_info_print (ignored_error
);
575 go_error_info_free (ignored_error
);
579 res
= ssol
->cbs
.creator (factory
, param
, data
);
581 go_plugin_use_ref (service
->plugin
);
582 g_object_set_data_full (G_OBJECT (res
),
583 "plugin-use", service
->plugin
,
584 (GDestroyNotify
)go_plugin_use_unref
);
591 cb_load_and_functional (GnmSolverFactory
*factory
,
595 PluginServiceSolver
*ssol
=
596 g_object_get_data (G_OBJECT (factory
), "ssol");
597 GOPluginService
*service
= GO_PLUGIN_SERVICE (ssol
);
598 GOErrorInfo
*ignored_error
= NULL
;
599 GnmSolverFactoryFunctional functional
;
601 go_plugin_service_load (service
, &ignored_error
);
602 if (ignored_error
!= NULL
) {
603 go_error_info_print (ignored_error
);
604 go_error_info_free (ignored_error
);
608 functional
= ssol
->cbs
.functional
;
609 return (functional
== NULL
|| functional (factory
, wbcg
, data
));
613 plugin_service_solver_init (PluginServiceSolver
*ssol
)
615 GO_PLUGIN_SERVICE (ssol
)->cbs_ptr
= &ssol
->cbs
;
616 ssol
->factory
= NULL
;
617 ssol
->cbs
.creator
= NULL
;
621 plugin_service_solver_finalize (GObject
*obj
)
623 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (obj
);
624 GObjectClass
*parent_class
;
627 g_object_unref (ssol
->factory
);
629 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
630 parent_class
->finalize (obj
);
634 plugin_service_solver_read_xml (GOPluginService
*service
, xmlNode
*tree
,
635 GOErrorInfo
**ret_error
)
637 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
638 xmlChar
*s_id
, *s_name
, *s_type
;
639 GnmSolverModelType type
= GNM_SOLVER_LP
;
640 xmlNode
*information_node
;
642 GO_INIT_RET_ERROR_INFO (ret_error
);
644 s_type
= go_xml_node_get_cstr (tree
, "model_type");
645 if (s_type
&& strcmp (CXML2C (s_type
), "mip") == 0)
646 type
= GNM_SOLVER_LP
;
647 else if (s_type
&& strcmp (CXML2C (s_type
), "qp") == 0)
648 type
= GNM_SOLVER_QP
;
649 else if (s_type
&& strcmp (CXML2C (s_type
), "nlp") == 0)
650 type
= GNM_SOLVER_NLP
;
652 *ret_error
= go_error_info_new_str (_("Invalid solver model type."));
657 s_id
= go_xml_node_get_cstr (tree
, "id");
660 information_node
= go_xml_get_child_by_name (tree
, "information");
661 if (information_node
!= NULL
) {
663 go_xml_get_child_by_name_by_lang (information_node
,
666 s_name
= xmlNodeGetContent (node
);
670 if (!s_id
|| !s_name
) {
671 *ret_error
= go_error_info_new_str (_("Missing fields in plugin file"));
673 ssol
->factory
= gnm_solver_factory_new (CXML2C (s_id
),
677 cb_load_and_functional
,
680 g_object_set_data (G_OBJECT (ssol
->factory
), "ssol", ssol
);
691 plugin_service_solver_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
693 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
695 GO_INIT_RET_ERROR_INFO (ret_error
);
696 gnm_solver_db_register (ssol
->factory
);
697 service
->is_active
= TRUE
;
701 plugin_service_solver_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
703 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
705 GO_INIT_RET_ERROR_INFO (ret_error
);
706 gnm_solver_db_unregister (ssol
->factory
);
707 service
->is_active
= FALSE
;
711 plugin_service_solver_get_description (GOPluginService
*service
)
713 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
714 return g_strdup_printf (_("Solver Algorithm %s"),
715 ssol
->factory
->name
);
719 plugin_service_solver_class_init (GObjectClass
*gobject_class
)
721 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
723 gobject_class
->finalize
= plugin_service_solver_finalize
;
724 plugin_service_class
->read_xml
= plugin_service_solver_read_xml
;
725 plugin_service_class
->activate
= plugin_service_solver_activate
;
726 plugin_service_class
->deactivate
= plugin_service_solver_deactivate
;
727 plugin_service_class
->get_description
= plugin_service_solver_get_description
;
730 GSF_CLASS (PluginServiceSolver
, gnm_plugin_service_solver
,
731 plugin_service_solver_class_init
, plugin_service_solver_init
,
732 GO_TYPE_PLUGIN_SERVICE
)
734 /****************************************************************************/
737 typedef GOPluginLoaderModule GnmPluginLoaderModule
;
738 typedef GOPluginLoaderModuleClass GnmPluginLoaderModuleClass
;
741 * Service - function_group
744 GnmFuncDescriptor
*module_fn_info_array
;
745 GHashTable
*function_indices
;
746 } ServiceLoaderDataFunctionGroup
;
749 function_group_loader_data_free (gpointer data
)
751 ServiceLoaderDataFunctionGroup
*ld
= data
;
753 g_hash_table_destroy (ld
->function_indices
);
758 gnm_plugin_loader_module_func_load_stub (GOPluginService
*service
,
761 ServiceLoaderDataFunctionGroup
*loader_data
;
763 GnmFuncDescriptor
*desc
;
766 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
));
767 g_return_if_fail (GNM_IS_FUNC (func
));
769 name
= gnm_func_get_name (func
, FALSE
);
770 loader_data
= g_object_get_data (G_OBJECT (service
), "loader_data");
771 if (!g_hash_table_lookup_extended (loader_data
->function_indices
,
776 desc
= loader_data
->module_fn_info_array
+ GPOINTER_TO_INT (index_ptr
);
777 gnm_func_set_from_desc (func
, desc
);
781 gnm_plugin_loader_module_load_service_function_group (GOPluginLoader
*loader
,
782 GOPluginService
*service
,
783 GOErrorInfo
**ret_error
)
785 GnmPluginLoaderModule
*loader_module
= GNM_PLUGIN_LOADER_MODULE (loader
);
786 gchar
*fn_info_array_name
;
787 GnmFuncDescriptor
*module_fn_info_array
= NULL
;
789 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
));
791 GO_INIT_RET_ERROR_INFO (ret_error
);
792 fn_info_array_name
= g_strconcat (
793 go_plugin_service_get_id (service
), "_functions", NULL
);
794 g_module_symbol (loader_module
->handle
, fn_info_array_name
, (gpointer
) &module_fn_info_array
);
795 if (module_fn_info_array
!= NULL
) {
796 GnmPluginServiceFunctionGroupCallbacks
*cbs
;
797 ServiceLoaderDataFunctionGroup
*loader_data
;
800 cbs
= go_plugin_service_get_cbs (service
);
801 cbs
->load_stub
= &gnm_plugin_loader_module_func_load_stub
;
803 loader_data
= g_new (ServiceLoaderDataFunctionGroup
, 1);
804 loader_data
->module_fn_info_array
= module_fn_info_array
;
805 loader_data
->function_indices
= g_hash_table_new (&g_str_hash
, &g_str_equal
);
806 for (i
= 0; module_fn_info_array
[i
].name
!= NULL
; i
++) {
807 g_hash_table_insert (loader_data
->function_indices
,
808 (gpointer
) module_fn_info_array
[i
].name
,
809 GINT_TO_POINTER (i
));
811 g_object_set_data_full (
812 G_OBJECT (service
), "loader_data", loader_data
, function_group_loader_data_free
);
814 *ret_error
= go_error_info_new_printf (
815 _("Module file \"%s\" has invalid format."),
816 loader_module
->module_file_name
);
817 go_error_info_add_details (*ret_error
,
818 go_error_info_new_printf (
819 _("File doesn't contain \"%s\" array."),
820 fn_info_array_name
));
822 g_free (fn_info_array_name
);
830 GnmModulePluginUIActions
*module_ui_actions_array
;
831 GHashTable
*ui_actions_hash
;
832 } ServiceLoaderDataUI
;
835 ui_loader_data_free (gpointer data
)
837 ServiceLoaderDataUI
*ld
= data
;
839 g_hash_table_destroy (ld
->ui_actions_hash
);
844 gnm_plugin_loader_module_func_exec_action (GOPluginService
*service
,
845 GnmAction
const *action
,
846 WorkbookControl
*wbc
,
847 GOErrorInfo
**ret_error
)
849 ServiceLoaderDataUI
*loader_data
;
850 gpointer action_index_ptr
;
853 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_UI (service
));
855 GO_INIT_RET_ERROR_INFO (ret_error
);
856 loader_data
= g_object_get_data (G_OBJECT (service
), "loader_data");
857 if (!g_hash_table_lookup_extended (loader_data
->ui_actions_hash
, action
->id
,
858 NULL
, &action_index_ptr
)) {
859 *ret_error
= go_error_info_new_printf (_("Unknown action: %s"), action
->id
);
862 action_index
= GPOINTER_TO_INT (action_index_ptr
);
863 if (NULL
!= loader_data
->module_ui_actions_array
[action_index
].handler
)
864 (*loader_data
->module_ui_actions_array
[action_index
].handler
) (action
, wbc
);
868 gnm_plugin_loader_module_load_service_ui (GOPluginLoader
*loader
,
869 GOPluginService
*service
,
870 GOErrorInfo
**ret_error
)
872 GnmPluginLoaderModule
*loader_module
= GNM_PLUGIN_LOADER_MODULE (loader
);
873 char *ui_actions_array_name
;
874 GnmModulePluginUIActions
*module_ui_actions_array
= NULL
;
875 GnmPluginServiceUICallbacks
*cbs
;
876 ServiceLoaderDataUI
*loader_data
;
879 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_UI (service
));
881 GO_INIT_RET_ERROR_INFO (ret_error
);
882 ui_actions_array_name
= g_strconcat (
883 go_plugin_service_get_id (service
), "_ui_actions", NULL
);
884 g_module_symbol (loader_module
->handle
, ui_actions_array_name
, (gpointer
) &module_ui_actions_array
);
885 if (module_ui_actions_array
== NULL
) {
886 *ret_error
= go_error_info_new_printf (
887 _("Module file \"%s\" has invalid format."),
888 loader_module
->module_file_name
);
889 go_error_info_add_details (*ret_error
, go_error_info_new_printf (
890 _("File doesn't contain \"%s\" array."), ui_actions_array_name
));
891 g_free (ui_actions_array_name
);
894 g_free (ui_actions_array_name
);
896 cbs
= go_plugin_service_get_cbs (service
);
897 cbs
->plugin_func_exec_action
= gnm_plugin_loader_module_func_exec_action
;
899 loader_data
= g_new (ServiceLoaderDataUI
, 1);
900 loader_data
->module_ui_actions_array
= module_ui_actions_array
;
901 loader_data
->ui_actions_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
902 for (i
= 0; module_ui_actions_array
[i
].name
!= NULL
; i
++)
903 g_hash_table_insert (loader_data
->ui_actions_hash
,
904 (gpointer
) module_ui_actions_array
[i
].name
,
905 GINT_TO_POINTER (i
));
906 g_object_set_data_full (G_OBJECT (service
),
907 "loader_data", loader_data
, ui_loader_data_free
);
911 gnm_plugin_loader_module_load_service_solver (GOPluginLoader
*loader
,
912 GOPluginService
*service
,
913 GOErrorInfo
**ret_error
)
915 GnmPluginLoaderModule
*loader_module
=
916 GNM_PLUGIN_LOADER_MODULE (loader
);
917 GnmPluginServiceSolverCallbacks
*cbs
;
919 GnmSolverCreator creator
;
920 GnmSolverFactoryFunctional functional
;
922 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_SOLVER (service
));
924 GO_INIT_RET_ERROR_INFO (ret_error
);
926 symname
= g_strconcat (go_plugin_service_get_id (service
),
929 g_module_symbol (loader_module
->handle
, symname
, (gpointer
)&creator
);
932 *ret_error
= go_error_info_new_printf (
933 _("Module file \"%s\" has invalid format."),
934 loader_module
->module_file_name
);
938 symname
= g_strconcat (go_plugin_service_get_id (service
),
939 "_solver_factory_functional",
941 g_module_symbol (loader_module
->handle
, symname
, (gpointer
)&functional
);
944 cbs
= go_plugin_service_get_cbs (service
);
945 cbs
->creator
= creator
;
946 cbs
->functional
= functional
;
950 gplm_service_load (GOPluginLoader
*l
, GOPluginService
*s
, GOErrorInfo
**err
)
952 if (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (s
))
953 gnm_plugin_loader_module_load_service_function_group (l
, s
, err
);
954 else if (GNM_IS_PLUGIN_SERVICE_UI (s
))
955 gnm_plugin_loader_module_load_service_ui (l
, s
, err
);
956 else if (GNM_IS_PLUGIN_SERVICE_SOLVER (s
))
957 gnm_plugin_loader_module_load_service_solver (l
, s
, err
);
964 gplm_service_unload (GOPluginLoader
*l
, GOPluginService
*s
, GOErrorInfo
**err
)
966 if (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (s
)) {
967 GnmPluginServiceFunctionGroupCallbacks
*cbs
= go_plugin_service_get_cbs (s
);
968 cbs
->load_stub
= NULL
;
969 } else if (GNM_IS_PLUGIN_SERVICE_UI (s
)) {
970 GnmPluginServiceUICallbacks
*cbs
= go_plugin_service_get_cbs (s
);
971 cbs
->plugin_func_exec_action
= NULL
;
972 } else if (GNM_IS_PLUGIN_SERVICE_SOLVER (s
)) {
973 GnmPluginServiceSolverCallbacks
*cbs
=
974 go_plugin_service_get_cbs (s
);
976 cbs
->functional
= NULL
;
983 go_plugin_loader_module_iface_init (GOPluginLoaderClass
*iface
)
985 iface
->service_load
= gplm_service_load
;
986 iface
->service_unload
= gplm_service_unload
;
989 GSF_CLASS_FULL (GnmPluginLoaderModule
, gnm_plugin_loader_module
,
990 NULL
, NULL
, NULL
, NULL
,
991 NULL
, GO_TYPE_PLUGIN_LOADER_MODULE
, 0,
992 GSF_INTERFACE (go_plugin_loader_module_iface_init
, GO_TYPE_PLUGIN_LOADER
))
994 /****************************************************************************/
997 * gnm_plugins_service_init: (skip)
1000 gnm_plugins_service_init (void)
1002 go_plugin_service_define ("function_group",
1003 &gnm_plugin_service_function_group_get_type
);
1004 go_plugin_service_define ("ui",
1005 &gnm_plugin_service_ui_get_type
);
1006 go_plugin_service_define ("solver",
1007 &gnm_plugin_service_solver_get_type
);
1008 go_plugin_loader_module_register_version ("gnumeric", GNM_VERSION_FULL
);
1013 gnm_plugins_init (GOCmdContext
*context
)
1015 char const *env_var
;
1016 GSList
*dir_list
= go_slist_create (
1017 g_build_filename (gnm_sys_lib_dir (), PLUGIN_SUBDIR
, NULL
),
1018 g_strdup (gnm_sys_extern_plugin_dir ()),
1019 (gnm_usr_dir (TRUE
) == NULL
? NULL
:
1020 g_build_filename (gnm_usr_dir (TRUE
), PLUGIN_SUBDIR
, NULL
)),
1022 dir_list
= g_slist_concat (dir_list
,
1023 go_string_slist_copy (gnm_conf_get_plugins_extra_dirs ()));
1025 env_var
= g_getenv ("GNUMERIC_PLUGIN_PATH");
1026 if (env_var
!= NULL
)
1027 GO_SLIST_CONCAT (dir_list
, go_strsplit_to_slist (env_var
, G_SEARCHPATH_SEPARATOR
));
1029 go_plugins_init (GO_CMD_CONTEXT (context
),
1030 gnm_conf_get_plugins_file_states (),
1031 gnm_conf_get_plugins_active (),
1033 gnm_conf_get_plugins_activate_newplugins (),
1034 gnm_plugin_loader_module_get_type ());