Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-application"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libtracker-sparql/tracker-sparql.h>
10 : :
11 : : #include "valent-application.h"
12 : : #include "valent-application-plugin.h"
13 : : #include "valent-component-private.h"
14 : : #include "valent-debug.h"
15 : : #include "valent-global.h"
16 : :
17 : :
18 : : /**
19 : : * ValentApplication:
20 : : *
21 : : * The primary application class of Valent.
22 : : *
23 : : * `ValentApplication` is the primary application class for Valent.
24 : : *
25 : : * Since: 1.0
26 : : */
27 : :
28 : : struct _ValentApplication
29 : : {
30 : : GApplication parent_instance;
31 : :
32 : : GHashTable *plugins;
33 : : ValentContext *plugins_context;
34 : : };
35 : :
36 [ + + + - ]: 170 : G_DEFINE_FINAL_TYPE (ValentApplication, valent_application, G_TYPE_APPLICATION)
37 : :
38 : :
39 : : /*
40 : : * PeasEngine
41 : : */
42 : : static inline void
43 : 8 : valent_application_enable_plugin (ValentApplication *self,
44 : : ValentPlugin *plugin)
45 : : {
46 : 8 : g_autofree char *urn = NULL;
47 : 8 : const char *title = NULL;
48 : 8 : const char *description = NULL;
49 : 8 : const char *module = NULL;
50 : :
51 [ + - ]: 8 : g_assert (VALENT_IS_APPLICATION (self));
52 : :
53 : 8 : title = peas_plugin_info_get_name (plugin->info);
54 : 8 : description = peas_plugin_info_get_description (plugin->info);
55 : 8 : module = peas_plugin_info_get_module_name (plugin->info);
56 : 8 : urn = tracker_sparql_escape_uri_printf ("urn:valent:application:%s", module);
57 : 8 : plugin->extension = peas_engine_create_extension (valent_get_plugin_engine (),
58 : : plugin->info,
59 : : VALENT_TYPE_APPLICATION_PLUGIN,
60 : : "iri", urn,
61 : : // FIXME: root source
62 : : "source", NULL,
63 : : "title", title,
64 : : "description", description,
65 : : NULL);
66 [ - + ]: 8 : g_return_if_fail (G_IS_OBJECT (plugin->extension));
67 : : }
68 : :
69 : : static inline void
70 : 1 : valent_application_disable_plugin (ValentApplication *self,
71 : : ValentPlugin *plugin)
72 : : {
73 [ + - ]: 1 : g_assert (VALENT_IS_APPLICATION (self));
74 : :
75 [ + - ]: 1 : if (plugin->extension != NULL)
76 : : {
77 : 1 : valent_object_destroy (VALENT_OBJECT (plugin->extension));
78 [ + - ]: 1 : g_clear_object (&plugin->extension);
79 : : }
80 : 1 : }
81 : :
82 : : static void
83 : 2 : on_plugin_enabled_changed (ValentPlugin *plugin)
84 : : {
85 [ + - ]: 2 : g_assert (plugin != NULL);
86 [ - + ]: 2 : g_assert (VALENT_IS_APPLICATION (plugin->parent));
87 : :
88 [ + + ]: 2 : if (valent_plugin_get_enabled (plugin))
89 : 1 : valent_application_enable_plugin (plugin->parent, plugin);
90 : : else
91 : 1 : valent_application_disable_plugin (plugin->parent, plugin);
92 : 2 : }
93 : :
94 : : static void
95 : 10 : on_load_plugin (PeasEngine *engine,
96 : : PeasPluginInfo *info,
97 : : ValentApplication *self)
98 : : {
99 : 10 : ValentPlugin *plugin = NULL;
100 : :
101 [ + - ]: 10 : g_assert (PEAS_IS_ENGINE (engine));
102 [ - + ]: 10 : g_assert (info != NULL);
103 [ - + ]: 10 : g_assert (VALENT_IS_APPLICATION (self));
104 : :
105 [ + + ]: 10 : if (!peas_engine_provides_extension (engine, info, VALENT_TYPE_APPLICATION_PLUGIN))
106 : : return;
107 : :
108 : 7 : VALENT_NOTE ("%s: %s",
109 : : g_type_name (VALENT_TYPE_APPLICATION_PLUGIN),
110 : : peas_plugin_info_get_module_name (info));
111 : :
112 : 7 : plugin = valent_plugin_new (self, self->plugins_context, info,
113 : : G_CALLBACK (on_plugin_enabled_changed));
114 : 7 : g_hash_table_insert (self->plugins, info, plugin);
115 : :
116 [ + - ]: 7 : if (valent_plugin_get_enabled (plugin))
117 : 7 : valent_application_enable_plugin (self, plugin);
118 : : }
119 : :
120 : : static void
121 : 1 : on_unload_plugin (PeasEngine *engine,
122 : : PeasPluginInfo *info,
123 : : ValentApplication *self)
124 : : {
125 [ + - ]: 1 : g_assert (PEAS_IS_ENGINE (engine));
126 [ - + ]: 1 : g_assert (info != NULL);
127 [ - + ]: 1 : g_assert (VALENT_IS_APPLICATION (self));
128 : :
129 [ + - ]: 1 : if (!peas_engine_provides_extension (engine, info, VALENT_TYPE_APPLICATION_PLUGIN))
130 : : return;
131 : :
132 : 1 : g_hash_table_remove (self->plugins, info);
133 : : }
134 : :
135 : :
136 : : /*
137 : : * GActions
138 : : */
139 : : static void
140 : 1 : quit_action (GSimpleAction *action,
141 : : GVariant *parameter,
142 : : gpointer user_data)
143 : : {
144 : 1 : GApplication *application = G_APPLICATION (user_data);
145 : :
146 [ + - + - : 1 : g_assert (G_IS_APPLICATION (application));
+ - - + ]
147 : :
148 : 1 : g_application_quit (application);
149 : 1 : }
150 : :
151 : : static const GActionEntry app_actions[] = {
152 : : { "quit", quit_action, NULL, NULL, NULL },
153 : : };
154 : :
155 : :
156 : : /*
157 : : * GApplication
158 : : */
159 : : static void
160 : 3 : valent_application_activate (GApplication *application)
161 : : {
162 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
163 : 3 : GHashTableIter iter;
164 : 3 : ValentPlugin *plugin;
165 : :
166 [ + - ]: 3 : g_assert (VALENT_IS_APPLICATION (self));
167 : :
168 : 3 : g_hash_table_iter_init (&iter, self->plugins);
169 [ + - ]: 3 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
170 : : {
171 [ - + ]: 3 : if (plugin->extension == NULL)
172 : 0 : continue;
173 : :
174 [ + - ]: 3 : if (valent_application_plugin_activate (VALENT_APPLICATION_PLUGIN (plugin->extension)))
175 : 3 : return;
176 : : }
177 : :
178 : 0 : g_debug ("%s(): unhandled activation", G_STRFUNC);
179 : : }
180 : :
181 : : static void
182 : 1 : valent_application_open (GApplication *application,
183 : : GFile **files,
184 : : int n_files,
185 : : const char *hint)
186 : : {
187 : 1 : ValentApplication *self = VALENT_APPLICATION (application);
188 : 1 : GHashTableIter iter;
189 : 1 : ValentPlugin *plugin;
190 : :
191 [ + - ]: 1 : g_assert (VALENT_IS_APPLICATION (self));
192 : :
193 : 1 : g_hash_table_iter_init (&iter, self->plugins);
194 [ + - ]: 1 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
195 : : {
196 [ - + ]: 1 : if (plugin->extension == NULL)
197 : 0 : continue;
198 : :
199 [ + - ]: 1 : if (valent_application_plugin_open (VALENT_APPLICATION_PLUGIN (plugin->extension),
200 : : files,
201 : : n_files,
202 : : hint))
203 : 1 : return;
204 : : }
205 : :
206 : 0 : g_warning ("%s(): %i unhandled files", G_STRFUNC, n_files);
207 : : }
208 : :
209 : : static void
210 : 3 : valent_application_startup (GApplication *application)
211 : : {
212 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
213 : 3 : GHashTableIter iter;
214 : 3 : ValentPlugin *plugin;
215 : :
216 [ + - ]: 3 : g_assert (VALENT_IS_APPLICATION (application));
217 : :
218 : : /* Chain-up first */
219 : 3 : G_APPLICATION_CLASS (valent_application_parent_class)->startup (application);
220 : 3 : g_application_hold (application);
221 : :
222 : 3 : g_action_map_add_action_entries (G_ACTION_MAP (application),
223 : : app_actions,
224 : : G_N_ELEMENTS (app_actions),
225 : : application);
226 : :
227 : 3 : g_hash_table_iter_init (&iter, self->plugins);
228 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
229 : : {
230 [ - + ]: 6 : if (plugin->extension == NULL)
231 : 0 : continue;
232 : :
233 : 6 : valent_application_plugin_startup (VALENT_APPLICATION_PLUGIN (plugin->extension));
234 : : }
235 : 3 : }
236 : :
237 : : static void
238 : 3 : valent_application_shutdown (GApplication *application)
239 : : {
240 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
241 : 3 : GHashTableIter iter;
242 : 3 : ValentPlugin *plugin;
243 : :
244 : 3 : g_hash_table_iter_init (&iter, self->plugins);
245 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
246 : : {
247 [ - + ]: 6 : if (plugin->extension == NULL)
248 : 0 : continue;
249 : :
250 : 6 : valent_application_plugin_shutdown (VALENT_APPLICATION_PLUGIN (plugin->extension));
251 : : }
252 : :
253 : 3 : G_APPLICATION_CLASS (valent_application_parent_class)->shutdown (application);
254 : 3 : }
255 : :
256 : : static gboolean
257 : 3 : valent_application_dbus_register (GApplication *application,
258 : : GDBusConnection *connection,
259 : : const char *object_path,
260 : : GError **error)
261 : : {
262 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
263 : 3 : GApplicationClass *klass = G_APPLICATION_CLASS (valent_application_parent_class);
264 : 3 : GHashTableIter iter;
265 : 3 : ValentPlugin *plugin;
266 : :
267 : : /* Chain-up first */
268 [ - + ]: 3 : if (!klass->dbus_register (application, connection, object_path, error))
269 : : return FALSE;
270 : :
271 : 3 : g_hash_table_iter_init (&iter, self->plugins);
272 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
273 : : {
274 [ - + ]: 6 : if (plugin->extension == NULL)
275 : 0 : continue;
276 : :
277 [ - + ]: 6 : if (!valent_application_plugin_dbus_register (VALENT_APPLICATION_PLUGIN (plugin->extension),
278 : : connection,
279 : : object_path,
280 : : error))
281 : : return FALSE;
282 : : }
283 : :
284 : : return TRUE;
285 : : }
286 : :
287 : : static void
288 : 3 : valent_application_dbus_unregister (GApplication *application,
289 : : GDBusConnection *connection,
290 : : const char *object_path)
291 : : {
292 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
293 : 3 : GApplicationClass *klass = G_APPLICATION_CLASS (valent_application_parent_class);
294 : 3 : GHashTableIter iter;
295 : 3 : ValentPlugin *plugin;
296 : :
297 : 3 : g_hash_table_iter_init (&iter, self->plugins);
298 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
299 : : {
300 [ - + ]: 6 : if (plugin->extension == NULL)
301 : 0 : continue;
302 : :
303 : 6 : valent_application_plugin_dbus_unregister (VALENT_APPLICATION_PLUGIN (plugin->extension),
304 : : connection,
305 : : object_path);
306 : : }
307 : :
308 : : /* Chain-up last */
309 : 3 : klass->dbus_unregister (application, connection, object_path);
310 : 3 : }
311 : :
312 : :
313 : : /*
314 : : * GObject
315 : : */
316 : : static void
317 : 3 : valent_application_constructed (GObject *object)
318 : : {
319 : 3 : ValentApplication *self = VALENT_APPLICATION (object);
320 : 3 : PeasEngine *engine = NULL;
321 : 3 : unsigned int n_plugins = 0;
322 : :
323 : 3 : G_OBJECT_CLASS (valent_application_parent_class)->constructed (object);
324 : :
325 : 3 : engine = valent_get_plugin_engine ();
326 : 3 : g_signal_connect_object (engine,
327 : : "load-plugin",
328 : : G_CALLBACK (on_load_plugin),
329 : : self,
330 : : G_CONNECT_AFTER);
331 : :
332 : 3 : g_signal_connect_object (engine,
333 : : "unload-plugin",
334 : : G_CALLBACK (on_unload_plugin),
335 : : self,
336 : : G_CONNECT_DEFAULT);
337 : :
338 : 3 : n_plugins = g_list_model_get_n_items (G_LIST_MODEL (engine));
339 [ + + ]: 12 : for (unsigned int i = 0; i < n_plugins; i++)
340 : : {
341 : 9 : g_autoptr (PeasPluginInfo) info = NULL;
342 : :
343 : 9 : info = g_list_model_get_item (G_LIST_MODEL (engine), i);
344 [ + - ]: 9 : if (peas_plugin_info_is_loaded (info))
345 : 9 : on_load_plugin (engine, info, self);
346 : : }
347 : 3 : }
348 : :
349 : : static void
350 : 3 : valent_application_dispose (GObject *object)
351 : : {
352 : 3 : ValentApplication *self = VALENT_APPLICATION (object);
353 : :
354 : 3 : g_signal_handlers_disconnect_by_data (valent_get_plugin_engine (), self);
355 : 3 : g_hash_table_remove_all (self->plugins);
356 [ + - ]: 3 : g_clear_pointer (&self->plugins, g_hash_table_unref);
357 [ + - ]: 3 : g_clear_object (&self->plugins_context);
358 : :
359 : 3 : G_OBJECT_CLASS (valent_application_parent_class)->dispose (object);
360 : 3 : }
361 : :
362 : : static void
363 : 2 : valent_application_class_init (ValentApplicationClass *klass)
364 : : {
365 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
366 : 2 : GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
367 : :
368 : 2 : object_class->constructed = valent_application_constructed;
369 : 2 : object_class->dispose = valent_application_dispose;
370 : :
371 : 2 : application_class->activate = valent_application_activate;
372 : 2 : application_class->startup = valent_application_startup;
373 : 2 : application_class->shutdown = valent_application_shutdown;
374 : 2 : application_class->open = valent_application_open;
375 : 2 : application_class->dbus_register = valent_application_dbus_register;
376 : 2 : application_class->dbus_unregister = valent_application_dbus_unregister;
377 : : }
378 : :
379 : : static void
380 : 3 : valent_application_init (ValentApplication *self)
381 : : {
382 : 3 : self->plugins = g_hash_table_new_full (NULL, NULL, NULL, valent_plugin_free);
383 : 3 : self->plugins_context = valent_context_new (NULL, "application", NULL);
384 : 3 : }
385 : :
386 : : GApplication *
387 : 3 : _valent_application_new (void)
388 : : {
389 : 3 : return g_object_new (VALENT_TYPE_APPLICATION,
390 : : "application-id", APPLICATION_ID,
391 : : "resource-base-path", "/ca/andyholmes/Valent",
392 : : "flags", G_APPLICATION_HANDLES_OPEN,
393 : : NULL);
394 : : }
395 : :
|