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