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.
This commit is contained in:
Joshua Strobl 2021-07-10 01:20:20 +03:00
parent d8b71b8548
commit ca4873e07f
13 changed files with 265 additions and 142 deletions

View file

@ -18,7 +18,9 @@
#include <glib-2.0/glib.h>
#include <gtk-4.0/gtk/gtk.h>
#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;
}
KotoPlaylist * playlist = NULL;
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);
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
}
}
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_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
}
}
koto_playback_engine_set_track_by_uuid(playback_engine, koto_track_get_uuid(track), TRUE); // Set the track to play
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);

View file

@ -18,6 +18,8 @@
#include <glib-2.0/glib.h>
#include <gtk-4.0/gtk/gtk.h>
#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() {

View file

@ -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,

View file

@ -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

View file

@ -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(

View file

@ -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,16 +660,14 @@ 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;
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
@ -654,13 +676,14 @@ void koto_playerbar_update_track_info(
} 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
}
}
}
GtkWidget * koto_playerbar_get_main(KotoPlayerBar * bar) {

View file

@ -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) {

View file

@ -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

View file

@ -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(

View file

@ -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";

View file

@ -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);

View file

@ -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() {

View file

@ -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