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-media-remote"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <adwaita.h>
9 : : #include <glib/gi18n-lib.h>
10 : : #include <gtk/gtk.h>
11 : : #include <valent.h>
12 : :
13 : : #include "valent-media-remote.h"
14 : : #include "valent-ui-utils-private.h"
15 : :
16 : : /* Time (ms) to delay the seek command when moving the position slider. Minimal
17 : : * testing indicates values in the 50-100ms work well. */
18 : : #define MEDIA_SEEK_DELAY (75)
19 : :
20 : :
21 : : struct _ValentMediaRemote
22 : : {
23 : : AdwBreakpointBin parent_instance;
24 : :
25 : : ValentMediaPlayer *player;
26 : : ValentMediaRepeat repeat;
27 : : unsigned int timer_id;
28 : : unsigned int seek_id;
29 : :
30 : : /* template */
31 : : GtkStack *media_art_stack;
32 : : GtkPicture *media_art_image;
33 : : GtkLabel *media_title;
34 : : GtkLabel *media_artist;
35 : : GtkLabel *media_album;
36 : : GtkScale *media_position;
37 : : GtkAdjustment *media_position_adjustment;
38 : : GtkLabel *media_position_current;
39 : : GtkLabel *media_position_length;
40 : : GtkButton *play_pause_button;
41 : : GtkMenuButton *playback_options;
42 : : GtkVolumeButton *volume_button;
43 : : };
44 : :
45 [ + + + - ]: 47 : G_DEFINE_FINAL_TYPE (ValentMediaRemote, valent_media_remote, ADW_TYPE_BREAKPOINT_BIN)
46 : :
47 : : typedef enum {
48 : : PROP_PLAYER = 1,
49 : : PROP_REPEAT,
50 : : PROP_SHUFFLE,
51 : : } ValentMediaRemoteProperty;
52 : :
53 : : static GParamSpec *properties[PROP_SHUFFLE + 1] = { NULL, };
54 : :
55 : :
56 : : static gboolean
57 : 0 : valent_media_remote_timer_tick (gpointer data)
58 : : {
59 : 0 : ValentMediaRemote *self = VALENT_MEDIA_REMOTE (data);
60 : 0 : g_autofree char *length_str = NULL;
61 : 0 : g_autofree char *position_str = NULL;
62 : 0 : double length = 0.0;
63 : 0 : double position = 0.0;
64 : :
65 [ # # ]: 0 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
66 : :
67 : 0 : position = gtk_adjustment_get_value (self->media_position_adjustment) + 1.0;
68 : 0 : length = gtk_adjustment_get_upper (self->media_position_adjustment);
69 [ # # ]: 0 : if (position <= length)
70 : : {
71 : 0 : gtk_adjustment_set_value (self->media_position_adjustment, position);
72 : : }
73 : : else
74 : : {
75 : 0 : position = -1.0;
76 : 0 : length = -1.0;
77 : 0 : gtk_adjustment_set_upper (self->media_position_adjustment, 1.0);
78 : 0 : gtk_adjustment_set_value (self->media_position_adjustment, 1.0);
79 : : }
80 : :
81 : 0 : position_str = valent_media_time_to_string ((int64_t)(position * 1000L),
82 : : TOTEM_TIME_FLAG_NONE);
83 : 0 : gtk_label_set_label (self->media_position_current, position_str);
84 : :
85 : 0 : length_str = valent_media_time_to_string ((int64_t)(length * 1000L),
86 : : TOTEM_TIME_FLAG_NONE);
87 : 0 : gtk_label_set_label (self->media_position_length, length_str);
88 : :
89 : 0 : return G_SOURCE_CONTINUE;
90 : : }
91 : :
92 : : /*
93 : : * Interface
94 : : */
95 : : static void
96 : 1 : valent_media_remote_update_flags (ValentMediaRemote *self)
97 : : {
98 : 1 : GtkWidget *widget = GTK_WIDGET (self);
99 : 1 : ValentMediaActions flags = VALENT_MEDIA_ACTION_NONE;
100 : :
101 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
102 [ - + ]: 1 : g_assert (VALENT_IS_MEDIA_PLAYER (self->player));
103 : :
104 : 1 : flags = valent_media_player_get_flags (self->player);
105 : :
106 : 1 : gtk_widget_action_set_enabled (widget, "remote.next",
107 : 1 : (flags & VALENT_MEDIA_ACTION_NEXT) != 0);
108 : 1 : gtk_widget_action_set_enabled (widget, "remote.pause",
109 : 1 : (flags & VALENT_MEDIA_ACTION_PAUSE) != 0);
110 : 1 : gtk_widget_action_set_enabled (widget, "remote.play",
111 : : (flags & VALENT_MEDIA_ACTION_PLAY) != 0);
112 : 1 : gtk_widget_action_set_enabled (widget, "remote.previous",
113 : 1 : (flags & VALENT_MEDIA_ACTION_PREVIOUS) != 0);
114 : 1 : }
115 : :
116 : : static void
117 : 1 : valent_media_remote_update_position (ValentMediaRemote *self)
118 : : {
119 : 1 : double length = 0.0;
120 : 1 : double position = 0.0;
121 : 2 : g_autofree char *position_str = NULL;
122 : :
123 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
124 [ - + ]: 1 : g_assert (VALENT_IS_MEDIA_PLAYER (self->player));
125 : :
126 : 1 : position = valent_media_player_get_position (self->player);
127 : 1 : length = gtk_adjustment_get_upper (self->media_position_adjustment);
128 [ - + ]: 1 : if (position <= length)
129 : : {
130 : 0 : gtk_adjustment_set_value (self->media_position_adjustment, position);
131 : : }
132 : : else
133 : : {
134 : 1 : position = -1.0;
135 : 1 : gtk_adjustment_set_upper (self->media_position_adjustment, 1.0);
136 : 1 : gtk_adjustment_set_value (self->media_position_adjustment, 1.0);
137 : : }
138 : :
139 : 1 : position_str = valent_media_time_to_string ((int64_t)(position * 1000L),
140 : : TOTEM_TIME_FLAG_NONE);
141 : 1 : gtk_label_set_label (self->media_position_current, position_str);
142 : 1 : }
143 : :
144 : : static void
145 : 1 : valent_media_remote_update_metadata (ValentMediaRemote *self)
146 : : {
147 : 2 : g_autoptr (GVariant) metadata = NULL;
148 [ + - ]: 1 : g_autoptr (GFile) art_file = NULL;
149 [ - + ]: 1 : g_autofree const char **artists = NULL;
150 : 1 : g_autofree char *length_str = NULL;
151 : 1 : const char *title;
152 : 1 : const char *album;
153 : 1 : const char *art_url;
154 : 1 : int64_t length_us = 0;
155 : 1 : double length = -1.0;
156 : :
157 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
158 [ - + ]: 1 : g_assert (VALENT_IS_MEDIA_PLAYER (self->player));
159 : :
160 : 1 : metadata = valent_media_player_get_metadata (self->player);
161 : :
162 [ - + ]: 1 : if (g_variant_lookup (metadata, "xesam:artist", "^a&s", &artists) &&
163 [ # # # # ]: 0 : artists[0] != NULL && *artists[0] != '\0')
164 : 0 : {
165 : 0 : g_autofree char *artist = NULL;
166 : :
167 : 0 : artist = g_strjoinv (", ", (char **)artists);
168 : 0 : gtk_label_set_label (self->media_artist, artist);
169 : : }
170 : : else
171 : : {
172 : 1 : gtk_label_set_label (self->media_artist, "");
173 : : }
174 : :
175 [ - + ]: 1 : if (g_variant_lookup (metadata, "xesam:album", "&s", &album))
176 : 0 : gtk_label_set_label (self->media_album, album);
177 : : else
178 : 1 : gtk_label_set_label (self->media_album, "");
179 : :
180 [ - + ]: 1 : if (g_variant_lookup (metadata, "xesam:title", "&s", &title))
181 : 0 : gtk_label_set_label (self->media_title, title);
182 : : else
183 : 1 : gtk_label_set_label (self->media_title, "");
184 : :
185 [ - + ]: 1 : if (g_variant_lookup (metadata, "mpris:artUrl", "&s", &art_url))
186 : 0 : art_file = g_file_new_for_uri (art_url);
187 : :
188 : 1 : gtk_picture_set_file (self->media_art_image, art_file);
189 [ + - ]: 2 : gtk_stack_set_visible_child_name (self->media_art_stack,
190 : : art_file != NULL ? "image" : "icon");
191 : :
192 : : /* Convert microseconds to seconds */
193 [ - + ]: 1 : if (g_variant_lookup (metadata, "mpris:length", "x", &length_us))
194 : 0 : length = length_us / G_TIME_SPAN_SECOND;
195 : :
196 : 1 : gtk_adjustment_set_upper (self->media_position_adjustment, length);
197 : 1 : length_str = valent_media_time_to_string ((int64_t)(length * 1000L),
198 : : TOTEM_TIME_FLAG_NONE);
199 : 1 : gtk_label_set_label (self->media_position_length, length_str);
200 : :
201 : 1 : valent_media_remote_update_position (self);
202 : 1 : }
203 : :
204 : : static void
205 : 1 : valent_media_remote_update_repeat (ValentMediaRemote *self)
206 : : {
207 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
208 : :
209 : 1 : g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_REPEAT]);
210 : 1 : }
211 : :
212 : : static void
213 : 1 : valent_media_remote_update_shuffle (ValentMediaRemote *self)
214 : : {
215 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
216 : :
217 : 1 : g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHUFFLE]);
218 : 1 : }
219 : :
220 : : static void
221 : 1 : valent_media_remote_update_state (ValentMediaRemote *self)
222 : : {
223 : 1 : ValentMediaState state;
224 : :
225 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
226 [ - + ]: 1 : g_assert (VALENT_IS_MEDIA_PLAYER (self->player));
227 : :
228 : 1 : state = valent_media_player_get_state (self->player);
229 [ - + ]: 1 : if (state == VALENT_MEDIA_STATE_PLAYING)
230 : : {
231 : 0 : g_object_set (self->play_pause_button,
232 : : "action-name", "remote.pause",
233 : : "icon-name", "media-playback-pause-symbolic",
234 : 0 : "tooltip-text", _("Pause"),
235 : : NULL);
236 : :
237 [ # # ]: 0 : if (self->timer_id == 0)
238 : 0 : self->timer_id = g_timeout_add_seconds (1, valent_media_remote_timer_tick, self);
239 : : }
240 : : else
241 : : {
242 : 1 : g_object_set (self->play_pause_button,
243 : : "action-name", "remote.play",
244 : : "icon-name", "media-playback-start-symbolic",
245 : 1 : "tooltip-text", _("Play"),
246 : : NULL);
247 [ - + ]: 1 : g_clear_handle_id (&self->timer_id, g_source_remove);
248 : : }
249 : :
250 [ + - ]: 1 : if (state == VALENT_MEDIA_STATE_STOPPED)
251 : : {
252 : 1 : g_object_freeze_notify (G_OBJECT (self->media_position_adjustment));
253 : 1 : gtk_adjustment_set_value (self->media_position_adjustment, 0.0);
254 : 1 : gtk_adjustment_set_upper (self->media_position_adjustment, 0.0);
255 : 1 : g_object_thaw_notify (G_OBJECT (self->media_position_adjustment));
256 : : }
257 : :
258 : 1 : valent_media_remote_update_metadata (self);
259 : 1 : }
260 : :
261 : : static void
262 : 1 : valent_media_remote_update_volume (ValentMediaRemote *self)
263 : : {
264 : 1 : double volume = 0.0;
265 : :
266 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
267 : :
268 : 1 : volume = valent_media_player_get_volume (self->player);
269 : 1 : gtk_scale_button_set_value (GTK_SCALE_BUTTON (self->volume_button), volume);
270 : 1 : }
271 : :
272 : : static void
273 : 0 : on_player_changed (ValentMediaPlayer *player,
274 : : GParamSpec *pspec,
275 : : ValentMediaRemote *self)
276 : : {
277 : 0 : const char *name = g_param_spec_get_name (pspec);
278 : :
279 [ # # ]: 0 : if (self->player == NULL)
280 : : return;
281 : :
282 [ # # ]: 0 : if (g_str_equal (name, "flags"))
283 : 0 : valent_media_remote_update_flags (self);
284 [ # # ]: 0 : else if (g_str_equal (name, "metadata"))
285 : 0 : valent_media_remote_update_metadata (self);
286 [ # # ]: 0 : else if (g_str_equal (name, "position"))
287 : 0 : valent_media_remote_update_position (self);
288 [ # # ]: 0 : else if (g_str_equal (name, "repeat"))
289 : 0 : valent_media_remote_update_repeat (self);
290 [ # # ]: 0 : else if (g_str_equal (name, "shuffle"))
291 : 0 : valent_media_remote_update_shuffle (self);
292 [ # # ]: 0 : else if (g_str_equal (name, "state"))
293 : 0 : valent_media_remote_update_state (self);
294 [ # # ]: 0 : else if (g_str_equal (name, "volume"))
295 : 0 : valent_media_remote_update_volume (self);
296 : : }
297 : :
298 : : static gboolean
299 : 0 : on_change_value_cb (gpointer data)
300 : : {
301 : 0 : ValentMediaRemote *self = VALENT_MEDIA_REMOTE (data);
302 : 0 : double lower, upper, value, page_size;
303 : :
304 [ # # ]: 0 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
305 : :
306 : 0 : self->seek_id = 0;
307 : :
308 [ # # ]: 0 : if (self->player == NULL)
309 : : return G_SOURCE_REMOVE;
310 : :
311 : 0 : lower = gtk_adjustment_get_lower (self->media_position_adjustment);
312 : 0 : upper = gtk_adjustment_get_upper (self->media_position_adjustment);
313 : 0 : value = gtk_adjustment_get_value (self->media_position_adjustment);
314 : 0 : page_size = gtk_adjustment_get_page_size (self->media_position_adjustment);
315 [ # # ]: 0 : value = CLAMP (value, lower, (upper - page_size));
316 : :
317 : 0 : valent_media_player_set_position (self->player, value);
318 : :
319 : 0 : return G_SOURCE_REMOVE;
320 : : }
321 : :
322 : : static gboolean
323 : 0 : on_change_value (GtkRange *range,
324 : : GtkScrollType scroll,
325 : : double value,
326 : : ValentMediaRemote *self)
327 : : {
328 : 0 : double lower, upper, page_size;
329 : :
330 [ # # ]: 0 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
331 : :
332 [ # # ]: 0 : if (self->player == NULL)
333 : : return GDK_EVENT_STOP;
334 : :
335 [ # # ]: 0 : g_clear_handle_id (&self->seek_id, g_source_remove);
336 : 0 : self->seek_id = g_timeout_add (MEDIA_SEEK_DELAY, on_change_value_cb, self);
337 : :
338 : 0 : lower = gtk_adjustment_get_lower (self->media_position_adjustment);
339 : 0 : upper = gtk_adjustment_get_upper (self->media_position_adjustment);
340 : 0 : page_size = gtk_adjustment_get_page_size (self->media_position_adjustment);
341 [ # # ]: 0 : value = CLAMP (value, lower, (upper - page_size));
342 : :
343 : 0 : gtk_adjustment_set_value (self->media_position_adjustment, value);
344 : :
345 : 0 : return GDK_EVENT_STOP;
346 : : }
347 : :
348 : : static void
349 : 1 : on_volume_changed (GtkScaleButton *button,
350 : : double value,
351 : : ValentMediaRemote *self)
352 : : {
353 [ + - ]: 1 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
354 : :
355 [ + - ]: 1 : if (self->player == NULL)
356 : : return;
357 : :
358 [ - + - + ]: 1 : if (!G_APPROX_VALUE (valent_media_player_get_volume (self->player), value, 0.01))
359 : 0 : valent_media_player_set_volume (self->player, value);
360 : : }
361 : :
362 : : /*
363 : : * GAction
364 : : */
365 : : static void
366 : 0 : remote_player_action (GtkWidget *widget,
367 : : const char *action_name,
368 : : GVariant *parameter)
369 : : {
370 : 0 : ValentMediaRemote *self = VALENT_MEDIA_REMOTE (widget);
371 : :
372 [ # # ]: 0 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
373 : :
374 [ # # # # ]: 0 : if (self->player == NULL || action_name == NULL)
375 : : return;
376 : :
377 [ # # ]: 0 : else if (g_str_equal (action_name, "remote.next"))
378 : 0 : valent_media_player_next (self->player);
379 : :
380 [ # # ]: 0 : else if (g_str_equal (action_name, "remote.pause"))
381 : 0 : valent_media_player_pause (self->player);
382 : :
383 [ # # ]: 0 : else if (g_str_equal (action_name, "remote.play"))
384 : 0 : valent_media_player_play (self->player);
385 : :
386 [ # # ]: 0 : else if (g_str_equal (action_name, "remote.previous"))
387 : 0 : valent_media_player_previous (self->player);
388 : : }
389 : :
390 : : /*
391 : : * ValentMediaRemote
392 : : */
393 : : static void
394 : 4 : valent_media_remote_set_player (ValentMediaRemote *self,
395 : : ValentMediaPlayer *player)
396 : : {
397 [ + - ]: 4 : g_assert (VALENT_IS_MEDIA_REMOTE (self));
398 [ + + - + ]: 4 : g_assert (player == NULL || VALENT_IS_MEDIA_PLAYER (player));
399 : :
400 [ + + ]: 4 : if (self->player == player)
401 : : return;
402 : :
403 [ + + ]: 2 : if (self->player != NULL)
404 : : {
405 [ - + ]: 1 : g_clear_handle_id (&self->seek_id, g_source_remove);
406 [ - + ]: 1 : g_clear_handle_id (&self->timer_id, g_source_remove);
407 : 1 : g_signal_handlers_disconnect_by_func (self->player, on_player_changed, self);
408 [ + - ]: 1 : g_clear_object (&self->player);
409 : : }
410 : :
411 [ + + ]: 2 : if (player != NULL)
412 : : {
413 : 1 : self->player = g_object_ref (player);
414 : 1 : g_signal_connect_object (self->player,
415 : : "notify",
416 : : G_CALLBACK (on_player_changed),
417 : : self,
418 : : G_CONNECT_DEFAULT);
419 : :
420 : 1 : valent_media_remote_update_flags (self);
421 : 1 : valent_media_remote_update_repeat (self);
422 : 1 : valent_media_remote_update_shuffle (self);
423 : 1 : valent_media_remote_update_state (self);
424 : 1 : valent_media_remote_update_volume (self);
425 : 1 : gtk_widget_set_sensitive (GTK_WIDGET (self->playback_options), TRUE);
426 : 1 : gtk_widget_set_sensitive (GTK_WIDGET (self->volume_button), TRUE);
427 : : }
428 : : else
429 : : {
430 : 1 : gtk_stack_set_visible_child_name (self->media_art_stack, "icon");
431 : 1 : gtk_label_set_label (self->media_artist, "");
432 : 1 : gtk_label_set_label (self->media_title, "");
433 : 1 : gtk_label_set_label (self->media_album, "");
434 : :
435 : 1 : gtk_adjustment_set_value (self->media_position_adjustment, 0.0);
436 : 1 : gtk_adjustment_set_upper (self->media_position_adjustment, 0.0);
437 : 1 : gtk_label_set_label (self->media_position_current, "");
438 : 1 : gtk_label_set_label (self->media_position_length, "");
439 : :
440 : 1 : gtk_widget_action_set_enabled (GTK_WIDGET (self), "remote.next", FALSE);
441 : 1 : gtk_widget_action_set_enabled (GTK_WIDGET (self), "remote.pause", FALSE);
442 : 1 : gtk_widget_action_set_enabled (GTK_WIDGET (self), "remote.play", FALSE);
443 : 1 : gtk_widget_action_set_enabled (GTK_WIDGET (self), "remote.previous", FALSE);
444 : 1 : gtk_widget_set_sensitive (GTK_WIDGET (self->playback_options), FALSE);
445 : 1 : gtk_widget_set_sensitive (GTK_WIDGET (self->volume_button), FALSE);
446 : : }
447 : 2 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PLAYER]);
448 : : }
449 : :
450 : : /*
451 : : * GObject
452 : : */
453 : : static void
454 : 1 : valent_media_remote_dispose (GObject *object)
455 : : {
456 : 1 : ValentMediaRemote *self = VALENT_MEDIA_REMOTE (object);
457 : :
458 [ - + ]: 1 : if (self->player != NULL)
459 : : {
460 [ # # ]: 0 : g_clear_handle_id (&self->seek_id, g_source_remove);
461 [ # # ]: 0 : g_clear_handle_id (&self->timer_id, g_source_remove);
462 : 0 : g_signal_handlers_disconnect_by_data (self->player, self);
463 [ # # ]: 0 : g_clear_object (&self->player);
464 : : }
465 : :
466 : 1 : G_OBJECT_CLASS (valent_media_remote_parent_class)->dispose (object);
467 : 1 : }
468 : :
469 : : static void
470 : 8 : valent_media_remote_get_property (GObject *object,
471 : : guint prop_id,
472 : : GValue *value,
473 : : GParamSpec *pspec)
474 : : {
475 : 8 : ValentMediaRemote *self = VALENT_MEDIA_REMOTE (object);
476 : :
477 [ - + + - ]: 8 : switch ((ValentMediaRemoteProperty)prop_id)
478 : : {
479 : 0 : case PROP_PLAYER:
480 : 0 : g_value_set_object (value, self->player);
481 : 0 : break;
482 : :
483 : 4 : case PROP_REPEAT:
484 [ + + ]: 4 : if (self->player != NULL)
485 : 1 : g_value_set_enum (value, valent_media_player_get_repeat (self->player));
486 : : else
487 : 3 : g_value_set_enum (value, VALENT_MEDIA_REPEAT_NONE);
488 : : break;
489 : :
490 : 4 : case PROP_SHUFFLE:
491 [ + + ]: 4 : if (self->player != NULL)
492 : 1 : g_value_set_boolean (value, valent_media_player_get_shuffle (self->player));
493 : : else
494 : 3 : g_value_set_boolean (value, FALSE);
495 : : break;
496 : :
497 : 0 : default:
498 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
499 : : }
500 : 8 : }
501 : :
502 : : static void
503 : 4 : valent_media_remote_set_property (GObject *object,
504 : : guint prop_id,
505 : : const GValue *value,
506 : : GParamSpec *pspec)
507 : : {
508 : 4 : ValentMediaRemote *self = VALENT_MEDIA_REMOTE (object);
509 : :
510 [ + - - - ]: 4 : switch ((ValentMediaRemoteProperty)prop_id)
511 : : {
512 : 4 : case PROP_PLAYER:
513 : 4 : valent_media_remote_set_player (self, g_value_get_object (value));
514 : 4 : break;
515 : :
516 : 0 : case PROP_REPEAT:
517 [ # # ]: 0 : if (self->player != NULL)
518 : 0 : valent_media_player_set_repeat (self->player, g_value_get_enum (value));
519 : : break;
520 : :
521 : 0 : case PROP_SHUFFLE:
522 [ # # ]: 0 : if (self->player != NULL)
523 : 0 : valent_media_player_set_shuffle (self->player, g_value_get_boolean (value));
524 : : break;
525 : :
526 : 0 : default:
527 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
528 : : }
529 : 4 : }
530 : :
531 : : static void
532 : 1 : valent_media_remote_class_init (ValentMediaRemoteClass *klass)
533 : : {
534 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
535 : 1 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
536 : :
537 : 1 : object_class->dispose = valent_media_remote_dispose;
538 : 1 : object_class->get_property = valent_media_remote_get_property;
539 : 1 : object_class->set_property = valent_media_remote_set_property;
540 : :
541 : 1 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-media-remote.ui");
542 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_art_stack);
543 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_art_image);
544 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_title);
545 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_artist);
546 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_album);
547 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_position);
548 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_position_adjustment);
549 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_position_current);
550 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, media_position_length);
551 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, play_pause_button);
552 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, playback_options);
553 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentMediaRemote, volume_button);
554 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_change_value);
555 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_volume_changed);
556 : :
557 : 1 : gtk_widget_class_install_action (widget_class, "remote.next", NULL, remote_player_action);
558 : 1 : gtk_widget_class_install_action (widget_class, "remote.pause", NULL, remote_player_action);
559 : 1 : gtk_widget_class_install_action (widget_class, "remote.play", NULL, remote_player_action);
560 : 1 : gtk_widget_class_install_action (widget_class, "remote.previous", NULL, remote_player_action);
561 : :
562 : 2 : properties [PROP_PLAYER] =
563 : 1 : g_param_spec_object ("player", NULL, NULL,
564 : : VALENT_TYPE_MEDIA_PLAYER,
565 : : (G_PARAM_READWRITE |
566 : : G_PARAM_EXPLICIT_NOTIFY |
567 : : G_PARAM_STATIC_STRINGS));
568 : :
569 : 2 : properties [PROP_REPEAT] =
570 : 1 : g_param_spec_enum ("repeat", NULL, NULL,
571 : : VALENT_TYPE_MEDIA_REPEAT,
572 : : VALENT_MEDIA_REPEAT_NONE,
573 : : (G_PARAM_READWRITE |
574 : : G_PARAM_EXPLICIT_NOTIFY |
575 : : G_PARAM_STATIC_STRINGS));
576 : :
577 : 2 : properties [PROP_SHUFFLE] =
578 : 1 : g_param_spec_boolean ("shuffle", NULL, NULL,
579 : : FALSE,
580 : : (G_PARAM_READWRITE |
581 : : G_PARAM_EXPLICIT_NOTIFY |
582 : : G_PARAM_STATIC_STRINGS));
583 : :
584 : 1 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
585 : :
586 : 1 : gtk_widget_class_install_property_action (widget_class, "remote.repeat", "repeat");
587 : 1 : gtk_widget_class_install_property_action (widget_class, "remote.shuffle", "shuffle");
588 : 1 : }
589 : :
590 : : static void
591 : 1 : valent_media_remote_init (ValentMediaRemote *self)
592 : : {
593 : 1 : GtkWidget *child;
594 : :
595 : 1 : gtk_widget_init_template (GTK_WIDGET (self));
596 : :
597 : 1 : for (child = gtk_widget_get_first_child (GTK_WIDGET (self->volume_button));
598 [ + + ]: 3 : child != NULL;
599 : 2 : child = gtk_widget_get_next_sibling (child))
600 : : {
601 [ + - + + : 2 : if (!GTK_IS_TOGGLE_BUTTON (child))
+ - ]
602 : 1 : continue;
603 : :
604 : 1 : gtk_widget_set_css_classes (child, (const char *[]){
605 : : "circular",
606 : : "toggle",
607 : : NULL
608 : : });
609 : : }
610 : 1 : }
611 : :
|