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  * Copyright (C) 2012-2021 MATE Developers
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <glib.h>
28 #include <string.h>
29 
30 #include "gsm-app.h"
31 #include "gsm-app-glue.h"
32 
33 typedef struct {
34         char            *id;
35         char            *app_id;
36         int              phase;
37         char            *startup_id;
38         DBusGConnection *connection;
39 } GsmAppPrivate;
40 
41 enum {
42         EXITED,
43         DIED,
44         REGISTERED,
45         LAST_SIGNAL
46 };
47 
48 static guint32 app_serial = 1;
49 
50 static guint signals[LAST_SIGNAL] = { 0 };
51 
52 enum {
53         PROP_0,
54         PROP_ID,
55         PROP_STARTUP_ID,
56         PROP_PHASE,
57         LAST_PROP
58 };
59 
G_DEFINE_TYPE_WITH_PRIVATE(GsmApp,gsm_app,G_TYPE_OBJECT)60 G_DEFINE_TYPE_WITH_PRIVATE (GsmApp, gsm_app, G_TYPE_OBJECT)
61 
62 GQuark
63 gsm_app_error_quark (void)
64 {
65         static GQuark ret = 0;
66         if (ret == 0) {
67                 ret = g_quark_from_static_string ("gsm_app_error");
68         }
69 
70         return ret;
71 
72 }
73 
74 static guint32
get_next_app_serial(void)75 get_next_app_serial (void)
76 {
77         guint32 serial;
78 
79         serial = app_serial++;
80 
81         if ((gint32)app_serial < 0) {
82                 app_serial = 1;
83         }
84 
85         return serial;
86 }
87 
88 static gboolean
register_app(GsmApp * app)89 register_app (GsmApp *app)
90 {
91         GError *error;
92         GsmAppPrivate *priv;
93 
94         error = NULL;
95         priv = gsm_app_get_instance_private (app);
96 
97         priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
98         if (priv->connection == NULL) {
99                 if (error != NULL) {
100                         g_critical ("error getting session bus: %s", error->message);
101                         g_error_free (error);
102                 }
103                 return FALSE;
104         }
105 
106         dbus_g_connection_register_g_object (priv->connection, priv->id, G_OBJECT (app));
107 
108         return TRUE;
109 }
110 
111 static GObject *
gsm_app_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)112 gsm_app_constructor (GType                  type,
113                      guint                  n_construct_properties,
114                      GObjectConstructParam *construct_properties)
115 {
116         GsmApp    *app;
117         gboolean   res;
118         GsmAppPrivate *priv;
119 
120         app = GSM_APP (G_OBJECT_CLASS (gsm_app_parent_class)->constructor (type,
121                                                                            n_construct_properties,
122                                                                            construct_properties));
123         priv = gsm_app_get_instance_private (app);
124 
125         g_free (priv->id);
126         priv->id = g_strdup_printf ("/org/gnome/SessionManager/App%u", get_next_app_serial ());
127 
128         res = register_app (app);
129         if (! res) {
130                 g_warning ("Unable to register app with session bus");
131         }
132 
133         return G_OBJECT (app);
134 }
135 
136 static void
gsm_app_init(GsmApp * app)137 gsm_app_init (GsmApp *app)
138 {
139 }
140 
141 static void
gsm_app_set_phase(GsmApp * app,int phase)142 gsm_app_set_phase (GsmApp *app,
143                    int     phase)
144 {
145         GsmAppPrivate *priv;
146         g_return_if_fail (GSM_IS_APP (app));
147 
148         priv = gsm_app_get_instance_private (app);
149 
150         priv->phase = phase;
151 }
152 
153 static void
gsm_app_set_id(GsmApp * app,const char * id)154 gsm_app_set_id (GsmApp     *app,
155                 const char *id)
156 {
157         GsmAppPrivate *priv;
158         g_return_if_fail (GSM_IS_APP (app));
159 
160         priv = gsm_app_get_instance_private (app);
161 
162         g_free (priv->id);
163 
164         priv->id = g_strdup (id);
165         g_object_notify (G_OBJECT (app), "id");
166 
167 }
168 static void
gsm_app_set_startup_id(GsmApp * app,const char * startup_id)169 gsm_app_set_startup_id (GsmApp     *app,
170                         const char *startup_id)
171 {
172         GsmAppPrivate *priv;
173         g_return_if_fail (GSM_IS_APP (app));
174 
175         priv = gsm_app_get_instance_private (app);
176 
177         g_free (priv->startup_id);
178 
179         priv->startup_id = g_strdup (startup_id);
180         g_object_notify (G_OBJECT (app), "startup-id");
181 
182 }
183 
184 static void
gsm_app_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)185 gsm_app_set_property (GObject      *object,
186                       guint         prop_id,
187                       const GValue *value,
188                       GParamSpec   *pspec)
189 {
190         GsmApp *app = GSM_APP (object);
191 
192         switch (prop_id) {
193         case PROP_STARTUP_ID:
194                 gsm_app_set_startup_id (app, g_value_get_string (value));
195                 break;
196         case PROP_ID:
197                 gsm_app_set_id (app, g_value_get_string (value));
198                 break;
199         case PROP_PHASE:
200                 gsm_app_set_phase (app, g_value_get_int (value));
201                 break;
202         default:
203                 break;
204         }
205 }
206 
207 static void
gsm_app_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)208 gsm_app_get_property (GObject    *object,
209                       guint       prop_id,
210                       GValue     *value,
211                       GParamSpec *pspec)
212 {
213         GsmAppPrivate *priv;
214         GsmApp *app = GSM_APP (object);
215 
216         priv = gsm_app_get_instance_private (app);
217 
218         switch (prop_id) {
219         case PROP_STARTUP_ID:
220                 g_value_set_string (value, priv->startup_id);
221                 break;
222         case PROP_ID:
223                 g_value_set_string (value, priv->id);
224                 break;
225         case PROP_PHASE:
226                 g_value_set_int (value, priv->phase);
227                 break;
228         default:
229                 break;
230         }
231 }
232 
233 static void
gsm_app_dispose(GObject * object)234 gsm_app_dispose (GObject *object)
235 {
236         GsmAppPrivate *priv;
237         GsmApp *app = GSM_APP (object);
238 
239         priv = gsm_app_get_instance_private (app);
240 
241         g_free (priv->startup_id);
242         priv->startup_id = NULL;
243 
244         g_free (priv->id);
245         priv->id = NULL;
246 
247         G_OBJECT_CLASS (gsm_app_parent_class)->dispose (object);
248 }
249 
250 static void
gsm_app_class_init(GsmAppClass * klass)251 gsm_app_class_init (GsmAppClass *klass)
252 {
253         GObjectClass *object_class = G_OBJECT_CLASS (klass);
254 
255         object_class->set_property = gsm_app_set_property;
256         object_class->get_property = gsm_app_get_property;
257         object_class->dispose = gsm_app_dispose;
258         object_class->constructor = gsm_app_constructor;
259 
260         klass->impl_start = NULL;
261         klass->impl_get_app_id = NULL;
262         klass->impl_get_autorestart = NULL;
263         klass->impl_provides = NULL;
264         klass->impl_is_running = NULL;
265         klass->impl_peek_autostart_delay = NULL;
266 
267         g_object_class_install_property (object_class,
268                                          PROP_PHASE,
269                                          g_param_spec_int ("phase",
270                                                            "Phase",
271                                                            "Phase",
272                                                            -1,
273                                                            G_MAXINT,
274                                                            -1,
275                                                            G_PARAM_READWRITE));
276         g_object_class_install_property (object_class,
277                                          PROP_ID,
278                                          g_param_spec_string ("id",
279                                                               "ID",
280                                                               "ID",
281                                                               NULL,
282                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
283         g_object_class_install_property (object_class,
284                                          PROP_STARTUP_ID,
285                                          g_param_spec_string ("startup-id",
286                                                               "startup ID",
287                                                               "Session management startup ID",
288                                                               NULL,
289                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
290 
291         signals[EXITED] =
292                 g_signal_new ("exited",
293                               G_OBJECT_CLASS_TYPE (object_class),
294                               G_SIGNAL_RUN_LAST,
295                               G_STRUCT_OFFSET (GsmAppClass, exited),
296                               NULL, NULL,
297                               g_cclosure_marshal_VOID__VOID,
298                               G_TYPE_NONE,
299                               0);
300         signals[DIED] =
301                 g_signal_new ("died",
302                               G_OBJECT_CLASS_TYPE (object_class),
303                               G_SIGNAL_RUN_LAST,
304                               G_STRUCT_OFFSET (GsmAppClass, died),
305                               NULL, NULL,
306                               g_cclosure_marshal_VOID__VOID,
307                               G_TYPE_NONE,
308                               0);
309 
310         signals[REGISTERED] =
311                 g_signal_new ("registered",
312                               G_OBJECT_CLASS_TYPE (object_class),
313                               G_SIGNAL_RUN_LAST,
314                               G_STRUCT_OFFSET (GsmAppClass, registered),
315                               NULL, NULL,
316                               g_cclosure_marshal_VOID__VOID,
317                               G_TYPE_NONE,
318                               0);
319 
320         dbus_g_object_type_install_info (GSM_TYPE_APP, &dbus_glib_gsm_app_object_info);
321 }
322 
323 const char *
gsm_app_peek_id(GsmApp * app)324 gsm_app_peek_id (GsmApp *app)
325 {
326         GsmAppPrivate *priv;
327         priv = gsm_app_get_instance_private (app);
328 
329         return priv->id;
330 }
331 
332 const char *
gsm_app_peek_app_id(GsmApp * app)333 gsm_app_peek_app_id (GsmApp *app)
334 {
335         return GSM_APP_GET_CLASS (app)->impl_get_app_id (app);
336 }
337 
338 const char *
gsm_app_peek_startup_id(GsmApp * app)339 gsm_app_peek_startup_id (GsmApp *app)
340 {
341         GsmAppPrivate *priv;
342 
343         priv = gsm_app_get_instance_private (app);
344         return priv->startup_id;
345 }
346 
347 /**
348  * gsm_app_peek_phase:
349  * @app: a %GsmApp
350  *
351  * Returns @app's startup phase.
352  *
353  * Return value: @app's startup phase
354  **/
355 GsmManagerPhase
gsm_app_peek_phase(GsmApp * app)356 gsm_app_peek_phase (GsmApp *app)
357 {
358         GsmAppPrivate *priv;
359         g_return_val_if_fail (GSM_IS_APP (app), GSM_MANAGER_PHASE_APPLICATION);
360 
361         priv = gsm_app_get_instance_private (app);
362 
363         return priv->phase;
364 }
365 
366 gboolean
gsm_app_peek_is_disabled(GsmApp * app)367 gsm_app_peek_is_disabled (GsmApp *app)
368 {
369         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
370 
371         if (GSM_APP_GET_CLASS (app)->impl_is_disabled) {
372                 return GSM_APP_GET_CLASS (app)->impl_is_disabled (app);
373         } else {
374                 return FALSE;
375         }
376 }
377 
378 gboolean
gsm_app_peek_is_conditionally_disabled(GsmApp * app)379 gsm_app_peek_is_conditionally_disabled (GsmApp *app)
380 {
381         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
382 
383         if (GSM_APP_GET_CLASS (app)->impl_is_conditionally_disabled) {
384                 return GSM_APP_GET_CLASS (app)->impl_is_conditionally_disabled (app);
385         } else {
386                 return FALSE;
387         }
388 }
389 
390 gboolean
gsm_app_is_running(GsmApp * app)391 gsm_app_is_running (GsmApp *app)
392 {
393         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
394 
395         if (GSM_APP_GET_CLASS (app)->impl_is_running) {
396                 return GSM_APP_GET_CLASS (app)->impl_is_running (app);
397         } else {
398                 return FALSE;
399         }
400 }
401 
402 gboolean
gsm_app_peek_autorestart(GsmApp * app)403 gsm_app_peek_autorestart (GsmApp *app)
404 {
405         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
406 
407         if (GSM_APP_GET_CLASS (app)->impl_get_autorestart) {
408                 return GSM_APP_GET_CLASS (app)->impl_get_autorestart (app);
409         } else {
410                 return FALSE;
411         }
412 }
413 
414 gboolean
gsm_app_provides(GsmApp * app,const char * service)415 gsm_app_provides (GsmApp *app, const char *service)
416 {
417 
418         if (GSM_APP_GET_CLASS (app)->impl_provides) {
419                 return GSM_APP_GET_CLASS (app)->impl_provides (app, service);
420         } else {
421                 return FALSE;
422         }
423 }
424 
425 gboolean
gsm_app_has_autostart_condition(GsmApp * app,const char * condition)426 gsm_app_has_autostart_condition (GsmApp     *app,
427                                  const char *condition)
428 {
429 
430         if (GSM_APP_GET_CLASS (app)->impl_has_autostart_condition) {
431                 return GSM_APP_GET_CLASS (app)->impl_has_autostart_condition (app, condition);
432         } else {
433                 return FALSE;
434         }
435 }
436 
437 gboolean
gsm_app_start(GsmApp * app,GError ** error)438 gsm_app_start (GsmApp  *app,
439                GError **error)
440 {
441         GsmAppPrivate *priv;
442 
443         priv = gsm_app_get_instance_private (app);
444         g_debug ("Starting app: %s", priv->id);
445 
446         return GSM_APP_GET_CLASS (app)->impl_start (app, error);
447 }
448 
449 gboolean
gsm_app_restart(GsmApp * app,GError ** error)450 gsm_app_restart (GsmApp  *app,
451                  GError **error)
452 {
453         GsmAppPrivate *priv;
454 
455         priv = gsm_app_get_instance_private (app);
456 
457         g_debug ("Re-starting app: %s", priv->id);
458 
459         return GSM_APP_GET_CLASS (app)->impl_restart (app, error);
460 }
461 
462 gboolean
gsm_app_stop(GsmApp * app,GError ** error)463 gsm_app_stop (GsmApp  *app,
464               GError **error)
465 {
466         return GSM_APP_GET_CLASS (app)->impl_stop (app, error);
467 }
468 
469 void
gsm_app_registered(GsmApp * app)470 gsm_app_registered (GsmApp *app)
471 {
472         g_return_if_fail (GSM_IS_APP (app));
473 
474         g_signal_emit (app, signals[REGISTERED], 0);
475 }
476 
477 int
gsm_app_peek_autostart_delay(GsmApp * app)478 gsm_app_peek_autostart_delay (GsmApp *app)
479 {
480         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
481 
482         if (GSM_APP_GET_CLASS (app)->impl_peek_autostart_delay) {
483                 return GSM_APP_GET_CLASS (app)->impl_peek_autostart_delay (app);
484         } else {
485                 return 0;
486         }
487 }
488 
489 void
gsm_app_exited(GsmApp * app)490 gsm_app_exited (GsmApp *app)
491 {
492         g_return_if_fail (GSM_IS_APP (app));
493 
494         g_signal_emit (app, signals[EXITED], 0);
495 }
496 
497 void
gsm_app_died(GsmApp * app)498 gsm_app_died (GsmApp *app)
499 {
500         g_return_if_fail (GSM_IS_APP (app));
501 
502         g_signal_emit (app, signals[DIED], 0);
503 }
504 
505 gboolean
gsm_app_get_app_id(GsmApp * app,char ** id,GError ** error)506 gsm_app_get_app_id (GsmApp     *app,
507                     char      **id,
508                     GError    **error)
509 {
510         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
511         *id = g_strdup (GSM_APP_GET_CLASS (app)->impl_get_app_id (app));
512         return TRUE;
513 }
514 
515 gboolean
gsm_app_get_startup_id(GsmApp * app,char ** id,GError ** error)516 gsm_app_get_startup_id (GsmApp     *app,
517                         char      **id,
518                         GError    **error)
519 {
520         GsmAppPrivate *priv;
521         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
522 
523         priv = gsm_app_get_instance_private (app);
524         *id = g_strdup (priv->startup_id);
525         return TRUE;
526 }
527 
528 gboolean
gsm_app_get_phase(GsmApp * app,guint * phase,GError ** error)529 gsm_app_get_phase (GsmApp     *app,
530                    guint      *phase,
531                    GError    **error)
532 {
533         GsmAppPrivate *priv;
534         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
535 
536         priv = gsm_app_get_instance_private (app);
537         *phase = priv->phase;
538         return TRUE;
539 }
540