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_desc_load (GnmFunc
const *fn_def
,
148 GnmFuncDescriptor
*res
)
150 GOPluginService
*service
= gnm_func_get_user_data (fn_def
);
151 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
152 GOErrorInfo
*error
= NULL
;
154 g_return_val_if_fail (fn_def
!= NULL
, FALSE
);
156 go_plugin_service_load (service
, &error
);
158 go_error_info_print (error
);
159 go_error_info_free (error
);
162 if (NULL
== sfg
->cbs
.func_desc_load
) {
163 error
= go_error_info_new_printf (_("No func_desc_load method.\n"));
164 go_error_info_print (error
);
165 go_error_info_free (error
);
168 return sfg
->cbs
.func_desc_load (service
,
169 gnm_func_get_name (fn_def
, FALSE
),
174 plugin_service_function_group_func_ref_notify (GnmFunc
*fn_def
, int refcount
)
176 GOPluginService
*service
;
178 service
= gnm_func_get_user_data (fn_def
);
179 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
));
181 go_plugin_use_unref (service
->plugin
);
183 go_plugin_use_ref (service
->plugin
);
188 delayed_ref_notify (GOPlugin
*plugin
, GnmFunc
*fd
)
190 g_signal_handlers_disconnect_by_func (plugin
,
191 G_CALLBACK (delayed_ref_notify
),
194 /* We cannot do this until after the plugin has been activated. */
195 plugin_service_function_group_func_ref_notify (fd
, 1);
199 plugin_service_function_group_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
201 GnmPluginServiceFunctionGroup
*sfg
=
202 GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
204 GO_INIT_RET_ERROR_INFO (ret_error
);
205 sfg
->func_group
= gnm_func_group_fetch (sfg
->category_name
,
206 sfg
->translated_category_name
);
207 if (gnm_debug_flag ("plugin-func"))
208 g_printerr ("Activating group %s\n", sfg
->category_name
);
210 (sfg
->function_name_list
, char, fname
,
213 fd
= gnm_func_lookup (fname
, NULL
);
216 g_printerr ("Reusing placeholder for %s\n", fname
);
219 fd
= gnm_func_add_placeholder (NULL
, fname
, "?");
221 if (fd
->flags
& GNM_FUNC_IS_PLACEHOLDER
) {
222 gnm_func_set_user_data (fd
, service
);
223 gnm_func_upgrade_placeholder
224 (fd
, sfg
->func_group
,
226 plugin_service_function_group_func_desc_load
,
227 plugin_service_function_group_func_ref_notify
);
228 if (fd
->usage_count
> 0)
229 g_signal_connect (go_plugin_service_get_plugin (service
),
231 G_CALLBACK (delayed_ref_notify
),
234 g_warning ("Multiple definitions of function %s -- this cannot be good!", fname
);
237 service
->is_active
= TRUE
;
241 plugin_service_function_group_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
243 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
245 if (gnm_debug_flag ("plugin-func"))
246 g_printerr ("Deactivating group %s\n", sfg
->category_name
);
248 GO_INIT_RET_ERROR_INFO (ret_error
);
249 GO_SLIST_FOREACH (sfg
->function_name_list
, char, fname
,
250 gnm_func_free (gnm_func_lookup (fname
, NULL
));
252 service
->is_active
= FALSE
;
256 plugin_service_function_group_get_description (GOPluginService
*service
)
258 GnmPluginServiceFunctionGroup
*sfg
= GNM_PLUGIN_SERVICE_FUNCTION_GROUP (service
);
260 char const *category_name
;
262 n_functions
= g_slist_length (sfg
->function_name_list
);
263 category_name
= sfg
->translated_category_name
!= NULL
264 ? sfg
->translated_category_name
265 : sfg
->category_name
;
267 return g_strdup_printf (ngettext (
268 "%d function in category \"%s\"",
269 "Group of %d functions in category \"%s\"",
271 n_functions
, category_name
);
275 plugin_service_function_group_init (GnmPluginServiceFunctionGroup
*s
)
277 GO_PLUGIN_SERVICE (s
)->cbs_ptr
= &s
->cbs
;
278 s
->category_name
= NULL
;
279 s
->translated_category_name
= NULL
;
280 s
->function_name_list
= NULL
;
281 s
->func_group
= NULL
;
286 plugin_service_function_group_class_init (GObjectClass
*gobject_class
)
288 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
290 gobject_class
->finalize
= plugin_service_function_group_finalize
;
291 plugin_service_class
->read_xml
= plugin_service_function_group_read_xml
;
292 plugin_service_class
->activate
= plugin_service_function_group_activate
;
293 plugin_service_class
->deactivate
= plugin_service_function_group_deactivate
;
294 plugin_service_class
->get_description
= plugin_service_function_group_get_description
;
297 GSF_CLASS (GnmPluginServiceFunctionGroup
, gnm_plugin_service_function_group
,
298 plugin_service_function_group_class_init
, plugin_service_function_group_init
,
299 GO_TYPE_PLUGIN_SERVICE_SIMPLE
)
301 /****************************************************************************/
306 typedef GOPluginServiceSimpleClass PluginServiceUIClass
;
307 struct GnmPluginServiceUI_
{
308 GOPluginServiceSimple base
;
314 GnmPluginServiceUICallbacks cbs
;
318 plugin_service_ui_init (PluginServiceUI
*s
)
320 GO_PLUGIN_SERVICE (s
)->cbs_ptr
= &s
->cbs
;
324 s
->cbs
.plugin_func_exec_action
= NULL
;
328 plugin_service_ui_finalize (GObject
*obj
)
330 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (obj
);
331 GObjectClass
*parent_class
;
333 g_free (service_ui
->file_name
);
334 service_ui
->file_name
= NULL
;
335 g_slist_free_full (service_ui
->actions
, (GDestroyNotify
)gnm_action_free
);
336 service_ui
->actions
= NULL
;
338 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
339 parent_class
->finalize (obj
);
343 cb_ui_service_activate (GnmAction
const *action
, WorkbookControl
*wbc
, GOPluginService
*service
)
345 GOErrorInfo
*load_error
= NULL
;
347 go_plugin_service_load (service
, &load_error
);
348 if (load_error
== NULL
) {
349 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
350 GOErrorInfo
*ignored_error
= NULL
;
352 g_return_if_fail (service_ui
->cbs
.plugin_func_exec_action
!= NULL
);
353 service_ui
->cbs
.plugin_func_exec_action (
354 service
, action
, wbc
, &ignored_error
);
355 if (ignored_error
!= NULL
) {
356 go_error_info_print (ignored_error
);
357 go_error_info_free (ignored_error
);
360 go_error_info_print (load_error
);
361 go_error_info_free (load_error
);
366 plugin_service_ui_read_xml (GOPluginService
*service
, xmlNode
*tree
, GOErrorInfo
**ret_error
)
368 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
371 GSList
*actions
= NULL
;
373 GO_INIT_RET_ERROR_INFO (ret_error
);
374 file_name
= xml2c (go_xml_node_get_cstr (tree
, "file"));
375 if (file_name
== NULL
) {
376 *ret_error
= go_error_info_new_str (
377 _("Missing file name."));
380 verbs_node
= go_xml_get_child_by_name (tree
, "actions");
381 if (verbs_node
!= NULL
) {
382 xmlNode
*ptr
, *label_node
;
383 xmlChar
*name
, *icon
;
385 gboolean always_available
;
388 for (ptr
= verbs_node
->xmlChildrenNode
; ptr
!= NULL
; ptr
= ptr
->next
) {
389 if (xmlIsBlankNode (ptr
) || ptr
->name
== NULL
||
390 strcmp (CXML2C (ptr
->name
), "action"))
392 name
= go_xml_node_get_cstr (ptr
, "name");
393 /* label = go_xml_node_get_cstr (ptr, "label");*/
394 /*****************************************************************************************/
395 label_node
= go_xml_get_child_by_name_no_lang (ptr
, "label");
397 ? xml2c (xmlNodeGetContent (label_node
))
400 label_node
= go_xml_get_child_by_name_by_lang (ptr
, "label");
401 if (label_node
!= NULL
) {
404 lang
= go_xml_node_get_cstr (label_node
, "lang");
406 label
= xml2c (xmlNodeGetContent (label_node
));
410 /*****************************************************************************************/
411 icon
= go_xml_node_get_cstr (ptr
, "icon");
412 if (!go_xml_node_get_bool (ptr
, "always_available", &always_available
))
413 always_available
= FALSE
;
414 action
= gnm_action_new (name
, label
, icon
, always_available
,
415 (GnmActionHandler
) cb_ui_service_activate
);
416 if (NULL
!= name
) xmlFree (name
);
418 if (NULL
!= icon
) xmlFree (icon
);
420 GO_SLIST_PREPEND (actions
, action
);
423 GO_SLIST_REVERSE (actions
);
425 service_ui
->file_name
= file_name
;
426 service_ui
->actions
= actions
;
430 plugin_service_ui_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
432 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
433 const char *uifile
= service_ui
->file_name
;
434 char *xml_ui
, *group_name
;
436 GError
*error
= NULL
;
440 GO_INIT_RET_ERROR_INFO (ret_error
);
442 if (strncmp (uifile
, "res:", 4) == 0) {
444 gconstpointer data
= go_rsm_lookup (uifile
+ 4, &len
);
446 ? gsf_input_memory_new (data
, len
, FALSE
)
448 } else if (strncmp (uifile
, "data:", 5) == 0) {
449 const char *data
= uifile
+ 5;
450 src
= gsf_input_memory_new (data
, strlen (data
), FALSE
);
452 char *full_file_name
= g_path_is_absolute (uifile
)
455 (go_plugin_get_dir_name (service
->plugin
),
458 src
= gsf_input_stdio_new (full_file_name
, &error
);
459 g_free (full_file_name
);
464 src
= gsf_input_uncompress (src
);
465 len
= gsf_input_size (src
);
466 xml_ui
= g_strndup (gsf_input_read (src
, len
, NULL
), len
);
470 tdomain
= go_plugin_get_textdomain (service
->plugin
);
471 group_name
= g_strconcat (go_plugin_get_id (service
->plugin
), service
->id
, NULL
);
472 service_ui
->layout_id
= gnm_app_add_extra_ui (group_name
,
474 xml_ui
, tdomain
, service
);
477 g_object_unref (src
);
478 service
->is_active
= TRUE
;
482 *ret_error
= go_error_info_new_printf
483 (_("Cannot read UI description from %s: %s"),
485 error
? error
->message
: "?");
486 g_clear_error (&error
);
488 g_object_unref (src
);
492 plugin_service_ui_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
494 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
496 GO_INIT_RET_ERROR_INFO (ret_error
);
497 gnm_app_remove_extra_ui (service_ui
->layout_id
);
498 service_ui
->layout_id
= NULL
;
499 service
->is_active
= FALSE
;
503 plugin_service_ui_get_description (GOPluginService
*service
)
505 PluginServiceUI
*service_ui
= GNM_PLUGIN_SERVICE_UI (service
);
508 n_actions
= g_slist_length (service_ui
->actions
);
509 return g_strdup_printf (
511 /* xgettext : %d gives the number of actions. This is input to ngettext. */
512 "User interface with %d action",
513 "User interface with %d actions",
519 plugin_service_ui_class_init (GObjectClass
*gobject_class
)
521 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
523 gobject_class
->finalize
= plugin_service_ui_finalize
;
524 plugin_service_class
->read_xml
= plugin_service_ui_read_xml
;
525 plugin_service_class
->activate
= plugin_service_ui_activate
;
526 plugin_service_class
->deactivate
= plugin_service_ui_deactivate
;
527 plugin_service_class
->get_description
= plugin_service_ui_get_description
;
530 GSF_CLASS (PluginServiceUI
, gnm_plugin_service_ui
,
531 plugin_service_ui_class_init
, plugin_service_ui_init
,
532 GO_TYPE_PLUGIN_SERVICE_SIMPLE
)
534 /****************************************************************************/
537 * PluginServiceSolver
539 typedef GOPluginServiceClass PluginServiceSolverClass
;
540 struct GnmPluginServiceSolver_
{
541 GOPluginService base
;
543 GnmSolverFactory
*factory
;
545 GnmPluginServiceSolverCallbacks cbs
;
549 cb_load_and_create (GnmSolverFactory
*factory
, GnmSolverParameters
*param
,
552 PluginServiceSolver
*ssol
=
553 g_object_get_data (G_OBJECT (factory
), "ssol");
554 GOPluginService
*service
= GO_PLUGIN_SERVICE (ssol
);
555 GOErrorInfo
*ignored_error
= NULL
;
558 go_plugin_service_load (service
, &ignored_error
);
559 if (ignored_error
!= NULL
) {
560 go_error_info_print (ignored_error
);
561 go_error_info_free (ignored_error
);
565 res
= ssol
->cbs
.creator (factory
, param
, data
);
567 go_plugin_use_ref (service
->plugin
);
568 g_object_set_data_full (G_OBJECT (res
),
569 "plugin-use", service
->plugin
,
570 (GDestroyNotify
)go_plugin_use_unref
);
577 cb_load_and_functional (GnmSolverFactory
*factory
,
581 PluginServiceSolver
*ssol
=
582 g_object_get_data (G_OBJECT (factory
), "ssol");
583 GOPluginService
*service
= GO_PLUGIN_SERVICE (ssol
);
584 GOErrorInfo
*ignored_error
= NULL
;
585 GnmSolverFactoryFunctional functional
;
587 go_plugin_service_load (service
, &ignored_error
);
588 if (ignored_error
!= NULL
) {
589 go_error_info_print (ignored_error
);
590 go_error_info_free (ignored_error
);
594 functional
= ssol
->cbs
.functional
;
595 return (functional
== NULL
|| functional (factory
, wbcg
, data
));
599 plugin_service_solver_init (PluginServiceSolver
*ssol
)
601 GO_PLUGIN_SERVICE (ssol
)->cbs_ptr
= &ssol
->cbs
;
602 ssol
->factory
= NULL
;
603 ssol
->cbs
.creator
= NULL
;
607 plugin_service_solver_finalize (GObject
*obj
)
609 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (obj
);
610 GObjectClass
*parent_class
;
613 g_object_unref (ssol
->factory
);
615 parent_class
= g_type_class_peek (GO_TYPE_PLUGIN_SERVICE
);
616 parent_class
->finalize (obj
);
620 plugin_service_solver_read_xml (GOPluginService
*service
, xmlNode
*tree
,
621 GOErrorInfo
**ret_error
)
623 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
624 xmlChar
*s_id
, *s_name
, *s_type
;
625 GnmSolverModelType type
= GNM_SOLVER_LP
;
626 xmlNode
*information_node
;
628 GO_INIT_RET_ERROR_INFO (ret_error
);
630 s_type
= go_xml_node_get_cstr (tree
, "model_type");
631 if (s_type
&& strcmp (CXML2C (s_type
), "mip") == 0)
632 type
= GNM_SOLVER_LP
;
633 else if (s_type
&& strcmp (CXML2C (s_type
), "qp") == 0)
634 type
= GNM_SOLVER_QP
;
635 else if (s_type
&& strcmp (CXML2C (s_type
), "nlp") == 0)
636 type
= GNM_SOLVER_NLP
;
638 *ret_error
= go_error_info_new_str (_("Invalid solver model type."));
643 s_id
= go_xml_node_get_cstr (tree
, "id");
646 information_node
= go_xml_get_child_by_name (tree
, "information");
647 if (information_node
!= NULL
) {
649 go_xml_get_child_by_name_by_lang (information_node
,
652 s_name
= xmlNodeGetContent (node
);
656 if (!s_id
|| !s_name
) {
657 *ret_error
= go_error_info_new_str (_("Missing fields in plugin file"));
659 ssol
->factory
= gnm_solver_factory_new (CXML2C (s_id
),
663 cb_load_and_functional
,
666 g_object_set_data (G_OBJECT (ssol
->factory
), "ssol", ssol
);
677 plugin_service_solver_activate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
679 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
681 GO_INIT_RET_ERROR_INFO (ret_error
);
682 gnm_solver_db_register (ssol
->factory
);
683 service
->is_active
= TRUE
;
687 plugin_service_solver_deactivate (GOPluginService
*service
, GOErrorInfo
**ret_error
)
689 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
691 GO_INIT_RET_ERROR_INFO (ret_error
);
692 gnm_solver_db_unregister (ssol
->factory
);
693 service
->is_active
= FALSE
;
697 plugin_service_solver_get_description (GOPluginService
*service
)
699 PluginServiceSolver
*ssol
= GNM_PLUGIN_SERVICE_SOLVER (service
);
700 return g_strdup_printf (_("Solver Algorithm %s"),
701 ssol
->factory
->name
);
705 plugin_service_solver_class_init (GObjectClass
*gobject_class
)
707 GOPluginServiceClass
*plugin_service_class
= GO_PLUGIN_SERVICE_CLASS (gobject_class
);
709 gobject_class
->finalize
= plugin_service_solver_finalize
;
710 plugin_service_class
->read_xml
= plugin_service_solver_read_xml
;
711 plugin_service_class
->activate
= plugin_service_solver_activate
;
712 plugin_service_class
->deactivate
= plugin_service_solver_deactivate
;
713 plugin_service_class
->get_description
= plugin_service_solver_get_description
;
716 GSF_CLASS (PluginServiceSolver
, gnm_plugin_service_solver
,
717 plugin_service_solver_class_init
, plugin_service_solver_init
,
718 GO_TYPE_PLUGIN_SERVICE
)
720 /****************************************************************************/
723 typedef GOPluginLoaderModule GnmPluginLoaderModule
;
724 typedef GOPluginLoaderModuleClass GnmPluginLoaderModuleClass
;
727 * Service - function_group
730 GnmFuncDescriptor
*module_fn_info_array
;
731 GHashTable
*function_indices
;
732 } ServiceLoaderDataFunctionGroup
;
735 function_group_loader_data_free (gpointer data
)
737 ServiceLoaderDataFunctionGroup
*ld
= data
;
739 g_hash_table_destroy (ld
->function_indices
);
744 gnm_plugin_loader_module_func_desc_load (GOPluginService
*service
,
746 GnmFuncDescriptor
*res
)
748 ServiceLoaderDataFunctionGroup
*loader_data
;
749 gpointer func_index_ptr
;
751 g_return_val_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
), FALSE
);
752 g_return_val_if_fail (name
!= NULL
, FALSE
);
754 loader_data
= g_object_get_data (G_OBJECT (service
), "loader_data");
755 if (g_hash_table_lookup_extended (loader_data
->function_indices
, (gpointer
) name
,
756 NULL
, &func_index_ptr
)) {
757 int i
= GPOINTER_TO_INT (func_index_ptr
);
758 *res
= loader_data
->module_fn_info_array
[i
];
764 gnm_plugin_loader_module_load_service_function_group (GOPluginLoader
*loader
,
765 GOPluginService
*service
,
766 GOErrorInfo
**ret_error
)
768 GnmPluginLoaderModule
*loader_module
= GNM_PLUGIN_LOADER_MODULE (loader
);
769 gchar
*fn_info_array_name
;
770 GnmFuncDescriptor
*module_fn_info_array
= NULL
;
772 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (service
));
774 GO_INIT_RET_ERROR_INFO (ret_error
);
775 fn_info_array_name
= g_strconcat (
776 go_plugin_service_get_id (service
), "_functions", NULL
);
777 g_module_symbol (loader_module
->handle
, fn_info_array_name
, (gpointer
) &module_fn_info_array
);
778 if (module_fn_info_array
!= NULL
) {
779 GnmPluginServiceFunctionGroupCallbacks
*cbs
;
780 ServiceLoaderDataFunctionGroup
*loader_data
;
783 cbs
= go_plugin_service_get_cbs (service
);
784 cbs
->func_desc_load
= &gnm_plugin_loader_module_func_desc_load
;
786 loader_data
= g_new (ServiceLoaderDataFunctionGroup
, 1);
787 loader_data
->module_fn_info_array
= module_fn_info_array
;
788 loader_data
->function_indices
= g_hash_table_new (&g_str_hash
, &g_str_equal
);
789 for (i
= 0; module_fn_info_array
[i
].name
!= NULL
; i
++) {
790 g_hash_table_insert (loader_data
->function_indices
,
791 (gpointer
) module_fn_info_array
[i
].name
,
792 GINT_TO_POINTER (i
));
794 g_object_set_data_full (
795 G_OBJECT (service
), "loader_data", loader_data
, function_group_loader_data_free
);
797 *ret_error
= go_error_info_new_printf (
798 _("Module file \"%s\" has invalid format."),
799 loader_module
->module_file_name
);
800 go_error_info_add_details (*ret_error
,
801 go_error_info_new_printf (
802 _("File doesn't contain \"%s\" array."),
803 fn_info_array_name
));
805 g_free (fn_info_array_name
);
813 GnmModulePluginUIActions
*module_ui_actions_array
;
814 GHashTable
*ui_actions_hash
;
815 } ServiceLoaderDataUI
;
818 ui_loader_data_free (gpointer data
)
820 ServiceLoaderDataUI
*ld
= data
;
822 g_hash_table_destroy (ld
->ui_actions_hash
);
827 gnm_plugin_loader_module_func_exec_action (GOPluginService
*service
,
828 GnmAction
const *action
,
829 WorkbookControl
*wbc
,
830 GOErrorInfo
**ret_error
)
832 ServiceLoaderDataUI
*loader_data
;
833 gpointer action_index_ptr
;
836 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_UI (service
));
838 GO_INIT_RET_ERROR_INFO (ret_error
);
839 loader_data
= g_object_get_data (G_OBJECT (service
), "loader_data");
840 if (!g_hash_table_lookup_extended (loader_data
->ui_actions_hash
, action
->id
,
841 NULL
, &action_index_ptr
)) {
842 *ret_error
= go_error_info_new_printf (_("Unknown action: %s"), action
->id
);
845 action_index
= GPOINTER_TO_INT (action_index_ptr
);
846 if (NULL
!= loader_data
->module_ui_actions_array
[action_index
].handler
)
847 (*loader_data
->module_ui_actions_array
[action_index
].handler
) (action
, wbc
);
851 gnm_plugin_loader_module_load_service_ui (GOPluginLoader
*loader
,
852 GOPluginService
*service
,
853 GOErrorInfo
**ret_error
)
855 GnmPluginLoaderModule
*loader_module
= GNM_PLUGIN_LOADER_MODULE (loader
);
856 char *ui_actions_array_name
;
857 GnmModulePluginUIActions
*module_ui_actions_array
= NULL
;
858 GnmPluginServiceUICallbacks
*cbs
;
859 ServiceLoaderDataUI
*loader_data
;
862 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_UI (service
));
864 GO_INIT_RET_ERROR_INFO (ret_error
);
865 ui_actions_array_name
= g_strconcat (
866 go_plugin_service_get_id (service
), "_ui_actions", NULL
);
867 g_module_symbol (loader_module
->handle
, ui_actions_array_name
, (gpointer
) &module_ui_actions_array
);
868 if (module_ui_actions_array
== NULL
) {
869 *ret_error
= go_error_info_new_printf (
870 _("Module file \"%s\" has invalid format."),
871 loader_module
->module_file_name
);
872 go_error_info_add_details (*ret_error
, go_error_info_new_printf (
873 _("File doesn't contain \"%s\" array."), ui_actions_array_name
));
874 g_free (ui_actions_array_name
);
877 g_free (ui_actions_array_name
);
879 cbs
= go_plugin_service_get_cbs (service
);
880 cbs
->plugin_func_exec_action
= gnm_plugin_loader_module_func_exec_action
;
882 loader_data
= g_new (ServiceLoaderDataUI
, 1);
883 loader_data
->module_ui_actions_array
= module_ui_actions_array
;
884 loader_data
->ui_actions_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
885 for (i
= 0; module_ui_actions_array
[i
].name
!= NULL
; i
++)
886 g_hash_table_insert (loader_data
->ui_actions_hash
,
887 (gpointer
) module_ui_actions_array
[i
].name
,
888 GINT_TO_POINTER (i
));
889 g_object_set_data_full (G_OBJECT (service
),
890 "loader_data", loader_data
, ui_loader_data_free
);
894 gnm_plugin_loader_module_load_service_solver (GOPluginLoader
*loader
,
895 GOPluginService
*service
,
896 GOErrorInfo
**ret_error
)
898 GnmPluginLoaderModule
*loader_module
=
899 GNM_PLUGIN_LOADER_MODULE (loader
);
900 GnmPluginServiceSolverCallbacks
*cbs
;
902 GnmSolverCreator creator
;
903 GnmSolverFactoryFunctional functional
;
905 g_return_if_fail (GNM_IS_PLUGIN_SERVICE_SOLVER (service
));
907 GO_INIT_RET_ERROR_INFO (ret_error
);
909 symname
= g_strconcat (go_plugin_service_get_id (service
),
912 g_module_symbol (loader_module
->handle
, symname
, (gpointer
)&creator
);
915 *ret_error
= go_error_info_new_printf (
916 _("Module file \"%s\" has invalid format."),
917 loader_module
->module_file_name
);
921 symname
= g_strconcat (go_plugin_service_get_id (service
),
922 "_solver_factory_functional",
924 g_module_symbol (loader_module
->handle
, symname
, (gpointer
)&functional
);
927 cbs
= go_plugin_service_get_cbs (service
);
928 cbs
->creator
= creator
;
929 cbs
->functional
= functional
;
933 gplm_service_load (GOPluginLoader
*l
, GOPluginService
*s
, GOErrorInfo
**err
)
935 if (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (s
))
936 gnm_plugin_loader_module_load_service_function_group (l
, s
, err
);
937 else if (GNM_IS_PLUGIN_SERVICE_UI (s
))
938 gnm_plugin_loader_module_load_service_ui (l
, s
, err
);
939 else if (GNM_IS_PLUGIN_SERVICE_SOLVER (s
))
940 gnm_plugin_loader_module_load_service_solver (l
, s
, err
);
947 gplm_service_unload (GOPluginLoader
*l
, GOPluginService
*s
, GOErrorInfo
**err
)
949 if (GNM_IS_PLUGIN_SERVICE_FUNCTION_GROUP (s
)) {
950 GnmPluginServiceFunctionGroupCallbacks
*cbs
= go_plugin_service_get_cbs (s
);
951 cbs
->func_desc_load
= NULL
;
952 } else if (GNM_IS_PLUGIN_SERVICE_UI (s
)) {
953 GnmPluginServiceUICallbacks
*cbs
= go_plugin_service_get_cbs (s
);
954 cbs
->plugin_func_exec_action
= NULL
;
955 } else if (GNM_IS_PLUGIN_SERVICE_SOLVER (s
)) {
956 GnmPluginServiceSolverCallbacks
*cbs
=
957 go_plugin_service_get_cbs (s
);
959 cbs
->functional
= NULL
;
966 go_plugin_loader_module_iface_init (GOPluginLoaderClass
*iface
)
968 iface
->service_load
= gplm_service_load
;
969 iface
->service_unload
= gplm_service_unload
;
972 GSF_CLASS_FULL (GnmPluginLoaderModule
, gnm_plugin_loader_module
,
973 NULL
, NULL
, NULL
, NULL
,
974 NULL
, GO_TYPE_PLUGIN_LOADER_MODULE
, 0,
975 GSF_INTERFACE (go_plugin_loader_module_iface_init
, GO_TYPE_PLUGIN_LOADER
))
977 /****************************************************************************/
980 * gnm_plugins_service_init: (skip)
983 gnm_plugins_service_init (void)
985 go_plugin_service_define ("function_group",
986 &gnm_plugin_service_function_group_get_type
);
987 go_plugin_service_define ("ui",
988 &gnm_plugin_service_ui_get_type
);
989 go_plugin_service_define ("solver",
990 &gnm_plugin_service_solver_get_type
);
991 go_plugin_loader_module_register_version ("gnumeric", GNM_VERSION_FULL
);
996 gnm_plugins_init (GOCmdContext
*context
)
999 GSList
*dir_list
= go_slist_create (
1000 g_build_filename (gnm_sys_lib_dir (), PLUGIN_SUBDIR
, NULL
),
1001 g_strdup (gnm_sys_extern_plugin_dir ()),
1002 (gnm_usr_dir (TRUE
) == NULL
? NULL
:
1003 g_build_filename (gnm_usr_dir (TRUE
), PLUGIN_SUBDIR
, NULL
)),
1005 dir_list
= g_slist_concat (dir_list
,
1006 go_string_slist_copy (gnm_conf_get_plugins_extra_dirs ()));
1008 env_var
= g_getenv ("GNUMERIC_PLUGIN_PATH");
1009 if (env_var
!= NULL
)
1010 GO_SLIST_CONCAT (dir_list
, go_strsplit_to_slist (env_var
, G_SEARCHPATH_SEPARATOR
));
1012 go_plugins_init (GO_CMD_CONTEXT (context
),
1013 gnm_conf_get_plugins_file_states (),
1014 gnm_conf_get_plugins_active (),
1016 gnm_conf_get_plugins_activate_newplugins (),
1017 gnm_plugin_loader_module_get_type ());