1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2007 Novell, Inc.
4 * Copyright (C) 2008 Red Hat, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <config.h>
21
22 #include <ctype.h>
23 #include <string.h>
24 #include <sys/wait.h>
25 #include <errno.h>
26
27 #include <glib.h>
28 #include <gio/gio.h>
29 #include <gio/gdesktopappinfo.h>
30
31 #define GNOME_DESKTOP_USE_UNSTABLE_API
32 #include <libgnome-desktop/gnome-systemd.h>
33
34 #ifdef HAVE_SYSTEMD
35 #ifdef ENABLE_SYSTEMD_JOURNAL
36 #include <systemd/sd-journal.h>
37 #endif
38 #include <systemd/sd-daemon.h>
39 #endif
40
41 #include "gsm-autostart-app.h"
42 #include "gsm-util.h"
43
44 enum {
45 AUTOSTART_LAUNCH_SPAWN = 0,
46 AUTOSTART_LAUNCH_ACTIVATE
47 };
48
49 enum {
50 GSM_CONDITION_NONE = 0,
51 GSM_CONDITION_IF_EXISTS = 1,
52 GSM_CONDITION_UNLESS_EXISTS = 2,
53 GSM_CONDITION_GSETTINGS = 3,
54 GSM_CONDITION_IF_SESSION = 4,
55 GSM_CONDITION_UNLESS_SESSION = 5,
56 GSM_CONDITION_UNKNOWN = 6
57 };
58
59 #define GSM_SESSION_CLIENT_DBUS_INTERFACE "org.gnome.SessionClient"
60
61 struct _GsmAutostartAppPrivate {
62 gboolean mask_systemd;
63 char *desktop_filename;
64 char *desktop_id;
65 char *startup_id;
66
67 GDesktopAppInfo *app_info;
68 /* provides defined in session definition */
69 GSList *session_provides;
70
71 /* desktop file state */
72 char *condition_string;
73 gboolean condition;
74 gboolean autorestart;
75
76 GFileMonitor *condition_monitor;
77 guint condition_notify_id;
78 GSettings *condition_settings;
79
80 int launch_type;
81 GPid pid;
82 guint child_watch_id;
83 };
84
85 enum {
86 CONDITION_CHANGED,
87 LAST_SIGNAL
88 };
89
90 enum {
91 PROP_0,
92 PROP_DESKTOP_FILENAME,
93 PROP_MASK_SYSTEMD
94 };
95
96 static guint signals[LAST_SIGNAL] = { 0 };
97
98 #define GSM_AUTOSTART_APP_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSM_TYPE_AUTOSTART_APP, GsmAutostartAppPrivate))
99
100 static void gsm_autostart_app_initable_iface_init (GInitableIface *iface);
101
G_DEFINE_TYPE_WITH_CODE(GsmAutostartApp,gsm_autostart_app,GSM_TYPE_APP,G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,gsm_autostart_app_initable_iface_init))102 G_DEFINE_TYPE_WITH_CODE (GsmAutostartApp, gsm_autostart_app, GSM_TYPE_APP,
103 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gsm_autostart_app_initable_iface_init))
104
105 static void
106 gsm_autostart_app_init (GsmAutostartApp *app)
107 {
108 app->priv = GSM_AUTOSTART_APP_GET_PRIVATE (app);
109
110 app->priv->pid = -1;
111 app->priv->condition_monitor = NULL;
112 app->priv->condition = FALSE;
113 }
114
115 static gboolean
is_disabled(GsmApp * app)116 is_disabled (GsmApp *app)
117 {
118 GsmAutostartAppPrivate *priv;
119
120 priv = GSM_AUTOSTART_APP (app)->priv;
121
122 /* GSM_AUTOSTART_APP_ENABLED_KEY key, used by old gnome-session */
123 if (g_desktop_app_info_has_key (priv->app_info,
124 GSM_AUTOSTART_APP_ENABLED_KEY) &&
125 !g_desktop_app_info_get_boolean (priv->app_info,
126 GSM_AUTOSTART_APP_ENABLED_KEY)) {
127 g_debug ("app %s is disabled by " GSM_AUTOSTART_APP_ENABLED_KEY,
128 gsm_app_peek_id (app));
129 return TRUE;
130 }
131
132 /* Hidden key, used by autostart spec */
133 if (g_desktop_app_info_get_is_hidden (priv->app_info)) {
134 g_debug ("app %s is disabled by Hidden",
135 gsm_app_peek_id (app));
136 return TRUE;
137 }
138
139 /* Check OnlyShowIn/NotShowIn/TryExec */
140 if (!g_desktop_app_info_get_show_in (priv->app_info, NULL)) {
141 g_debug ("app %s is not for the current desktop",
142 gsm_app_peek_id (app));
143 return TRUE;
144 }
145
146 /* Check if app is systemd enabled and mask-systemd is set. */
147 if (priv->mask_systemd &&
148 g_desktop_app_info_has_key (priv->app_info,
149 GSM_AUTOSTART_APP_SYSTEMD_KEY) &&
150 g_desktop_app_info_get_boolean (priv->app_info,
151 GSM_AUTOSTART_APP_SYSTEMD_KEY)) {
152 g_debug ("app %s is disabled by " GSM_AUTOSTART_APP_SYSTEMD_KEY,
153 gsm_app_peek_id (app));
154 return TRUE;
155 }
156
157 /* Do not check AutostartCondition - this method is only to determine
158 if the app is unconditionally disabled */
159
160 return FALSE;
161 }
162
163 static gboolean
parse_condition_string(const char * condition_string,guint * condition_kindp,char ** keyp)164 parse_condition_string (const char *condition_string,
165 guint *condition_kindp,
166 char **keyp)
167 {
168 const char *space;
169 const char *key;
170 int len;
171 guint kind;
172
173 space = condition_string + strcspn (condition_string, " ");
174 len = space - condition_string;
175 key = space;
176 while (isspace ((unsigned char)*key)) {
177 key++;
178 }
179
180 kind = GSM_CONDITION_UNKNOWN;
181
182 if (!g_ascii_strncasecmp (condition_string, "if-exists", len) && key) {
183 kind = GSM_CONDITION_IF_EXISTS;
184 } else if (!g_ascii_strncasecmp (condition_string, "unless-exists", len) && key) {
185 kind = GSM_CONDITION_UNLESS_EXISTS;
186 } else if (!g_ascii_strncasecmp (condition_string, "GSettings", len)) {
187 kind = GSM_CONDITION_GSETTINGS;
188 } else if (!g_ascii_strncasecmp (condition_string, "GNOME3", len)) {
189 condition_string = key;
190 space = condition_string + strcspn (condition_string, " ");
191 len = space - condition_string;
192 key = space;
193 while (isspace ((unsigned char)*key)) {
194 key++;
195 }
196 if (!g_ascii_strncasecmp (condition_string, "if-session", len) && key) {
197 kind = GSM_CONDITION_IF_SESSION;
198 } else if (!g_ascii_strncasecmp (condition_string, "unless-session", len) && key) {
199 kind = GSM_CONDITION_UNLESS_SESSION;
200 }
201 }
202
203 if (kind == GSM_CONDITION_UNKNOWN) {
204 key = NULL;
205 }
206
207 if (keyp != NULL) {
208 *keyp = g_strdup (key);
209 }
210
211 if (condition_kindp != NULL) {
212 *condition_kindp = kind;
213 }
214
215 return (kind != GSM_CONDITION_UNKNOWN);
216 }
217
218 static void
if_exists_condition_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event,GsmApp * app)219 if_exists_condition_cb (GFileMonitor *monitor,
220 GFile *file,
221 GFile *other_file,
222 GFileMonitorEvent event,
223 GsmApp *app)
224 {
225 GsmAutostartAppPrivate *priv;
226 gboolean condition = FALSE;
227
228 priv = GSM_AUTOSTART_APP (app)->priv;
229
230 switch (event) {
231 case G_FILE_MONITOR_EVENT_CREATED:
232 condition = TRUE;
233 break;
234 case G_FILE_MONITOR_EVENT_DELETED:
235 condition = FALSE;
236 break;
237 default:
238 /* Ignore any other monitor event */
239 return;
240 }
241
242 /* Emit only if the condition actually changed */
243 if (condition != priv->condition) {
244 priv->condition = condition;
245 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
246 }
247 }
248
249 static void
unless_exists_condition_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event,GsmApp * app)250 unless_exists_condition_cb (GFileMonitor *monitor,
251 GFile *file,
252 GFile *other_file,
253 GFileMonitorEvent event,
254 GsmApp *app)
255 {
256 GsmAutostartAppPrivate *priv;
257 gboolean condition = FALSE;
258
259 priv = GSM_AUTOSTART_APP (app)->priv;
260
261 switch (event) {
262 case G_FILE_MONITOR_EVENT_CREATED:
263 condition = FALSE;
264 break;
265 case G_FILE_MONITOR_EVENT_DELETED:
266 condition = TRUE;
267 break;
268 default:
269 /* Ignore any other monitor event */
270 return;
271 }
272
273 /* Emit only if the condition actually changed */
274 if (condition != priv->condition) {
275 priv->condition = condition;
276 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
277 }
278 }
279
280 static void
gsettings_condition_cb(GSettings * settings,const char * key,gpointer user_data)281 gsettings_condition_cb (GSettings *settings,
282 const char *key,
283 gpointer user_data)
284 {
285 GsmApp *app;
286 GsmAutostartAppPrivate *priv;
287 gboolean condition;
288
289 g_return_if_fail (GSM_IS_APP (user_data));
290
291 app = GSM_APP (user_data);
292
293 priv = GSM_AUTOSTART_APP (app)->priv;
294
295 condition = g_settings_get_boolean (settings, key);
296
297 g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
298 gsm_app_peek_id (app),
299 condition);
300
301 /* Emit only if the condition actually changed */
302 if (condition != priv->condition) {
303 priv->condition = condition;
304 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
305 }
306 }
307
308 static gboolean
setup_gsettings_condition_monitor(GsmAutostartApp * app,const char * key)309 setup_gsettings_condition_monitor (GsmAutostartApp *app,
310 const char *key)
311 {
312 GSettingsSchemaSource *source;
313 GSettingsSchema *schema;
314 GSettings *settings;
315 GSettingsSchemaKey *schema_key;
316 const GVariantType *key_type;
317 char **elems;
318 gboolean retval = FALSE;
319 char *signal;
320
321 retval = FALSE;
322
323 schema = NULL;
324
325 elems = g_strsplit (key, " ", 2);
326
327 if (elems == NULL)
328 goto out;
329
330 if (elems[0] == NULL || elems[1] == NULL)
331 goto out;
332
333 source = g_settings_schema_source_get_default ();
334
335 schema = g_settings_schema_source_lookup (source, elems[0], TRUE);
336
337 if (schema == NULL)
338 goto out;
339
340 if (!g_settings_schema_has_key (schema, elems[1]))
341 goto out;
342
343 schema_key = g_settings_schema_get_key (schema, elems[1]);
344
345 g_assert (schema_key != NULL);
346
347 key_type = g_settings_schema_key_get_value_type (schema_key);
348
349 g_settings_schema_key_unref (schema_key);
350
351 g_assert (key_type != NULL);
352
353 if (!g_variant_type_equal (key_type, G_VARIANT_TYPE_BOOLEAN))
354 goto out;
355
356 settings = g_settings_new_full (schema, NULL, NULL);
357 retval = g_settings_get_boolean (settings, elems[1]);
358
359 signal = g_strdup_printf ("changed::%s", elems[1]);
360 g_signal_connect (G_OBJECT (settings), signal,
361 G_CALLBACK (gsettings_condition_cb), app);
362 g_free (signal);
363
364 app->priv->condition_settings = settings;
365
366 out:
367 if (schema)
368 g_settings_schema_unref (schema);
369 g_strfreev (elems);
370
371 return retval;
372 }
373
374 static void
if_session_condition_cb(GObject * object,GParamSpec * pspec,gpointer user_data)375 if_session_condition_cb (GObject *object,
376 GParamSpec *pspec,
377 gpointer user_data)
378 {
379 GsmApp *app;
380 GsmAutostartAppPrivate *priv;
381 char *session_name;
382 char *key;
383 gboolean condition;
384
385 g_return_if_fail (GSM_IS_APP (user_data));
386
387 app = GSM_APP (user_data);
388
389 priv = GSM_AUTOSTART_APP (app)->priv;
390
391 parse_condition_string (priv->condition_string, NULL, &key);
392
393 g_object_get (object, "session-name", &session_name, NULL);
394 condition = strcmp (session_name, key) == 0;
395 g_free (session_name);
396
397 g_free (key);
398
399 g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
400 gsm_app_peek_id (app),
401 condition);
402
403 /* Emit only if the condition actually changed */
404 if (condition != priv->condition) {
405 priv->condition = condition;
406 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
407 }
408 }
409
410 static void
unless_session_condition_cb(GObject * object,GParamSpec * pspec,gpointer user_data)411 unless_session_condition_cb (GObject *object,
412 GParamSpec *pspec,
413 gpointer user_data)
414 {
415 GsmApp *app;
416 GsmAutostartAppPrivate *priv;
417 char *session_name;
418 char *key;
419 gboolean condition;
420
421 g_return_if_fail (GSM_IS_APP (user_data));
422
423 app = GSM_APP (user_data);
424
425 priv = GSM_AUTOSTART_APP (app)->priv;
426
427 parse_condition_string (priv->condition_string, NULL, &key);
428
429 g_object_get (object, "session-name", &session_name, NULL);
430 condition = strcmp (session_name, key) != 0;
431 g_free (session_name);
432
433 g_free (key);
434
435 g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
436 gsm_app_peek_id (app),
437 condition);
438
439 /* Emit only if the condition actually changed */
440 if (condition != priv->condition) {
441 priv->condition = condition;
442 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
443 }
444 }
445
446 static char *
resolve_conditional_file_path(const char * file)447 resolve_conditional_file_path (const char *file)
448 {
449 if (g_path_is_absolute (file))
450 return g_strdup (file);
451 return g_build_filename (g_get_user_config_dir (), file, NULL);
452 }
453
454 static void
setup_condition_monitor(GsmAutostartApp * app)455 setup_condition_monitor (GsmAutostartApp *app)
456 {
457 guint kind;
458 char *key;
459 gboolean res;
460 gboolean disabled;
461
462 if (app->priv->condition_monitor != NULL) {
463 g_file_monitor_cancel (app->priv->condition_monitor);
464 }
465
466 if (app->priv->condition_string == NULL) {
467 return;
468 }
469
470 /* if it is disabled outright there is no point in monitoring */
471 if (is_disabled (GSM_APP (app))) {
472 return;
473 }
474
475 key = NULL;
476 res = parse_condition_string (app->priv->condition_string, &kind, &key);
477 if (! res) {
478 g_free (key);
479 return;
480 }
481
482 if (key == NULL) {
483 return;
484 }
485
486 if (kind == GSM_CONDITION_IF_EXISTS) {
487 char *file_path;
488 GFile *file;
489
490 file_path = resolve_conditional_file_path (key);
491 disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS);
492
493 file = g_file_new_for_path (file_path);
494 app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL);
495
496 g_signal_connect (app->priv->condition_monitor, "changed",
497 G_CALLBACK (if_exists_condition_cb),
498 app);
499
500 g_object_unref (file);
501 g_free (file_path);
502 } else if (kind == GSM_CONDITION_UNLESS_EXISTS) {
503 char *file_path;
504 GFile *file;
505
506 file_path = resolve_conditional_file_path (key);
507 disabled = g_file_test (file_path, G_FILE_TEST_EXISTS);
508
509 file = g_file_new_for_path (file_path);
510 app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL);
511
512 g_signal_connect (app->priv->condition_monitor, "changed",
513 G_CALLBACK (unless_exists_condition_cb),
514 app);
515
516 g_object_unref (file);
517 g_free (file_path);
518 } else if (kind == GSM_CONDITION_GSETTINGS) {
519 disabled = !setup_gsettings_condition_monitor (app, key);
520 } else if (kind == GSM_CONDITION_IF_SESSION) {
521 GsmManager *manager;
522 char *session_name;
523
524 /* get the singleton */
525 manager = gsm_manager_get ();
526
527 g_object_get (manager, "session-name", &session_name, NULL);
528 disabled = strcmp (session_name, key) != 0;
529
530 g_signal_connect (manager, "notify::session-name",
531 G_CALLBACK (if_session_condition_cb), app);
532 g_free (session_name);
533 } else if (kind == GSM_CONDITION_UNLESS_SESSION) {
534 GsmManager *manager;
535 char *session_name;
536
537 /* get the singleton */
538 manager = gsm_manager_get ();
539
540 g_object_get (manager, "session-name", &session_name, NULL);
541 disabled = strcmp (session_name, key) == 0;
542
543 g_signal_connect (manager, "notify::session-name",
544 G_CALLBACK (unless_session_condition_cb), app);
545 g_free (session_name);
546 } else {
547 disabled = TRUE;
548 }
549
550 g_free (key);
551
552 if (disabled) {
553 /* FIXME: cache the disabled value? */
554 }
555 }
556
557 static void
load_desktop_file(GsmAutostartApp * app)558 load_desktop_file (GsmAutostartApp *app)
559 {
560 char *dbus_name;
561 char *startup_id;
562 char *phase_str;
563 int phase;
564 gboolean res;
565
566 g_assert (app->priv->app_info != NULL);
567
568 phase_str = g_desktop_app_info_get_string (app->priv->app_info,
569 GSM_AUTOSTART_APP_PHASE_KEY);
570 if (phase_str != NULL) {
571 if (strcmp (phase_str, "EarlyInitialization") == 0) {
572 phase = GSM_MANAGER_PHASE_EARLY_INITIALIZATION;
573 } else if (strcmp (phase_str, "PreDisplayServer") == 0) {
574 phase = GSM_MANAGER_PHASE_PRE_DISPLAY_SERVER;
575 } else if (strcmp (phase_str, "DisplayServer") == 0) {
576 phase = GSM_MANAGER_PHASE_DISPLAY_SERVER;
577 } else if (strcmp (phase_str, "Initialization") == 0) {
578 phase = GSM_MANAGER_PHASE_INITIALIZATION;
579 } else if (strcmp (phase_str, "WindowManager") == 0) {
580 phase = GSM_MANAGER_PHASE_WINDOW_MANAGER;
581 } else if (strcmp (phase_str, "Panel") == 0) {
582 phase = GSM_MANAGER_PHASE_PANEL;
583 } else if (strcmp (phase_str, "Desktop") == 0) {
584 phase = GSM_MANAGER_PHASE_DESKTOP;
585 } else {
586 phase = GSM_MANAGER_PHASE_APPLICATION;
587 }
588
589 g_free (phase_str);
590 } else {
591 phase = GSM_MANAGER_PHASE_APPLICATION;
592 }
593
594 dbus_name = g_desktop_app_info_get_string (app->priv->app_info,
595 GSM_AUTOSTART_APP_DBUS_NAME_KEY);
596 if (dbus_name != NULL) {
597 app->priv->launch_type = AUTOSTART_LAUNCH_ACTIVATE;
598 } else {
599 app->priv->launch_type = AUTOSTART_LAUNCH_SPAWN;
600 }
601
602 /* this must only be done on first load */
603 switch (app->priv->launch_type) {
604 case AUTOSTART_LAUNCH_SPAWN:
605 startup_id =
606 g_desktop_app_info_get_string (app->priv->app_info,
607 GSM_AUTOSTART_APP_STARTUP_ID_KEY);
608
609 if (startup_id == NULL) {
610 startup_id = gsm_util_generate_startup_id ();
611 }
612 break;
613 case AUTOSTART_LAUNCH_ACTIVATE:
614 startup_id = g_strdup (dbus_name);
615 break;
616 default:
617 g_assert_not_reached ();
618 }
619
620 res = g_desktop_app_info_has_key (app->priv->app_info,
621 GSM_AUTOSTART_APP_AUTORESTART_KEY);
622 if (res) {
623 app->priv->autorestart = g_desktop_app_info_get_boolean (app->priv->app_info,
624 GSM_AUTOSTART_APP_AUTORESTART_KEY);
625 } else {
626 app->priv->autorestart = FALSE;
627 }
628
629 g_free (app->priv->condition_string);
630 app->priv->condition_string = g_desktop_app_info_get_string (app->priv->app_info,
631 "AutostartCondition");
632 setup_condition_monitor (app);
633
634 g_object_set (app,
635 "phase", phase,
636 "startup-id", startup_id,
637 NULL);
638
639 g_free (startup_id);
640 g_free (dbus_name);
641 }
642
643 static void
gsm_autostart_app_set_desktop_filename(GsmAutostartApp * app,const char * desktop_filename)644 gsm_autostart_app_set_desktop_filename (GsmAutostartApp *app,
645 const char *desktop_filename)
646 {
647 if (app->priv->app_info != NULL) {
648 g_clear_object (&app->priv->app_info);
649 g_clear_pointer (&app->priv->desktop_filename, g_free);
650 g_clear_pointer (&app->priv->desktop_id, g_free);
651 }
652
653 if (desktop_filename == NULL) {
654 return;
655 }
656
657 app->priv->desktop_filename = g_strdup (desktop_filename);
658 app->priv->desktop_id = g_path_get_basename (desktop_filename);
659 }
660
661 static void
gsm_autostart_app_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)662 gsm_autostart_app_set_property (GObject *object,
663 guint prop_id,
664 const GValue *value,
665 GParamSpec *pspec)
666 {
667 GsmAutostartApp *self;
668
669 self = GSM_AUTOSTART_APP (object);
670
671 switch (prop_id) {
672 case PROP_DESKTOP_FILENAME:
673 gsm_autostart_app_set_desktop_filename (self, g_value_get_string (value));
674 break;
675 case PROP_MASK_SYSTEMD:
676 self->priv->mask_systemd = g_value_get_boolean (value);
677 break;
678 default:
679 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
680 break;
681 }
682 }
683
684 static void
gsm_autostart_app_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)685 gsm_autostart_app_get_property (GObject *object,
686 guint prop_id,
687 GValue *value,
688 GParamSpec *pspec)
689 {
690 GsmAutostartApp *self;
691
692 self = GSM_AUTOSTART_APP (object);
693
694 switch (prop_id) {
695 case PROP_DESKTOP_FILENAME:
696 if (self->priv->app_info != NULL) {
697 g_value_set_string (value, g_desktop_app_info_get_filename (self->priv->app_info));
698 } else {
699 g_value_set_string (value, NULL);
700 }
701 break;
702 case PROP_MASK_SYSTEMD:
703 g_value_set_boolean (value, self->priv->mask_systemd);
704 break;
705 default:
706 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
707 break;
708 }
709 }
710
711 static void
gsm_autostart_app_dispose(GObject * object)712 gsm_autostart_app_dispose (GObject *object)
713 {
714 GsmAutostartAppPrivate *priv;
715
716 priv = GSM_AUTOSTART_APP (object)->priv;
717
718 g_clear_pointer (&priv->startup_id, g_free);
719
720 if (priv->session_provides) {
721 g_slist_free_full (priv->session_provides, g_free);
722 priv->session_provides = NULL;
723 }
724
725 g_clear_pointer (&priv->condition_string, g_free);
726 g_clear_object (&priv->condition_settings);
727 g_clear_object (&priv->app_info);
728 g_clear_pointer (&priv->desktop_filename, g_free);
729 g_clear_pointer (&priv->desktop_id, g_free);
730
731 if (priv->child_watch_id > 0) {
732 g_source_remove (priv->child_watch_id);
733 priv->child_watch_id = 0;
734 }
735
736 if (priv->condition_monitor) {
737 g_file_monitor_cancel (priv->condition_monitor);
738 }
739
740 G_OBJECT_CLASS (gsm_autostart_app_parent_class)->dispose (object);
741 }
742
743 static gboolean
is_running(GsmApp * app)744 is_running (GsmApp *app)
745 {
746 GsmAutostartAppPrivate *priv;
747 gboolean is;
748
749 priv = GSM_AUTOSTART_APP (app)->priv;
750
751 /* is running if pid is still valid or
752 * or a client is connected
753 */
754 /* FIXME: check client */
755 is = (priv->pid != -1);
756
757 return is;
758 }
759
760 static gboolean
is_conditionally_disabled(GsmApp * app)761 is_conditionally_disabled (GsmApp *app)
762 {
763 GsmAutostartAppPrivate *priv;
764 gboolean res;
765 gboolean disabled;
766 char *key;
767 guint kind;
768
769 priv = GSM_AUTOSTART_APP (app)->priv;
770
771 /* Check AutostartCondition */
772 if (priv->condition_string == NULL) {
773 return FALSE;
774 }
775
776 key = NULL;
777 res = parse_condition_string (priv->condition_string, &kind, &key);
778 if (! res) {
779 g_free (key);
780 return TRUE;
781 }
782
783 if (key == NULL) {
784 return TRUE;
785 }
786
787 if (kind == GSM_CONDITION_IF_EXISTS) {
788 char *file_path;
789
790 file_path = resolve_conditional_file_path (key);
791 disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS);
792 g_free (file_path);
793 } else if (kind == GSM_CONDITION_UNLESS_EXISTS) {
794 char *file_path;
795
796 file_path = resolve_conditional_file_path (key);
797 disabled = g_file_test (file_path, G_FILE_TEST_EXISTS);
798 g_free (file_path);
799 } else if (kind == GSM_CONDITION_GSETTINGS &&
800 priv->condition_settings != NULL) {
801 char **elems;
802 elems = g_strsplit (key, " ", 2);
803 disabled = !g_settings_get_boolean (priv->condition_settings, elems[1]);
804 g_strfreev (elems);
805 } else if (kind == GSM_CONDITION_IF_SESSION) {
806 GsmManager *manager;
807 char *session_name;
808
809 /* get the singleton */
810 manager = gsm_manager_get ();
811
812 g_object_get (manager, "session-name", &session_name, NULL);
813 disabled = strcmp (session_name, key) != 0;
814 g_free (session_name);
815 } else if (kind == GSM_CONDITION_UNLESS_SESSION) {
816 GsmManager *manager;
817 char *session_name;
818
819 /* get the singleton */
820 manager = gsm_manager_get ();
821
822 g_object_get (manager, "session-name", &session_name, NULL);
823 disabled = strcmp (session_name, key) == 0;
824 g_free (session_name);
825 } else {
826 disabled = TRUE;
827 }
828
829 /* Set initial condition */
830 priv->condition = !disabled;
831
832 g_free (key);
833
834 return disabled;
835 }
836
837 static void
app_exited(GPid pid,int status,GsmAutostartApp * app)838 app_exited (GPid pid,
839 int status,
840 GsmAutostartApp *app)
841 {
842 g_debug ("GsmAutostartApp: (pid:%d) done (%s:%d)",
843 (int) pid,
844 WIFEXITED (status) ? "status"
845 : WIFSIGNALED (status) ? "signal"
846 : "unknown",
847 WIFEXITED (status) ? WEXITSTATUS (status)
848 : WIFSIGNALED (status) ? WTERMSIG (status)
849 : -1);
850
851 g_spawn_close_pid (app->priv->pid);
852 app->priv->pid = -1;
853 app->priv->child_watch_id = 0;
854
855 if (WIFEXITED (status)) {
856 gsm_app_exited (GSM_APP (app), WEXITSTATUS (status));
857 } else if (WIFSIGNALED (status)) {
858 gsm_app_died (GSM_APP (app), WTERMSIG (status));
859 }
860 }
861
862 static int
_signal_pid(int pid,int signal)863 _signal_pid (int pid,
864 int signal)
865 {
866 int status;
867
868 /* perhaps block sigchld */
869 g_debug ("GsmAutostartApp: sending signal %d to process %d", signal, pid);
870 errno = 0;
871 status = kill (pid, signal);
872
873 if (status < 0) {
874 if (errno == ESRCH) {
875 g_warning ("Child process %d was already dead.",
876 (int)pid);
877 } else {
878 g_warning ("Couldn't kill child process %d: %s",
879 pid,
880 g_strerror (errno));
881 }
882 }
883
884 /* perhaps unblock sigchld */
885
886 return status;
887 }
888
889 static gboolean
autostart_app_stop_spawn(GsmAutostartApp * app,GError ** error)890 autostart_app_stop_spawn (GsmAutostartApp *app,
891 GError **error)
892 {
893 int res;
894
895 if (app->priv->pid < 1) {
896 g_set_error (error,
897 GSM_APP_ERROR,
898 GSM_APP_ERROR_STOP,
899 "Not running");
900 return FALSE;
901 }
902
903 res = _signal_pid (app->priv->pid, SIGTERM);
904 if (res != 0) {
905 g_set_error (error,
906 GSM_APP_ERROR,
907 GSM_APP_ERROR_STOP,
908 "Unable to stop: %s",
909 g_strerror (errno));
910 return FALSE;
911 }
912
913 return TRUE;
914 }
915
916 static gboolean
autostart_app_stop_activate(GsmAutostartApp * app,GError ** error)917 autostart_app_stop_activate (GsmAutostartApp *app,
918 GError **error)
919 {
920 return TRUE;
921 }
922
923 static gboolean
gsm_autostart_app_stop(GsmApp * app,GError ** error)924 gsm_autostart_app_stop (GsmApp *app,
925 GError **error)
926 {
927 GsmAutostartApp *aapp;
928 gboolean ret;
929
930 aapp = GSM_AUTOSTART_APP (app);
931
932 g_return_val_if_fail (aapp->priv->app_info != NULL, FALSE);
933
934 switch (aapp->priv->launch_type) {
935 case AUTOSTART_LAUNCH_SPAWN:
936 ret = autostart_app_stop_spawn (aapp, error);
937 break;
938 case AUTOSTART_LAUNCH_ACTIVATE:
939 ret = autostart_app_stop_activate (aapp, error);
940 break;
941 default:
942 g_assert_not_reached ();
943 break;
944 }
945
946 return ret;
947 }
948
949 static void
app_launched(GAppLaunchContext * ctx,GAppInfo * appinfo,GVariant * platform_data,gpointer data)950 app_launched (GAppLaunchContext *ctx,
951 GAppInfo *appinfo,
952 GVariant *platform_data,
953 gpointer data)
954 {
955 GsmAutostartApp *app = data;
956 gint pid;
957 gchar *sn_id;
958
959 pid = 0;
960 sn_id = NULL;
961
962 g_variant_lookup (platform_data, "pid", "i", &pid);
963 g_variant_lookup (platform_data, "startup-notification-id", "s", &sn_id);
964 app->priv->pid = pid;
965 app->priv->startup_id = sn_id;
966
967 /* We are not interested in the result. */
968 gnome_start_systemd_scope (app->priv->desktop_id,
969 pid,
970 NULL,
971 NULL,
972 NULL, NULL, NULL);
973 }
974
975 #ifdef ENABLE_SYSTEMD_JOURNAL
976 static void
on_child_setup(GsmAutostartApp * app)977 on_child_setup (GsmAutostartApp *app)
978 {
979 int standard_output, standard_error;
980
981 /* The FALSE means programs aren't expected to prefix each
982 * line with <n> prefix to specify priority.
983 */
984 standard_output = sd_journal_stream_fd (app->priv->desktop_id,
985 LOG_INFO,
986 FALSE);
987 standard_error = sd_journal_stream_fd (app->priv->desktop_id,
988 LOG_WARNING,
989 FALSE);
990
991 if (standard_output >= 0) {
992 dup2 (standard_output, STDOUT_FILENO);
993 close (standard_output);
994 }
995
996 if (standard_error >= 0) {
997 dup2 (standard_error, STDERR_FILENO);
998 close (standard_error);
999 }
1000 }
1001 #endif
1002
1003 static gboolean
autostart_app_start_spawn(GsmAutostartApp * app,GError ** error)1004 autostart_app_start_spawn (GsmAutostartApp *app,
1005 GError **error)
1006 {
1007 gboolean success;
1008 GError *local_error;
1009 const char *startup_id;
1010 const char * const *variable_blacklist;
1011 const char * const *child_environment;
1012 int i;
1013 GAppLaunchContext *ctx;
1014 GSpawnChildSetupFunc child_setup_func = NULL;
1015 gpointer child_setup_data = NULL;
1016 guint handler;
1017
1018 startup_id = gsm_app_peek_startup_id (GSM_APP (app));
1019 g_assert (startup_id != NULL);
1020
1021 g_debug ("GsmAutostartApp: starting %s: command=%s startup-id=%s", app->priv->desktop_id, g_app_info_get_commandline (G_APP_INFO (app->priv->app_info)), startup_id);
1022
1023 g_free (app->priv->startup_id);
1024 local_error = NULL;
1025 ctx = g_app_launch_context_new ();
1026
1027 variable_blacklist = gsm_util_get_variable_blacklist ();
1028 for (i = 0; variable_blacklist[i] != NULL; i++)
1029 g_app_launch_context_unsetenv (ctx, variable_blacklist[i]);
1030
1031 child_environment = gsm_util_listenv ();
1032 for (i = 0; child_environment[i] != NULL; i++) {
1033 char **environment_tuple;
1034 const char *key;
1035 const char *value;
1036
1037 environment_tuple = g_strsplit (child_environment[i], "=", 2);
1038 key = environment_tuple[0];
1039 value = environment_tuple[1];
1040
1041 if (value != NULL)
1042 g_app_launch_context_setenv (ctx, key, value);
1043
1044 g_strfreev (environment_tuple);
1045 }
1046
1047 if (startup_id != NULL) {
1048 g_app_launch_context_setenv (ctx, "DESKTOP_AUTOSTART_ID", startup_id);
1049 }
1050
1051 #ifdef ENABLE_SYSTEMD_JOURNAL
1052 if (sd_booted () > 0) {
1053 child_setup_func = (GSpawnChildSetupFunc) on_child_setup;
1054 child_setup_data = app;
1055 }
1056 #endif
1057
1058 handler = g_signal_connect (ctx, "launched", G_CALLBACK (app_launched), app);
1059 success = g_desktop_app_info_launch_uris_as_manager (app->priv->app_info,
1060 NULL,
1061 ctx,
1062 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
1063 child_setup_func, child_setup_data,
1064 NULL, NULL,
1065 &local_error);
1066 g_signal_handler_disconnect (ctx, handler);
1067
1068 if (success) {
1069 if (app->priv->pid > 0) {
1070 g_debug ("GsmAutostartApp: started pid:%d", app->priv->pid);
1071 app->priv->child_watch_id = g_child_watch_add (app->priv->pid,
1072 (GChildWatchFunc)app_exited,
1073 app);
1074 }
1075 } else {
1076 g_set_error (error,
1077 GSM_APP_ERROR,
1078 GSM_APP_ERROR_START,
1079 "Unable to start application: %s", local_error->message);
1080 g_error_free (local_error);
1081 }
1082
1083 return success;
1084 }
1085
1086 static void
start_notify(GObject * source,GAsyncResult * result,gpointer user_data)1087 start_notify (GObject *source,
1088 GAsyncResult *result,
1089 gpointer user_data)
1090 {
1091 GError *error;
1092 GsmAutostartApp *app;
1093
1094 app = user_data;
1095 error = NULL;
1096
1097 g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
1098
1099 if (error != NULL) {
1100 g_warning ("GsmAutostartApp: Error starting application: %s", error->message);
1101 g_error_free (error);
1102 } else {
1103 g_debug ("GsmAutostartApp: Started application %s", app->priv->desktop_id);
1104 }
1105 }
1106
1107 static gboolean
autostart_app_start_activate(GsmAutostartApp * app,GError ** error)1108 autostart_app_start_activate (GsmAutostartApp *app,
1109 GError **error)
1110 {
1111 const char *name;
1112 char *path;
1113 char *arguments;
1114 GDBusConnection *bus;
1115 GError *local_error;
1116
1117 local_error = NULL;
1118 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
1119 if (local_error != NULL) {
1120 g_warning ("error getting session bus: %s", local_error->message);
1121 g_propagate_error (error, local_error);
1122 return FALSE;
1123 }
1124
1125 name = gsm_app_peek_startup_id (GSM_APP (app));
1126 g_assert (name != NULL);
1127
1128 path = g_desktop_app_info_get_string (app->priv->app_info,
1129 GSM_AUTOSTART_APP_DBUS_PATH_KEY);
1130 if (path == NULL) {
1131 /* just pick one? */
1132 path = g_strdup ("/");
1133 }
1134
1135 arguments = g_desktop_app_info_get_string (app->priv->app_info,
1136 GSM_AUTOSTART_APP_DBUS_ARGS_KEY);
1137
1138 g_dbus_connection_call (bus,
1139 name,
1140 path,
1141 GSM_SESSION_CLIENT_DBUS_INTERFACE,
1142 "Start",
1143 g_variant_new ("(s)", arguments),
1144 NULL,
1145 G_DBUS_CALL_FLAGS_NONE,
1146 -1, NULL,
1147 start_notify, app);
1148 g_object_unref (bus);
1149
1150 return TRUE;
1151 }
1152
1153 static gboolean
gsm_autostart_app_start(GsmApp * app,GError ** error)1154 gsm_autostart_app_start (GsmApp *app,
1155 GError **error)
1156 {
1157 GsmAutostartApp *aapp;
1158 gboolean ret;
1159
1160 aapp = GSM_AUTOSTART_APP (app);
1161
1162 g_return_val_if_fail (aapp->priv->app_info != NULL, FALSE);
1163
1164 switch (aapp->priv->launch_type) {
1165 case AUTOSTART_LAUNCH_SPAWN:
1166 ret = autostart_app_start_spawn (aapp, error);
1167 break;
1168 case AUTOSTART_LAUNCH_ACTIVATE:
1169 ret = autostart_app_start_activate (aapp, error);
1170 break;
1171 default:
1172 g_assert_not_reached ();
1173 break;
1174 }
1175
1176 return ret;
1177 }
1178
1179 static gboolean
gsm_autostart_app_restart(GsmApp * app,GError ** error)1180 gsm_autostart_app_restart (GsmApp *app,
1181 GError **error)
1182 {
1183 GError *local_error;
1184 gboolean res;
1185
1186 /* ignore stop errors - it is fine if it is already stopped */
1187 local_error = NULL;
1188 res = gsm_app_stop (app, &local_error);
1189 if (! res) {
1190 g_debug ("GsmAutostartApp: Couldn't stop app: %s", local_error->message);
1191 g_error_free (local_error);
1192 }
1193
1194 res = gsm_app_start (app, &local_error);
1195 if (! res) {
1196 g_propagate_error (error, local_error);
1197 return FALSE;
1198 }
1199
1200 return TRUE;
1201 }
1202
1203 static gboolean
gsm_autostart_app_provides(GsmApp * app,const char * service)1204 gsm_autostart_app_provides (GsmApp *app,
1205 const char *service)
1206 {
1207 gchar *provides_str;
1208 char **provides;
1209 gsize i;
1210 GSList *l;
1211 GsmAutostartApp *aapp;
1212
1213 g_return_val_if_fail (GSM_IS_APP (app), FALSE);
1214
1215 aapp = GSM_AUTOSTART_APP (app);
1216
1217 if (aapp->priv->app_info == NULL) {
1218 return FALSE;
1219 }
1220
1221 for (l = aapp->priv->session_provides; l != NULL; l = l->next) {
1222 if (!strcmp (l->data, service))
1223 return TRUE;
1224 }
1225
1226 provides_str = g_desktop_app_info_get_string (aapp->priv->app_info,
1227 GSM_AUTOSTART_APP_PROVIDES_KEY);
1228 if (!provides_str) {
1229 return FALSE;
1230 }
1231 provides = g_strsplit (provides_str, ";", -1);
1232 g_free (provides_str);
1233
1234 for (i = 0; provides[i]; i++) {
1235 if (!strcmp (provides[i], service)) {
1236 g_strfreev (provides);
1237 return TRUE;
1238 }
1239 }
1240
1241 g_strfreev (provides);
1242
1243 return FALSE;
1244 }
1245
1246 static char **
gsm_autostart_app_get_provides(GsmApp * app)1247 gsm_autostart_app_get_provides (GsmApp *app)
1248 {
1249 GsmAutostartApp *aapp;
1250 gchar *provides_str;
1251 char **provides;
1252 gsize provides_len;
1253 char **result;
1254 gsize result_len;
1255 int i;
1256 GSList *l;
1257
1258 g_return_val_if_fail (GSM_IS_APP (app), NULL);
1259
1260 aapp = GSM_AUTOSTART_APP (app);
1261
1262 if (aapp->priv->app_info == NULL) {
1263 return NULL;
1264 }
1265
1266 provides_str = g_desktop_app_info_get_string (aapp->priv->app_info,
1267 GSM_AUTOSTART_APP_PROVIDES_KEY);
1268
1269 if (provides_str == NULL) {
1270 return NULL;
1271 }
1272
1273 provides = g_strsplit (provides_str, ";", -1);
1274 provides_len = g_strv_length (provides);
1275 g_free (provides_str);
1276
1277 if (!aapp->priv->session_provides) {
1278 return provides;
1279 }
1280
1281 result_len = provides_len + g_slist_length (aapp->priv->session_provides);
1282 result = g_new (char *, result_len + 1); /* including last NULL */
1283
1284 for (i = 0; provides[i] != NULL; i++)
1285 result[i] = provides[i];
1286 g_free (provides);
1287
1288 for (l = aapp->priv->session_provides; l != NULL; l = l->next, i++)
1289 result[i] = g_strdup (l->data);
1290
1291 result[i] = NULL;
1292
1293 g_assert (i == result_len);
1294
1295 return result;
1296 }
1297
1298 void
gsm_autostart_app_add_provides(GsmAutostartApp * aapp,const char * provides)1299 gsm_autostart_app_add_provides (GsmAutostartApp *aapp,
1300 const char *provides)
1301 {
1302 g_return_if_fail (GSM_IS_AUTOSTART_APP (aapp));
1303
1304 aapp->priv->session_provides = g_slist_prepend (aapp->priv->session_provides,
1305 g_strdup (provides));
1306 }
1307
1308 static gboolean
gsm_autostart_app_has_autostart_condition(GsmApp * app,const char * condition)1309 gsm_autostart_app_has_autostart_condition (GsmApp *app,
1310 const char *condition)
1311 {
1312 GsmAutostartApp *aapp;
1313
1314 g_return_val_if_fail (GSM_IS_APP (app), FALSE);
1315 g_return_val_if_fail (condition != NULL, FALSE);
1316
1317 aapp = GSM_AUTOSTART_APP (app);
1318
1319 if (aapp->priv->condition_string == NULL) {
1320 return FALSE;
1321 }
1322
1323 if (strcmp (aapp->priv->condition_string, condition) == 0) {
1324 return TRUE;
1325 }
1326
1327 return FALSE;
1328 }
1329
1330 static gboolean
gsm_autostart_app_get_autorestart(GsmApp * app)1331 gsm_autostart_app_get_autorestart (GsmApp *app)
1332 {
1333 gboolean res;
1334 gboolean autorestart;
1335
1336 if (GSM_AUTOSTART_APP (app)->priv->app_info == NULL) {
1337 return FALSE;
1338 }
1339
1340 autorestart = FALSE;
1341
1342 res = g_desktop_app_info_has_key (GSM_AUTOSTART_APP (app)->priv->app_info,
1343 GSM_AUTOSTART_APP_AUTORESTART_KEY);
1344 if (res) {
1345 autorestart = g_desktop_app_info_get_boolean (GSM_AUTOSTART_APP (app)->priv->app_info,
1346 GSM_AUTOSTART_APP_AUTORESTART_KEY);
1347 }
1348
1349 return autorestart;
1350 }
1351
1352 static const char *
gsm_autostart_app_get_app_id(GsmApp * app)1353 gsm_autostart_app_get_app_id (GsmApp *app)
1354 {
1355 if (GSM_AUTOSTART_APP (app)->priv->app_info == NULL) {
1356 return NULL;
1357 }
1358
1359 return g_app_info_get_id (G_APP_INFO (GSM_AUTOSTART_APP (app)->priv->app_info));
1360 }
1361
1362 static gboolean
gsm_autostart_app_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)1363 gsm_autostart_app_initable_init (GInitable *initable,
1364 GCancellable *cancellable,
1365 GError **error)
1366 {
1367 GsmAutostartApp *app = GSM_AUTOSTART_APP (initable);
1368
1369 g_assert (app->priv->desktop_filename != NULL);
1370 app->priv->app_info = g_desktop_app_info_new_from_filename (app->priv->desktop_filename);
1371 if (app->priv->app_info == NULL) {
1372 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1373 "Could not parse desktop file %s or it references a not found TryExec binary", app->priv->desktop_id);
1374 return FALSE;
1375 }
1376
1377 load_desktop_file (app);
1378
1379 return TRUE;
1380 }
1381
1382 static gboolean
gsm_autostart_app_save_to_keyfile(GsmApp * base_app,GKeyFile * keyfile,GError ** error)1383 gsm_autostart_app_save_to_keyfile (GsmApp *base_app,
1384 GKeyFile *keyfile,
1385 GError **error)
1386 {
1387 GsmAutostartApp *app = GSM_AUTOSTART_APP (base_app);
1388 char **provides = NULL;
1389 char *dbus_name;
1390 char *phase;
1391 gboolean res;
1392
1393 provides = gsm_app_get_provides (base_app);
1394 if (provides != NULL) {
1395 g_key_file_set_string_list (keyfile,
1396 G_KEY_FILE_DESKTOP_GROUP,
1397 GSM_AUTOSTART_APP_PROVIDES_KEY,
1398 (const char * const *)
1399 provides,
1400 g_strv_length (provides));
1401 g_strfreev (provides);
1402 }
1403
1404 phase = g_desktop_app_info_get_string (app->priv->app_info,
1405 GSM_AUTOSTART_APP_PHASE_KEY);
1406 if (phase != NULL) {
1407 g_key_file_set_string (keyfile,
1408 G_KEY_FILE_DESKTOP_GROUP,
1409 GSM_AUTOSTART_APP_PHASE_KEY,
1410 phase);
1411 g_free (phase);
1412 }
1413
1414 dbus_name = g_desktop_app_info_get_string (app->priv->app_info,
1415 GSM_AUTOSTART_APP_DBUS_NAME_KEY);
1416 if (dbus_name != NULL) {
1417 g_key_file_set_string (keyfile,
1418 G_KEY_FILE_DESKTOP_GROUP,
1419 GSM_AUTOSTART_APP_DBUS_NAME_KEY,
1420 dbus_name);
1421 g_free (dbus_name);
1422 }
1423
1424 res = g_desktop_app_info_has_key (app->priv->app_info,
1425 GSM_AUTOSTART_APP_AUTORESTART_KEY);
1426 if (res) {
1427 g_key_file_set_boolean (keyfile,
1428 G_KEY_FILE_DESKTOP_GROUP,
1429 GSM_AUTOSTART_APP_AUTORESTART_KEY,
1430 g_desktop_app_info_get_boolean (app->priv->app_info,
1431 GSM_AUTOSTART_APP_AUTORESTART_KEY));
1432 }
1433
1434 res = g_desktop_app_info_has_key (app->priv->app_info,
1435 GSM_AUTOSTART_APP_AUTORESTART_KEY);
1436 if (res) {
1437 char *autostart_condition;
1438
1439 autostart_condition = g_desktop_app_info_get_string (app->priv->app_info, "AutostartCondition");
1440
1441 g_key_file_set_string (keyfile,
1442 G_KEY_FILE_DESKTOP_GROUP,
1443 "AutostartCondition",
1444 autostart_condition);
1445 g_free (autostart_condition);
1446 }
1447
1448 return TRUE;
1449 }
1450
1451 static void
gsm_autostart_app_initable_iface_init(GInitableIface * iface)1452 gsm_autostart_app_initable_iface_init (GInitableIface *iface)
1453 {
1454 iface->init = gsm_autostart_app_initable_init;
1455 }
1456
1457 static void
gsm_autostart_app_class_init(GsmAutostartAppClass * klass)1458 gsm_autostart_app_class_init (GsmAutostartAppClass *klass)
1459 {
1460 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1461 GsmAppClass *app_class = GSM_APP_CLASS (klass);
1462
1463 object_class->set_property = gsm_autostart_app_set_property;
1464 object_class->get_property = gsm_autostart_app_get_property;
1465 object_class->dispose = gsm_autostart_app_dispose;
1466
1467 app_class->impl_is_disabled = is_disabled;
1468 app_class->impl_is_conditionally_disabled = is_conditionally_disabled;
1469 app_class->impl_is_running = is_running;
1470 app_class->impl_start = gsm_autostart_app_start;
1471 app_class->impl_restart = gsm_autostart_app_restart;
1472 app_class->impl_stop = gsm_autostart_app_stop;
1473 app_class->impl_provides = gsm_autostart_app_provides;
1474 app_class->impl_get_provides = gsm_autostart_app_get_provides;
1475 app_class->impl_has_autostart_condition = gsm_autostart_app_has_autostart_condition;
1476 app_class->impl_get_app_id = gsm_autostart_app_get_app_id;
1477 app_class->impl_get_autorestart = gsm_autostart_app_get_autorestart;
1478 app_class->impl_save_to_keyfile = gsm_autostart_app_save_to_keyfile;
1479
1480 g_object_class_install_property (object_class,
1481 PROP_DESKTOP_FILENAME,
1482 g_param_spec_string ("desktop-filename",
1483 "Desktop filename",
1484 "Freedesktop .desktop file",
1485 NULL,
1486 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1487 g_object_class_install_property (object_class,
1488 PROP_MASK_SYSTEMD,
1489 g_param_spec_boolean ("mask-systemd",
1490 "Mask if systemd started",
1491 "Mask if GNOME systemd flag is set in desktop file",
1492 FALSE,
1493 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1494 signals[CONDITION_CHANGED] =
1495 g_signal_new ("condition-changed",
1496 G_OBJECT_CLASS_TYPE (object_class),
1497 G_SIGNAL_RUN_LAST,
1498 G_STRUCT_OFFSET (GsmAutostartAppClass, condition_changed),
1499 NULL, NULL, NULL,
1500 G_TYPE_NONE,
1501 1,
1502 G_TYPE_BOOLEAN);
1503
1504 g_type_class_add_private (object_class, sizeof (GsmAutostartAppPrivate));
1505 }
1506
1507 GsmApp *
gsm_autostart_app_new(const char * desktop_file,gboolean mask_systemd,GError ** error)1508 gsm_autostart_app_new (const char *desktop_file,
1509 gboolean mask_systemd,
1510 GError **error)
1511 {
1512 return (GsmApp*) g_initable_new (GSM_TYPE_AUTOSTART_APP, NULL, error,
1513 "desktop-filename", desktop_file,
1514 "mask-systemd", mask_systemd,
1515 NULL);
1516 }
1517