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