diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a6886c0..161c8df 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -13,6 +13,18 @@ ], "problemMatcher": [] }, + { + "label": "Format", + "type": "shell", + "command": "uncrustify", + "args": [ + "-c", + "jsc.cfg", + "--no-backup", + "**/*.c", + "**/*.h" + ] + }, { "label": "Meson Configure and Build", "type": "shell", diff --git a/jsc.cfg b/jsc.cfg index 10cf04a..4ed68a1 100644 --- a/jsc.cfg +++ b/jsc.cfg @@ -157,27 +157,27 @@ sp_before_ptr_star = ignore # ignore/add/remove/force # Add or remove space before pointer star '*' that isn't followed by a # variable name. If set to ignore, sp_before_ptr_star is used instead. -sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force +sp_before_unnamed_ptr_star = remove # ignore/add/remove/force # Add or remove space between pointer stars '*'. -sp_between_ptr_star = remove # ignore/add/remove/force +sp_between_ptr_star = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a word. # # Overrides sp_type_func. -sp_after_ptr_star = remove # ignore/add/remove/force +sp_after_ptr_star = force # ignore/add/remove/force # Add or remove space after pointer caret '^', if followed by a word. sp_after_ptr_block_caret = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a qualifier. -sp_after_ptr_star_qualifier = remove # ignore/add/remove/force +sp_after_ptr_star_qualifier = force # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by a function # prototype or function definition. # # Overrides sp_after_ptr_star and sp_type_func. -sp_after_ptr_star_func = remove # ignore/add/remove/force +sp_after_ptr_star_func = force # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by an open # parenthesis, as in 'void* (*)(). @@ -1055,7 +1055,7 @@ donot_indent_func_def_close_paren = false # true/false # Whether to collapse empty blocks between '{' and '}'. # If true, overrides nl_inside_empty_func -nl_collapse_empty_body = true # true/false +nl_collapse_empty_body = false # true/false # Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. nl_assign_leave_one_liners = false # true/false @@ -1349,10 +1349,10 @@ nl_func_call_paren = ignore # ignore/add/remove/force nl_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove newline after '(' in a function declaration. -nl_func_decl_start = remove # ignore/add/remove/force +nl_func_decl_start = force # ignore/add/remove/force # Add or remove newline after '(' in a function definition. -nl_func_def_start = remove # ignore/add/remove/force +nl_func_def_start = force # ignore/add/remove/force # Overrides nl_func_decl_start when there is only one parameter. nl_func_decl_start_single = remove # ignore/add/remove/force @@ -1369,13 +1369,13 @@ nl_func_decl_start_multi_line = false # true/false nl_func_def_start_multi_line = true # true/false # Add or remove newline after each ',' in a function declaration. -nl_func_decl_args = ignore # ignore/add/remove/force +nl_func_decl_args = force # ignore/add/remove/force # Add or remove newline after each ',' in a function definition. -nl_func_def_args = remove # ignore/add/remove/force +nl_func_def_args = force # ignore/add/remove/force # Add or remove newline after each ',' in a function call. -nl_func_call_args = ignore # ignore/add/remove/force +nl_func_call_args = remove # ignore/add/remove/force # Whether to add a newline after each ',' in a function declaration if '(' # and ')' are in different lines. If false, nl_func_decl_args is used instead. @@ -1386,10 +1386,10 @@ nl_func_decl_args_multi_line = true # true/false nl_func_def_args_multi_line = true # true/false # Add or remove newline before the ')' in a function declaration. -nl_func_decl_end = add # ignore/add/remove/force +nl_func_decl_end = force # ignore/add/remove/force # Add or remove newline before the ')' in a function definition. -nl_func_def_end = ignore # ignore/add/remove/force +nl_func_def_end = force # ignore/add/remove/force # Overrides nl_func_decl_end when there is only one parameter. nl_func_decl_end_single = remove # ignore/add/remove/force @@ -1399,7 +1399,7 @@ nl_func_def_end_single = remove # ignore/add/remove/force # Whether to add a newline before ')' in a function declaration if '(' and ')' # are in different lines. If false, nl_func_decl_end is used instead. -nl_func_decl_end_multi_line = false # true/false +nl_func_decl_end_multi_line = true # true/false # Whether to add a newline before ')' in a function definition if '(' and ')' # are in different lines. If false, nl_func_def_end is used instead. @@ -1456,7 +1456,7 @@ nl_fdef_brace_cond = ignore # ignore/add/remove/force nl_return_expr = remove # ignore/add/remove/force # Whether to add a newline after semicolons, except in 'for' statements. -nl_after_semicolon = false # true/false +nl_after_semicolon = true # true/false # Whether to add a newline after the type in an unnamed temporary # direct-list-initialization. @@ -1643,7 +1643,7 @@ nl_before_func_class_proto = 0 # unsigned number nl_before_func_class_def = 0 # unsigned number # The number of newlines after a function prototype. -nl_after_func_proto = 0 # unsigned number +nl_after_func_proto = 2 # unsigned number # The number of newlines after a function prototype, if not followed by # another function prototype. @@ -1734,13 +1734,13 @@ nl_after_multiline_comment = false # true/false nl_after_label_colon = false # true/false # The number of newlines after '}' or ';' of a struct/enum/union definition. -nl_after_struct = 0 # unsigned number +nl_after_struct = 1 # unsigned number # The number of newlines before a class definition. nl_before_class = 0 # unsigned number # The number of newlines after '}' or ';' of a class definition. -nl_after_class = 0 # unsigned number +nl_after_class = 1 # unsigned number # The number of newlines before a namespace. nl_before_namespace = 0 # unsigned number @@ -2291,9 +2291,6 @@ mod_full_brace_do = ignore # ignore/add/remove/force # Add or remove braces on a single-line 'for' statement. mod_full_brace_for = ignore # ignore/add/remove/force -# (Pawn) Add or remove braces on a single-line function definition. -mod_full_brace_function = ignore # ignore/add/remove/force - # Add or remove braces on a single-line 'if' statement. Braces will not be # removed if the braced statement contains an 'else'. mod_full_brace_if = ignore # ignore/add/remove/force @@ -2337,10 +2334,7 @@ mod_full_brace_nl = 0 # unsigned number mod_full_brace_nl_block_rem_mlcond = false # true/false # Add or remove unnecessary parenthesis on 'return' statement. -mod_paren_on_return = ignore # ignore/add/remove/force - -# (Pawn) Whether to change optional semicolons to real semicolons. -mod_pawn_semicolon = false # true/false +mod_paren_on_return = ignore # ignore/add/remove/forceĀ“ # Whether to fully parenthesize Boolean expressions in 'while' and 'if' # statement, as in 'if (a && b > c)' => 'if (a && (b > c))'. diff --git a/src/components/koto-action-bar.c b/src/components/koto-action-bar.c index 6525292..3f96979 100644 --- a/src/components/koto-action-bar.c +++ b/src/components/koto-action-bar.c @@ -26,52 +26,55 @@ #include "../koto-utils.h" #include "../koto-window.h" -extern KotoAddRemoveTrackPopover *koto_add_remove_track_popup; -extern KotoCartographer *koto_maps; -extern KotoPageMusicLocal *music_local_page; -extern KotoPlaybackEngine *playback_engine; -extern KotoWindow *main_window; +extern KotoAddRemoveTrackPopover * koto_add_remove_track_popup; +extern KotoCartographer * koto_maps; +extern KotoPageMusicLocal * music_local_page; +extern KotoPlaybackEngine * playback_engine; +extern KotoWindow * main_window; enum { SIGNAL_CLOSED, N_SIGNALS }; -static guint actionbar_signals[N_SIGNALS] = { 0 }; +static guint actionbar_signals[N_SIGNALS] = { + 0 +}; struct _KotoActionBar { GObject parent_instance; - GtkActionBar *main; + GtkActionBar * main; - GtkWidget *center_box_content; - GtkWidget *start_box_content; - GtkWidget *stop_box_content; + GtkWidget * center_box_content; + GtkWidget * start_box_content; + GtkWidget * stop_box_content; - KotoButton *close_button; - GtkWidget *go_to_artist; - GtkWidget *playlists; - GtkWidget *play_track; - GtkWidget *remove_from_playlist; + KotoButton * close_button; + GtkWidget * go_to_artist; + GtkWidget * playlists; + GtkWidget * play_track; + GtkWidget * remove_from_playlist; - GList *current_list; - gchar *current_album_uuid; - gchar *current_playlist_uuid; + GList * current_list; + gchar * current_album_uuid; + gchar * current_playlist_uuid; KotoActionBarRelative relative; }; struct _KotoActionBarClass { GObjectClass parent_class; - void (* closed) (KotoActionBar *self); + void (* closed) (KotoActionBar * self); }; G_DEFINE_TYPE(KotoActionBar, koto_action_bar, G_TYPE_OBJECT); KotoActionBar* action_bar; -static void koto_action_bar_class_init(KotoActionBarClass *c) { - GObjectClass *gobject_class = G_OBJECT_CLASS(c); +static void koto_action_bar_class_init(KotoActionBarClass * c) { + GObjectClass * gobject_class = G_OBJECT_CLASS(c); + actionbar_signals[SIGNAL_CLOSED] = g_signal_new( "closed", @@ -86,7 +89,7 @@ static void koto_action_bar_class_init(KotoActionBarClass *c) { ); } -static void koto_action_bar_init(KotoActionBar *self) { +static void koto_action_bar_init(KotoActionBar * self) { self->main = GTK_ACTION_BAR(gtk_action_bar_new()); // Create a new action bar self->current_list = NULL; @@ -135,7 +138,7 @@ static void koto_action_bar_init(KotoActionBar *self) { koto_action_bar_toggle_reveal(self, FALSE); // Hide by default } -void koto_action_bar_close(KotoActionBar *self) { +void koto_action_bar_close(KotoActionBar * self) { if (!KOTO_IS_ACTION_BAR(self)) { return; } @@ -151,7 +154,7 @@ void koto_action_bar_close(KotoActionBar *self) { ); } -GtkActionBar* koto_action_bar_get_main(KotoActionBar *self) { +GtkActionBar * koto_action_bar_get_main(KotoActionBar * self) { if (!KOTO_IS_ACTION_BAR(self)) { return NULL; } @@ -159,14 +162,27 @@ GtkActionBar* koto_action_bar_get_main(KotoActionBar *self) { return self->main; } -void koto_action_bar_handle_close_button_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; +void koto_action_bar_handle_close_button_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; koto_action_bar_close(data); } -void koto_action_bar_handle_go_to_artist_button_clicked(GtkButton *button, gpointer data) { +void koto_action_bar_handle_go_to_artist_button_clicked( + GtkButton * button, + gpointer data +) { (void) button; - KotoActionBar *self = data; + KotoActionBar * self = data; + if (!KOTO_IS_ACTION_BAR(self)) { return; @@ -176,13 +192,16 @@ void koto_action_bar_handle_go_to_artist_button_clicked(GtkButton *button, gpoin return; } - KotoIndexedTrack *selected_track = g_list_nth_data(self->current_list, 0); // Get the first item + KotoIndexedTrack * selected_track = g_list_nth_data(self->current_list, 0); // Get the first item + if (!KOTO_IS_INDEXED_TRACK(selected_track)) { // Not a track return; } - gchar *artist_uuid = NULL; + gchar * artist_uuid = NULL; + + g_object_get( selected_track, "artist-uuid", @@ -190,13 +209,17 @@ void koto_action_bar_handle_go_to_artist_button_clicked(GtkButton *button, gpoin NULL ); - koto_page_music_local_go_to_artist_by_uuid(music_local_page, artist_uuid); // Go to the artist + koto_page_music_local_go_to_artist_by_uuid(music_local_page, artist_uuid); // Go to the artist koto_window_go_to_page(main_window, "music.local"); // Navigate to the local music stack so we can see the substack page koto_action_bar_close(self); // Close the action bar } -void koto_action_bar_handle_playlists_button_clicked(GtkButton *button, gpointer data) { +void koto_action_bar_handle_playlists_button_clicked( + GtkButton * button, + gpointer data +) { (void) button; - KotoActionBar *self = data; + KotoActionBar * self = data; + if (!KOTO_IS_ACTION_BAR(self)) { return; @@ -211,9 +234,13 @@ void koto_action_bar_handle_playlists_button_clicked(GtkButton *button, gpointer gtk_widget_show(GTK_WIDGET(koto_add_remove_track_popup)); } -void koto_action_bar_handle_play_track_button_clicked(GtkButton *button, gpointer data) { +void koto_action_bar_handle_play_track_button_clicked( + GtkButton * button, + gpointer data +) { (void) button; - KotoActionBar *self = data; + KotoActionBar * self = data; + if (!KOTO_IS_ACTION_BAR(self)) { return; @@ -223,7 +250,8 @@ void koto_action_bar_handle_play_track_button_clicked(GtkButton *button, gpointe goto doclose; } - KotoIndexedTrack *track = g_list_nth_data(self->current_list, 0); // Get the first track + KotoIndexedTrack * track = g_list_nth_data(self->current_list, 0); // Get the first track + if (!KOTO_IS_INDEXED_TRACK(track)) { // Not a track goto doclose; @@ -235,9 +263,13 @@ doclose: koto_action_bar_close(self); } -void koto_action_bar_handle_remove_from_playlist_button_clicked(GtkButton *button, gpointer data) { +void koto_action_bar_handle_remove_from_playlist_button_clicked( + GtkButton * button, + gpointer data +) { (void) button; - KotoActionBar *self = data; + KotoActionBar * self = data; + if (!KOTO_IS_ACTION_BAR(self)) { return; @@ -251,15 +283,18 @@ void koto_action_bar_handle_remove_from_playlist_button_clicked(GtkButton *butto goto doclose; } - KotoPlaylist *playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->current_playlist_uuid); + KotoPlaylist * playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->current_playlist_uuid); + if (!KOTO_IS_PLAYLIST(playlist)) { // Not a playlist goto doclose; } - GList *cur_list; + GList * cur_list; + + for (cur_list = self->current_list; cur_list != NULL; cur_list = cur_list->next) { // For each KotoIndexedTrack - KotoIndexedTrack *track = cur_list->data; + KotoIndexedTrack * track = cur_list->data; koto_playlist_remove_track_by_uuid(playlist, koto_indexed_track_get_uuid(track)); // Remove this track } @@ -267,7 +302,11 @@ doclose: koto_action_bar_close(self); } -void koto_action_bar_set_tracks_in_album_selection(KotoActionBar *self, gchar *album_uuid, GList *tracks) { +void koto_action_bar_set_tracks_in_album_selection( + KotoActionBar * self, + gchar * album_uuid, + GList * tracks +) { if (!KOTO_IS_ACTION_BAR(self)) { return; } @@ -297,7 +336,11 @@ void koto_action_bar_set_tracks_in_album_selection(KotoActionBar *self, gchar *a gtk_widget_hide(GTK_WIDGET(self->remove_from_playlist)); } -void koto_action_bar_set_tracks_in_playlist_selection(KotoActionBar *self, gchar *playlist_uuid, GList *tracks) { +void koto_action_bar_set_tracks_in_playlist_selection( + KotoActionBar * self, + gchar * playlist_uuid, + GList * tracks +) { if (!KOTO_IS_ACTION_BAR(self)) { return; } @@ -318,13 +361,18 @@ void koto_action_bar_set_tracks_in_playlist_selection(KotoActionBar *self, gchar self->current_list = g_list_copy(tracks); gboolean single_selected = g_list_length(tracks) == 1; + + koto_action_bar_toggle_go_to_artist_visibility(self, single_selected); koto_action_bar_toggle_play_button_visibility(self, single_selected); gtk_widget_hide(GTK_WIDGET(self->playlists)); gtk_widget_show(GTK_WIDGET(self->remove_from_playlist)); } -void koto_action_bar_toggle_go_to_artist_visibility(KotoActionBar *self, gboolean visible) { +void koto_action_bar_toggle_go_to_artist_visibility( + KotoActionBar * self, + gboolean visible +) { if (!KOTO_IS_ACTION_BAR(self)) { return; } @@ -332,7 +380,10 @@ void koto_action_bar_toggle_go_to_artist_visibility(KotoActionBar *self, gboolea (visible) ? gtk_widget_show(GTK_WIDGET(self->go_to_artist)) : gtk_widget_hide(GTK_WIDGET(self->go_to_artist)); } -void koto_action_bar_toggle_play_button_visibility(KotoActionBar *self, gboolean visible) { +void koto_action_bar_toggle_play_button_visibility( + KotoActionBar * self, + gboolean visible +) { if (!KOTO_IS_ACTION_BAR(self)) { return; } @@ -340,7 +391,10 @@ void koto_action_bar_toggle_play_button_visibility(KotoActionBar *self, gboolean (visible) ? gtk_widget_show(GTK_WIDGET(self->play_track)) : gtk_widget_hide(GTK_WIDGET(self->play_track)); } -void koto_action_bar_toggle_reveal(KotoActionBar *self, gboolean state) { +void koto_action_bar_toggle_reveal( + KotoActionBar * self, + gboolean state +) { if (!KOTO_IS_ACTION_BAR(self)) { return; } @@ -348,7 +402,7 @@ void koto_action_bar_toggle_reveal(KotoActionBar *self, gboolean state) { gtk_action_bar_set_revealed(self->main, state); } -KotoActionBar* koto_action_bar_new() { +KotoActionBar * koto_action_bar_new() { return g_object_new( KOTO_TYPE_ACTION_BAR, NULL diff --git a/src/components/koto-action-bar.h b/src/components/koto-action-bar.h index 4cc05ba..d8c4572 100644 --- a/src/components/koto-action-bar.h +++ b/src/components/koto-action-bar.h @@ -39,20 +39,67 @@ GType koto_action_bar_get_type(void) G_GNUC_CONST; /** * Action Bar Functions -**/ + **/ -KotoActionBar* koto_action_bar_new(void); -void koto_action_bar_close(KotoActionBar *self); -GtkActionBar* koto_action_bar_get_main(KotoActionBar *self); -void koto_action_bar_handle_close_button_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_action_bar_handle_go_to_artist_button_clicked(GtkButton *button, gpointer data); -void koto_action_bar_handle_playlists_button_clicked(GtkButton *button, gpointer data); -void koto_action_bar_handle_play_track_button_clicked(GtkButton *button, gpointer data); -void koto_action_bar_handle_remove_from_playlist_button_clicked(GtkButton *button, gpointer data); -void koto_action_bar_set_tracks_in_album_selection(KotoActionBar *self, gchar *album_uuid, GList *tracks); -void koto_action_bar_set_tracks_in_playlist_selection(KotoActionBar *self, gchar *playlist_uuid, GList *tracks); -void koto_action_bar_toggle_go_to_artist_visibility(KotoActionBar *self, gboolean visible); -void koto_action_bar_toggle_play_button_visibility(KotoActionBar *self, gboolean visible); -void koto_action_bar_toggle_reveal(KotoActionBar *self, gboolean state); +KotoActionBar * koto_action_bar_new(void); + +void koto_action_bar_close(KotoActionBar * self); + +GtkActionBar * koto_action_bar_get_main(KotoActionBar * self); + +void koto_action_bar_handle_close_button_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_action_bar_handle_go_to_artist_button_clicked( + GtkButton * button, + gpointer data +); + +void koto_action_bar_handle_playlists_button_clicked( + GtkButton * button, + gpointer data +); + +void koto_action_bar_handle_play_track_button_clicked( + GtkButton * button, + gpointer data +); + +void koto_action_bar_handle_remove_from_playlist_button_clicked( + GtkButton * button, + gpointer data +); + +void koto_action_bar_set_tracks_in_album_selection( + KotoActionBar * self, + gchar * album_uuid, + GList * tracks +); + +void koto_action_bar_set_tracks_in_playlist_selection( + KotoActionBar * self, + gchar * playlist_uuid, + GList * tracks +); + +void koto_action_bar_toggle_go_to_artist_visibility( + KotoActionBar * self, + gboolean visible +); + +void koto_action_bar_toggle_play_button_visibility( + KotoActionBar * self, + gboolean visible +); + +void koto_action_bar_toggle_reveal( + KotoActionBar * self, + gboolean state +); G_END_DECLS \ No newline at end of file diff --git a/src/components/koto-cover-art-button.c b/src/components/koto-cover-art-button.c index 67188a8..f1e43ec 100644 --- a/src/components/koto-cover-art-button.c +++ b/src/components/koto-cover-art-button.c @@ -24,10 +24,10 @@ struct _KotoCoverArtButton { GObject parent_instance; - GtkWidget *art; - GtkWidget *main; - GtkWidget *revealer; - KotoButton *play_pause_button; + GtkWidget * art; + GtkWidget * main; + GtkWidget * revealer; + KotoButton * play_pause_button; guint height; guint width; @@ -43,12 +43,27 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; -static void koto_cover_art_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_cover_art_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; +static void koto_cover_art_button_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_cover_art_button_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_cover_art_button_class_init(KotoCoverArtButtonClass * c) { + GObjectClass * gobject_class; + -static void koto_cover_art_button_class_init(KotoCoverArtButtonClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->get_property = koto_cover_art_button_get_property; gobject_class->set_property = koto_cover_art_button_set_property; @@ -60,7 +75,7 @@ static void koto_cover_art_button_class_init(KotoCoverArtButtonClass *c) { 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_WRITABLE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_WRITABLE ); props[PROP_DESIRED_WIDTH] = g_param_spec_uint( @@ -70,7 +85,7 @@ static void koto_cover_art_button_class_init(KotoCoverArtButtonClass *c) { 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_WRITABLE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_WRITABLE ); props[PROP_ART_PATH] = g_param_spec_string( @@ -78,20 +93,22 @@ static void koto_cover_art_button_class_init(KotoCoverArtButtonClass *c) { "Path to art", "Path to art", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_WRITABLE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_WRITABLE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_cover_art_button_init(KotoCoverArtButton *self) { +static void koto_cover_art_button_init(KotoCoverArtButton * self) { self->main = gtk_overlay_new(); // Create our overlay container gtk_widget_add_css_class(self->main, "cover-art-button"); self->revealer = gtk_revealer_new(); // Create a new revealer gtk_revealer_set_transition_type(GTK_REVEALER(self->revealer), GTK_REVEALER_TRANSITION_TYPE_CROSSFADE); gtk_revealer_set_transition_duration(GTK_REVEALER(self->revealer), 400); - GtkWidget *controls = gtk_center_box_new(); // Create a center box for the controls + GtkWidget * controls = gtk_center_box_new(); // Create a center box for the controls + + self->play_pause_button = koto_button_new_with_icon("", "media-playback-start-symbolic", "media-playback-pause-symbolic", KOTO_BUTTON_PIXBUF_SIZE_NORMAL); gtk_center_box_set_center_widget(GTK_CENTER_BOX(controls), GTK_WIDGET(self->play_pause_button)); @@ -99,13 +116,20 @@ static void koto_cover_art_button_init(KotoCoverArtButton *self) { koto_cover_art_button_hide_overlay_controls(NULL, self); // Hide by default gtk_overlay_add_overlay(GTK_OVERLAY(self->main), self->revealer); // Add our revealer as the overlay - GtkEventController *motion_controller = gtk_event_controller_motion_new(); // Create our new motion event controller to track mouse leave and enter + GtkEventController * motion_controller = gtk_event_controller_motion_new(); // Create our new motion event controller to track mouse leave and enter + + g_signal_connect(motion_controller, "enter", G_CALLBACK(koto_cover_art_button_show_overlay_controls), self); g_signal_connect(motion_controller, "leave", G_CALLBACK(koto_cover_art_button_hide_overlay_controls), self); gtk_widget_add_controller(self->main, motion_controller); } -static void koto_cover_art_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { +static void koto_cover_art_button_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { (void) val; switch (prop_id) { @@ -115,8 +139,14 @@ static void koto_cover_art_button_get_property(GObject *obj, guint prop_id, GVal } } -static void koto_cover_art_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoCoverArtButton *self = KOTO_COVER_ART_BUTTON(obj); +static void koto_cover_art_button_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoCoverArtButton * self = KOTO_COVER_ART_BUTTON(obj); + switch (prop_id) { case PROP_ART_PATH: @@ -134,13 +164,18 @@ static void koto_cover_art_button_set_property(GObject *obj, guint prop_id, cons } } -void koto_cover_art_button_hide_overlay_controls(GtkEventControllerFocus *controller, gpointer data) { +void koto_cover_art_button_hide_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +) { (void) controller; KotoCoverArtButton* self = data; + + gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), FALSE); } -KotoButton* koto_cover_art_button_get_button(KotoCoverArtButton *self) { +KotoButton * koto_cover_art_button_get_button(KotoCoverArtButton * self) { if (!KOTO_IS_COVER_ART_BUTTON(self)) { return NULL; } @@ -148,7 +183,7 @@ KotoButton* koto_cover_art_button_get_button(KotoCoverArtButton *self) { return self->play_pause_button; } -GtkWidget* koto_cover_art_button_get_main(KotoCoverArtButton *self) { +GtkWidget * koto_cover_art_button_get_main(KotoCoverArtButton * self) { if (!KOTO_IS_COVER_ART_BUTTON(self)) { return NULL; } @@ -156,13 +191,17 @@ GtkWidget* koto_cover_art_button_get_main(KotoCoverArtButton *self) { return self->main; } -void koto_cover_art_button_set_art_path(KotoCoverArtButton *self, gchar *art_path) { +void koto_cover_art_button_set_art_path( + KotoCoverArtButton * self, + gchar * art_path +) { if (!KOTO_IS_COVER_ART_BUTTON(self)) { return; } gboolean defined_artwork = koto_utils_is_string_valid(art_path); + if (GTK_IS_IMAGE(self->art)) { // Already have an image if (!defined_artwork) { // No art path or empty string gtk_image_set_from_icon_name(GTK_IMAGE(self->art), "audio-x-generic-symbolic"); @@ -175,7 +214,11 @@ void koto_cover_art_button_set_art_path(KotoCoverArtButton *self, gchar *art_pat } } -void koto_cover_art_button_set_dimensions(KotoCoverArtButton *self, guint height, guint width) { +void koto_cover_art_button_set_dimensions( + KotoCoverArtButton * self, + guint height, + guint width +) { if (!KOTO_IS_COVER_ART_BUTTON(self)) { return; } @@ -197,15 +240,24 @@ void koto_cover_art_button_set_dimensions(KotoCoverArtButton *self, guint height } } -void koto_cover_art_button_show_overlay_controls(GtkEventControllerFocus *controller, gpointer data) { +void koto_cover_art_button_show_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +) { (void) controller; KotoCoverArtButton* self = data; + gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), TRUE); } -KotoCoverArtButton* koto_cover_art_button_new(guint height, guint width, gchar *art_path) { - return g_object_new(KOTO_TYPE_COVER_ART_BUTTON, +KotoCoverArtButton * koto_cover_art_button_new( + guint height, + guint width, + gchar * art_path +) { + return g_object_new( + KOTO_TYPE_COVER_ART_BUTTON, "desired-height", height, "desired-width", diff --git a/src/components/koto-cover-art-button.h b/src/components/koto-cover-art-button.h index ce0c6ce..9d9b843 100644 --- a/src/components/koto-cover-art-button.h +++ b/src/components/koto-cover-art-button.h @@ -27,14 +27,37 @@ G_DECLARE_FINAL_TYPE(KotoCoverArtButton, koto_cover_art_button, KOTO, COVER_ART_ /** * Cover Art Functions -**/ + **/ -KotoCoverArtButton* koto_cover_art_button_new(guint height, guint width, gchar *art_path); -KotoButton* koto_cover_art_button_get_button(KotoCoverArtButton *self); -GtkWidget* koto_cover_art_button_get_main(KotoCoverArtButton *self); -void koto_cover_art_button_hide_overlay_controls(GtkEventControllerFocus *controller, gpointer data); -void koto_cover_art_button_set_art_path(KotoCoverArtButton *self, gchar *art_path); -void koto_cover_art_button_set_dimensions(KotoCoverArtButton *self, guint height, guint width); -void koto_cover_art_button_show_overlay_controls(GtkEventControllerFocus *controller, gpointer data); +KotoCoverArtButton * koto_cover_art_button_new( + guint height, + guint width, + gchar * art_path +); + +KotoButton * koto_cover_art_button_get_button(KotoCoverArtButton * self); + +GtkWidget * koto_cover_art_button_get_main(KotoCoverArtButton * self); + +void koto_cover_art_button_hide_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +); + +void koto_cover_art_button_set_art_path( + KotoCoverArtButton * self, + gchar * art_path +); + +void koto_cover_art_button_set_dimensions( + KotoCoverArtButton * self, + guint height, + guint width +); + +void koto_cover_art_button_show_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +); G_END_DECLS \ No newline at end of file diff --git a/src/db/cartographer.c b/src/db/cartographer.c index 98da8dd..f7af98e 100644 --- a/src/db/cartographer.c +++ b/src/db/cartographer.c @@ -30,36 +30,64 @@ enum { N_SIGNALS }; -static guint cartographer_signals[N_SIGNALS] = { 0 }; +static guint cartographer_signals[N_SIGNALS] = { + 0 +}; struct _KotoCartographer { GObject parent_instance; - GHashTable *albums; - GHashTable *artists; - GHashTable *playlists; - GHashTable *tracks; + GHashTable * albums; + GHashTable * artists; + GHashTable * playlists; + GHashTable * tracks; }; struct _KotoCartographerClass { GObjectClass parent_class; - void (* album_added) (KotoCartographer *cartographer, KotoIndexedAlbum *album); - void (* album_removed) (KotoCartographer *cartographer, KotoIndexedAlbum *album); - void (* artist_added) (KotoCartographer *cartographer, KotoIndexedArtist *artist); - void (* artist_removed) (KotoCartographer *cartographer, KotoIndexedArtist *artist); - void (* playlist_added) (KotoCartographer *cartographer, KotoPlaylist *playlist); - void (* playlist_removed) (KotoCartographer *cartographer, KotoPlaylist *playlist); - void (* track_added) (KotoCartographer *cartographer, KotoIndexedTrack *track); - void (* track_removed) (KotoCartographer *cartographer, KotoIndexedTrack *track); + void (* album_added) ( + KotoCartographer * cartographer, + KotoIndexedAlbum * album + ); + void (* album_removed) ( + KotoCartographer * cartographer, + KotoIndexedAlbum * album + ); + void (* artist_added) ( + KotoCartographer * cartographer, + KotoIndexedArtist * artist + ); + void (* artist_removed) ( + KotoCartographer * cartographer, + KotoIndexedArtist * artist + ); + void (* playlist_added) ( + KotoCartographer * cartographer, + KotoPlaylist * playlist + ); + void (* playlist_removed) ( + KotoCartographer * cartographer, + KotoPlaylist * playlist + ); + void (* track_added) ( + KotoCartographer * cartographer, + KotoIndexedTrack * track + ); + void (* track_removed) ( + KotoCartographer * cartographer, + KotoIndexedTrack * track + ); }; G_DEFINE_TYPE(KotoCartographer, koto_cartographer, G_TYPE_OBJECT); -KotoCartographer *koto_maps = NULL; +KotoCartographer * koto_maps = NULL; + +static void koto_cartographer_class_init(KotoCartographerClass * c) { + GObjectClass * gobject_class; + -static void koto_cartographer_class_init(KotoCartographerClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); cartographer_signals[SIGNAL_ALBUM_ADDED] = g_signal_new( @@ -167,15 +195,20 @@ static void koto_cartographer_class_init(KotoCartographerClass *c) { ); } -static void koto_cartographer_init(KotoCartographer *self) { +static void koto_cartographer_init(KotoCartographer * self) { self->albums = g_hash_table_new(g_str_hash, g_str_equal); self->artists = g_hash_table_new(g_str_hash, g_str_equal); self->playlists = g_hash_table_new(g_str_hash, g_str_equal); self->tracks = g_hash_table_new(g_str_hash, g_str_equal); } -void koto_cartographer_add_album(KotoCartographer *self, KotoIndexedAlbum *album) { - gchar *album_uuid = NULL; +void koto_cartographer_add_album( + KotoCartographer * self, + KotoIndexedAlbum * album +) { + gchar * album_uuid = NULL; + + g_object_get(album, "uuid", &album_uuid, NULL); if ((album_uuid == NULL) || koto_cartographer_has_album_by_uuid(self, album_uuid)) { // Have the album or invalid UUID @@ -192,8 +225,13 @@ void koto_cartographer_add_album(KotoCartographer *self, KotoIndexedAlbum *album ); } -void koto_cartographer_add_artist(KotoCartographer *self, KotoIndexedArtist *artist) { - gchar *artist_uuid = NULL; +void koto_cartographer_add_artist( + KotoCartographer * self, + KotoIndexedArtist * artist +) { + gchar * artist_uuid = NULL; + + g_object_get(artist, "uuid", &artist_uuid, NULL); if ((artist_uuid == NULL) || koto_cartographer_has_artist_by_uuid(self, artist_uuid)) { // Have the artist or invalid UUID @@ -210,8 +248,13 @@ void koto_cartographer_add_artist(KotoCartographer *self, KotoIndexedArtist *art ); } -void koto_cartographer_add_playlist(KotoCartographer *self, KotoPlaylist *playlist) { - gchar *playlist_uuid = NULL; +void koto_cartographer_add_playlist( + KotoCartographer * self, + KotoPlaylist * playlist +) { + gchar * playlist_uuid = NULL; + + g_object_get(playlist, "uuid", &playlist_uuid, NULL); if ((playlist_uuid == NULL) || koto_cartographer_has_playlist_by_uuid(self, playlist_uuid)) { // Have the playlist or invalid UUID @@ -227,8 +270,11 @@ void koto_cartographer_add_playlist(KotoCartographer *self, KotoPlaylist *playli } } -void koto_cartographer_emit_playlist_added(KotoPlaylist *playlist, KotoCartographer *self) { - g_signal_emit( +void koto_cartographer_emit_playlist_added( + KotoPlaylist * playlist, + KotoCartographer * self +) { + g_signal_emit( self, cartographer_signals[SIGNAL_PLAYLIST_ADDED], 0, @@ -236,8 +282,13 @@ void koto_cartographer_emit_playlist_added(KotoPlaylist *playlist, KotoCartograp ); } -void koto_cartographer_add_track(KotoCartographer *self, KotoIndexedTrack *track) { - gchar *track_uuid = NULL; +void koto_cartographer_add_track( + KotoCartographer * self, + KotoIndexedTrack * track +) { + gchar * track_uuid = NULL; + + g_object_get(track, "uuid", &track_uuid, NULL); if ((track_uuid == NULL) || koto_cartographer_has_track_by_uuid(self, track_uuid)) { // Have the track or invalid UUID @@ -254,33 +305,53 @@ void koto_cartographer_add_track(KotoCartographer *self, KotoIndexedTrack *track ); } -KotoIndexedAlbum* koto_cartographer_get_album_by_uuid(KotoCartographer *self, gchar* album_uuid) { +KotoIndexedAlbum * koto_cartographer_get_album_by_uuid( + KotoCartographer * self, + gchar* album_uuid +) { return g_hash_table_lookup(self->albums, album_uuid); } -KotoIndexedArtist* koto_cartographer_get_artist_by_uuid(KotoCartographer *self, gchar* artist_uuid) { +KotoIndexedArtist * koto_cartographer_get_artist_by_uuid( + KotoCartographer * self, + gchar* artist_uuid +) { return g_hash_table_lookup(self->artists, artist_uuid); } -GHashTable* koto_cartographer_get_playlists(KotoCartographer *self) { +GHashTable * koto_cartographer_get_playlists(KotoCartographer * self) { return self->playlists; } -KotoPlaylist* koto_cartographer_get_playlist_by_uuid(KotoCartographer *self, gchar* playlist_uuid) { +KotoPlaylist * koto_cartographer_get_playlist_by_uuid( + KotoCartographer * self, + gchar* playlist_uuid +) { return g_hash_table_lookup(self->playlists, playlist_uuid); } -KotoIndexedTrack* koto_cartographer_get_track_by_uuid(KotoCartographer *self, gchar* track_uuid) { +KotoIndexedTrack * koto_cartographer_get_track_by_uuid( + KotoCartographer * self, + gchar* track_uuid +) { return g_hash_table_lookup(self->tracks, track_uuid); } -gboolean koto_cartographer_has_album(KotoCartographer *self, KotoIndexedAlbum *album) { - gchar *album_uuid = NULL; +gboolean koto_cartographer_has_album( + KotoCartographer * self, + KotoIndexedAlbum * album +) { + gchar * album_uuid = NULL; + + g_object_get(album, "uuid", &album_uuid, NULL); return koto_cartographer_has_album_by_uuid(self, album_uuid); } -gboolean koto_cartographer_has_album_by_uuid(KotoCartographer *self, gchar* album_uuid) { +gboolean koto_cartographer_has_album_by_uuid( + KotoCartographer * self, + gchar* album_uuid +) { if (album_uuid == NULL) { return FALSE; } @@ -288,13 +359,21 @@ gboolean koto_cartographer_has_album_by_uuid(KotoCartographer *self, gchar* albu return g_hash_table_contains(self->albums, album_uuid); } -gboolean koto_cartographer_has_artist(KotoCartographer *self, KotoIndexedArtist *artist) { - gchar *artist_uuid = NULL; +gboolean koto_cartographer_has_artist( + KotoCartographer * self, + KotoIndexedArtist * artist +) { + gchar * artist_uuid = NULL; + + g_object_get(artist, "uuid", &artist_uuid, NULL); return koto_cartographer_has_artist_by_uuid(self, artist_uuid); } -gboolean koto_cartographer_has_artist_by_uuid(KotoCartographer *self, gchar* artist_uuid) { +gboolean koto_cartographer_has_artist_by_uuid( + KotoCartographer * self, + gchar* artist_uuid +) { if (artist_uuid == NULL) { return FALSE; } @@ -302,13 +381,21 @@ gboolean koto_cartographer_has_artist_by_uuid(KotoCartographer *self, gchar* art return g_hash_table_contains(self->artists, artist_uuid); } -gboolean koto_cartographer_has_playlist(KotoCartographer *self, KotoPlaylist *playlist) { - gchar *playlist_uuid = NULL; +gboolean koto_cartographer_has_playlist( + KotoCartographer * self, + KotoPlaylist * playlist +) { + gchar * playlist_uuid = NULL; + + g_object_get(playlist, "uuid", &playlist_uuid, NULL); return koto_cartographer_has_playlist_by_uuid(self, playlist_uuid); } -gboolean koto_cartographer_has_playlist_by_uuid(KotoCartographer *self, gchar* playlist_uuid) { +gboolean koto_cartographer_has_playlist_by_uuid( + KotoCartographer * self, + gchar* playlist_uuid +) { if (playlist_uuid == NULL) { return FALSE; } @@ -316,13 +403,21 @@ gboolean koto_cartographer_has_playlist_by_uuid(KotoCartographer *self, gchar* p return g_hash_table_contains(self->playlists, playlist_uuid); } -gboolean koto_cartographer_has_track(KotoCartographer *self, KotoIndexedTrack *track) { - gchar *track_uuid = NULL; +gboolean koto_cartographer_has_track( + KotoCartographer * self, + KotoIndexedTrack * track +) { + gchar * track_uuid = NULL; + + g_object_get(track, "uuid", &track_uuid, NULL); return koto_cartographer_has_album_by_uuid(self, track_uuid); } -gboolean koto_cartographer_has_track_by_uuid(KotoCartographer *self, gchar* track_uuid) { +gboolean koto_cartographer_has_track_by_uuid( + KotoCartographer * self, + gchar* track_uuid +) { if (track_uuid == NULL) { return FALSE; } @@ -330,13 +425,21 @@ gboolean koto_cartographer_has_track_by_uuid(KotoCartographer *self, gchar* trac return g_hash_table_contains(self->tracks, track_uuid); } -void koto_cartographer_remove_album(KotoCartographer *self, KotoIndexedAlbum *album) { - gchar *album_uuid = NULL; +void koto_cartographer_remove_album( + KotoCartographer * self, + KotoIndexedAlbum * album +) { + gchar * album_uuid = NULL; + + g_object_get(album, "uuid", &album_uuid, NULL); koto_cartographer_remove_album_by_uuid(self, album_uuid); } -void koto_cartographer_remove_album_by_uuid(KotoCartographer *self, gchar* album_uuid) { +void koto_cartographer_remove_album_by_uuid( + KotoCartographer * self, + gchar* album_uuid +) { if (album_uuid != NULL) { g_hash_table_remove(self->albums, album_uuid); @@ -349,13 +452,21 @@ void koto_cartographer_remove_album_by_uuid(KotoCartographer *self, gchar* album } } -void koto_cartographer_remove_artist(KotoCartographer *self, KotoIndexedArtist *artist) { - gchar *artist_uuid = NULL; +void koto_cartographer_remove_artist( + KotoCartographer * self, + KotoIndexedArtist * artist +) { + gchar * artist_uuid = NULL; + + g_object_get(artist, "uuid", &artist_uuid, NULL); koto_cartographer_remove_artist_by_uuid(self, artist_uuid); } -void koto_cartographer_remove_artist_by_uuid(KotoCartographer *self, gchar* artist_uuid) { +void koto_cartographer_remove_artist_by_uuid( + KotoCartographer * self, + gchar* artist_uuid +) { if (artist_uuid == NULL) { g_hash_table_remove(self->artists, artist_uuid); @@ -368,13 +479,21 @@ void koto_cartographer_remove_artist_by_uuid(KotoCartographer *self, gchar* arti } } -void koto_cartographer_remove_playlist(KotoCartographer *self, KotoPlaylist *playlist) { - gchar *playlist_uuid = NULL; +void koto_cartographer_remove_playlist( + KotoCartographer * self, + KotoPlaylist * playlist +) { + gchar * playlist_uuid = NULL; + + g_object_get(playlist, "uuid", &playlist_uuid, NULL); koto_cartographer_remove_playlist_by_uuid(self, playlist_uuid); } -void koto_cartographer_remove_playlist_by_uuid(KotoCartographer *self, gchar* playlist_uuid) { +void koto_cartographer_remove_playlist_by_uuid( + KotoCartographer * self, + gchar* playlist_uuid +) { if (playlist_uuid != NULL) { g_hash_table_remove(self->playlists, playlist_uuid); @@ -387,13 +506,21 @@ void koto_cartographer_remove_playlist_by_uuid(KotoCartographer *self, gchar* pl } } -void koto_cartographer_remove_track(KotoCartographer *self, KotoIndexedTrack *track) { - gchar *track_uuid = NULL; +void koto_cartographer_remove_track( + KotoCartographer * self, + KotoIndexedTrack * track +) { + gchar * track_uuid = NULL; + + g_object_get(track, "uuid", &track_uuid, NULL); koto_cartographer_remove_track_by_uuid(self, track_uuid); } -void koto_cartographer_remove_track_by_uuid(KotoCartographer *self, gchar* track_uuid) { +void koto_cartographer_remove_track_by_uuid( + KotoCartographer * self, + gchar* track_uuid +) { if (track_uuid != NULL) { g_hash_table_remove(self->tracks, track_uuid); @@ -406,6 +533,6 @@ void koto_cartographer_remove_track_by_uuid(KotoCartographer *self, gchar* track } } -KotoCartographer* koto_cartographer_new() { +KotoCartographer * koto_cartographer_new() { return g_object_new(KOTO_TYPE_CARTOGRAPHER, NULL); } diff --git a/src/db/cartographer.h b/src/db/cartographer.h index b7d675e..90bfa24 100644 --- a/src/db/cartographer.h +++ b/src/db/cartographer.h @@ -24,7 +24,7 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_CARTOGRAPHER koto_cartographer_get_type() @@ -36,39 +36,135 @@ GType koto_cartographer_get_type(void) G_GNUC_CONST; /** * Cartographer Functions -**/ + **/ -KotoCartographer* koto_cartographer_new(); +KotoCartographer * koto_cartographer_new(); -void koto_cartographer_add_album(KotoCartographer *self, KotoIndexedAlbum *album); -void koto_cartographer_add_artist(KotoCartographer *self, KotoIndexedArtist *artist); -void koto_cartographer_add_playlist(KotoCartographer *self, KotoPlaylist *playlist); -void koto_cartographer_add_track(KotoCartographer *self, KotoIndexedTrack *track); +void koto_cartographer_add_album( + KotoCartographer * self, + KotoIndexedAlbum * album +); -void koto_cartographer_emit_playlist_added(KotoPlaylist *playlist, KotoCartographer *self); +void koto_cartographer_add_artist( + KotoCartographer * self, + KotoIndexedArtist * artist +); -KotoIndexedAlbum* koto_cartographer_get_album_by_uuid(KotoCartographer *self, gchar* album_uuid); -KotoIndexedArtist* koto_cartographer_get_artist_by_uuid(KotoCartographer *self, gchar* artist_uuid); -KotoPlaylist* koto_cartographer_get_playlist_by_uuid(KotoCartographer *self, gchar* playlist_uuid); -GHashTable* koto_cartographer_get_playlists(KotoCartographer *self); -KotoIndexedTrack* koto_cartographer_get_track_by_uuid(KotoCartographer *self, gchar* track_uuid); +void koto_cartographer_add_playlist( + KotoCartographer * self, + KotoPlaylist * playlist +); -gboolean koto_cartographer_has_album(KotoCartographer *self, KotoIndexedAlbum *album); -gboolean koto_cartographer_has_album_by_uuid(KotoCartographer *self, gchar* album_uuid); -gboolean koto_cartographer_has_artist(KotoCartographer *self, KotoIndexedArtist *artist); -gboolean koto_cartographer_has_artist_by_uuid(KotoCartographer *self, gchar* artist_uuid); -gboolean koto_cartographer_has_playlist(KotoCartographer *self, KotoPlaylist *playlist); -gboolean koto_cartographer_has_playlist_by_uuid(KotoCartographer *self, gchar* playlist_uuid); -gboolean koto_cartographer_has_track(KotoCartographer *self, KotoIndexedTrack *track); -gboolean koto_cartographer_has_track_by_uuid(KotoCartographer *self, gchar* track_uuid); +void koto_cartographer_add_track( + KotoCartographer * self, + KotoIndexedTrack * track +); -void koto_cartographer_remove_album(KotoCartographer *self, KotoIndexedAlbum *album); -void koto_cartographer_remove_album_by_uuid(KotoCartographer *self, gchar* album_uuid); -void koto_cartographer_remove_artist(KotoCartographer *self, KotoIndexedArtist *artist); -void koto_cartographer_remove_artist_by_uuid(KotoCartographer *self, gchar* artist_uuid); -void koto_cartographer_remove_playlist(KotoCartographer *self, KotoPlaylist *playlist); -void koto_cartographer_remove_playlist_by_uuid(KotoCartographer *self, gchar* playlist_uuid); -void koto_cartographer_remove_track(KotoCartographer *self, KotoIndexedTrack *track); -void koto_cartographer_remove_track_by_uuid(KotoCartographer *self, gchar* track_uuid); +void koto_cartographer_emit_playlist_added( + KotoPlaylist * playlist, + KotoCartographer * self +); + +KotoIndexedAlbum * koto_cartographer_get_album_by_uuid( + KotoCartographer * self, + gchar* album_uuid +); + +KotoIndexedArtist * koto_cartographer_get_artist_by_uuid( + KotoCartographer * self, + gchar* artist_uuid +); + +KotoPlaylist * koto_cartographer_get_playlist_by_uuid( + KotoCartographer * self, + gchar* playlist_uuid +); + +GHashTable * koto_cartographer_get_playlists(KotoCartographer * self); + +KotoIndexedTrack * koto_cartographer_get_track_by_uuid( + KotoCartographer * self, + gchar* track_uuid +); + +gboolean koto_cartographer_has_album( + KotoCartographer * self, + KotoIndexedAlbum * album +); + +gboolean koto_cartographer_has_album_by_uuid( + KotoCartographer * self, + gchar* album_uuid +); + +gboolean koto_cartographer_has_artist( + KotoCartographer * self, + KotoIndexedArtist * artist +); + +gboolean koto_cartographer_has_artist_by_uuid( + KotoCartographer * self, + gchar* artist_uuid +); + +gboolean koto_cartographer_has_playlist( + KotoCartographer * self, + KotoPlaylist * playlist +); + +gboolean koto_cartographer_has_playlist_by_uuid( + KotoCartographer * self, + gchar* playlist_uuid +); + +gboolean koto_cartographer_has_track( + KotoCartographer * self, + KotoIndexedTrack * track +); + +gboolean koto_cartographer_has_track_by_uuid( + KotoCartographer * self, + gchar* track_uuid +); + +void koto_cartographer_remove_album( + KotoCartographer * self, + KotoIndexedAlbum * album +); + +void koto_cartographer_remove_album_by_uuid( + KotoCartographer * self, + gchar* album_uuid +); + +void koto_cartographer_remove_artist( + KotoCartographer * self, + KotoIndexedArtist * artist +); + +void koto_cartographer_remove_artist_by_uuid( + KotoCartographer * self, + gchar* artist_uuid +); + +void koto_cartographer_remove_playlist( + KotoCartographer * self, + KotoPlaylist * playlist +); + +void koto_cartographer_remove_playlist_by_uuid( + KotoCartographer * self, + gchar* playlist_uuid +); + +void koto_cartographer_remove_track( + KotoCartographer * self, + KotoIndexedTrack * track +); + +void koto_cartographer_remove_track_by_uuid( + KotoCartographer * self, + gchar* track_uuid +); G_END_DECLS diff --git a/src/db/db.c b/src/db/db.c index 0100353..1d4afa8 100644 --- a/src/db/db.c +++ b/src/db/db.c @@ -26,8 +26,8 @@ int KOTO_DB_SUCCESS = 0; int KOTO_DB_NEW = 1; int KOTO_DB_FAIL = 2; -sqlite3 *koto_db = NULL; -gchar *db_filepath = NULL; +sqlite3 * koto_db = NULL; +gchar * db_filepath = NULL; gboolean created_new_db = FALSE; void close_db() { @@ -35,14 +35,15 @@ void close_db() { } int create_db_tables() { - char *tables_creation_queries = "CREATE TABLE IF NOT EXISTS artists(id string UNIQUE PRIMARY KEY, path string, type int, name string, art_path string);" - "CREATE TABLE IF NOT EXISTS albums(id string UNIQUE PRIMARY KEY, path string, artist_id string, name string, art_path string, FOREIGN KEY(artist_id) REFERENCES artists(id) ON DELETE CASCADE);" - "CREATE TABLE IF NOT EXISTS tracks(id string UNIQUE PRIMARY KEY, path string, type int, artist_id string, album_id string, file_name string, name string, disc int, position int, FOREIGN KEY(artist_id) REFERENCES artists(id) ON DELETE CASCADE);" - "CREATE TABLE IF NOT EXISTS playlist_meta(id string UNIQUE PRIMARY KEY, name string, art_path string, preferred_model int);" - "CREATE TABLE IF NOT EXISTS playlist_tracks(position INTEGER PRIMARY KEY AUTOINCREMENT, playlist_id string, track_id string, current int, FOREIGN KEY(playlist_id) REFERENCES playlist_meta(id), FOREIGN KEY(track_id) REFERENCES tracks(id) ON DELETE CASCADE);"; + char * tables_creation_queries = "CREATE TABLE IF NOT EXISTS artists(id string UNIQUE PRIMARY KEY, path string, type int, name string, art_path string);" + "CREATE TABLE IF NOT EXISTS albums(id string UNIQUE PRIMARY KEY, path string, artist_id string, name string, art_path string, FOREIGN KEY(artist_id) REFERENCES artists(id) ON DELETE CASCADE);" + "CREATE TABLE IF NOT EXISTS tracks(id string UNIQUE PRIMARY KEY, path string, type int, artist_id string, album_id string, file_name string, name string, disc int, position int, FOREIGN KEY(artist_id) REFERENCES artists(id) ON DELETE CASCADE);" + "CREATE TABLE IF NOT EXISTS playlist_meta(id string UNIQUE PRIMARY KEY, name string, art_path string, preferred_model int);" + "CREATE TABLE IF NOT EXISTS playlist_tracks(position INTEGER PRIMARY KEY AUTOINCREMENT, playlist_id string, track_id string, current int, FOREIGN KEY(playlist_id) REFERENCES playlist_meta(id), FOREIGN KEY(track_id) REFERENCES tracks(id) ON DELETE CASCADE);"; + + gchar * create_tables_errmsg = NULL; + int rc = sqlite3_exec(koto_db, tables_creation_queries, 0, 0, &create_tables_errmsg); - gchar *create_tables_errmsg = NULL; - int rc = sqlite3_exec(koto_db, tables_creation_queries, 0,0, &create_tables_errmsg); if (rc != SQLITE_OK) { g_critical("Failed to create required tables: %s", create_tables_errmsg); @@ -52,9 +53,10 @@ int create_db_tables() { } int enable_foreign_keys() { - gchar *enable_foreign_keys_err = NULL; + gchar * enable_foreign_keys_err = NULL; int rc = sqlite3_exec(koto_db, "PRAGMA foreign_keys = ON;", 0, 0, &enable_foreign_keys_err); + if (rc != SQLITE_OK) { g_critical("Failed to enable foreign key support. Ensure your sqlite3 is compiled with neither SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined: %s", enable_foreign_keys_err); } @@ -63,10 +65,10 @@ int enable_foreign_keys() { return (rc == SQLITE_OK) ? KOTO_DB_SUCCESS : KOTO_DB_FAIL; } -gchar* get_db_path() { +gchar * get_db_path() { if (db_filepath == NULL) { - const gchar *data_home = g_get_user_data_dir(); - gchar *data_dir = g_build_path(G_DIR_SEPARATOR_S, data_home, "com.github.joshstrobl.koto", NULL); + const gchar * data_home = g_get_user_data_dir(); + gchar * data_dir = g_build_path(G_DIR_SEPARATOR_S, data_home, "com.github.joshstrobl.koto", NULL); db_filepath = g_build_filename(g_strdup(data_dir), "db", NULL); // Build out our path using XDG_DATA_HOME (e.g. .local/share/) + our namespace + db as the file name g_free(data_dir); } @@ -78,15 +80,17 @@ int have_existing_db() { struct stat db_stat; int success = stat(get_db_path(), &db_stat); + return ((success == 0) && S_ISREG(db_stat.st_mode)) ? 0 : 1; } int open_db() { int ret = KOTO_DB_SUCCESS; // Default to last return being SUCCESS + if (have_existing_db() == 1) { // If we do not have an existing DB - const gchar *data_home = g_get_user_data_dir(); - const gchar *data_dir = g_path_get_dirname(db_filepath); + const gchar * data_home = g_get_user_data_dir(); + const gchar * data_dir = g_path_get_dirname(db_filepath); mkdir(data_home, 0755); mkdir(data_dir, 0755); chown(data_dir, getuid(), getgid()); @@ -102,7 +106,7 @@ int open_db() { return KOTO_DB_FAIL; } - if (create_db_tables() != KOTO_DB_SUCCESS) {// Failed to create our database tables + if (create_db_tables() != KOTO_DB_SUCCESS) { // Failed to create our database tables return KOTO_DB_FAIL; } diff --git a/src/db/db.h b/src/db/db.h index dd8d83f..2748aa0 100644 --- a/src/db/db.h +++ b/src/db/db.h @@ -24,8 +24,13 @@ extern int KOTO_DB_FAIL; extern gboolean created_new_db; void close_db(); + int create_db_tables(); -gchar* get_db_path(); + +gchar * get_db_path(); + int enable_foreign_keys(); + int have_existing_db(); + int open_db(); diff --git a/src/indexer/album.c b/src/indexer/album.c index 881cb1c..42affa8 100644 --- a/src/indexer/album.c +++ b/src/indexer/album.c @@ -25,19 +25,19 @@ #include "structs.h" #include "koto-utils.h" -extern KotoCartographer *koto_maps; -extern KotoCurrentPlaylist *current_playlist; -extern sqlite3 *koto_db; +extern KotoCartographer * koto_maps; +extern KotoCurrentPlaylist * current_playlist; +extern sqlite3 * koto_db; struct _KotoIndexedAlbum { GObject parent_instance; - gchar *uuid; - gchar *path; + gchar * uuid; + gchar * path; - gchar *name; - gchar *art_path; - gchar *artist_uuid; - GList *tracks; + gchar * name; + gchar * art_path; + gchar * artist_uuid; + GList * tracks; gboolean has_album_art; gboolean do_initial_index; @@ -56,13 +56,28 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; + +static void koto_indexed_album_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_indexed_album_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_indexed_album_class_init(KotoIndexedAlbumClass * c) { + GObjectClass * gobject_class; -static void koto_indexed_album_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_indexed_album_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_indexed_album_set_property; gobject_class->get_property = koto_indexed_album_get_property; @@ -72,7 +87,7 @@ static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { "UUID to Album in database", "UUID to Album in database", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_DO_INITIAL_INDEX] = g_param_spec_boolean( @@ -80,7 +95,7 @@ static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { "Do an initial indexing operating instead of pulling from the database", "Do an initial indexing operating instead of pulling from the database", FALSE, - G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_PATH] = g_param_spec_string( @@ -88,7 +103,7 @@ static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { "Path", "Path to Album", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ALBUM_NAME] = g_param_spec_string( @@ -96,7 +111,7 @@ static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { "Name", "Name of Album", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ART_PATH] = g_param_spec_string( @@ -104,7 +119,7 @@ static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { "Path to Artwork", "Path to Artwork", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ARTIST_UUID] = g_param_spec_string( @@ -112,23 +127,28 @@ static void koto_indexed_album_class_init(KotoIndexedAlbumClass *c) { "UUID of Artist associated with Album", "UUID of Artist associated with Album", NULL, - G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_indexed_album_init(KotoIndexedAlbum *self) { +static void koto_indexed_album_init(KotoIndexedAlbum * self) { self->has_album_art = FALSE; self->tracks = NULL; } -void koto_indexed_album_add_track(KotoIndexedAlbum *self, KotoIndexedTrack *track) { +void koto_indexed_album_add_track( + KotoIndexedAlbum * self, + KotoIndexedTrack * track +) { if (track == NULL) { // Not a file return; } - gchar *track_uuid; + gchar * track_uuid; + + g_object_get(track, "uuid", &track_uuid, NULL); if (g_list_index(self->tracks, track_uuid) == -1) { @@ -136,12 +156,12 @@ void koto_indexed_album_add_track(KotoIndexedAlbum *self, KotoIndexedTrack *trac } } -void koto_indexed_album_commit(KotoIndexedAlbum *self) { +void koto_indexed_album_commit(KotoIndexedAlbum * self) { if (self->art_path == NULL) { // If art_path isn't defined when committing koto_indexed_album_set_album_art(self, ""); // Set to an empty string } - gchar *commit_op = g_strdup_printf( + gchar * commit_op = g_strdup_printf( "INSERT INTO albums(id, path, artist_id, name, art_path)" "VALUES('%s', quote(\"%s\"), '%s', quote(\"%s\"), quote(\"%s\"))" "ON CONFLICT(id) DO UPDATE SET path=excluded.path, name=excluded.name, art_path=excluded.art_path;", @@ -152,9 +172,10 @@ void koto_indexed_album_commit(KotoIndexedAlbum *self) { self->art_path ); - gchar *commit_op_errmsg = NULL; + gchar * commit_op_errmsg = NULL; int rc = sqlite3_exec(koto_db, commit_op, 0, 0, &commit_op_errmsg); + if (rc != SQLITE_OK) { g_warning("Failed to write our album to the database: %s", commit_op_errmsg); } @@ -163,9 +184,10 @@ void koto_indexed_album_commit(KotoIndexedAlbum *self) { g_free(commit_op_errmsg); } -void koto_indexed_album_find_album_art(KotoIndexedAlbum *self) { +void koto_indexed_album_find_album_art(KotoIndexedAlbum * self) { magic_t magic_cookie = magic_open(MAGIC_MIME); + if (magic_cookie == NULL) { return; } @@ -175,13 +197,15 @@ void koto_indexed_album_find_album_art(KotoIndexedAlbum *self) { return; } - DIR *dir = opendir(self->path); // Attempt to open our directory + DIR * dir = opendir(self->path); // Attempt to open our directory + if (dir == NULL) { return; } - struct dirent *entry; + struct dirent * entry; + while ((entry = readdir(dir))) { if (entry->d_type != DT_REG) { // Not a regular file @@ -192,9 +216,9 @@ void koto_indexed_album_find_album_art(KotoIndexedAlbum *self) { continue; // Skip } - gchar *full_path = g_strdup_printf("%s%s%s", self->path, G_DIR_SEPARATOR_S, entry->d_name); + gchar * full_path = g_strdup_printf("%s%s%s", self->path, G_DIR_SEPARATOR_S, entry->d_name); - const char *mime_type = magic_file(magic_cookie, full_path); + const char * mime_type = magic_file(magic_cookie, full_path); if (mime_type == NULL) { // Failed to get the mimetype g_free(full_path); @@ -202,8 +226,8 @@ void koto_indexed_album_find_album_art(KotoIndexedAlbum *self) { } if (g_str_has_prefix(mime_type, "image/") && !self->has_album_art) { // Is an image file and doesn't have album art yet - gchar *album_art_no_ext = g_strdup(koto_utils_get_filename_without_extension(entry->d_name)); // Get the name of the file without the extension - gchar *lower_art = g_strdup(g_utf8_strdown(album_art_no_ext, -1)); // Lowercase + gchar * album_art_no_ext = g_strdup(koto_utils_get_filename_without_extension(entry->d_name)); // Get the name of the file without the extension + gchar * lower_art = g_strdup(g_utf8_strdown(album_art_no_ext, -1)); // Lowercase if ( (g_strrstr(lower_art, "Small") == NULL) && // Not Small @@ -226,7 +250,11 @@ void koto_indexed_album_find_album_art(KotoIndexedAlbum *self) { magic_close(magic_cookie); } -void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie, const gchar *path) { +void koto_indexed_album_find_tracks( + KotoIndexedAlbum * self, + magic_t magic_cookie, + const gchar * path +) { if (magic_cookie == NULL) { // No cookie provided magic_cookie = magic_open(MAGIC_MIME); } @@ -244,20 +272,22 @@ void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie return; } - DIR *dir = opendir(path); // Attempt to open our directory + DIR * dir = opendir(path); // Attempt to open our directory + if (dir == NULL) { return; } - struct dirent *entry; + struct dirent * entry; + while ((entry = readdir(dir))) { if (g_str_has_prefix(entry->d_name, ".")) { // Reference to parent dir, self, or a hidden item continue; // Skip } - gchar *full_path = g_strdup_printf("%s%s%s", path, G_DIR_SEPARATOR_S, entry->d_name); + gchar * full_path = g_strdup_printf("%s%s%s", path, G_DIR_SEPARATOR_S, entry->d_name); if (entry->d_type == DT_DIR) { // If this is a directory koto_indexed_album_find_tracks(self, magic_cookie, full_path); // Recursively find tracks @@ -269,7 +299,7 @@ void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie continue; // SKIP } - const char *mime_type = magic_file(magic_cookie, full_path); + const char * mime_type = magic_file(magic_cookie, full_path); if (mime_type == NULL) { // Failed to get the mimetype g_free(full_path); @@ -277,19 +307,19 @@ void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie } if (g_str_has_prefix(mime_type, "audio/") || g_str_has_prefix(mime_type, "video/ogg")) { // Is an audio file or ogg because it is special - gchar *appended_slash_to_path = g_strdup_printf("%s%s", g_strdup(self->path), G_DIR_SEPARATOR_S); - gchar **possible_cd_split = g_strsplit(full_path, appended_slash_to_path, -1); // Split based on the album path - guint *cd = (guint*) 1; + gchar * appended_slash_to_path = g_strdup_printf("%s%s", g_strdup(self->path), G_DIR_SEPARATOR_S); + gchar ** possible_cd_split = g_strsplit(full_path, appended_slash_to_path, -1); // Split based on the album path + guint * cd = (guint*) 1; - gchar *track_with_cd_sep = g_strdup(possible_cd_split[1]); // Duplicate - gchar **split_on_cd = g_strsplit(track_with_cd_sep, G_DIR_SEPARATOR_S, -1); // Split based on separator (e.g. / ) + gchar * track_with_cd_sep = g_strdup(possible_cd_split[1]); // Duplicate + gchar ** split_on_cd = g_strsplit(track_with_cd_sep, G_DIR_SEPARATOR_S, -1); // Split based on separator (e.g. / ) if (g_strv_length(split_on_cd) > 1) { - gchar *cdd = g_strdup(split_on_cd[0]); - gchar **cd_sep = g_strsplit(g_utf8_strdown(cdd, -1), "cd", -1); + gchar * cdd = g_strdup(split_on_cd[0]); + gchar ** cd_sep = g_strsplit(g_utf8_strdown(cdd, -1), "cd", -1); if (g_strv_length(cd_sep) > 1) { - gchar *pos_str = g_strdup(cd_sep[1]); + gchar * pos_str = g_strdup(cd_sep[1]); cd = (guint*) g_ascii_strtoull(pos_str, NULL, 10); // Attempt to convert g_free(pos_str); } @@ -304,7 +334,7 @@ void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie g_strfreev(possible_cd_split); g_free(appended_slash_to_path); - KotoIndexedTrack *track = koto_indexed_track_new(self, full_path, cd); + KotoIndexedTrack * track = koto_indexed_track_new(self, full_path, cd); if (track != NULL) { // Is a file koto_indexed_album_add_track(self, track); // Add our file @@ -315,8 +345,14 @@ void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie } } -static void koto_indexed_album_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoIndexedAlbum *self = KOTO_INDEXED_ALBUM(obj); +static void koto_indexed_album_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoIndexedAlbum * self = KOTO_INDEXED_ALBUM(obj); + switch (prop_id) { case PROP_UUID: @@ -343,8 +379,14 @@ static void koto_indexed_album_get_property(GObject *obj, guint prop_id, GValue } } -static void koto_indexed_album_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec){ - KotoIndexedAlbum *self = KOTO_INDEXED_ALBUM(obj); +static void koto_indexed_album_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoIndexedAlbum * self = KOTO_INDEXED_ALBUM(obj); + switch (prop_id) { case PROP_UUID: @@ -372,7 +414,7 @@ static void koto_indexed_album_set_property(GObject *obj, guint prop_id, const G } } -gchar* koto_indexed_album_get_album_art(KotoIndexedAlbum *self) { +gchar * koto_indexed_album_get_album_art(KotoIndexedAlbum * self) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return g_strdup(""); } @@ -380,7 +422,7 @@ gchar* koto_indexed_album_get_album_art(KotoIndexedAlbum *self) { return g_strdup((self->has_album_art && koto_utils_is_string_valid(self->art_path)) ? self->art_path : ""); } -gchar *koto_indexed_album_get_album_name(KotoIndexedAlbum *self) { +gchar * koto_indexed_album_get_album_name(KotoIndexedAlbum * self) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return NULL; } @@ -392,7 +434,7 @@ gchar *koto_indexed_album_get_album_name(KotoIndexedAlbum *self) { return g_strdup(self->name); // Return duplicate of the name } -gchar* koto_indexed_album_get_album_uuid(KotoIndexedAlbum *self) { +gchar * koto_indexed_album_get_album_uuid(KotoIndexedAlbum * self) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return NULL; } @@ -404,7 +446,7 @@ gchar* koto_indexed_album_get_album_uuid(KotoIndexedAlbum *self) { return g_strdup(self->uuid); // Return a duplicate of the UUID } -GList* koto_indexed_album_get_tracks(KotoIndexedAlbum *self) { +GList * koto_indexed_album_get_tracks(KotoIndexedAlbum * self) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return NULL; } @@ -412,7 +454,10 @@ GList* koto_indexed_album_get_tracks(KotoIndexedAlbum *self) { return self->tracks; // Return } -void koto_indexed_album_set_album_art(KotoIndexedAlbum *self, const gchar *album_art) { +void koto_indexed_album_set_album_art( + KotoIndexedAlbum * self, + const gchar * album_art +) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return; } @@ -430,7 +475,10 @@ void koto_indexed_album_set_album_art(KotoIndexedAlbum *self, const gchar *album self->has_album_art = TRUE; } -void koto_indexed_album_remove_file(KotoIndexedAlbum *self, KotoIndexedTrack *track) { +void koto_indexed_album_remove_file( + KotoIndexedAlbum * self, + KotoIndexedTrack * track +) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return; } @@ -439,12 +487,17 @@ void koto_indexed_album_remove_file(KotoIndexedAlbum *self, KotoIndexedTrack *tr return; } - gchar *track_uuid; + gchar * track_uuid; + + g_object_get(track, "parsed-name", &track_uuid, NULL); self->tracks = g_list_remove(self->tracks, track_uuid); } -void koto_indexed_album_set_album_name(KotoIndexedAlbum *self, const gchar *album_name) { +void koto_indexed_album_set_album_name( + KotoIndexedAlbum * self, + const gchar * album_name +) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return; } @@ -460,7 +513,10 @@ void koto_indexed_album_set_album_name(KotoIndexedAlbum *self, const gchar *albu self->name = g_strdup(album_name); } -void koto_indexed_album_set_artist_uuid(KotoIndexedAlbum *self, const gchar *artist_uuid) { +void koto_indexed_album_set_artist_uuid( + KotoIndexedAlbum * self, + const gchar * artist_uuid +) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return; } @@ -476,7 +532,7 @@ void koto_indexed_album_set_artist_uuid(KotoIndexedAlbum *self, const gchar *art self->artist_uuid = g_strdup(artist_uuid); } -void koto_indexed_album_set_as_current_playlist(KotoIndexedAlbum *self) { +void koto_indexed_album_set_as_current_playlist(KotoIndexedAlbum * self) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return; } @@ -485,17 +541,23 @@ void koto_indexed_album_set_as_current_playlist(KotoIndexedAlbum *self) { return; } - KotoPlaylist *new_album_playlist = koto_playlist_new(); // Create a new playlist + 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 + 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; + 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 @@ -508,10 +570,15 @@ void koto_indexed_album_set_as_current_playlist(KotoIndexedAlbum *self) { koto_current_playlist_set_playlist(current_playlist, new_album_playlist); // Set our new current playlist } -gint koto_indexed_album_sort_tracks(gconstpointer track1_uuid, gconstpointer track2_uuid, gpointer user_data) { +gint koto_indexed_album_sort_tracks( + gconstpointer track1_uuid, + gconstpointer track2_uuid, + gpointer user_data +) { (void) user_data; - KotoIndexedTrack *track1 = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) track1_uuid); - KotoIndexedTrack *track2 = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) track2_uuid); + KotoIndexedTrack * track1 = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) track1_uuid); + KotoIndexedTrack * track2 = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) track2_uuid); + if ((track1 == NULL) && (track2 == NULL)) { // Neither tracks actually exist return 0; @@ -521,8 +588,9 @@ gint koto_indexed_album_sort_tracks(gconstpointer track1_uuid, gconstpointer tra return 1; } - guint *track1_disc = (guint*) 1; - guint *track2_disc = (guint*) 2; + guint * track1_disc = (guint*) 1; + guint * track2_disc = (guint*) 2; + g_object_get(track1, "cd", &track1_disc, NULL); g_object_get(track2, "cd", &track2_disc, NULL); @@ -533,15 +601,16 @@ gint koto_indexed_album_sort_tracks(gconstpointer track1_uuid, gconstpointer tra return 1; } - guint16 *track1_pos; - guint16 *track2_pos; + guint16 * track1_pos; + guint16 * track2_pos; + g_object_get(track1, "position", &track1_pos, NULL); g_object_get(track2, "position", &track2_pos, NULL); if (track1_pos == track2_pos) { // Identical positions (like reported as 0) - gchar *track1_name; - gchar *track2_name; + gchar * track1_name; + gchar * track2_name; g_object_get(track1, "parsed-name", &track1_name, NULL); g_object_get(track2, "parsed-name", &track2_name, NULL); @@ -554,7 +623,10 @@ gint koto_indexed_album_sort_tracks(gconstpointer track1_uuid, gconstpointer tra } } -void koto_indexed_album_update_path(KotoIndexedAlbum *self, gchar* new_path) { +void koto_indexed_album_update_path( + KotoIndexedAlbum * self, + gchar* new_path +) { if (!KOTO_IS_INDEXED_ALBUM(self)) { // Not an album return; } @@ -577,32 +649,52 @@ void koto_indexed_album_update_path(KotoIndexedAlbum *self, gchar* new_path) { koto_indexed_album_find_album_art(self); // Update our path for the album art } -KotoIndexedAlbum* koto_indexed_album_new(KotoIndexedArtist *artist, const gchar *path) { - gchar *artist_uuid = NULL; +KotoIndexedAlbum * koto_indexed_album_new( + KotoIndexedArtist * artist, + const gchar * path +) { + gchar * artist_uuid = NULL; + + g_object_get(artist, "uuid", &artist_uuid, NULL); - KotoIndexedAlbum* album = g_object_new(KOTO_TYPE_INDEXED_ALBUM, - "artist-uuid", artist_uuid, - "uuid", g_strdup(g_uuid_string_random()), - "do-initial-index", TRUE, - "path", path, + KotoIndexedAlbum* album = g_object_new( + KOTO_TYPE_INDEXED_ALBUM, + "artist-uuid", + artist_uuid, + "uuid", + g_strdup(g_uuid_string_random()), + "do-initial-index", + TRUE, + "path", + path, NULL ); + koto_indexed_album_commit(album); koto_indexed_album_find_tracks(album, NULL, NULL); // Scan for tracks now that we committed to the database (hopefully) return album; } -KotoIndexedAlbum* koto_indexed_album_new_with_uuid(KotoIndexedArtist *artist, const gchar *uuid) { - gchar *artist_uuid = NULL; +KotoIndexedAlbum * koto_indexed_album_new_with_uuid( + KotoIndexedArtist * artist, + const gchar * uuid +) { + gchar * artist_uuid = NULL; + + g_object_get(artist, "uuid", &artist_uuid, NULL); - return g_object_new(KOTO_TYPE_INDEXED_ALBUM, - "artist-uuid", artist, - "uuid", g_strdup(uuid), - "do-initial-index", FALSE, + return g_object_new( + KOTO_TYPE_INDEXED_ALBUM, + "artist-uuid", + artist, + "uuid", + g_strdup(uuid), + "do-initial-index", + FALSE, NULL ); } diff --git a/src/indexer/artist.c b/src/indexer/artist.c index 245979c..4587bca 100644 --- a/src/indexer/artist.c +++ b/src/indexer/artist.c @@ -21,16 +21,16 @@ #include "../db/db.h" #include "../koto-utils.h" -extern sqlite3 *koto_db; +extern sqlite3 * koto_db; struct _KotoIndexedArtist { GObject parent_instance; - gchar *uuid; - gchar *path; + gchar * uuid; + gchar * path; gboolean has_artist_art; - gchar *artist_name; - GList *albums; + gchar * artist_name; + GList * albums; }; G_DEFINE_TYPE(KotoIndexedArtist, koto_indexed_artist, G_TYPE_OBJECT); @@ -43,13 +43,28 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; + +static void koto_indexed_artist_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_indexed_artist_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_indexed_artist_class_init(KotoIndexedArtistClass * c) { + GObjectClass * gobject_class; -static void koto_indexed_artist_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_indexed_artist_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_indexed_artist_class_init(KotoIndexedArtistClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_indexed_artist_set_property; gobject_class->get_property = koto_indexed_artist_get_property; @@ -59,7 +74,7 @@ static void koto_indexed_artist_class_init(KotoIndexedArtistClass *c) { "UUID to Artist in database", "UUID to Artist in database", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_PATH] = g_param_spec_string( @@ -67,7 +82,7 @@ static void koto_indexed_artist_class_init(KotoIndexedArtistClass *c) { "Path", "Path to Artist", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ARTIST_NAME] = g_param_spec_string( @@ -75,19 +90,19 @@ static void koto_indexed_artist_class_init(KotoIndexedArtistClass *c) { "Name", "Name of Artist", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -void koto_indexed_artist_commit(KotoIndexedArtist *self) { +void koto_indexed_artist_commit(KotoIndexedArtist * self) { if ((self->uuid == NULL) || strcmp(self->uuid, "")) { // UUID not set self->uuid = g_strdup(g_uuid_string_random()); } // TODO: Support multiple types instead of just local music artist - gchar *commit_op = g_strdup_printf( + gchar * commit_op = g_strdup_printf( "INSERT INTO artists(id,path,type,name,art_path)" "VALUES ('%s', quote(\"%s\"), 0, quote(\"%s\"), NULL)" "ON CONFLICT(id) DO UPDATE SET path=excluded.path, type=excluded.type, name=excluded.name, art_path=excluded.art_path;", @@ -96,9 +111,10 @@ void koto_indexed_artist_commit(KotoIndexedArtist *self) { self->artist_name ); - gchar *commit_opt_errmsg = NULL; + gchar * commit_opt_errmsg = NULL; int rc = sqlite3_exec(koto_db, commit_op, 0, 0, &commit_opt_errmsg); + if (rc != SQLITE_OK) { g_warning("Failed to write our artist to the database: %s", commit_opt_errmsg); } @@ -107,13 +123,19 @@ void koto_indexed_artist_commit(KotoIndexedArtist *self) { g_free(commit_opt_errmsg); } -static void koto_indexed_artist_init(KotoIndexedArtist *self) { +static void koto_indexed_artist_init(KotoIndexedArtist * self) { self->has_artist_art = FALSE; self->albums = NULL; // Create a new GList } -static void koto_indexed_artist_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoIndexedArtist *self = KOTO_INDEXED_ARTIST(obj); +static void koto_indexed_artist_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoIndexedArtist * self = KOTO_INDEXED_ARTIST(obj); + switch (prop_id) { case PROP_UUID: @@ -131,8 +153,14 @@ static void koto_indexed_artist_get_property(GObject *obj, guint prop_id, GValue } } -static void koto_indexed_artist_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoIndexedArtist *self = KOTO_INDEXED_ARTIST(obj); +static void koto_indexed_artist_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoIndexedArtist * self = KOTO_INDEXED_ARTIST(obj); + switch (prop_id) { case PROP_UUID: @@ -151,7 +179,10 @@ static void koto_indexed_artist_set_property(GObject *obj, guint prop_id, const } } -void koto_indexed_artist_add_album(KotoIndexedArtist *self, gchar *album_uuid) { +void koto_indexed_artist_add_album( + KotoIndexedArtist * self, + gchar * album_uuid +) { if (!KOTO_IS_INDEXED_ARTIST(self)) { // Not an artist return; } @@ -160,14 +191,15 @@ void koto_indexed_artist_add_album(KotoIndexedArtist *self, gchar *album_uuid) { return; } - gchar *uuid = g_strdup(album_uuid); // Duplicate our UUID + gchar * uuid = g_strdup(album_uuid); // Duplicate our UUID + if (g_list_index(self->albums, uuid) == -1) { self->albums = g_list_append(self->albums, uuid); // Push to end of list } } -GList* koto_indexed_artist_get_albums(KotoIndexedArtist *self) { +GList * koto_indexed_artist_get_albums(KotoIndexedArtist * self) { if (!KOTO_IS_INDEXED_ARTIST(self)) { // Not an artist return NULL; } @@ -175,7 +207,7 @@ GList* koto_indexed_artist_get_albums(KotoIndexedArtist *self) { return g_list_copy(self->albums); } -gchar* koto_indexed_artist_get_name(KotoIndexedArtist *self) { +gchar * koto_indexed_artist_get_name(KotoIndexedArtist * self) { if (!KOTO_IS_INDEXED_ARTIST(self)) { // Not an artist return g_strdup(""); } @@ -183,7 +215,10 @@ gchar* koto_indexed_artist_get_name(KotoIndexedArtist *self) { return g_strdup(koto_utils_is_string_valid(self->artist_name) ? self->artist_name : ""); // Return artist name if set } -void koto_indexed_artist_remove_album(KotoIndexedArtist *self, KotoIndexedAlbum *album) { +void koto_indexed_artist_remove_album( + KotoIndexedArtist * self, + KotoIndexedAlbum * album +) { if (!KOTO_IS_INDEXED_ARTIST(self)) { // Not an artist return; } @@ -192,12 +227,17 @@ void koto_indexed_artist_remove_album(KotoIndexedArtist *self, KotoIndexedAlbum return; } - gchar *album_uuid; + gchar * album_uuid; + + g_object_get(album, "uuid", &album_uuid, NULL); self->albums = g_list_remove(self->albums, album_uuid); } -void koto_indexed_artist_update_path(KotoIndexedArtist *self, gchar *new_path) { +void koto_indexed_artist_update_path( + KotoIndexedArtist * self, + gchar * new_path +) { if (!KOTO_IS_INDEXED_ARTIST(self)) { // Not an artist return; } @@ -214,7 +254,10 @@ void koto_indexed_artist_update_path(KotoIndexedArtist *self, gchar *new_path) { g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PATH]); } -void koto_indexed_artist_set_artist_name(KotoIndexedArtist *self, gchar *artist_name) { +void koto_indexed_artist_set_artist_name( + KotoIndexedArtist * self, + gchar * artist_name +) { if (!KOTO_IS_INDEXED_ARTIST(self)) { // Not an artist return; } @@ -231,21 +274,28 @@ void koto_indexed_artist_set_artist_name(KotoIndexedArtist *self, gchar *artist_ g_object_notify_by_pspec(G_OBJECT(self), props[PROP_ARTIST_NAME]); } -KotoIndexedArtist* koto_indexed_artist_new(gchar *path) { - KotoIndexedArtist* artist = g_object_new(KOTO_TYPE_INDEXED_ARTIST, - "uuid", g_uuid_string_random(), - "path", path, - "name", g_path_get_basename(path), +KotoIndexedArtist * koto_indexed_artist_new(gchar * path) { + KotoIndexedArtist* artist = g_object_new( + KOTO_TYPE_INDEXED_ARTIST, + "uuid", + g_uuid_string_random(), + "path", + path, + "name", + g_path_get_basename(path), NULL ); + koto_indexed_artist_commit(artist); // Commit the artist immediately to the database return artist; } -KotoIndexedArtist* koto_indexed_artist_new_with_uuid(const gchar *uuid) { - return g_object_new(KOTO_TYPE_INDEXED_ARTIST, - "uuid", g_strdup(uuid), +KotoIndexedArtist * koto_indexed_artist_new_with_uuid(const gchar * uuid) { + return g_object_new( + KOTO_TYPE_INDEXED_ARTIST, + "uuid", + g_strdup(uuid), NULL ); } diff --git a/src/indexer/file-indexer.c b/src/indexer/file-indexer.c index b5568f7..4e579ca 100644 --- a/src/indexer/file-indexer.c +++ b/src/indexer/file-indexer.c @@ -26,14 +26,14 @@ #include "../koto-utils.h" #include "structs.h" -extern KotoCartographer *koto_maps; -extern sqlite3 *koto_db; +extern KotoCartographer * koto_maps; +extern sqlite3 * koto_db; struct _KotoIndexedLibrary { GObject parent_instance; - gchar *path; + gchar * path; magic_t magic_cookie; - GHashTable *music_artists; + GHashTable * music_artists; }; G_DEFINE_TYPE(KotoIndexedLibrary, koto_indexed_library, G_TYPE_OBJECT); @@ -44,13 +44,28 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; + +static void koto_indexed_library_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_indexed_library_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_indexed_library_class_init(KotoIndexedLibraryClass * c) { + GObjectClass * gobject_class; -static void koto_indexed_library_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_indexed_library_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_indexed_library_class_init(KotoIndexedLibraryClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_indexed_library_set_property; gobject_class->get_property = koto_indexed_library_get_property; @@ -60,26 +75,31 @@ static void koto_indexed_library_class_init(KotoIndexedLibraryClass *c) { "Path", "Path to Music", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_UTF8); // Ensure our id3v2 text encoding is UTF-8 } -static void koto_indexed_library_init(KotoIndexedLibrary *self) { +static void koto_indexed_library_init(KotoIndexedLibrary * self) { self->music_artists = g_hash_table_new(g_str_hash, g_str_equal); } -void koto_indexed_library_add_artist(KotoIndexedLibrary *self, KotoIndexedArtist *artist) { +void koto_indexed_library_add_artist( + KotoIndexedLibrary * self, + KotoIndexedArtist * artist +) { if (artist == NULL) { // No artist return; } koto_indexed_library_get_artists(self); // Call to generate if needed - gchar *artist_name; - gchar *artist_uuid; + gchar * artist_name; + gchar * artist_uuid; + + g_object_get(artist, "name", &artist_name, "uuid", &artist_uuid, NULL); if (g_hash_table_contains(self->music_artists, artist_name)) { // Already have the artist @@ -90,24 +110,28 @@ void koto_indexed_library_add_artist(KotoIndexedLibrary *self, KotoIndexedArtist g_hash_table_insert(self->music_artists, artist_name, artist_uuid); // Add the artist by its name (this needs to be done so we can get the artist when doing the depth of 2 indexing for the album) } -KotoIndexedArtist* koto_indexed_library_get_artist(KotoIndexedLibrary *self, gchar *artist_name) { +KotoIndexedArtist * koto_indexed_library_get_artist( + KotoIndexedLibrary * self, + gchar * artist_name +) { if (artist_name == NULL) { return NULL; } koto_indexed_library_get_artists(self); // Call to generate if needed - gchar *artist_uuid = g_hash_table_lookup(self->music_artists, artist_name); // Get the UUID from our music artists + gchar * artist_uuid = g_hash_table_lookup(self->music_artists, artist_name); // Get the UUID from our music artists + if (artist_uuid != NULL) { - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); // Return any artist from cartographer + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); // Return any artist from cartographer return artist; } else { return NULL; } } -GHashTable* koto_indexed_library_get_artists(KotoIndexedLibrary *self) { +GHashTable * koto_indexed_library_get_artists(KotoIndexedLibrary * self) { if (self->music_artists == NULL) { // Not a HashTable self->music_artists = g_hash_table_new(g_str_hash, g_str_equal); } @@ -115,21 +139,32 @@ GHashTable* koto_indexed_library_get_artists(KotoIndexedLibrary *self) { return self->music_artists; } -void koto_indexed_library_remove_artist(KotoIndexedLibrary *self, KotoIndexedArtist *artist) { +void koto_indexed_library_remove_artist( + KotoIndexedLibrary * self, + KotoIndexedArtist * artist +) { if (artist == NULL) { return; } koto_indexed_library_get_artists(self); // Call to generate if needed - gchar *artist_name; + gchar * artist_name; + + g_object_get(artist, "name", &artist_name, NULL); g_hash_table_remove(self->music_artists, artist_name); // Remove the artist } -static void koto_indexed_library_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoIndexedLibrary *self = KOTO_INDEXED_LIBRARY(obj); +static void koto_indexed_library_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoIndexedLibrary * self = KOTO_INDEXED_LIBRARY(obj); + switch (prop_id) { case PROP_PATH: @@ -141,8 +176,14 @@ static void koto_indexed_library_get_property(GObject *obj, guint prop_id, GValu } } -static void koto_indexed_library_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec){ - KotoIndexedLibrary *self = KOTO_INDEXED_LIBRARY(obj); +static void koto_indexed_library_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoIndexedLibrary * self = KOTO_INDEXED_LIBRARY(obj); + switch (prop_id) { case PROP_PATH: @@ -154,7 +195,10 @@ static void koto_indexed_library_set_property(GObject *obj, guint prop_id, const } } -void koto_indexed_library_set_path(KotoIndexedLibrary *self, gchar *path) { +void koto_indexed_library_set_path( + KotoIndexedLibrary * self, + gchar * path +) { if (path == NULL) { return; } @@ -172,25 +216,37 @@ void koto_indexed_library_set_path(KotoIndexedLibrary *self, gchar *path) { } } -int process_artists(void *data, int num_columns, char **fields, char **column_names) { - (void) num_columns; (void) column_names; // Don't need any of the params +int process_artists( + void * data, + int num_columns, + char ** fields, + char ** column_names +) { + (void) num_columns; + (void) column_names; // Don't need any of the params - KotoIndexedLibrary *library = (KotoIndexedLibrary*) data; - gchar *artist_uuid = g_strdup(koto_utils_unquote_string(fields[0])); // First column is UUID - gchar *artist_path = g_strdup(koto_utils_unquote_string(fields[1])); // Second column is path - gchar *artist_name = g_strdup(koto_utils_unquote_string(fields[3])); // Fourth column is artist name + KotoIndexedLibrary * library = (KotoIndexedLibrary*) data; + gchar * artist_uuid = g_strdup(koto_utils_unquote_string(fields[0])); // First column is UUID + gchar * artist_path = g_strdup(koto_utils_unquote_string(fields[1])); // Second column is path + gchar * artist_name = g_strdup(koto_utils_unquote_string(fields[3])); // Fourth column is artist name - KotoIndexedArtist *artist = koto_indexed_artist_new_with_uuid(artist_uuid); // Create our artist with the UUID + KotoIndexedArtist * artist = koto_indexed_artist_new_with_uuid(artist_uuid); // Create our artist with the UUID - g_object_set(artist, - "path", artist_path, // Set path - "name", artist_name, // Set name - NULL); + + g_object_set( + artist, + "path", + artist_path, // Set path + "name", + artist_name, // Set name + NULL); koto_cartographer_add_artist(koto_maps, artist); // Add the artist to our global cartographer koto_indexed_library_add_artist(library, artist); int albums_rc = sqlite3_exec(koto_db, g_strdup_printf("SELECT * FROM albums WHERE artist_id=\"%s\"", artist_uuid), process_albums, artist, NULL); // Process our albums + + if (albums_rc != SQLITE_OK) { // Failed to get our albums g_critical("Failed to read our albums: %s", sqlite3_errmsg(koto_db)); return 1; @@ -203,29 +259,42 @@ int process_artists(void *data, int num_columns, char **fields, char **column_na return 0; } -int process_albums(void *data, int num_columns, char **fields, char **column_names) { - (void) num_columns; (void) column_names; // Don't need these +int process_albums( + void * data, + int num_columns, + char ** fields, + char ** column_names +) { + (void) num_columns; + (void) column_names; // Don't need these - KotoIndexedArtist *artist = (KotoIndexedArtist*) data; + KotoIndexedArtist * artist = (KotoIndexedArtist*) data; - gchar *album_uuid = g_strdup(koto_utils_unquote_string(fields[0])); - gchar *path = g_strdup(koto_utils_unquote_string(fields[1])); - gchar *artist_uuid = g_strdup(koto_utils_unquote_string(fields[2])); - gchar *album_name = g_strdup(koto_utils_unquote_string(fields[3])); - gchar *album_art = (fields[4] != NULL) ? g_strdup(koto_utils_unquote_string(fields[4])) : NULL; + gchar * album_uuid = g_strdup(koto_utils_unquote_string(fields[0])); + gchar * path = g_strdup(koto_utils_unquote_string(fields[1])); + gchar * artist_uuid = g_strdup(koto_utils_unquote_string(fields[2])); + gchar * album_name = g_strdup(koto_utils_unquote_string(fields[3])); + gchar * album_art = (fields[4] != NULL) ? g_strdup(koto_utils_unquote_string(fields[4])) : NULL; - KotoIndexedAlbum *album = koto_indexed_album_new_with_uuid(artist, album_uuid); // Create our album + KotoIndexedAlbum * album = koto_indexed_album_new_with_uuid(artist, album_uuid); // Create our album - g_object_set(album, - "path", path, // Set the path - "name", album_name, // Set name - "art-path", album_art, // Set art path if any - NULL); + + g_object_set( + album, + "path", + path, // Set the path + "name", + album_name, // Set name + "art-path", + album_art, // Set art path if any + NULL); koto_cartographer_add_album(koto_maps, album); // Add the album to our global cartographer koto_indexed_artist_add_album(artist, album_uuid); // Add the album int tracks_rc = sqlite3_exec(koto_db, g_strdup_printf("SELECT * FROM tracks WHERE album_id=\"%s\"", album_uuid), process_tracks, album, NULL); // Process our tracks + + if (tracks_rc != SQLITE_OK) { // Failed to get our tracks g_critical("Failed to read our tracks: %s", sqlite3_errmsg(koto_db)); return 1; @@ -243,20 +312,31 @@ int process_albums(void *data, int num_columns, char **fields, char **column_nam return 0; } -int process_playlists(void *data, int num_columns, char **fields, char **column_names) { - (void) data; (void) num_columns; (void) column_names; // Don't need any of the params +int process_playlists( + void * data, + int num_columns, + char ** fields, + char ** column_names +) { + (void) data; + (void) num_columns; + (void) column_names; // Don't need any of the params + + gchar * playlist_uuid = g_strdup(koto_utils_unquote_string(fields[0])); // First column is UUID + gchar * playlist_name = g_strdup(koto_utils_unquote_string(fields[1])); // Second column is playlist name + gchar * playlist_art_path = g_strdup(koto_utils_unquote_string(fields[2])); // Third column is any art path + + KotoPlaylist * playlist = koto_playlist_new_with_uuid(playlist_uuid); // Create a playlist using the existing UUID - gchar *playlist_uuid = g_strdup(koto_utils_unquote_string(fields[0])); // First column is UUID - gchar *playlist_name = g_strdup(koto_utils_unquote_string(fields[1])); // Second column is playlist name - gchar *playlist_art_path = g_strdup(koto_utils_unquote_string(fields[2])); // Third column is any art path - KotoPlaylist *playlist = koto_playlist_new_with_uuid(playlist_uuid); // Create a playlist using the existing UUID koto_playlist_set_name(playlist, playlist_name); // Add the playlist name koto_playlist_set_artwork(playlist, playlist_art_path); // Add the playlist art path koto_cartographer_add_playlist(koto_maps, playlist); // Add to cartographer int playlist_tracks_rc = sqlite3_exec(koto_db, g_strdup_printf("SELECT * FROM playlist_tracks WHERE playlist_id=\"%s\" ORDER BY position ASC", playlist_uuid), process_playlists_tracks, playlist, NULL); // Process our playlist tracks + + if (playlist_tracks_rc != SQLITE_OK) { // Failed to get our playlist tracks g_critical("Failed to read our playlist tracks: %s", sqlite3_errmsg(koto_db)); return 1; @@ -271,15 +351,23 @@ int process_playlists(void *data, int num_columns, char **fields, char **column_ return 0; } -int process_playlists_tracks(void *data, int num_columns, char **fields, char **column_names) { - (void) data; (void) num_columns; (void) column_names; // Don't need these +int process_playlists_tracks( + void * data, + int num_columns, + char ** fields, + char ** column_names +) { + (void) data; + (void) num_columns; + (void) column_names; // Don't need these - gchar *playlist_uuid = g_strdup(koto_utils_unquote_string(fields[1])); - gchar *track_uuid = g_strdup(koto_utils_unquote_string(fields[2])); + gchar * playlist_uuid = g_strdup(koto_utils_unquote_string(fields[1])); + gchar * track_uuid = g_strdup(koto_utils_unquote_string(fields[2])); gboolean current = g_strcmp0(koto_utils_unquote_string(fields[3]), "0"); - KotoPlaylist *playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, playlist_uuid); // Get the playlist - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, track_uuid); // Get the track + KotoPlaylist * playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, playlist_uuid); // Get the playlist + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, track_uuid); // Get the track + if (!KOTO_IS_PLAYLIST(playlist)) { goto freeforret; @@ -294,29 +382,29 @@ freeforret: return 0; } -int process_tracks(void *data, int num_columns, char **fields, char **column_names) { - (void) num_columns; (void) column_names; // Don't need these +int process_tracks( + void * data, + int num_columns, + char ** fields, + char ** column_names +) { + (void) num_columns; + (void) column_names; // Don't need these - KotoIndexedAlbum *album = (KotoIndexedAlbum*) data; - gchar *track_uuid = g_strdup(koto_utils_unquote_string(fields[0])); - gchar *path = g_strdup(koto_utils_unquote_string(fields[1])); - gchar *artist_uuid = g_strdup(koto_utils_unquote_string(fields[3])); - gchar *album_uuid = g_strdup(koto_utils_unquote_string(fields[4])); - gchar *file_name = g_strdup(koto_utils_unquote_string(fields[5])); - gchar *name = g_strdup(koto_utils_unquote_string(fields[6])); - guint *disc_num = (guint*) g_ascii_strtoull(fields[7], NULL, 10); - guint *position = (guint*) g_ascii_strtoull(fields[8], NULL, 10); + KotoIndexedAlbum * album = (KotoIndexedAlbum*) data; + gchar * track_uuid = g_strdup(koto_utils_unquote_string(fields[0])); + gchar * path = g_strdup(koto_utils_unquote_string(fields[1])); + gchar * artist_uuid = g_strdup(koto_utils_unquote_string(fields[3])); + gchar * album_uuid = g_strdup(koto_utils_unquote_string(fields[4])); + gchar * file_name = g_strdup(koto_utils_unquote_string(fields[5])); + gchar * name = g_strdup(koto_utils_unquote_string(fields[6])); + guint * disc_num = (guint*) g_ascii_strtoull(fields[7], NULL, 10); + guint * position = (guint*) g_ascii_strtoull(fields[8], NULL, 10); - KotoIndexedTrack *track = koto_indexed_track_new_with_uuid(track_uuid); // Create our file - g_object_set(track, - "artist-uuid", artist_uuid, - "album-uuid", album_uuid, - "path", path, - "file-name", file_name, - "parsed-name", name, - "cd", disc_num, - "position", position, - NULL); + KotoIndexedTrack * track = koto_indexed_track_new_with_uuid(track_uuid); // Create our file + + + g_object_set(track, "artist-uuid", artist_uuid, "album-uuid", album_uuid, "path", path, "file-name", file_name, "parsed-name", name, "cd", disc_num, "position", position, NULL); koto_cartographer_add_track(koto_maps, track); // Add the track to cartographer koto_indexed_album_add_track(album, track); // Add the track @@ -331,8 +419,10 @@ int process_tracks(void *data, int num_columns, char **fields, char **column_nam return 0; } -void read_from_db(KotoIndexedLibrary *self) { +void read_from_db(KotoIndexedLibrary * self) { int artists_rc = sqlite3_exec(koto_db, "SELECT * FROM artists", process_artists, self, NULL); // Process our artists + + if (artists_rc != SQLITE_OK) { // Failed to get our artists g_critical("Failed to read our artists: %s", sqlite3_errmsg(koto_db)); return; @@ -341,16 +431,19 @@ void read_from_db(KotoIndexedLibrary *self) { g_hash_table_foreach(self->music_artists, output_artists, NULL); int playlist_rc = sqlite3_exec(koto_db, "SELECT * FROM playlist_meta", process_playlists, self, NULL); // Process our playlists + + if (playlist_rc != SQLITE_OK) { // Failed to get our playlists g_critical("Failed to read our playlists: %s", sqlite3_errmsg(koto_db)); return; } } -void start_indexing(KotoIndexedLibrary *self) { +void start_indexing(KotoIndexedLibrary * self) { struct stat library_stat; int success = stat(self->path, &library_stat); + if (success != 0) { // Failed to read the library path return; } @@ -376,38 +469,48 @@ void start_indexing(KotoIndexedLibrary *self) { g_hash_table_foreach(self->music_artists, output_artists, NULL); } -KotoIndexedLibrary* koto_indexed_library_new(const gchar *path) { - return g_object_new(KOTO_TYPE_INDEXED_LIBRARY, - "path", path, +KotoIndexedLibrary * koto_indexed_library_new(const gchar * path) { + return g_object_new( + KOTO_TYPE_INDEXED_LIBRARY, + "path", + path, NULL ); } -void index_folder(KotoIndexedLibrary *self, gchar *path, guint depth) { +void index_folder( + KotoIndexedLibrary * self, + gchar * path, + guint depth +) { depth++; - DIR *dir = opendir(path); // Attempt to open our directory + DIR * dir = opendir(path); // Attempt to open our directory + if (dir == NULL) { return; } - struct dirent *entry; + struct dirent * entry; + while ((entry = readdir(dir))) { if (g_str_has_prefix(entry->d_name, ".")) { // A reference to parent dir, self, or a hidden item continue; } - gchar *full_path = g_strdup_printf("%s%s%s", path, G_DIR_SEPARATOR_S, entry->d_name); + gchar * full_path = g_strdup_printf("%s%s%s", path, G_DIR_SEPARATOR_S, entry->d_name); if (entry->d_type == DT_DIR) { // Directory if (depth == 1) { // If we are following FOLDER/ARTIST/ALBUM then this would be artist - KotoIndexedArtist *artist = koto_indexed_artist_new(full_path); // Attempt to get the artist - gchar *artist_name; + KotoIndexedArtist * artist = koto_indexed_artist_new(full_path); // Attempt to get the artist + gchar * artist_name; - g_object_get(artist, - "name", &artist_name, + g_object_get( + artist, + "name", + &artist_name, NULL ); @@ -416,17 +519,17 @@ void index_folder(KotoIndexedLibrary *self, gchar *path, guint depth) { index_folder(self, full_path, depth); // Index this directory g_free(artist_name); } else if (depth == 2) { // If we are following FOLDER/ARTIST/ALBUM then this would be album - gchar *artist_name = g_path_get_basename(path); // Get the last entry from our path which is probably the artist - KotoIndexedArtist *artist = koto_indexed_library_get_artist(self, artist_name); // Get the artist + gchar * artist_name = g_path_get_basename(path); // Get the last entry from our path which is probably the artist + KotoIndexedArtist * artist = koto_indexed_library_get_artist(self, artist_name); // Get the artist if (artist == NULL) { continue; } - KotoIndexedAlbum *album = koto_indexed_album_new(artist, full_path); + KotoIndexedAlbum * album = koto_indexed_album_new(artist, full_path); koto_cartographer_add_album(koto_maps, album); // Add our album to the cartographer - gchar *album_uuid = NULL; + gchar * album_uuid = NULL; g_object_get(album, "uuid", &album_uuid, NULL); koto_indexed_artist_add_album(artist, album_uuid); // Add the album g_free(artist_name); @@ -439,35 +542,46 @@ void index_folder(KotoIndexedLibrary *self, gchar *path, guint depth) { closedir(dir); // Close the directory } -void output_artists(gpointer artist_key, gpointer artist_ptr, gpointer data) { - (void) artist_ptr; (void) data; - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, (gchar*) artist_key); +void output_artists( + gpointer artist_key, + gpointer artist_ptr, + gpointer data +) { + (void) artist_ptr; + (void) data; + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, (gchar*) artist_key); + if (artist == NULL) { return; } - gchar *artist_name; + gchar * artist_name; + + g_object_get(artist, "name", &artist_name, NULL); g_debug("Artist: %s", artist_name); - GList *albums = koto_indexed_artist_get_albums(artist); // Get the albums for this artist + GList * albums = koto_indexed_artist_get_albums(artist); // Get the albums for this artist + if (albums != NULL) { g_debug("Length of Albums: %d", g_list_length(albums)); } - GList *a; + GList * a; + + for (a = albums; a != NULL; a = a->next) { - gchar *album_uuid = a->data; - KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); + gchar * album_uuid = a->data; + KotoIndexedAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); if (album == NULL) { continue; } - gchar *artwork = koto_indexed_album_get_album_art(album); - gchar *album_name; + gchar * artwork = koto_indexed_album_get_album_art(album); + gchar * album_name; g_object_get(album, "name", &album_name, NULL); g_debug("Album Art: %s", artwork); g_debug("Album Name: %s", album_name); @@ -476,24 +590,25 @@ void output_artists(gpointer artist_key, gpointer artist_ptr, gpointer data) { } } -void output_track(gpointer data, gpointer user_data) { +void output_track( + gpointer data, + gpointer user_data +) { (void) user_data; - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) data); + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) data); + if (track == NULL) { return; } - gchar *filepath; - gchar *parsed_name; - guint *pos; + gchar * filepath; + gchar * parsed_name; + guint * pos; - g_object_get(track, - "path", &filepath, - "parsed-name", &parsed_name, - "position", &pos, - NULL); + + g_object_get(track, "path", &filepath, "parsed-name", &parsed_name, "position", &pos, NULL); g_debug("File Path: %s", filepath); g_debug("Parsed Name: %s", parsed_name); g_debug("Position: %d", GPOINTER_TO_INT(pos)); diff --git a/src/indexer/structs.h b/src/indexer/structs.h index 85c601f..f288805 100644 --- a/src/indexer/structs.h +++ b/src/indexer/structs.h @@ -23,18 +23,18 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_INDEXED_LIBRARY koto_indexed_library_get_type() G_DECLARE_FINAL_TYPE(KotoIndexedLibrary, koto_indexed_library, KOTO, INDEXED_LIBRARY, GObject); #define KOTO_IS_INDEXED_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_INDEXED_LIBRARY)) #define KOTO_TYPE_INDEXED_ARTIST koto_indexed_artist_get_type() -G_DECLARE_FINAL_TYPE (KotoIndexedArtist, koto_indexed_artist, KOTO, INDEXED_ARTIST, GObject); +G_DECLARE_FINAL_TYPE(KotoIndexedArtist, koto_indexed_artist, KOTO, INDEXED_ARTIST, GObject); #define KOTO_IS_INDEXED_ARTIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_INDEXED_ARTIST)) #define KOTO_TYPE_INDEXED_ALBUM koto_indexed_album_get_type() -G_DECLARE_FINAL_TYPE (KotoIndexedAlbum, koto_indexed_album, KOTO, INDEXED_ALBUM, GObject); +G_DECLARE_FINAL_TYPE(KotoIndexedAlbum, koto_indexed_album, KOTO, INDEXED_ALBUM, GObject); #define KOTO_IS_INDEXED_ALBUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_INDEXED_ALBUM)) #define KOTO_TYPE_INDEXED_TRACK koto_indexed_track_get_type() @@ -43,84 +43,258 @@ G_DECLARE_FINAL_TYPE(KotoIndexedTrack, koto_indexed_track, KOTO, INDEXED_TRACK, /** * Library Functions -**/ + **/ -KotoIndexedLibrary* koto_indexed_library_new(const gchar *path); +KotoIndexedLibrary * koto_indexed_library_new(const gchar * path); -void koto_indexed_library_add_artist(KotoIndexedLibrary *self, KotoIndexedArtist *artist); -KotoIndexedArtist* koto_indexed_library_get_artist(KotoIndexedLibrary *self, gchar* artist_name); -GHashTable* koto_indexed_library_get_artists(KotoIndexedLibrary *self); -void koto_indexed_library_remove_artist(KotoIndexedLibrary *self, KotoIndexedArtist *artist); -void koto_indexed_library_set_path(KotoIndexedLibrary *self, gchar *path); -int process_artists(void *data, int num_columns, char **fields, char **column_names); -int process_albums(void *data, int num_columns, char **fields, char **column_names); -int process_playlists(void *data, int num_columns, char **fields, char **column_names); -int process_playlists_tracks(void *data, int num_columns, char **fields, char **column_names); -int process_tracks(void *data, int num_columns, char **fields, char **column_names); -void read_from_db(KotoIndexedLibrary *self); -void start_indexing(KotoIndexedLibrary *self); -void index_folder(KotoIndexedLibrary *self, gchar *path, guint depth); -void output_track(gpointer data, gpointer user_data); +void koto_indexed_library_add_artist( + KotoIndexedLibrary * self, + KotoIndexedArtist * artist +); + +KotoIndexedArtist * koto_indexed_library_get_artist( + KotoIndexedLibrary * self, + gchar* artist_name +); + +GHashTable * koto_indexed_library_get_artists(KotoIndexedLibrary * self); + +void koto_indexed_library_remove_artist( + KotoIndexedLibrary * self, + KotoIndexedArtist * artist +); + +void koto_indexed_library_set_path( + KotoIndexedLibrary * self, + gchar * path +); + +int process_artists( + void * data, + int num_columns, + char ** fields, + char ** column_names +); + +int process_albums( + void * data, + int num_columns, + char ** fields, + char ** column_names +); + +int process_playlists( + void * data, + int num_columns, + char ** fields, + char ** column_names +); + +int process_playlists_tracks( + void * data, + int num_columns, + char ** fields, + char ** column_names +); + +int process_tracks( + void * data, + int num_columns, + char ** fields, + char ** column_names +); + +void read_from_db(KotoIndexedLibrary * self); + +void start_indexing(KotoIndexedLibrary * self); + +void index_folder( + KotoIndexedLibrary * self, + gchar * path, + guint depth +); + +void output_track( + gpointer data, + gpointer user_data +); /** * Artist Functions -**/ + **/ -KotoIndexedArtist* koto_indexed_artist_new(gchar *path); -KotoIndexedArtist* koto_indexed_artist_new_with_uuid(const gchar *uuid); +KotoIndexedArtist * koto_indexed_artist_new(gchar * path); -void koto_indexed_artist_add_album(KotoIndexedArtist *self, gchar *album_uuid); -void koto_indexed_artist_commit(KotoIndexedArtist *self); -guint koto_indexed_artist_find_album_with_name(gconstpointer *album_data, gconstpointer *album_name_data); -GList* koto_indexed_artist_get_albums(KotoIndexedArtist *self); -gchar* koto_indexed_artist_get_name(KotoIndexedArtist *self); -void koto_indexed_artist_remove_album(KotoIndexedArtist *self, KotoIndexedAlbum *album); -void koto_indexed_artist_remove_album_by_name(KotoIndexedArtist *self, gchar *album_name); -void koto_indexed_artist_set_artist_name(KotoIndexedArtist *self, gchar *artist_name); -void koto_indexed_artist_update_path(KotoIndexedArtist *self, gchar *new_path); -void output_artists(gpointer artist_key, gpointer artist_ptr, gpointer data); +KotoIndexedArtist * koto_indexed_artist_new_with_uuid(const gchar * uuid); + +void koto_indexed_artist_add_album( + KotoIndexedArtist * self, + gchar * album_uuid +); + +void koto_indexed_artist_commit(KotoIndexedArtist * self); + +guint koto_indexed_artist_find_album_with_name( + gconstpointer * album_data, + gconstpointer * album_name_data +); + +GList * koto_indexed_artist_get_albums(KotoIndexedArtist * self); + +gchar * koto_indexed_artist_get_name(KotoIndexedArtist * self); + +void koto_indexed_artist_remove_album( + KotoIndexedArtist * self, + KotoIndexedAlbum * album +); + +void koto_indexed_artist_remove_album_by_name( + KotoIndexedArtist * self, + gchar * album_name +); + +void koto_indexed_artist_set_artist_name( + KotoIndexedArtist * self, + gchar * artist_name +); + +void koto_indexed_artist_update_path( + KotoIndexedArtist * self, + gchar * new_path +); + +void output_artists( + gpointer artist_key, + gpointer artist_ptr, + gpointer data +); /** * Album Functions -**/ + **/ -KotoIndexedAlbum* koto_indexed_album_new(KotoIndexedArtist *artist, const gchar *path); -KotoIndexedAlbum* koto_indexed_album_new_with_uuid(KotoIndexedArtist *artist, const gchar *uuid); +KotoIndexedAlbum * koto_indexed_album_new( + KotoIndexedArtist * artist, + const gchar * path +); -void koto_indexed_album_add_track(KotoIndexedAlbum *self, KotoIndexedTrack *track); -void koto_indexed_album_commit(KotoIndexedAlbum *self); -void koto_indexed_album_find_album_art(KotoIndexedAlbum *self); -void koto_indexed_album_find_tracks(KotoIndexedAlbum *self, magic_t magic_cookie, const gchar *path); -gchar* koto_indexed_album_get_album_art(KotoIndexedAlbum *self); -gchar* koto_indexed_album_get_album_name(KotoIndexedAlbum *self); -gchar* koto_indexed_album_get_album_uuid(KotoIndexedAlbum *self); -GList* koto_indexed_album_get_tracks(KotoIndexedAlbum *self); -void koto_indexed_album_remove_file(KotoIndexedAlbum *self, KotoIndexedTrack *track); -void koto_indexed_album_set_album_art(KotoIndexedAlbum *self, const gchar *album_art); -void koto_indexed_album_set_album_name(KotoIndexedAlbum *self, const gchar *album_name); -void koto_indexed_album_set_artist_uuid(KotoIndexedAlbum *self, const gchar *artist_uuid); -void koto_indexed_album_set_as_current_playlist(KotoIndexedAlbum *self); -void koto_indexed_album_update_path(KotoIndexedAlbum *self, gchar *path); -gint koto_indexed_album_sort_tracks(gconstpointer track1_uuid, gconstpointer track2_uuid, gpointer user_data); +KotoIndexedAlbum * koto_indexed_album_new_with_uuid( + KotoIndexedArtist * artist, + const gchar * uuid +); + +void koto_indexed_album_add_track( + KotoIndexedAlbum * self, + KotoIndexedTrack * track +); + +void koto_indexed_album_commit(KotoIndexedAlbum * self); + +void koto_indexed_album_find_album_art(KotoIndexedAlbum * self); + +void koto_indexed_album_find_tracks( + KotoIndexedAlbum * self, + magic_t magic_cookie, + const gchar * path +); + +gchar * koto_indexed_album_get_album_art(KotoIndexedAlbum * self); + +gchar * koto_indexed_album_get_album_name(KotoIndexedAlbum * self); + +gchar * koto_indexed_album_get_album_uuid(KotoIndexedAlbum * self); + +GList * koto_indexed_album_get_tracks(KotoIndexedAlbum * self); + +void koto_indexed_album_remove_file( + KotoIndexedAlbum * self, + KotoIndexedTrack * track +); + +void koto_indexed_album_set_album_art( + KotoIndexedAlbum * self, + const gchar * album_art +); + +void koto_indexed_album_set_album_name( + KotoIndexedAlbum * self, + const gchar * album_name +); + +void koto_indexed_album_set_artist_uuid( + KotoIndexedAlbum * self, + const gchar * artist_uuid +); + +void koto_indexed_album_set_as_current_playlist(KotoIndexedAlbum * self); + +void koto_indexed_album_update_path( + KotoIndexedAlbum * self, + gchar * path +); + +gint koto_indexed_album_sort_tracks( + gconstpointer track1_uuid, + gconstpointer track2_uuid, + gpointer user_data +); /** * File / Track Functions -**/ + **/ -KotoIndexedTrack* koto_indexed_track_new(KotoIndexedAlbum *album, const gchar *path, guint *cd); -KotoIndexedTrack* koto_indexed_track_new_with_uuid(const gchar *uuid); +KotoIndexedTrack * koto_indexed_track_new( + KotoIndexedAlbum * album, + const gchar * path, + guint * cd +); -void koto_indexed_track_commit(KotoIndexedTrack *self); -GVariant* koto_indexed_track_get_metadata_vardict(KotoIndexedTrack *self); -gchar* koto_indexed_track_get_uuid(KotoIndexedTrack *self); -void koto_indexed_track_parse_name(KotoIndexedTrack *self); -void koto_indexed_track_remove_from_playlist(KotoIndexedTrack *self, gchar *playlist_uuid); -void koto_indexed_track_save_to_playlist(KotoIndexedTrack *self, gchar *playlist_uuid, gint current); -void koto_indexed_track_set_file_name(KotoIndexedTrack *self, gchar *new_file_name); -void koto_indexed_track_set_cd(KotoIndexedTrack *self, guint cd); -void koto_indexed_track_set_parsed_name(KotoIndexedTrack *self, gchar *new_parsed_name); -void koto_indexed_track_set_position(KotoIndexedTrack *self, guint pos); -void koto_indexed_track_update_metadata(KotoIndexedTrack *self); -void koto_indexed_track_update_path(KotoIndexedTrack *self, const gchar *new_path); +KotoIndexedTrack * koto_indexed_track_new_with_uuid(const gchar * uuid); + +void koto_indexed_track_commit(KotoIndexedTrack * self); + +GVariant * koto_indexed_track_get_metadata_vardict(KotoIndexedTrack * self); + +gchar * koto_indexed_track_get_uuid(KotoIndexedTrack * self); + +void koto_indexed_track_parse_name(KotoIndexedTrack * self); + +void koto_indexed_track_remove_from_playlist( + KotoIndexedTrack * self, + gchar * playlist_uuid +); + +void koto_indexed_track_save_to_playlist( + KotoIndexedTrack * self, + gchar * playlist_uuid, + gint current +); + +void koto_indexed_track_set_file_name( + KotoIndexedTrack * self, + gchar * new_file_name +); + +void koto_indexed_track_set_cd( + KotoIndexedTrack * self, + guint cd +); + +void koto_indexed_track_set_parsed_name( + KotoIndexedTrack * self, + gchar * new_parsed_name +); + +void koto_indexed_track_set_position( + KotoIndexedTrack * self, + guint pos +); + +void koto_indexed_track_update_metadata(KotoIndexedTrack * self); + +void koto_indexed_track_update_path( + KotoIndexedTrack * self, + const gchar * new_path +); G_END_DECLS diff --git a/src/indexer/track.c b/src/indexer/track.c index 68b08f7..9c56c8e 100644 --- a/src/indexer/track.c +++ b/src/indexer/track.c @@ -22,21 +22,21 @@ #include "structs.h" #include "koto-utils.h" -extern KotoCartographer *koto_maps; -extern sqlite3 *koto_db; +extern KotoCartographer * koto_maps; +extern sqlite3 * koto_db; struct _KotoIndexedTrack { GObject parent_instance; - gchar *artist_uuid; - gchar *album_uuid; - gchar *uuid; - gchar *path; + gchar * artist_uuid; + gchar * album_uuid; + gchar * uuid; + gchar * path; - gchar *file_name; - gchar *parsed_name; - guint *cd; - guint *position; - guint *playback_position; + gchar * file_name; + gchar * parsed_name; + guint * cd; + guint * position; + guint * playback_position; gboolean acquired_metadata_from_id3; gboolean do_initial_index; @@ -59,13 +59,28 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL }; +static GParamSpec * props[N_PROPERTIES] = { + NULL +}; + +static void koto_indexed_track_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_indexed_track_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_indexed_track_class_init(KotoIndexedTrackClass * c) { + GObjectClass * gobject_class; -static void koto_indexed_track_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_indexed_track_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_indexed_track_set_property; gobject_class->get_property = koto_indexed_track_get_property; @@ -75,7 +90,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "UUID to Artist associated with the File", "UUID to Artist associated with the File", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ALBUM_UUID] = g_param_spec_string( @@ -83,7 +98,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "UUID to Album associated with the File", "UUID to Album associated with the File", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_UUID] = g_param_spec_string( @@ -91,7 +106,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "UUID to File in database", "UUID to File in database", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_DO_INITIAL_INDEX] = g_param_spec_boolean( @@ -99,7 +114,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "Do an initial indexing operating instead of pulling from the database", "Do an initial indexing operating instead of pulling from the database", FALSE, - G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_PATH] = g_param_spec_string( @@ -107,7 +122,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "Path", "Path to File", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_FILE_NAME] = g_param_spec_string( @@ -115,7 +130,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "Name of File", "Name of File", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_PARSED_NAME] = g_param_spec_string( @@ -123,7 +138,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { "Parsed Name of File", "Parsed Name of File", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_CD] = g_param_spec_uint( @@ -133,7 +148,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { 0, G_MAXUINT16, 1, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_POSITION] = g_param_spec_uint( @@ -143,7 +158,7 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { 0, G_MAXUINT16, 0, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_PLAYBACK_POSITION] = g_param_spec_uint( @@ -153,18 +168,24 @@ static void koto_indexed_track_class_init(KotoIndexedTrackClass *c) { 0, G_MAXUINT16, 0, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_indexed_track_init(KotoIndexedTrack *self) { +static void koto_indexed_track_init(KotoIndexedTrack * self) { self->acquired_metadata_from_id3 = FALSE; } -static void koto_indexed_track_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoIndexedTrack *self = KOTO_INDEXED_TRACK(obj); +static void koto_indexed_track_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoIndexedTrack * self = KOTO_INDEXED_TRACK(obj); + switch (prop_id) { case PROP_ARTIST_UUID: @@ -200,8 +221,14 @@ static void koto_indexed_track_get_property(GObject *obj, guint prop_id, GValue } } -static void koto_indexed_track_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoIndexedTrack *self = KOTO_INDEXED_TRACK(obj); +static void koto_indexed_track_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoIndexedTrack * self = KOTO_INDEXED_TRACK(obj); + switch (prop_id) { case PROP_ARTIST_UUID: @@ -244,7 +271,7 @@ static void koto_indexed_track_set_property(GObject *obj, guint prop_id, const G } -void koto_indexed_track_commit(KotoIndexedTrack *self) { +void koto_indexed_track_commit(KotoIndexedTrack * self) { if ((self->artist_uuid == NULL) || (strcmp(self->artist_uuid, "") == 0)) { // No valid required artist UUID return; } @@ -253,7 +280,7 @@ void koto_indexed_track_commit(KotoIndexedTrack *self) { g_object_set(self, "album-uuid", "", NULL); // Set to an empty string } - gchar *commit_op = g_strdup_printf( + gchar * commit_op = g_strdup_printf( "INSERT INTO tracks(id, path, type, artist_id, album_id, file_name, name, disc, position)" "VALUES('%s', quote(\"%s\"), 0, '%s', '%s', quote(\"%s\"), quote(\"%s\"), %d, %d)" "ON CONFLICT(id) DO UPDATE SET path=excluded.path, type=excluded.type, album_id=excluded.album_id, file_name=excluded.file_name, name=excluded.file_name, disc=excluded.disc, position=excluded.position;", @@ -267,9 +294,10 @@ void koto_indexed_track_commit(KotoIndexedTrack *self) { GPOINTER_TO_INT((int*) self->position) ); - gchar *commit_op_errmsg = NULL; + gchar * commit_op_errmsg = NULL; int rc = sqlite3_exec(koto_db, commit_op, 0, 0, &commit_op_errmsg); + if (rc != SQLITE_OK) { g_warning("Failed to write our file to the database: %s", commit_op_errmsg); } @@ -278,28 +306,24 @@ void koto_indexed_track_commit(KotoIndexedTrack *self) { g_free(commit_op_errmsg); } -GVariant* koto_indexed_track_get_metadata_vardict(KotoIndexedTrack *self) { +GVariant * koto_indexed_track_get_metadata_vardict(KotoIndexedTrack * self) { if (!KOTO_IS_INDEXED_TRACK(self)) { return NULL; } - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); + GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); - gchar *album_art_path = NULL; - gchar *album_name = NULL; - gchar *artist_name = NULL; + gchar * album_art_path = NULL; + gchar * album_name = NULL; + gchar * artist_name = NULL; - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, self->artist_uuid); - KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, self->album_uuid); + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, self->artist_uuid); + KotoIndexedAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, self->album_uuid); - g_object_get(album, - "art-path", &album_art_path, - "name", &album_name, - NULL); - g_object_get(artist, - "name", &artist_name, - NULL); + g_object_get(album, "art-path", &album_art_path, "name", &album_name, NULL); + + g_object_get(artist, "name", &artist_name, NULL); g_variant_builder_add(builder, "{sv}", "mpris:trackid", g_variant_new_string(self->uuid)); @@ -311,8 +335,8 @@ GVariant* koto_indexed_track_get_metadata_vardict(KotoIndexedTrack *self) { g_variant_builder_add(builder, "{sv}", "xesam:album", g_variant_new_string(album_name)); if (koto_utils_is_string_valid(artist_name)) { // Valid artist name - GVariant *artist_name_variant; - GVariantBuilder *artist_list_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); + GVariant * artist_name_variant; + GVariantBuilder * artist_list_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); g_variant_builder_add(artist_list_builder, "s", artist_name); artist_name_variant = g_variant_new("as", artist_list_builder); g_variant_builder_unref(artist_list_builder); @@ -326,12 +350,13 @@ GVariant* koto_indexed_track_get_metadata_vardict(KotoIndexedTrack *self) { g_variant_builder_add(builder, "{sv}", "xesam:url", g_variant_new_string(self->path)); g_variant_builder_add(builder, "{sv}", "xesam:trackNumber", g_variant_new_uint64(GPOINTER_TO_UINT(self->position))); - GVariant *metadata_ret = g_variant_builder_end(builder); + GVariant * metadata_ret = g_variant_builder_end(builder); + return metadata_ret; } -gchar* koto_indexed_track_get_uuid(KotoIndexedTrack *self) { +gchar * koto_indexed_track_get_uuid(KotoIndexedTrack * self) { if (!KOTO_IS_INDEXED_TRACK(self)) { return NULL; } @@ -339,18 +364,20 @@ gchar* koto_indexed_track_get_uuid(KotoIndexedTrack *self) { return self->uuid; // Do not return a duplicate since otherwise comparison refs fail due to pointer positions being different } -void koto_indexed_track_parse_name(KotoIndexedTrack *self) { - gchar *copied_file_name = g_strdelimit(g_strdup(self->file_name), "_", ' '); // Replace _ with whitespace for starters +void koto_indexed_track_parse_name(KotoIndexedTrack * self) { + gchar * copied_file_name = g_strdelimit(g_strdup(self->file_name), "_", ' '); // Replace _ with whitespace for starters + + KotoIndexedArtist * artist = NULL; + - KotoIndexedArtist *artist = NULL; artist = koto_cartographer_get_artist_by_uuid(koto_maps, self->artist_uuid); if (artist != NULL) { // If we have artist - gchar *artist_name = NULL; + gchar * artist_name = NULL; g_object_get(artist, "name", &artist_name, NULL); if (artist_name != NULL && (strcmp(artist_name, "") != 0)) { - gchar **split = g_strsplit(copied_file_name, artist_name, -1); // Split whenever we encounter the artist + gchar ** split = g_strsplit(copied_file_name, artist_name, -1); // Split whenever we encounter the artist copied_file_name = g_strjoinv("", split); // Remove the artist g_strfreev(split); @@ -360,13 +387,16 @@ void koto_indexed_track_parse_name(KotoIndexedTrack *self) { } } - gchar *file_without_ext = koto_utils_get_filename_without_extension(copied_file_name); + gchar * file_without_ext = koto_utils_get_filename_without_extension(copied_file_name); + + g_free(copied_file_name); - gchar **split = g_regex_split_simple("^([\\d]+)", file_without_ext, G_REGEX_JAVASCRIPT_COMPAT, 0); + gchar ** split = g_regex_split_simple("^([\\d]+)", file_without_ext, G_REGEX_JAVASCRIPT_COMPAT, 0); + if (g_strv_length(split) > 1) { // Has positional info at the beginning of the file - gchar *num = split[1]; + gchar * num = split[1]; g_free(file_without_ext); // Free the prior name file_without_ext = g_strdup(split[2]); // Set to our second item which is the rest of the song name without the prefixed numbers @@ -396,19 +426,24 @@ void koto_indexed_track_parse_name(KotoIndexedTrack *self) { g_free(file_without_ext); } -void koto_indexed_track_remove_from_playlist(KotoIndexedTrack *self, gchar *playlist_uuid) { +void koto_indexed_track_remove_from_playlist( + KotoIndexedTrack * self, + gchar * playlist_uuid +) { if (!KOTO_IS_INDEXED_TRACK(self)) { return; } - gchar *commit_op = g_strdup_printf( + gchar * commit_op = g_strdup_printf( "DELETE FROM playlist_tracks WHERE track_id='%s' AND playlist_id='%s'", self->uuid, playlist_uuid ); - gchar *commit_op_errmsg = NULL; + gchar * commit_op_errmsg = NULL; int rc = sqlite3_exec(koto_db, commit_op, 0, 0, &commit_op_errmsg); + + if (rc != SQLITE_OK) { g_warning("Failed to remove track from playlist: %s", commit_op_errmsg); } @@ -417,12 +452,16 @@ void koto_indexed_track_remove_from_playlist(KotoIndexedTrack *self, gchar *play g_free(commit_op_errmsg); } -void koto_indexed_track_save_to_playlist(KotoIndexedTrack *self, gchar *playlist_uuid, gint current) { +void koto_indexed_track_save_to_playlist( + KotoIndexedTrack * self, + gchar * playlist_uuid, + gint current +) { if (!KOTO_IS_INDEXED_TRACK(self)) { return; } - gchar *commit_op = g_strdup_printf( + gchar * commit_op = g_strdup_printf( "INSERT INTO playlist_tracks(playlist_id, track_id, current)" "VALUES('%s', '%s', quote(\"%d\"))", playlist_uuid, @@ -430,9 +469,10 @@ void koto_indexed_track_save_to_playlist(KotoIndexedTrack *self, gchar *playlist current ); - gchar *commit_op_errmsg = NULL; + gchar * commit_op_errmsg = NULL; int rc = sqlite3_exec(koto_db, commit_op, 0, 0, &commit_op_errmsg); + if (rc != SQLITE_OK) { g_warning("Failed to save track to playlist: %s", commit_op_errmsg); } @@ -441,7 +481,10 @@ void koto_indexed_track_save_to_playlist(KotoIndexedTrack *self, gchar *playlist g_free(commit_op_errmsg); } -void koto_indexed_track_set_file_name(KotoIndexedTrack *self, gchar *new_file_name) { +void koto_indexed_track_set_file_name( + KotoIndexedTrack * self, + gchar * new_file_name +) { if (new_file_name == NULL) { return; } @@ -462,7 +505,10 @@ void koto_indexed_track_set_file_name(KotoIndexedTrack *self, gchar *new_file_na } } -void koto_indexed_track_set_cd(KotoIndexedTrack *self, guint cd) { +void koto_indexed_track_set_cd( + KotoIndexedTrack * self, + guint cd +) { if (cd == 0) { // No change really return; } @@ -471,7 +517,10 @@ void koto_indexed_track_set_cd(KotoIndexedTrack *self, guint cd) { g_object_notify_by_pspec(G_OBJECT(self), props[PROP_CD]); } -void koto_indexed_track_set_parsed_name(KotoIndexedTrack *self, gchar *new_parsed_name) { +void koto_indexed_track_set_parsed_name( + KotoIndexedTrack * self, + gchar * new_parsed_name +) { if (new_parsed_name == NULL) { return; } @@ -488,7 +537,10 @@ void koto_indexed_track_set_parsed_name(KotoIndexedTrack *self, gchar *new_parse g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PARSED_NAME]); } -void koto_indexed_track_set_position(KotoIndexedTrack *self, guint pos) { +void koto_indexed_track_set_position( + KotoIndexedTrack * self, + guint pos +) { if (pos == 0) { // No position change really return; } @@ -497,24 +549,28 @@ void koto_indexed_track_set_position(KotoIndexedTrack *self, guint pos) { g_object_notify_by_pspec(G_OBJECT(self), props[PROP_POSITION]); } -void koto_indexed_track_update_metadata(KotoIndexedTrack *self) { - TagLib_File *t_file = taglib_file_new(self->path); // Get a taglib file for this file +void koto_indexed_track_update_metadata(KotoIndexedTrack * self) { + TagLib_File * t_file = taglib_file_new(self->path); // Get a taglib file for this file - if ((t_file != NULL) && taglib_file_is_valid(t_file)) { // If we got the taglib file and it is valid - self->acquired_metadata_from_id3 = TRUE; - TagLib_Tag *tag = taglib_file_tag(t_file); // Get our tag - koto_indexed_track_set_parsed_name(self, taglib_tag_title(tag)); // Set the title of the file - koto_indexed_track_set_position(self, (uint) taglib_tag_track(tag)); // Get the track, convert to uint and cast as a pointer - koto_indexed_track_set_file_name(self, g_path_get_basename(self->path)); // Update our file name - } else { - koto_indexed_track_set_file_name(self, g_path_get_basename(self->path)); // Update our file name - } - taglib_tag_free_strings(); // Free strings - taglib_file_free(t_file); // Free the file + if ((t_file != NULL) && taglib_file_is_valid(t_file)) { // If we got the taglib file and it is valid + self->acquired_metadata_from_id3 = TRUE; + TagLib_Tag * tag = taglib_file_tag(t_file); // Get our tag + koto_indexed_track_set_parsed_name(self, taglib_tag_title(tag)); // Set the title of the file + koto_indexed_track_set_position(self, (uint) taglib_tag_track(tag)); // Get the track, convert to uint and cast as a pointer + koto_indexed_track_set_file_name(self, g_path_get_basename(self->path)); // Update our file name + } else { + koto_indexed_track_set_file_name(self, g_path_get_basename(self->path)); // Update our file name + } + + taglib_tag_free_strings(); // Free strings + taglib_file_free(t_file); // Free the file } -void koto_indexed_track_update_path(KotoIndexedTrack *self, const gchar *new_path) { +void koto_indexed_track_update_path( + KotoIndexedTrack * self, + const gchar * new_path +) { if (new_path == NULL) { return; } @@ -532,29 +588,44 @@ void koto_indexed_track_update_path(KotoIndexedTrack *self, const gchar *new_pat g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PATH]); } -KotoIndexedTrack* koto_indexed_track_new(KotoIndexedAlbum *album, const gchar *path, guint *cd) { - gchar *artist_uuid; - gchar *album_uuid; +KotoIndexedTrack * koto_indexed_track_new( + KotoIndexedAlbum * album, + const gchar * path, + guint * cd +) { + gchar * artist_uuid; + gchar * album_uuid; + g_object_get(album, "artist-uuid", &artist_uuid, "uuid", &album_uuid, NULL); // Get the artist and album uuids from our Album - KotoIndexedTrack *track = g_object_new(KOTO_TYPE_INDEXED_TRACK, - "artist-uuid", artist_uuid, - "album-uuid", album_uuid, - "do-initial-index", TRUE, - "uuid", g_uuid_string_random(), - "path", path, - "cd", cd, + KotoIndexedTrack * track = g_object_new( + KOTO_TYPE_INDEXED_TRACK, + "artist-uuid", + artist_uuid, + "album-uuid", + album_uuid, + "do-initial-index", + TRUE, + "uuid", + g_uuid_string_random(), + "path", + path, + "cd", + cd, NULL ); + koto_indexed_track_commit(track); // Immediately commit to the database return track; } -KotoIndexedTrack* koto_indexed_track_new_with_uuid(const gchar *uuid) { - return g_object_new(KOTO_TYPE_INDEXED_TRACK, - "uuid", g_strdup(uuid), +KotoIndexedTrack * koto_indexed_track_new_with_uuid(const gchar * uuid) { + return g_object_new( + KOTO_TYPE_INDEXED_TRACK, + "uuid", + g_strdup(uuid), NULL ); } diff --git a/src/koto-button.c b/src/koto-button.c index 0d1209f..bae717f 100644 --- a/src/koto-button.c +++ b/src/koto-button.c @@ -26,7 +26,7 @@ struct _PixbufSize { typedef struct _PixbufSize PixbufSize; -static PixbufSize *pixbuf_sizes = NULL; +static PixbufSize * pixbuf_sizes = NULL; static guint pixbuf_sizes_allocated = 0; static void init_pixbuf_sizes() { @@ -62,24 +62,26 @@ enum { N_BTN_PROPERTIES }; -static GParamSpec *btn_props[N_BTN_PROPERTIES] = { NULL, }; +static GParamSpec * btn_props[N_BTN_PROPERTIES] = { + NULL, +}; struct _KotoButton { GtkBox parent_instance; guint pix_size; - GtkWidget *button_pic; - GtkWidget *badge_label; - GtkWidget *button_label; + GtkWidget * button_pic; + GtkWidget * badge_label; + GtkWidget * button_label; - GtkGesture *left_click_gesture; - GtkGesture *right_click_gesture; + GtkGesture * left_click_gesture; + GtkGesture * right_click_gesture; - gchar *image_file_path; - gchar *badge_text; - gchar *icon_name; - gchar *alt_icon_name; - gchar *text; + gchar * image_file_path; + gchar * badge_text; + gchar * icon_name; + gchar * alt_icon_name; + gchar * text; KotoButtonImagePosition image_position; gboolean use_from_file; @@ -92,12 +94,26 @@ struct _KotoButtonClass { G_DEFINE_TYPE(KotoButton, koto_button, GTK_TYPE_BOX); -static void koto_button_constructed(GObject *obj); -static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static void koto_button_constructed(GObject * obj); + +static void koto_button_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_button_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_button_class_init(KotoButtonClass * c) { + GObjectClass * gobject_class; + -static void koto_button_class_init(KotoButtonClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->constructed = koto_button_constructed; gobject_class->set_property = koto_button_set_property; @@ -110,7 +126,7 @@ static void koto_button_class_init(KotoButtonClass *c) { koto_get_pixbuf_size(KOTO_BUTTON_PIXBUF_SIZE_TINY), koto_get_pixbuf_size(KOTO_BUTTON_PIXBUF_SIZE_GODLIKE), koto_get_pixbuf_size(KOTO_BUTTON_PIXBUF_SIZE_SMALL), - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); btn_props[PROP_TEXT] = g_param_spec_string( @@ -118,7 +134,7 @@ static void koto_button_class_init(KotoButtonClass *c) { "Button Text", "Text of Button", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); btn_props[PROP_BADGE_TEXT] = g_param_spec_string( @@ -126,7 +142,7 @@ static void koto_button_class_init(KotoButtonClass *c) { "Badge Text", "Text of Badge", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); btn_props[PROP_USE_FROM_FILE] = g_param_spec_boolean( @@ -134,7 +150,7 @@ static void koto_button_class_init(KotoButtonClass *c) { "Use from a file / file name", "Use from a file / file name", FALSE, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); btn_props[PROP_IMAGE_FILE_PATH] = g_param_spec_string( @@ -142,7 +158,7 @@ static void koto_button_class_init(KotoButtonClass *c) { "File path to image", "File path to image", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); btn_props[PROP_ICON_NAME] = g_param_spec_string( @@ -150,7 +166,7 @@ static void koto_button_class_init(KotoButtonClass *c) { "Icon Name", "Name of Icon", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); btn_props[PROP_ALT_ICON_NAME] = g_param_spec_string( @@ -158,13 +174,13 @@ static void koto_button_class_init(KotoButtonClass *c) { "Name of an Alternate Icon", "Name of an Alternate Icon", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_BTN_PROPERTIES, btn_props); } -static void koto_button_init(KotoButton *self) { +static void koto_button_init(KotoButton * self) { self->currently_showing_alt = FALSE; self->image_position = KOTO_BUTTON_IMAGE_POS_LEFT; @@ -178,16 +194,24 @@ static void koto_button_init(KotoButton *self) { gtk_widget_add_controller(GTK_WIDGET(self), GTK_EVENT_CONTROLLER(self->right_click_gesture)); // Add our right click gesture } -static void koto_button_constructed(GObject *obj) { - KotoButton *self = KOTO_BUTTON(obj); - GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self)); +static void koto_button_constructed(GObject * obj) { + KotoButton * self = KOTO_BUTTON(obj); + GtkStyleContext * style = gtk_widget_get_style_context(GTK_WIDGET(self)); + + gtk_style_context_add_class(style, "koto-button"); - G_OBJECT_CLASS (koto_button_parent_class)->constructed (obj); + G_OBJECT_CLASS(koto_button_parent_class)->constructed(obj); } -static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoButton *self = KOTO_BUTTON(obj); +static void koto_button_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoButton * self = KOTO_BUTTON(obj); + switch (prop_id) { case PROP_IMAGE_FILE_PATH: @@ -217,8 +241,14 @@ static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, G } } -static void koto_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoButton *self = KOTO_BUTTON(obj); +static void koto_button_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoButton * self = KOTO_BUTTON(obj); + switch (prop_id) { case PROP_PIX_SIZE: @@ -257,7 +287,12 @@ static void koto_button_set_property(GObject *obj, guint prop_id, const GValue * } } -void koto_button_add_click_handler(KotoButton *self, KotoButtonClickType button, GCallback handler, gpointer user_data) { +void koto_button_add_click_handler( + KotoButton * self, + KotoButtonClickType button, + GCallback handler, + gpointer user_data +) { if (!KOTO_IS_BUTTON(self)) { return; } @@ -269,7 +304,7 @@ void koto_button_add_click_handler(KotoButton *self, KotoButtonClickType button, g_signal_connect((button == KOTO_BUTTON_CLICK_TYPE_PRIMARY) ? self->left_click_gesture : self->right_click_gesture, "pressed", handler, user_data); } -void koto_button_flip(KotoButton *self) { +void koto_button_flip(KotoButton * self) { if (!KOTO_IS_BUTTON(self)) { return; } @@ -277,13 +312,16 @@ void koto_button_flip(KotoButton *self) { koto_button_show_image(self, !self->currently_showing_alt); } -void koto_button_hide_image(KotoButton *self) { +void koto_button_hide_image(KotoButton * self) { if (GTK_IS_WIDGET(self->button_pic)) { // Is a widget gtk_widget_hide(self->button_pic); } } -void koto_button_set_badge_text(KotoButton *self, gchar *text) { +void koto_button_set_badge_text( + KotoButton * self, + gchar * text +) { if ((text == NULL) || (strcmp(text, "") == 0)) { // If the text is empty self->badge_text = g_strdup(""); } else { @@ -307,7 +345,10 @@ void koto_button_set_badge_text(KotoButton *self, gchar *text) { g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_BADGE_TEXT]); } -void koto_button_set_file_path(KotoButton *self, gchar *file_path) { +void koto_button_set_file_path( + KotoButton * self, + gchar * file_path +) { if (!KOTO_IS_BUTTON(self)) { // Not a button return; } @@ -324,8 +365,13 @@ void koto_button_set_file_path(KotoButton *self, gchar *file_path) { koto_button_show_image(self, FALSE); } -void koto_button_set_icon_name(KotoButton *self, gchar *icon_name, gboolean for_alt) { - gchar *copied_icon_name = g_strdup(icon_name); +void koto_button_set_icon_name( + KotoButton * self, + gchar * icon_name, + gboolean for_alt +) { + gchar * copied_icon_name = g_strdup(icon_name); + if (for_alt) { // Is for the alternate icon if ((self->alt_icon_name != NULL) && strcmp(icon_name, self->alt_icon_name) != 0) { // If the icons are different @@ -342,9 +388,11 @@ void koto_button_set_icon_name(KotoButton *self, gchar *icon_name, gboolean for_ } gboolean hide_image = FALSE; + + if (for_alt && self->currently_showing_alt && ((self->alt_icon_name == NULL) || strcmp(self->alt_icon_name, "") == 0)) { // For alt, alt is currently showing, and no longer have alt hide_image = TRUE; - } else if (!for_alt && ((self->icon_name == NULL) || (strcmp(self->icon_name,"") == 0))) { // Not for alt, no icon + } else if (!for_alt && ((self->icon_name == NULL) || (strcmp(self->icon_name, "") == 0))) { // Not for alt, no icon hide_image = TRUE; } @@ -359,7 +407,10 @@ void koto_button_set_icon_name(KotoButton *self, gchar *icon_name, gboolean for_ g_object_notify_by_pspec(G_OBJECT(self), for_alt ? btn_props[PROP_ALT_ICON_NAME] : btn_props[PROP_ICON_NAME]); } -void koto_button_set_image_position(KotoButton *self, KotoButtonImagePosition pos) { +void koto_button_set_image_position( + KotoButton * self, + KotoButtonImagePosition pos +) { if (self->image_position == pos) { // Is a different position that currently return; } @@ -375,7 +426,10 @@ void koto_button_set_image_position(KotoButton *self, KotoButtonImagePosition po self->image_position = pos; } -void koto_button_set_pixbuf_size(KotoButton *self, guint size) { +void koto_button_set_pixbuf_size( + KotoButton * self, + guint size +) { if (size == self->pix_size) { return; } @@ -386,7 +440,10 @@ void koto_button_set_pixbuf_size(KotoButton *self, guint size) { g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_PIX_SIZE]); } -void koto_button_set_text(KotoButton *self, gchar *text) { +void koto_button_set_text( + KotoButton * self, + gchar * text +) { if (text == NULL) { return; } @@ -421,7 +478,10 @@ void koto_button_set_text(KotoButton *self, gchar *text) { g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_TEXT]); } -void koto_button_show_image(KotoButton *self, gboolean use_alt) { +void koto_button_show_image( + KotoButton * self, + gboolean use_alt +) { if (!KOTO_IS_BUTTON(self)) { return; } @@ -446,7 +506,7 @@ void koto_button_show_image(KotoButton *self, gboolean use_alt) { } self->currently_showing_alt = use_alt; - gchar *name = use_alt ? self->alt_icon_name : self->icon_name; + gchar * name = use_alt ? self->alt_icon_name : self->icon_name; if (GTK_IS_IMAGE(self->button_pic)) { gtk_image_set_from_icon_name(GTK_IMAGE(self->button_pic), name); // Just update the existing iamge @@ -461,7 +521,7 @@ void koto_button_show_image(KotoButton *self, gboolean use_alt) { gtk_widget_show(self->button_pic); // Ensure we actually are showing the image } -void koto_button_unflatten(KotoButton *self) { +void koto_button_unflatten(KotoButton * self) { if (!KOTO_IS_BUTTON(self)) { return; } @@ -469,26 +529,44 @@ void koto_button_unflatten(KotoButton *self) { gtk_widget_remove_css_class(GTK_WIDGET(self), "flat"); } -KotoButton* koto_button_new_plain(gchar *label) { - return g_object_new(KOTO_TYPE_BUTTON, - "button-text", label, +KotoButton * koto_button_new_plain(gchar * label) { + return g_object_new( + KOTO_TYPE_BUTTON, + "button-text", + label, NULL ); } -KotoButton* koto_button_new_with_icon(gchar *label, gchar *icon_name, gchar *alt_icon_name, KotoButtonPixbufSize size) { - return g_object_new(KOTO_TYPE_BUTTON, - "button-text", label, - "icon-name", icon_name, - "alt-icon-name", alt_icon_name, - "pixbuf-size", koto_get_pixbuf_size(size), +KotoButton * koto_button_new_with_icon( + gchar * label, + gchar * icon_name, + gchar * alt_icon_name, + KotoButtonPixbufSize size +) { + return g_object_new( + KOTO_TYPE_BUTTON, + "button-text", + label, + "icon-name", + icon_name, + "alt-icon-name", + alt_icon_name, + "pixbuf-size", + koto_get_pixbuf_size(size), NULL ); } -KotoButton *koto_button_new_with_file(gchar *label, gchar *file_path, KotoButtonPixbufSize size) { - return g_object_new(KOTO_TYPE_BUTTON, - "button-text", label, +KotoButton * koto_button_new_with_file( + gchar * label, + gchar * file_path, + KotoButtonPixbufSize size +) { + return g_object_new( + KOTO_TYPE_BUTTON, + "button-text", + label, "use-from-file", TRUE, "image-file-path", diff --git a/src/koto-button.h b/src/koto-button.h index 2687991..84cd84f 100644 --- a/src/koto-button.h +++ b/src/koto-button.h @@ -46,26 +46,78 @@ typedef enum { #define NUM_BUILTIN_SIZES 7 #define KOTO_TYPE_BUTTON (koto_button_get_type()) -G_DECLARE_FINAL_TYPE (KotoButton, koto_button, KOTO, BUTTON, GtkBox) +G_DECLARE_FINAL_TYPE(KotoButton, koto_button, KOTO, BUTTON, GtkBox) #define KOTO_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_BUTTON)) guint koto_get_pixbuf_size(KotoButtonPixbufSize size); -KotoButton* koto_button_new_plain(gchar *label); -KotoButton* koto_button_new_with_icon(gchar *label, gchar *icon_name, gchar *alt_icon_name, KotoButtonPixbufSize size); -KotoButton *koto_button_new_with_file(gchar *label, gchar *file_path, KotoButtonPixbufSize size); +KotoButton * koto_button_new_plain(gchar * label); -void koto_button_add_click_handler(KotoButton *self, KotoButtonClickType button, GCallback handler, gpointer user_data); -void koto_button_flip(KotoButton *self); -void koto_button_hide_image(KotoButton *self); -void koto_button_set_badge_text(KotoButton *self, gchar *text); -void koto_button_set_file_path(KotoButton *self, gchar *file_path); -void koto_button_set_icon_name(KotoButton *self, gchar *icon_name, gboolean for_alt); -void koto_button_set_image_position(KotoButton *self, KotoButtonImagePosition pos); -void koto_button_set_pixbuf(KotoButton *self, GdkPixbuf *pix); -void koto_button_set_pixbuf_size(KotoButton *self, guint size); -void koto_button_set_text(KotoButton *self, gchar *text); -void koto_button_show_image(KotoButton *self, gboolean use_alt); -void koto_button_unflatten(KotoButton *self); +KotoButton * koto_button_new_with_icon( + gchar * label, + gchar * icon_name, + gchar * alt_icon_name, + KotoButtonPixbufSize size +); + +KotoButton * koto_button_new_with_file( + gchar * label, + gchar * file_path, + KotoButtonPixbufSize size +); + +void koto_button_add_click_handler( + KotoButton * self, + KotoButtonClickType button, + GCallback handler, + gpointer user_data +); + +void koto_button_flip(KotoButton * self); + +void koto_button_hide_image(KotoButton * self); + +void koto_button_set_badge_text( + KotoButton * self, + gchar * text +); + +void koto_button_set_file_path( + KotoButton * self, + gchar * file_path +); + +void koto_button_set_icon_name( + KotoButton * self, + gchar * icon_name, + gboolean for_alt +); + +void koto_button_set_image_position( + KotoButton * self, + KotoButtonImagePosition pos +); + +void koto_button_set_pixbuf( + KotoButton * self, + GdkPixbuf * pix +); + +void koto_button_set_pixbuf_size( + KotoButton * self, + guint size +); + +void koto_button_set_text( + KotoButton * self, + gchar * text +); + +void koto_button_show_image( + KotoButton * self, + gboolean use_alt +); + +void koto_button_unflatten(KotoButton * self); G_END_DECLS diff --git a/src/koto-dialog-container.c b/src/koto-dialog-container.c index 6521650..41049d0 100644 --- a/src/koto-dialog-container.c +++ b/src/koto-dialog-container.c @@ -22,25 +22,20 @@ struct _KotoDialogContainer { GtkBox parent_instance; - KotoButton *close_button; - GtkWidget *dialogs; + KotoButton * close_button; + GtkWidget * dialogs; }; G_DEFINE_TYPE(KotoDialogContainer, koto_dialog_container, GTK_TYPE_BOX); -static void koto_dialog_container_class_init(KotoDialogContainerClass *c) { +static void koto_dialog_container_class_init(KotoDialogContainerClass * c) { (void) c; } -static void koto_dialog_container_init(KotoDialogContainer *self) { +static void koto_dialog_container_init(KotoDialogContainer * self) { gtk_widget_add_css_class(GTK_WIDGET(self), "koto-dialog-container"); - g_object_set(GTK_WIDGET(self), - "hexpand", - TRUE, - "vexpand", - TRUE, - NULL); + g_object_set(GTK_WIDGET(self), "hexpand", TRUE, "vexpand", TRUE, NULL); self->close_button = koto_button_new_with_icon(NULL, "window-close-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_LARGE); gtk_widget_set_halign(GTK_WIDGET(self->close_button), GTK_ALIGN_END); @@ -60,7 +55,11 @@ static void koto_dialog_container_init(KotoDialogContainer *self) { gtk_widget_hide(GTK_WIDGET(self)); // Hide by default } -void koto_dialog_container_add_dialog(KotoDialogContainer *self, gchar *dialog_name, GtkWidget *dialog) { +void koto_dialog_container_add_dialog( + KotoDialogContainer * self, + gchar * dialog_name, + GtkWidget * dialog +) { if (!KOTO_IS_DIALOG_CONTAINER(self)) { // Not a dialog container return; } @@ -68,12 +67,21 @@ void koto_dialog_container_add_dialog(KotoDialogContainer *self, gchar *dialog_n gtk_stack_add_named(GTK_STACK(self->dialogs), dialog, dialog_name); // Add the dialog to the stack } -void koto_dialog_container_handle_close_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; +void koto_dialog_container_handle_close_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; koto_dialog_container_hide((KotoDialogContainer*) user_data); } -void koto_dialog_container_hide(KotoDialogContainer *self) { +void koto_dialog_container_hide(KotoDialogContainer * self) { if (!KOTO_IS_DIALOG_CONTAINER(self)) { // Not a dialog container return; } @@ -81,7 +89,10 @@ void koto_dialog_container_hide(KotoDialogContainer *self) { gtk_widget_hide(GTK_WIDGET(self)); } -void koto_dialog_container_show_dialog(KotoDialogContainer *self, gchar *dialog_name) { +void koto_dialog_container_show_dialog( + KotoDialogContainer * self, + gchar * dialog_name +) { if (!KOTO_IS_DIALOG_CONTAINER(self)) { // Not a dialog container return; } @@ -90,8 +101,9 @@ void koto_dialog_container_show_dialog(KotoDialogContainer *self, gchar *dialog_ gtk_widget_show(GTK_WIDGET(self)); // Ensure we show self } -KotoDialogContainer* koto_dialog_container_new() { - return g_object_new(KOTO_TYPE_DIALOG_CONTAINER, +KotoDialogContainer * koto_dialog_container_new() { + return g_object_new( + KOTO_TYPE_DIALOG_CONTAINER, "orientation", GTK_ORIENTATION_VERTICAL, NULL diff --git a/src/koto-dialog-container.h b/src/koto-dialog-container.h index f2a253b..886be2c 100644 --- a/src/koto-dialog-container.h +++ b/src/koto-dialog-container.h @@ -23,7 +23,7 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_DIALOG_CONTAINER koto_dialog_container_get_type() G_DECLARE_FINAL_TYPE(KotoDialogContainer, koto_dialog_container, KOTO, DIALOG_CONTAINER, GtkBox); @@ -31,12 +31,29 @@ G_DECLARE_FINAL_TYPE(KotoDialogContainer, koto_dialog_container, KOTO, DIALOG_CO /** * Functions -**/ + **/ -KotoDialogContainer* koto_dialog_container_new(); -void koto_dialog_container_add_dialog(KotoDialogContainer *self, gchar *dialog_name, GtkWidget *dialog); -void koto_dialog_container_handle_close_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_dialog_container_hide(KotoDialogContainer *self); -void koto_dialog_container_show_dialog(KotoDialogContainer *self, gchar *dialog_name); +KotoDialogContainer * koto_dialog_container_new(); + +void koto_dialog_container_add_dialog( + KotoDialogContainer * self, + gchar * dialog_name, + GtkWidget * dialog +); + +void koto_dialog_container_handle_close_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_dialog_container_hide(KotoDialogContainer * self); + +void koto_dialog_container_show_dialog( + KotoDialogContainer * self, + gchar * dialog_name +); G_END_DECLS diff --git a/src/koto-expander.c b/src/koto-expander.c index 000c80d..192f183 100644 --- a/src/koto-expander.c +++ b/src/koto-expander.c @@ -30,22 +30,24 @@ enum { N_EXP_PROPERTIES }; -static GParamSpec *expander_props[N_EXP_PROPERTIES] = { NULL, }; +static GParamSpec * expander_props[N_EXP_PROPERTIES] = { + NULL, +}; struct _KotoExpander { GtkBox parent_instance; gboolean constructed; - GtkWidget *header; - KotoButton *header_button; + GtkWidget * header; + KotoButton * header_button; - gchar *icon_name; - gchar *label; + gchar * icon_name; + gchar * label; - KotoButton *header_secondary_button; - KotoButton *header_expand_button; + KotoButton * header_secondary_button; + KotoButton * header_expand_button; - GtkWidget *revealer; - GtkWidget *content; + GtkWidget * revealer; + GtkWidget * content; }; struct _KotoExpanderClass { @@ -54,11 +56,24 @@ struct _KotoExpanderClass { G_DEFINE_TYPE(KotoExpander, koto_expander, GTK_TYPE_BOX); -static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_expander_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static void koto_expander_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_expander_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_expander_class_init(KotoExpanderClass * c) { + GObjectClass * gobject_class = G_OBJECT_CLASS(c); + -static void koto_expander_class_init(KotoExpanderClass *c) { - GObjectClass *gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_expander_set_property; gobject_class->get_property = koto_expander_get_property; @@ -67,7 +82,7 @@ static void koto_expander_class_init(KotoExpanderClass *c) { "Icon Name", "Name of the icon to use in the Expander", "emblem-favorite-symbolic", - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); expander_props[PROP_HEADER_LABEL] = g_param_spec_string( @@ -75,7 +90,7 @@ static void koto_expander_class_init(KotoExpanderClass *c) { "Label", "Label for the Expander", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); expander_props[PROP_HEADER_SECONDARY_BUTTON] = g_param_spec_object( @@ -83,7 +98,7 @@ static void koto_expander_class_init(KotoExpanderClass *c) { "Secondary Button", "Secondary Button to be placed next to Expander button", KOTO_TYPE_BUTTON, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); expander_props[PROP_CONTENT] = g_param_spec_object( @@ -91,14 +106,20 @@ static void koto_expander_class_init(KotoExpanderClass *c) { "Content", "Content inside the Expander", GTK_TYPE_WIDGET, - G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_EXP_PROPERTIES, expander_props); } -static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoExpander *self = KOTO_EXPANDER(obj); +static void koto_expander_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoExpander * self = KOTO_EXPANDER(obj); + switch (prop_id) { case PROP_HEADER_ICON_NAME: @@ -108,10 +129,10 @@ static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, g_value_set_string(val, self->label); break; case PROP_HEADER_SECONDARY_BUTTON: - g_value_set_object(val, (GObject *) self->header_secondary_button); + g_value_set_object(val, (GObject*) self->header_secondary_button); break; case PROP_CONTENT: - g_value_set_object(val, (GObject *) self->content); + g_value_set_object(val, (GObject*) self->content); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); @@ -119,48 +140,58 @@ static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, } } -static void koto_expander_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoExpander *self = KOTO_EXPANDER(obj); +static void koto_expander_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoExpander * self = KOTO_EXPANDER(obj); - if (!GTK_IS_WIDGET(self->header_button)) { // Header Button is not a widget - KotoButton *new_button = koto_button_new_with_icon(NULL, "emblem-favorite-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL); - if (GTK_IS_WIDGET(new_button)) { // Created our widget successfully - self->header_button = new_button; - gtk_widget_set_hexpand(GTK_WIDGET(self->header_button), TRUE); - gtk_box_prepend(GTK_BOX(self->header), GTK_WIDGET(self->header_button)); - } + if (!GTK_IS_WIDGET(self->header_button)) { // Header Button is not a widget + KotoButton * new_button = koto_button_new_with_icon(NULL, "emblem-favorite-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL); + + if (GTK_IS_WIDGET(new_button)) { // Created our widget successfully + self->header_button = new_button; + gtk_widget_set_hexpand(GTK_WIDGET(self->header_button), TRUE); + gtk_box_prepend(GTK_BOX(self->header), GTK_WIDGET(self->header_button)); } + } - switch (prop_id) { - case PROP_HEADER_ICON_NAME: - g_return_if_fail(GTK_IS_WIDGET(self->header_button)); - koto_button_set_icon_name(self->header_button, g_strdup(g_value_get_string(val)), FALSE); - break; - case PROP_HEADER_LABEL: - g_return_if_fail(GTK_IS_WIDGET(self->header_button)); - koto_button_set_text(self->header_button, g_strdup(g_value_get_string(val))); - break; - case PROP_HEADER_SECONDARY_BUTTON: - koto_expander_set_secondary_button(self, (KotoButton*) g_value_get_object(val)); - break; - case PROP_CONTENT: - koto_expander_set_content(self, (GtkWidget*) g_value_get_object(val)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); - break; - } + switch (prop_id) { + case PROP_HEADER_ICON_NAME: + g_return_if_fail(GTK_IS_WIDGET(self->header_button)); + koto_button_set_icon_name(self->header_button, g_strdup(g_value_get_string(val)), FALSE); + break; + case PROP_HEADER_LABEL: + g_return_if_fail(GTK_IS_WIDGET(self->header_button)); + koto_button_set_text(self->header_button, g_strdup(g_value_get_string(val))); + break; + case PROP_HEADER_SECONDARY_BUTTON: + koto_expander_set_secondary_button(self, (KotoButton*) g_value_get_object(val)); + break; + case PROP_CONTENT: + koto_expander_set_content(self, (GtkWidget*) g_value_get_object(val)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); + break; + } } -static void koto_expander_init(KotoExpander *self) { - GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self)); +static void koto_expander_init(KotoExpander * self) { + GtkStyleContext * style = gtk_widget_get_style_context(GTK_WIDGET(self)); + + gtk_style_context_add_class(style, "expander"); gtk_widget_set_hexpand((GTK_WIDGET(self)), TRUE); self->header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - GtkStyleContext *header_style = gtk_widget_get_style_context(self->header); + GtkStyleContext * header_style = gtk_widget_get_style_context(self->header); + + gtk_style_context_add_class(header_style, "expander-header"); self->revealer = gtk_revealer_new(); @@ -178,7 +209,10 @@ static void koto_expander_init(KotoExpander *self) { koto_button_add_click_handler(self->header_expand_button, KOTO_BUTTON_CLICK_TYPE_PRIMARY, G_CALLBACK(koto_expander_toggle_content), self); } -void koto_expander_set_secondary_button(KotoExpander *self, KotoButton *new_button) { +void koto_expander_set_secondary_button( + KotoExpander * self, + KotoButton * new_button +) { if (!self->constructed) { return; } @@ -197,7 +231,10 @@ void koto_expander_set_secondary_button(KotoExpander *self, KotoButton *new_butt g_object_notify_by_pspec(G_OBJECT(self), expander_props[PROP_HEADER_SECONDARY_BUTTON]); } -void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content) { +void koto_expander_set_content( + KotoExpander * self, + GtkWidget * new_content +) { if (!self->constructed) { return; } @@ -213,34 +250,62 @@ void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content) { g_object_notify_by_pspec(G_OBJECT(self), expander_props[PROP_CONTENT]); } -GtkWidget* koto_expander_get_content(KotoExpander *self) { +GtkWidget * koto_expander_get_content(KotoExpander * self) { return self->content; } -void koto_expander_toggle_content(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; +void koto_expander_toggle_content( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; KotoExpander* self = data; + koto_button_flip(KOTO_BUTTON(self->header_expand_button)); GtkRevealer* rev = GTK_REVEALER(self->revealer); + + gtk_revealer_set_reveal_child(rev, !gtk_revealer_get_reveal_child(rev)); // Invert our values } -KotoExpander* koto_expander_new(gchar *primary_icon_name, gchar *primary_label_text) { - return g_object_new(KOTO_TYPE_EXPANDER, - "orientation", GTK_ORIENTATION_VERTICAL, - "icon-name", primary_icon_name, - "label", primary_label_text, +KotoExpander * koto_expander_new( + gchar * primary_icon_name, + gchar * primary_label_text +) { + return g_object_new( + KOTO_TYPE_EXPANDER, + "orientation", + GTK_ORIENTATION_VERTICAL, + "icon-name", + primary_icon_name, + "label", + primary_label_text, NULL ); } -KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, KotoButton *secondary_button) { - return g_object_new(KOTO_TYPE_EXPANDER, - "orientation", GTK_ORIENTATION_VERTICAL, - "icon-name", primary_icon_name, - "label", primary_label_text, - "secondary-button", secondary_button, +KotoExpander * koto_expander_new_with_button( + gchar * primary_icon_name, + gchar * primary_label_text, + KotoButton * secondary_button +) { + return g_object_new( + KOTO_TYPE_EXPANDER, + "orientation", + GTK_ORIENTATION_VERTICAL, + "icon-name", + primary_icon_name, + "label", + primary_label_text, + "secondary-button", + secondary_button, NULL ); } diff --git a/src/koto-expander.h b/src/koto-expander.h index 4f4fb2a..2677cd3 100644 --- a/src/koto-expander.h +++ b/src/koto-expander.h @@ -23,16 +23,44 @@ G_BEGIN_DECLS #define KOTO_TYPE_EXPANDER (koto_expander_get_type()) -G_DECLARE_FINAL_TYPE (KotoExpander, koto_expander, KOTO, EXPANDER, GtkBox) +G_DECLARE_FINAL_TYPE(KotoExpander, koto_expander, KOTO, EXPANDER, GtkBox) #define KOTO_IS_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_EXPANDER)) -KotoExpander* koto_expander_new(gchar *primary_icon_name, gchar *primary_label_text); -KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, KotoButton *secondary_button); -GtkWidget* koto_expander_get_content(KotoExpander *self); -void koto_expander_set_icon_name(KotoExpander *self, const gchar *in); -void koto_expander_set_label(KotoExpander *self, const gchar *label); -void koto_expander_set_secondary_button(KotoExpander *self, KotoButton *new_button); -void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content); -void koto_expander_toggle_content(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); +KotoExpander * koto_expander_new(gchar * primary_icon_name, gchar * primary_label_text); +KotoExpander * koto_expander_new_with_button( + gchar * primary_icon_name, + gchar * primary_label_text, + KotoButton * secondary_button +); + +GtkWidget * koto_expander_get_content(KotoExpander * self); + +void koto_expander_set_icon_name( + KotoExpander * self, + const gchar* in +); + +void koto_expander_set_label( + KotoExpander * self, + const gchar * label +); + +void koto_expander_set_secondary_button( + KotoExpander * self, + KotoButton * new_button +); + +void koto_expander_set_content( + KotoExpander * self, + GtkWidget * new_content +); + +void koto_expander_toggle_content( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); G_END_DECLS diff --git a/src/koto-nav.c b/src/koto-nav.c index f45e80a..94ca2b4 100644 --- a/src/koto-nav.c +++ b/src/koto-nav.c @@ -26,39 +26,39 @@ #include "koto-utils.h" #include "koto-window.h" -extern KotoCartographer *koto_maps; -extern KotoWindow *main_window; +extern KotoCartographer * koto_maps; +extern KotoWindow * main_window; struct _KotoNav { GObject parent_instance; - GtkWidget *win; - GtkWidget *content; + GtkWidget * win; + GtkWidget * content; - KotoButton *home_button; - KotoExpander *audiobook_expander; - KotoExpander *music_expander; - KotoExpander *podcast_expander; - KotoExpander *playlists_expander; + KotoButton * home_button; + KotoExpander * audiobook_expander; + KotoExpander * music_expander; + KotoExpander * podcast_expander; + KotoExpander * playlists_expander; // Audiobooks - KotoButton *audiobooks_local; - KotoButton *audiobooks_audible; - KotoButton *audiobooks_librivox; + KotoButton * audiobooks_local; + KotoButton * audiobooks_audible; + KotoButton * audiobooks_librivox; // Music - KotoButton *music_local; - KotoButton *music_radio; + KotoButton * music_local; + KotoButton * music_radio; // Playlists - GHashTable *playlist_buttons; + GHashTable * playlist_buttons; // Podcasts - KotoButton *podcasts_local; - KotoButton *podcasts_discover; + KotoButton * podcasts_local; + KotoButton * podcasts_discover; }; struct _KotoNavClass { @@ -67,11 +67,11 @@ struct _KotoNavClass { G_DEFINE_TYPE(KotoNav, koto_nav, G_TYPE_OBJECT); -static void koto_nav_class_init(KotoNavClass *c) { +static void koto_nav_class_init(KotoNavClass * c) { (void) c; } -static void koto_nav_init(KotoNav *self) { +static void koto_nav_init(KotoNav * self) { self->playlist_buttons = g_hash_table_new(g_str_hash, g_str_equal); self->win = gtk_scrolled_window_new(); gtk_widget_set_hexpand_set(self->win, TRUE); // using hexpand-set works, hexpand seems to break it by causing it to take up way too much space @@ -88,7 +88,8 @@ static void koto_nav_init(KotoNav *self) { gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(self->win), self->content); - KotoButton *h_button = koto_button_new_with_icon("Home", "user-home-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL); + KotoButton * h_button = koto_button_new_with_icon("Home", "user-home-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL); + if (h_button != NULL) { self->home_button = h_button; @@ -101,13 +102,16 @@ static void koto_nav_init(KotoNav *self) { koto_nav_create_playlist_section(self); } -void koto_nav_create_audiobooks_section(KotoNav *self) { - KotoExpander *a_expander = koto_expander_new("ephy-bookmarks-symbolic", "Audiobooks"); +void koto_nav_create_audiobooks_section(KotoNav * self) { + KotoExpander * a_expander = koto_expander_new("ephy-bookmarks-symbolic", "Audiobooks"); + self->audiobook_expander = a_expander; gtk_box_append(GTK_BOX(self->content), GTK_WIDGET(self->audiobook_expander)); - GtkWidget *new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget * new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + + koto_expander_set_content(a_expander, new_content); self->audiobooks_local = koto_button_new_plain("Local Library"); @@ -119,12 +123,15 @@ void koto_nav_create_audiobooks_section(KotoNav *self) { gtk_box_append(GTK_BOX(new_content), GTK_WIDGET(self->audiobooks_librivox)); } -void koto_nav_create_music_section(KotoNav *self) { - KotoExpander *m_expander = koto_expander_new("emblem-music-symbolic", "Music"); +void koto_nav_create_music_section(KotoNav * self) { + KotoExpander * m_expander = koto_expander_new("emblem-music-symbolic", "Music"); + + self->music_expander = m_expander; gtk_box_append(GTK_BOX(self->content), GTK_WIDGET(self->music_expander)); - GtkWidget *new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget * new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + self->music_local = koto_button_new_plain("Local Library"); self->music_radio = koto_button_new_plain("Radio"); @@ -136,15 +143,17 @@ void koto_nav_create_music_section(KotoNav *self) { koto_button_add_click_handler(self->music_local, KOTO_BUTTON_CLICK_TYPE_PRIMARY, G_CALLBACK(koto_nav_handle_local_music_click), NULL); } -void koto_nav_create_playlist_section(KotoNav *self) { - KotoButton *playlist_add_button = koto_button_new_with_icon("", "list-add-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL); - KotoExpander *pl_expander = koto_expander_new_with_button("playlist-symbolic", "Playlists", playlist_add_button); +void koto_nav_create_playlist_section(KotoNav * self) { + KotoButton * playlist_add_button = koto_button_new_with_icon("", "list-add-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL); + KotoExpander * pl_expander = koto_expander_new_with_button("playlist-symbolic", "Playlists", playlist_add_button); + self->playlists_expander = pl_expander; gtk_box_append(GTK_BOX(self->content), GTK_WIDGET(self->playlists_expander)); // TODO: Turn into ListBox to sort playlists - GtkWidget *playlist_list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget * playlist_list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + koto_expander_set_content(self->playlists_expander, playlist_list); koto_button_add_click_handler(playlist_add_button, KOTO_BUTTON_CLICK_TYPE_PRIMARY, G_CALLBACK(koto_nav_handle_playlist_add_click), NULL); @@ -153,12 +162,15 @@ void koto_nav_create_playlist_section(KotoNav *self) { g_signal_connect(koto_maps, "playlist-removed", G_CALLBACK(koto_nav_handle_playlist_removed), self); } -void koto_nav_create_podcasts_section(KotoNav *self) { - KotoExpander *p_expander = koto_expander_new("microphone-sensitivity-high-symbolic", "Podcasts"); +void koto_nav_create_podcasts_section(KotoNav * self) { + KotoExpander * p_expander = koto_expander_new("microphone-sensitivity-high-symbolic", "Podcasts"); + + self->podcast_expander = p_expander; gtk_box_append(GTK_BOX(self->content), GTK_WIDGET(self->podcast_expander)); - GtkWidget *new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget * new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + self->podcasts_local = koto_button_new_plain("Library"); self->podcasts_discover = koto_button_new_plain("Find New Podcasts"); @@ -169,43 +181,82 @@ void koto_nav_create_podcasts_section(KotoNav *self) { koto_expander_set_content(p_expander, new_content); } -void koto_nav_handle_playlist_add_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) user_data; +void koto_nav_handle_playlist_add_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) user_data; koto_window_show_dialog(main_window, "create-modify-playlist"); } -void koto_nav_handle_local_music_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) user_data; +void koto_nav_handle_local_music_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) user_data; koto_window_go_to_page(main_window, "music.local"); // Go to the playlist page } -void koto_nav_handle_playlist_button_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - gchar *playlist_uuid = user_data; +void koto_nav_handle_playlist_button_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + gchar * playlist_uuid = user_data; + + koto_window_go_to_page(main_window, playlist_uuid); // Go to the playlist page } -void koto_nav_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playlist, gpointer user_data) { +void koto_nav_handle_playlist_added( + KotoCartographer * carto, + KotoPlaylist * playlist, + gpointer user_data +) { (void) carto; if (!KOTO_IS_PLAYLIST(playlist)) { return; } - KotoNav *self = user_data; + KotoNav * self = user_data; + + if (!KOTO_IS_NAV(self)) { return; } - gchar *playlist_uuid = koto_playlist_get_uuid(playlist); // Get the UUID for a playlist + gchar * playlist_uuid = koto_playlist_get_uuid(playlist); // Get the UUID for a playlist + if (g_hash_table_contains(self->playlist_buttons, playlist_uuid)) { // Already added button g_free(playlist_uuid); return; } - gchar *playlist_name = koto_playlist_get_name(playlist); - gchar *playlist_art_path = koto_playlist_get_artwork(playlist); // Get any file path for it - KotoButton *playlist_button = NULL; + gchar * playlist_name = koto_playlist_get_name(playlist); + gchar * playlist_art_path = koto_playlist_get_artwork(playlist); // Get any file path for it + KotoButton * playlist_button = NULL; + if (koto_utils_is_string_valid(playlist_art_path)) { // Have a file associated playlist_button = koto_button_new_with_file(playlist_name, playlist_art_path, KOTO_BUTTON_PIXBUF_SIZE_NORMAL); @@ -217,7 +268,7 @@ void koto_nav_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playl g_hash_table_insert(self->playlist_buttons, playlist_uuid, playlist_button); // Add the button // TODO: Make this a ListBox and sort the playlists alphabetically - GtkBox *playlist_expander_content = GTK_BOX(koto_expander_get_content(self->playlists_expander)); + GtkBox * playlist_expander_content = GTK_BOX(koto_expander_get_content(self->playlists_expander)); if (GTK_IS_BOX(playlist_expander_content)) { gtk_box_append(playlist_expander_content, GTK_WIDGET(playlist_button)); @@ -229,58 +280,76 @@ void koto_nav_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playl } } -void koto_nav_handle_playlist_modified(KotoPlaylist *playlist, gpointer user_data) { +void koto_nav_handle_playlist_modified( + KotoPlaylist * playlist, + gpointer user_data +) { if (!KOTO_IS_PLAYLIST(playlist)) { return; } - KotoNav *self = user_data; + KotoNav * self = user_data; + + if (!KOTO_IS_NAV(self)) { return; } - gchar *playlist_uuid = koto_playlist_get_uuid(playlist); // Get the UUID for a playlist + gchar * playlist_uuid = koto_playlist_get_uuid(playlist); // Get the UUID for a playlist + + KotoButton * playlist_button = g_hash_table_lookup(self->playlist_buttons, playlist_uuid); - KotoButton *playlist_button = g_hash_table_lookup(self->playlist_buttons, playlist_uuid); if (!KOTO_IS_BUTTON(playlist_button)) { return; } - gchar *artwork = koto_playlist_get_artwork(playlist); // Get the artwork + gchar * artwork = koto_playlist_get_artwork(playlist); // Get the artwork + + if (koto_utils_is_string_valid(artwork)) { // Have valid artwork koto_button_set_file_path(playlist_button, artwork); // Update the artwork path } - gchar *name = koto_playlist_get_name(playlist); // Get the name + gchar * name = koto_playlist_get_name(playlist); // Get the name + + if (koto_utils_is_string_valid(name)) { // Have valid name koto_button_set_text(playlist_button, name); // Update the button text } } -void koto_nav_handle_playlist_removed(KotoCartographer *carto, gchar *playlist_uuid, gpointer user_data) { +void koto_nav_handle_playlist_removed( + KotoCartographer * carto, + gchar * playlist_uuid, + gpointer user_data +) { (void) carto; - KotoNav *self = user_data; + KotoNav * self = user_data; + if (!g_hash_table_contains(self->playlist_buttons, playlist_uuid)) { // Does not contain this return; } - KotoButton *playlist_btn = g_hash_table_lookup(self->playlist_buttons, playlist_uuid); // Get the playlist button + KotoButton * playlist_btn = g_hash_table_lookup(self->playlist_buttons, playlist_uuid); // Get the playlist button + if (!KOTO_IS_BUTTON(playlist_btn)) { // Not a playlist button return; } - GtkBox *playlist_expander_content = GTK_BOX(koto_expander_get_content(self->playlists_expander)); + GtkBox * playlist_expander_content = GTK_BOX(koto_expander_get_content(self->playlists_expander)); + + gtk_box_remove(playlist_expander_content, GTK_WIDGET(playlist_btn)); // Remove the button g_hash_table_remove(self->playlist_buttons, playlist_uuid); // Remove from the playlist buttons hash table } -GtkWidget* koto_nav_get_nav(KotoNav *self) { +GtkWidget * koto_nav_get_nav(KotoNav * self) { return self->win; } -KotoNav* koto_nav_new(void) { - return g_object_new(KOTO_TYPE_NAV ,NULL); +KotoNav * koto_nav_new(void) { + return g_object_new(KOTO_TYPE_NAV, NULL); } diff --git a/src/koto-nav.h b/src/koto-nav.h index ebe2d47..d69d7bf 100644 --- a/src/koto-nav.h +++ b/src/koto-nav.h @@ -24,19 +24,50 @@ G_BEGIN_DECLS #define KOTO_TYPE_NAV (koto_nav_get_type()) -G_DECLARE_FINAL_TYPE (KotoNav, koto_nav, KOTO, NAV, GObject) +G_DECLARE_FINAL_TYPE(KotoNav, koto_nav, KOTO, NAV, GObject) -KotoNav* koto_nav_new (void); -void koto_nav_create_audiobooks_section(KotoNav *self); -void koto_nav_create_music_section(KotoNav *self); -void koto_nav_create_playlist_section(KotoNav *self); -void koto_nav_create_podcasts_section(KotoNav *self); -void koto_nav_handle_playlist_add_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_nav_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playlist, gpointer user_data); -void koto_nav_handle_playlist_modified(KotoPlaylist *playlist, gpointer user_data); -void koto_nav_handle_playlist_removed(KotoCartographer *carto, gchar *playlist_uuid, gpointer user_data); -void koto_nav_handle_local_music_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); +KotoNav* koto_nav_new(void); +void koto_nav_create_audiobooks_section(KotoNav * self); -GtkWidget* koto_nav_get_nav(KotoNav *self); +void koto_nav_create_music_section(KotoNav * self); + +void koto_nav_create_playlist_section(KotoNav * self); + +void koto_nav_create_podcasts_section(KotoNav * self); + +void koto_nav_handle_playlist_add_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_nav_handle_playlist_added( + KotoCartographer * carto, + KotoPlaylist * playlist, + gpointer user_data +); + +void koto_nav_handle_playlist_modified( + KotoPlaylist * playlist, + gpointer user_data +); + +void koto_nav_handle_playlist_removed( + KotoCartographer * carto, + gchar * playlist_uuid, + gpointer user_data +); + +void koto_nav_handle_local_music_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +GtkWidget * koto_nav_get_nav(KotoNav * self); G_END_DECLS diff --git a/src/koto-playerbar.c b/src/koto-playerbar.c index b45ea85..583c660 100644 --- a/src/koto-playerbar.c +++ b/src/koto-playerbar.c @@ -26,40 +26,40 @@ #include "koto-config.h" #include "koto-playerbar.h" -extern KotoAddRemoveTrackPopover *koto_add_remove_track_popup; -extern KotoCurrentPlaylist *current_playlist; -extern KotoCartographer *koto_maps; -extern KotoPlaybackEngine *playback_engine; +extern KotoAddRemoveTrackPopover * koto_add_remove_track_popup; +extern KotoCurrentPlaylist * current_playlist; +extern KotoCartographer * koto_maps; +extern KotoPlaybackEngine * playback_engine; struct _KotoPlayerBar { GObject parent_instance; - GtkWidget *main; - GtkWidget *controls; + GtkWidget * main; + GtkWidget * controls; /* Sections */ - GtkWidget *playback_section; - GtkWidget *primary_controls_section; - GtkWidget *secondary_controls_section; + GtkWidget * playback_section; + GtkWidget * primary_controls_section; + GtkWidget * secondary_controls_section; /* Primary Buttons */ - KotoButton *back_button; - KotoButton *play_pause_button; - KotoButton *forward_button; - KotoButton *repeat_button; - KotoButton *shuffle_button; - KotoButton *playlist_button; - KotoButton *eq_button; - GtkWidget *volume_button; + KotoButton * back_button; + KotoButton * play_pause_button; + KotoButton * forward_button; + KotoButton * repeat_button; + KotoButton * shuffle_button; + KotoButton * playlist_button; + KotoButton * eq_button; + GtkWidget * volume_button; - GtkWidget *progress_bar; + GtkWidget * progress_bar; /* Selected Playback Section */ - GtkWidget *playback_details_section; - GtkWidget *artwork; - GtkWidget *playback_title; - GtkWidget *playback_album; - GtkWidget *playback_artist; + GtkWidget * playback_details_section; + GtkWidget * artwork; + GtkWidget * playback_title; + GtkWidget * playback_album; + GtkWidget * playback_artist; gint64 last_recorded_duration; @@ -72,17 +72,21 @@ struct _KotoPlayerBarClass { G_DEFINE_TYPE(KotoPlayerBar, koto_playerbar, G_TYPE_OBJECT); -static void koto_playerbar_constructed(GObject *obj); +static void koto_playerbar_constructed(GObject * obj); + +static void koto_playerbar_class_init(KotoPlayerBarClass * c) { + GObjectClass * gobject_class; + -static void koto_playerbar_class_init(KotoPlayerBarClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->constructed = koto_playerbar_constructed; } -static void koto_playerbar_constructed(GObject *obj) { - KotoPlayerBar *self = KOTO_PLAYERBAR(obj); +static void koto_playerbar_constructed(GObject * obj) { + KotoPlayerBar * self = KOTO_PLAYERBAR(obj); + + self->main = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_add_css_class(self->main, "player-bar"); @@ -93,7 +97,9 @@ static void koto_playerbar_constructed(GObject *obj) { gtk_range_set_increments(GTK_RANGE(self->progress_bar), 1, 1); gtk_range_set_round_digits(GTK_RANGE(self->progress_bar), 1); - GtkGesture *press_controller = gtk_gesture_click_new(); // Create a new GtkGestureLongPress + GtkGesture * press_controller = gtk_gesture_click_new(); // Create a new GtkGestureLongPress + + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(press_controller), 1); // Set to left click g_signal_connect(press_controller, "begin", G_CALLBACK(koto_playerbar_handle_progressbar_gesture_begin), self); @@ -140,19 +146,20 @@ static void koto_playerbar_constructed(GObject *obj) { g_signal_connect(playback_engine, "track-shuffle-changed", G_CALLBACK(koto_playerbar_handle_track_shuffle), self); } -static void koto_playerbar_init(KotoPlayerBar *self) { +static void koto_playerbar_init(KotoPlayerBar * self) { self->last_recorded_duration = 0; self->is_progressbar_seeking = FALSE; } -KotoPlayerBar* koto_playerbar_new(void) { +KotoPlayerBar * koto_playerbar_new(void) { return g_object_new(KOTO_TYPE_PLAYERBAR, NULL); } void koto_playerbar_create_playback_details(KotoPlayerBar* bar) { bar->playback_details_section = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkIconTheme *default_icon_theme = gtk_icon_theme_get_for_display(gdk_display_get_default()); // Get the icon theme for this display + GtkIconTheme * default_icon_theme = gtk_icon_theme_get_for_display(gdk_display_get_default()); // Get the icon theme for this display + if (default_icon_theme != NULL) { gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(bar->main)); @@ -235,7 +242,7 @@ void koto_playerbar_create_secondary_controls(KotoPlayerBar* bar) { } if (GTK_IS_VOLUME_BUTTON(bar->volume_button)) { - GtkAdjustment *granular_volume_change = gtk_adjustment_new(0.5, 0, 1.0, 0.02, 0.02, 0.02); + GtkAdjustment * granular_volume_change = gtk_adjustment_new(0.5, 0, 1.0, 0.02, 0.02, 0.02); g_object_set(bar->volume_button, "use-symbolic", TRUE, NULL); gtk_scale_button_set_adjustment(GTK_SCALE_BUTTON(bar->volume_button), granular_volume_change); // Set our adjustment gtk_box_append(GTK_BOX(bar->secondary_controls_section), bar->volume_button); @@ -245,24 +252,48 @@ void koto_playerbar_create_secondary_controls(KotoPlayerBar* bar) { } } -void koto_playerbar_go_backwards(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) data; +void koto_playerbar_go_backwards( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) data; koto_playback_engine_backwards(playback_engine); } -void koto_playerbar_go_forwards(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) data; +void koto_playerbar_go_forwards( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) data; koto_playback_engine_forwards(playback_engine); } -void koto_playerbar_handle_is_playing(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_handle_is_playing( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -271,12 +302,16 @@ void koto_playerbar_handle_is_playing(KotoPlaybackEngine *engine, gpointer user_ koto_button_show_image(bar->play_pause_button, TRUE); // Set to TRUE to show pause as the next action } -void koto_playerbar_handle_is_paused(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_handle_is_paused( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -285,9 +320,19 @@ void koto_playerbar_handle_is_paused(KotoPlaybackEngine *engine, gpointer user_d koto_button_show_image(bar->play_pause_button, FALSE); // Set to FALSE to show play as the next action } -void koto_playerbar_handle_playlist_button_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlayerBar *self = data; +void koto_playerbar_handle_playlist_button_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlayerBar * self = data; + if (!KOTO_IS_PLAYERBAR(self)) { // Not a playerbar return; @@ -297,9 +342,15 @@ void koto_playerbar_handle_playlist_button_clicked(GtkGestureClick *gesture, int gtk_widget_show(GTK_WIDGET(koto_add_remove_track_popup)); } -void koto_playerbar_handle_progressbar_gesture_begin(GtkGesture *gesture, GdkEventSequence *seq, gpointer data) { - (void) gesture; (void) seq; - KotoPlayerBar *bar = data; +void koto_playerbar_handle_progressbar_gesture_begin( + GtkGesture * gesture, + GdkEventSequence * seq, + gpointer data +) { + (void) gesture; + (void) seq; + KotoPlayerBar * bar = data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -308,9 +359,15 @@ void koto_playerbar_handle_progressbar_gesture_begin(GtkGesture *gesture, GdkEve bar->is_progressbar_seeking = TRUE; } -void koto_playerbar_handle_progressbar_gesture_end(GtkGesture *gesture, GdkEventSequence *seq, gpointer data) { - (void) gesture; (void) seq; - KotoPlayerBar *bar = data; +void koto_playerbar_handle_progressbar_gesture_end( + GtkGesture * gesture, + GdkEventSequence * seq, + gpointer data +) { + (void) gesture; + (void) seq; + KotoPlayerBar * bar = data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -318,9 +375,19 @@ void koto_playerbar_handle_progressbar_gesture_end(GtkGesture *gesture, GdkEvent bar->is_progressbar_seeking = FALSE; } -void koto_playerbar_handle_progressbar_pressed(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlayerBar *bar = data; +void koto_playerbar_handle_progressbar_pressed( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlayerBar * bar = data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -329,8 +396,12 @@ void koto_playerbar_handle_progressbar_pressed(GtkGestureClick *gesture, int n_p bar->is_progressbar_seeking = TRUE; } -void koto_playerbar_handle_progressbar_value_changed(GtkRange *progress_bar, gpointer data) { - KotoPlayerBar *bar = data; +void koto_playerbar_handle_progressbar_value_changed( + GtkRange * progress_bar, + gpointer data +) { + KotoPlayerBar * bar = data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -342,15 +413,20 @@ void koto_playerbar_handle_progressbar_value_changed(GtkRange *progress_bar, gpo int desired_position = (int) gtk_range_get_value(progress_bar); + koto_playback_engine_set_position(playback_engine, desired_position); // Update our position } -void koto_playerbar_handle_tick_duration(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_handle_tick_duration( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -360,12 +436,16 @@ void koto_playerbar_handle_tick_duration(KotoPlaybackEngine *engine, gpointer us } -void koto_playerbar_handle_tick_track(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_handle_tick_track( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -376,12 +456,16 @@ void koto_playerbar_handle_tick_track(KotoPlaybackEngine *engine, gpointer user_ } } -void koto_playerbar_handle_track_repeat(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_handle_track_repeat( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -394,12 +478,16 @@ void koto_playerbar_handle_track_repeat(KotoPlaybackEngine *engine, gpointer use } } -void koto_playerbar_handle_track_shuffle(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_handle_track_shuffle( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; @@ -412,8 +500,13 @@ void koto_playerbar_handle_track_shuffle(KotoPlaybackEngine *engine, gpointer us } } -void koto_playerbar_handle_volume_button_change(GtkScaleButton *button, double value, gpointer user_data) { - (void) button; (void) user_data; +void koto_playerbar_handle_volume_button_change( + GtkScaleButton * button, + double value, + gpointer user_data +) { + (void) button; + (void) user_data; koto_playback_engine_set_volume(playback_engine, value); } @@ -422,7 +515,10 @@ void koto_playerbar_reset_progressbar(KotoPlayerBar* bar) { gtk_range_set_value(GTK_RANGE(bar->progress_bar), 0); // Set value to 0 } -void koto_playerbar_set_progressbar_duration(KotoPlayerBar* bar, gint64 duration) { +void koto_playerbar_set_progressbar_duration( + KotoPlayerBar* bar, + gint64 duration +) { if (duration <= 0) { return; } @@ -433,52 +529,92 @@ void koto_playerbar_set_progressbar_duration(KotoPlayerBar* bar, gint64 duration } } -void koto_playerbar_set_progressbar_value(KotoPlayerBar* bar, double progress) { +void koto_playerbar_set_progressbar_value( + KotoPlayerBar* bar, + double progress +) { gtk_range_set_value(GTK_RANGE(bar->progress_bar), progress); } -void koto_playerbar_toggle_play_pause(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) data; +void koto_playerbar_toggle_play_pause( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) data; koto_playback_engine_toggle(playback_engine); } -void koto_playerbar_toggle_playlist_shuffle(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) data; +void koto_playerbar_toggle_playlist_shuffle( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) data; koto_playback_engine_toggle_track_shuffle(playback_engine); // Call our playback engine's toggle track shuffle function } -void koto_playerbar_toggle_track_repeat(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; (void) data; +void koto_playerbar_toggle_track_repeat( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + (void) data; koto_playback_engine_toggle_track_repeat(playback_engine); // Call our playback engine's toggle track repeat function } -void koto_playerbar_update_track_info(KotoPlaybackEngine *engine, gpointer user_data) { +void koto_playerbar_update_track_info( + KotoPlaybackEngine * engine, + gpointer user_data +) { if (!KOTO_IS_PLAYBACK_ENGINE(engine)) { return; } - KotoPlayerBar *bar = user_data; + KotoPlayerBar * bar = user_data; + if (!KOTO_IS_PLAYERBAR(bar)) { return; } - KotoIndexedTrack *current_track = koto_playback_engine_get_current_track(playback_engine); // Get the current track from the playback engine + KotoIndexedTrack * current_track = koto_playback_engine_get_current_track(playback_engine); // Get the current track from the playback engine + if (!KOTO_IS_INDEXED_TRACK(current_track)) { return; } - gchar *track_name = NULL; - gchar *artist_uuid = NULL; - gchar *album_uuid = NULL; + gchar * track_name = NULL; + gchar * artist_uuid = NULL; + gchar * album_uuid = NULL; + g_object_get(current_track, "parsed-name", &track_name, "artist-uuid", &artist_uuid, "album-uuid", &album_uuid, NULL); - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); - KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); + KotoIndexedAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); + g_free(artist_uuid); g_free(album_uuid); @@ -488,7 +624,7 @@ void koto_playerbar_update_track_info(KotoPlaybackEngine *engine, gpointer user_ } if (KOTO_IS_INDEXED_ARTIST(artist)) { - gchar *artist_name = NULL; + gchar * artist_name = NULL; g_object_get(artist, "name", &artist_name, NULL); if ((artist_name != NULL) && (strcmp(artist_name, "") != 0)) { // Have an artist name @@ -500,8 +636,8 @@ void koto_playerbar_update_track_info(KotoPlaybackEngine *engine, gpointer user_ } if (KOTO_IS_INDEXED_ALBUM(album)) { - gchar *album_name = NULL; - gchar *art_path = NULL; + 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 @@ -519,6 +655,6 @@ void koto_playerbar_update_track_info(KotoPlaybackEngine *engine, gpointer user_ } } -GtkWidget* koto_playerbar_get_main(KotoPlayerBar* bar) { +GtkWidget * koto_playerbar_get_main(KotoPlayerBar* bar) { return bar->main; } diff --git a/src/koto-playerbar.h b/src/koto-playerbar.h index 11fc947..465e867 100644 --- a/src/koto-playerbar.h +++ b/src/koto-playerbar.h @@ -23,35 +23,147 @@ G_BEGIN_DECLS #define KOTO_TYPE_PLAYERBAR (koto_playerbar_get_type()) -G_DECLARE_FINAL_TYPE (KotoPlayerBar, koto_playerbar, KOTO, PLAYERBAR, GObject) +G_DECLARE_FINAL_TYPE(KotoPlayerBar, koto_playerbar, KOTO, PLAYERBAR, GObject) #define KOTO_IS_PLAYERBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_PLAYERBAR)) -KotoPlayerBar* koto_playerbar_new (void); -GtkWidget* koto_playerbar_get_main(KotoPlayerBar* bar); +KotoPlayerBar * koto_playerbar_new(void); +GtkWidget * koto_playerbar_get_main(KotoPlayerBar* bar); + void koto_playerbar_create_playback_details(KotoPlayerBar* bar); + void koto_playerbar_create_primary_controls(KotoPlayerBar* bar); + void koto_playerbar_create_secondary_controls(KotoPlayerBar* bar); -void koto_playerbar_go_backwards(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_go_forwards(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_handle_is_playing(KotoPlaybackEngine *engine, gpointer user_data); -void koto_playerbar_handle_is_paused(KotoPlaybackEngine *engine, gpointer user_data); -void koto_playerbar_handle_playlist_button_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_handle_progressbar_scroll_begin(GtkEventControllerScroll *controller, gpointer data); -void koto_playerbar_handle_progressbar_gesture_begin(GtkGesture *gesture, GdkEventSequence *seq, gpointer data); -void koto_playerbar_handle_progressbar_gesture_end(GtkGesture *gesture, GdkEventSequence *seq, gpointer data); -void koto_playerbar_handle_progressbar_pressed(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_handle_progressbar_value_changed(GtkRange *progress_bar, gpointer data); -void koto_playerbar_handle_tick_duration(KotoPlaybackEngine *engine, gpointer user_data); -void koto_playerbar_handle_tick_track(KotoPlaybackEngine *engine, gpointer user_data); -void koto_playerbar_handle_track_repeat(KotoPlaybackEngine *engine, gpointer user_data); -void koto_playerbar_handle_track_shuffle(KotoPlaybackEngine *engine, gpointer user_data); -void koto_playerbar_handle_volume_button_change(GtkScaleButton *button, double value, gpointer user_data); + +void koto_playerbar_go_backwards( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_go_forwards( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_handle_is_playing( + KotoPlaybackEngine * engine, + gpointer user_data +); + +void koto_playerbar_handle_is_paused( + KotoPlaybackEngine * engine, + gpointer user_data +); + +void koto_playerbar_handle_playlist_button_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_handle_progressbar_scroll_begin( + GtkEventControllerScroll * controller, + gpointer data +); + +void koto_playerbar_handle_progressbar_gesture_begin( + GtkGesture * gesture, + GdkEventSequence * seq, + gpointer data +); + +void koto_playerbar_handle_progressbar_gesture_end( + GtkGesture * gesture, + GdkEventSequence * seq, + gpointer data +); + +void koto_playerbar_handle_progressbar_pressed( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_handle_progressbar_value_changed( + GtkRange * progress_bar, + gpointer data +); + +void koto_playerbar_handle_tick_duration( + KotoPlaybackEngine * engine, + gpointer user_data +); + +void koto_playerbar_handle_tick_track( + KotoPlaybackEngine * engine, + gpointer user_data +); + +void koto_playerbar_handle_track_repeat( + KotoPlaybackEngine * engine, + gpointer user_data +); + +void koto_playerbar_handle_track_shuffle( + KotoPlaybackEngine * engine, + gpointer user_data +); + +void koto_playerbar_handle_volume_button_change( + GtkScaleButton * button, + double value, + gpointer user_data +); + void koto_playerbar_reset_progressbar(KotoPlayerBar* bar); -void koto_playerbar_set_progressbar_duration(KotoPlayerBar* bar, gint64 duration); -void koto_playerbar_set_progressbar_value(KotoPlayerBar* bar, gdouble progress); -void koto_playerbar_toggle_play_pause(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_toggle_playlist_shuffle(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_toggle_track_repeat(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -void koto_playerbar_update_track_info(KotoPlaybackEngine *engine, gpointer user_data); + +void koto_playerbar_set_progressbar_duration( + KotoPlayerBar* bar, + gint64 duration +); + +void koto_playerbar_set_progressbar_value( + KotoPlayerBar* bar, + gdouble progress +); + +void koto_playerbar_toggle_play_pause( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_toggle_playlist_shuffle( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_toggle_track_repeat( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +void koto_playerbar_update_track_info( + KotoPlaybackEngine * engine, + gpointer user_data +); G_END_DECLS diff --git a/src/koto-track-item.c b/src/koto-track-item.c index 98874cc..96b7bf4 100644 --- a/src/koto-track-item.c +++ b/src/koto-track-item.c @@ -21,13 +21,13 @@ #include "koto-button.h" #include "koto-track-item.h" -extern KotoAddRemoveTrackPopover *koto_add_remove_track_popup; +extern KotoAddRemoveTrackPopover * koto_add_remove_track_popup; struct _KotoTrackItem { GtkBox parent_instance; - KotoIndexedTrack *track; + KotoIndexedTrack * track; - GtkWidget *track_label; + GtkWidget * track_label; }; struct _KotoTrackItemClass { @@ -40,15 +40,30 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; G_DEFINE_TYPE(KotoTrackItem, koto_track_item, GTK_TYPE_BOX); -static void koto_track_item_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_track_item_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static void koto_track_item_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_track_item_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_track_item_class_init(KotoTrackItemClass * c) { + GObjectClass * gobject_class; + -static void koto_track_item_class_init(KotoTrackItemClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_track_item_set_property; gobject_class->get_property = koto_track_item_get_property; @@ -58,14 +73,20 @@ static void koto_track_item_class_init(KotoTrackItemClass *c) { "Track", "Track", KOTO_TYPE_INDEXED_TRACK, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_track_item_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoTrackItem *self = KOTO_TRACK_ITEM(obj); +static void koto_track_item_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoTrackItem * self = KOTO_TRACK_ITEM(obj); + switch (prop_id) { case PROP_TRACK: @@ -77,8 +98,14 @@ static void koto_track_item_get_property(GObject *obj, guint prop_id, GValue *va } } -static void koto_track_item_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoTrackItem *self = KOTO_TRACK_ITEM(obj); +static void koto_track_item_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoTrackItem * self = KOTO_TRACK_ITEM(obj); + switch (prop_id) { case PROP_TRACK: @@ -90,7 +117,7 @@ static void koto_track_item_set_property(GObject *obj, guint prop_id, const GVal } } -static void koto_track_item_init(KotoTrackItem *self) { +static void koto_track_item_init(KotoTrackItem * self) { self->track_label = gtk_label_new(NULL); // Create with no track name gtk_label_set_xalign(GTK_LABEL(self->track_label), 0.0); @@ -101,23 +128,29 @@ static void koto_track_item_init(KotoTrackItem *self) { gtk_box_prepend(GTK_BOX(self), self->track_label); } -KotoIndexedTrack* koto_track_item_get_track(KotoTrackItem *self) { +KotoIndexedTrack * koto_track_item_get_track(KotoTrackItem * self) { return self->track; } -void koto_track_item_set_track(KotoTrackItem *self, KotoIndexedTrack *track) { +void koto_track_item_set_track( + KotoTrackItem * self, + KotoIndexedTrack * track +) { if (track == NULL) { // Not a track return; } self->track = track; - gchar *track_name; + gchar * track_name; + + g_object_get(self->track, "parsed-name", &track_name, NULL); gtk_label_set_text(GTK_LABEL(self->track_label), track_name); // Update the text } -KotoTrackItem* koto_track_item_new(KotoIndexedTrack *track) { - return g_object_new(KOTO_TYPE_TRACK_ITEM, +KotoTrackItem * koto_track_item_new(KotoIndexedTrack * track) { + return g_object_new( + KOTO_TYPE_TRACK_ITEM, "track", track, NULL diff --git a/src/koto-track-item.h b/src/koto-track-item.h index 0c9a54f..2152116 100644 --- a/src/koto-track-item.h +++ b/src/koto-track-item.h @@ -27,9 +27,20 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(KotoTrackItem, koto_track_item, KOTO, TRACK_ITEM, GtkBox) -KotoTrackItem* koto_track_item_new(KotoIndexedTrack *track); -void koto_track_item_handle_add_to_playlist_button_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -KotoIndexedTrack* koto_track_item_get_track(KotoTrackItem *self); -void koto_track_item_set_track(KotoTrackItem *self, KotoIndexedTrack *track); +KotoTrackItem* koto_track_item_new(KotoIndexedTrack * track); +void koto_track_item_handle_add_to_playlist_button_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +KotoIndexedTrack * koto_track_item_get_track(KotoTrackItem * self); + +void koto_track_item_set_track( + KotoTrackItem * self, + KotoIndexedTrack * track +); G_END_DECLS diff --git a/src/koto-utils.c b/src/koto-utils.c index 89953f7..6ff15f5 100644 --- a/src/koto-utils.c +++ b/src/koto-utils.c @@ -18,10 +18,10 @@ #include #include -extern GtkWindow *main_window; +extern GtkWindow * main_window; -GtkFileChooserNative* koto_utils_create_image_file_chooser(gchar *file_chooser_label) { - GtkFileChooserNative* chooser = gtk_file_chooser_native_new( +GtkFileChooserNative * koto_utils_create_image_file_chooser(gchar * file_chooser_label) { + GtkFileChooserNative* chooser = gtk_file_chooser_native_new( file_chooser_label, main_window, GTK_FILE_CHOOSER_ACTION_OPEN, @@ -29,7 +29,9 @@ GtkFileChooserNative* koto_utils_create_image_file_chooser(gchar *file_chooser_l "Cancel" ); - GtkFileFilter *image_filter = gtk_file_filter_new(); // Create our file filter + GtkFileFilter * image_filter = gtk_file_filter_new(); // Create our file filter + + gtk_file_filter_add_mime_type(image_filter, "image/*"); // Only allow for images gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(chooser), image_filter); // Only allow picking images gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), FALSE); @@ -37,9 +39,15 @@ GtkFileChooserNative* koto_utils_create_image_file_chooser(gchar *file_chooser_l return chooser; } -GtkWidget* koto_utils_create_image_from_filepath(gchar *filepath, gchar *fallback_icon, guint width, guint height) { +GtkWidget * koto_utils_create_image_from_filepath( + gchar * filepath, + gchar * fallback_icon, + guint width, + guint height +) { GtkWidget* image = NULL; + if ((filepath != NULL) && (strcmp(filepath, "") != 0)) { // If we have a filepath if (g_file_test(filepath, G_FILE_TEST_EXISTS)) { // File exists image = gtk_image_new_from_file(filepath); // Load from the filepath @@ -57,21 +65,24 @@ GtkWidget* koto_utils_create_image_from_filepath(gchar *filepath, gchar *fallbac return image; } -gchar* koto_utils_get_filename_without_extension(gchar *filename) { - gchar *trimmed_file_name = g_strdup(filename); - gchar **split = g_strsplit(filename, ".", -1); // Split every time we see . +gchar * koto_utils_get_filename_without_extension(gchar * filename) { + gchar * trimmed_file_name = g_strdup(filename); + gchar ** split = g_strsplit(filename, ".", -1); // Split every time we see . + + g_free(trimmed_file_name); guint len_of_extension_split = g_strv_length(split); + if (len_of_extension_split == 2) { // Only have two elements trimmed_file_name = g_strdup(split[0]); // Get the first element } else { - gchar *new_parsed_name = ""; + gchar * new_parsed_name = ""; for (guint i = 0; i < len_of_extension_split - 1; i++) { // Iterate over everything except the last item if (g_strcmp0(new_parsed_name, "") == 0) { // Currently empty new_parsed_name = g_strdup(split[i]); // Just duplicate this string } else { - gchar *tmp_copy = g_strdup(new_parsed_name); + gchar * tmp_copy = g_strdup(new_parsed_name); g_free(new_parsed_name); // Free the old new_parsed_name = g_strjoin(".", tmp_copy, split[i], NULL); // Join the two strings with a . again and duplicate it, setting it to our new_parsed_name g_free(tmp_copy); // Free our temporary copy @@ -82,22 +93,32 @@ gchar* koto_utils_get_filename_without_extension(gchar *filename) { g_free(new_parsed_name); } - gchar *stripped_file_name = g_strstrip(g_strdup(trimmed_file_name)); // Strip leading and trailing whitespace + gchar * stripped_file_name = g_strstrip(g_strdup(trimmed_file_name)); // Strip leading and trailing whitespace + + g_free(trimmed_file_name); return stripped_file_name; } -gboolean koto_utils_is_string_valid(gchar *str) { +gboolean koto_utils_is_string_valid(gchar * str) { return ((str != NULL) && (g_strcmp0(str, "") != 0)); } -void koto_utils_push_queue_element_to_store(gpointer data, gpointer user_data) { +void koto_utils_push_queue_element_to_store( + gpointer data, + gpointer user_data +) { g_list_store_append(G_LIST_STORE(user_data), data); } -gchar* koto_utils_replace_string_all(gchar *str, gchar *find, gchar *repl) { - gchar *cleaned_string = ""; - gchar **split = g_strsplit(str, find, -1); // Split on find +gchar * koto_utils_replace_string_all( + gchar * str, + gchar * find, + gchar * repl +) { + gchar * cleaned_string = ""; + gchar ** split = g_strsplit(str, find, -1); // Split on find + for (guint i = 0; i < g_strv_length(split); i++) { // For each split cleaned_string = g_strjoin(repl, cleaned_string, split[i], NULL); // Join the strings with our replace string @@ -107,16 +128,19 @@ gchar* koto_utils_replace_string_all(gchar *str, gchar *find, gchar *repl) { return cleaned_string; } -gchar* koto_utils_unquote_string(gchar *s) { - gchar *new_s = NULL; +gchar * koto_utils_unquote_string(gchar * s) { + gchar * new_s = NULL; + if (g_str_has_prefix(s, "'") && g_str_has_suffix(s, "'")) { // Begins and ends with ' - new_s = g_utf8_substring(s, 1, g_utf8_strlen(s, -1)-1); // Start at 1 and end at n-1 + new_s = g_utf8_substring(s, 1, g_utf8_strlen(s, -1) - 1); // Start at 1 and end at n-1 } else { new_s = g_strdup(s); } - gchar **split_on_double_single = g_strsplit(new_s, "''", -1); // Split on instances of '' + gchar ** split_on_double_single = g_strsplit(new_s, "''", -1); // Split on instances of '' + + new_s = g_strjoinv("'", split_on_double_single); // Rejoin as ' g_strfreev(split_on_double_single); // Free our array diff --git a/src/koto-utils.h b/src/koto-utils.h index 21ecf77..1bc3a3e 100644 --- a/src/koto-utils.h +++ b/src/koto-utils.h @@ -21,12 +21,30 @@ G_BEGIN_DECLS -GtkFileChooserNative* koto_utils_create_image_file_chooser(gchar *file_chooser_label); -GtkWidget* koto_utils_create_image_from_filepath(gchar *filepath, gchar *fallback_icon, guint width, guint height); -gchar* koto_utils_get_filename_without_extension(gchar *filename); -gboolean koto_utils_is_string_valid(gchar *str); -void koto_utils_push_queue_element_to_store(gpointer data, gpointer user_data); -gchar *koto_utils_replace_string_all(gchar *str, gchar *find, gchar *repl); -gchar* koto_utils_unquote_string(gchar *s); +GtkFileChooserNative * koto_utils_create_image_file_chooser(gchar * file_chooser_label); + +GtkWidget * koto_utils_create_image_from_filepath( + gchar * filepath, + gchar * fallback_icon, + guint width, + guint height +); + +gchar * koto_utils_get_filename_without_extension(gchar * filename); + +gboolean koto_utils_is_string_valid(gchar * str); + +void koto_utils_push_queue_element_to_store( + gpointer data, + gpointer user_data +); + +gchar * koto_utils_replace_string_all( + gchar * str, + gchar * find, + gchar * repl +); + +gchar * koto_utils_unquote_string(gchar * s); G_END_DECLS diff --git a/src/koto-window.c b/src/koto-window.c index bca8166..9c5ccf6 100644 --- a/src/koto-window.c +++ b/src/koto-window.c @@ -31,45 +31,47 @@ #include "koto-playerbar.h" #include "koto-window.h" -extern KotoActionBar *action_bar; -extern KotoAddRemoveTrackPopover *koto_add_remove_track_popup; -extern KotoCartographer *koto_maps; -extern KotoCreateModifyPlaylistDialog *playlist_create_modify_dialog; -extern KotoCurrentPlaylist *current_playlist; -extern KotoPageMusicLocal *music_local_page; -extern KotoPlaybackEngine *playback_engine; +extern KotoActionBar * action_bar; +extern KotoAddRemoveTrackPopover * koto_add_remove_track_popup; +extern KotoCartographer * koto_maps; +extern KotoCreateModifyPlaylistDialog * playlist_create_modify_dialog; +extern KotoCurrentPlaylist * current_playlist; +extern KotoPageMusicLocal * music_local_page; +extern KotoPlaybackEngine * playback_engine; struct _KotoWindow { - GtkApplicationWindow parent_instance; - KotoIndexedLibrary *library; - KotoCurrentPlaylist *current_playlist; + GtkApplicationWindow parent_instance; + KotoIndexedLibrary * library; + KotoCurrentPlaylist * current_playlist; - KotoDialogContainer *dialogs; + KotoDialogContainer * dialogs; - GtkWidget *overlay; - GtkWidget *header_bar; - GtkWidget *menu_button; - GtkWidget *search_entry; + GtkWidget * overlay; + GtkWidget * header_bar; + GtkWidget * menu_button; + GtkWidget * search_entry; - GtkWidget *primary_layout; - GtkWidget *content_layout; + GtkWidget * primary_layout; + GtkWidget * content_layout; - KotoNav *nav; - GtkWidget *pages; - KotoPlayerBar *player_bar; + KotoNav * nav; + GtkWidget * pages; + KotoPlayerBar * player_bar; }; -G_DEFINE_TYPE (KotoWindow, koto_window, GTK_TYPE_APPLICATION_WINDOW) +G_DEFINE_TYPE(KotoWindow, koto_window, GTK_TYPE_APPLICATION_WINDOW) -static void koto_window_class_init (KotoWindowClass *klass) { - (void)klass; +static void koto_window_class_init (KotoWindowClass * klass) { + (void) klass; } -static void koto_window_init (KotoWindow *self) { +static void koto_window_init (KotoWindow * self) { current_playlist = koto_current_playlist_new(); playback_engine = koto_playback_engine_new(); GtkCssProvider* provider = gtk_css_provider_new(); + + gtk_css_provider_load_from_resource(provider, "/com/github/joshstrobl/koto/style.css"); gtk_style_context_add_provider_for_display(gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); @@ -115,7 +117,7 @@ static void koto_window_init (KotoWindow *self) { action_bar = koto_action_bar_new(); // Create our Koto Action Bar if (KOTO_IS_ACTION_BAR(action_bar)) { // Is an action bar - GtkActionBar *bar = koto_action_bar_get_main(action_bar); + GtkActionBar * bar = koto_action_bar_get_main(action_bar); if (GTK_IS_ACTION_BAR(bar)) { gtk_box_append(GTK_BOX(self->primary_layout), GTK_WIDGET(bar)); // Add the action @@ -125,7 +127,7 @@ static void koto_window_init (KotoWindow *self) { self->player_bar = koto_playerbar_new(); if (KOTO_IS_PLAYERBAR(self->player_bar)) { // Is a playerbar - GtkWidget *playerbar_main = koto_playerbar_get_main(self->player_bar); + GtkWidget * playerbar_main = koto_playerbar_get_main(self->player_bar); gtk_box_append(GTK_BOX(self->primary_layout), playerbar_main); } @@ -141,45 +143,65 @@ static void koto_window_init (KotoWindow *self) { g_thread_new("load-library", (void*) load_library, self); } -void koto_window_add_page(KotoWindow *self, gchar *page_name, GtkWidget *page) { +void koto_window_add_page( + KotoWindow * self, + gchar * page_name, + GtkWidget * page +) { gtk_stack_add_named(GTK_STACK(self->pages), page, page_name); } -void koto_window_go_to_page(KotoWindow *self, gchar *page_name) { +void koto_window_go_to_page( + KotoWindow * self, + gchar * page_name +) { gtk_stack_set_visible_child_name(GTK_STACK(self->pages), page_name); } -void koto_window_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playlist, gpointer user_data) { +void koto_window_handle_playlist_added( + KotoCartographer * carto, + KotoPlaylist * playlist, + gpointer user_data +) { (void) carto; if (!KOTO_IS_PLAYLIST(playlist)) { return; } - KotoWindow *self = user_data; + KotoWindow * self = user_data; + + gchar * playlist_uuid = koto_playlist_get_uuid(playlist); + KotoPlaylistPage * playlist_page = koto_playlist_page_new(playlist_uuid); // Create our new Playlist Page + - gchar *playlist_uuid = koto_playlist_get_uuid(playlist); - KotoPlaylistPage *playlist_page = koto_playlist_page_new(playlist_uuid); // Create our new Playlist Page koto_window_add_page(self, playlist_uuid, koto_playlist_page_get_main(playlist_page)); // Get the GtkScrolledWindow "main" content of the playlist page and add that as a page to our stack by the playlist UUID } -void koto_window_hide_dialogs(KotoWindow *self) { +void koto_window_hide_dialogs(KotoWindow * self) { koto_dialog_container_hide(self->dialogs); // Hide the dialog container } -void koto_window_remove_page(KotoWindow *self, gchar *page_name) { - GtkWidget *page = gtk_stack_get_child_by_name(GTK_STACK(self->pages), page_name); +void koto_window_remove_page( + KotoWindow * self, + gchar * page_name +) { + GtkWidget * page = gtk_stack_get_child_by_name(GTK_STACK(self->pages), page_name); + if (GTK_IS_WIDGET(page)) { gtk_stack_remove(GTK_STACK(self->pages), page); } } -void koto_window_show_dialog(KotoWindow *self, gchar *dialog_name) { +void koto_window_show_dialog( + KotoWindow * self, + gchar * dialog_name +) { koto_dialog_container_show_dialog(self->dialogs, dialog_name); } -void create_new_headerbar(KotoWindow *self) { +void create_new_headerbar(KotoWindow * self) { self->header_bar = gtk_header_bar_new(); gtk_widget_add_css_class(self->header_bar, "hdr"); g_return_if_fail(GTK_IS_HEADER_BAR(self->header_bar)); @@ -199,8 +221,9 @@ void create_new_headerbar(KotoWindow *self) { gtk_window_set_titlebar(GTK_WINDOW(self), self->header_bar); } -void load_library(KotoWindow *self) { - KotoIndexedLibrary *lib = koto_indexed_library_new(g_get_user_special_dir(G_USER_DIRECTORY_MUSIC)); +void load_library(KotoWindow * self) { + KotoIndexedLibrary * lib = koto_indexed_library_new(g_get_user_special_dir(G_USER_DIRECTORY_MUSIC)); + if (lib != NULL) { self->library = lib; @@ -216,20 +239,26 @@ void load_library(KotoWindow *self) { g_thread_exit(0); } -void set_optimal_default_window_size(KotoWindow *self) { - GdkDisplay *default_display = gdk_display_get_default(); +void set_optimal_default_window_size(KotoWindow * self) { + GdkDisplay * default_display = gdk_display_get_default(); + if (!GDK_IS_X11_DISPLAY(default_display)) { // Not an X11 display return; } - GdkMonitor *default_monitor = gdk_x11_display_get_primary_monitor(GDK_X11_DISPLAY(default_display)); // Get primary monitor for the X11 + GdkMonitor * default_monitor = gdk_x11_display_get_primary_monitor(GDK_X11_DISPLAY(default_display)); // Get primary monitor for the X11 + if (!GDK_IS_X11_MONITOR(default_monitor)) { // Not an X11 Monitor return; } - GdkRectangle workarea = {0}; + GdkRectangle workarea = { + 0 + }; + + gdk_monitor_get_geometry(default_monitor, &workarea); if (workarea.width <= 1280) { // Honestly how do you even get anything done? diff --git a/src/koto-window.h b/src/koto-window.h index aab9609..7043fc5 100644 --- a/src/koto-window.h +++ b/src/koto-window.h @@ -25,18 +25,43 @@ G_BEGIN_DECLS #define KOTO_TYPE_WINDOW (koto_window_get_type()) -G_DECLARE_FINAL_TYPE (KotoWindow, koto_window, KOTO, WINDOW, GtkApplicationWindow) +G_DECLARE_FINAL_TYPE(KotoWindow, koto_window, KOTO, WINDOW, GtkApplicationWindow) -void koto_window_add_page(KotoWindow *self, gchar *page_name, GtkWidget *page); -void koto_window_go_to_page(KotoWindow *self, gchar *page_name); -void koto_window_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playlist, gpointer user_data); -void koto_window_hide_dialogs(KotoWindow *self); -void koto_window_remove_page(KotoWindow *self, gchar *page_name); -void koto_window_show_dialog(KotoWindow *self, gchar *dialog_name); +void koto_window_add_page( + KotoWindow * self, + gchar * page_name, + GtkWidget * page +); + +void koto_window_go_to_page( + KotoWindow * self, + gchar * page_name +); + +void koto_window_handle_playlist_added( + KotoCartographer * carto, + KotoPlaylist * playlist, + gpointer user_data +); + +void koto_window_hide_dialogs(KotoWindow * self); + +void koto_window_remove_page( + KotoWindow * self, + gchar * page_name +); + +void koto_window_show_dialog( + KotoWindow * self, + gchar * dialog_name +); + +void create_new_headerbar(KotoWindow * self); -void create_new_headerbar(KotoWindow *self); void handle_album_added(); -void load_library(KotoWindow *self); -void set_optimal_default_window_size(KotoWindow *self); + +void load_library(KotoWindow * self); + +void set_optimal_default_window_size(KotoWindow * self); G_END_DECLS diff --git a/src/main.c b/src/main.c index f6f28ba..687ec62 100644 --- a/src/main.c +++ b/src/main.c @@ -27,23 +27,23 @@ #include "koto-window.h" extern guint mpris_bus_id; -extern GDBusNodeInfo *introspection_data; +extern GDBusNodeInfo * introspection_data; -extern KotoCartographer *koto_maps; -extern sqlite3 *koto_db; +extern KotoCartographer * koto_maps; +extern sqlite3 * koto_db; -extern GHashTable *supported_mimes_hash; -extern GList *supported_mimes; +extern GHashTable * supported_mimes_hash; +extern GList * supported_mimes; -GtkApplication *app = NULL; -GtkWindow *main_window; +GtkApplication * app = NULL; +GtkWindow * main_window; -static void on_activate (GtkApplication *app) { - g_assert(GTK_IS_APPLICATION (app)); +static void on_activate (GtkApplication * app) { + g_assert(GTK_IS_APPLICATION(app)); - main_window = gtk_application_get_active_window (app); + main_window = gtk_application_get_active_window(app); if (main_window == NULL) { - main_window = g_object_new(KOTO_TYPE_WINDOW, "application", app, "default-width", 1200, "default-height", 675, NULL); + main_window = g_object_new(KOTO_TYPE_WINDOW, "application", app, "default-width", 1200, "default-height", 675, NULL); setup_mpris_interfaces(); // Set up our MPRIS interfaces setup_mediakeys_interface(); // Set up our media key support } @@ -51,20 +51,24 @@ static void on_activate (GtkApplication *app) { gtk_window_present(main_window); } -static void on_shutdown(GtkApplication *app) { +static void on_shutdown(GtkApplication * app) { (void) app; close_db(); // Close the database g_bus_unown_name(mpris_bus_id); g_dbus_node_info_unref(introspection_data); } -int main (int argc, char *argv[]) { +int main ( + int argc, + char * argv[] +) { int ret; + /* Set up gettext translations */ - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); gtk_init(); gst_init(&argc, &argv); @@ -76,10 +80,10 @@ int main (int argc, char *argv[]) { koto_maps = koto_cartographer_new(); // Create our new cartographer and their collection of maps open_db(); // Open our database - app = gtk_application_new ("com.github.joshstrobl.koto", G_APPLICATION_FLAGS_NONE); - g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); + app = gtk_application_new("com.github.joshstrobl.koto", G_APPLICATION_FLAGS_NONE); + g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL); g_signal_connect(app, "shutdown", G_CALLBACK(on_shutdown), NULL); - ret = g_application_run (G_APPLICATION (app), argc, argv); + ret = g_application_run(G_APPLICATION(app), argc, argv); return ret; } diff --git a/src/pages/music/album-view.c b/src/pages/music/album-view.c index d3d5e22..40b95fa 100644 --- a/src/pages/music/album-view.c +++ b/src/pages/music/album-view.c @@ -25,23 +25,23 @@ #include "koto-config.h" #include "koto-utils.h" -extern KotoCartographer *koto_maps; +extern KotoCartographer * koto_maps; struct _KotoAlbumView { GObject parent_instance; - KotoIndexedAlbum *album; - GtkWidget *main; - GtkWidget *album_tracks_box; - GtkWidget *discs; + KotoIndexedAlbum * album; + GtkWidget * main; + GtkWidget * album_tracks_box; + GtkWidget * discs; - GtkWidget *album_overlay_art; - GtkWidget *album_overlay_container; - GtkWidget *album_overlay_controls; - GtkWidget *album_overlay_revealer; - KotoButton *play_pause_button; + GtkWidget * album_overlay_art; + GtkWidget * album_overlay_container; + GtkWidget * album_overlay_controls; + GtkWidget * album_overlay_revealer; + KotoButton * play_pause_button; - GtkWidget *album_label; - GHashTable *cd_to_track_listbox; + GtkWidget * album_label; + GHashTable * cd_to_track_listbox; }; G_DEFINE_TYPE(KotoAlbumView, koto_album_view, G_TYPE_OBJECT); @@ -52,12 +52,27 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; -static void koto_album_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_album_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; +static void koto_album_view_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_album_view_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_album_view_class_init(KotoAlbumViewClass * c) { + GObjectClass * gobject_class; + -static void koto_album_view_class_init(KotoAlbumViewClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_album_view_set_property; gobject_class->get_property = koto_album_view_get_property; @@ -67,13 +82,13 @@ static void koto_album_view_class_init(KotoAlbumViewClass *c) { "Album", "Album", KOTO_TYPE_INDEXED_ALBUM, - G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_album_view_init(KotoAlbumView *self) { +static void koto_album_view_init(KotoAlbumView * self) { self->cd_to_track_listbox = g_hash_table_new(g_str_hash, g_str_equal); self->main = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_add_css_class(self->main, "album-view"); @@ -113,7 +128,9 @@ static void koto_album_view_init(KotoAlbumView *self) { gtk_overlay_add_overlay(GTK_OVERLAY(self->album_overlay_container), self->album_overlay_revealer); // Add our revealer as the overlay gtk_box_prepend(GTK_BOX(self->main), self->album_overlay_container); // Add our album overlay container - GtkEventController *motion_controller = gtk_event_controller_motion_new(); // Create our new motion event controller to track mouse leave and enter + GtkEventController * motion_controller = gtk_event_controller_motion_new(); // Create our new motion event controller to track mouse leave and enter + + g_signal_connect(motion_controller, "enter", G_CALLBACK(koto_album_view_show_overlay_controls), self); g_signal_connect(motion_controller, "leave", G_CALLBACK(koto_album_view_hide_overlay_controls), self); gtk_widget_add_controller(self->album_overlay_container, motion_controller); @@ -121,12 +138,18 @@ static void koto_album_view_init(KotoAlbumView *self) { koto_button_add_click_handler(self->play_pause_button, KOTO_BUTTON_CLICK_TYPE_PRIMARY, G_CALLBACK(koto_album_view_toggle_album_playback), self); } -GtkWidget* koto_album_view_get_main(KotoAlbumView *self) { +GtkWidget * koto_album_view_get_main(KotoAlbumView * self) { return self->main; } -static void koto_album_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoAlbumView *self = KOTO_ALBUM_VIEW(obj); +static void koto_album_view_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoAlbumView * self = KOTO_ALBUM_VIEW(obj); + switch (prop_id) { case PROP_ALBUM: @@ -138,8 +161,14 @@ static void koto_album_view_get_property(GObject *obj, guint prop_id, GValue *va } } -static void koto_album_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoAlbumView *self = KOTO_ALBUM_VIEW(obj); +static void koto_album_view_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoAlbumView * self = KOTO_ALBUM_VIEW(obj); + switch (prop_id) { case PROP_ALBUM: @@ -151,58 +180,75 @@ static void koto_album_view_set_property(GObject *obj, guint prop_id, const GVal } } -void koto_album_view_add_track_to_listbox(KotoIndexedAlbum *self, KotoIndexedTrack *track) { - (void) self; (void) track; +void koto_album_view_add_track_to_listbox( + KotoIndexedAlbum * self, + KotoIndexedTrack * track +) { + (void) self; + (void) track; } -void koto_album_view_hide_overlay_controls(GtkEventControllerFocus *controller, gpointer data) { +void koto_album_view_hide_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +) { (void) controller; KotoAlbumView* self = data; + + gtk_revealer_set_reveal_child(GTK_REVEALER(self->album_overlay_revealer), FALSE); } -void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album) { +void koto_album_view_set_album( + KotoAlbumView * self, + KotoIndexedAlbum * album +) { if (album == NULL) { return; } self->album = album; - gchar *album_art = koto_indexed_album_get_album_art(self->album); // Get the art for the album + gchar * album_art = koto_indexed_album_get_album_art(self->album); // Get the art for the album + + gtk_image_set_from_file(GTK_IMAGE(self->album_overlay_art), album_art); - gchar *album_name; + gchar * album_name; + + g_object_get(album, "name", &album_name, NULL); // Get the album name self->album_label = gtk_label_new(album_name); gtk_widget_set_halign(self->album_label, GTK_ALIGN_START); gtk_box_prepend(GTK_BOX(self->album_tracks_box), self->album_label); // Prepend our new label to the album + tracks box - GHashTable *discs = g_hash_table_new(g_str_hash, g_str_equal); - GList *tracks = koto_indexed_album_get_tracks(album); // Get the tracks for this album + GHashTable * discs = g_hash_table_new(g_str_hash, g_str_equal); + GList * tracks = koto_indexed_album_get_tracks(album); // Get the tracks for this album + for (guint i = 0; i < g_list_length(tracks); i++) { - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) g_list_nth_data(tracks, i)); // Get the track by its UUID + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) g_list_nth_data(tracks, i)); // Get the track by its UUID if (track == NULL) { // Track doesn't exist continue; } - guint *disc_number; + guint * disc_number; g_object_get(track, "cd", &disc_number, NULL); - gchar *disc_num_as_str = g_strdup_printf("%u", GPOINTER_TO_UINT(disc_number)); + gchar * disc_num_as_str = g_strdup_printf("%u", GPOINTER_TO_UINT(disc_number)); if (g_hash_table_contains(discs, disc_num_as_str)) { // Already have this added continue; // Skip } g_hash_table_insert(discs, disc_num_as_str, "0"); // Mark this disc number in the hash table - KotoDiscView *disc_view = koto_disc_view_new(album, disc_number); + KotoDiscView * disc_view = koto_disc_view_new(album, disc_number); gtk_list_box_append(GTK_LIST_BOX(self->discs), GTK_WIDGET(disc_view)); // Add the Disc View to the List Box } if (g_list_length(g_hash_table_get_keys(discs)) == 1) { // Only have one album - GtkListBoxRow *row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(self->discs), 0); // Get the first item + GtkListBoxRow * row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(self->discs), 0); // Get the first item if (GTK_IS_LIST_BOX_ROW(row)) { // Is a row koto_disc_view_set_disc_label_visible((KotoDiscView*) gtk_list_box_row_get_child(row), FALSE); // Get @@ -212,21 +258,30 @@ void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album) { g_hash_table_destroy(discs); } -void koto_album_view_show_overlay_controls(GtkEventControllerFocus *controller, gpointer data) { +void koto_album_view_show_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +) { (void) controller; KotoAlbumView* self = data; + gtk_revealer_set_reveal_child(GTK_REVEALER(self->album_overlay_revealer), TRUE); } -int koto_album_view_sort_discs(GtkListBoxRow *disc1, GtkListBoxRow *disc2, gpointer user_data) { +int koto_album_view_sort_discs( + GtkListBoxRow * disc1, + GtkListBoxRow * disc2, + gpointer user_data +) { (void) user_data; - KotoDiscView *disc1_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc1)); - KotoDiscView *disc2_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc2)); + KotoDiscView * disc1_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc1)); + KotoDiscView * disc2_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc2)); guint disc1_num; guint disc2_num; + g_object_get(disc1_item, "disc", &disc1_num, NULL); g_object_get(disc2_item, "disc", &disc2_num, NULL); @@ -239,14 +294,24 @@ int koto_album_view_sort_discs(GtkListBoxRow *disc1, GtkListBoxRow *disc2, gpoin } } -void koto_album_view_toggle_album_playback(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) gesture; (void) n_press; (void) x; (void) y; +void koto_album_view_toggle_album_playback( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; KotoAlbumView* self = data; + koto_button_show_image(KOTO_BUTTON(self->play_pause_button), TRUE); koto_indexed_album_set_as_current_playlist(self->album); // Set as the current playlist } -KotoAlbumView* koto_album_view_new(KotoIndexedAlbum *album) { +KotoAlbumView * koto_album_view_new(KotoIndexedAlbum * album) { return g_object_new(KOTO_TYPE_ALBUM_VIEW, "album", album, NULL); } diff --git a/src/pages/music/album-view.h b/src/pages/music/album-view.h index a7dcbb9..72c8c41 100644 --- a/src/pages/music/album-view.h +++ b/src/pages/music/album-view.h @@ -27,13 +27,41 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(KotoAlbumView, koto_album_view, KOTO, ALBUM_VIEW, GObject) -KotoAlbumView* koto_album_view_new(KotoIndexedAlbum *album); -GtkWidget* koto_album_view_get_main(KotoAlbumView *self); -void koto_album_view_add_track_to_listbox(KotoIndexedAlbum *self, KotoIndexedTrack *track); -void koto_album_view_hide_overlay_controls(GtkEventControllerFocus *controller, gpointer data); -void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album); -void koto_album_view_show_overlay_controls(GtkEventControllerFocus *controller, gpointer data); -void koto_album_view_toggle_album_playback(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); -int koto_album_view_sort_discs(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data); +KotoAlbumView* koto_album_view_new(KotoIndexedAlbum * album); +GtkWidget * koto_album_view_get_main(KotoAlbumView * self); + +void koto_album_view_add_track_to_listbox( + KotoIndexedAlbum * self, + KotoIndexedTrack * track +); + +void koto_album_view_hide_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +); + +void koto_album_view_set_album( + KotoAlbumView * self, + KotoIndexedAlbum * album +); + +void koto_album_view_show_overlay_controls( + GtkEventControllerFocus * controller, + gpointer data +); + +void koto_album_view_toggle_album_playback( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer data +); + +int koto_album_view_sort_discs( + GtkListBoxRow * track1, + GtkListBoxRow * track2, + gpointer user_data +); G_END_DECLS diff --git a/src/pages/music/artist-view.c b/src/pages/music/artist-view.c index 1622dba..a424dcf 100644 --- a/src/pages/music/artist-view.c +++ b/src/pages/music/artist-view.c @@ -24,17 +24,17 @@ #include "koto-config.h" #include "koto-utils.h" -extern KotoCartographer *koto_maps; +extern KotoCartographer * koto_maps; struct _KotoArtistView { GObject parent_instance; - KotoIndexedArtist *artist; - GtkWidget *scrolled_window; - GtkWidget *content; - GtkWidget *favorites_list; - GtkWidget *album_list; + KotoIndexedArtist * artist; + GtkWidget * scrolled_window; + GtkWidget * content; + GtkWidget * favorites_list; + GtkWidget * album_list; - GHashTable *albums_to_component; + GHashTable * albums_to_component; gboolean constructed; }; @@ -47,13 +47,29 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; -static void koto_artist_view_constructed(GObject *obj); -static void koto_artist_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_artist_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; +static void koto_artist_view_constructed(GObject * obj); + +static void koto_artist_view_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_artist_view_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_artist_view_class_init(KotoArtistViewClass * c) { + GObjectClass * gobject_class; + -static void koto_artist_view_class_init(KotoArtistViewClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->constructed = koto_artist_view_constructed; gobject_class->set_property = koto_artist_view_set_property; @@ -64,14 +80,20 @@ static void koto_artist_view_class_init(KotoArtistViewClass *c) { "Artist", "Artist", KOTO_TYPE_INDEXED_ARTIST, - G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_artist_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoArtistView *self = KOTO_ARTIST_VIEW(obj); +static void koto_artist_view_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoArtistView * self = KOTO_ARTIST_VIEW(obj); + switch (prop_id) { case PROP_ARTIST: @@ -83,8 +105,14 @@ static void koto_artist_view_get_property(GObject *obj, guint prop_id, GValue *v } } -static void koto_artist_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoArtistView *self = KOTO_ARTIST_VIEW(obj); +static void koto_artist_view_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoArtistView * self = KOTO_ARTIST_VIEW(obj); + switch (prop_id) { case PROP_ARTIST: @@ -96,13 +124,15 @@ static void koto_artist_view_set_property(GObject *obj, guint prop_id, const GVa } } -static void koto_artist_view_init(KotoArtistView *self) { +static void koto_artist_view_init(KotoArtistView * self) { self->artist = NULL; self->constructed = FALSE; } -static void koto_artist_view_constructed(GObject *obj) { - KotoArtistView *self = KOTO_ARTIST_VIEW(obj); +static void koto_artist_view_constructed(GObject * obj) { + KotoArtistView * self = KOTO_ARTIST_VIEW(obj); + + self->albums_to_component = g_hash_table_new(g_str_hash, g_str_equal); self->scrolled_window = gtk_scrolled_window_new(); // Create our scrolled window self->content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); // Create our content as a GtkBox @@ -132,23 +162,33 @@ static void koto_artist_view_constructed(GObject *obj) { gtk_widget_set_hexpand(GTK_WIDGET(self->favorites_list), TRUE); gtk_widget_set_hexpand(GTK_WIDGET(self->album_list), TRUE); - G_OBJECT_CLASS (koto_artist_view_parent_class)->constructed (obj); + G_OBJECT_CLASS(koto_artist_view_parent_class)->constructed(obj); self->constructed = TRUE; } -void koto_artist_view_add_album(KotoArtistView *self, KotoIndexedAlbum *album) { - gchar *album_art = koto_indexed_album_get_album_art(album); // Get the art for the album +void koto_artist_view_add_album( + KotoArtistView * self, + KotoIndexedAlbum * album +) { + gchar * album_art = koto_indexed_album_get_album_art(album); // Get the art for the album + + GtkWidget * art_image = koto_utils_create_image_from_filepath(album_art, "audio-x-generic-symbolic", 220, 220); + - GtkWidget *art_image = koto_utils_create_image_from_filepath(album_art, "audio-x-generic-symbolic", 220, 220); gtk_widget_set_halign(art_image, GTK_ALIGN_START); // Align to start gtk_flow_box_insert(GTK_FLOW_BOX(self->favorites_list), art_image, -1); // Append the album art KotoAlbumView* album_view = koto_album_view_new(album); // Create our new album view GtkWidget* album_view_main = koto_album_view_get_main(album_view); + + gtk_flow_box_insert(GTK_FLOW_BOX(self->album_list), album_view_main, -1); // Append the album view to the album list } -void koto_artist_view_add_artist(KotoArtistView *self, KotoIndexedArtist *artist) { +void koto_artist_view_add_artist( + KotoArtistView * self, + KotoIndexedArtist * artist +) { if (artist == NULL) { return; } @@ -159,11 +199,13 @@ void koto_artist_view_add_artist(KotoArtistView *self, KotoIndexedArtist *artist return; } - GList *albums = koto_indexed_artist_get_albums(self->artist); // Get the albums + GList * albums = koto_indexed_artist_get_albums(self->artist); // Get the albums + + GList * a; + - GList *a; for (a = albums; a != NULL; a = a->next) { - KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, (gchar*) a->data); + KotoIndexedAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, (gchar*) a->data); if (album != NULL) { koto_artist_view_add_album(self, album); // Add the album @@ -171,10 +213,10 @@ void koto_artist_view_add_artist(KotoArtistView *self, KotoIndexedArtist *artist } } -GtkWidget* koto_artist_view_get_main(KotoArtistView *self) { +GtkWidget * koto_artist_view_get_main(KotoArtistView * self) { return self->scrolled_window; } -KotoArtistView* koto_artist_view_new() { +KotoArtistView * koto_artist_view_new() { return g_object_new(KOTO_TYPE_ARTIST_VIEW, NULL); } diff --git a/src/pages/music/artist-view.h b/src/pages/music/artist-view.h index 800ecea..820351d 100644 --- a/src/pages/music/artist-view.h +++ b/src/pages/music/artist-view.h @@ -25,11 +25,19 @@ G_BEGIN_DECLS #define KOTO_TYPE_ARTIST_VIEW (koto_artist_view_get_type()) -G_DECLARE_FINAL_TYPE (KotoArtistView, koto_artist_view, KOTO, ARTIST_VIEW, GObject) +G_DECLARE_FINAL_TYPE(KotoArtistView, koto_artist_view, KOTO, ARTIST_VIEW, GObject) KotoArtistView* koto_artist_view_new(); -void koto_artist_view_add_album(KotoArtistView *self, KotoIndexedAlbum *album); -void koto_artist_view_add_artist(KotoArtistView *self, KotoIndexedArtist *artist); -GtkWidget* koto_artist_view_get_main(KotoArtistView *self); +void koto_artist_view_add_album( + KotoArtistView * self, + KotoIndexedAlbum * album +); + +void koto_artist_view_add_artist( + KotoArtistView * self, + KotoIndexedArtist * artist +); + +GtkWidget * koto_artist_view_get_main(KotoArtistView * self); G_END_DECLS diff --git a/src/pages/music/disc-view.c b/src/pages/music/disc-view.c index 8c4e97d..eb9dcba 100644 --- a/src/pages/music/disc-view.c +++ b/src/pages/music/disc-view.c @@ -23,17 +23,17 @@ #include "../../koto-utils.h" #include "disc-view.h" -extern KotoActionBar *action_bar; -extern KotoCartographer *koto_maps; +extern KotoActionBar * action_bar; +extern KotoCartographer * koto_maps; struct _KotoDiscView { GtkBox parent_instance; - KotoIndexedAlbum *album; - GtkWidget *header; - GtkWidget *label; - GtkWidget *list; + KotoIndexedAlbum * album; + GtkWidget * header; + GtkWidget * label; + GtkWidget * list; - guint *disc_number; + guint * disc_number; }; G_DEFINE_TYPE(KotoDiscView, koto_disc_view, GTK_TYPE_BOX); @@ -45,12 +45,27 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; -static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; +static void koto_disc_view_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_disc_view_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_disc_view_class_init(KotoDiscViewClass * c) { + GObjectClass * gobject_class; + -static void koto_disc_view_class_init(KotoDiscViewClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_disc_view_set_property; gobject_class->get_property = koto_disc_view_get_property; @@ -62,7 +77,7 @@ static void koto_disc_view_class_init(KotoDiscViewClass *c) { 0, G_MAXUINT16, 1, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ALBUM] = g_param_spec_object( @@ -70,14 +85,20 @@ static void koto_disc_view_class_init(KotoDiscViewClass *c) { "Album", "Album", KOTO_TYPE_INDEXED_ALBUM, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoDiscView *self = KOTO_DISC_VIEW(obj); +static void koto_disc_view_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoDiscView * self = KOTO_DISC_VIEW(obj); + switch (prop_id) { case PROP_DISC: @@ -92,8 +113,14 @@ static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val } } -static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoDiscView *self = KOTO_DISC_VIEW(obj); +static void koto_disc_view_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoDiscView * self = KOTO_DISC_VIEW(obj); + switch (prop_id) { case PROP_DISC: @@ -108,14 +135,16 @@ static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValu } } -static void koto_disc_view_init(KotoDiscView *self) { +static void koto_disc_view_init(KotoDiscView * self) { gtk_widget_add_css_class(GTK_WIDGET(self), "disc-view"); gtk_widget_set_can_focus(GTK_WIDGET(self), FALSE); self->header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_set_hexpand(self->header, TRUE); gtk_widget_set_size_request(self->header, 16, -1); - GtkWidget *ico = gtk_image_new_from_icon_name("drive-optical-symbolic"); + GtkWidget * ico = gtk_image_new_from_icon_name("drive-optical-symbolic"); + + gtk_box_prepend(GTK_BOX(self->header), ico); self->label = gtk_label_new(NULL); // Create an empty label @@ -137,41 +166,55 @@ static void koto_disc_view_init(KotoDiscView *self) { g_signal_connect(self->list, "selected-rows-changed", G_CALLBACK(koto_disc_view_handle_selected_rows_changed), self); } -void koto_disc_view_list_tracks(gpointer data, gpointer selfptr) { - KotoDiscView *self = (KotoDiscView*) selfptr; - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) data); // Get the track by its UUID +void koto_disc_view_list_tracks( + gpointer data, + gpointer selfptr +) { + KotoDiscView * self = (KotoDiscView*) selfptr; + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) data); // Get the track by its UUID + + guint * disc_number; + - guint *disc_number; g_object_get(track, "cd", &disc_number, NULL); // get the disc number if (GPOINTER_TO_UINT(self->disc_number) != GPOINTER_TO_UINT(disc_number)) { // Track does not belong to this CD return; } - KotoTrackItem *track_item = koto_track_item_new(track); // Create our new track item + KotoTrackItem * track_item = koto_track_item_new(track); // Create our new track item + + gtk_list_box_append(GTK_LIST_BOX(self->list), GTK_WIDGET(track_item)); // Add to our tracks list box } -void koto_disc_view_handle_selected_rows_changed(GtkListBox *box, gpointer user_data) { - KotoDiscView *self = user_data; +void koto_disc_view_handle_selected_rows_changed( + GtkListBox * box, + gpointer user_data +) { + KotoDiscView * self = user_data; + + gchar * album_uuid = koto_indexed_album_get_album_uuid(self->album); // Get the UUID - gchar *album_uuid = koto_indexed_album_get_album_uuid(self->album); // Get the UUID if (!koto_utils_is_string_valid(album_uuid)) { // Not set return; } - GList *selected_rows = gtk_list_box_get_selected_rows(box); // Get the selected rows + GList * selected_rows = gtk_list_box_get_selected_rows(box); // Get the selected rows + if (g_list_length(selected_rows) == 0) { // No rows selected koto_action_bar_toggle_reveal(action_bar, FALSE); // Close the action bar return; } - GList *selected_tracks = NULL; // Create our list of KotoIndexedTracks - GList *cur_selected_rows; + GList * selected_tracks = NULL; // Create our list of KotoIndexedTracks + GList * cur_selected_rows; + + for (cur_selected_rows = selected_rows; cur_selected_rows != NULL; cur_selected_rows = cur_selected_rows->next) { // Iterate over the rows - KotoTrackItem *track_item = (KotoTrackItem*) gtk_list_box_row_get_child(cur_selected_rows->data); + KotoTrackItem * track_item = (KotoTrackItem*) gtk_list_box_row_get_child(cur_selected_rows->data); selected_tracks = g_list_append(selected_tracks, koto_track_item_get_track(track_item)); // Add the KotoIndexedTrack to our list } @@ -181,7 +224,10 @@ void koto_disc_view_handle_selected_rows_changed(GtkListBox *box, gpointer user_ koto_action_bar_toggle_reveal(action_bar, TRUE); // Show the action bar } -void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album) { +void koto_disc_view_set_album( + KotoDiscView * self, + KotoIndexedAlbum * album +) { if (album == NULL) { return; } @@ -195,28 +241,43 @@ void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album) { g_list_foreach(koto_indexed_album_get_tracks(self->album), koto_disc_view_list_tracks, self); } -void koto_disc_view_set_disc_number(KotoDiscView *self, guint disc_number) { +void koto_disc_view_set_disc_number( + KotoDiscView * self, + guint disc_number +) { if (disc_number == 0) { return; } self->disc_number = GUINT_TO_POINTER(disc_number); - gchar *disc_label = g_strdup_printf("Disc %u", disc_number); - gtk_label_set_text(GTK_LABEL(self->label), disc_label); // Set the label + gchar * disc_label = g_strdup_printf("Disc %u", disc_number); + + + gtk_label_set_text(GTK_LABEL(self->label), disc_label); // Set the label g_free(disc_label); } -void koto_disc_view_set_disc_label_visible(KotoDiscView *self, gboolean visible) { +void koto_disc_view_set_disc_label_visible( + KotoDiscView * self, + gboolean visible +) { (visible) ? gtk_widget_show(self->header) : gtk_widget_hide(self->header); } -KotoDiscView* koto_disc_view_new(KotoIndexedAlbum *album, guint *disc_number) { - return g_object_new(KOTO_TYPE_DISC_VIEW, - "disc", disc_number, - "album", album, - "orientation", GTK_ORIENTATION_VERTICAL, +KotoDiscView * koto_disc_view_new( + KotoIndexedAlbum * album, + guint * disc_number +) { + return g_object_new( + KOTO_TYPE_DISC_VIEW, + "disc", + disc_number, + "album", + album, + "orientation", + GTK_ORIENTATION_VERTICAL, NULL ); } diff --git a/src/pages/music/disc-view.h b/src/pages/music/disc-view.h index 683f9a5..c7e4209 100644 --- a/src/pages/music/disc-view.h +++ b/src/pages/music/disc-view.h @@ -27,11 +27,30 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(KotoDiscView, koto_disc_view, KOTO, DISC_VIEW, GtkBox) -KotoDiscView* koto_disc_view_new(KotoIndexedAlbum *album, guint *disc); -void koto_disc_view_handle_selected_rows_changed(GtkListBox *box, gpointer user_data); -void koto_disc_view_list_tracks(gpointer data, gpointer selfptr); -void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album); -void koto_disc_view_set_disc_label_visible(KotoDiscView *self, gboolean visible); -void koto_disc_view_set_disc_number(KotoDiscView *self, guint disc_number); +KotoDiscView* koto_disc_view_new(KotoIndexedAlbum * album, guint * disc); +void koto_disc_view_handle_selected_rows_changed( + GtkListBox * box, + gpointer user_data +); + +void koto_disc_view_list_tracks( + gpointer data, + gpointer selfptr +); + +void koto_disc_view_set_album( + KotoDiscView * self, + KotoIndexedAlbum * album +); + +void koto_disc_view_set_disc_label_visible( + KotoDiscView * self, + gboolean visible +); + +void koto_disc_view_set_disc_number( + KotoDiscView * self, + guint disc_number +); G_END_DECLS diff --git a/src/pages/music/music-local.c b/src/pages/music/music-local.c index ca19e48..9763769 100644 --- a/src/pages/music/music-local.c +++ b/src/pages/music/music-local.c @@ -24,7 +24,7 @@ #include "../../koto-utils.h" #include "music-local.h" -extern KotoCartographer *koto_maps; +extern KotoCartographer * koto_maps; enum { PROP_0, @@ -32,15 +32,17 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; struct _KotoPageMusicLocal { GtkBox parent_instance; - GtkWidget *scrolled_window; - GtkWidget *artist_list; - GtkWidget *stack; + GtkWidget * scrolled_window; + GtkWidget * artist_list; + GtkWidget * stack; - KotoIndexedLibrary *lib; + KotoIndexedLibrary * lib; gboolean constructed; }; @@ -50,14 +52,28 @@ struct _KotoPageMusicLocalClass { G_DEFINE_TYPE(KotoPageMusicLocal, koto_page_music_local, GTK_TYPE_BOX); -KotoPageMusicLocal *music_local_page; +KotoPageMusicLocal * music_local_page; + +static void koto_page_music_local_constructed(GObject * obj); + +static void koto_page_music_local_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_page_music_local_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_page_music_local_class_init(KotoPageMusicLocalClass * c) { + GObjectClass * gobject_class; -static void koto_page_music_local_constructed(GObject *obj); -static void koto_page_music_local_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_page_music_local_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_page_music_local_class_init(KotoPageMusicLocalClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->constructed = koto_page_music_local_constructed; gobject_class->set_property = koto_page_music_local_set_property; @@ -68,14 +84,20 @@ static void koto_page_music_local_class_init(KotoPageMusicLocalClass *c) { "Library", "Library", KOTO_TYPE_INDEXED_LIBRARY, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_page_music_local_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoPageMusicLocal *self = KOTO_PAGE_MUSIC_LOCAL(obj); +static void koto_page_music_local_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoPageMusicLocal * self = KOTO_PAGE_MUSIC_LOCAL(obj); + switch (prop_id) { case PROP_LIB: @@ -87,8 +109,14 @@ static void koto_page_music_local_get_property(GObject *obj, guint prop_id, GVal } } -static void koto_page_music_local_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoPageMusicLocal *self = KOTO_PAGE_MUSIC_LOCAL(obj); +static void koto_page_music_local_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoPageMusicLocal * self = KOTO_PAGE_MUSIC_LOCAL(obj); + switch (prop_id) { case PROP_LIB: @@ -100,7 +128,7 @@ static void koto_page_music_local_set_property(GObject *obj, guint prop_id, cons } } -static void koto_page_music_local_init(KotoPageMusicLocal *self) { +static void koto_page_music_local_init(KotoPageMusicLocal * self) { self->lib = NULL; self->constructed = FALSE; @@ -130,36 +158,55 @@ static void koto_page_music_local_init(KotoPageMusicLocal *self) { gtk_box_append(GTK_BOX(self), self->stack); } -static void koto_page_music_local_constructed(GObject *obj) { - KotoPageMusicLocal *self = KOTO_PAGE_MUSIC_LOCAL(obj); +static void koto_page_music_local_constructed(GObject * obj) { + KotoPageMusicLocal * self = KOTO_PAGE_MUSIC_LOCAL(obj); - G_OBJECT_CLASS (koto_page_music_local_parent_class)->constructed (obj); + + G_OBJECT_CLASS(koto_page_music_local_parent_class)->constructed(obj); self->constructed = TRUE; } -void koto_page_music_local_add_artist(KotoPageMusicLocal *self, KotoIndexedArtist *artist) { - gchar *artist_name; +void koto_page_music_local_add_artist( + KotoPageMusicLocal * self, + KotoIndexedArtist * artist +) { + gchar * artist_name; + + g_object_get(artist, "name", &artist_name, NULL); - KotoButton *artist_button = koto_button_new_plain(artist_name); + KotoButton * artist_button = koto_button_new_plain(artist_name); + + gtk_list_box_prepend(GTK_LIST_BOX(self->artist_list), GTK_WIDGET(artist_button)); - KotoArtistView *artist_view = koto_artist_view_new(); // Create our new artist view + KotoArtistView * artist_view = koto_artist_view_new(); // Create our new artist view + + koto_artist_view_add_artist(artist_view, artist); // Add the artist gtk_stack_add_named(GTK_STACK(self->stack), koto_artist_view_get_main(artist_view), artist_name); } -void koto_page_music_local_go_to_artist_by_name(KotoPageMusicLocal *self, gchar *artist_name) { +void koto_page_music_local_go_to_artist_by_name( + KotoPageMusicLocal * self, + gchar * artist_name +) { gtk_stack_set_visible_child_name(GTK_STACK(self->stack), artist_name); } -void koto_page_music_local_go_to_artist_by_uuid(KotoPageMusicLocal *self, gchar *artist_uuid) { - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); // Get the artist +void koto_page_music_local_go_to_artist_by_uuid( + KotoPageMusicLocal * self, + gchar * artist_uuid +) { + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); // Get the artist + if (!KOTO_IS_INDEXED_ARTIST(artist)) { // No artist for this UUID return; } - gchar *artist_name = NULL; + gchar * artist_name = NULL; + + g_object_get( artist, "name", @@ -174,17 +221,26 @@ void koto_page_music_local_go_to_artist_by_uuid(KotoPageMusicLocal *self, gchar koto_page_music_local_go_to_artist_by_name(self, artist_name); } -void koto_page_music_local_handle_artist_click(GtkListBox *box, GtkListBoxRow *row, gpointer data) { +void koto_page_music_local_handle_artist_click( + GtkListBox * box, + GtkListBoxRow * row, + gpointer data +) { (void) box; - KotoPageMusicLocal *self = (KotoPageMusicLocal*) data; - KotoButton *btn = KOTO_BUTTON(gtk_list_box_row_get_child(row)); + KotoPageMusicLocal * self = (KotoPageMusicLocal*) data; + KotoButton * btn = KOTO_BUTTON(gtk_list_box_row_get_child(row)); + + gchar * artist_name; + - gchar *artist_name; g_object_get(btn, "button-text", &artist_name, NULL); koto_page_music_local_go_to_artist_by_name(self, artist_name); } -void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibrary *lib) { +void koto_page_music_local_set_library( + KotoPageMusicLocal * self, + KotoIndexedLibrary * lib +) { if (lib == NULL) { return; } @@ -203,11 +259,12 @@ void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibr gpointer artist_key; gpointer artist_data; - GHashTable *artists = koto_indexed_library_get_artists(self->lib); // Get the artists + GHashTable * artists = koto_indexed_library_get_artists(self->lib); // Get the artists + g_hash_table_iter_init(&artist_list_iter, artists); while (g_hash_table_iter_next(&artist_list_iter, &artist_key, &artist_data)) { // For each of the music artists - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, (gchar*) artist_data); // Cast our data as a KotoIndexedArtist + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, (gchar*) artist_data); // Cast our data as a KotoIndexedArtist if (artist != NULL) { koto_page_music_local_add_artist(self, artist); @@ -215,13 +272,18 @@ void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibr } } -int koto_page_music_local_sort_artists(GtkListBoxRow *artist1, GtkListBoxRow *artist2, gpointer user_data) { +int koto_page_music_local_sort_artists( + GtkListBoxRow * artist1, + GtkListBoxRow * artist2, + gpointer user_data +) { (void) user_data; - KotoButton *artist1_btn = KOTO_BUTTON(gtk_list_box_row_get_child(artist1)); - KotoButton *artist2_btn = KOTO_BUTTON(gtk_list_box_row_get_child(artist2)); + KotoButton * artist1_btn = KOTO_BUTTON(gtk_list_box_row_get_child(artist1)); + KotoButton * artist2_btn = KOTO_BUTTON(gtk_list_box_row_get_child(artist2)); + + gchar * artist1_text; + gchar * artist2_text; - gchar *artist1_text; - gchar *artist2_text; g_object_get(artist1_btn, "button-text", &artist1_text, NULL); g_object_get(artist2_btn, "button-text", &artist2_text, NULL); @@ -229,9 +291,11 @@ int koto_page_music_local_sort_artists(GtkListBoxRow *artist1, GtkListBoxRow *ar return g_utf8_collate(artist1_text, artist2_text); } -KotoPageMusicLocal* koto_page_music_local_new() { - return g_object_new(KOTO_TYPE_PAGE_MUSIC_LOCAL, - "orientation", GTK_ORIENTATION_HORIZONTAL, +KotoPageMusicLocal * koto_page_music_local_new() { + return g_object_new( + KOTO_TYPE_PAGE_MUSIC_LOCAL, + "orientation", + GTK_ORIENTATION_HORIZONTAL, NULL ); } diff --git a/src/pages/music/music-local.h b/src/pages/music/music-local.h index 4e37e5a..11a5ae3 100644 --- a/src/pages/music/music-local.h +++ b/src/pages/music/music-local.h @@ -26,14 +26,39 @@ G_BEGIN_DECLS #define KOTO_TYPE_PAGE_MUSIC_LOCAL (koto_page_music_local_get_type()) -G_DECLARE_FINAL_TYPE (KotoPageMusicLocal, koto_page_music_local, KOTO, PAGE_MUSIC_LOCAL, GtkBox) +G_DECLARE_FINAL_TYPE(KotoPageMusicLocal, koto_page_music_local, KOTO, PAGE_MUSIC_LOCAL, GtkBox) KotoPageMusicLocal* koto_page_music_local_new(); -void koto_page_music_local_add_artist(KotoPageMusicLocal *self, KotoIndexedArtist *artist); -void koto_page_music_local_handle_artist_click(GtkListBox *box, GtkListBoxRow *row, gpointer data); -void koto_page_music_local_go_to_artist_by_name(KotoPageMusicLocal *self, gchar *artist_name); -void koto_page_music_local_go_to_artist_by_uuid(KotoPageMusicLocal *self, gchar *artist_uuid); -void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibrary *lib); -int koto_page_music_local_sort_artists(GtkListBoxRow *artist1, GtkListBoxRow *artist2, gpointer user_data); +void koto_page_music_local_add_artist( + KotoPageMusicLocal * self, + KotoIndexedArtist * artist +); + +void koto_page_music_local_handle_artist_click( + GtkListBox * box, + GtkListBoxRow * row, + gpointer data +); + +void koto_page_music_local_go_to_artist_by_name( + KotoPageMusicLocal * self, + gchar * artist_name +); + +void koto_page_music_local_go_to_artist_by_uuid( + KotoPageMusicLocal * self, + gchar * artist_uuid +); + +void koto_page_music_local_set_library( + KotoPageMusicLocal * self, + KotoIndexedLibrary * lib +); + +int koto_page_music_local_sort_artists( + GtkListBoxRow * artist1, + GtkListBoxRow * artist2, + gpointer user_data +); G_END_DECLS diff --git a/src/pages/playlist/list.c b/src/pages/playlist/list.c index 0768314..1e59af4 100644 --- a/src/pages/playlist/list.c +++ b/src/pages/playlist/list.c @@ -27,11 +27,11 @@ #include "../../playlist/create-modify-dialog.h" #include "list.h" -extern KotoActionBar *action_bar; -extern KotoCartographer *koto_maps; -extern KotoCreateModifyPlaylistDialog *playlist_create_modify_dialog; -extern KotoCurrentPlaylist *current_playlist; -extern KotoWindow *main_window; +extern KotoActionBar * action_bar; +extern KotoCartographer * koto_maps; +extern KotoCreateModifyPlaylistDialog * playlist_create_modify_dialog; +extern KotoCurrentPlaylist * current_playlist; +extern KotoWindow * main_window; enum { PROP_0, @@ -39,41 +39,43 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; struct _KotoPlaylistPage { GObject parent_instance; - KotoPlaylist *playlist; - gchar *uuid; + KotoPlaylist * playlist; + gchar * uuid; - GtkWidget *main; // Our Scrolled Window - GtkWidget *content; // Content inside scrolled window - GtkWidget *header; + GtkWidget * main; // Our Scrolled Window + GtkWidget * content; // Content inside scrolled window + GtkWidget * header; - KotoCoverArtButton *playlist_image; - GtkWidget *name_label; - GtkWidget *tracks_count_label; - GtkWidget *type_label; - KotoButton *favorite_button; - KotoButton *edit_button; + KotoCoverArtButton * playlist_image; + GtkWidget * name_label; + GtkWidget * tracks_count_label; + GtkWidget * type_label; + KotoButton * favorite_button; + KotoButton * edit_button; - GtkListItemFactory *item_factory; - GListModel *model; - GtkSelectionModel *selection_model; + GtkListItemFactory * item_factory; + GListModel * model; + GtkSelectionModel * selection_model; - GtkWidget *track_list_content; - GtkWidget *track_list_header; - GtkWidget *track_list_view; + GtkWidget * track_list_content; + GtkWidget * track_list_header; + GtkWidget * track_list_view; - KotoButton *track_num_button; - KotoButton *track_title_button; - KotoButton *track_album_button; - KotoButton *track_artist_button; + KotoButton * track_num_button; + KotoButton * track_title_button; + KotoButton * track_album_button; + KotoButton * track_artist_button; - GtkSizeGroup *track_pos_size_group; - GtkSizeGroup *track_name_size_group; - GtkSizeGroup *track_album_size_group; - GtkSizeGroup *track_artist_size_group; + GtkSizeGroup * track_pos_size_group; + GtkSizeGroup * track_name_size_group; + GtkSizeGroup * track_album_size_group; + GtkSizeGroup * track_artist_size_group; }; struct _KotoPlaylistPageClass { @@ -82,11 +84,24 @@ struct _KotoPlaylistPageClass { G_DEFINE_TYPE(KotoPlaylistPage, koto_playlist_page, G_TYPE_OBJECT); -static void koto_playlist_page_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_playlist_page_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); +static void koto_playlist_page_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_playlist_page_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_playlist_page_class_init(KotoPlaylistPageClass * c) { + GObjectClass * gobject_class; + -static void koto_playlist_page_class_init(KotoPlaylistPageClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->get_property = koto_playlist_page_get_property; gobject_class->set_property = koto_playlist_page_set_property; @@ -96,13 +111,13 @@ static void koto_playlist_page_class_init(KotoPlaylistPageClass *c) { "UUID of associated Playlist", "UUID of associated Playlist", NULL, - G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_playlist_page_init(KotoPlaylistPage *self) { +static void koto_playlist_page_init(KotoPlaylistPage * self) { self->track_name_size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); self->track_pos_size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); self->track_album_size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); @@ -119,10 +134,14 @@ static void koto_playlist_page_init(KotoPlaylistPage *self) { gtk_box_prepend(GTK_BOX(self->content), self->header); self->playlist_image = koto_cover_art_button_new(220, 220, NULL); // Create our Cover Art Button with no art by default - KotoButton *cover_art_button = koto_cover_art_button_get_button(self->playlist_image); // Get the button for the cover art + KotoButton * cover_art_button = koto_cover_art_button_get_button(self->playlist_image); // Get the button for the cover art + + koto_button_add_click_handler(cover_art_button, KOTO_BUTTON_CLICK_TYPE_PRIMARY, G_CALLBACK(koto_playlist_page_handle_cover_art_clicked), self); - GtkWidget *info_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget * info_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + + gtk_widget_set_size_request(info_box, -1, 220); gtk_widget_add_css_class(info_box, "playlist-page-header-info"); gtk_widget_set_hexpand(info_box, TRUE); @@ -176,8 +195,14 @@ static void koto_playlist_page_init(KotoPlaylistPage *self) { g_signal_connect(action_bar, "closed", G_CALLBACK(koto_playlist_page_handle_action_bar_closed), self); // Handle closed action bar } -static void koto_playlist_page_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoPlaylistPage *self = KOTO_PLAYLIST_PAGE(obj); +static void koto_playlist_page_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoPlaylistPage * self = KOTO_PLAYLIST_PAGE(obj); + switch (prop_id) { case PROP_PLAYLIST_UUID: @@ -189,8 +214,15 @@ static void koto_playlist_page_get_property(GObject *obj, guint prop_id, GValue } } -static void koto_playlist_page_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoPlaylistPage *self = KOTO_PLAYLIST_PAGE(obj); +static void koto_playlist_page_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoPlaylistPage * self = KOTO_PLAYLIST_PAGE(obj); + + switch (prop_id) { case PROP_PLAYLIST_UUID: koto_playlist_page_set_playlist_uuid(self, g_strdup(g_value_get_string(val))); // Call to our playlist UUID set function @@ -201,23 +233,29 @@ static void koto_playlist_page_set_property(GObject *obj, guint prop_id, const G } } -void koto_playlist_page_bind_track_item(GtkListItemFactory *factory, GtkListItem *item, KotoPlaylistPage *self) { +void koto_playlist_page_bind_track_item( + GtkListItemFactory * factory, + GtkListItem * item, + KotoPlaylistPage * self +) { (void) factory; - GtkWidget *track_position_label = gtk_widget_get_first_child(gtk_list_item_get_child(item)); - 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); + GtkWidget * track_position_label = gtk_widget_get_first_child(gtk_list_item_get_child(item)); + 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); + + KotoIndexedTrack * track = gtk_list_item_get_item(item); // Get the track UUID from our model - KotoIndexedTrack *track = gtk_list_item_get_item(item); // Get the track UUID from our model if (!KOTO_IS_INDEXED_TRACK(track)) { return; } - gchar *track_name = NULL; - gchar *album_uuid = NULL; - gchar *artist_uuid = NULL; + gchar * track_name = NULL; + gchar * album_uuid = NULL; + gchar * artist_uuid = NULL; + g_object_get( track, @@ -232,23 +270,26 @@ void koto_playlist_page_bind_track_item(GtkListItemFactory *factory, GtkListItem guint track_position = koto_playlist_get_position_of_track(self->playlist, track); + gtk_label_set_label(GTK_LABEL(track_position_label), g_strdup_printf("%u", track_position)); // Set the track position gtk_label_set_label(GTK_LABEL(track_name_label), track_name); // Set our track name - KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); + KotoIndexedAlbum * album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); + if (KOTO_IS_INDEXED_ALBUM(album)) { gtk_label_set_label(GTK_LABEL(track_album_label), koto_indexed_album_get_album_name(album)); // Get the name of the album and set it to the label } - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); + KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); + if (KOTO_IS_INDEXED_ARTIST(artist)) { gtk_label_set_label(GTK_LABEL(track_artist_label), koto_indexed_artist_get_name(artist)); // Get the name of the artist and set it to the label } } -void koto_playlist_page_create_tracks_header(KotoPlaylistPage *self) { +void koto_playlist_page_create_tracks_header(KotoPlaylistPage * self) { self->track_num_button = koto_button_new_with_icon("#", "pan-down-symbolic", "pan-up-symbolic", KOTO_BUTTON_PIXBUF_SIZE_SMALL); koto_button_add_click_handler(self->track_num_button, KOTO_BUTTON_CLICK_TYPE_PRIMARY, G_CALLBACK(koto_playlist_page_handle_track_num_clicked), self); koto_button_set_image_position(self->track_num_button, KOTO_BUTTON_IMAGE_POS_RIGHT); // Move the image to the right @@ -276,13 +317,17 @@ void koto_playlist_page_create_tracks_header(KotoPlaylistPage *self) { gtk_box_append(GTK_BOX(self->track_list_header), GTK_WIDGET(self->track_artist_button)); } -GtkWidget* koto_playlist_page_get_main(KotoPlaylistPage *self) { +GtkWidget * koto_playlist_page_get_main(KotoPlaylistPage * self) { return self->main; } -void koto_playlist_page_handle_action_bar_closed(KotoActionBar *bar, gpointer data) { +void koto_playlist_page_handle_action_bar_closed( + KotoActionBar * bar, + gpointer data +) { (void) bar; - KotoPlaylistPage *self = data; + KotoPlaylistPage * self = data; + if (!KOTO_IS_PLAYLIST(self->playlist)) { // No playlist set return; @@ -292,9 +337,19 @@ void koto_playlist_page_handle_action_bar_closed(KotoActionBar *bar, gpointer da gtk_widget_grab_focus(GTK_WIDGET(main_window)); // Focus on the window } -void koto_playlist_page_handle_cover_art_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlaylistPage *self = user_data; +void koto_playlist_page_handle_cover_art_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlaylistPage * self = user_data; + if (!KOTO_IS_PLAYLIST(self->playlist)) { // No playlist set return; @@ -303,64 +358,127 @@ void koto_playlist_page_handle_cover_art_clicked(GtkGestureClick *gesture, int n koto_current_playlist_set_playlist(current_playlist, self->playlist); } -void koto_playlist_page_handle_edit_button_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlaylistPage *self = user_data; +void koto_playlist_page_handle_edit_button_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlaylistPage * self = user_data; + + koto_create_modify_playlist_dialog_set_playlist_uuid(playlist_create_modify_dialog, koto_playlist_get_uuid(self->playlist)); koto_window_show_dialog(main_window, "create-modify-playlist"); } -void koto_playlist_page_handle_playlist_modified(KotoPlaylist *playlist, gpointer user_data) { +void koto_playlist_page_handle_playlist_modified( + KotoPlaylist * playlist, + gpointer user_data +) { if (!KOTO_IS_PLAYLIST(playlist)) { return; } - KotoPlaylistPage *self = user_data; + KotoPlaylistPage * self = user_data; + + if (!KOTO_IS_PLAYLIST_PAGE(self)) { return; } - gchar *artwork = koto_playlist_get_artwork(playlist); // Get the artwork + gchar * artwork = koto_playlist_get_artwork(playlist); // Get the artwork + + if (koto_utils_is_string_valid(artwork)) { // Have valid artwork koto_cover_art_button_set_art_path(self->playlist_image, artwork); // Update our Koto Cover Art Button } - gchar *name = koto_playlist_get_name(playlist); // Get the name + gchar * name = koto_playlist_get_name(playlist); // Get the name + + if (koto_utils_is_string_valid(name)) { // Have valid name gtk_label_set_label(GTK_LABEL(self->name_label), name); // Update the name label } } -void koto_playlist_page_handle_track_album_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlaylistPage *self = user_data; +void koto_playlist_page_handle_track_album_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlaylistPage * self = user_data; + + gtk_widget_add_css_class(GTK_WIDGET(self->track_album_button), "active"); koto_button_hide_image(self->track_num_button); // Go back to hiding the image koto_playlist_page_set_playlist_model(self, KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ALBUM); } -void koto_playlist_page_handle_track_artist_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlaylistPage *self = user_data; +void koto_playlist_page_handle_track_artist_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlaylistPage * self = user_data; + + gtk_widget_add_css_class(GTK_WIDGET(self->track_artist_button), "active"); koto_button_hide_image(self->track_num_button); // Go back to hiding the image koto_playlist_page_set_playlist_model(self, KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ARTIST); } -void koto_playlist_page_handle_track_name_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlaylistPage *self = user_data; +void koto_playlist_page_handle_track_name_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlaylistPage * self = user_data; + + gtk_widget_add_css_class(GTK_WIDGET(self->track_title_button), "active"); koto_button_hide_image(self->track_num_button); // Go back to hiding the image koto_playlist_page_set_playlist_model(self, KOTO_PREFERRED_MODEL_TYPE_SORT_BY_TRACK_NAME); } -void koto_playlist_page_handle_track_num_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; - KotoPlaylistPage *self = user_data; +void koto_playlist_page_handle_track_num_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; + KotoPlaylistPage * self = user_data; KotoPreferredModelType current_model = koto_playlist_get_current_model(self->playlist); + if (current_model == KOTO_PREFERRED_MODEL_TYPE_DEFAULT) { // Set to newest currently koto_playlist_page_set_playlist_model(self, KOTO_PREFERRED_MODEL_TYPE_OLDEST_FIRST); // Sort reversed (oldest) koto_button_show_image(self->track_num_button, TRUE); // Use inverted value (pan-up-symbolic) @@ -370,21 +488,29 @@ void koto_playlist_page_handle_track_num_clicked(GtkGestureClick *gesture, int n } } -void koto_playlist_page_handle_tracks_selected(GtkSelectionModel *model, guint position, guint n_items, gpointer user_data) { +void koto_playlist_page_handle_tracks_selected( + GtkSelectionModel * model, + guint position, + guint n_items, + gpointer user_data +) { (void) position; - KotoPlaylistPage *self = user_data; + KotoPlaylistPage * self = user_data; + if (n_items == 0) { // No items selected koto_action_bar_toggle_reveal(action_bar, FALSE); // Hide the action bar return; } - GtkBitset *selected_items_bitset = gtk_selection_model_get_selection(model); // Get the selected items as a GtkBitSet + GtkBitset * selected_items_bitset = gtk_selection_model_get_selection(model); // Get the selected items as a GtkBitSet GtkBitsetIter iter; - GList *selected_tracks = NULL; - GList *selected_tracks_pos = NULL; + GList * selected_tracks = NULL; + GList * selected_tracks_pos = NULL; guint first_track_pos; + + if (!gtk_bitset_iter_init_first(&iter, selected_items_bitset, &first_track_pos)) { // Failed to get the first item return; } @@ -392,6 +518,8 @@ void koto_playlist_page_handle_tracks_selected(GtkSelectionModel *model, guint p selected_tracks_pos = g_list_append(selected_tracks_pos, GUINT_TO_POINTER(first_track_pos)); gboolean have_more_items = TRUE; + + while (have_more_items) { // While we are able to get selected items guint track_pos; have_more_items = gtk_bitset_iter_next(&iter, &track_pos); @@ -400,9 +528,11 @@ void koto_playlist_page_handle_tracks_selected(GtkSelectionModel *model, guint p } } - GList *cur_pos_list; + GList * cur_pos_list; + + for (cur_pos_list = selected_tracks_pos; cur_pos_list != NULL; cur_pos_list = cur_pos_list->next) { // Iterate over every position that we accumulated - KotoIndexedTrack *selected_track = g_list_model_get_item(self->model, GPOINTER_TO_UINT(cur_pos_list->data)); // Get the KotoIndexedTrack in the GListModel for this current position + KotoIndexedTrack * selected_track = g_list_model_get_item(self->model, GPOINTER_TO_UINT(cur_pos_list->data)); // Get the KotoIndexedTrack in the GListModel for this current position selected_tracks = g_list_append(selected_tracks, selected_track); // Add to selected tracks } @@ -410,7 +540,10 @@ void koto_playlist_page_handle_tracks_selected(GtkSelectionModel *model, guint p koto_action_bar_toggle_reveal(action_bar, TRUE); // Show the items } -void koto_playlist_page_set_playlist_uuid(KotoPlaylistPage *self, gchar *playlist_uuid) { +void koto_playlist_page_set_playlist_uuid( + KotoPlaylistPage * self, + gchar * playlist_uuid +) { if (!KOTO_IS_PLAYLIST_PAGE(self)) { return; } @@ -428,7 +561,9 @@ void koto_playlist_page_set_playlist_uuid(KotoPlaylistPage *self, gchar *playlis } self->uuid = g_strdup(playlist_uuid); // Duplicate the playlist UUID - KotoPlaylist *playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->uuid); + KotoPlaylist * playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->uuid); + + self->playlist = playlist; koto_playlist_page_set_playlist_model(self, KOTO_PREFERRED_MODEL_TYPE_DEFAULT); // TODO: Enable this to be changed koto_playlist_page_update_header(self); // Update our header @@ -436,7 +571,10 @@ void koto_playlist_page_set_playlist_uuid(KotoPlaylistPage *self, gchar *playlis g_signal_connect(playlist, "modified", G_CALLBACK(koto_playlist_page_handle_playlist_modified), self); // Handle playlist modification } -void koto_playlist_page_set_playlist_model(KotoPlaylistPage *self, KotoPreferredModelType model) { +void koto_playlist_page_set_playlist_model( + KotoPlaylistPage * self, + KotoPreferredModelType model +) { if (!KOTO_IS_PLAYLIST_PAGE(self)) { return; } @@ -447,11 +585,11 @@ void koto_playlist_page_set_playlist_model(KotoPlaylistPage *self, KotoPreferred if (model != KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ALBUM) { // Not sorting by album currently gtk_widget_remove_css_class(GTK_WIDGET(self->track_album_button), "active"); } - + if (model != KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ARTIST) { // Not sorting by artist currently gtk_widget_remove_css_class(GTK_WIDGET(self->track_artist_button), "active"); } - + if (model != KOTO_PREFERRED_MODEL_TYPE_SORT_BY_TRACK_NAME) { // Not sorting by track name gtk_widget_remove_css_class(GTK_WIDGET(self->track_title_button), "active"); } @@ -462,18 +600,27 @@ void koto_playlist_page_set_playlist_model(KotoPlaylistPage *self, KotoPreferred gtk_list_view_set_model(GTK_LIST_VIEW(self->track_list_view), self->selection_model); // Set our multi selection model to our provided model } -void koto_playlist_page_setup_track_item(GtkListItemFactory *factory, GtkListItem *item, gpointer user_data) { +void koto_playlist_page_setup_track_item( + GtkListItemFactory * factory, + GtkListItem * item, + gpointer user_data +) { (void) factory; - KotoPlaylistPage *self = user_data; + KotoPlaylistPage * self = user_data; + if (!KOTO_IS_PLAYLIST_PAGE(self)) { return; } - GtkWidget *item_content = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); // Have a horizontal box for our content + GtkWidget * item_content = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); // Have a horizontal box for our content + + gtk_widget_add_css_class(item_content, "track-list-columned-item"); - GtkWidget *track_number = gtk_label_new(NULL); // Our track number + GtkWidget * track_number = gtk_label_new(NULL); // Our track number + + gtk_label_set_xalign(GTK_LABEL(track_number), 0); gtk_widget_add_css_class(track_number, "track-column-number"); gtk_widget_set_halign(track_number, GTK_ALIGN_END); @@ -482,7 +629,9 @@ void koto_playlist_page_setup_track_item(GtkListItemFactory *factory, GtkListIte gtk_box_append(GTK_BOX(item_content), track_number); gtk_size_group_add_widget(self->track_pos_size_group, track_number); - GtkWidget *track_name = gtk_label_new(NULL); // Our track name + GtkWidget * track_name = gtk_label_new(NULL); // Our track name + + gtk_label_set_xalign(GTK_LABEL(track_name), 0); gtk_widget_add_css_class(track_name, "track-column-name"); gtk_widget_set_halign(track_name, GTK_ALIGN_START); @@ -491,7 +640,9 @@ void koto_playlist_page_setup_track_item(GtkListItemFactory *factory, GtkListIte gtk_box_append(GTK_BOX(item_content), track_name); gtk_size_group_add_widget(self->track_name_size_group, track_name); - GtkWidget *track_album = gtk_label_new(NULL); // Our track album + GtkWidget * track_album = gtk_label_new(NULL); // Our track album + + gtk_label_set_xalign(GTK_LABEL(track_album), 0); gtk_widget_add_css_class(track_album, "track-column-album"); gtk_widget_set_halign(track_album, GTK_ALIGN_START); @@ -501,7 +652,9 @@ void koto_playlist_page_setup_track_item(GtkListItemFactory *factory, GtkListIte gtk_box_append(GTK_BOX(item_content), track_album); gtk_size_group_add_widget(self->track_album_size_group, track_album); - GtkWidget *track_artist = gtk_label_new(NULL); // Our track artist + GtkWidget * track_artist = gtk_label_new(NULL); // Our track artist + + gtk_label_set_xalign(GTK_LABEL(track_artist), 0); gtk_widget_add_css_class(track_artist, "track-column-artist"); gtk_widget_set_halign(track_artist, GTK_ALIGN_START); @@ -514,7 +667,7 @@ void koto_playlist_page_setup_track_item(GtkListItemFactory *factory, GtkListIte gtk_list_item_set_child(item, item_content); } -void koto_playlist_page_update_header(KotoPlaylistPage *self) { +void koto_playlist_page_update_header(KotoPlaylistPage * self) { if (!KOTO_IS_PLAYLIST_PAGE(self)) { return; } @@ -524,6 +677,8 @@ void koto_playlist_page_update_header(KotoPlaylistPage *self) { } gboolean ephemeral = TRUE; + + g_object_get( self->playlist, "ephemeral", @@ -535,22 +690,28 @@ void koto_playlist_page_update_header(KotoPlaylistPage *self) { gtk_label_set_text(GTK_LABEL(self->name_label), koto_playlist_get_name(self->playlist)); // Set the name label to our playlist name guint track_count = koto_playlist_get_length(self->playlist); // Get the number of tracks + + gtk_label_set_text(GTK_LABEL(self->tracks_count_label), g_strdup_printf(track_count != 1 ? "%u tracks" : "%u track", track_count)); // Set the text to "N tracks" where N is the number - gchar *artwork = koto_playlist_get_artwork(self->playlist); + gchar * artwork = koto_playlist_get_artwork(self->playlist); + if (koto_utils_is_string_valid(artwork)) { // Have artwork koto_cover_art_button_set_art_path(self->playlist_image, artwork); // Update our artwork } KotoPreferredModelType current_model = koto_playlist_get_current_model(self->playlist); // Get the current model + + if (current_model == KOTO_PREFERRED_MODEL_TYPE_OLDEST_FIRST) { koto_button_show_image(self->track_num_button, TRUE); // Immediately use pan-up-symbolic } } -KotoPlaylistPage* koto_playlist_page_new(gchar *playlist_uuid) { - return g_object_new(KOTO_TYPE_PLAYLIST_PAGE, +KotoPlaylistPage * koto_playlist_page_new(gchar * playlist_uuid) { + return g_object_new( + KOTO_TYPE_PLAYLIST_PAGE, "uuid", playlist_uuid, NULL diff --git a/src/pages/playlist/list.h b/src/pages/playlist/list.h index 4204e36..f36d2ab 100644 --- a/src/pages/playlist/list.h +++ b/src/pages/playlist/list.h @@ -26,31 +26,122 @@ G_BEGIN_DECLS #define KOTO_TYPE_PLAYLIST_PAGE koto_playlist_page_get_type() -G_DECLARE_FINAL_TYPE (KotoPlaylistPage, koto_playlist_page, KOTO, PLAYLIST_PAGE, GObject); +G_DECLARE_FINAL_TYPE(KotoPlaylistPage, koto_playlist_page, KOTO, PLAYLIST_PAGE, GObject); #define KOTO_IS_PLAYLIST_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_PLAYLIST_PAGE)) -KotoPlaylistPage* koto_playlist_page_new(gchar *playlist_uuid); -void koto_playlist_page_add_track(KotoPlaylistPage* self, const gchar *track_uuid); -void koto_playlist_page_create_tracks_header(KotoPlaylistPage *self); -void koto_playlist_page_bind_track_item(GtkListItemFactory *factory, GtkListItem *item, KotoPlaylistPage *self); -void koto_playlist_page_remove_track(KotoPlaylistPage *self, const gchar *track_uuid); -GtkWidget* koto_playlist_page_get_main(KotoPlaylistPage *self); -void koto_playlist_page_handle_action_bar_closed(KotoActionBar *bar, gpointer data); -void koto_playlist_page_handle_cover_art_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_playlist_page_handle_edit_button_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_playlist_page_handle_playlist_modified(KotoPlaylist *playlist, gpointer user_data); -void koto_playlist_page_handle_track_album_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_playlist_page_handle_track_artist_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_playlist_page_handle_track_name_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_playlist_page_handle_track_num_clicked(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_playlist_page_handle_tracks_selected(GtkSelectionModel *model, guint position, guint n_items, gpointer user_data); -void koto_playlist_page_hide_popover(KotoPlaylistPage *self); -void koto_playlist_page_setup_track_item(GtkListItemFactory *factory, GtkListItem *item, gpointer user_data); -void koto_playlist_page_set_playlist_uuid(KotoPlaylistPage *self, gchar *playlist_uuid); -void koto_playlist_page_set_playlist_model(KotoPlaylistPage *self, KotoPreferredModelType model); -void koto_playlist_page_show_popover(KotoPlaylistPage *self); -void koto_playlist_page_update_header(KotoPlaylistPage *self); +KotoPlaylistPage * koto_playlist_page_new(gchar * playlist_uuid); -void koto_playlist_page_handle_listitem_activate(GtkListView *list, guint position, gpointer user_data); +void koto_playlist_page_add_track( + KotoPlaylistPage* self, + const gchar * track_uuid +); + +void koto_playlist_page_create_tracks_header(KotoPlaylistPage * self); + +void koto_playlist_page_bind_track_item( + GtkListItemFactory * factory, + GtkListItem * item, + KotoPlaylistPage * self +); + +void koto_playlist_page_remove_track( + KotoPlaylistPage * self, + const gchar * track_uuid +); + +GtkWidget * koto_playlist_page_get_main(KotoPlaylistPage * self); + +void koto_playlist_page_handle_action_bar_closed( + KotoActionBar * bar, + gpointer data +); + +void koto_playlist_page_handle_cover_art_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_playlist_page_handle_edit_button_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_playlist_page_handle_playlist_modified( + KotoPlaylist * playlist, + gpointer user_data +); + +void koto_playlist_page_handle_track_album_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_playlist_page_handle_track_artist_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_playlist_page_handle_track_name_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_playlist_page_handle_track_num_clicked( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_playlist_page_handle_tracks_selected( + GtkSelectionModel * model, + guint position, + guint n_items, + gpointer user_data +); + +void koto_playlist_page_hide_popover(KotoPlaylistPage * self); + +void koto_playlist_page_setup_track_item( + GtkListItemFactory * factory, + GtkListItem * item, + gpointer user_data +); + +void koto_playlist_page_set_playlist_uuid( + KotoPlaylistPage * self, + gchar * playlist_uuid +); + +void koto_playlist_page_set_playlist_model( + KotoPlaylistPage * self, + KotoPreferredModelType model +); + +void koto_playlist_page_show_popover(KotoPlaylistPage * self); + +void koto_playlist_page_update_header(KotoPlaylistPage * self); + +void koto_playlist_page_handle_listitem_activate( + GtkListView * list, + guint position, + gpointer user_data +); G_END_DECLS diff --git a/src/playback/engine.c b/src/playback/engine.c index 6273ed4..8ec2173 100644 --- a/src/playback/engine.c +++ b/src/playback/engine.c @@ -38,25 +38,26 @@ enum { N_SIGNALS }; -static guint playback_engine_signals[N_SIGNALS] = { 0 }; +static guint playback_engine_signals[N_SIGNALS] = { + 0 +}; -extern KotoCartographer *koto_maps; -extern KotoCurrentPlaylist *current_playlist; +extern KotoCartographer * koto_maps; +extern KotoCurrentPlaylist * current_playlist; -KotoPlaybackEngine *playback_engine; +KotoPlaybackEngine * playback_engine; struct _KotoPlaybackEngine { GObject parent_class; - GstElement *player; - GstElement *playbin; - GstElement *suppress_video; - GstBus *monitor; + GstElement * player; + GstElement * playbin; + GstElement * suppress_video; + GstBus * monitor; - GstQuery *duration_query; - GstQuery *position_query; + GstQuery * duration_query; + GstQuery * position_query; - KotoIndexedTrack *current_track; - NotifyNotification *track_notification; + KotoIndexedTrack * current_track; gboolean is_muted; gboolean is_repeat_enabled; @@ -74,22 +75,24 @@ struct _KotoPlaybackEngine { struct _KotoPlaybackEngineClass { GObjectClass parent_class; - void (* is_playing) (KotoPlaybackEngine *engine); - void (* is_paused) (KotoPlaybackEngine *engine); - void (* play_state_changed) (KotoPlaybackEngine *engine); - void (* tick_duration) (KotoPlaybackEngine *engine); - void (* tick_track) (KotoPlaybackEngine *engine); - void (* track_changed) (KotoPlaybackEngine *engine); - void (* track_repeat_changed) (KotoPlaybackEngine *engine); - void (* track_shuffle_changed) (KotoPlaybackEngine *engine); + void (* is_playing) (KotoPlaybackEngine * engine); + void (* is_paused) (KotoPlaybackEngine * engine); + void (* play_state_changed) (KotoPlaybackEngine * engine); + void (* tick_duration) (KotoPlaybackEngine * engine); + void (* tick_track) (KotoPlaybackEngine * engine); + void (* track_changed) (KotoPlaybackEngine * engine); + void (* track_repeat_changed) (KotoPlaybackEngine * engine); + void (* track_shuffle_changed) (KotoPlaybackEngine * engine); }; G_DEFINE_TYPE(KotoPlaybackEngine, koto_playback_engine, G_TYPE_OBJECT); -static void koto_playback_engine_class_init(KotoPlaybackEngineClass *c) { +static void koto_playback_engine_class_init(KotoPlaybackEngineClass * c) { c->play_state_changed = NULL; - GObjectClass *gobject_class; + GObjectClass * gobject_class; + + gobject_class = G_OBJECT_CLASS(c); playback_engine_signals[SIGNAL_IS_PLAYING] = g_signal_new( @@ -189,7 +192,7 @@ static void koto_playback_engine_class_init(KotoPlaybackEngineClass *c) { ); } -static void koto_playback_engine_init(KotoPlaybackEngine *self) { +static void koto_playback_engine_init(KotoPlaybackEngine * self) { self->current_track = NULL; self->player = gst_pipeline_new("player"); @@ -223,8 +226,9 @@ static void koto_playback_engine_init(KotoPlaybackEngine *self) { } } -void koto_playback_engine_backwards(KotoPlaybackEngine *self) { - KotoPlaylist *playlist = koto_current_playlist_get_playlist(current_playlist); // Get the current playlist +void koto_playback_engine_backwards(KotoPlaybackEngine * self) { + 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; @@ -242,7 +246,8 @@ void koto_playback_engine_current_playlist_changed() { return; } - KotoPlaylist *playlist = koto_current_playlist_get_playlist(current_playlist); // Get the current playlist + 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; @@ -251,8 +256,9 @@ void koto_playback_engine_current_playlist_changed() { koto_playback_engine_set_track_by_uuid(playback_engine, koto_playlist_go_to_next(playlist)); // Go to "next" which is the first track } -void koto_playback_engine_forwards(KotoPlaybackEngine *self) { - KotoPlaylist *playlist = koto_current_playlist_get_playlist(current_playlist); // Get the current playlist +void koto_playback_engine_forwards(KotoPlaybackEngine * self) { + 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; @@ -265,12 +271,14 @@ void koto_playback_engine_forwards(KotoPlaybackEngine *self) { } } -KotoIndexedTrack* koto_playback_engine_get_current_track(KotoPlaybackEngine *self) { +KotoIndexedTrack * koto_playback_engine_get_current_track(KotoPlaybackEngine * self) { return self->current_track; } -gint64 koto_playback_engine_get_duration(KotoPlaybackEngine *self) { +gint64 koto_playback_engine_get_duration(KotoPlaybackEngine * self) { gint64 duration = 0; + + if (gst_element_query(self->player, self->duration_query)) { // Able to query our duration gst_query_parse_duration(self->duration_query, NULL, &duration); // Get the duration duration = duration / GST_SECOND; // Divide by NS to get seconds @@ -279,9 +287,11 @@ gint64 koto_playback_engine_get_duration(KotoPlaybackEngine *self) { return duration; } -gdouble koto_playback_engine_get_progress(KotoPlaybackEngine *self) { +gdouble koto_playback_engine_get_progress(KotoPlaybackEngine * self) { gdouble progress = 0.0; gint64 gstprog = 0; + + if (gst_element_query(self->playbin, self->position_query)) { // Able to get our position gst_query_parse_position(self->position_query, NULL, &gstprog); // Get the progress @@ -295,31 +305,39 @@ gdouble koto_playback_engine_get_progress(KotoPlaybackEngine *self) { return progress; } -GstState koto_playback_engine_get_state(KotoPlaybackEngine *self) { +GstState koto_playback_engine_get_state(KotoPlaybackEngine * self) { return GST_STATE(self->player); } -gboolean koto_playback_engine_get_track_repeat(KotoPlaybackEngine *self) { +gboolean koto_playback_engine_get_track_repeat(KotoPlaybackEngine * self) { return self->is_repeat_enabled; } -gboolean koto_playback_engine_get_track_shuffle(KotoPlaybackEngine *self) { +gboolean koto_playback_engine_get_track_shuffle(KotoPlaybackEngine * self) { (void) self; - KotoPlaylist *playlist = koto_current_playlist_get_playlist(current_playlist); + KotoPlaylist * playlist = koto_current_playlist_get_playlist(current_playlist); + if (!KOTO_IS_PLAYLIST(playlist)) { // Don't have a playlist currently return FALSE; } gboolean currently_shuffling = FALSE; + + g_object_get(playlist, "is-shuffle-enabled", ¤tly_shuffling, NULL); // Get the current is-shuffle-enabled return currently_shuffling; } -gboolean koto_playback_engine_monitor_changed(GstBus *bus, GstMessage *msg, gpointer user_data) { +gboolean koto_playback_engine_monitor_changed( + GstBus * bus, + GstMessage * msg, + gpointer user_data +) { (void) bus; - KotoPlaybackEngine *self = user_data; + KotoPlaybackEngine * self = user_data; + switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ASYNC_DONE: @@ -357,7 +375,7 @@ gboolean koto_playback_engine_monitor_changed(GstBus *bus, GstMessage *msg, gpoi return TRUE; } -void koto_playback_engine_play(KotoPlaybackEngine *self) { +void koto_playback_engine_play(KotoPlaybackEngine * self) { self->is_playing = TRUE; gst_element_set_state(self->player, GST_STATE_PLAYING); // Set our state to play @@ -374,23 +392,33 @@ void koto_playback_engine_play(KotoPlaybackEngine *self) { koto_update_mpris_playback_state(GST_STATE_PLAYING); } -void koto_playback_engine_pause(KotoPlaybackEngine *self) { +void koto_playback_engine_pause(KotoPlaybackEngine * self) { self->is_playing = FALSE; gst_element_change_state(self->player, GST_STATE_CHANGE_PLAYING_TO_PAUSED); koto_update_mpris_playback_state(GST_STATE_PAUSED); } -void koto_playback_engine_set_position(KotoPlaybackEngine *self, int position) { +void koto_playback_engine_set_position( + KotoPlaybackEngine * self, + int position +) { gst_element_seek_simple(self->playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position * GST_SECOND); } -void koto_playback_engine_set_track_repeat(KotoPlaybackEngine *self, gboolean enable_repeat) { +void koto_playback_engine_set_track_repeat( + KotoPlaybackEngine * self, + gboolean enable_repeat +) { self->is_repeat_enabled = enable_repeat; g_signal_emit(self, playback_engine_signals[SIGNAL_TRACK_REPEAT_CHANGE], 0); // Emit our track repeat changed event } -void koto_playback_engine_set_track_shuffle(KotoPlaybackEngine *self, gboolean enable_shuffle) { - KotoPlaylist *playlist = koto_current_playlist_get_playlist(current_playlist); +void koto_playback_engine_set_track_shuffle( + KotoPlaybackEngine * self, + gboolean enable_shuffle +) { + KotoPlaylist * playlist = koto_current_playlist_get_playlist(current_playlist); + if (!KOTO_IS_PLAYLIST(playlist)) { // Don't have a playlist currently return; @@ -400,12 +428,16 @@ void koto_playback_engine_set_track_shuffle(KotoPlaybackEngine *self, gboolean e g_signal_emit(self, playback_engine_signals[SIGNAL_TRACK_SHUFFLE_CHANGE], 0); // Emit our track shuffle changed event } -void koto_playback_engine_set_track_by_uuid(KotoPlaybackEngine *self, gchar *track_uuid) { +void koto_playback_engine_set_track_by_uuid( + KotoPlaybackEngine * self, + gchar * track_uuid +) { if (track_uuid == NULL) { return; } - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, track_uuid); // Get the track from cartographer + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, track_uuid); // Get the track from cartographer + if (!KOTO_IS_INDEXED_TRACK(track)) { // Not a track return; @@ -413,12 +445,15 @@ void koto_playback_engine_set_track_by_uuid(KotoPlaybackEngine *self, gchar *tra self->current_track = track; - gchar *track_file_path = NULL; + gchar * track_file_path = NULL; + + g_object_get(track, "path", &track_file_path, NULL); // Get the path to the track koto_playback_engine_stop(self); // Stop current track - gchar *gst_filename = gst_filename_to_uri(track_file_path, NULL); // Get the gst supported file naem + gchar * gst_filename = gst_filename_to_uri(track_file_path, NULL); // Get the gst supported file naem + g_object_set(self->playbin, "uri", gst_filename, NULL); g_free(gst_filename); // Free the filename @@ -429,34 +464,36 @@ void koto_playback_engine_set_track_by_uuid(KotoPlaybackEngine *self, gchar *tra koto_playback_engine_set_position(self, 0); koto_playback_engine_set_volume(self, self->volume); // Re-enforce our volume on the updated playbin - GVariant *metadata = koto_indexed_track_get_metadata_vardict(track); // Get the GVariantBuilder variable dict for the metadata - GVariantDict *metadata_dict = g_variant_dict_new(metadata); + GVariant * metadata = koto_indexed_track_get_metadata_vardict(track); // Get the GVariantBuilder variable dict for the metadata + GVariantDict * metadata_dict = g_variant_dict_new(metadata); + g_signal_emit(self, playback_engine_signals[SIGNAL_TRACK_CHANGE], 0); // Emit our track change signal koto_update_mpris_info_for_track(self->current_track); - GVariant *track_name_var = g_variant_dict_lookup_value(metadata_dict, "xesam:title", NULL); // Get the GVariant for the name of the track - const gchar *track_name = g_variant_get_string(track_name_var, NULL); // Get the string of the track name + GVariant * track_name_var = g_variant_dict_lookup_value(metadata_dict, "xesam:title", NULL); // Get the GVariant for the name of the track + 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 + 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 - 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 + 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_album_combo = g_strjoin(" - ", artist_name, album_name, NULL); // Join artist and album name separated by " - " + gchar * artist_album_combo = g_strjoin(" - ", artist_name, album_name, NULL); // Join artist and album name separated by " - " + + gchar * icon_name = "audio-x-generic-symbolic"; - gchar *icon_name = "audio-x-generic-symbolic"; if (g_variant_dict_contains(metadata_dict, "mpris:artUrl")) { // If we have artwork specified - GVariant *art_url_var = g_variant_dict_lookup_value(metadata_dict, "mpris:artUrl", NULL); // Get the GVariant for the art URL - const gchar *art_uri = g_variant_get_string(art_url_var, NULL); // Get the string for the artwork + GVariant * art_url_var = g_variant_dict_lookup_value(metadata_dict, "mpris:artUrl", NULL); // Get the GVariant for the art URL + const gchar * art_uri = g_variant_get_string(art_url_var, NULL); // Get the string for the artwork icon_name = koto_utils_replace_string_all(g_strdup(art_uri), "file://", ""); } // Super important note: We are not using libnotify directly because the synchronous nature of notify_notification_send seems to result in dbus timeouts if (g_find_program_in_path("notify-send") != NULL) { // Have notify-send - char *argv[12]; + char * argv[12]; argv[0] = "notify-send"; argv[1] = "-a"; argv[2] = "Koto"; @@ -474,14 +511,18 @@ void koto_playback_engine_set_track_by_uuid(KotoPlaybackEngine *self, gchar *tra } } -void koto_playback_engine_set_volume(KotoPlaybackEngine *self, gdouble volume) { +void koto_playback_engine_set_volume( + KotoPlaybackEngine * self, + gdouble volume +) { self->volume = volume; g_object_set(self->playbin, "volume", self->volume, NULL); } -void koto_playback_engine_stop(KotoPlaybackEngine *self) { +void koto_playback_engine_stop(KotoPlaybackEngine * self) { gst_element_set_state(self->player, GST_STATE_NULL); - GstPad *pad = gst_element_get_static_pad(self->player, "sink"); // Get the static pad of the audio element + GstPad * pad = gst_element_get_static_pad(self->player, "sink"); // Get the static pad of the audio element + if (!GST_IS_PAD(pad)) { return; @@ -491,7 +532,7 @@ void koto_playback_engine_stop(KotoPlaybackEngine *self) { koto_update_mpris_playback_state(GST_STATE_NULL); } -void koto_playback_engine_toggle(KotoPlaybackEngine *self) { +void koto_playback_engine_toggle(KotoPlaybackEngine * self) { if (self->is_playing) { // Currently playing koto_playback_engine_pause(self); // Pause } else { @@ -500,7 +541,8 @@ void koto_playback_engine_toggle(KotoPlaybackEngine *self) { } gboolean koto_playback_engine_tick_duration(gpointer user_data) { - KotoPlaybackEngine *self = user_data; + KotoPlaybackEngine * self = user_data; + if (self->is_playing) { // Is playing g_signal_emit(self, playback_engine_signals[SIGNAL_TICK_DURATION], 0); // Emit our 1s track tick @@ -512,7 +554,8 @@ gboolean koto_playback_engine_tick_duration(gpointer user_data) { } gboolean koto_playback_engine_tick_track(gpointer user_data) { - KotoPlaybackEngine *self = user_data; + KotoPlaybackEngine * self = user_data; + if (self->is_playing) { // Is playing g_signal_emit(self, playback_engine_signals[SIGNAL_TICK_TRACK], 0); // Emit our 100ms track tick @@ -523,14 +566,14 @@ gboolean koto_playback_engine_tick_track(gpointer user_data) { return self->is_playing; } -void koto_playback_engine_toggle_track_repeat(KotoPlaybackEngine *self) { +void koto_playback_engine_toggle_track_repeat(KotoPlaybackEngine * self) { koto_playback_engine_set_track_repeat(self, !self->is_repeat_enabled); } -void koto_playback_engine_toggle_track_shuffle(KotoPlaybackEngine *self) { +void koto_playback_engine_toggle_track_shuffle(KotoPlaybackEngine * self) { koto_playback_engine_set_track_shuffle(self, !koto_playback_engine_get_track_shuffle(self)); // Invert the currently shuffling vale } -KotoPlaybackEngine* koto_playback_engine_new() { +KotoPlaybackEngine * koto_playback_engine_new() { return g_object_new(KOTO_TYPE_PLAYBACK_ENGINE, NULL); } diff --git a/src/playback/engine.h b/src/playback/engine.h index 698ab82..1465760 100644 --- a/src/playback/engine.h +++ b/src/playback/engine.h @@ -25,10 +25,10 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_PLAYBACK_ENGINE (koto_playback_engine_get_type()) -#define KOTO_PLAYBACK_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), KOTO_TYPE_PLAYBACK_ENGINE, KotoPlaybackEngine)) +#define KOTO_PLAYBACK_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KOTO_TYPE_PLAYBACK_ENGINE, KotoPlaybackEngine)) #define KOTO_IS_PLAYBACK_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_PLAYBACK_ENGINE)) typedef struct _KotoPlaybackEngine KotoPlaybackEngine; @@ -39,32 +39,75 @@ GType koto_playback_engine_get_type(void) G_GNUC_CONST; /** * Playback Engine Functions -**/ + **/ + +KotoPlaybackEngine * koto_playback_engine_new(); + +void koto_playback_engine_backwards(KotoPlaybackEngine * self); -KotoPlaybackEngine* koto_playback_engine_new(); -void koto_playback_engine_backwards(KotoPlaybackEngine *self); void koto_playback_engine_current_playlist_changed(); -void koto_playback_engine_forwards(KotoPlaybackEngine *self); -KotoIndexedTrack* koto_playback_engine_get_current_track(KotoPlaybackEngine *self); -gint64 koto_playback_engine_get_duration(KotoPlaybackEngine *self); -GstState koto_playback_engine_get_state(KotoPlaybackEngine *self); -gdouble koto_playback_engine_get_progress(KotoPlaybackEngine *self); -gboolean koto_playback_engine_get_track_repeat(KotoPlaybackEngine *self); -gboolean koto_playback_engine_get_track_shuffle(KotoPlaybackEngine *self); -void koto_playback_engine_mute(KotoPlaybackEngine *self); -gboolean koto_playback_engine_monitor_changed(GstBus *bus, GstMessage *msg, gpointer user_data); -void koto_playback_engine_pause(KotoPlaybackEngine *self); -void koto_playback_engine_play(KotoPlaybackEngine *self); -void koto_playback_engine_toggle(KotoPlaybackEngine *self); -void koto_playback_engine_set_position(KotoPlaybackEngine *self, int position); -void koto_playback_engine_set_track_repeat(KotoPlaybackEngine *self, gboolean enable_repeat); -void koto_playback_engine_set_track_shuffle(KotoPlaybackEngine *self, gboolean enable_shuffle); -void koto_playback_engine_set_track_by_uuid(KotoPlaybackEngine *self, gchar *track_uuid); -void koto_playback_engine_set_volume(KotoPlaybackEngine *self, gdouble volume); -void koto_playback_engine_stop(KotoPlaybackEngine *self); -void koto_playback_engine_toggle_track_repeat(KotoPlaybackEngine *self); -void koto_playback_engine_toggle_track_shuffle(KotoPlaybackEngine *self); -void koto_playback_engine_update_duration(KotoPlaybackEngine *self); + +void koto_playback_engine_forwards(KotoPlaybackEngine * self); + +KotoIndexedTrack * koto_playback_engine_get_current_track(KotoPlaybackEngine * self); + +gint64 koto_playback_engine_get_duration(KotoPlaybackEngine * self); + +GstState koto_playback_engine_get_state(KotoPlaybackEngine * self); + +gdouble koto_playback_engine_get_progress(KotoPlaybackEngine * self); + +gboolean koto_playback_engine_get_track_repeat(KotoPlaybackEngine * self); + +gboolean koto_playback_engine_get_track_shuffle(KotoPlaybackEngine * self); + +void koto_playback_engine_mute(KotoPlaybackEngine * self); + +gboolean koto_playback_engine_monitor_changed( + GstBus * bus, + GstMessage * msg, + gpointer user_data +); + +void koto_playback_engine_pause(KotoPlaybackEngine * self); + +void koto_playback_engine_play(KotoPlaybackEngine * self); + +void koto_playback_engine_toggle(KotoPlaybackEngine * self); + +void koto_playback_engine_set_position( + KotoPlaybackEngine * self, + int position +); + +void koto_playback_engine_set_track_repeat( + KotoPlaybackEngine * self, + gboolean enable_repeat +); + +void koto_playback_engine_set_track_shuffle( + KotoPlaybackEngine * self, + gboolean enable_shuffle +); + +void koto_playback_engine_set_track_by_uuid( + KotoPlaybackEngine * self, + gchar * track_uuid +); + +void koto_playback_engine_set_volume( + KotoPlaybackEngine * self, + gdouble volume +); + +void koto_playback_engine_stop(KotoPlaybackEngine * self); + +void koto_playback_engine_toggle_track_repeat(KotoPlaybackEngine * self); + +void koto_playback_engine_toggle_track_shuffle(KotoPlaybackEngine * self); + +void koto_playback_engine_update_duration(KotoPlaybackEngine * self); gboolean koto_playback_engine_tick_duration(gpointer user_data); + gboolean koto_playback_engine_tick_track(gpointer user_data); diff --git a/src/playback/media-keys.c b/src/playback/media-keys.c index 28e099c..8578a35 100644 --- a/src/playback/media-keys.c +++ b/src/playback/media-keys.c @@ -21,30 +21,30 @@ #include "engine.h" #include "media-keys.h" -extern GtkWindow *main_window; -extern KotoPlaybackEngine *playback_engine; +extern GtkWindow * main_window; +extern KotoPlaybackEngine * playback_engine; -GDBusConnection *media_keys_dbus_conn = NULL; -GDBusProxy *media_keys_proxy = NULL; -GDBusNodeInfo *media_keys_introspection_data = NULL; +GDBusConnection * media_keys_dbus_conn = NULL; +GDBusProxy * media_keys_proxy = NULL; +GDBusNodeInfo * media_keys_introspection_data = NULL; static const gchar introspection_xml[] = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; void grab_media_keys() { if (media_keys_proxy == NULL) { // No connection @@ -63,19 +63,32 @@ void grab_media_keys() { ); } -void handle_media_keys_async_done(GObject *source_object, GAsyncResult *res, gpointer user_data) { +void handle_media_keys_async_done( + GObject * source_object, + GAsyncResult * res, + gpointer user_data +) { (void) user_data; g_dbus_proxy_call_finish(G_DBUS_PROXY(source_object), res, NULL); // Ensure we finish our call } -void handle_media_keys_signal(GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { - (void) proxy; (void) sender_name; (void) user_data; +void handle_media_keys_signal( + GDBusProxy * proxy, + const gchar * sender_name, + const gchar * signal_name, + GVariant * parameters, + gpointer user_data +) { + (void) proxy; + (void) sender_name; + (void) user_data; if (g_strcmp0(signal_name, "MediaPlayerKeyPressed") != 0) { // Not MediaPlayerKeyPressed return; } - gchar *application_name = NULL; - gchar *key = NULL; + gchar * application_name = NULL; + gchar * key = NULL; + g_variant_get(parameters, "(ss)", &application_name, &key); @@ -100,13 +113,21 @@ void handle_media_keys_signal(GDBusProxy *proxy, const gchar *sender_name, const } } -void handle_window_enter(GtkEventControllerFocus *controller, gpointer user_data) { - (void) controller; (void) user_data; +void handle_window_enter( + GtkEventControllerFocus * controller, + gpointer user_data +) { + (void) controller; + (void) user_data; grab_media_keys(); // Grab our media keys } -void handle_window_leave(GtkEventControllerFocus *controller, gpointer user_data) { - (void) controller; (void) user_data; +void handle_window_leave( + GtkEventControllerFocus * controller, + gpointer user_data +) { + (void) controller; + (void) user_data; release_media_keys(); // Release our media keys } @@ -115,7 +136,8 @@ void release_media_keys() { return; } - GVariant *params = g_variant_new_string(g_strdup("com.github.joshstrobl.koto")); + GVariant * params = g_variant_new_string(g_strdup("com.github.joshstrobl.koto")); + g_dbus_proxy_call( media_keys_proxy, @@ -133,8 +155,9 @@ void setup_mediakeys_interface() { media_keys_introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); g_assert(media_keys_introspection_data != NULL); - GDBusConnection *bus; - GError *error = NULL; + GDBusConnection * bus; + GError * error = NULL; + bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); @@ -169,7 +192,9 @@ void setup_mediakeys_interface() { 0 ); - GtkEventController *focus_controller = gtk_event_controller_focus_new(); // Create a new focus controller + GtkEventController * focus_controller = gtk_event_controller_focus_new(); // Create a new focus controller + + g_signal_connect(focus_controller, "enter", G_CALLBACK(handle_window_enter), NULL); g_signal_connect(focus_controller, "leave", G_CALLBACK(handle_window_leave), NULL); gtk_widget_add_controller(GTK_WIDGET(main_window), focus_controller); diff --git a/src/playback/media-keys.h b/src/playback/media-keys.h index 2549d99..20eee0c 100644 --- a/src/playback/media-keys.h +++ b/src/playback/media-keys.h @@ -22,11 +22,33 @@ G_BEGIN_DECLS void grab_media_keys(); -void handle_media_keys_async_done(GObject *source_object, GAsyncResult *res, gpointer user_data); -void handle_media_keys_signal(GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data); -void handle_window_enter(GtkEventControllerFocus *controller, gpointer user_data); -void handle_window_leave(GtkEventControllerFocus *controller, gpointer user_data); + +void handle_media_keys_async_done( + GObject * source_object, + GAsyncResult * res, + gpointer user_data +); + +void handle_media_keys_signal( + GDBusProxy * proxy, + const gchar * sender_name, + const gchar * signal_name, + GVariant * parameters, + gpointer user_data +); + +void handle_window_enter( + GtkEventControllerFocus * controller, + gpointer user_data +); + +void handle_window_leave( + GtkEventControllerFocus * controller, + gpointer user_data +); + void release_media_keys(); + void setup_mediakeys_interface(); G_END_DECLS diff --git a/src/playback/mimes.c b/src/playback/mimes.c index 6f1b44d..4700ba2 100644 --- a/src/playback/mimes.c +++ b/src/playback/mimes.c @@ -20,12 +20,18 @@ #include #include "../koto-utils.h" -GHashTable *supported_mimes_hash = NULL; -GList *supported_mimes = NULL; +GHashTable * supported_mimes_hash = NULL; +GList * supported_mimes = NULL; + +gboolean koto_playback_engine_gst_caps_iter( + GstCapsFeatures * features, + GstStructure * structure, + gpointer user_data +) { + (void) features; + (void) user_data; + gchar * caps_name = (gchar*) gst_structure_get_name(structure); // Get the name, typically a mimetype -gboolean koto_playback_engine_gst_caps_iter(GstCapsFeatures *features, GstStructure *structure, gpointer user_data) { - (void) features; (void) user_data; - gchar *caps_name = (gchar*) gst_structure_get_name(structure); // Get the name, typically a mimetype if (g_str_has_prefix(caps_name, "unknown")) { // Is unknown return TRUE; @@ -42,11 +48,16 @@ gboolean koto_playback_engine_gst_caps_iter(GstCapsFeatures *features, GstStruct return TRUE; } -void koto_playback_engine_gst_pad_iter(gpointer list_data, gpointer user_data) { +void koto_playback_engine_gst_pad_iter( + gpointer list_data, + gpointer user_data +) { (void) user_data; - GstStaticPadTemplate *templ = list_data; + GstStaticPadTemplate * templ = list_data; + + if (templ->direction == GST_PAD_SINK) { // Is a sink pad - GstCaps *capabilities = gst_static_pad_template_get_caps(templ); // Get the capabilities + GstCaps * capabilities = gst_static_pad_template_get_caps(templ); // Get the capabilities gst_caps_foreach(capabilities, koto_playback_engine_gst_caps_iter, NULL); // Iterate over and add to mimes gst_caps_unref(capabilities); } @@ -55,12 +66,14 @@ void koto_playback_engine_gst_pad_iter(gpointer list_data, gpointer user_data) { void koto_playback_engine_get_supported_mimetypes() { // Credit for code goes to https://github.com/mopidy/mopidy/issues/812#issuecomment-75868363 // These are GstElementFactory - GList *elements = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER | GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_PARSER | GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_NONE); + GList * elements = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER | GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_PARSER | GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_NONE); + + GList * ele; + - GList *ele; for (ele = elements; ele != NULL; ele = ele->next) { // For each of the elements // GList of GstStaticPadTemplate - GList *static_pads = (GList*) gst_element_factory_get_static_pad_templates(ele->data); // Get the pads + GList * static_pads = (GList*) gst_element_factory_get_static_pad_templates(ele->data); // Get the pads g_list_foreach(static_pads, koto_playback_engine_gst_pad_iter, NULL); } } diff --git a/src/playback/mimes.h b/src/playback/mimes.h index cef291b..f5010f7 100644 --- a/src/playback/mimes.h +++ b/src/playback/mimes.h @@ -21,8 +21,17 @@ G_BEGIN_DECLS -gboolean koto_bplayback_engine_gst_caps_iter(GstCapsFeatures *features, GstStructure *structure, gpointer user_data); -void koto_playback_engine_gst_pad_iter(gpointer list_data, gpointer user_data); -void koto_playback_engine_get_supported_mimetypes(GList *mimes); +gboolean koto_bplayback_engine_gst_caps_iter( + GstCapsFeatures * features, + GstStructure * structure, + gpointer user_data +); + +void koto_playback_engine_gst_pad_iter( + gpointer list_data, + gpointer user_data +); + +void koto_playback_engine_get_supported_mimetypes(GList * mimes); G_END_DECLS diff --git a/src/playback/mpris.c b/src/playback/mpris.c index cb4c11d..f208afb 100644 --- a/src/playback/mpris.c +++ b/src/playback/mpris.c @@ -28,73 +28,78 @@ #include "mimes.h" #include "mpris.h" -extern KotoCartographer *koto_maps; -extern KotoCurrentPlaylist *current_playlist; -extern GtkApplication *app; -extern GtkWindow *main_window; -extern KotoPlaybackEngine *playback_engine; -extern GList *supported_mimes; +extern KotoCartographer * koto_maps; +extern KotoCurrentPlaylist * current_playlist; +extern GtkApplication * app; +extern GtkWindow * main_window; +extern KotoPlaybackEngine * playback_engine; +extern GList * supported_mimes; -GDBusConnection *dbus_conn = NULL; +GDBusConnection * dbus_conn = NULL; guint mpris_bus_id = 0; -GDBusNodeInfo *introspection_data = NULL; +GDBusNodeInfo * introspection_data = NULL; static const gchar introspection_xml[] = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; void handle_method_call( - GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, + GDBusConnection * connection, + const gchar * sender, + const gchar * object_path, + const gchar * interface_name, + const gchar * method_name, + GVariant * parameters, + GDBusMethodInvocation * invocation, gpointer user_data ) { - (void) connection; (void) sender; (void) object_path; (void) parameters; (void) invocation; (void) user_data; + (void) connection; + (void) sender; + (void) object_path; + (void) parameters; + (void) invocation; + (void) user_data; if (g_strcmp0(interface_name, "org.mpris.MediaPlayer2") == 0) { // Root mediaplayer2 interface if (g_strcmp0(method_name, "Raise") == 0) { // Raise the window @@ -140,17 +145,24 @@ void handle_method_call( } } -GVariant* handle_get_property( - GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *property_name, - GError **error, +GVariant * handle_get_property( + GDBusConnection * connection, + const gchar * sender, + const gchar * object_path, + const gchar * interface_name, + const gchar * property_name, + GError ** error, gpointer user_data ) { - (void) connection; (void) sender; (void) object_path; (void) interface_name; (void) error; (void) user_data; - GVariant *ret; + (void) connection; + (void) sender; + (void) object_path; + (void) interface_name; + (void) error; + (void) user_data; + GVariant * ret; + + ret = NULL; if (g_strcmp0(property_name, "CanQuit") == 0) { // If property is CanQuit @@ -162,7 +174,7 @@ GVariant* handle_get_property( } if (g_strcmp0(property_name, "HasTrackList") == 0) { // If property is HasTrackList - KotoPlaylist *playlist = koto_current_playlist_get_playlist(current_playlist); + KotoPlaylist * playlist = koto_current_playlist_get_playlist(current_playlist); if (KOTO_IS_PLAYLIST(playlist)) { ret = g_variant_new_boolean(koto_playlist_get_length(playlist) > 0); } else { // Don't have a playlist @@ -179,15 +191,15 @@ GVariant* handle_get_property( } if (g_strcmp0(property_name, "SupportedUriSchemas") == 0) { // Supported URI Schemas - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("as")); // Array of strings + GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE("as")); // Array of strings g_variant_builder_add(builder, "s", "file"); ret = g_variant_new("as", builder); g_variant_builder_unref(builder); // Unref builder since we no longer need it } if (g_strcmp0(property_name, "SupportedMimeTypes") == 0) { // Supported mimetypes - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("as")); // Array of strings - GList *mimes; + GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE("as")); // Array of strings + GList * mimes; mimes = NULL; for (mimes = supported_mimes; mimes != NULL; mimes = mimes->next) { // For each mimetype @@ -200,21 +212,21 @@ GVariant* handle_get_property( } if (g_strcmp0(property_name, "Metadata") == 0) { // Metadata - KotoIndexedTrack *current_track = koto_playback_engine_get_current_track(playback_engine); + KotoIndexedTrack * current_track = koto_playback_engine_get_current_track(playback_engine); if (KOTO_IS_INDEXED_TRACK(current_track)) { // Currently playing a track ret = koto_indexed_track_get_metadata_vardict(current_track); } else { // No track - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); // Create an empty builder + GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); // Create an empty builder ret = g_variant_builder_end(builder); // return the vardict } } if ( - (g_strcmp0(property_name, "CanPlay") == 0) || - (g_strcmp0(property_name, "CanPause") == 0) + (g_strcmp0(property_name, "CanPlay") == 0) || + (g_strcmp0(property_name, "CanPause") == 0) ) { - KotoIndexedTrack *current_track = koto_playback_engine_get_current_track(playback_engine); + KotoIndexedTrack * current_track = koto_playback_engine_get_current_track(playback_engine); ret = g_variant_new_boolean(KOTO_IS_INDEXED_TRACK(current_track)); } @@ -232,7 +244,7 @@ GVariant* handle_get_property( ret = g_variant_new_boolean(TRUE); } - if (g_strcmp0(property_name, "CanControl") == 0){ // Can Control + if (g_strcmp0(property_name, "CanControl") == 0) { // Can Control ret = g_variant_new_boolean(TRUE); } @@ -252,16 +264,21 @@ GVariant* handle_get_property( } gboolean handle_set_property( - GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *property_name, - GVariant *value, - GError **error, + GDBusConnection * connection, + const gchar * sender, + const gchar * object_path, + const gchar * interface_name, + const gchar * property_name, + GVariant * value, + GError ** error, gpointer user_data ) { - (void) connection; (void) sender; (void) interface_name; (void) object_path; (void) error; (void) user_data; + (void) connection; + (void) sender; + (void) interface_name; + (void) object_path; + (void) error; + (void) user_data; if (g_strcmp0(property_name, "LoopStatus") == 0) { // Changing LoopStatus koto_playback_engine_set_track_repeat(playback_engine, g_variant_get_boolean(value)); // Set the loop status state @@ -277,7 +294,8 @@ gboolean handle_set_property( } void koto_update_mpris_playback_state(GstState state) { - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + if (state == GST_STATE_PLAYING) { g_variant_builder_add(builder, "{sv}", "PlaybackStatus", g_variant_new_string("Playing")); @@ -287,7 +305,8 @@ void koto_update_mpris_playback_state(GstState state) { g_variant_builder_add(builder, "{sv}", "PlaybackStatus", g_variant_new_string("Stopped")); } - g_dbus_connection_emit_signal(dbus_conn, + g_dbus_connection_emit_signal( + dbus_conn, NULL, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", @@ -297,24 +316,32 @@ void koto_update_mpris_playback_state(GstState state) { ); } -void koto_update_mpris_info_for_track(KotoIndexedTrack *track) { +void koto_update_mpris_info_for_track(KotoIndexedTrack * track) { if (!KOTO_IS_INDEXED_TRACK(track)) { return; } - GVariant *metadata = koto_indexed_track_get_metadata_vardict(track); // Get the GVariantBuilder variable dict for the metadata + GVariant * metadata = koto_indexed_track_get_metadata_vardict(track); // Get the GVariantBuilder variable dict for the metadata + + koto_update_mpris_info_for_track_with_metadata(track, metadata); } -void koto_update_mpris_info_for_track_with_metadata(KotoIndexedTrack *track, GVariant *metadata) { +void koto_update_mpris_info_for_track_with_metadata( + KotoIndexedTrack * track, + GVariant * metadata +) { if (!KOTO_IS_INDEXED_TRACK(track)) { return; } - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + + g_variant_builder_add(builder, "{sv}", "Metadata", metadata); - g_dbus_connection_emit_signal(dbus_conn, + g_dbus_connection_emit_signal( + dbus_conn, NULL, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", @@ -331,10 +358,16 @@ static const GDBusInterfaceVTable main_mpris_interface_vtable = { { 0 } }; -void on_main_mpris_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - (void) name; (void) user_data; +void on_main_mpris_bus_acquired( + GDBusConnection * connection, + const gchar * name, + gpointer user_data +) { + (void) name; + (void) user_data; dbus_conn = connection; - g_dbus_connection_register_object(dbus_conn, + g_dbus_connection_register_object( + dbus_conn, "/org/mpris/MediaPlayer2", introspection_data->interfaces[0], &main_mpris_interface_vtable, @@ -343,7 +376,8 @@ void on_main_mpris_bus_acquired(GDBusConnection *connection, const gchar *name, NULL ); - g_dbus_connection_register_object(dbus_conn, + g_dbus_connection_register_object( + dbus_conn, "/org/mpris/MediaPlayer2", introspection_data->interfaces[1], &main_mpris_interface_vtable, @@ -357,7 +391,8 @@ void setup_mpris_interfaces() { introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); g_assert(introspection_data != NULL); - mpris_bus_id = g_bus_own_name(G_BUS_TYPE_SESSION, + mpris_bus_id = g_bus_own_name( + G_BUS_TYPE_SESSION, "org.mpris.MediaPlayer2.koto", G_BUS_NAME_OWNER_FLAGS_NONE, on_main_mpris_bus_acquired, diff --git a/src/playback/mpris.h b/src/playback/mpris.h index 097acd1..78e9fa6 100644 --- a/src/playback/mpris.h +++ b/src/playback/mpris.h @@ -22,10 +22,50 @@ #include "../indexer/structs.h" void koto_update_mpris_playback_state(GstState state); -void koto_update_mpris_info_for_track(KotoIndexedTrack *track); -void koto_update_mpris_info_for_track_with_metadata(KotoIndexedTrack *track, GVariant *metadata); -void handle_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data); -GVariant* handle_get_property(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data); -gboolean handle_set_property(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data); -void on_main_mpris_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data); + +void koto_update_mpris_info_for_track(KotoIndexedTrack * track); + +void koto_update_mpris_info_for_track_with_metadata( + KotoIndexedTrack * track, + GVariant * metadata +); + +void handle_method_call( + GDBusConnection * connection, + const gchar * sender, + const gchar * object_path, + const gchar * interface_name, + const gchar * method_name, + GVariant * parameters, + GDBusMethodInvocation * invocation, + gpointer user_data +); + +GVariant * handle_get_property( + GDBusConnection * connection, + const gchar * sender, + const gchar * object_path, + const gchar * interface_name, + const gchar * property_name, + GError ** error, + gpointer user_data +); + +gboolean handle_set_property( + GDBusConnection * connection, + const gchar * sender, + const gchar * object_path, + const gchar * interface_name, + const gchar * property_name, + GVariant * value, + GError ** error, + gpointer user_data +); + +void on_main_mpris_bus_acquired( + GDBusConnection * connection, + const gchar * name, + gpointer user_data +); + void setup_mpris_interfaces(); diff --git a/src/playlist/add-remove-track-popover.c b/src/playlist/add-remove-track-popover.c index 8f6338a..14cc7ed 100644 --- a/src/playlist/add-remove-track-popover.c +++ b/src/playlist/add-remove-track-popover.c @@ -22,27 +22,27 @@ #include "../playlist/playlist.h" #include "add-remove-track-popover.h" -extern KotoCartographer *koto_maps; +extern KotoCartographer * koto_maps; struct _KotoAddRemoveTrackPopover { GtkPopover parent_instance; - GtkWidget *list_box; - GHashTable *checkbox_to_playlist_uuid; - GHashTable *playlist_uuid_to_checkbox; - GList *tracks; + GtkWidget * list_box; + GHashTable * checkbox_to_playlist_uuid; + GHashTable * playlist_uuid_to_checkbox; + GList * tracks; - GHashTable *checkbox_to_signal_ids; + GHashTable * checkbox_to_signal_ids; }; G_DEFINE_TYPE(KotoAddRemoveTrackPopover, koto_add_remove_track_popover, GTK_TYPE_POPOVER); -KotoAddRemoveTrackPopover *koto_add_remove_track_popup = NULL; +KotoAddRemoveTrackPopover * koto_add_remove_track_popup = NULL; -static void koto_add_remove_track_popover_class_init(KotoAddRemoveTrackPopoverClass *c) { +static void koto_add_remove_track_popover_class_init(KotoAddRemoveTrackPopoverClass * c) { (void) c; } -static void koto_add_remove_track_popover_init(KotoAddRemoveTrackPopover *self) { +static void koto_add_remove_track_popover_init(KotoAddRemoveTrackPopover * self) { self->list_box = gtk_list_box_new(); // Create our new GtkListBox gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->list_box), GTK_SELECTION_NONE); @@ -58,7 +58,10 @@ static void koto_add_remove_track_popover_init(KotoAddRemoveTrackPopover *self) g_signal_connect(koto_maps, "playlist-removed", G_CALLBACK(koto_add_remove_track_popover_handle_playlist_removed), self); } -void koto_add_remove_track_popover_add_playlist(KotoAddRemoveTrackPopover *self, KotoPlaylist *playlist) { +void koto_add_remove_track_popover_add_playlist( + KotoAddRemoveTrackPopover * self, + KotoPlaylist * playlist +) { if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; } @@ -67,24 +70,29 @@ void koto_add_remove_track_popover_add_playlist(KotoAddRemoveTrackPopover *self, return; } - gchar *playlist_uuid = koto_playlist_get_uuid(playlist); // Get the UUID of the playlist + gchar * playlist_uuid = koto_playlist_get_uuid(playlist); // Get the UUID of the playlist + if (GTK_IS_CHECK_BUTTON(g_hash_table_lookup(self->playlist_uuid_to_checkbox, playlist_uuid))) { // Already have a check button for this g_free(playlist_uuid); return; } - GtkWidget *playlist_button = gtk_check_button_new_with_label(koto_playlist_get_name(playlist)); // Create our GtkCheckButton + GtkWidget * playlist_button = gtk_check_button_new_with_label(koto_playlist_get_name(playlist)); // Create our GtkCheckButton + + g_hash_table_insert(self->checkbox_to_playlist_uuid, playlist_button, playlist_uuid); g_hash_table_insert(self->playlist_uuid_to_checkbox, playlist_uuid, playlist_button); gulong playlist_sig_id = g_signal_connect(playlist_button, "toggled", G_CALLBACK(koto_add_remove_track_popover_handle_checkbutton_toggle), self); + + g_hash_table_insert(self->checkbox_to_signal_ids, playlist_button, GUINT_TO_POINTER(playlist_sig_id)); // Add our GSignal handler ID gtk_list_box_append(GTK_LIST_BOX(self->list_box), playlist_button); // Add the playlist to the list box } -void koto_add_remove_track_popover_clear_tracks(KotoAddRemoveTrackPopover *self) { +void koto_add_remove_track_popover_clear_tracks(KotoAddRemoveTrackPopover * self) { if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; } @@ -95,7 +103,10 @@ void koto_add_remove_track_popover_clear_tracks(KotoAddRemoveTrackPopover *self) } } -void koto_add_remove_track_popover_remove_playlist(KotoAddRemoveTrackPopover *self, gchar *playlist_uuid) { +void koto_add_remove_track_popover_remove_playlist( + KotoAddRemoveTrackPopover * self, + gchar * playlist_uuid +) { if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; } @@ -104,7 +115,8 @@ void koto_add_remove_track_popover_remove_playlist(KotoAddRemoveTrackPopover *se return; } - GtkCheckButton *btn = GTK_CHECK_BUTTON(g_hash_table_lookup(self->playlist_uuid_to_checkbox, playlist_uuid)); // Get the check button + GtkCheckButton * btn = GTK_CHECK_BUTTON(g_hash_table_lookup(self->playlist_uuid_to_checkbox, playlist_uuid)); // Get the check button + if (GTK_IS_CHECK_BUTTON(btn)) { // Is a check button g_hash_table_remove(self->checkbox_to_playlist_uuid, btn); // Remove uuid based on btn @@ -114,31 +126,38 @@ void koto_add_remove_track_popover_remove_playlist(KotoAddRemoveTrackPopover *se g_hash_table_remove(self->playlist_uuid_to_checkbox, playlist_uuid); } -void koto_add_remove_track_popover_handle_checkbutton_toggle(GtkCheckButton *btn, gpointer user_data) { - KotoAddRemoveTrackPopover *self = user_data; +void koto_add_remove_track_popover_handle_checkbutton_toggle( + GtkCheckButton * btn, + gpointer user_data +) { + KotoAddRemoveTrackPopover * self = user_data; + if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; } gboolean should_add = gtk_check_button_get_active(btn); // Get the now active state - gchar *playlist_uuid = g_hash_table_lookup(self->checkbox_to_playlist_uuid, btn); // Get the playlist UUID for this button + gchar * playlist_uuid = g_hash_table_lookup(self->checkbox_to_playlist_uuid, btn); // Get the playlist UUID for this button + + KotoPlaylist * playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, playlist_uuid); // Get the playlist - KotoPlaylist *playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, playlist_uuid); // Get the playlist if (!KOTO_IS_PLAYLIST(playlist)) { // Failed to get the playlist return; } - GList *pos; + GList * pos; + + for (pos = self->tracks; pos != NULL; pos = pos->next) { // Iterate over our KotoIndexedTracks - KotoIndexedTrack *track = pos->data; + KotoIndexedTrack * track = pos->data; if (!KOTO_INDEXED_TRACK(track)) { // Not a track continue; // Skip this } - gchar *track_uuid = koto_indexed_track_get_uuid(track); // Get the track + gchar * track_uuid = koto_indexed_track_get_uuid(track); // Get the track if (should_add) { // Should be adding koto_playlist_add_track_by_uuid(playlist, track_uuid, FALSE, TRUE); // Add the track to the playlist @@ -150,9 +169,14 @@ void koto_add_remove_track_popover_handle_checkbutton_toggle(GtkCheckButton *btn gtk_popover_popdown(GTK_POPOVER(self)); // Temporary to hopefully prevent a bork } -void koto_add_remove_track_popover_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playlist, gpointer user_data) { +void koto_add_remove_track_popover_handle_playlist_added( + KotoCartographer * carto, + KotoPlaylist * playlist, + gpointer user_data +) { (void) carto; - KotoAddRemoveTrackPopover *self = user_data; + KotoAddRemoveTrackPopover * self = user_data; + if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; @@ -161,9 +185,14 @@ void koto_add_remove_track_popover_handle_playlist_added(KotoCartographer *carto koto_add_remove_track_popover_add_playlist(self, playlist); } -void koto_add_remove_track_popover_handle_playlist_removed(KotoCartographer *carto, gchar *playlist_uuid, gpointer user_data) { +void koto_add_remove_track_popover_handle_playlist_removed( + KotoCartographer * carto, + gchar * playlist_uuid, + gpointer user_data +) { (void) carto; - KotoAddRemoveTrackPopover *self = user_data; + KotoAddRemoveTrackPopover * self = user_data; + if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; @@ -172,7 +201,11 @@ void koto_add_remove_track_popover_handle_playlist_removed(KotoCartographer *car koto_add_remove_track_popover_remove_playlist(self, playlist_uuid); } -void koto_add_remove_track_popover_set_pointing_to_widget(KotoAddRemoveTrackPopover *self, GtkWidget *widget, GtkPositionType pos) { +void koto_add_remove_track_popover_set_pointing_to_widget( + KotoAddRemoveTrackPopover * self, + GtkWidget * widget, + GtkPositionType pos +) { if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; } @@ -183,6 +216,7 @@ void koto_add_remove_track_popover_set_pointing_to_widget(KotoAddRemoveTrackPopo GtkWidget* existing_parent = gtk_widget_get_parent(GTK_WIDGET(self)); + if (existing_parent != NULL) { g_object_ref(GTK_WIDGET(self)); // Increment widget ref since unparent will do an unref gtk_widget_unparent(GTK_WIDGET(self)); // Unparent the popup @@ -192,30 +226,35 @@ void koto_add_remove_track_popover_set_pointing_to_widget(KotoAddRemoveTrackPopo gtk_popover_set_position(GTK_POPOVER(self), pos); } -void koto_add_remove_track_popover_set_tracks(KotoAddRemoveTrackPopover *self, GList *tracks) { +void koto_add_remove_track_popover_set_tracks( + KotoAddRemoveTrackPopover * self, + GList * tracks +) { if (!KOTO_JS_ADD_REMOVE_TRACK_POPOVER(self)) { return; } gint tracks_len = g_list_length(tracks); + if (tracks_len == 0) { // No tracks return; } self->tracks = g_list_copy(tracks); - GHashTable *playlists = koto_cartographer_get_playlists(koto_maps); // Get our playlists + GHashTable * playlists = koto_cartographer_get_playlists(koto_maps); // Get our playlists GHashTableIter playlists_iter; gpointer uuid, playlist_ptr; + g_hash_table_iter_init(&playlists_iter, playlists); // Init our HashTable iterator while (g_hash_table_iter_next(&playlists_iter, &uuid, &playlist_ptr)) { // While we are iterating through our playlists - KotoPlaylist *playlist = playlist_ptr; + KotoPlaylist * playlist = playlist_ptr; gboolean should_be_checked = FALSE; if (tracks_len > 1) { // More than one track - GList *pos; + GList * pos; for (pos = self->tracks; pos != NULL; pos = pos->next) { // Iterate over our tracks should_be_checked = (koto_playlist_get_position_of_track(playlist, pos->data) != -1); @@ -224,7 +263,7 @@ void koto_add_remove_track_popover_set_tracks(KotoAddRemoveTrackPopover *self, G } } } else { - KotoIndexedTrack *track = g_list_nth_data(self->tracks, 0); // Get the first track + KotoIndexedTrack * track = g_list_nth_data(self->tracks, 0); // Get the first track if (KOTO_IS_INDEXED_TRACK(track)) { gint pos = koto_playlist_get_position_of_track(playlist, track); @@ -232,7 +271,7 @@ void koto_add_remove_track_popover_set_tracks(KotoAddRemoveTrackPopover *self, G } } - GtkCheckButton *playlist_check = g_hash_table_lookup(self->playlist_uuid_to_checkbox, uuid); // Get the GtkCheckButton for this playlist + GtkCheckButton * playlist_check = g_hash_table_lookup(self->playlist_uuid_to_checkbox, uuid); // Get the GtkCheckButton for this playlist if (GTK_IS_CHECK_BUTTON(playlist_check)) { // Is a checkbox gpointer sig_id_ptr = g_hash_table_lookup(self->checkbox_to_signal_ids, playlist_check); @@ -244,6 +283,6 @@ void koto_add_remove_track_popover_set_tracks(KotoAddRemoveTrackPopover *self, G } } -KotoAddRemoveTrackPopover* koto_add_remove_track_popover_new() { +KotoAddRemoveTrackPopover * koto_add_remove_track_popover_new() { return g_object_new(KOTO_TYPE_ADD_REMOVE_TRACK_POPOVER, NULL); } \ No newline at end of file diff --git a/src/playlist/add-remove-track-popover.h b/src/playlist/add-remove-track-popover.h index c301e01..481bcd5 100644 --- a/src/playlist/add-remove-track-popover.h +++ b/src/playlist/add-remove-track-popover.h @@ -25,7 +25,7 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_ADD_REMOVE_TRACK_POPOVER koto_add_remove_track_popover_get_type() G_DECLARE_FINAL_TYPE(KotoAddRemoveTrackPopover, koto_add_remove_track_popover, KOTO, ADD_REMOVE_TRACK_POPOVER, GtkPopover); @@ -33,16 +33,48 @@ G_DECLARE_FINAL_TYPE(KotoAddRemoveTrackPopover, koto_add_remove_track_popover, K /** * Functions -**/ + **/ -KotoAddRemoveTrackPopover* koto_add_remove_track_popover_new(); -void koto_add_remove_track_popover_add_playlist(KotoAddRemoveTrackPopover *self, KotoPlaylist *playlist); -void koto_add_remove_track_popover_clear_tracks(KotoAddRemoveTrackPopover *self); -void koto_add_remove_track_popover_remove_playlist(KotoAddRemoveTrackPopover *self, gchar *playlist_uuid); -void koto_add_remove_track_popover_handle_checkbutton_toggle(GtkCheckButton *btn, gpointer user_data); -void koto_add_remove_track_popover_handle_playlist_added(KotoCartographer *carto, KotoPlaylist *playlist, gpointer user_data); -void koto_add_remove_track_popover_handle_playlist_removed(KotoCartographer *carto, gchar *playlist_uuid, gpointer user_data); -void koto_add_remove_track_popover_set_pointing_to_widget(KotoAddRemoveTrackPopover *self, GtkWidget *widget, GtkPositionType pos); -void koto_add_remove_track_popover_set_tracks(KotoAddRemoveTrackPopover *self, GList *tracks); +KotoAddRemoveTrackPopover * koto_add_remove_track_popover_new(); + +void koto_add_remove_track_popover_add_playlist( + KotoAddRemoveTrackPopover * self, + KotoPlaylist * playlist +); + +void koto_add_remove_track_popover_clear_tracks(KotoAddRemoveTrackPopover * self); + +void koto_add_remove_track_popover_remove_playlist( + KotoAddRemoveTrackPopover * self, + gchar * playlist_uuid +); + +void koto_add_remove_track_popover_handle_checkbutton_toggle( + GtkCheckButton * btn, + gpointer user_data +); + +void koto_add_remove_track_popover_handle_playlist_added( + KotoCartographer * carto, + KotoPlaylist * playlist, + gpointer user_data +); + +void koto_add_remove_track_popover_handle_playlist_removed( + KotoCartographer * carto, + gchar * playlist_uuid, + gpointer user_data +); + +void koto_add_remove_track_popover_set_pointing_to_widget( + KotoAddRemoveTrackPopover * self, + GtkWidget * widget, + GtkPositionType pos +); + +void koto_add_remove_track_popover_set_tracks( + KotoAddRemoveTrackPopover * self, + GList * tracks +); G_END_DECLS \ No newline at end of file diff --git a/src/playlist/create-modify-dialog.c b/src/playlist/create-modify-dialog.c index 6a147fd..700c93b 100644 --- a/src/playlist/create-modify-dialog.c +++ b/src/playlist/create-modify-dialog.c @@ -24,8 +24,8 @@ #include "../koto-window.h" #include "create-modify-dialog.h" -extern KotoCartographer *koto_maps; -extern KotoWindow *main_window; +extern KotoCartographer * koto_maps; +extern KotoWindow * main_window; enum { PROP_DIALOG_0, @@ -33,29 +33,44 @@ enum { N_PROPS }; -static GParamSpec *dialog_props[N_PROPS] = { NULL, }; +static GParamSpec * dialog_props[N_PROPS] = { + NULL, +}; struct _KotoCreateModifyPlaylistDialog { GtkBox parent_instance; - GtkWidget *playlist_image; - GtkWidget *name_entry; + GtkWidget * playlist_image; + GtkWidget * name_entry; - GtkWidget *create_button; + GtkWidget * create_button; - gchar *playlist_image_path; - gchar *playlist_uuid; + gchar * playlist_image_path; + gchar * playlist_uuid; }; G_DEFINE_TYPE(KotoCreateModifyPlaylistDialog, koto_create_modify_playlist_dialog, GTK_TYPE_BOX); -KotoCreateModifyPlaylistDialog *playlist_create_modify_dialog; +KotoCreateModifyPlaylistDialog * playlist_create_modify_dialog; + +static void koto_create_modify_playlist_dialog_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +static void koto_create_modify_playlist_dialog_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_create_modify_playlist_dialog_class_init(KotoCreateModifyPlaylistDialogClass * c) { + GObjectClass * gobject_class; -static void koto_create_modify_playlist_dialog_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); -static void koto_create_modify_playlist_dialog_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_create_modify_playlist_dialog_class_init(KotoCreateModifyPlaylistDialogClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_create_modify_playlist_dialog_set_property; gobject_class->get_property = koto_create_modify_playlist_dialog_get_property; @@ -65,13 +80,13 @@ static void koto_create_modify_playlist_dialog_class_init(KotoCreateModifyPlayli "Playlist UUID", "Playlist UUID", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPS, dialog_props); } -static void koto_create_modify_playlist_dialog_init(KotoCreateModifyPlaylistDialog *self) { +static void koto_create_modify_playlist_dialog_init(KotoCreateModifyPlaylistDialog * self) { self->playlist_image_path = NULL; gtk_widget_set_halign(GTK_WIDGET(self), GTK_ALIGN_CENTER); @@ -82,11 +97,15 @@ static void koto_create_modify_playlist_dialog_init(KotoCreateModifyPlaylistDial gtk_widget_set_size_request(self->playlist_image, 220, 220); gtk_box_append(GTK_BOX(self), self->playlist_image); // Add our image - GtkDropTarget *target = gtk_drop_target_new(G_TYPE_FILE, GDK_ACTION_COPY); + GtkDropTarget * target = gtk_drop_target_new(G_TYPE_FILE, GDK_ACTION_COPY); + + g_signal_connect(GTK_EVENT_CONTROLLER(target), "drop", G_CALLBACK(koto_create_modify_playlist_dialog_handle_drop), self); gtk_widget_add_controller(self->playlist_image, GTK_EVENT_CONTROLLER(target)); - GtkGesture *image_click_controller = gtk_gesture_click_new(); // Create a click gesture for the image clicking + GtkGesture * image_click_controller = gtk_gesture_click_new(); // Create a click gesture for the image clicking + + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(image_click_controller), 1); // Only allow left click g_signal_connect(GTK_EVENT_CONTROLLER(image_click_controller), "pressed", G_CALLBACK(koto_create_modify_playlist_dialog_handle_image_click), self); @@ -105,8 +124,14 @@ static void koto_create_modify_playlist_dialog_init(KotoCreateModifyPlaylistDial gtk_box_append(GTK_BOX(self), self->create_button); // Add the create button } -static void koto_create_modify_playlist_dialog_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec){ - KotoCreateModifyPlaylistDialog *self = KOTO_CREATE_MODIFY_PLAYLIST_DIALOG(obj); +static void koto_create_modify_playlist_dialog_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoCreateModifyPlaylistDialog * self = KOTO_CREATE_MODIFY_PLAYLIST_DIALOG(obj); + switch (prop_id) { case PROP_PLAYLIST_UUID: @@ -118,9 +143,17 @@ static void koto_create_modify_playlist_dialog_get_property(GObject *obj, guint } } -static void koto_create_modify_playlist_dialog_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoCreateModifyPlaylistDialog *self = KOTO_CREATE_MODIFY_PLAYLIST_DIALOG(obj); - (void) self; (void) val; +static void koto_create_modify_playlist_dialog_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoCreateModifyPlaylistDialog * self = KOTO_CREATE_MODIFY_PLAYLIST_DIALOG(obj); + + + (void) self; + (void) val; switch (prop_id) { case PROP_PLAYLIST_UUID: @@ -132,19 +165,26 @@ static void koto_create_modify_playlist_dialog_set_property(GObject *obj, guint } } -void koto_create_modify_playlist_dialog_handle_chooser_response(GtkNativeDialog *native, int response, gpointer user_data) { +void koto_create_modify_playlist_dialog_handle_chooser_response( + GtkNativeDialog * native, + int response, + gpointer user_data +) { if (response != GTK_RESPONSE_ACCEPT) { // Not accept g_object_unref(native); return; } - KotoCreateModifyPlaylistDialog *self = user_data; + KotoCreateModifyPlaylistDialog * self = user_data; + + if (!KOTO_IS_CURRENT_MODIFY_PLAYLIST(self)) { return; } - GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(native)); - gchar *file_path = g_file_get_path(file); // Get the absolute path + GFile * file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(native)); + gchar * file_path = g_file_get_path(file); // Get the absolute path + if (file_path != NULL) { self->playlist_image_path = g_strdup(file_path); @@ -156,10 +196,14 @@ void koto_create_modify_playlist_dialog_handle_chooser_response(GtkNativeDialog g_object_unref(native); } -void koto_create_modify_playlist_dialog_handle_create_click(GtkButton *button, gpointer user_data) { +void koto_create_modify_playlist_dialog_handle_create_click( + GtkButton * button, + gpointer user_data +) { (void) button; - KotoCreateModifyPlaylistDialog *self = user_data; + KotoCreateModifyPlaylistDialog * self = user_data; + if (!KOTO_IS_CURRENT_MODIFY_PLAYLIST(self)) { return; @@ -170,9 +214,10 @@ void koto_create_modify_playlist_dialog_handle_create_click(GtkButton *button, g return; } - KotoPlaylist *playlist = NULL; + KotoPlaylist * playlist = NULL; gboolean modify_existing_playlist = koto_utils_is_string_valid(self->playlist_uuid); + if (modify_existing_playlist) { // Modifying an existing playlist playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, self->playlist_uuid); } else { // Creating a new playlist @@ -196,21 +241,32 @@ void koto_create_modify_playlist_dialog_handle_create_click(GtkButton *button, g koto_window_hide_dialogs(main_window); // Hide the dialogs } -gboolean koto_create_modify_playlist_dialog_handle_drop(GtkDropTarget *target, const GValue *val, double x, double y, gpointer user_data) { - (void) target; (void) x; (void) y; +gboolean koto_create_modify_playlist_dialog_handle_drop( + GtkDropTarget * target, + const GValue * val, + double x, + double y, + gpointer user_data +) { + (void) target; + (void) x; + (void) y; if (!G_VALUE_HOLDS(val, G_TYPE_FILE)) { // Not a file return FALSE; } - KotoCreateModifyPlaylistDialog *self = user_data; + KotoCreateModifyPlaylistDialog * self = user_data; + if (!KOTO_IS_CURRENT_MODIFY_PLAYLIST(self)) { // No dialog return FALSE; } - GFile *dropped_file = g_value_get_object(val); // Get the GValue - gchar *file_path = g_file_get_path(dropped_file); // Get the absolute path + GFile * dropped_file = g_value_get_object(val); // Get the GValue + gchar * file_path = g_file_get_path(dropped_file); // Get the absolute path + + g_object_unref(dropped_file); // Unref the file if (file_path == NULL) { @@ -219,6 +275,7 @@ gboolean koto_create_modify_playlist_dialog_handle_drop(GtkDropTarget *target, c magic_t magic_cookie = magic_open(MAGIC_MIME); + if (magic_cookie == NULL) { return FALSE; } @@ -227,7 +284,8 @@ gboolean koto_create_modify_playlist_dialog_handle_drop(GtkDropTarget *target, c goto cookie_closure; } - const char *mime_type = magic_file(magic_cookie, file_path); + const char * mime_type = magic_file(magic_cookie, file_path); + if ((mime_type != NULL) && g_str_has_prefix(mime_type, "image/")) { // Is an image self->playlist_image_path = g_strdup(file_path); @@ -237,21 +295,32 @@ gboolean koto_create_modify_playlist_dialog_handle_drop(GtkDropTarget *target, c } cookie_closure: - magic_close(magic_cookie); - return FALSE; + magic_close(magic_cookie); + return FALSE; } -void koto_create_modify_playlist_dialog_handle_image_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { - (void) gesture; (void) n_press; (void) x; (void) y; +void koto_create_modify_playlist_dialog_handle_image_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +) { + (void) gesture; + (void) n_press; + (void) x; + (void) y; - KotoCreateModifyPlaylistDialog *self = user_data; + KotoCreateModifyPlaylistDialog * self = user_data; GtkFileChooserNative* chooser = koto_utils_create_image_file_chooser("Choose playlist image"); + + g_signal_connect(chooser, "response", G_CALLBACK(koto_create_modify_playlist_dialog_handle_chooser_response), self); gtk_native_dialog_show(GTK_NATIVE_DIALOG(chooser)); // Show our file chooser } -void koto_create_modify_playlist_dialog_reset(KotoCreateModifyPlaylistDialog *self) { +void koto_create_modify_playlist_dialog_reset(KotoCreateModifyPlaylistDialog * self) { if (!KOTO_IS_CURRENT_MODIFY_PLAYLIST(self)) { return; } @@ -262,12 +331,16 @@ void koto_create_modify_playlist_dialog_reset(KotoCreateModifyPlaylistDialog *se gtk_button_set_label(GTK_BUTTON(self->create_button), "Create"); } -void koto_create_modify_playlist_dialog_set_playlist_uuid(KotoCreateModifyPlaylistDialog *self, gchar *playlist_uuid) { +void koto_create_modify_playlist_dialog_set_playlist_uuid( + KotoCreateModifyPlaylistDialog * self, + gchar * playlist_uuid +) { if (!koto_utils_is_string_valid(playlist_uuid)) { // Not a valid playlist UUID string return; } - KotoPlaylist *playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, playlist_uuid); + KotoPlaylist * playlist = koto_cartographer_get_playlist_by_uuid(koto_maps, playlist_uuid); + if (!KOTO_IS_PLAYLIST(playlist)) { return; @@ -277,7 +350,8 @@ void koto_create_modify_playlist_dialog_set_playlist_uuid(KotoCreateModifyPlayli gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(self->name_entry)), koto_playlist_get_name(playlist), -1); // Update the input buffer gtk_entry_set_placeholder_text(GTK_ENTRY(self->name_entry), ""); // Clear placeholder - gchar *art = koto_playlist_get_artwork(playlist); + gchar * art = koto_playlist_get_artwork(playlist); + if (!koto_utils_is_string_valid(art)) { // If art is not defined gtk_image_set_from_icon_name(GTK_IMAGE(self->playlist_image), "insert-image-symbolic"); // Reset the image @@ -289,13 +363,8 @@ void koto_create_modify_playlist_dialog_set_playlist_uuid(KotoCreateModifyPlayli gtk_button_set_label(GTK_BUTTON(self->create_button), "Save"); } -KotoCreateModifyPlaylistDialog* koto_create_modify_playlist_dialog_new(char *playlist_uuid) { +KotoCreateModifyPlaylistDialog * koto_create_modify_playlist_dialog_new(char * playlist_uuid) { (void) playlist_uuid; - return g_object_new(KOTO_TYPE_CREATE_MODIFY_PLAYLIST_DIALOG, - "orientation", - GTK_ORIENTATION_VERTICAL, - "spacing", - 40, - NULL); + return g_object_new(KOTO_TYPE_CREATE_MODIFY_PLAYLIST_DIALOG, "orientation", GTK_ORIENTATION_VERTICAL, "spacing", 40, NULL); } \ No newline at end of file diff --git a/src/playlist/create-modify-dialog.h b/src/playlist/create-modify-dialog.h index 3d9ad35..0d7d26b 100644 --- a/src/playlist/create-modify-dialog.h +++ b/src/playlist/create-modify-dialog.h @@ -23,7 +23,7 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_CREATE_MODIFY_PLAYLIST_DIALOG koto_create_modify_playlist_dialog_get_type() G_DECLARE_FINAL_TYPE(KotoCreateModifyPlaylistDialog, koto_create_modify_playlist_dialog, KOTO, CREATE_MODIFY_PLAYLIST_DIALOG, GtkBox); @@ -31,14 +31,42 @@ G_DECLARE_FINAL_TYPE(KotoCreateModifyPlaylistDialog, koto_create_modify_playlist /** * Functions -**/ + **/ -KotoCreateModifyPlaylistDialog* koto_create_modify_playlist_dialog_new(); -void koto_create_modify_playlist_dialog_handle_chooser_response(GtkNativeDialog *native, int response, gpointer user_data); -void koto_create_modify_playlist_dialog_handle_create_click(GtkButton *button, gpointer user_data); -gboolean koto_create_modify_playlist_dialog_handle_drop(GtkDropTarget *target, const GValue *val, double x, double y, gpointer user_data); -void koto_create_modify_playlist_dialog_handle_image_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); -void koto_create_modify_playlist_dialog_reset(KotoCreateModifyPlaylistDialog *self); -void koto_create_modify_playlist_dialog_set_playlist_uuid(KotoCreateModifyPlaylistDialog *self, gchar *playlist_uuid); +KotoCreateModifyPlaylistDialog * koto_create_modify_playlist_dialog_new(); + +void koto_create_modify_playlist_dialog_handle_chooser_response( + GtkNativeDialog * native, + int response, + gpointer user_data +); + +void koto_create_modify_playlist_dialog_handle_create_click( + GtkButton * button, + gpointer user_data +); + +gboolean koto_create_modify_playlist_dialog_handle_drop( + GtkDropTarget * target, + const GValue * val, + double x, + double y, + gpointer user_data +); + +void koto_create_modify_playlist_dialog_handle_image_click( + GtkGestureClick * gesture, + int n_press, + double x, + double y, + gpointer user_data +); + +void koto_create_modify_playlist_dialog_reset(KotoCreateModifyPlaylistDialog * self); + +void koto_create_modify_playlist_dialog_set_playlist_uuid( + KotoCreateModifyPlaylistDialog * self, + gchar * playlist_uuid +); G_END_DECLS diff --git a/src/playlist/current.c b/src/playlist/current.c index fb3b333..41a7324 100644 --- a/src/playlist/current.c +++ b/src/playlist/current.c @@ -24,22 +24,37 @@ enum { N_PROPERTIES }; -static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static GParamSpec * props[N_PROPERTIES] = { + NULL, +}; -KotoCurrentPlaylist *current_playlist = NULL; +KotoCurrentPlaylist * current_playlist = NULL; struct _KotoCurrentPlaylist { GObject parent_class; - KotoPlaylist *current_playlist; + KotoPlaylist * current_playlist; }; G_DEFINE_TYPE(KotoCurrentPlaylist, koto_current_playlist, G_TYPE_OBJECT); -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); +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 +); + +static void koto_current_playlist_class_init(KotoCurrentPlaylistClass * c) { + GObjectClass * gobject_class; + -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; @@ -49,18 +64,24 @@ static void koto_current_playlist_class_init(KotoCurrentPlaylistClass *c) { "Current Playlist", "Current Playlist", KOTO_TYPE_PLAYLIST, - G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); } -static void koto_current_playlist_init(KotoCurrentPlaylist *self) { +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); +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: @@ -72,8 +93,14 @@ void koto_current_playlist_get_property(GObject *obj, guint prop_id, GValue *val } } -void koto_current_playlist_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoCurrentPlaylist *self = KOTO_CURRENT_PLAYLIST(obj); +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: @@ -85,11 +112,14 @@ void koto_current_playlist_set_property(GObject *obj, guint prop_id, const GValu } } -KotoPlaylist* koto_current_playlist_get_playlist(KotoCurrentPlaylist *self) { +KotoPlaylist * koto_current_playlist_get_playlist(KotoCurrentPlaylist * self) { return self->current_playlist; } -void koto_current_playlist_set_playlist(KotoCurrentPlaylist *self, KotoPlaylist *playlist) { +void koto_current_playlist_set_playlist( + KotoCurrentPlaylist * self, + KotoPlaylist * playlist +) { if (!KOTO_IS_CURRENT_PLAYLIST(self)) { return; } @@ -99,7 +129,7 @@ void koto_current_playlist_set_playlist(KotoCurrentPlaylist *self, KotoPlaylist } if (self->current_playlist != NULL && KOTO_IS_PLAYLIST(self->current_playlist)) { - gboolean *is_temp = FALSE; + gboolean * is_temp = FALSE; g_object_get(self->current_playlist, "ephemeral", &is_temp, NULL); // Get the current ephemeral value if (is_temp) { // Is a temporary playlist @@ -118,6 +148,6 @@ void koto_current_playlist_set_playlist(KotoCurrentPlaylist *self, KotoPlaylist g_object_notify_by_pspec(G_OBJECT(self), props[PROP_CURRENT_PLAYLIST]); } -KotoCurrentPlaylist* koto_current_playlist_new() { +KotoCurrentPlaylist * koto_current_playlist_new() { return g_object_new(KOTO_TYPE_CURRENT_PLAYLIST, NULL); } diff --git a/src/playlist/current.h b/src/playlist/current.h index 96be2f5..10cddef 100644 --- a/src/playlist/current.h +++ b/src/playlist/current.h @@ -23,7 +23,7 @@ G_BEGIN_DECLS /** * Type Definition -**/ + **/ #define KOTO_TYPE_CURRENT_PLAYLIST koto_current_playlist_get_type() G_DECLARE_FINAL_TYPE(KotoCurrentPlaylist, koto_current_playlist, KOTO, CURRENT_PLAYLIST, GObject); @@ -31,10 +31,15 @@ G_DECLARE_FINAL_TYPE(KotoCurrentPlaylist, koto_current_playlist, KOTO, CURRENT_P /** * Current Playlist Functions -**/ + **/ -KotoCurrentPlaylist* koto_current_playlist_new(); -KotoPlaylist* koto_current_playlist_get_playlist(KotoCurrentPlaylist *self); -void koto_current_playlist_set_playlist(KotoCurrentPlaylist *self, KotoPlaylist *playlist); +KotoCurrentPlaylist * koto_current_playlist_new(); + +KotoPlaylist * koto_current_playlist_get_playlist(KotoCurrentPlaylist * self); + +void koto_current_playlist_set_playlist( + KotoCurrentPlaylist * self, + KotoPlaylist * playlist +); G_END_DECLS diff --git a/src/playlist/playlist.c b/src/playlist/playlist.c index 78e194c..8560992 100644 --- a/src/playlist/playlist.c +++ b/src/playlist/playlist.c @@ -23,8 +23,8 @@ #include "../koto-utils.h" #include "playlist.h" -extern KotoCartographer *koto_maps; -extern sqlite3 *koto_db; +extern KotoCartographer * koto_maps; +extern sqlite3 * koto_db; enum { PROP_0, @@ -46,11 +46,11 @@ enum { struct _KotoPlaylist { GObject parent_instance; - gchar *uuid; - gchar *name; - gchar *art_path; + gchar * uuid; + gchar * name; + gchar * art_path; gint current_position; - gchar *current_uuid; + gchar * current_uuid; KotoPreferredModelType model; @@ -58,32 +58,56 @@ struct _KotoPlaylist { gboolean is_shuffle_enabled; gboolean finalized; - GListStore *store; - GQueue *sorted_tracks; + GListStore * store; + GQueue * sorted_tracks; - GQueue *tracks; // This is effectively our vanilla value that should never change - GQueue *played_tracks; + GQueue * tracks; // This is effectively our vanilla value that should never change + GQueue * played_tracks; }; struct _KotoPlaylistClass { GObjectClass parent_class; - void (* modified) (KotoPlaylist *playlist); - void (* track_added) (KotoPlaylist *playlist, gchar *track_uuid); - void (* track_load_finalized) (KotoPlaylist *playlist); - void (* track_removed) (KotoPlaylist *playlist, gchar *track_uuid); + void (* modified) (KotoPlaylist * playlist); + void (* track_added) ( + KotoPlaylist * playlist, + gchar * track_uuid + ); + void (* track_load_finalized) (KotoPlaylist * playlist); + void (* track_removed) ( + KotoPlaylist * playlist, + gchar * track_uuid + ); }; G_DEFINE_TYPE(KotoPlaylist, koto_playlist, G_TYPE_OBJECT); -static GParamSpec *props[N_PROPERTIES] = { NULL }; -static guint playlist_signals[N_SIGNALS] = { 0 }; +static GParamSpec * props[N_PROPERTIES] = { + NULL +}; +static guint playlist_signals[N_SIGNALS] = { + 0 +}; + +static void koto_playlist_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +); + +; +static void koto_playlist_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +); + +static void koto_playlist_class_init(KotoPlaylistClass * c) { + GObjectClass * gobject_class; -static void koto_playlist_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);; -static void koto_playlist_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); -static void koto_playlist_class_init(KotoPlaylistClass *c) { - GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS(c); gobject_class->set_property = koto_playlist_set_property; gobject_class->get_property = koto_playlist_get_property; @@ -93,7 +117,7 @@ static void koto_playlist_class_init(KotoPlaylistClass *c) { "UUID of the Playlist", "UUID of the Playlist", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_NAME] = g_param_spec_string( @@ -101,7 +125,7 @@ static void koto_playlist_class_init(KotoPlaylistClass *c) { "Name of the Playlist", "Name of the Playlist", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_ART_PATH] = g_param_spec_string( @@ -109,7 +133,7 @@ static void koto_playlist_class_init(KotoPlaylistClass *c) { "Path to any associated artwork of the Playlist", "Path to any associated artwork of the Playlist", NULL, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_EPHEMERAL] = g_param_spec_boolean( @@ -117,7 +141,7 @@ static void koto_playlist_class_init(KotoPlaylistClass *c) { "Is the playlist ephemeral (temporary)", "Is the playlist ephemeral (temporary)", FALSE, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); props[PROP_IS_SHUFFLE_ENABLED] = g_param_spec_boolean( @@ -125,7 +149,7 @@ static void koto_playlist_class_init(KotoPlaylistClass *c) { "Is shuffling enabled", "Is shuffling enabled", FALSE, - G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE ); g_object_class_install_properties(gobject_class, N_PROPERTIES, props); @@ -181,8 +205,14 @@ static void koto_playlist_class_init(KotoPlaylistClass *c) { ); } -static void koto_playlist_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { - KotoPlaylist *self = KOTO_PLAYLIST(obj); +static void koto_playlist_get_property( + GObject * obj, + guint prop_id, + GValue * val, + GParamSpec * spec +) { + KotoPlaylist * self = KOTO_PLAYLIST(obj); + switch (prop_id) { case PROP_UUID: @@ -206,8 +236,14 @@ static void koto_playlist_get_property(GObject *obj, guint prop_id, GValue *val, } } -static void koto_playlist_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { - KotoPlaylist *self = KOTO_PLAYLIST(obj); +static void koto_playlist_set_property( + GObject * obj, + guint prop_id, + const GValue * val, + GParamSpec * spec +) { + KotoPlaylist * self = KOTO_PLAYLIST(obj); + switch (prop_id) { case PROP_UUID: @@ -231,7 +267,7 @@ static void koto_playlist_set_property(GObject *obj, guint prop_id, const GValue } } -static void koto_playlist_init(KotoPlaylist *self) { +static void koto_playlist_init(KotoPlaylist * self) { self->current_position = -1; // Default to -1 so first time incrementing puts it at 0 self->current_uuid = NULL; self->model = KOTO_PREFERRED_MODEL_TYPE_DEFAULT; // Default to default model @@ -245,7 +281,10 @@ static void koto_playlist_init(KotoPlaylist *self) { self->store = g_list_store_new(KOTO_TYPE_INDEXED_TRACK); } -void koto_playlist_add_to_played_tracks(KotoPlaylist *self, gchar *uuid) { +void koto_playlist_add_to_played_tracks( + KotoPlaylist * self, + gchar * uuid +) { if (g_queue_index(self->played_tracks, uuid) != -1) { // Already added return; } @@ -253,18 +292,31 @@ void koto_playlist_add_to_played_tracks(KotoPlaylist *self, gchar *uuid) { g_queue_push_tail(self->played_tracks, uuid); // Add to end } -void koto_playlist_add_track(KotoPlaylist *self, KotoIndexedTrack *track, gboolean current, gboolean commit_to_table) { +void koto_playlist_add_track( + KotoPlaylist * self, + KotoIndexedTrack * track, + gboolean current, + gboolean commit_to_table +) { koto_playlist_add_track_by_uuid(self, koto_indexed_track_get_uuid(track), current, commit_to_table); } -void koto_playlist_add_track_by_uuid(KotoPlaylist *self, gchar *uuid, gboolean current, gboolean commit_to_table) { - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, uuid); // Get the track +void koto_playlist_add_track_by_uuid( + KotoPlaylist * self, + gchar * uuid, + gboolean current, + gboolean commit_to_table +) { + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, uuid); // Get the track + if (!KOTO_IS_INDEXED_TRACK(track)) { return; } - GList *found_tracks_uuids = g_queue_find_custom(self->tracks, uuid, koto_playlist_compare_track_uuids); + GList * found_tracks_uuids = g_queue_find_custom(self->tracks, uuid, koto_playlist_compare_track_uuids); + + if (found_tracks_uuids != NULL) { // Is somewhere in the tracks already g_list_free(found_tracks_uuids); return; @@ -296,8 +348,13 @@ void koto_playlist_add_track_by_uuid(KotoPlaylist *self, gchar *uuid, gboolean c ); } -void koto_playlist_apply_model(KotoPlaylist *self, KotoPreferredModelType preferred_model) { - GList *sort_user_data = NULL; +void koto_playlist_apply_model( + KotoPlaylist * self, + KotoPreferredModelType preferred_model +) { + GList * sort_user_data = NULL; + + sort_user_data = g_list_prepend(sort_user_data, GUINT_TO_POINTER(preferred_model)); // Prepend our preferred model first sort_user_data = g_list_prepend(sort_user_data, self); // Prepend ourself @@ -307,16 +364,16 @@ void koto_playlist_apply_model(KotoPlaylist *self, KotoPreferredModelType prefer self->model = preferred_model; // Update our preferred model /*if (self->current_position != -1) { // Have a position set - koto_playlist_set_track_as_current(self, self->current_uuid); // Update the position based on the new model just by setting it as current again - }*/ + koto_playlist_set_track_as_current(self, self->current_uuid); // Update the position based on the new model just by setting it as current again + }*/ } -void koto_playlist_commit(KotoPlaylist *self) { +void koto_playlist_commit(KotoPlaylist * self) { if (self->ephemeral) { // Temporary playlist return; } - gchar *commit_op = g_strdup_printf( + gchar * commit_op = g_strdup_printf( "INSERT INTO playlist_meta(id, name, art_path, preferred_model)" "VALUES('%s', quote(\"%s\"), quote(\"%s\"), 0)" "ON CONFLICT(id) DO UPDATE SET name=excluded.name, art_path=excluded.art_path;", @@ -325,9 +382,10 @@ void koto_playlist_commit(KotoPlaylist *self) { self->art_path ); - gchar *commit_op_errmsg = NULL; + gchar * commit_op_errmsg = NULL; int rc = sqlite3_exec(koto_db, commit_op, 0, 0, &commit_op_errmsg); + if (rc != SQLITE_OK) { g_warning("Failed to save playlist: %s", commit_op_errmsg); } else { // Successfully saved our playlist @@ -338,49 +396,59 @@ void koto_playlist_commit(KotoPlaylist *self) { g_free(commit_op_errmsg); } -void koto_playlist_commit_tracks(gpointer data, gpointer user_data) { - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, data); // Get the track +void koto_playlist_commit_tracks( + gpointer data, + gpointer user_data +) { + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, data); // Get the track + if (track == NULL) { // Not a track - KotoPlaylist *self = user_data; - gchar *playlist_uuid = self->uuid; // Get the playlist UUID + KotoPlaylist * self = user_data; + gchar * playlist_uuid = self->uuid; // Get the playlist UUID - gchar *current_track = g_queue_peek_nth(self->tracks, self->current_position); // Get the UUID of the current track + gchar * current_track = g_queue_peek_nth(self->tracks, self->current_position); // Get the UUID of the current track //koto_indexed_track_save_to_playlist(track, playlist_uuid, (data == current_track) ? 1 : 0); // Call to save the playlist to the track g_free(playlist_uuid); g_free(current_track); } } -gint koto_playlist_compare_track_uuids(gconstpointer a, gconstpointer b) { +gint koto_playlist_compare_track_uuids( + gconstpointer a, + gconstpointer b +) { return g_strcmp0(a, b); } -gchar* koto_playlist_get_artwork(KotoPlaylist *self) { +gchar * koto_playlist_get_artwork(KotoPlaylist * self) { return (self->art_path == NULL) ? NULL : g_strdup(self->art_path); // Return a duplicate of our art path } -KotoPreferredModelType koto_playlist_get_current_model(KotoPlaylist *self) { +KotoPreferredModelType koto_playlist_get_current_model(KotoPlaylist * self) { return self->model; } -guint koto_playlist_get_current_position(KotoPlaylist *self) { +guint koto_playlist_get_current_position(KotoPlaylist * self) { return self->current_position; } -gboolean koto_playlist_get_is_finalized(KotoPlaylist *self) { +gboolean koto_playlist_get_is_finalized(KotoPlaylist * self) { return self->finalized; } -guint koto_playlist_get_length(KotoPlaylist *self) { +guint koto_playlist_get_length(KotoPlaylist * self) { return g_queue_get_length(self->tracks); // Get the length of the tracks } -gchar* koto_playlist_get_name(KotoPlaylist *self) { +gchar * koto_playlist_get_name(KotoPlaylist * self) { return (self->name == NULL) ? NULL : g_strdup(self->name); } -gint koto_playlist_get_position_of_track(KotoPlaylist *self, KotoIndexedTrack *track) { +gint koto_playlist_get_position_of_track( + KotoPlaylist * self, + KotoIndexedTrack * track +) { if (!KOTO_IS_PLAYLIST(self)) { return -1; } @@ -396,17 +464,19 @@ gint koto_playlist_get_position_of_track(KotoPlaylist *self, KotoIndexedTrack *t gint position = -1; guint found_pos = 0; - if (g_list_store_find(self->store , track, &found_pos)) { // Found the item + + if (g_list_store_find(self->store, track, &found_pos)) { // Found the item position = (gint) found_pos; // Cast our found position from guint to gint } return position; } -gchar* koto_playlist_get_random_track(KotoPlaylist *self) { - gchar *track_uuid = NULL; +gchar * koto_playlist_get_random_track(KotoPlaylist * self) { + gchar * track_uuid = NULL; guint tracks_len = g_queue_get_length(self->sorted_tracks); + if (tracks_len == g_queue_get_length(self->played_tracks)) { // Played all tracks track_uuid = g_list_nth_data(self->sorted_tracks->head, 0); // Get the first g_queue_clear(self->played_tracks); // Clear our played tracks @@ -414,10 +484,10 @@ gchar* koto_playlist_get_random_track(KotoPlaylist *self) { GRand* rando_calrissian = g_rand_new(); // Create a new RNG guint attempt = 0; - while (track_uuid == NULL) { // Haven't selected a track yet + while (track_uuid == NULL) { // Haven't selected a track yet attempt++; gint32 selected_item = g_rand_int_range(rando_calrissian, 0, (gint32) tracks_len); - gchar *selected_track = g_queue_peek_nth(self->sorted_tracks, (guint) selected_item); // Get the UUID of the selected item + gchar * selected_track = g_queue_peek_nth(self->sorted_tracks, (guint) selected_item); // Get the UUID of the selected item if (g_queue_index(self->played_tracks, selected_track) == -1) { // Haven't played the track self->current_position = (gint) selected_item; @@ -436,25 +506,25 @@ gchar* koto_playlist_get_random_track(KotoPlaylist *self) { return track_uuid; } -GListStore* koto_playlist_get_store(KotoPlaylist *self) { +GListStore * koto_playlist_get_store(KotoPlaylist * self) { return self->store; } -GQueue* koto_playlist_get_tracks(KotoPlaylist *self) { +GQueue * koto_playlist_get_tracks(KotoPlaylist * self) { return self->tracks; } -gchar* koto_playlist_get_uuid(KotoPlaylist *self) { +gchar * koto_playlist_get_uuid(KotoPlaylist * self) { return g_strdup(self->uuid); } -gchar* koto_playlist_go_to_next(KotoPlaylist *self) { +gchar * koto_playlist_go_to_next(KotoPlaylist * self) { if (!KOTO_IS_PLAYLIST(self)) { return NULL; } if (self->is_shuffle_enabled) { // Shuffling enabled - gchar *random_track_uuid = koto_playlist_get_random_track(self); // Get a random track + gchar * random_track_uuid = koto_playlist_get_random_track(self); // Get a random track koto_playlist_add_to_played_tracks(self, random_track_uuid); return random_track_uuid; } @@ -462,7 +532,7 @@ gchar* koto_playlist_go_to_next(KotoPlaylist *self) { if (!koto_utils_is_string_valid(self->current_uuid)) { // No valid UUID yet self->current_position++; } else { // Have a UUID currently - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, self->current_uuid); + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, self->current_uuid); if (!KOTO_IS_INDEXED_TRACK(track)) { return NULL; @@ -474,7 +544,7 @@ gchar* koto_playlist_go_to_next(KotoPlaylist *self) { return NULL; } - self->current_position = pos_of_song+1; // Increment our position based on position of song + self->current_position = pos_of_song + 1; // Increment our position based on position of song } self->current_uuid = g_queue_peek_nth(self->sorted_tracks, self->current_position); @@ -483,7 +553,7 @@ gchar* koto_playlist_go_to_next(KotoPlaylist *self) { return self->current_uuid; } -gchar* koto_playlist_go_to_previous(KotoPlaylist *self) { +gchar * koto_playlist_go_to_previous(KotoPlaylist * self) { if (self->is_shuffle_enabled) { // Shuffling enabled return koto_playlist_get_random_track(self); // Get a random track } @@ -492,7 +562,8 @@ gchar* koto_playlist_go_to_previous(KotoPlaylist *self) { return NULL; } - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, self->current_uuid); + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, self->current_uuid); + if (!KOTO_IS_INDEXED_TRACK(track)) { return NULL; @@ -500,6 +571,7 @@ gchar* koto_playlist_go_to_previous(KotoPlaylist *self) { gint pos_of_song = koto_playlist_get_position_of_track(self, track); // Get the position of the current track based on the current model + if (pos_of_song == 0) { return NULL; } @@ -510,14 +582,14 @@ gchar* koto_playlist_go_to_previous(KotoPlaylist *self) { return self->current_uuid; } -void koto_playlist_mark_as_finalized(KotoPlaylist *self) { +void koto_playlist_mark_as_finalized(KotoPlaylist * self) { if (self->finalized) { // Already finalized return; } self->finalized = TRUE; koto_playlist_apply_model(self, self->model); // Re-apply our model to enforce mass sort - + g_signal_emit( self, playlist_signals[SIGNAL_TRACK_LOAD_FINALIZED], @@ -525,24 +597,34 @@ void koto_playlist_mark_as_finalized(KotoPlaylist *self) { ); } -gint koto_playlist_model_sort_by_uuid(gconstpointer first_item, gconstpointer second_item, gpointer data_list) { - KotoIndexedTrack *first_track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) first_item); - KotoIndexedTrack *second_track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) second_item); +gint koto_playlist_model_sort_by_uuid( + gconstpointer first_item, + gconstpointer second_item, + gpointer data_list +) { + KotoIndexedTrack * first_track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) first_item); + KotoIndexedTrack * second_track = koto_cartographer_get_track_by_uuid(koto_maps, (gchar*) second_item); + return koto_playlist_model_sort_by_track(first_track, second_track, data_list); } -gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer second_item, gpointer data_list) { - KotoIndexedTrack *first_track = (KotoIndexedTrack*) first_item; - KotoIndexedTrack *second_track = (KotoIndexedTrack*) second_item; +gint koto_playlist_model_sort_by_track( + gconstpointer first_item, + gconstpointer second_item, + gpointer data_list +) { + KotoIndexedTrack * first_track = (KotoIndexedTrack*) first_item; + KotoIndexedTrack * second_track = (KotoIndexedTrack*) second_item; GList* ptr_list = data_list; - KotoPlaylist *self = g_list_nth_data(ptr_list, 0); // First item in the GPtrArray is a pointer to our playlist + KotoPlaylist * self = g_list_nth_data(ptr_list, 0); // First item in the GPtrArray is a pointer to our playlist KotoPreferredModelType model = GPOINTER_TO_UINT(g_list_nth_data(ptr_list, 1)); // Second item in the GPtrArray is a pointer to our KotoPreferredModelType + if ( - (model == KOTO_PREFERRED_MODEL_TYPE_DEFAULT) || // Newest first model - (model == KOTO_PREFERRED_MODEL_TYPE_OLDEST_FIRST) // Oldest first + (model == KOTO_PREFERRED_MODEL_TYPE_DEFAULT) || // Newest first model + (model == KOTO_PREFERRED_MODEL_TYPE_OLDEST_FIRST) // Oldest first ) { gint first_track_pos = g_queue_index(self->tracks, koto_indexed_track_get_uuid(first_track)); gint second_track_pos = g_queue_index(self->tracks, koto_indexed_track_get_uuid(second_track)); @@ -563,8 +645,8 @@ gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer s } if (model == KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ALBUM) { // Sort by album name - gchar *first_album_uuid = NULL; - gchar *second_album_uuid = NULL; + gchar * first_album_uuid = NULL; + gchar * second_album_uuid = NULL; g_object_get( first_track, @@ -586,8 +668,8 @@ gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer s return 0; // Don't get too granular, just consider them equal } - KotoIndexedAlbum *first_album = koto_cartographer_get_album_by_uuid(koto_maps, first_album_uuid); - KotoIndexedAlbum *second_album = koto_cartographer_get_album_by_uuid(koto_maps, second_album_uuid); + KotoIndexedAlbum * first_album = koto_cartographer_get_album_by_uuid(koto_maps, first_album_uuid); + KotoIndexedAlbum * second_album = koto_cartographer_get_album_by_uuid(koto_maps, second_album_uuid); g_free(first_album_uuid); g_free(second_album_uuid); @@ -600,8 +682,8 @@ gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer s } if (model == KOTO_PREFERRED_MODEL_TYPE_SORT_BY_ARTIST) { // Sort by artist name - gchar *first_artist_uuid = NULL; - gchar *second_artist_uuid = NULL; + gchar * first_artist_uuid = NULL; + gchar * second_artist_uuid = NULL; g_object_get( first_track, @@ -617,8 +699,8 @@ gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer s NULL ); - KotoIndexedArtist *first_artist = koto_cartographer_get_artist_by_uuid(koto_maps, first_artist_uuid); - KotoIndexedArtist *second_artist = koto_cartographer_get_artist_by_uuid(koto_maps, second_artist_uuid); + KotoIndexedArtist * first_artist = koto_cartographer_get_artist_by_uuid(koto_maps, first_artist_uuid); + KotoIndexedArtist * second_artist = koto_cartographer_get_artist_by_uuid(koto_maps, second_artist_uuid); g_free(first_artist_uuid); g_free(second_artist_uuid); @@ -631,8 +713,8 @@ gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer s } if (model == KOTO_PREFERRED_MODEL_TYPE_SORT_BY_TRACK_NAME) { // Track name - gchar *first_track_name = NULL; - gchar *second_track_name = NULL; + gchar * first_track_name = NULL; + gchar * second_track_name = NULL; g_object_get( first_track, @@ -658,28 +740,37 @@ gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer s return 0; } -void koto_playlist_remove_from_played_tracks(KotoPlaylist *self, gchar *uuid) { +void koto_playlist_remove_from_played_tracks( + KotoPlaylist * self, + gchar * uuid +) { g_queue_remove(self->played_tracks, uuid); } -void koto_playlist_remove_track_by_uuid(KotoPlaylist *self, gchar *uuid) { +void koto_playlist_remove_track_by_uuid( + KotoPlaylist * self, + gchar * uuid +) { if (!KOTO_IS_PLAYLIST(self)) { return; } gint file_index = g_queue_index(self->tracks, uuid); // Get the position of this uuid + if (file_index != -1) { // Have in tracks g_queue_pop_nth(self->tracks, file_index); // Remove nth where it is the file index } gint file_index_in_sorted = g_queue_index(self->sorted_tracks, uuid); // Get position in sorted tracks + if (file_index_in_sorted != -1) { // Have in sorted tracks g_queue_pop_nth(self->sorted_tracks, file_index_in_sorted); // Remove nth where it is the index in sorted tracks } - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, uuid); // Get the track + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, uuid); // Get the track + if (!KOTO_IS_INDEXED_TRACK(track)) { // Is not a track return; @@ -687,6 +778,7 @@ void koto_playlist_remove_track_by_uuid(KotoPlaylist *self, gchar *uuid) { guint position = 0; + if (g_list_store_find(self->store, track, &position)) { // Got the position g_list_store_remove(self->store, position); // Remove from the store } @@ -701,13 +793,17 @@ void koto_playlist_remove_track_by_uuid(KotoPlaylist *self, gchar *uuid) { ); } -void koto_playlist_set_artwork(KotoPlaylist *self, const gchar *path) { +void koto_playlist_set_artwork( + KotoPlaylist * self, + const gchar * path +) { if (path == NULL) { return; } magic_t cookie = magic_open(MAGIC_MIME); // Create our magic cookie so we can validate if what we are setting is an image + if (cookie == NULL) { // Failed to allocate return; } @@ -716,7 +812,8 @@ void koto_playlist_set_artwork(KotoPlaylist *self, const gchar *path) { goto free_cookie; } - const gchar *mime_type = magic_file(cookie, path); // Get the mimetype for this file + const gchar * mime_type = magic_file(cookie, path); // Get the mimetype for this file + if ((mime_type == NULL) || !g_str_has_prefix(mime_type, "image/")) { // Failed to get our mimetype or not an image goto free_cookie; @@ -737,10 +834,13 @@ void koto_playlist_set_artwork(KotoPlaylist *self, const gchar *path) { } free_cookie: - magic_close(cookie); // Close and free the cookie to the cookie monster + magic_close(cookie); // Close and free the cookie to the cookie monster } -void koto_playlist_set_name(KotoPlaylist *self, const gchar *name) { +void koto_playlist_set_name( + KotoPlaylist * self, + const gchar * name +) { if (name == NULL) { return; } @@ -760,19 +860,29 @@ void koto_playlist_set_name(KotoPlaylist *self, const gchar *name) { } } -void koto_playlist_set_position(KotoPlaylist *self, gint position) { +void koto_playlist_set_position( + KotoPlaylist * self, + gint position +) { self->current_position = position; } -void koto_playlist_set_track_as_current(KotoPlaylist *self, gchar *track_uuid) { +void koto_playlist_set_track_as_current( + KotoPlaylist * self, + gchar * track_uuid +) { gint position_of_track = g_queue_index(self->sorted_tracks, track_uuid); // Get the position of the UUID in our tracks + if (position_of_track != -1) { // In tracks self->current_position = position_of_track; } } -void koto_playlist_set_uuid(KotoPlaylist *self, const gchar *uuid) { +void koto_playlist_set_uuid( + KotoPlaylist * self, + const gchar * uuid +) { if (uuid == NULL) { // No actual UUID return; } @@ -784,9 +894,13 @@ void koto_playlist_set_uuid(KotoPlaylist *self, const gchar *uuid) { self->uuid = g_strdup(uuid); // Set the new UUID } -void koto_playlist_tracks_queue_push_to_store(gpointer data, gpointer user_data) { - gchar *track_uuid = (gchar *) data; - KotoIndexedTrack *track = koto_cartographer_get_track_by_uuid(koto_maps, track_uuid); +void koto_playlist_tracks_queue_push_to_store( + gpointer data, + gpointer user_data +) { + gchar * track_uuid = (gchar*) data; + KotoIndexedTrack * track = koto_cartographer_get_track_by_uuid(koto_maps, track_uuid); + if (!KOTO_IS_INDEXED_TRACK(track)) { // Not a track return; @@ -795,20 +909,24 @@ void koto_playlist_tracks_queue_push_to_store(gpointer data, gpointer user_data) g_list_store_append(G_LIST_STORE(user_data), track); } -void koto_playlist_unmap(KotoPlaylist *self) { +void koto_playlist_unmap(KotoPlaylist * self) { koto_cartographer_remove_playlist_by_uuid(koto_maps, self->uuid); // Remove from our cartographer } -KotoPlaylist* koto_playlist_new() { - return g_object_new(KOTO_TYPE_PLAYLIST, - "uuid", g_uuid_string_random(), +KotoPlaylist * koto_playlist_new() { + return g_object_new( + KOTO_TYPE_PLAYLIST, + "uuid", + g_uuid_string_random(), NULL ); } -KotoPlaylist* koto_playlist_new_with_uuid(const gchar *uuid) { - return g_object_new(KOTO_TYPE_PLAYLIST, - "uuid", uuid, +KotoPlaylist * koto_playlist_new_with_uuid(const gchar * uuid) { + return g_object_new( + KOTO_TYPE_PLAYLIST, + "uuid", + uuid, NULL ); } diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 65d05cc..4a277be 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -32,10 +32,10 @@ typedef enum { /** * Type Definition -**/ + **/ #define KOTO_TYPE_PLAYLIST koto_playlist_get_type() -#define KOTO_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), KOTO_TYPE_PLAYLIST, KotoPlaylist)) +#define KOTO_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KOTO_TYPE_PLAYLIST, KotoPlaylist)) #define KOTO_IS_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KOTO_TYPE_PLAYLIST)) typedef struct _KotoPlaylist KotoPlaylist; @@ -46,41 +46,131 @@ GType koto_playlist_get_type(void) G_GNUC_CONST; /** * Playlist Functions -**/ + **/ -KotoPlaylist* koto_playlist_new(); -KotoPlaylist* koto_playlist_new_with_uuid(const gchar *uuid); -void koto_playlist_add_to_played_tracks(KotoPlaylist *self, gchar *uuid); -void koto_playlist_add_track(KotoPlaylist *self, KotoIndexedTrack *track, gboolean current, gboolean commit_to_table); -void koto_playlist_add_track_by_uuid(KotoPlaylist *self, gchar *uuid, gboolean current, gboolean commit_to_table); -void koto_playlist_apply_model(KotoPlaylist *self, KotoPreferredModelType preferred_model); -void koto_playlist_commit(KotoPlaylist *self); -void koto_playlist_commit_tracks(gpointer data, gpointer user_data); -gint koto_playlist_compare_track_uuids(gconstpointer a, gconstpointer b); -gchar* koto_playlist_get_artwork(KotoPlaylist *self); -KotoPreferredModelType koto_playlist_get_current_model(KotoPlaylist *self); -guint koto_playlist_get_current_position(KotoPlaylist *self); -guint koto_playlist_get_length(KotoPlaylist *self); -gboolean koto_playlist_get_is_finalized(KotoPlaylist *self); -gchar* koto_playlist_get_name(KotoPlaylist *self); -gint koto_playlist_get_position_of_track(KotoPlaylist *self, KotoIndexedTrack *track); -GListStore* koto_playlist_get_store(KotoPlaylist *self); -GQueue* koto_playlist_get_tracks(KotoPlaylist *self); -gchar* koto_playlist_get_uuid(KotoPlaylist *self); -gchar* koto_playlist_go_to_next(KotoPlaylist *self); -gchar* koto_playlist_go_to_previous(KotoPlaylist *self); -void koto_playlist_mark_as_finalized(KotoPlaylist *self); -gint koto_playlist_model_sort_by_uuid(gconstpointer first_item, gconstpointer second_item, gpointer data_list); -gint koto_playlist_model_sort_by_track(gconstpointer first_item, gconstpointer second_item, gpointer model_ptr); -void koto_playlist_remove_from_played_tracks(KotoPlaylist *self, gchar *uuid); -void koto_playlist_remove_track_by_uuid(KotoPlaylist *self, gchar *uuid); -void koto_playlist_set_artwork(KotoPlaylist *self, const gchar *path); -void koto_playlist_save_state(KotoPlaylist *self); -void koto_playlist_set_name(KotoPlaylist *self, const gchar *name); -void koto_playlist_set_position(KotoPlaylist *self, gint position); -void koto_playlist_set_track_as_current(KotoPlaylist *self, gchar *track_uuid); -void koto_playlist_set_uuid(KotoPlaylist *self, const gchar *uuid); -void koto_playlist_tracks_queue_push_to_store(gpointer data, gpointer user_data); -void koto_playlist_unmap(KotoPlaylist *self); +KotoPlaylist * koto_playlist_new(); + +KotoPlaylist * koto_playlist_new_with_uuid(const gchar * uuid); + +void koto_playlist_add_to_played_tracks( + KotoPlaylist * self, + gchar * uuid +); + +void koto_playlist_add_track( + KotoPlaylist * self, + KotoIndexedTrack * track, + gboolean current, + gboolean commit_to_table +); + +void koto_playlist_add_track_by_uuid( + KotoPlaylist * self, + gchar * uuid, + gboolean current, + gboolean commit_to_table +); + +void koto_playlist_apply_model( + KotoPlaylist * self, + KotoPreferredModelType preferred_model +); + +void koto_playlist_commit(KotoPlaylist * self); + +void koto_playlist_commit_tracks( + gpointer data, + gpointer user_data +); + +gint koto_playlist_compare_track_uuids( + gconstpointer a, + gconstpointer b +); + +gchar * koto_playlist_get_artwork(KotoPlaylist * self); + +KotoPreferredModelType koto_playlist_get_current_model(KotoPlaylist * self); + +guint koto_playlist_get_current_position(KotoPlaylist * self); + +guint koto_playlist_get_length(KotoPlaylist * self); + +gboolean koto_playlist_get_is_finalized(KotoPlaylist * self); + +gchar * koto_playlist_get_name(KotoPlaylist * self); + +gint koto_playlist_get_position_of_track( + KotoPlaylist * self, + KotoIndexedTrack * track +); + +GListStore * koto_playlist_get_store(KotoPlaylist * self); + +GQueue * koto_playlist_get_tracks(KotoPlaylist * self); + +gchar * koto_playlist_get_uuid(KotoPlaylist * self); + +gchar * koto_playlist_go_to_next(KotoPlaylist * self); + +gchar * koto_playlist_go_to_previous(KotoPlaylist * self); + +void koto_playlist_mark_as_finalized(KotoPlaylist * self); + +gint koto_playlist_model_sort_by_uuid( + gconstpointer first_item, + gconstpointer second_item, + gpointer data_list +); + +gint koto_playlist_model_sort_by_track( + gconstpointer first_item, + gconstpointer second_item, + gpointer model_ptr +); + +void koto_playlist_remove_from_played_tracks( + KotoPlaylist * self, + gchar * uuid +); + +void koto_playlist_remove_track_by_uuid( + KotoPlaylist * self, + gchar * uuid +); + +void koto_playlist_set_artwork( + KotoPlaylist * self, + const gchar * path +); + +void koto_playlist_save_state(KotoPlaylist * self); + +void koto_playlist_set_name( + KotoPlaylist * self, + const gchar * name +); + +void koto_playlist_set_position( + KotoPlaylist * self, + gint position +); + +void koto_playlist_set_track_as_current( + KotoPlaylist * self, + gchar * track_uuid +); + +void koto_playlist_set_uuid( + KotoPlaylist * self, + const gchar * uuid +); + +void koto_playlist_tracks_queue_push_to_store( + gpointer data, + gpointer user_data +); + +void koto_playlist_unmap(KotoPlaylist * self); G_END_DECLS