From ca4873e07fcb846c7e13eeeb0d5a87b67b88c4b7 Mon Sep 17 00:00:00 2001 From: Joshua Strobl Date: Sat, 10 Jul 2021 01:20:20 +0300 Subject: [PATCH] Implement double-click logic in our Track Table to immediately start playback of track and respective playlist. Rewrote some legacy KotoCurrentPlaylist code that relied on communicating KotoPlaylist change via a property change. Changed to using a signal. Implemented new koto_album_create_playlist function so we can use our KotoPlaylist generation in the KotoActionBar. Prior to this change, clicking "Play" on a given track in a DiscView would only play that specific track and never give you the opportunity to go backwards or forwards. Now we will use our "continue on playlist" config to determine that behaviour and dynamically generate a playlist when the actionbar is relative to an Album. This functionality is leveraged with a change to koto_current_playlist_set_playlist that now requires a gboolean for determining if we should play immediately as well. Added type checks in our KotoPlayerbar progress / range usage. Prior to this change, you would get a (harmless) GLib Warning when closing the application. Fixed KotoPlayerbar info updating returning early when it failed to get an Album for a track, resulting in the artwork never being reset. Fixed multiple warnings when missing metadata and using g_variants in our koto_playback_set_track_by_uuid. --- src/components/koto-action-bar.c | 25 ++++++-- src/components/track-table.c | 56 +++++++++++++++- src/components/track-table.h | 8 +++ src/indexer/album-playlist-funcs.h | 25 ++++++++ src/indexer/album.c | 67 ++++++++++++------- src/koto-playerbar.c | 69 +++++++++++++------- src/pages/music/artist-view.c | 2 +- src/pages/music/disc-view.c | 4 ++ src/pages/playlist/list.c | 2 +- src/playback/engine.c | 31 ++++----- src/playback/engine.h | 7 +- src/playlist/current.c | 100 ++++++++++------------------- src/playlist/current.h | 11 +++- 13 files changed, 265 insertions(+), 142 deletions(-) create mode 100644 src/indexer/album-playlist-funcs.h diff --git a/src/components/koto-action-bar.c b/src/components/koto-action-bar.c index 31ddd0f..3270d8a 100644 --- a/src/components/koto-action-bar.c +++ b/src/components/koto-action-bar.c @@ -18,7 +18,9 @@ #include #include #include "koto-action-bar.h" +#include "../config/config.h" #include "../db/cartographer.h" +#include "../indexer/album-playlist-funcs.h" #include "../pages/music/music-local.h" #include "../playlist/add-remove-track-popover.h" #include "../playlist/current.h" @@ -29,6 +31,7 @@ extern KotoAddRemoveTrackPopover * koto_add_remove_track_popup; extern KotoCartographer * koto_maps; +extern KotoConfig * config; extern KotoCurrentPlaylist * current_playlist; extern KotoPageMusicLocal * music_local_page; extern KotoPlaybackEngine * playback_engine; @@ -252,16 +255,26 @@ void koto_action_bar_handle_play_track_button_clicked( goto doclose; } - if (self->relative == KOTO_ACTION_BAR_IS_PLAYLIST_RELATIVE) { // Relative to a playlist - KotoPlaylist * playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->current_playlist_uuid); + KotoPlaylist * playlist = NULL; - if (KOTO_IS_PLAYLIST(playlist)) { // Is a playlist - koto_current_playlist_set_playlist(current_playlist, playlist); // Update our playlist to the one associated with the track we are playing - koto_playlist_set_track_as_current(playlist, koto_track_get_uuid(track)); // Get this track as the current track in the position + if (self->relative == KOTO_ACTION_BAR_IS_PLAYLIST_RELATIVE) { // Relative to a playlist + playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->current_playlist_uuid); + } else if (self->relative == KOTO_ACTION_BAR_IS_ALBUM_RELATIVE) { // Relative to an Album + KotoAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, self->current_album_uuid); // Get the Album + + if (KOTO_IS_ALBUM(album)) { // Have an Album + playlist = koto_album_create_playlist(album); // Create our playlist dynamically for the Album } } - koto_playback_engine_set_track_by_uuid(playback_engine, koto_track_get_uuid(track), TRUE); // Set the track to play + if (KOTO_IS_PLAYLIST(playlist)) { // Is a playlist + koto_current_playlist_set_playlist(current_playlist, playlist, FALSE); // Update our playlist to the one associated with the track we are playing + koto_playlist_set_track_as_current(playlist, koto_track_get_uuid(track)); // Get this track as the current track in the position + } + + gboolean continue_playback = FALSE; + g_object_get(config, "playback-continue-on-playlist", &continue_playback, NULL); + koto_playback_engine_set_track_by_uuid(playback_engine, koto_track_get_uuid(track), continue_playback); // Set the track to play doclose: koto_action_bar_close(self); diff --git a/src/components/track-table.c b/src/components/track-table.c index e1ec15b..0d3cd7f 100644 --- a/src/components/track-table.c +++ b/src/components/track-table.c @@ -18,6 +18,8 @@ #include #include #include "../db/cartographer.h" +#include "../playback/engine.h" +#include "../playlist/current.h" #include "../playlist/playlist.h" #include "../koto-button.h" #include "../koto-utils.h" @@ -27,6 +29,8 @@ extern KotoActionBar * action_bar; extern KotoCartographer * koto_maps; +extern KotoCurrentPlaylist * current_playlist; +extern KotoPlaybackEngine * playback_engine; extern KotoWindow * main_window; struct _KotoTrackTable { @@ -106,7 +110,8 @@ void koto_track_table_bind_track_item( ) { (void) factory; - GtkWidget * track_position_label = gtk_widget_get_first_child(gtk_list_item_get_child(item)); + GtkWidget * box = gtk_list_item_get_child(item); + GtkWidget * track_position_label = gtk_widget_get_first_child(box); GtkWidget * track_name_label = gtk_widget_get_next_sibling(track_position_label); GtkWidget * track_album_label = gtk_widget_get_next_sibling(track_name_label); GtkWidget * track_artist_label = gtk_widget_get_next_sibling(track_album_label); @@ -150,6 +155,12 @@ void koto_track_table_bind_track_item( if (KOTO_IS_ARTIST(artist)) { gtk_label_set_label(GTK_LABEL(track_artist_label), koto_artist_get_name(artist)); // Get the name of the artist and set it to the label } + + GList * data = NULL; + data = g_list_append(data, self); // Reference self first + data = g_list_append(data, koto_track_get_uuid(track)); // Next reference the track UUID string + + g_object_set_data(G_OBJECT(box), "data", data); // Bind our list data } void koto_track_table_create_tracks_header(KotoTrackTable * self) { @@ -239,6 +250,45 @@ void koto_track_table_handle_track_artist_clicked( koto_track_table_set_playlist_model(self, KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ARTIST); } +void koto_track_table_item_handle_clicked( + GtkGesture * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) x; + (void) y; + + if (n_press != 2) { // Not a double click or tap + return; + } + + GObject * track_item_as_object = G_OBJECT(user_data); + + if (!G_IS_OBJECT(track_item_as_object)) { // Not a GObject + return; + } + + GList * data = g_object_get_data(track_item_as_object, "data"); + + KotoTrackTable * self = g_list_nth_data(data, 0); + gchar * track_uuid = g_list_nth_data(data, 1); + + if (!koto_utils_is_string_valid(track_uuid)) { // Not a valid string + return; + } + + gtk_selection_model_unselect_all(self->selection_model); + gtk_widget_grab_focus(GTK_WIDGET(main_window)); // Focus on the window + koto_action_bar_toggle_reveal(action_bar, FALSE); + koto_action_bar_close(action_bar); // Close the action bar + koto_current_playlist_set_playlist(current_playlist, self->playlist, FALSE); // Set the current playlist to the artist's playlist but do not play immediately + koto_playlist_set_track_as_current(self->playlist, track_uuid); // Set this track as the current one for the playlist + koto_playback_engine_set_track_by_uuid(playback_engine, track_uuid, FALSE); // Tell our playback engine to start playing at this track +} + void koto_track_table_handle_track_name_clicked( GtkGestureClick * gesture, int n_press, @@ -476,6 +526,10 @@ void koto_track_table_setup_track_item( gtk_size_group_add_widget(self->track_artist_size_group, track_artist); gtk_list_item_set_child(item, item_content); + + GtkGesture * double_click_gesture = gtk_gesture_click_new(); // Create our new GtkGesture for double-click handling + gtk_widget_add_controller(item_content, GTK_EVENT_CONTROLLER(double_click_gesture)); // Have our item handle double clicking + g_signal_connect(double_click_gesture, "released", G_CALLBACK(koto_track_table_item_handle_clicked), item_content); } KotoTrackTable * koto_track_table_new() { diff --git a/src/components/track-table.h b/src/components/track-table.h index 5b73212..287d9b4 100644 --- a/src/components/track-table.h +++ b/src/components/track-table.h @@ -73,6 +73,14 @@ void koto_track_table_handle_track_name_clicked( gpointer user_data ); +void koto_track_table_handle_track_name_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + void koto_track_table_handle_track_num_clicked( GtkGestureClick * gesture, int n_press, diff --git a/src/indexer/album-playlist-funcs.h b/src/indexer/album-playlist-funcs.h new file mode 100644 index 0000000..083f284 --- /dev/null +++ b/src/indexer/album-playlist-funcs.h @@ -0,0 +1,25 @@ +/* album-playlist-funcs.h + * + * Copyright 2021 Joshua Strobl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../playlist/playlist.h" +#include "structs.h" + +G_BEGIN_DECLS + +KotoPlaylist * koto_album_create_playlist(KotoAlbum * self); + +G_END_DECLS \ No newline at end of file diff --git a/src/indexer/album.c b/src/indexer/album.c index 4f681fa..06b9f73 100644 --- a/src/indexer/album.c +++ b/src/indexer/album.c @@ -24,7 +24,7 @@ #include "../playlist/current.h" #include "../playlist/playlist.h" #include "../koto-utils.h" -#include "structs.h" +#include "album-playlist-funcs.h" #include "track-helpers.h" extern KotoCartographer * koto_maps; @@ -284,6 +284,42 @@ void koto_album_commit(KotoAlbum * self) { } } +KotoPlaylist * koto_album_create_playlist(KotoAlbum * self) { + if (!KOTO_IS_ALBUM(self)) { // Not an album + return NULL; + } + + if (self->tracks == NULL) { // No files to add to the playlist + return NULL; + } + + KotoPlaylist * new_album_playlist = koto_playlist_new(); // Create a new playlist + + g_object_set(new_album_playlist, "ephemeral", TRUE, NULL); // Set as ephemeral / temporary + + // The following section effectively reverses our tracks, so the first is now last. + // It then adds them in reverse order, since our playlist add function will prepend to our queue + // This enables the preservation and defaulting of "newest" first everywhere else, while in albums preserving the rightful order of the album + // e.g. first track (0) being added last is actually first in the playlist's tracks + GList * reversed_tracks = g_list_copy(self->tracks); // Copy our tracks so we can reverse the order + + reversed_tracks = g_list_reverse(reversed_tracks); // Actually reverse it + + GList * t; + + for (t = reversed_tracks; t != NULL; t = t->next) { // For each of the tracks + gchar * track_uuid = t->data; + koto_playlist_add_track_by_uuid(new_album_playlist, track_uuid, FALSE, FALSE); // Add the UUID, skip commit to table since it is temporary + } + + g_list_free(t); + g_list_free(reversed_tracks); + + koto_playlist_apply_model(new_album_playlist, KOTO_PREFERRED_MODEL_TYPE_DEFAULT); // Ensure we are using our default model + + return new_album_playlist; +} + void koto_album_find_album_art(KotoAlbum * self) { if (self->has_album_art) { // If we already have album art return; @@ -588,38 +624,21 @@ void koto_album_set_artist_uuid( } void koto_album_set_as_current_playlist(KotoAlbum * self) { - if (!KOTO_IS_ALBUM(self)) { // Not an album + if (!KOTO_IS_ALBUM(self)) { return; } - if (self->tracks == NULL) { // No files to add to the playlist + if (!KOTO_IS_CURRENT_PLAYLIST(current_playlist)) { return; } - KotoPlaylist * new_album_playlist = koto_playlist_new(); // Create a new playlist + KotoPlaylist * album_playlist = koto_album_create_playlist(self); - g_object_set(new_album_playlist, "ephemeral", TRUE, NULL); // Set as ephemeral / temporary - - // The following section effectively reverses our tracks, so the first is now last. - // It then adds them in reverse order, since our playlist add function will prepend to our queue - // This enables the preservation and defaulting of "newest" first everywhere else, while in albums preserving the rightful order of the album - // e.g. first track (0) being added last is actually first in the playlist's tracks - GList * reversed_tracks = g_list_copy(self->tracks); // Copy our tracks so we can reverse the order - - reversed_tracks = g_list_reverse(reversed_tracks); // Actually reverse it - - GList * t; - - for (t = reversed_tracks; t != NULL; t = t->next) { // For each of the tracks - gchar * track_uuid = t->data; - koto_playlist_add_track_by_uuid(new_album_playlist, track_uuid, FALSE, FALSE); // Add the UUID, skip commit to table since it is temporary + if (!KOTO_IS_PLAYLIST(album_playlist)) { + return; } - g_list_free(t); - g_list_free(reversed_tracks); - - koto_playlist_apply_model(new_album_playlist, KOTO_PREFERRED_MODEL_TYPE_DEFAULT); // Ensure we are using our default model - koto_current_playlist_set_playlist(current_playlist, new_album_playlist); // Set our new current playlist + koto_current_playlist_set_playlist(current_playlist, album_playlist, TRUE); // Set our new current playlist and start playing immediately } void koto_album_set_preparsed_genres( diff --git a/src/koto-playerbar.c b/src/koto-playerbar.c index 423fc38..6625ef9 100644 --- a/src/koto-playerbar.c +++ b/src/koto-playerbar.c @@ -518,6 +518,14 @@ void koto_playerbar_handle_volume_button_change( } void koto_playerbar_reset_progressbar(KotoPlayerBar * bar) { + if (!KOTO_IS_PLAYERBAR(bar)) { + return; + } + + if (!GTK_IS_RANGE(bar->progress_bar)) { + return; + } + gtk_range_set_range(GTK_RANGE(bar->progress_bar), 0, 0); // Reset range gtk_range_set_value(GTK_RANGE(bar->progress_bar), 0); // Set value to 0 } @@ -526,6 +534,14 @@ void koto_playerbar_set_progressbar_duration( KotoPlayerBar * bar, gint64 duration ) { + if (!KOTO_IS_PLAYERBAR(bar)) { + return; + } + + if (!GTK_IS_RANGE(bar->progress_bar)) { + return; + } + if (duration <= 0) { return; } @@ -540,6 +556,14 @@ void koto_playerbar_set_progressbar_value( KotoPlayerBar * bar, double progress ) { + if (!KOTO_IS_PLAYERBAR(bar)) { + return; + } + + if (!GTK_IS_RANGE(bar->progress_bar)) { + return; + } + gtk_range_set_value(GTK_RANGE(bar->progress_bar), progress); } @@ -620,7 +644,7 @@ void koto_playerbar_update_track_info( g_free(artist_uuid); - if ((track_name != NULL) && (strcmp(track_name, "") != 0)) { // Have a track name + if (koto_utils_is_string_valid(track_name)) { // Have a track name gtk_label_set_text(GTK_LABEL(bar->playback_title), track_name); // Set the label } @@ -636,30 +660,29 @@ void koto_playerbar_update_track_info( } } - if (!koto_utils_is_string_valid(album_uuid)) { // Do not have a valid album UUID - return; + gchar * art_path = NULL; + + if (koto_utils_is_string_valid(album_uuid)) { // Have a valid album UUID + KotoAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); + g_free(album_uuid); + + if (KOTO_IS_ALBUM(album)) { + gchar * album_name = NULL; + g_object_get(album, "name", &album_name, "art-path", &art_path, NULL); // Get album name and art path + + if ((album_name != NULL) && (strcmp(album_name, "") != 0)) { // Have an album name + gtk_label_set_text(GTK_LABEL(bar->playback_album), album_name); + gtk_widget_show(bar->playback_album); + } else { + gtk_widget_hide(bar->playback_album); + } + } } - KotoAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); - g_free(album_uuid); - - if (KOTO_IS_ALBUM(album)) { - gchar * album_name = NULL; - gchar * art_path = NULL; - g_object_get(album, "name", &album_name, "art-path", &art_path, NULL); // Get album name and art path - - if ((album_name != NULL) && (strcmp(album_name, "") != 0)) { // Have an album name - gtk_label_set_text(GTK_LABEL(bar->playback_album), album_name); - gtk_widget_show(bar->playback_album); - } else { - gtk_widget_hide(bar->playback_album); - } - - if ((art_path != NULL) && g_path_is_absolute(art_path)) { // Have an album artist path - gtk_image_set_from_file(GTK_IMAGE(bar->artwork), art_path); // Update the art - } else { - gtk_image_set_from_icon_name(GTK_IMAGE(bar->artwork), "audio-x-generic-symbolic"); // Use generic instead - } + if ((art_path != NULL) && g_path_is_absolute(art_path)) { // Have an album artist path + gtk_image_set_from_file(GTK_IMAGE(bar->artwork), art_path); // Update the art + } else { + gtk_image_set_from_icon_name(GTK_IMAGE(bar->artwork), "audio-x-generic-symbolic"); // Use generic instead } } diff --git a/src/pages/music/artist-view.c b/src/pages/music/artist-view.c index 03abfb0..314487f 100644 --- a/src/pages/music/artist-view.c +++ b/src/pages/music/artist-view.c @@ -323,7 +323,7 @@ void koto_artist_view_toggle_playback( return; } - koto_current_playlist_set_playlist(current_playlist, artist_playlist); // Set our playlist to the one associated with the Artist + koto_current_playlist_set_playlist(current_playlist, artist_playlist, TRUE); // Set our playlist to the one associated with the Artist and start playback immediately } KotoArtistView * koto_artist_view_new(KotoArtist * artist) { diff --git a/src/pages/music/disc-view.c b/src/pages/music/disc-view.c index a8487d5..4425baa 100644 --- a/src/pages/music/disc-view.c +++ b/src/pages/music/disc-view.c @@ -208,6 +208,10 @@ void koto_disc_view_handle_selected_rows_changed( ) { KotoDiscView * self = user_data; + if (!KOTO_IS_DISC_VIEW(self)) { + return; + } + gchar * album_uuid = koto_album_get_album_uuid(self->album); // Get the UUID if (!koto_utils_is_string_valid(album_uuid)) { // Not set diff --git a/src/pages/playlist/list.c b/src/pages/playlist/list.c index c5354d5..f35f3e2 100644 --- a/src/pages/playlist/list.c +++ b/src/pages/playlist/list.c @@ -209,7 +209,7 @@ void koto_playlist_page_handle_cover_art_clicked( return; } - koto_current_playlist_set_playlist(current_playlist, self->playlist); + koto_current_playlist_set_playlist(current_playlist, self->playlist, TRUE); // Switch to this playlist and start playing immediately } void koto_playlist_page_handle_edit_button_clicked( diff --git a/src/playback/engine.c b/src/playback/engine.c index abe3e42..e449842 100644 --- a/src/playback/engine.c +++ b/src/playback/engine.c @@ -238,7 +238,7 @@ static void koto_playback_engine_init(KotoPlaybackEngine * self) { g_signal_connect(config, "notify::maintain-shuffle", G_CALLBACK(koto_playback_engine_apply_configuration_state), self); // Handle changes to our config if (KOTO_IS_CURRENT_PLAYLIST(current_playlist)) { - g_signal_connect(current_playlist, "notify::current-playlist", G_CALLBACK(koto_playback_engine_current_playlist_changed), self); + g_signal_connect(current_playlist, "playlist-changed", G_CALLBACK(koto_playback_engine_handle_current_playlist_changed), self); } } @@ -287,29 +287,26 @@ void koto_playback_engine_backwards(KotoPlaybackEngine * self) { koto_playback_engine_set_track_by_uuid(self, koto_playlist_go_to_previous(playlist), FALSE); } -void koto_playback_engine_current_playlist_changed( +void koto_playback_engine_handle_current_playlist_changed( KotoCurrentPlaylist * current_pl, - guint prop_id, - KotoPlaybackEngine * self + KotoPlaylist * playlist, + gboolean play_immediately, + gpointer user_data ) { (void) current_pl; - (void) prop_id; + KotoPlaybackEngine * self = user_data; if (!KOTO_IS_PLAYBACK_ENGINE(self)) { return; } - KotoPlaylist * playlist = koto_current_playlist_get_playlist(current_playlist); // Get the current playlist - - if (!KOTO_IS_PLAYLIST(playlist)) { // If we do not have a playlist currently - return; - } - if (self->is_shuffle_enabled) { // If shuffle is enabled koto_playback_engine_set_track_shuffle(self, self->via_config_maintain_shuffle); // Set to our maintain shuffle value } - koto_playback_engine_set_track_by_uuid(playback_engine, koto_playlist_go_to_next(playlist), FALSE); // Go to "next" which is the first track + if (play_immediately) { // Should play immediately + koto_playback_engine_set_track_by_uuid(self, koto_playlist_go_to_next(playlist), FALSE); // Go to "next" which is the first track + } } void koto_playback_engine_forwards(KotoPlaybackEngine * self) { @@ -495,6 +492,10 @@ void koto_playback_engine_set_track_by_uuid( gchar * track_uuid, gboolean playing_specific_track ) { + if (!KOTO_IS_PLAYBACK_ENGINE(self)) { + return; + } + if (!koto_utils_is_string_valid(track_uuid)) { // If this is not a valid track uuid string return; } @@ -534,12 +535,12 @@ void koto_playback_engine_set_track_by_uuid( const gchar * track_name = g_variant_get_string(track_name_var, NULL); // Get the string of the track name GVariant * album_name_var = g_variant_dict_lookup_value(metadata_dict, "xesam:album", NULL); // Get the GVariant for the album name - const gchar * album_name = g_variant_get_string(album_name_var, NULL); // Get the string for the album name + gchar * album_name = (album_name_var != NULL) ? g_strdup(g_variant_get_string(album_name_var, NULL)) : NULL; // Get the string for the album name GVariant * artist_name_var = g_variant_dict_lookup_value(metadata_dict, "playbackengine:artist", NULL); // Get the GVariant for the name of the artist - const gchar * artist_name = g_variant_get_string(artist_name_var, NULL); // Get the string for the artist name + gchar * artist_name = g_strdup(g_variant_get_string(artist_name_var, NULL)); // Get the string for the artist name - gchar * artist_album_combo = g_strjoin(" - ", artist_name, album_name, NULL); // Join artist and album name separated by " - " + gchar * artist_album_combo = koto_utils_is_string_valid(album_name) ? g_strjoin(" - ", artist_name, album_name, NULL) : artist_name; // Join artist and album name separated by " - " gchar * icon_name = "audio-x-generic-symbolic"; diff --git a/src/playback/engine.h b/src/playback/engine.h index f90f4a7..88889fb 100644 --- a/src/playback/engine.h +++ b/src/playback/engine.h @@ -52,10 +52,11 @@ void koto_playback_engine_apply_configuration_state( void koto_playback_engine_backwards(KotoPlaybackEngine * self); -void koto_playback_engine_current_playlist_changed( +void koto_playback_engine_handle_current_playlist_changed( KotoCurrentPlaylist * current_pl, - guint prop_id, - KotoPlaybackEngine * self + KotoPlaylist * playlist, + gboolean play_immediately, + gpointer user_data ); void koto_playback_engine_forwards(KotoPlaybackEngine * self); diff --git a/src/playlist/current.c b/src/playlist/current.c index 52c179b..9275340 100644 --- a/src/playlist/current.c +++ b/src/playlist/current.c @@ -19,13 +19,12 @@ #include "current.h" enum { - PROP_0, - PROP_CURRENT_PLAYLIST, - N_PROPERTIES + SIGNAL_PLAYLIST_CHANGED, + N_SIGNALS }; -static GParamSpec * props[N_PROPERTIES] = { - NULL, +static guint signals[N_SIGNALS] = { + 0 }; KotoCurrentPlaylist * current_playlist = NULL; @@ -35,87 +34,50 @@ struct _KotoCurrentPlaylist { KotoPlaylist * current_playlist; }; -G_DEFINE_TYPE(KotoCurrentPlaylist, koto_current_playlist, G_TYPE_OBJECT); +struct _KotoCurrentPlaylistClass { + GObjectClass parent_class; -static void koto_current_playlist_get_property( - GObject * obj, - guint prop_id, - GValue * val, - GParamSpec * spec -); - -static void koto_current_playlist_set_property( - GObject * obj, - guint prop_id, - const GValue * val, - GParamSpec * spec -); + void (* playlist_changed) ( + KotoCurrentPlaylist * self, + KotoPlaylist * playlist, + gboolean play_immediately + ); +}; static void koto_current_playlist_class_init(KotoCurrentPlaylistClass * c) { GObjectClass * gobject_class; gobject_class = G_OBJECT_CLASS(c); - gobject_class->set_property = koto_current_playlist_set_property; - gobject_class->get_property = koto_current_playlist_get_property; - props[PROP_CURRENT_PLAYLIST] = g_param_spec_object( - "current-playlist", - "Current Playlist", - "Current Playlist", + signals[SIGNAL_PLAYLIST_CHANGED] = g_signal_new( + "playlist-changed", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(KotoCurrentPlaylistClass, playlist_changed), + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, KOTO_TYPE_PLAYLIST, - G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE + G_TYPE_BOOLEAN ); - - g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } +G_DEFINE_TYPE(KotoCurrentPlaylist, koto_current_playlist, G_TYPE_OBJECT); + static void koto_current_playlist_init(KotoCurrentPlaylist * self) { self->current_playlist = NULL; } -void koto_current_playlist_get_property( - GObject * obj, - guint prop_id, - GValue * val, - GParamSpec * spec -) { - KotoCurrentPlaylist * self = KOTO_CURRENT_PLAYLIST(obj); - - switch (prop_id) { - case PROP_CURRENT_PLAYLIST: - g_value_set_object(val, self->current_playlist); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); - break; - } -} - -void koto_current_playlist_set_property( - GObject * obj, - guint prop_id, - const GValue * val, - GParamSpec * spec -) { - KotoCurrentPlaylist * self = KOTO_CURRENT_PLAYLIST(obj); - - switch (prop_id) { - case PROP_CURRENT_PLAYLIST: - koto_current_playlist_set_playlist(self, (KotoPlaylist*) g_value_get_object(val)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); - break; - } -} - KotoPlaylist * koto_current_playlist_get_playlist(KotoCurrentPlaylist * self) { return self->current_playlist; } void koto_current_playlist_set_playlist( KotoCurrentPlaylist * self, - KotoPlaylist * playlist + KotoPlaylist * playlist, + gboolean play_immediately ) { if (!KOTO_IS_CURRENT_PLAYLIST(self)) { return; @@ -142,7 +104,13 @@ void koto_current_playlist_set_playlist( // TODO: Saved state koto_playlist_set_position(self->current_playlist, -1); // Reset our position, use -1 since "next" song is then 0 g_object_ref(playlist); // Increment the reference - g_object_notify_by_pspec(G_OBJECT(self), props[PROP_CURRENT_PLAYLIST]); + g_signal_emit( + self, + signals[SIGNAL_PLAYLIST_CHANGED], + 0, + playlist, + play_immediately + ); } KotoCurrentPlaylist * koto_current_playlist_new() { diff --git a/src/playlist/current.h b/src/playlist/current.h index 10cddef..09409e5 100644 --- a/src/playlist/current.h +++ b/src/playlist/current.h @@ -26,9 +26,15 @@ G_BEGIN_DECLS **/ #define KOTO_TYPE_CURRENT_PLAYLIST koto_current_playlist_get_type() -G_DECLARE_FINAL_TYPE(KotoCurrentPlaylist, koto_current_playlist, KOTO, CURRENT_PLAYLIST, GObject); +#define KOTO_CURRENT_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KOTO_TYPE_CURRENT_PLAYLIST, KotoCurrentPlaylist)) #define KOTO_IS_CURRENT_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_CURRENT_PLAYLIST)) +typedef struct _KotoCurrentPlaylist KotoCurrentPlaylist; +typedef struct _KotoCurrentPlaylistClass KotoCurrentPlaylistClass; + +GLIB_AVAILABLE_IN_ALL +GType koto_current_playlist_get_type(void) G_GNUC_CONST; + /** * Current Playlist Functions **/ @@ -39,7 +45,8 @@ KotoPlaylist * koto_current_playlist_get_playlist(KotoCurrentPlaylist * self); void koto_current_playlist_set_playlist( KotoCurrentPlaylist * self, - KotoPlaylist * playlist + KotoPlaylist * playlist, + gboolean play_immediately ); G_END_DECLS