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 : g_clear_object (&plugin->extension);
76 : 1 : }
77 : :
78 : : static void
79 : 2 : on_plugin_enabled_changed (ValentPlugin *plugin)
80 : : {
81 [ + - ]: 2 : g_assert (plugin != NULL);
82 [ - + ]: 2 : g_assert (VALENT_IS_APPLICATION (plugin->parent));
83 : :
84 [ + + ]: 2 : if (valent_plugin_get_enabled (plugin))
85 : 1 : valent_application_enable_plugin (plugin->parent, plugin);
86 : : else
87 : 1 : valent_application_disable_plugin (plugin->parent, plugin);
88 : 2 : }
89 : :
90 : : static void
91 : 10 : on_load_plugin (PeasEngine *engine,
92 : : PeasPluginInfo *info,
93 : : ValentApplication *self)
94 : : {
95 : 10 : ValentPlugin *plugin = NULL;
96 : :
97 [ + - ]: 10 : g_assert (PEAS_IS_ENGINE (engine));
98 [ - + ]: 10 : g_assert (info != NULL);
99 [ - + ]: 10 : g_assert (VALENT_IS_APPLICATION (self));
100 : :
101 [ + + ]: 10 : if (!peas_engine_provides_extension (engine, info, VALENT_TYPE_APPLICATION_PLUGIN))
102 : : return;
103 : :
104 : 7 : VALENT_NOTE ("%s: %s",
105 : : g_type_name (VALENT_TYPE_APPLICATION_PLUGIN),
106 : : peas_plugin_info_get_module_name (info));
107 : :
108 : 7 : plugin = valent_plugin_new (self, self->plugins_context, info,
109 : : G_CALLBACK (on_plugin_enabled_changed));
110 : 7 : g_hash_table_insert (self->plugins, info, plugin);
111 : :
112 [ + - ]: 7 : if (valent_plugin_get_enabled (plugin))
113 : 7 : valent_application_enable_plugin (self, plugin);
114 : : }
115 : :
116 : : static void
117 : 1 : on_unload_plugin (PeasEngine *engine,
118 : : PeasPluginInfo *info,
119 : : ValentApplication *self)
120 : : {
121 [ + - ]: 1 : g_assert (PEAS_IS_ENGINE (engine));
122 [ - + ]: 1 : g_assert (info != NULL);
123 [ - + ]: 1 : g_assert (VALENT_IS_APPLICATION (self));
124 : :
125 [ + - ]: 1 : if (!peas_engine_provides_extension (engine, info, VALENT_TYPE_APPLICATION_PLUGIN))
126 : : return;
127 : :
128 : 1 : g_hash_table_remove (self->plugins, info);
129 : : }
130 : :
131 : :
132 : : /*
133 : : * GActions
134 : : */
135 : : static void
136 : 1 : quit_action (GSimpleAction *action,
137 : : GVariant *parameter,
138 : : gpointer user_data)
139 : : {
140 : 1 : GApplication *application = G_APPLICATION (user_data);
141 : :
142 [ + - + - : 1 : g_assert (G_IS_APPLICATION (application));
+ - - + ]
143 : :
144 : 1 : g_application_quit (application);
145 : 1 : }
146 : :
147 : : static const GActionEntry app_actions[] = {
148 : : { "quit", quit_action, NULL, NULL, NULL },
149 : : };
150 : :
151 : :
152 : : /*
153 : : * GApplication
154 : : */
155 : : static void
156 : 3 : valent_application_activate (GApplication *application)
157 : : {
158 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
159 : 3 : GHashTableIter iter;
160 : 3 : ValentPlugin *plugin;
161 : :
162 [ + - ]: 3 : g_assert (VALENT_IS_APPLICATION (self));
163 : :
164 : 3 : g_hash_table_iter_init (&iter, self->plugins);
165 : :
166 [ + - ]: 3 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
167 : : {
168 [ - + ]: 3 : if (plugin->extension == NULL)
169 : 0 : continue;
170 : :
171 [ + - ]: 3 : if (valent_application_plugin_activate (VALENT_APPLICATION_PLUGIN (plugin->extension)))
172 : 3 : return;
173 : : }
174 : :
175 : 0 : g_debug ("%s(): unhandled activation", G_STRFUNC);
176 : : }
177 : :
178 : : static void
179 : 1 : valent_application_open (GApplication *application,
180 : : GFile **files,
181 : : int n_files,
182 : : const char *hint)
183 : : {
184 : 1 : ValentApplication *self = VALENT_APPLICATION (application);
185 : 1 : GHashTableIter iter;
186 : 1 : ValentPlugin *plugin;
187 : :
188 [ + - ]: 1 : g_assert (VALENT_IS_APPLICATION (self));
189 : :
190 : 1 : g_hash_table_iter_init (&iter, self->plugins);
191 : :
192 [ + - ]: 1 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
193 : : {
194 [ - + ]: 1 : if (plugin->extension == NULL)
195 : 0 : continue;
196 : :
197 [ + - ]: 1 : if (valent_application_plugin_open (VALENT_APPLICATION_PLUGIN (plugin->extension),
198 : : files,
199 : : n_files,
200 : : hint))
201 : 1 : return;
202 : : }
203 : :
204 : : /* If no plugin takes ownership of the files, print a warning. */
205 : 0 : g_warning ("%s(): %i unhandled files", G_STRFUNC, n_files);
206 : : }
207 : :
208 : : static void
209 : 3 : valent_application_startup (GApplication *application)
210 : : {
211 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
212 : 3 : GHashTableIter iter;
213 : 3 : ValentPlugin *plugin;
214 : :
215 [ + - ]: 3 : g_assert (VALENT_IS_APPLICATION (application));
216 : :
217 : : /* Chain-up first */
218 : 3 : G_APPLICATION_CLASS (valent_application_parent_class)->startup (application);
219 : 3 : g_application_hold (application);
220 : :
221 : 3 : g_action_map_add_action_entries (G_ACTION_MAP (application),
222 : : app_actions,
223 : : G_N_ELEMENTS (app_actions),
224 : : application);
225 : :
226 : 3 : g_hash_table_iter_init (&iter, self->plugins);
227 : :
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 : :
246 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
247 : : {
248 [ - + ]: 6 : if (plugin->extension == NULL)
249 : 0 : continue;
250 : :
251 : 6 : valent_application_plugin_shutdown (VALENT_APPLICATION_PLUGIN (plugin->extension));
252 : : }
253 : :
254 : 3 : G_APPLICATION_CLASS (valent_application_parent_class)->shutdown (application);
255 : 3 : }
256 : :
257 : : static gboolean
258 : 3 : valent_application_dbus_register (GApplication *application,
259 : : GDBusConnection *connection,
260 : : const char *object_path,
261 : : GError **error)
262 : : {
263 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
264 : 3 : GApplicationClass *klass = G_APPLICATION_CLASS (valent_application_parent_class);
265 : 3 : GHashTableIter iter;
266 : 3 : ValentPlugin *plugin;
267 : :
268 : : /* Chain-up first */
269 [ - + ]: 3 : if (!klass->dbus_register (application, connection, object_path, error))
270 : : return FALSE;
271 : :
272 : 3 : g_hash_table_iter_init (&iter, self->plugins);
273 : :
274 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
275 : : {
276 [ - + ]: 6 : if (plugin->extension == NULL)
277 : 0 : continue;
278 : :
279 [ - + ]: 6 : if (!valent_application_plugin_dbus_register (VALENT_APPLICATION_PLUGIN (plugin->extension),
280 : : connection,
281 : : object_path,
282 : : error))
283 : : return FALSE;
284 : : }
285 : :
286 : : return TRUE;
287 : : }
288 : :
289 : : static void
290 : 3 : valent_application_dbus_unregister (GApplication *application,
291 : : GDBusConnection *connection,
292 : : const char *object_path)
293 : : {
294 : 3 : ValentApplication *self = VALENT_APPLICATION (application);
295 : 3 : GApplicationClass *klass = G_APPLICATION_CLASS (valent_application_parent_class);
296 : 3 : GHashTableIter iter;
297 : 3 : ValentPlugin *plugin;
298 : :
299 : 3 : g_hash_table_iter_init (&iter, self->plugins);
300 : :
301 [ + + ]: 9 : while (g_hash_table_iter_next (&iter, NULL, (void **)&plugin))
302 : : {
303 [ - + ]: 6 : if (plugin->extension == NULL)
304 : 0 : continue;
305 : :
306 : 6 : valent_application_plugin_dbus_unregister (VALENT_APPLICATION_PLUGIN (plugin->extension),
307 : : connection,
308 : : object_path);
309 : : }
310 : :
311 : : /* Chain-up last */
312 : 3 : klass->dbus_unregister (application, connection, object_path);
313 : 3 : }
314 : :
315 : :
316 : : /*
317 : : * GObject
318 : : */
319 : : static void
320 : 3 : valent_application_constructed (GObject *object)
321 : : {
322 : 3 : ValentApplication *self = VALENT_APPLICATION (object);
323 : 3 : PeasEngine *engine = NULL;
324 : 3 : unsigned int n_plugins = 0;
325 : :
326 : 3 : G_OBJECT_CLASS (valent_application_parent_class)->constructed (object);
327 : :
328 : 3 : self->plugins = g_hash_table_new_full (NULL, NULL, NULL, valent_plugin_free);
329 : 3 : self->plugins_context = valent_context_new (NULL, "application", NULL);
330 : :
331 : 3 : engine = valent_get_plugin_engine ();
332 : 3 : n_plugins = g_list_model_get_n_items (G_LIST_MODEL (engine));
333 : :
334 [ + + ]: 12 : for (unsigned int i = 0; i < n_plugins; i++)
335 : : {
336 : 9 : g_autoptr (PeasPluginInfo) info = NULL;
337 : :
338 : 9 : info = g_list_model_get_item (G_LIST_MODEL (engine), i);
339 : :
340 [ + - ]: 9 : if (peas_plugin_info_is_loaded (info))
341 : 9 : on_load_plugin (engine, info, self);
342 : : }
343 : :
344 : 3 : g_signal_connect_object (engine,
345 : : "load-plugin",
346 : : G_CALLBACK (on_load_plugin),
347 : : self,
348 : : G_CONNECT_AFTER);
349 : :
350 : 3 : g_signal_connect_object (engine,
351 : : "unload-plugin",
352 : : G_CALLBACK (on_unload_plugin),
353 : : self,
354 : : 0);
355 : 3 : }
356 : :
357 : : static void
358 : 3 : valent_application_dispose (GObject *object)
359 : : {
360 : 3 : ValentApplication *self = VALENT_APPLICATION (object);
361 : 3 : PeasEngine *engine = NULL;
362 : :
363 : 3 : engine = valent_get_plugin_engine ();
364 : 3 : g_signal_handlers_disconnect_by_data (engine, self);
365 : :
366 : 3 : g_hash_table_remove_all (self->plugins);
367 [ + - ]: 3 : g_clear_pointer (&self->plugins, g_hash_table_unref);
368 [ + - ]: 3 : g_clear_object (&self->plugins_context);
369 : :
370 : 3 : G_OBJECT_CLASS (valent_application_parent_class)->dispose (object);
371 : 3 : }
372 : :
373 : : static void
374 : 2 : valent_application_class_init (ValentApplicationClass *klass)
375 : : {
376 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
377 : 2 : GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
378 : :
379 : 2 : object_class->constructed = valent_application_constructed;
380 : 2 : object_class->dispose = valent_application_dispose;
381 : :
382 : 2 : application_class->activate = valent_application_activate;
383 : 2 : application_class->startup = valent_application_startup;
384 : 2 : application_class->shutdown = valent_application_shutdown;
385 : 2 : application_class->open = valent_application_open;
386 : 2 : application_class->dbus_register = valent_application_dbus_register;
387 : 2 : application_class->dbus_unregister = valent_application_dbus_unregister;
388 : : }
389 : :
390 : : static void
391 : 3 : valent_application_init (ValentApplication *self)
392 : : {
393 : 3 : }
394 : :
395 : : GApplication *
396 : 3 : _valent_application_new (void)
397 : : {
398 : 3 : return g_object_new (VALENT_TYPE_APPLICATION,
399 : : "application-id", APPLICATION_ID,
400 : : "resource-base-path", "/ca/andyholmes/Valent",
401 : : "flags", G_APPLICATION_HANDLES_OPEN,
402 : : NULL);
403 : : }
404 : :
|