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