]> Dogcows Code - chaz/openbox/blob - openbox/plugin.c
rename "Slit" to "Dock".
[chaz/openbox] / openbox / plugin.c
1 #include <glib.h>
2 #include <gmodule.h>
3
4 typedef void (*PluginSetupConfig)();
5 typedef void (*PluginStartup)();
6 typedef void (*PluginShutdown)();
7 typedef void *(*PluginCreate)(/* TODO */);
8 typedef void (*PluginDestroy)(void *);
9
10 typedef struct {
11 GModule *module;
12 char *name;
13
14 PluginSetupConfig config;
15 PluginStartup startup;
16 PluginShutdown shutdown;
17 PluginCreate create;
18 PluginDestroy destroy;
19 } Plugin;
20
21 static gpointer load_sym(GModule *module, char *name, char *symbol,
22 gboolean allow_fail)
23 {
24 gpointer var;
25 if (!g_module_symbol(module, symbol, &var)) {
26 if (!allow_fail)
27 g_warning("Failed to load symbol '%s' from plugin '%s'",
28 symbol, name);
29 var = NULL;
30 }
31 return var;
32 }
33
34 static Plugin *plugin_new(char *name)
35 {
36 Plugin *p;
37 char *path;
38
39 p = g_new(Plugin, 1);
40
41 path = g_build_filename(g_get_home_dir(), ".openbox", "plugins", name,
42 NULL);
43 p->module = g_module_open(path, 0);
44 g_free(path);
45
46 if (p->module == NULL) {
47 path = g_build_filename(PLUGINDIR, name, NULL);
48 p->module = g_module_open(path, 0);
49 g_free(path);
50 }
51
52 if (p->module == NULL) {
53 g_warning(g_module_error());
54 g_free(p);
55 return NULL;
56 }
57
58 p->config = (PluginSetupConfig)load_sym(p->module, name,
59 "plugin_setup_config", FALSE);
60 p->startup = (PluginStartup)load_sym(p->module, name, "plugin_startup",
61 FALSE);
62 p->shutdown = (PluginShutdown)load_sym(p->module, name, "plugin_shutdown",
63 FALSE);
64 p->create = (PluginCreate)load_sym(p->module, name, "plugin_create", TRUE);
65 p->destroy = (PluginDestroy)load_sym(p->module, name, "plugin_destroy",
66 TRUE);
67
68 if (p->config == NULL || p->startup == NULL || p->shutdown == NULL) {
69 g_module_close(p->module);
70 g_free(p);
71 return NULL;
72 }
73
74 p->name = g_strdup(name);
75 return p;
76 }
77
78 static void plugin_free(Plugin *p)
79 {
80 p->shutdown();
81
82 g_free(p->name);
83 g_module_close(p->module);
84 }
85
86
87 static GData *plugins = NULL;
88
89 void plugin_startup()
90 {
91 g_datalist_init(&plugins);
92 }
93
94 void plugin_shutdown()
95 {
96 g_datalist_clear(&plugins);
97 }
98
99 gboolean plugin_open_full(char *name, gboolean reopen)
100 {
101 Plugin *p;
102
103 if (g_datalist_get_data(&plugins, name) != NULL) {
104 if (!reopen)
105 g_warning("plugin '%s' already loaded, can't load again", name);
106 return TRUE;
107 }
108
109 p = plugin_new(name);
110 if (p == NULL) {
111 g_warning("failed to load plugin '%s'", name);
112 return FALSE;
113 }
114 p->config();
115
116 g_datalist_set_data_full(&plugins, name, p, (GDestroyNotify) plugin_free);
117 return TRUE;
118 }
119
120 gboolean plugin_open(char *name) {
121 return plugin_open_full(name, FALSE);
122 }
123
124 gboolean plugin_open_reopen(char *name) {
125 return plugin_open_full(name, TRUE);
126 }
127
128 void plugin_close(char *name)
129 {
130 g_datalist_remove_data(&plugins, name);
131 }
132
133 static void foreach_start(GQuark key, Plugin *p, gpointer *foo)
134 {
135 p->startup();
136 }
137
138 void plugin_startall()
139 {
140 g_datalist_foreach(&plugins, (GDataForeachFunc)foreach_start, NULL);
141 }
142
143 void plugin_loadall()
144 {
145 GIOChannel *io;
146 GError *err;
147 char *path, *name;
148
149 path = g_build_filename(g_get_home_dir(), ".openbox", "pluginrc", NULL);
150 err = NULL;
151 io = g_io_channel_new_file(path, "r", &err);
152 g_free(path);
153
154 if (io == NULL) {
155 path = g_build_filename(RCDIR, "pluginrc", NULL);
156 err = NULL;
157 io = g_io_channel_new_file(path, "r", &err);
158 g_free(path);
159 }
160
161 if (io == NULL) {
162 /* load the default plugins */
163 plugin_open("keyboard");
164 plugin_open("mouse");
165 plugin_open("placement");
166 plugin_open("resistance");
167 } else {
168 /* load the plugins in the rc file */
169 while (g_io_channel_read_line(io, &name, NULL, NULL, &err) ==
170 G_IO_STATUS_NORMAL) {
171 g_strstrip(name);
172 if (name[0] != '\0' && name[0] != '#')
173 plugin_open(name);
174 g_free(name);
175 }
176 g_io_channel_unref(io);
177 }
178 }
179
180 void *plugin_create(char *name /* TODO */)
181 {
182 Plugin *p = (Plugin *)g_datalist_get_data(&plugins, name);
183
184 if (p == NULL) {
185 g_warning("Unable to find plugin for create: %s", name);
186 return NULL;
187 }
188
189 if (p->create == NULL || p->destroy == NULL) {
190 g_critical("Unsupported create/destroy: %s", name);
191 return NULL;
192 }
193
194 return p->create();
195 }
196
197 void plugin_destroy(char *name, void *data)
198 {
199 Plugin *p = (Plugin *)g_datalist_get_data(&plugins, name);
200
201 if (p == NULL) {
202 g_critical("Unable to find plugin for destroy: %s", name);
203 /* really shouldn't happen, but attempt to free something anyway? */
204 g_free(data);
205 return;
206 }
207
208 if (p->destroy == NULL || p->create == NULL) {
209 g_critical("Unsupported create/destroy: %s", name);
210 /* really, really shouldn't happen, but attempt to free anyway? */
211 g_free(data);
212 return;
213 }
214
215 p->destroy(data);
216 }
This page took 0.04506 seconds and 4 git commands to generate.