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