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