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-mpris-player"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <valent.h>
10 : :
11 : : #include "valent-mpris-player.h"
12 : : #include "valent-mpris-utils.h"
13 : :
14 : :
15 : : struct _ValentMPRISPlayer
16 : : {
17 : : ValentMediaPlayer parent_instance;
18 : :
19 : : char *bus_name;
20 : : GDBusProxy *application;
21 : : GDBusProxy *player;
22 : :
23 : : ValentMediaActions flags;
24 : : double position;
25 : : double position_time;
26 : : };
27 : :
28 : : static void g_async_initable_iface_init (GAsyncInitableIface *iface);
29 : :
30 [ + + + - ]: 58 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentMPRISPlayer, valent_mpris_player, VALENT_TYPE_MEDIA_PLAYER,
31 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, g_async_initable_iface_init))
32 : :
33 : : typedef enum {
34 : : PROP_BUS_NAME = 1,
35 : : } ValentMPRISPlayerProperty;
36 : :
37 : : static GParamSpec *properties[PROP_BUS_NAME + 1] = { NULL, };
38 : :
39 : :
40 : : /*
41 : : * DBus Property Mapping
42 : : */
43 : : static struct
44 : : {
45 : : const char *dbus;
46 : : const char *name;
47 : : } player_properties[] = {
48 : : {"CanControl", "flags"},
49 : : {"CanGoNext", "flags"},
50 : : {"CanGoPrevious", "flags"},
51 : : {"CanPause", "flags"},
52 : : {"CanPlay", "flags"},
53 : : {"CanSeek", "flags"},
54 : : {"Metadata", "metadata"},
55 : : {"LoopStatus", "repeat"},
56 : : {"PlaybackStatus", "state"},
57 : : {"Position", "position"},
58 : : {"Shuffle", "shuffle"},
59 : : {"Volume", "volume"},
60 : : };
61 : :
62 : :
63 : : /* For convenience, we use our object's ::notify signal to forward each proxy's
64 : : * GDBusProxy::g-properties-changed signal.
65 : : */
66 : : static void
67 : 0 : on_application_properties_changed (GDBusProxy *application,
68 : : GVariant *changed_properties,
69 : : GStrv invalidated_properties,
70 : : ValentMediaPlayer *player)
71 : : {
72 : 0 : GVariantDict dict;
73 : :
74 [ # # ]: 0 : g_assert (VALENT_IS_MEDIA_PLAYER (player));
75 : :
76 : 0 : g_variant_dict_init (&dict, changed_properties);
77 : :
78 [ # # ]: 0 : if (g_variant_dict_contains (&dict, "Identity"))
79 : 0 : g_object_notify (G_OBJECT (player), "name");
80 : :
81 : 0 : g_variant_dict_clear (&dict);
82 : 0 : }
83 : :
84 : : static void
85 : 27 : on_player_properties_changed (GDBusProxy *proxy,
86 : : GVariant *changed_properties,
87 : : GStrv invalidated_properties,
88 : : ValentMPRISPlayer *self)
89 : : {
90 : 27 : GVariantDict dict;
91 : :
92 [ + - ]: 27 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
93 [ - + ]: 27 : g_assert (changed_properties != NULL);
94 : :
95 : : /* Freeze property notification until all properties are updated, so that
96 : : * multiple properties can be accessed from a single change notification.
97 : : */
98 : 27 : g_object_freeze_notify (G_OBJECT (self));
99 : :
100 : 27 : g_variant_dict_init (&dict, changed_properties);
101 [ + + ]: 351 : for (size_t i = 0; i < G_N_ELEMENTS (player_properties); i++)
102 : : {
103 [ + + ]: 324 : if (g_variant_dict_contains (&dict, player_properties[i].dbus))
104 : : {
105 : : /* `PropertiesChanged` should not be emitted for `Position`, but if it
106 : : * is, we might as well update the internal representation.
107 : : */
108 [ - + ]: 139 : if (g_str_equal (player_properties[i].dbus, "Position"))
109 : : {
110 : 0 : int64_t position_us = 0;
111 : :
112 : 0 : g_variant_dict_lookup (&dict, "Position", "x", &position_us);
113 : 0 : self->position = position_us / G_TIME_SPAN_SECOND;
114 : 0 : self->position_time = valent_mpris_get_time ();
115 : : }
116 : :
117 : 139 : g_object_notify (G_OBJECT (self), player_properties[i].name);
118 : : }
119 : : }
120 : :
121 : 27 : g_variant_dict_clear (&dict);
122 : 27 : g_object_thaw_notify (G_OBJECT (self));
123 : 27 : }
124 : :
125 : : static void
126 : 7 : on_player_signal (GDBusProxy *proxy,
127 : : const char *sender_name,
128 : : const char *signal_name,
129 : : GVariant *parameters,
130 : : ValentMediaPlayer *player)
131 : : {
132 : 7 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
133 : :
134 [ + - ]: 7 : g_assert (VALENT_IS_MPRIS_PLAYER (player));
135 [ - + ]: 7 : g_assert (signal_name != NULL);
136 : :
137 [ + - ]: 7 : if (g_str_equal (signal_name, "Seeked"))
138 : : {
139 : 7 : int64_t position_us = 0;
140 : :
141 : : /* Convert microseconds to seconds */
142 : 7 : g_variant_get (parameters, "(x)", &position_us);
143 : 7 : self->position = position_us / G_TIME_SPAN_SECOND;
144 : 7 : self->position_time = valent_mpris_get_time ();
145 : 7 : g_object_notify (G_OBJECT (player), "position");
146 : : }
147 : 7 : }
148 : :
149 : : static void
150 : 21 : valent_mpris_player_sync_flags (ValentMPRISPlayer *self)
151 : : {
152 : 42 : g_autoptr (GVariant) value = NULL;
153 : :
154 : : // TODO: Controllable
155 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanControl");
156 [ + - + + ]: 21 : if (value != NULL && !g_variant_get_boolean (value))
157 : 5 : self->flags = VALENT_MEDIA_ACTION_NONE;
158 : :
159 : 21 : g_clear_pointer (&value, g_variant_unref);
160 : :
161 : : // Next
162 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanGoNext");
163 [ + - + + ]: 21 : if (value != NULL && g_variant_get_boolean (value))
164 : 9 : self->flags |= VALENT_MEDIA_ACTION_NEXT;
165 : : else
166 : 12 : self->flags &= ~VALENT_MEDIA_ACTION_NEXT;
167 : :
168 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
169 : :
170 : : // Previous
171 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanGoPrevious");
172 [ + - + + ]: 21 : if (value != NULL && g_variant_get_boolean (value))
173 : 1 : self->flags |= VALENT_MEDIA_ACTION_PREVIOUS;
174 : : else
175 : 20 : self->flags &= ~VALENT_MEDIA_ACTION_PREVIOUS;
176 : :
177 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
178 : :
179 : : // Pause
180 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanPause");
181 [ + - + + ]: 21 : if (value != NULL && g_variant_get_boolean (value))
182 : 6 : self->flags |= VALENT_MEDIA_ACTION_PAUSE;
183 : : else
184 : 15 : self->flags &= ~VALENT_MEDIA_ACTION_PAUSE;
185 : :
186 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
187 : :
188 : : // Play
189 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanPlay");
190 [ + - + + ]: 21 : if (value != NULL && g_variant_get_boolean (value))
191 : 11 : self->flags |= VALENT_MEDIA_ACTION_PLAY;
192 : : else
193 : 10 : self->flags &= ~VALENT_MEDIA_ACTION_PLAY;
194 : :
195 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
196 : :
197 : : // Seek
198 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanSeek");
199 [ + - + + ]: 21 : if (value != NULL && g_variant_get_boolean (value))
200 : 9 : self->flags |= VALENT_MEDIA_ACTION_SEEK;
201 : : else
202 : 12 : self->flags &= ~VALENT_MEDIA_ACTION_SEEK;
203 : :
204 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
205 : 21 : }
206 : :
207 : : /*
208 : : * ValentMediaPlayer
209 : : */
210 : : static ValentMediaActions
211 : 11 : valent_mpris_player_get_flags (ValentMediaPlayer *player)
212 : : {
213 : 11 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
214 : :
215 : 11 : return self->flags;
216 : : }
217 : :
218 : : static GVariant *
219 : 13 : valent_mpris_player_get_metadata (ValentMediaPlayer *player)
220 : : {
221 : 13 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
222 : :
223 : 13 : return g_dbus_proxy_get_cached_property (self->player, "Metadata");
224 : : }
225 : :
226 : : static const char *
227 : 27 : valent_mpris_player_get_name (ValentMediaPlayer *player)
228 : : {
229 : 27 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
230 : 54 : g_autoptr (GVariant) value = NULL;
231 : :
232 : 27 : value = g_dbus_proxy_get_cached_property (self->application, "Identity");
233 : :
234 [ + - ]: 27 : if G_UNLIKELY (value == NULL)
235 : : return "MPRIS Player";
236 : :
237 : 27 : return g_variant_get_string (value, NULL);
238 : : }
239 : :
240 : : static double
241 : 13 : valent_mpris_player_get_position (ValentMediaPlayer *player)
242 : : {
243 : 13 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
244 : 26 : g_autoptr (GError) error = NULL;
245 [ + + ]: 13 : g_autoptr (GVariant) result = NULL;
246 [ - + ]: 13 : g_autoptr (GVariant) value = NULL;
247 : :
248 [ + + ]: 13 : if (valent_media_player_get_state (player) == VALENT_MEDIA_STATE_STOPPED)
249 : : return 0.0;
250 : :
251 : : /* If the position is non-zero, assume it's been updated */
252 [ + + ]: 5 : if (self->position > 0.0)
253 : 1 : return self->position + (valent_mpris_get_time () - self->position_time);
254 : :
255 : 4 : result = g_dbus_proxy_call_sync (self->player,
256 : : "org.freedesktop.DBus.Properties.Get",
257 : : g_variant_new ("(ss)",
258 : : "org.mpris.MediaPlayer2.Player",
259 : : "Position"),
260 : : G_DBUS_CALL_FLAGS_NONE,
261 : : 1,
262 : : NULL,
263 : : &error);
264 : :
265 [ + - ]: 4 : if (result == NULL)
266 : : {
267 [ - + ]: 4 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT))
268 : 0 : g_debug ("%s(): %s", G_STRFUNC, error->message);
269 : :
270 : 4 : return self->position + (valent_mpris_get_time () - self->position_time);
271 : : }
272 : :
273 : : /* Convert microseconds to seconds */
274 : 0 : g_variant_get (result, "(v)", &value);
275 : 0 : self->position = g_variant_get_int64 (value) / G_TIME_SPAN_SECOND;
276 : 0 : self->position_time = valent_mpris_get_time ();
277 : :
278 : 0 : return self->position;
279 : : }
280 : :
281 : : static void
282 : 2 : valent_mpris_player_set_position (ValentMediaPlayer *player,
283 : : double position)
284 : : {
285 : 2 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
286 : 2 : int64_t position_us = (int64_t)position * G_TIME_SPAN_SECOND;
287 : :
288 : : /* Convert seconds to microseconds */
289 : 2 : g_dbus_proxy_call (self->player,
290 : : "SetPosition",
291 : : g_variant_new ("(ox)", "/", position_us),
292 : : G_DBUS_CALL_FLAGS_NONE,
293 : : -1,
294 : : NULL,
295 : : NULL,
296 : : NULL);
297 : 2 : }
298 : :
299 : : static ValentMediaRepeat
300 : 12 : valent_mpris_player_get_repeat (ValentMediaPlayer *player)
301 : : {
302 : 12 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
303 : 24 : g_autoptr (GVariant) value = NULL;
304 : 12 : const char *loop_status = NULL;
305 : :
306 : 12 : value = g_dbus_proxy_get_cached_property (self->player, "LoopStatus");
307 : :
308 [ + - ]: 12 : if G_UNLIKELY (value == NULL)
309 : : return VALENT_MEDIA_REPEAT_NONE;
310 : :
311 : 12 : loop_status = g_variant_get_string (value, NULL);
312 : :
313 : 12 : return valent_mpris_repeat_from_string (loop_status);
314 : : }
315 : :
316 : : static void
317 : 3 : valent_mpris_player_set_repeat (ValentMediaPlayer *player,
318 : : ValentMediaRepeat repeat)
319 : : {
320 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
321 : 3 : const char *loop_status = valent_mpris_repeat_to_string (repeat);
322 : :
323 : 3 : g_dbus_proxy_call (self->player,
324 : : "org.freedesktop.DBus.Properties.Set",
325 : : g_variant_new ("(ssv)",
326 : : "org.mpris.MediaPlayer2.Player",
327 : : "LoopStatus",
328 : : g_variant_new_string (loop_status)),
329 : : G_DBUS_CALL_FLAGS_NONE,
330 : : -1,
331 : : NULL,
332 : : NULL,
333 : : NULL);
334 : 3 : }
335 : :
336 : : static ValentMediaState
337 : 40 : valent_mpris_player_get_state (ValentMediaPlayer *player)
338 : : {
339 : 40 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
340 : 80 : g_autoptr (GVariant) value = NULL;
341 : 40 : const char *playback_status = NULL;
342 : :
343 : 40 : value = g_dbus_proxy_get_cached_property (self->player, "PlaybackStatus");
344 : :
345 [ + - ]: 40 : if G_UNLIKELY (value == NULL)
346 : : return VALENT_MEDIA_STATE_STOPPED;
347 : :
348 : 40 : playback_status = g_variant_get_string (value, NULL);
349 : :
350 : 40 : return valent_mpris_state_from_string (playback_status);
351 : : }
352 : :
353 : : static gboolean
354 : 12 : valent_mpris_player_get_shuffle (ValentMediaPlayer *player)
355 : : {
356 : 12 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
357 : 24 : g_autoptr (GVariant) value = NULL;
358 : :
359 : 12 : value = g_dbus_proxy_get_cached_property (self->player, "Shuffle");
360 : :
361 [ + - ]: 12 : if G_UNLIKELY (value == NULL)
362 : : return FALSE;
363 : :
364 : 12 : return g_variant_get_boolean (value);
365 : : }
366 : :
367 : : static void
368 : 3 : valent_mpris_player_set_shuffle (ValentMediaPlayer *player,
369 : : gboolean shuffle)
370 : : {
371 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
372 : :
373 : 3 : g_dbus_proxy_call (self->player,
374 : : "org.freedesktop.DBus.Properties.Set",
375 : : g_variant_new ("(ssv)",
376 : : "org.mpris.MediaPlayer2.Player",
377 : : "Shuffle",
378 : : g_variant_new_boolean (shuffle)),
379 : : G_DBUS_CALL_FLAGS_NONE,
380 : : -1,
381 : : NULL,
382 : : NULL,
383 : : NULL);
384 : 3 : }
385 : :
386 : : static double
387 : 12 : valent_mpris_player_get_volume (ValentMediaPlayer *player)
388 : : {
389 : 12 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
390 : 24 : g_autoptr (GVariant) value = NULL;
391 : :
392 : 12 : value = g_dbus_proxy_get_cached_property (self->player, "Volume");
393 : :
394 [ + - ]: 12 : if G_UNLIKELY (value == NULL)
395 : : return 1.0;
396 : :
397 : 12 : return g_variant_get_double (value);
398 : : }
399 : :
400 : : static void
401 : 3 : valent_mpris_player_set_volume (ValentMediaPlayer *player,
402 : : double volume)
403 : : {
404 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
405 : :
406 : 3 : g_dbus_proxy_call (self->player,
407 : : "org.freedesktop.DBus.Properties.Set",
408 : : g_variant_new ("(ssv)",
409 : : "org.mpris.MediaPlayer2.Player",
410 : : "Volume",
411 : : g_variant_new_double (volume)),
412 : : G_DBUS_CALL_FLAGS_NONE,
413 : : -1,
414 : : NULL,
415 : : NULL,
416 : : NULL);
417 : 3 : }
418 : :
419 : : static void
420 : 3 : valent_mpris_player_next (ValentMediaPlayer *player)
421 : : {
422 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
423 : :
424 : 3 : g_dbus_proxy_call (self->player,
425 : : "Next",
426 : : NULL,
427 : : G_DBUS_CALL_FLAGS_NONE,
428 : : -1,
429 : : NULL,
430 : : NULL,
431 : : NULL);
432 : 3 : }
433 : :
434 : : static void
435 : 3 : valent_mpris_player_pause (ValentMediaPlayer *player)
436 : : {
437 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
438 : :
439 : 3 : g_dbus_proxy_call (self->player,
440 : : "Pause",
441 : : NULL,
442 : : G_DBUS_CALL_FLAGS_NONE,
443 : : -1,
444 : : NULL,
445 : : NULL,
446 : : NULL);
447 : 3 : }
448 : :
449 : : static void
450 : 3 : valent_mpris_player_play (ValentMediaPlayer *player)
451 : : {
452 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
453 : :
454 : 3 : g_dbus_proxy_call (self->player,
455 : : "Play",
456 : : NULL,
457 : : G_DBUS_CALL_FLAGS_NONE,
458 : : -1,
459 : : NULL,
460 : : NULL,
461 : : NULL);
462 : 3 : }
463 : :
464 : : #if 0
465 : : static void
466 : : valent_mpris_player_play_pause (ValentMediaPlayer *player)
467 : : {
468 : : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
469 : :
470 : : g_dbus_proxy_call (self->player,
471 : : "PlayPause",
472 : : NULL,
473 : : G_DBUS_CALL_FLAGS_NONE,
474 : : -1,
475 : : NULL,
476 : : NULL,
477 : : NULL);
478 : : }
479 : : #endif
480 : :
481 : : static void
482 : 3 : valent_mpris_player_previous (ValentMediaPlayer *player)
483 : : {
484 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
485 : :
486 : 3 : g_dbus_proxy_call (self->player,
487 : : "Previous",
488 : : NULL,
489 : : G_DBUS_CALL_FLAGS_NONE,
490 : : -1,
491 : : NULL,
492 : : NULL,
493 : : NULL);
494 : 3 : }
495 : :
496 : : static void
497 : 3 : valent_mpris_player_seek (ValentMediaPlayer *player,
498 : : double offset)
499 : : {
500 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
501 : :
502 : : /* Convert seconds to microseconds */
503 : 3 : g_dbus_proxy_call (self->player,
504 : : "Seek",
505 : 3 : g_variant_new ("(x)", (int64_t)offset * G_TIME_SPAN_SECOND),
506 : : G_DBUS_CALL_FLAGS_NONE,
507 : : -1,
508 : : NULL,
509 : : NULL,
510 : : NULL);
511 : 3 : }
512 : :
513 : : static void
514 : 3 : valent_mpris_player_stop (ValentMediaPlayer *player)
515 : : {
516 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
517 : :
518 : 3 : g_dbus_proxy_call (self->player,
519 : : "Stop",
520 : : NULL,
521 : : G_DBUS_CALL_FLAGS_NONE,
522 : : -1,
523 : : NULL,
524 : : NULL,
525 : : NULL);
526 : 3 : }
527 : :
528 : : /*
529 : : * GAsyncInitable
530 : : */
531 : : static void
532 : 5 : valent_mpris_player_init_player_cb (GObject *object,
533 : : GAsyncResult *result,
534 : : gpointer user_data)
535 : : {
536 : 10 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
537 : 5 : ValentMPRISPlayer *self = g_task_get_source_object (task);
538 [ - - + - ]: 5 : g_autoptr (GError) error = NULL;
539 : :
540 [ + - ]: 5 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
541 [ - + ]: 5 : g_assert (self->bus_name != NULL);
542 : :
543 : 5 : self->player = g_dbus_proxy_new_finish (result, &error);
544 [ - + ]: 5 : if (self->player == NULL)
545 : : {
546 : 0 : g_task_return_error (task, g_steal_pointer (&error));
547 [ # # ]: 0 : return;
548 : : }
549 : :
550 : 5 : g_signal_connect_object (self->player,
551 : : "g-properties-changed",
552 : : G_CALLBACK (on_player_properties_changed),
553 : : self,
554 : : G_CONNECT_DEFAULT);
555 : 5 : g_signal_connect_object (self->player,
556 : : "g-signal",
557 : : G_CALLBACK (on_player_signal),
558 : : self,
559 : : G_CONNECT_DEFAULT);
560 : :
561 : 5 : valent_mpris_player_sync_flags (self);
562 : :
563 [ - + ]: 5 : g_task_return_boolean (task, TRUE);
564 : : }
565 : :
566 : : static void
567 : 5 : valent_mpris_player_init_application_cb (GObject *object,
568 : : GAsyncResult *result,
569 : : gpointer user_data)
570 : : {
571 : 10 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
572 : 5 : ValentMPRISPlayer *self = g_task_get_source_object (task);
573 : 5 : GCancellable *cancellable = g_task_get_cancellable (task);
574 : 5 : g_autoptr (GError) error = NULL;
575 : :
576 [ + - ]: 5 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
577 [ - + ]: 5 : g_assert (self->bus_name != NULL);
578 [ + - + - : 5 : g_assert (G_IS_TASK (task));
- + - - ]
579 : :
580 : 5 : self->application = g_dbus_proxy_new_finish (result, &error);
581 [ - + ]: 5 : if (self->application == NULL)
582 : : {
583 : 0 : g_task_return_error (task, g_steal_pointer (&error));
584 [ # # ]: 0 : return;
585 : : }
586 : :
587 : 5 : g_signal_connect_object (self->application,
588 : : "g-properties-changed",
589 : : G_CALLBACK (on_application_properties_changed),
590 : : self,
591 : : G_CONNECT_DEFAULT);
592 : :
593 [ - + ]: 10 : g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
594 : : G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
595 : : VALENT_MPRIS_PLAYER_INFO,
596 : 5 : self->bus_name,
597 : : "/org/mpris/MediaPlayer2",
598 : : "org.mpris.MediaPlayer2.Player",
599 : : cancellable,
600 : : valent_mpris_player_init_player_cb,
601 : : g_object_ref (task));
602 : : }
603 : :
604 : : static void
605 : 5 : valent_mpris_player_init_async (GAsyncInitable *initable,
606 : : int io_priority,
607 : : GCancellable *cancellable,
608 : : GAsyncReadyCallback callback,
609 : : gpointer user_data)
610 : : {
611 : 5 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (initable);
612 : 0 : g_autoptr (GTask) task = NULL;
613 : :
614 [ + - ]: 5 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
615 [ - + ]: 5 : g_return_if_fail (self->bus_name != NULL);
616 : :
617 : 5 : task = g_task_new (initable, cancellable, callback, user_data);
618 : 5 : g_task_set_priority (task, io_priority);
619 [ + - ]: 5 : g_task_set_source_tag (task, valent_mpris_player_init_async);
620 : :
621 [ + - ]: 10 : g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
622 : : G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
623 : : VALENT_MPRIS_APPLICATION_INFO,
624 : 5 : self->bus_name,
625 : : "/org/mpris/MediaPlayer2",
626 : : "org.mpris.MediaPlayer2",
627 : : cancellable,
628 : : valent_mpris_player_init_application_cb,
629 : : g_object_ref (task));
630 : : }
631 : :
632 : : static void
633 : 2 : g_async_initable_iface_init (GAsyncInitableIface *iface)
634 : : {
635 : 2 : iface->init_async = valent_mpris_player_init_async;
636 : 2 : }
637 : :
638 : : /*
639 : : * GObject
640 : : */
641 : : static void
642 : 5 : valent_mpris_player_finalize (GObject *object)
643 : : {
644 : 5 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (object);
645 : :
646 [ + - ]: 5 : g_clear_pointer (&self->bus_name, g_free);
647 [ + - ]: 5 : g_clear_object (&self->player);
648 [ + - ]: 5 : g_clear_object (&self->application);
649 : :
650 : 5 : G_OBJECT_CLASS (valent_mpris_player_parent_class)->finalize (object);
651 : 5 : }
652 : :
653 : : static void
654 : 4 : valent_mpris_player_get_property (GObject *object,
655 : : guint prop_id,
656 : : GValue *value,
657 : : GParamSpec *pspec)
658 : : {
659 : 4 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (object);
660 : :
661 [ + - ]: 4 : switch ((ValentMPRISPlayerProperty)prop_id)
662 : : {
663 : 4 : case PROP_BUS_NAME:
664 : 4 : g_value_set_string (value, self->bus_name);
665 : 4 : break;
666 : :
667 : 0 : default:
668 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
669 : : }
670 : 4 : }
671 : :
672 : : static void
673 : 5 : valent_mpris_player_set_property (GObject *object,
674 : : guint prop_id,
675 : : const GValue *value,
676 : : GParamSpec *pspec)
677 : : {
678 : 5 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (object);
679 : :
680 [ + - ]: 5 : switch ((ValentMPRISPlayerProperty)prop_id)
681 : : {
682 : 5 : case PROP_BUS_NAME:
683 : 5 : self->bus_name = g_value_dup_string (value);
684 : 5 : break;
685 : :
686 : 0 : default:
687 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
688 : : }
689 : 5 : }
690 : :
691 : : static void
692 : 88 : valent_mpris_player_notify (GObject *object,
693 : : GParamSpec *pspec)
694 : : {
695 : 88 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (object);
696 : 88 : ValentMediaPlayer *player = VALENT_MEDIA_PLAYER (object);
697 : 88 : const char *name = g_param_spec_get_name (pspec);
698 : :
699 [ + + ]: 88 : if (g_str_equal (name, "flags"))
700 : 16 : valent_mpris_player_sync_flags (self);
701 : :
702 [ + + + + ]: 104 : if (g_str_equal (name, "state") &&
703 : 16 : valent_media_player_get_state (player) == VALENT_MEDIA_STATE_STOPPED)
704 : : {
705 : 7 : self->position = 0.0;
706 : 7 : self->position_time = 0.0;
707 : 7 : g_object_notify (G_OBJECT (self), "position");
708 : : }
709 : :
710 [ - + ]: 88 : if (G_OBJECT_CLASS (valent_mpris_player_parent_class)->notify)
711 : 0 : G_OBJECT_CLASS (valent_mpris_player_parent_class)->notify (object, pspec);
712 : 88 : }
713 : :
714 : : static void
715 : 2 : valent_mpris_player_class_init (ValentMPRISPlayerClass *klass)
716 : : {
717 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
718 : 2 : ValentMediaPlayerClass *player_class = VALENT_MEDIA_PLAYER_CLASS (klass);
719 : :
720 : 2 : object_class->finalize = valent_mpris_player_finalize;
721 : 2 : object_class->get_property = valent_mpris_player_get_property;
722 : 2 : object_class->set_property = valent_mpris_player_set_property;
723 : 2 : object_class->notify = valent_mpris_player_notify;
724 : :
725 : 2 : player_class->get_flags = valent_mpris_player_get_flags;
726 : 2 : player_class->get_metadata = valent_mpris_player_get_metadata;
727 : 2 : player_class->get_name = valent_mpris_player_get_name;
728 : 2 : player_class->get_position = valent_mpris_player_get_position;
729 : 2 : player_class->set_position = valent_mpris_player_set_position;
730 : 2 : player_class->get_repeat = valent_mpris_player_get_repeat;
731 : 2 : player_class->set_repeat = valent_mpris_player_set_repeat;
732 : 2 : player_class->get_shuffle = valent_mpris_player_get_shuffle;
733 : 2 : player_class->set_shuffle = valent_mpris_player_set_shuffle;
734 : 2 : player_class->get_state = valent_mpris_player_get_state;
735 : 2 : player_class->get_volume = valent_mpris_player_get_volume;
736 : 2 : player_class->set_volume = valent_mpris_player_set_volume;
737 : 2 : player_class->next = valent_mpris_player_next;
738 : 2 : player_class->pause = valent_mpris_player_pause;
739 : 2 : player_class->play = valent_mpris_player_play;
740 : 2 : player_class->previous = valent_mpris_player_previous;
741 : 2 : player_class->seek = valent_mpris_player_seek;
742 : 2 : player_class->stop = valent_mpris_player_stop;
743 : :
744 : : /**
745 : : * ValentMPRISPlayer:bus-name:
746 : : *
747 : : * The well-known or unique name that the player is on.
748 : : */
749 : 4 : properties [PROP_BUS_NAME] =
750 : 2 : g_param_spec_string ("bus-name", NULL, NULL,
751 : : NULL,
752 : : (G_PARAM_READWRITE |
753 : : G_PARAM_CONSTRUCT_ONLY |
754 : : G_PARAM_EXPLICIT_NOTIFY |
755 : : G_PARAM_STATIC_STRINGS));
756 : :
757 : 2 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
758 : 2 : }
759 : :
760 : : static void
761 : 5 : valent_mpris_player_init (ValentMPRISPlayer *media_player)
762 : : {
763 : 5 : }
764 : :
|