77d376aefd1a79b8a3ae315e3e0128715e3e9b0e
[hildon] / hildon-widgets / hildon-plugin-widget.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation.
5  *
6  * Author: Kuisma Salonen <kuisma.salonen@nokia.com>
7  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; version 2.1 of
12  * the License.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  *
24  */
25
26 /**
27  * SECTION:hildon-plugin-widget
28  * @short_description: A simple interface to load plugin based widgets. Not
29  * compatible with GObject.
30  *
31  * #HildonPluginWidgetInfo is a struct containing information about loaded
32  * module which contains code for a widget.
33  */
34
35
36 #include <stdio.h>
37 #include <memory.h>
38 #include <string.h>
39
40 #include <gtk/gtk.h>
41
42
43 #include "hildon-plugin-widget.h"
44
45
46 #ifndef PLUGIN_DIR
47 #define PLUGIN_DIR      "/usr/lib/hildon-widgets"
48 #endif
49
50
51 struct HildonPluginWidgetInfo_ {
52   GType base_type;
53
54   gchar *filename;
55
56   GModule *module;
57   int refcount;
58
59   GType (*get_type) ();
60 };
61
62
63 static gchar *hildon_plugin_filename(GType base_type, const gchar *name);
64
65   /* WARNING: works properly only with ASCII */
66 static gchar *ascii_decapitalize_without_dashes(gchar *source);
67
68 static gchar *hildon_plugin_default_name(gchar *typename);
69
70 /**
71  * hildon_plugin_info_initialize:
72  * @base_type: a #GType representing parent type of object that will be
73  * loaded.
74  * @name: Name of child. To load default (or #GtkSettings defined), NULL
75  * should be passed as name. To load specific child type, decapitalized name
76  * should be passed here.
77  * 
78  * Creates a new #HildonPluginWidgetInfo structure and opens a module.
79  *
80  * The naming of child widgets (or objects) doesn't matter, but for plugins
81  * the file names should be type
82  * <decapitalized-parent-type-name-with-dashes>-<pluginname>.so where the
83  * decapitalized type name would be for example for #GtkWidget gtk-widget.
84  *
85  * The name comes from name argument or from #GtkSettings where the variable
86  * storing it is with name <ParentTypeName>-plugin, for #GtkWidget this would
87  * be "GtkWidget-plugin". If nothing is defined in #GtkSettings, name
88  * "default" is assumed. For this case there should be symlink to some child
89  * type plugin named <parent-type-name>-default.so
90  *
91  * Returns: a #HildonPluginWidgetInfo struct pointer upon success, NULL if
92  * failed.
93  */
94 HildonPluginWidgetInfo *hildon_plugin_info_initialize(GType base_type, const gchar *name)
95 {
96   HildonPluginWidgetInfo *ret;
97   GModule *module;
98   gchar *filename;
99
100
101   if(!base_type) {
102     return NULL;
103   }
104
105
106   filename = hildon_plugin_filename(base_type, name);
107   g_return_val_if_fail (filename != NULL, NULL);
108
109
110   module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
111   if(!module) {
112     g_warning ("Failed to load plugin for '%s' (filename: '%s')", name, filename);
113     g_free(filename);
114     return NULL;
115   }
116
117
118   ret = (HildonPluginWidgetInfo *)g_malloc0(sizeof(HildonPluginWidgetInfo) + strlen(filename) + 1);
119   ret->filename = (gchar *)ret + sizeof(HildonPluginWidgetInfo);
120
121   ret->base_type = base_type;
122
123   ret->module = module;
124
125   g_module_symbol(module, "export_type", (void **)&ret->get_type);
126
127   memcpy(ret->filename, filename, strlen(filename));
128
129
130   g_free(filename);
131
132
133   return ret;
134 }
135
136 /**
137  * hildon_plugin_info_construct_widget:
138  * @info: pointer to a #HildonPluginWidgetInfo struct.
139  * 
140  * Creates instance of loaded type from module stored in
141  * #HildonPluginWidgetInfo struct. Designed for loading types inherited from
142  * GtkWidget, but could be basically any GTK+ type.
143  *
144  * Returns: a GtkWidget pointer to instance of loaded type.
145  */
146 GtkWidget *hildon_plugin_info_construct_widget(HildonPluginWidgetInfo *info)
147 {
148   g_return_val_if_fail (info != NULL, NULL);
149   info->refcount++;
150
151
152   return GTK_WIDGET(g_type_create_instance(info->get_type()));
153 }
154
155 /**
156  * hildon_plugin_info_kill:
157  * @info: a pointer to a #HildonPluginWidgetInfo struct that should be
158  * destroyed.
159  * 
160  * Frees the plugin information structure and unloads the module.
161  */
162 void hildon_plugin_info_kill(HildonPluginWidgetInfo *info)
163 {
164   if(!info) {
165     return;
166   }
167
168
169   g_module_close(info->module);
170
171
172   g_free(info);
173 }
174
175
176 static gchar *hildon_plugin_filename(GType base_type, const gchar *name)
177 {
178   gchar *ret, *name2, *plgbuf;
179   gchar *typename = (gchar *)g_type_name(base_type);
180   int retsize;
181
182
183   plgbuf = ascii_decapitalize_without_dashes(typename);
184
185
186   if(name) {
187     name2 = g_strdup(name);
188   } else {
189     name2 = hildon_plugin_default_name(typename);
190   }
191
192
193   retsize = strlen(PLUGIN_DIR) + strlen(plgbuf) + strlen(name2) + 6;
194   ret = (gchar *)g_malloc0(retsize);
195   g_snprintf(ret, retsize, "%s/%s_%s.so", PLUGIN_DIR, plgbuf, name2);
196
197
198   g_free(name2);
199   g_free(plgbuf);
200
201
202   return ret;
203 }
204
205   /* possible speedup: pre-allocate more memory and ditch the first loop */
206 static gchar *ascii_decapitalize_without_dashes(gchar *source)
207 {
208   gchar *ptr, *ret = g_strdup (source);
209
210
211   for(ptr = ret; *ptr; ptr++) {
212     if(*ptr >= 'A' && *ptr <= 'Z') {
213       *ptr += 0x20;
214     }
215   }
216
217
218   return ret;
219 }
220
221
222 static gchar *hildon_plugin_default_name(gchar *typename)
223 {
224   GtkSettings *settings;
225   gchar *ret, *val, *tmp;
226   int tmplen;
227
228
229   tmplen = strlen(typename) + strlen("-plugin") + 1;
230   tmp = (gchar *)g_malloc0(tmplen);
231   g_snprintf(tmp, tmplen, "%s-plugin", typename);
232
233
234   gtk_settings_install_property(g_param_spec_string(tmp,
235                                                     tmp,
236                                                     "Plugin for this pecific widget",
237                                                     NULL,
238                                                     G_PARAM_READWRITE));
239
240   settings = gtk_settings_get_default();
241
242   g_object_get(G_OBJECT(settings), tmp, &val, NULL);
243
244   g_free(tmp);
245
246
247   if(val) {
248     ret = (gchar *)g_malloc0(strlen(val)+1);
249     memcpy(ret, val, strlen(val));
250     g_free(val);
251   } else {
252     ret = (gchar *)g_malloc0(strlen("default")+1);
253
254
255     g_snprintf(ret, strlen("default")+1, "default");
256   }
257
258
259   return ret;
260 }