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