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 : : enum {
34 : : PROP_0,
35 : : PROP_BUS_NAME,
36 : : N_PROPERTIES
37 : : };
38 : :
39 : : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
40 : :
41 : :
42 : : /*
43 : : * DBus Property Mapping
44 : : */
45 : : typedef struct
46 : : {
47 : : const char *dbus;
48 : : const char *name;
49 : : } PropMapping;
50 : :
51 : : static const PropMapping player_properties[] = {
52 : : {"CanControl", "flags"},
53 : : {"CanGoNext", "flags"},
54 : : {"CanGoPrevious", "flags"},
55 : : {"CanPause", "flags"},
56 : : {"CanPlay", "flags"},
57 : : {"CanSeek", "flags"},
58 : : {"Metadata", "metadata"},
59 : : {"LoopStatus", "repeat"},
60 : : {"PlaybackStatus", "state"},
61 : : {"Position", "position"},
62 : : {"Shuffle", "shuffle"},
63 : : {"Volume", "volume"},
64 : : };
65 : :
66 : :
67 : : /* For convenience, we use our object's ::notify signal to forward each proxy's
68 : : * GDBusProxy::g-properties-changed signal.
69 : : */
70 : : static void
71 : 0 : on_application_properties_changed (GDBusProxy *application,
72 : : GVariant *changed_properties,
73 : : GStrv invalidated_properties,
74 : : ValentMediaPlayer *player)
75 : : {
76 : 0 : GVariantDict dict;
77 : :
78 [ # # ]: 0 : g_assert (VALENT_IS_MEDIA_PLAYER (player));
79 : :
80 : 0 : g_variant_dict_init (&dict, changed_properties);
81 : :
82 [ # # ]: 0 : if (g_variant_dict_contains (&dict, "Identity"))
83 : 0 : g_object_notify (G_OBJECT (player), "name");
84 : :
85 : 0 : g_variant_dict_clear (&dict);
86 : 0 : }
87 : :
88 : : static void
89 : 27 : on_player_properties_changed (GDBusProxy *proxy,
90 : : GVariant *changed_properties,
91 : : GStrv invalidated_properties,
92 : : ValentMPRISPlayer *self)
93 : : {
94 : 27 : GVariantDict dict;
95 : :
96 [ + - ]: 27 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
97 [ - + ]: 27 : g_assert (changed_properties != NULL);
98 : :
99 : 27 : g_object_freeze_notify (G_OBJECT (self));
100 : 27 : g_variant_dict_init (&dict, changed_properties);
101 : :
102 [ + + ]: 351 : for (size_t i = 0; i < G_N_ELEMENTS (player_properties); i++)
103 : : {
104 [ + + ]: 324 : if (g_variant_dict_contains (&dict, player_properties[i].dbus))
105 : : {
106 : : /* `PropertiesChanged` should not be emitted for `Position`, but if it
107 : : * is, we might as well update the internal representation. */
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 : : else
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 : :
157 [ + - + + ]: 21 : if (value && !g_variant_get_boolean (value))
158 : 5 : self->flags = VALENT_MEDIA_ACTION_NONE;
159 : :
160 : 21 : g_clear_pointer (&value, g_variant_unref);
161 : :
162 : : // Next
163 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanGoNext");
164 : :
165 [ + - + + ]: 21 : if (value && g_variant_get_boolean (value))
166 : 9 : self->flags |= VALENT_MEDIA_ACTION_NEXT;
167 : : else
168 : 12 : self->flags &= ~VALENT_MEDIA_ACTION_NEXT;
169 : :
170 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
171 : :
172 : : // Previous
173 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanGoPrevious");
174 : :
175 [ + - + + ]: 21 : if (value && g_variant_get_boolean (value))
176 : 1 : self->flags |= VALENT_MEDIA_ACTION_PREVIOUS;
177 : : else
178 : 20 : self->flags &= ~VALENT_MEDIA_ACTION_PREVIOUS;
179 : :
180 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
181 : :
182 : : // Pause
183 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanPause");
184 : :
185 [ + - + + ]: 21 : if (value && g_variant_get_boolean (value))
186 : 6 : self->flags |= VALENT_MEDIA_ACTION_PAUSE;
187 : : else
188 : 15 : self->flags &= ~VALENT_MEDIA_ACTION_PAUSE;
189 : :
190 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
191 : :
192 : : // Play
193 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanPlay");
194 : :
195 [ + - + + ]: 21 : if (value && g_variant_get_boolean (value))
196 : 11 : self->flags |= VALENT_MEDIA_ACTION_PLAY;
197 : : else
198 : 10 : self->flags &= ~VALENT_MEDIA_ACTION_PLAY;
199 : :
200 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
201 : :
202 : : // Seek
203 : 21 : value = g_dbus_proxy_get_cached_property (self->player, "CanSeek");
204 : :
205 [ + - + + ]: 21 : if (value && g_variant_get_boolean (value))
206 : 9 : self->flags |= VALENT_MEDIA_ACTION_SEEK;
207 : : else
208 : 12 : self->flags &= ~VALENT_MEDIA_ACTION_SEEK;
209 : :
210 [ + - ]: 21 : g_clear_pointer (&value, g_variant_unref);
211 : 21 : }
212 : :
213 : : /*
214 : : * ValentMediaPlayer
215 : : */
216 : : static ValentMediaActions
217 : 11 : valent_mpris_player_get_flags (ValentMediaPlayer *player)
218 : : {
219 : 11 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
220 : :
221 : 11 : return self->flags;
222 : : }
223 : :
224 : : static GVariant *
225 : 13 : valent_mpris_player_get_metadata (ValentMediaPlayer *player)
226 : : {
227 : 13 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
228 : :
229 : 13 : return g_dbus_proxy_get_cached_property (self->player, "Metadata");
230 : : }
231 : :
232 : : static const char *
233 : 27 : valent_mpris_player_get_name (ValentMediaPlayer *player)
234 : : {
235 : 27 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
236 : 54 : g_autoptr (GVariant) value = NULL;
237 : :
238 : 27 : value = g_dbus_proxy_get_cached_property (self->application, "Identity");
239 : :
240 [ + - ]: 27 : if G_UNLIKELY (value == NULL)
241 : : return "MPRIS Player";
242 : :
243 : 27 : return g_variant_get_string (value, NULL);
244 : : }
245 : :
246 : : static double
247 : 13 : valent_mpris_player_get_position (ValentMediaPlayer *player)
248 : : {
249 : 13 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
250 : 26 : g_autoptr (GError) error = NULL;
251 [ + + ]: 13 : g_autoptr (GVariant) result = NULL;
252 [ - + ]: 13 : g_autoptr (GVariant) value = NULL;
253 : :
254 [ + + ]: 13 : if (valent_media_player_get_state (player) == VALENT_MEDIA_STATE_STOPPED)
255 : : return 0.0;
256 : :
257 : : /* If the position is non-zero, assume it's been updated */
258 [ + + ]: 5 : if (self->position > 0.0)
259 : 1 : return self->position + (valent_mpris_get_time () - self->position_time);
260 : :
261 : 4 : result = g_dbus_proxy_call_sync (self->player,
262 : : "org.freedesktop.DBus.Properties.Get",
263 : : g_variant_new ("(ss)",
264 : : "org.mpris.MediaPlayer2.Player",
265 : : "Position"),
266 : : G_DBUS_CALL_FLAGS_NONE,
267 : : 1,
268 : : NULL,
269 : : &error);
270 : :
271 [ + - ]: 4 : if (result == NULL)
272 : : {
273 [ - + ]: 4 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT))
274 : 0 : g_debug ("%s(): %s", G_STRFUNC, error->message);
275 : :
276 : 4 : return self->position + (valent_mpris_get_time () - self->position_time);
277 : : }
278 : :
279 : : /* Convert microseconds to seconds */
280 : 0 : g_variant_get (result, "(v)", &value);
281 : 0 : self->position = g_variant_get_int64 (value) / G_TIME_SPAN_SECOND;
282 : 0 : self->position_time = valent_mpris_get_time ();
283 : :
284 : 0 : return self->position;
285 : : }
286 : :
287 : : static void
288 : 2 : valent_mpris_player_set_position (ValentMediaPlayer *player,
289 : : double position)
290 : : {
291 : 2 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
292 : 2 : int64_t position_us = (int64_t)position * G_TIME_SPAN_SECOND;
293 : :
294 : : /* Convert seconds to microseconds */
295 : 2 : g_dbus_proxy_call (self->player,
296 : : "SetPosition",
297 : : g_variant_new ("(ox)", "/", position_us),
298 : : G_DBUS_CALL_FLAGS_NONE,
299 : : -1,
300 : : NULL,
301 : : NULL,
302 : : NULL);
303 : 2 : }
304 : :
305 : : static ValentMediaRepeat
306 : 12 : valent_mpris_player_get_repeat (ValentMediaPlayer *player)
307 : : {
308 : 12 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
309 : 24 : g_autoptr (GVariant) value = NULL;
310 : 12 : const char *loop_status = NULL;
311 : :
312 : 12 : value = g_dbus_proxy_get_cached_property (self->player, "LoopStatus");
313 : :
314 [ + - ]: 12 : if G_UNLIKELY (value == NULL)
315 : : return VALENT_MEDIA_REPEAT_NONE;
316 : :
317 : 12 : loop_status = g_variant_get_string (value, NULL);
318 : :
319 : 12 : return valent_mpris_repeat_from_string (loop_status);
320 : : }
321 : :
322 : : static void
323 : 3 : valent_mpris_player_set_repeat (ValentMediaPlayer *player,
324 : : ValentMediaRepeat repeat)
325 : : {
326 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
327 : 3 : const char *loop_status = valent_mpris_repeat_to_string (repeat);
328 : :
329 : 3 : g_dbus_proxy_call (self->player,
330 : : "org.freedesktop.DBus.Properties.Set",
331 : : g_variant_new ("(ssv)",
332 : : "org.mpris.MediaPlayer2.Player",
333 : : "LoopStatus",
334 : : g_variant_new_string (loop_status)),
335 : : G_DBUS_CALL_FLAGS_NONE,
336 : : -1,
337 : : NULL,
338 : : NULL,
339 : : NULL);
340 : 3 : }
341 : :
342 : : static ValentMediaState
343 : 40 : valent_mpris_player_get_state (ValentMediaPlayer *player)
344 : : {
345 : 40 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
346 : 80 : g_autoptr (GVariant) value = NULL;
347 : 40 : const char *playback_status = NULL;
348 : :
349 : 40 : value = g_dbus_proxy_get_cached_property (self->player, "PlaybackStatus");
350 : :
351 [ + - ]: 40 : if G_UNLIKELY (value == NULL)
352 : : return VALENT_MEDIA_STATE_STOPPED;
353 : :
354 : 40 : playback_status = g_variant_get_string (value, NULL);
355 : :
356 : 40 : return valent_mpris_state_from_string (playback_status);
357 : : }
358 : :
359 : : static gboolean
360 : 12 : valent_mpris_player_get_shuffle (ValentMediaPlayer *player)
361 : : {
362 : 12 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
363 : 24 : g_autoptr (GVariant) value = NULL;
364 : :
365 : 12 : value = g_dbus_proxy_get_cached_property (self->player, "Shuffle");
366 : :
367 [ + - ]: 12 : if G_UNLIKELY (value == NULL)
368 : : return FALSE;
369 : :
370 : 12 : return g_variant_get_boolean (value);
371 : : }
372 : :
373 : : static void
374 : 3 : valent_mpris_player_set_shuffle (ValentMediaPlayer *player,
375 : : gboolean shuffle)
376 : : {
377 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
378 : :
379 : 3 : g_dbus_proxy_call (self->player,
380 : : "org.freedesktop.DBus.Properties.Set",
381 : : g_variant_new ("(ssv)",
382 : : "org.mpris.MediaPlayer2.Player",
383 : : "Shuffle",
384 : : g_variant_new_boolean (shuffle)),
385 : : G_DBUS_CALL_FLAGS_NONE,
386 : : -1,
387 : : NULL,
388 : : NULL,
389 : : NULL);
390 : 3 : }
391 : :
392 : : static double
393 : 12 : valent_mpris_player_get_volume (ValentMediaPlayer *player)
394 : : {
395 : 12 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
396 : 24 : g_autoptr (GVariant) value = NULL;
397 : :
398 : 12 : value = g_dbus_proxy_get_cached_property (self->player, "Volume");
399 : :
400 [ + - ]: 12 : if G_UNLIKELY (value == NULL)
401 : : return 1.0;
402 : :
403 : 12 : return g_variant_get_double (value);
404 : : }
405 : :
406 : : static void
407 : 3 : valent_mpris_player_set_volume (ValentMediaPlayer *player,
408 : : double volume)
409 : : {
410 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
411 : :
412 : 3 : g_dbus_proxy_call (self->player,
413 : : "org.freedesktop.DBus.Properties.Set",
414 : : g_variant_new ("(ssv)",
415 : : "org.mpris.MediaPlayer2.Player",
416 : : "Volume",
417 : : g_variant_new_double (volume)),
418 : : G_DBUS_CALL_FLAGS_NONE,
419 : : -1,
420 : : NULL,
421 : : NULL,
422 : : NULL);
423 : 3 : }
424 : :
425 : : static void
426 : 3 : valent_mpris_player_next (ValentMediaPlayer *player)
427 : : {
428 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
429 : :
430 : 3 : g_dbus_proxy_call (self->player,
431 : : "Next",
432 : : NULL,
433 : : G_DBUS_CALL_FLAGS_NONE,
434 : : -1,
435 : : NULL,
436 : : NULL,
437 : : NULL);
438 : 3 : }
439 : :
440 : : static void
441 : 3 : valent_mpris_player_pause (ValentMediaPlayer *player)
442 : : {
443 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
444 : :
445 : 3 : g_dbus_proxy_call (self->player,
446 : : "Pause",
447 : : NULL,
448 : : G_DBUS_CALL_FLAGS_NONE,
449 : : -1,
450 : : NULL,
451 : : NULL,
452 : : NULL);
453 : 3 : }
454 : :
455 : : static void
456 : 3 : valent_mpris_player_play (ValentMediaPlayer *player)
457 : : {
458 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
459 : :
460 : 3 : g_dbus_proxy_call (self->player,
461 : : "Play",
462 : : NULL,
463 : : G_DBUS_CALL_FLAGS_NONE,
464 : : -1,
465 : : NULL,
466 : : NULL,
467 : : NULL);
468 : 3 : }
469 : :
470 : : #if 0
471 : : static void
472 : : valent_mpris_player_play_pause (ValentMediaPlayer *player)
473 : : {
474 : : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
475 : :
476 : : g_dbus_proxy_call (self->player,
477 : : "PlayPause",
478 : : NULL,
479 : : G_DBUS_CALL_FLAGS_NONE,
480 : : -1,
481 : : NULL,
482 : : NULL,
483 : : NULL);
484 : : }
485 : : #endif
486 : :
487 : : static void
488 : 3 : valent_mpris_player_previous (ValentMediaPlayer *player)
489 : : {
490 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
491 : :
492 : 3 : g_dbus_proxy_call (self->player,
493 : : "Previous",
494 : : NULL,
495 : : G_DBUS_CALL_FLAGS_NONE,
496 : : -1,
497 : : NULL,
498 : : NULL,
499 : : NULL);
500 : 3 : }
501 : :
502 : : static void
503 : 3 : valent_mpris_player_seek (ValentMediaPlayer *player,
504 : : double offset)
505 : : {
506 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
507 : :
508 : : /* Convert seconds to microseconds */
509 : 3 : g_dbus_proxy_call (self->player,
510 : : "Seek",
511 : 3 : g_variant_new ("(x)", (int64_t)offset * G_TIME_SPAN_SECOND),
512 : : G_DBUS_CALL_FLAGS_NONE,
513 : : -1,
514 : : NULL,
515 : : NULL,
516 : : NULL);
517 : 3 : }
518 : :
519 : : static void
520 : 3 : valent_mpris_player_stop (ValentMediaPlayer *player)
521 : : {
522 : 3 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (player);
523 : :
524 : 3 : g_dbus_proxy_call (self->player,
525 : : "Stop",
526 : : NULL,
527 : : G_DBUS_CALL_FLAGS_NONE,
528 : : -1,
529 : : NULL,
530 : : NULL,
531 : : NULL);
532 : 3 : }
533 : :
534 : : /*
535 : : * GAsyncInitable
536 : : */
537 : : static void
538 : 5 : valent_mpris_player_init_player_cb (GObject *object,
539 : : GAsyncResult *result,
540 : : gpointer user_data)
541 : : {
542 : 5 : g_autoptr (GTask) task = G_TASK (user_data);
543 : 5 : ValentMPRISPlayer *self = g_task_get_source_object (task);
544 [ - - + - ]: 5 : g_autoptr (GError) error = NULL;
545 : :
546 [ + - ]: 5 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
547 [ - + ]: 5 : g_assert (self->bus_name != NULL);
548 : :
549 : 5 : self->player = g_dbus_proxy_new_finish (result, &error);
550 : :
551 [ - + ]: 5 : if (self->player == NULL)
552 [ # # ]: 0 : return g_task_return_error (task, g_steal_pointer (&error));
553 : :
554 : 5 : g_signal_connect_object (self->player,
555 : : "g-properties-changed",
556 : : G_CALLBACK (on_player_properties_changed),
557 : : self, 0);
558 : :
559 : 5 : g_signal_connect_object (self->player,
560 : : "g-signal",
561 : : G_CALLBACK (on_player_signal),
562 : : self, 0);
563 : :
564 : 5 : valent_mpris_player_sync_flags (self);
565 : :
566 [ - + ]: 5 : g_task_return_boolean (task, TRUE);
567 : : }
568 : :
569 : : static void
570 : 5 : valent_mpris_player_init_application_cb (GObject *object,
571 : : GAsyncResult *result,
572 : : gpointer user_data)
573 : : {
574 : 5 : g_autoptr (GTask) task = G_TASK (user_data);
575 : 5 : ValentMPRISPlayer *self = g_task_get_source_object (task);
576 : 5 : GCancellable *cancellable = g_task_get_cancellable (task);
577 : 5 : g_autoptr (GError) error = NULL;
578 : :
579 [ + - ]: 5 : g_assert (VALENT_IS_MPRIS_PLAYER (self));
580 [ - + ]: 5 : g_assert (self->bus_name != NULL);
581 [ + - + - : 5 : g_assert (G_IS_TASK (task));
- + - - ]
582 : :
583 : 5 : self->application = g_dbus_proxy_new_finish (result, &error);
584 : :
585 [ - + ]: 5 : if (self->application == NULL)
586 [ # # ]: 0 : return g_task_return_error (task, g_steal_pointer (&error));
587 : :
588 : 5 : g_signal_connect_object (self->application,
589 : : "g-properties-changed",
590 : : G_CALLBACK (on_application_properties_changed),
591 : : self, 0);
592 : :
593 [ - + ]: 5 : 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_steal_pointer (&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 : 5 : 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 : 5 : 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_steal_pointer (&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 (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 (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 : 82 : valent_mpris_player_notify (GObject *object,
693 : : GParamSpec *pspec)
694 : : {
695 : 82 : ValentMPRISPlayer *self = VALENT_MPRIS_PLAYER (object);
696 : 82 : ValentMediaPlayer *player = VALENT_MEDIA_PLAYER (object);
697 : 82 : const char *name = g_param_spec_get_name (pspec);
698 : :
699 [ + + ]: 82 : if (g_str_equal (name, "flags"))
700 : 16 : valent_mpris_player_sync_flags (self);
701 : :
702 [ + + + + ]: 98 : 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 [ - + ]: 82 : if (G_OBJECT_CLASS (valent_mpris_player_parent_class)->notify)
711 : 0 : G_OBJECT_CLASS (valent_mpris_player_parent_class)->notify (object, pspec);
712 : 82 : }
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, N_PROPERTIES, properties);
758 : 2 : }
759 : :
760 : : static void
761 : 5 : valent_mpris_player_init (ValentMPRISPlayer *media_player)
762 : : {
763 : 5 : }
764 : :
|