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 <glib/gi18n.h>
9 : : #include <gst/gst.h>
10 : : #include <gtk/gtk.h>
11 : : #include <adwaita.h>
12 : :
13 : : #include "valent-findmyphone-ringer.h"
14 : :
15 : :
16 : : struct _ValentFindmyphoneRinger
17 : : {
18 : : GtkWindow *dialog;
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 : gtk_window_destroy_idle (gpointer data)
29 : : {
30 : 0 : gtk_window_destroy (GTK_WINDOW (data));
31 : 0 : return G_SOURCE_REMOVE;
32 : : }
33 : :
34 : : static void
35 : 0 : on_motion_event (GtkWindow *dialog)
36 : : {
37 : 0 : g_idle_add (gtk_window_destroy_idle, dialog);
38 : 0 : }
39 : :
40 : : static gboolean
41 : 0 : ringer_source_func (GstBus *bus,
42 : : GstMessage *message,
43 : : gpointer user_data)
44 : : {
45 : 0 : ValentFindmyphoneRinger *ringer = user_data;
46 : :
47 [ # # ]: 0 : if (message->type == GST_MESSAGE_ERROR)
48 : : {
49 : 0 : g_autoptr (GError) error = NULL;
50 [ # # ]: 0 : g_autofree char *debug = NULL;
51 : :
52 : 0 : gst_message_parse_error (message, &error, &debug);
53 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
54 [ # # ]: 0 : g_debug ("%s: %s", G_STRFUNC, (debug) ? debug : "none");
55 : :
56 : 0 : return G_SOURCE_REMOVE;
57 : : }
58 : :
59 : : /* Rewind to beginning */
60 [ # # ]: 0 : if (message->type == GST_MESSAGE_EOS)
61 : : {
62 : 0 : return gst_element_seek_simple (ringer->playbin,
63 : : GST_FORMAT_TIME,
64 : : GST_SEEK_FLAG_FLUSH,
65 : : 0);
66 : : }
67 : :
68 : : return G_SOURCE_CONTINUE;
69 : : }
70 : :
71 : : static void
72 : 4 : valent_findmyphone_ringer_free (gpointer data)
73 : : {
74 : 4 : ValentFindmyphoneRinger *ringer = data;
75 : :
76 [ - + ]: 4 : g_clear_pointer (&ringer->dialog, gtk_window_destroy);
77 : :
78 [ - + ]: 4 : if (ringer->playbin != NULL)
79 : : {
80 : 0 : gst_element_set_state (ringer->playbin, GST_STATE_NULL);
81 [ # # ]: 0 : gst_clear_object (&ringer->playbin);
82 : : }
83 : :
84 : 4 : default_ringer = NULL;
85 : 4 : }
86 : :
87 : : /**
88 : : * valent_findmyphone_ringer_new:
89 : : *
90 : : * Create a new `ValentFindmyphoneRinger`.
91 : : *
92 : : * Returns: (transfer full): a `ValentFindmyphoneRinger`
93 : : */
94 : : ValentFindmyphoneRinger *
95 : 4 : valent_findmyphone_ringer_new (void)
96 : : {
97 : 4 : ValentFindmyphoneRinger *ringer;
98 : 8 : g_autoptr (GError) error = NULL;
99 : :
100 : 4 : ringer = g_rc_box_new0 (ValentFindmyphoneRinger);
101 : :
102 [ - + ]: 4 : if (!gst_init_check (NULL, NULL, &error))
103 : : {
104 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
105 : 0 : return ringer;
106 : : }
107 : :
108 : : /* Playbin */
109 : 4 : ringer->playbin = gst_element_factory_make ("playbin", "findmyphone-ringer");
110 : :
111 [ - + ]: 4 : if (ringer->playbin != NULL)
112 : : {
113 : 0 : g_object_set (ringer->playbin,
114 : : "uri", "resource:///plugins/findmyphone/alert.oga",
115 : : NULL);
116 : : }
117 : :
118 : : return ringer;
119 : : }
120 : :
121 : : /**
122 : : * valent_findmyphone_ringer_start:
123 : : * @ringer: a `ValentFindmyphoneRinger`
124 : : *
125 : : * Enable the ringing state of @ringer.
126 : : */
127 : : void
128 : 0 : valent_findmyphone_ringer_start (ValentFindmyphoneRinger *ringer)
129 : : {
130 : 0 : g_autoptr (GstBus) playbus = NULL;
131 : :
132 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
133 : :
134 [ # # # # ]: 0 : if (ringer->playbin == NULL || ringer->source_id > 0)
135 : : return;
136 : :
137 : 0 : playbus = gst_element_get_bus (ringer->playbin);
138 : 0 : ringer->source_id = gst_bus_add_watch (playbus, ringer_source_func, ringer);
139 : :
140 [ # # ]: 0 : if (gst_element_set_state (ringer->playbin, GST_STATE_PLAYING) == 0)
141 [ # # # # ]: 0 : g_clear_handle_id (&ringer->source_id, g_source_remove);
142 : : }
143 : :
144 : : /**
145 : : * valent_findmyphone_ringer_stop:
146 : : * @ringer: a `ValentFindmyphoneRinger`
147 : : *
148 : : * Disable the ringing state of @ringer.
149 : : */
150 : : void
151 : 0 : valent_findmyphone_ringer_stop (ValentFindmyphoneRinger *ringer)
152 : : {
153 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
154 : :
155 [ # # # # ]: 0 : if (ringer->playbin == NULL || ringer->source_id == 0)
156 : : return;
157 : :
158 : 0 : gst_element_set_state (ringer->playbin, GST_STATE_NULL);
159 [ # # ]: 0 : g_clear_handle_id (&ringer->source_id, g_source_remove);
160 : 0 : ringer->owner = NULL;
161 : : }
162 : :
163 : : /**
164 : : * valent_findmyphone_ringer_show:
165 : : * @ringer: a `ValentFindmyphoneRinger`
166 : : *
167 : : * Enable the ringing state of @ringer and show a dialog.
168 : : */
169 : : void
170 : 0 : valent_findmyphone_ringer_show (ValentFindmyphoneRinger *ringer)
171 : : {
172 : 0 : GtkEventController *controller;
173 : 0 : GtkWidget *label;
174 : :
175 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
176 : :
177 : 0 : valent_findmyphone_ringer_start (ringer);
178 : :
179 [ # # # # ]: 0 : if (!gtk_is_initialized () || ringer->dialog != NULL)
180 : : return;
181 : :
182 : : /* Create the dialog */
183 : 0 : ringer->dialog = g_object_new (GTK_TYPE_WINDOW,
184 : : "fullscreened", TRUE,
185 : : "maximized", TRUE,
186 : : NULL);
187 : 0 : g_object_add_weak_pointer (G_OBJECT (ringer->dialog),
188 : 0 : (gpointer)&ringer->dialog);
189 : :
190 : 0 : label = g_object_new (ADW_TYPE_STATUS_PAGE,
191 : : "title", _("Found"),
192 : : "icon-name", "phonelink-ring-symbolic",
193 : : NULL);
194 : 0 : gtk_window_set_child (ringer->dialog, label);
195 : :
196 : 0 : g_signal_connect_swapped (ringer->dialog,
197 : : "destroy",
198 : : G_CALLBACK (valent_findmyphone_ringer_stop),
199 : : ringer);
200 : :
201 : : /* Close on keypress, pointer motion or click */
202 : 0 : controller = gtk_event_controller_key_new ();
203 : 0 : gtk_widget_add_controller (GTK_WIDGET (ringer->dialog), controller);
204 : 0 : g_signal_connect_swapped (G_OBJECT (controller),
205 : : "key-pressed",
206 : : G_CALLBACK (gtk_window_destroy),
207 : : ringer->dialog);
208 : :
209 : 0 : controller = gtk_event_controller_motion_new ();
210 : 0 : gtk_widget_add_controller (GTK_WIDGET (ringer->dialog), controller);
211 : 0 : g_signal_connect_swapped (G_OBJECT (controller),
212 : : "motion",
213 : : G_CALLBACK (on_motion_event),
214 : : ringer->dialog);
215 : :
216 : 0 : controller = (GtkEventController *)gtk_gesture_click_new ();
217 : 0 : gtk_widget_add_controller (GTK_WIDGET (ringer->dialog), controller);
218 : 0 : g_signal_connect_swapped (G_OBJECT (controller),
219 : : "pressed",
220 : : G_CALLBACK (gtk_window_destroy),
221 : : ringer->dialog);
222 : :
223 : : /* Show the dialog */
224 : 0 : gtk_window_present (ringer->dialog);
225 : : }
226 : :
227 : : /**
228 : : * valent_findmyphone_ringer_hide:
229 : : * @ringer: a `ValentFindmyphoneRinger`
230 : : *
231 : : * Disable the ringing state of @ringer and hide the dialog.
232 : : */
233 : : void
234 : 0 : valent_findmyphone_ringer_hide (ValentFindmyphoneRinger *ringer)
235 : : {
236 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
237 : :
238 [ # # ]: 0 : if (ringer->dialog != NULL)
239 : 0 : g_clear_pointer (&ringer->dialog, gtk_window_destroy);
240 : : else
241 : 0 : valent_findmyphone_ringer_stop (ringer);
242 : : }
243 : :
244 : : /**
245 : : * valent_findmyphone_ringer_acquire:
246 : : *
247 : : * Acquire a reference on the default `ValentFindmyphoneRinger`.
248 : : *
249 : : * Returns: (transfer full): a `ValentFindmyphoneRinger`
250 : : */
251 : : ValentFindmyphoneRinger *
252 : 4 : valent_findmyphone_ringer_acquire (void)
253 : : {
254 [ + - ]: 4 : if (default_ringer == NULL)
255 : : {
256 : 4 : default_ringer = valent_findmyphone_ringer_new ();
257 : 4 : return default_ringer;
258 : : }
259 : :
260 : 0 : return g_rc_box_acquire (default_ringer);
261 : : }
262 : :
263 : : /**
264 : : * valent_findmyphone_ringer_release:
265 : : * @data: (type Valent.FindmyphoneRinger): a `ValentFindmyphoneRinger`
266 : : *
267 : : * Release a reference on the default `ValentFindmyphoneRinger`.
268 : : */
269 : : void
270 : 4 : valent_findmyphone_ringer_release (gpointer data)
271 : : {
272 : 4 : ValentFindmyphoneRinger *ringer = data;
273 : :
274 [ + - ]: 4 : g_return_if_fail (ringer != NULL);
275 : :
276 : 4 : g_rc_box_release_full (ringer, valent_findmyphone_ringer_free);
277 : : }
278 : :
279 : : /**
280 : : * valent_findmyphone_ringer_toggle:
281 : : * @ringer: a `ValentFindmyphoneRinger`
282 : : * @owner: (type GObject.Object): a `GObject`
283 : : *
284 : : * Toggle the ringing state of @ringer.
285 : : */
286 : : void
287 : 0 : valent_findmyphone_ringer_toggle (ValentFindmyphoneRinger *ringer,
288 : : gpointer owner)
289 : : {
290 [ # # ]: 0 : g_return_if_fail (ringer != NULL);
291 : :
292 [ # # # # ]: 0 : if (ringer->dialog != NULL || ringer->source_id > 0)
293 : : {
294 : 0 : valent_findmyphone_ringer_hide (ringer);
295 : 0 : ringer->owner = NULL;
296 : : }
297 : : else
298 : : {
299 : 0 : valent_findmyphone_ringer_show (ringer);
300 : 0 : ringer->owner = owner;
301 : : }
302 : : }
303 : :
304 : : /**
305 : : * valent_findmyphone_ringer_is_owner:
306 : : * @ringer: a `ValentFindmyphoneRinger`
307 : : * @owner: (type GObject.Object): a `GObject`
308 : : *
309 : : * Check if @owner is responsible for the current state of @ringer.
310 : : *
311 : : * Returns: %TRUE if @owner controls the ringer
312 : : */
313 : : gboolean
314 : 7 : valent_findmyphone_ringer_is_owner (ValentFindmyphoneRinger *ringer,
315 : : gpointer owner)
316 : : {
317 [ + - ]: 7 : g_return_val_if_fail (ringer != NULL, FALSE);
318 [ - + ]: 7 : g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
319 : :
320 : 7 : return ringer->owner == owner;
321 : : }
322 : :
|