1 /*
2  * Copyright (C) 2018, Matthias Clasen
3  *
4  * This file is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation, version 3.0 of the
7  * License.
8  *
9  * This file is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * SPDX-License-Identifier: LGPL-3.0-only
18  */
19 
20 #include "config.h"
21 
22 #include "portal-helpers.h"
23 #include "portal-private.h"
24 #include "portal-enums.h"
25 
26 /**
27  * XdpPortal
28  *
29  * Context for portal calls.
30  *
31  * The XdpPortal object provides the main context object
32  * for the portal operations of libportal.
33  *
34  * Typically, an application will create a single XdpPortal
35  * object with [ctor@Portal.new] and use it throughout its lifetime.
36  */
37 
38 enum {
39   SPAWN_EXITED,
40   SESSION_STATE_CHANGED,
41   UPDATE_AVAILABLE,
42   UPDATE_PROGRESS,
43   LOCATION_UPDATED,
44   NOTIFICATION_ACTION_INVOKED,
45   LAST_SIGNAL
46 };
47 
48 static guint signals[LAST_SIGNAL];
49 
G_DEFINE_TYPE(XdpPortal,xdp_portal,G_TYPE_OBJECT)50 G_DEFINE_TYPE (XdpPortal, xdp_portal, G_TYPE_OBJECT)
51 
52 static void
53 xdp_portal_finalize (GObject *object)
54 {
55   XdpPortal *portal = XDP_PORTAL (object);
56 
57   /* inhibit */
58   if (portal->inhibit_handles)
59     g_hash_table_unref (portal->inhibit_handles);
60 
61   if (portal->state_changed_signal)
62     g_dbus_connection_signal_unsubscribe (portal->bus, portal->state_changed_signal);
63 
64   g_free (portal->session_monitor_handle);
65 
66   /* spawn */
67   if (portal->spawn_exited_signal)
68     g_dbus_connection_signal_unsubscribe (portal->bus, portal->spawn_exited_signal);
69 
70   /* updates */
71   if (portal->update_available_signal)
72     g_dbus_connection_signal_unsubscribe (portal->bus, portal->update_available_signal);
73   if (portal->update_progress_signal)
74     g_dbus_connection_signal_unsubscribe (portal->bus, portal->update_progress_signal);
75   g_free (portal->update_monitor_handle);
76 
77   /* location */
78   if (portal->location_updated_signal)
79     g_dbus_connection_signal_unsubscribe (portal->bus, portal->location_updated_signal);
80   g_free (portal->location_monitor_handle);
81 
82   /* notification */
83   if (portal->action_invoked_signal)
84     g_dbus_connection_signal_unsubscribe (portal->bus, portal->action_invoked_signal);
85 
86   g_clear_object (&portal->bus);
87   g_free (portal->sender);
88 
89   G_OBJECT_CLASS (xdp_portal_parent_class)->finalize (object);
90 }
91 
92 static void
xdp_portal_class_init(XdpPortalClass * klass)93 xdp_portal_class_init (XdpPortalClass *klass)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (klass);
96 
97   object_class->finalize = xdp_portal_finalize;
98 
99   /**
100    * XdpPortal::spawn-exited:
101    * @portal: the [class@Portal] object
102    * @pid: the pid of the process
103    * @exit_status: the exit status of the process
104    *
105    * This signal is emitted when a process that was spawned
106    * with [method@Portal.spawn] exits.
107    */
108   signals[SPAWN_EXITED] = g_signal_new ("spawn-exited",
109                                         G_TYPE_FROM_CLASS (object_class),
110                                         G_SIGNAL_RUN_FIRST,
111                                         0,
112                                         NULL, NULL,
113                                         NULL,
114                                         G_TYPE_NONE, 2,
115                                         G_TYPE_UINT,
116                                         G_TYPE_UINT);
117 
118   /**
119    * XdpPortal::session-state-changed:
120    * @portal: the [class@Portal] object
121    * @screensaver_active: whether the screensaver is active
122    * @session_state: the current state of the login session
123    *
124    * This signal is emitted when session state monitoring is
125    * enabled and the state of the login session changes or
126    * the screensaver is activated or deactivated.
127    */
128   signals[SESSION_STATE_CHANGED] = g_signal_new ("session-state-changed",
129                                                  G_TYPE_FROM_CLASS (object_class),
130                                                  G_SIGNAL_RUN_FIRST,
131                                                  0,
132                                                  NULL, NULL,
133                                                  NULL,
134                                                  G_TYPE_NONE, 2,
135                                                  G_TYPE_BOOLEAN,
136                                                  XDP_TYPE_LOGIN_SESSION_STATE);
137 
138   /**
139    * XdpPortal::update-available:
140    * @portal: the [class@Portal] object
141    * @running_commit: the commit that the sandbox is running with
142    * @local_commit: the commit that is currently deployed. Restarting
143    *     the app will use this commit
144    * @remote_commit: the commit that is available as an update.
145    *     Updating the app will deloy this commit
146    *
147    * This signal is emitted when updates monitoring is enabled
148    * and a new update is available. It is only sent once with
149    * the same information, but it can be sent many times if
150    * new updates appear.
151    */
152   signals[UPDATE_AVAILABLE] = g_signal_new ("update-available",
153                                             G_TYPE_FROM_CLASS (object_class),
154                                             G_SIGNAL_RUN_FIRST,
155                                             0,
156                                             NULL, NULL,
157                                             NULL,
158                                             G_TYPE_NONE, 3,
159                                             G_TYPE_STRING,
160                                             G_TYPE_STRING,
161                                             G_TYPE_STRING);
162 
163   /**
164    * XdpPortal::update-progress:
165    * @portal: the [class@Portal] object
166    * @n_ops: the number of operations that the update consists of
167    * @op: the position of the currently active operation
168    * @progress: the progress of the currently active operation, as
169    *   a number between 0 and 100
170    * @status: the overall status of the update
171    * @error: the error name if the status is 'failed'
172    * @error_message: the error message if the status is 'failed'
173    *
174    * This signal gets emitted to indicate progress of an
175    * update installation. It is undefined exactly how often it
176    * is sent, but it will be emitted at least once at the end with
177    * a non-zero @status. For each successful operation in the
178    * update, we're also guaranteed to send exactly one signal
179    * with @progress 100.
180    */
181   signals[UPDATE_PROGRESS] = g_signal_new ("update-progress",
182                                            G_TYPE_FROM_CLASS (object_class),
183                                            G_SIGNAL_RUN_FIRST,
184                                            0,
185                                            NULL, NULL,
186                                            NULL,
187                                            G_TYPE_NONE, 6,
188                                            G_TYPE_UINT,
189                                            G_TYPE_UINT,
190                                            G_TYPE_UINT,
191                                            XDP_TYPE_UPDATE_STATUS,
192                                            G_TYPE_STRING,
193                                            G_TYPE_STRING);
194 
195  /**
196    * XdpPortal::location-updated:
197    * @portal: the [class@Portal]
198    * @latitude: the latitude, in degrees
199    * @longitude: the longitude, in degrees
200    * @altitude: the altitude, in meters
201    * @accuracy: the accuracy, in meters
202    * @speed: the speed, in meters per second
203    * @heading: the heading, in degrees
204    * @description: the description
205    * @timestamp_s: the timestamp seconds since the Unix epoch
206    * @timestamp_ms: the microseconds fraction of the timestamp
207    *
208    * The ::location-updated signal is emitted when location
209    * monitoring is enabled and the location changes.
210    */
211   signals[LOCATION_UPDATED] =
212     g_signal_new ("location-updated",
213                   G_TYPE_FROM_CLASS (object_class),
214                   G_SIGNAL_RUN_FIRST,
215                   0,
216                   NULL, NULL,
217                   NULL,
218                   G_TYPE_NONE, 9,
219                   G_TYPE_DOUBLE,
220                   G_TYPE_DOUBLE,
221                   G_TYPE_DOUBLE,
222                   G_TYPE_DOUBLE,
223                   G_TYPE_DOUBLE,
224                   G_TYPE_DOUBLE,
225                   G_TYPE_STRING,
226                   G_TYPE_INT64,
227                   G_TYPE_INT64);
228 
229   /**
230    * XdpPortal::notification-action-invoked:
231    * @portal: the [class@Portal]
232    * @id: the notification ID
233    * @action: the action name
234    * @parameter: (nullable): the target parameter for the action
235    *
236    * The ::notification-action-invoked signal is emitted when
237    * a non-exported action is activated on a notification.
238    */
239   signals[NOTIFICATION_ACTION_INVOKED] =
240     g_signal_new ("notification-action-invoked",
241                   G_TYPE_FROM_CLASS (object_class),
242                   G_SIGNAL_RUN_FIRST,
243                   0,
244                   NULL, NULL,
245                   NULL,
246                   G_TYPE_NONE, 3,
247                   G_TYPE_STRING,
248                   G_TYPE_STRING,
249                   G_TYPE_VARIANT);
250 }
251 
252 static void
xdp_portal_init(XdpPortal * portal)253 xdp_portal_init (XdpPortal *portal)
254 {
255   int i;
256 
257   portal->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
258   portal->sender = g_strdup (g_dbus_connection_get_unique_name (portal->bus) + 1);
259   for (i = 0; portal->sender[i]; i++)
260     if (portal->sender[i] == '.')
261       portal->sender[i] = '_';
262 }
263 
264 /**
265  * xdp_portal_new:
266  *
267  * Creates a new [class@Portal] object.
268  *
269  * Returns: a newly created [class@Portal] object
270  */
271 XdpPortal *
xdp_portal_new(void)272 xdp_portal_new (void)
273 {
274   return g_object_new (XDP_TYPE_PORTAL, NULL);
275 }
276