Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-findmyphone-plugin"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <glib/gi18n.h>
10 : : #include <gst/gst.h>
11 : :
12 : : #include "valent-findmyphone-ringer.h"
13 : :
14 : :
15 : : struct _ValentFindmyphoneRinger
16 : : {
17 : : GActionGroup *actions;
18 : : GNotification *notification;
19 : : GstElement *playbin;
20 : : unsigned int source_id;
21 : : gpointer owner;
22 : : };
23 : :
24 : : static ValentFindmyphoneRinger *default_ringer = NULL;
25 : :
26 : :
27 : : static gboolean
28 : 0 : ringer_source_func (GstBus *bus,
29 : : GstMessage *message,
30 : : gpointer user_data)
31 : : {
32 : 0 : ValentFindmyphoneRinger *ringer = user_data;
33 : :
34 [ # # ]: 0 : if (message->type == GST_MESSAGE_ERROR)
35 : : {
36 : 0 : g_autoptr (GError) error = NULL;
37 [ # # ]: 0 : g_autofree char *debug = NULL;
38 : :
39 : 0 : gst_message_parse_error (message, &error, &debug);
40 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
41 [ # # ]: 0 : g_debug ("%s: %s", G_STRFUNC, (debug) ? debug : "none");
42 : :
43 : 0 : return G_SOURCE_REMOVE;
44 : : }
45 : :
46 : : /* Rewind to beginning */
47 [ # # ]: 0 : if (message->type == GST_MESSAGE_EOS)
48 : : {
49 : 0 : return gst_element_seek_simple (ringer->playbin,
50 : : GST_FORMAT_TIME,
51 : : GST_SEEK_FLAG_FLUSH,
52 : : 0);
53 : : }
54 : :
55 : : return G_SOURCE_CONTINUE;
56 : : }
57 : :
58 : : static inline void
59 : 0 : app_ringer_action (GSimpleAction *action,
60 : : GVariant *parameters,
61 : : gpointer user_data)
62 : : {
63 : 0 : ValentFindmyphoneRinger *self = (ValentFindmyphoneRinger *)user_data;
64 : :
65 [ # # ]: 0 : g_assert (self != NULL);
66 : :
67 : 0 : valent_findmyphone_ringer_toggle (self, NULL);
68 : 0 : }
69 : :
70 : : static const GActionEntry app_actions[] = {
71 : : { "ringer", app_ringer_action, NULL, NULL, NULL },
72 : : };
73 : :
74 : : static void
75 : 4 : valent_findmyphone_ringer_free (gpointer data)
76 : : {
77 : 4 : ValentFindmyphoneRinger *ringer = data;
78 : :
79 [ - + ]: 4 : if (ringer->notification != NULL)
80 : : {
81 : 0 : GApplication *application = g_application_get_default ();
82 : :
83 : 0 : g_action_map_remove_action (G_ACTION_MAP (application), "ringer");
84 : 0 : g_application_withdraw_notification (application, "findmyphone::ringer");
85 [ # # ]: 0 : g_clear_object (&ringer->notification);
86 : : }
87 : :
88 [ - + ]: 4 : if (ringer->playbin != NULL)
89 : : {
90 : 0 : gst_element_set_state (ringer->playbin, GST_STATE_NULL);
91 [ # # ]: 0 : gst_clear_object (&ringer->playbin);
92 : : }
93 : :
94 : 4 : default_ringer = NULL;
95 : 4 : }
96 : :
97 : : /**
98 : : * valent_findmyphone_ringer_new:
99 : : *
100 : : * Create a new `ValentFindmyphoneRinger`.
101 : : *
102 : : * Returns: (transfer full): a `ValentFindmyphoneRinger`
103 : : */
104 : : ValentFindmyphoneRinger *
105 : 4 : valent_findmyphone_ringer_new (void)
106 : : {
107 : 4 : GApplication *application = g_application_get_default ();
108 : 4 : ValentFindmyphoneRinger *ringer;
109 : 8 : g_autoptr (GError) error = NULL;
110 : :
111 : 4 : ringer = g_rc_box_new0 (ValentFindmyphoneRinger);
112 : :
113 : : /* Notification
114 : : */
115 [ - + ]: 4 : if (application != NULL)
116 : : {
117 : 4 : g_autoptr (GIcon) icon = NULL;
118 : :
119 : 0 : g_action_map_add_action_entries (G_ACTION_MAP (application),
120 : : app_actions,
121 : : G_N_ELEMENTS (app_actions),
122 : : ringer);
123 : 0 : icon = g_icon_new_for_string ("phonelink-ring-symbolic", NULL);
124 : :
125 : 0 : ringer->notification = g_notification_new (_("Find My Device"));
126 : 0 : g_notification_set_icon (ringer->notification, icon);
127 : 0 : g_notification_set_priority (ringer->notification,
128 : : G_NOTIFICATION_PRIORITY_URGENT);
129 [ # # ]: 0 : g_notification_set_default_action (ringer->notification, "app.ringer");
130 : : }
131 : :
132 : : /* Playbin
133 : : */
134 [ - + ]: 4 : if (!gst_init_check (NULL, NULL, &error))
135 : : {
136 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
137 : 0 : return ringer;
138 : : }
139 : :
140 : 4 : ringer->playbin = gst_element_factory_make ("playbin", "findmyphone-ringer");
141 [ - + ]: 4 : if (ringer->playbin != NULL)
142 : : {
143 : 0 : gst_object_ref_sink (ringer->playbin);
144 : 0 : g_object_set (ringer->playbin,
145 : : "uri", "resource:///plugins/findmyphone/alert.oga",
146 : : NULL);
147 : : }
148 : :
149 : : return ringer;
150 : : }
151 : :
152 : : /**
153 : : * valent_findmyphone_ringer_start:
154 : : * @ringer: a `ValentFindmyphoneRinger`
155 : : *
156 : : * Enable the ringing state of @ringer.
157 : : */
158 : : void
159 : 0 : valent_findmyphone_ringer_start (ValentFindmyphoneRinger *ringer)
160 : : {
161 : 0 : g_autoptr (GstBus) playbus = NULL;
162 : :
163 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
164 : :
165 [ # # # # ]: 0 : if (ringer->playbin == NULL || ringer->source_id > 0)
166 : : return;
167 : :
168 : 0 : playbus = gst_element_get_bus (ringer->playbin);
169 : 0 : ringer->source_id = gst_bus_add_watch (playbus, ringer_source_func, ringer);
170 : :
171 [ # # ]: 0 : if (gst_element_set_state (ringer->playbin, GST_STATE_PLAYING) == 0)
172 [ # # # # ]: 0 : g_clear_handle_id (&ringer->source_id, g_source_remove);
173 : : }
174 : :
175 : : /**
176 : : * valent_findmyphone_ringer_stop:
177 : : * @ringer: a `ValentFindmyphoneRinger`
178 : : *
179 : : * Disable the ringing state of @ringer.
180 : : */
181 : : void
182 : 0 : valent_findmyphone_ringer_stop (ValentFindmyphoneRinger *ringer)
183 : : {
184 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
185 : :
186 [ # # # # ]: 0 : if (ringer->playbin == NULL || ringer->source_id == 0)
187 : : return;
188 : :
189 : 0 : gst_element_set_state (ringer->playbin, GST_STATE_NULL);
190 [ # # ]: 0 : g_clear_handle_id (&ringer->source_id, g_source_remove);
191 : 0 : ringer->owner = NULL;
192 : : }
193 : :
194 : : /**
195 : : * valent_findmyphone_ringer_show:
196 : : * @ringer: a `ValentFindmyphoneRinger`
197 : : *
198 : : * Enable the ringing state of @ringer and show a dialog.
199 : : */
200 : : void
201 : 0 : valent_findmyphone_ringer_show (ValentFindmyphoneRinger *ringer)
202 : : {
203 : 0 : GApplication *application = g_application_get_default ();
204 : :
205 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
206 : :
207 : 0 : valent_findmyphone_ringer_start (ringer);
208 [ # # ]: 0 : if (application != NULL)
209 : : {
210 : 0 : g_application_send_notification (application,
211 : : "findmyphone::ringer",
212 : : ringer->notification);
213 : : }
214 : : }
215 : :
216 : : /**
217 : : * valent_findmyphone_ringer_hide:
218 : : * @ringer: a `ValentFindmyphoneRinger`
219 : : *
220 : : * Disable the ringing state of @ringer and hide the dialog.
221 : : */
222 : : void
223 : 0 : valent_findmyphone_ringer_hide (ValentFindmyphoneRinger *ringer)
224 : : {
225 : 0 : GApplication *application = g_application_get_default ();
226 : :
227 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
228 : :
229 [ # # ]: 0 : if (ringer->notification != NULL)
230 : 0 : g_application_withdraw_notification (application, "findmyphone::ringer");
231 : :
232 : 0 : valent_findmyphone_ringer_stop (ringer);
233 : : }
234 : :
235 : : /**
236 : : * valent_findmyphone_ringer_acquire:
237 : : *
238 : : * Acquire a reference on the default `ValentFindmyphoneRinger`.
239 : : *
240 : : * Returns: (transfer full): a `ValentFindmyphoneRinger`
241 : : */
242 : : ValentFindmyphoneRinger *
243 : 4 : valent_findmyphone_ringer_acquire (void)
244 : : {
245 [ + - ]: 4 : if (default_ringer == NULL)
246 : : {
247 : 4 : default_ringer = valent_findmyphone_ringer_new ();
248 : 4 : return default_ringer;
249 : : }
250 : :
251 : 0 : return g_rc_box_acquire (default_ringer);
252 : : }
253 : :
254 : : /**
255 : : * valent_findmyphone_ringer_release:
256 : : * @data: (type Valent.FindmyphoneRinger): a `ValentFindmyphoneRinger`
257 : : *
258 : : * Release a reference on the default `ValentFindmyphoneRinger`.
259 : : */
260 : : void
261 : 4 : valent_findmyphone_ringer_release (gpointer data)
262 : : {
263 : 4 : ValentFindmyphoneRinger *ringer = data;
264 : :
265 [ + - ]: 4 : g_return_if_fail (ringer != NULL);
266 : :
267 : 4 : g_rc_box_release_full (ringer, valent_findmyphone_ringer_free);
268 : : }
269 : :
270 : : /**
271 : : * valent_findmyphone_ringer_toggle:
272 : : * @ringer: a `ValentFindmyphoneRinger`
273 : : * @owner: (type GObject.Object): a `GObject`
274 : : *
275 : : * Toggle the ringing state of @ringer.
276 : : */
277 : : void
278 : 0 : valent_findmyphone_ringer_toggle (ValentFindmyphoneRinger *ringer,
279 : : gpointer owner)
280 : : {
281 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
282 : :
283 [ # # ]: 0 : if (ringer->source_id > 0)
284 : : {
285 : 0 : valent_findmyphone_ringer_hide (ringer);
286 : 0 : ringer->owner = NULL;
287 : : }
288 : : else
289 : : {
290 : 0 : valent_findmyphone_ringer_show (ringer);
291 : 0 : ringer->owner = owner;
292 : : }
293 : : }
294 : :
295 : : /**
296 : : * valent_findmyphone_ringer_is_owner:
297 : : * @ringer: a `ValentFindmyphoneRinger`
298 : : * @owner: (type GObject.Object): a `GObject`
299 : : *
300 : : * Check if @owner is responsible for the current state of @ringer.
301 : : *
302 : : * Returns: %TRUE if @owner controls the ringer
303 : : */
304 : : gboolean
305 : 7 : valent_findmyphone_ringer_is_owner (ValentFindmyphoneRinger *ringer,
306 : : gpointer owner)
307 : : {
308 [ + - ]: 7 : g_return_val_if_fail (ringer != NULL, FALSE);
309 [ - + ]: 7 : g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
310 : :
311 : 7 : return ringer->owner == owner;
312 : : }
313 : :
|