Fix typo: Similar Artist -> Similar Artists
[gmpc.git] / src / playlist3.c
bloba7f147008b8798cdd5f83d3ad61ff100160d251b
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <gtk/gtk.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <config.h>
25 #include "main.h"
26 #include "plugin.h"
27 #include "misc.h"
28 #include "playlist3.h"
29 #include "preferences.h"
30 #include "revision.h"
31 #include "gmpc-metaimage.h"
32 #include "gmpc-extras.h"
33 #include "GUI/cmd.h"
34 #include "GUI/status_icon.h"
35 #include "GUI/title_header.h"
36 #include "GUI/control_window.h"
38 #define ALBUM_SIZE 42
40 #define LOG_DOMAIN "Playlist"
42 /* Drag and drop Target table */
43 static GtkTargetEntry target_table[] =
45 {(gchar *) "x-url/http", 0, 0},
46 {(gchar *) "_NETSCAPE_URL", 0, 1},
47 {(gchar *) "text/uri-list", 0, 2},
48 {(gchar *) "audio/*", 0, 3},
49 {(gchar *) "audio/x-scpls", 0, 4},
50 {(gchar *) "internal-drop", 0, 99}
53 GtkWidget *metaimage_album_art = NULL;
54 GtkWidget *metaimage_artist_art = NULL;
55 GmpcFavoritesButton *favorites_button = NULL;
57 GtkCellRenderer *sidebar_text = NULL;
58 /**
59 * Widgets used in the header.
60 * and the new progresbar
62 static GtkWidget *new_pb = NULL;
64 /**
65 * Indicates the zoom level and the previous zoom level.
67 int pl3_zoom = PLAYLIST_NO_ZOOM;
68 int pl3_old_zoom = PLAYLIST_NO_ZOOM;
70 static void playlist_zoom_level_changed(void);
71 void playlist_zoom_in(void);
72 void playlist_zoom_out(void);
75 void pl3_pb_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data);
77 void set_browser_format(void);
78 void set_playlist_format(void);
80 gboolean playlist_player_volume_changed(GtkWidget * vol_but, double new_vol);
82 /* Glade declarations, otherwise these would be static */
83 void about_window(void);
84 int pl3_cat_tree_button_press_event(GtkTreeView *, GdkEventButton *);
85 int pl3_cat_tree_button_release_event(GtkTreeView *, GdkEventButton *);
86 int pl3_window_key_release_event(GtkWidget * mw, GdkEventKey * event);
88 void cur_song_center_enable_tb(GtkToggleButton *);
89 void show_cover_case_tb(GtkToggleButton * but);
90 void save_possize_enable_tb(GtkToggleButton *);
91 void playlist_menu_repeat_changed(GtkToggleAction *);
92 void playlist_menu_single_mode_changed(GtkToggleAction * );
93 void playlist_menu_consume_changed(GtkToggleAction * );
95 void playlist_menu_random_changed(GtkToggleAction *);
96 void playlist_menu_artist_image_changed(GtkToggleAction *);
97 void hide_on_close_enable_tb(GtkToggleButton * but);
98 gboolean pl3_close(void);
99 static void pl3_update_profiles_menu(GmpcProfiles * prof, const int changed, const int col, const gchar * id);
100 gboolean playlist3_enter_notify_event(GtkWidget * wid, GdkEventCrossing * event, gpointer data);
101 gboolean playlist3_leave_notify_event(GtkWidget * wid, GdkEventCrossing * event, gpointer data);
102 gboolean pl3_window_focus_out_event(GtkWidget *window, GdkEventFocus *event, gpointer data);
104 static void pl3_profiles_changed(GmpcProfiles * prof, const int changed, const int col, const gchar * id);
105 static void playlist3_server_output_changed(GtkWidget * item, gpointer data);
106 static void playlist3_fill_server_menu(void);
107 void playlist3_server_update_db(void);
109 void easy_command_help_window(void);
111 void pl3_style_set_event(GtkWidget *widget, GtkStyle *previous_style, gpointer user_data);
113 void pl3_sidebar_plugins_init(void);
114 static gboolean pl3_cat_select_function(GtkTreeSelection *select, GtkTreeModel *model, GtkTreePath *path, gboolean cur_select, gpointer data);
116 /* Old category browser style */
117 static int old_type = -1;
119 /* interface description */
120 GtkBuilder *pl3_xml = NULL;
121 /* category treeview-store */
122 GtkTreeModel *pl3_tree = NULL;
124 /* size */
125 static GtkAllocation pl3_wsize = { 0, 0, 0, 0 };
127 static int pl3_hidden = TRUE;
129 static void playlist_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata);
131 /* Playlist "Plugin" */
132 static void playlist_pref_construct(GtkWidget * container);
133 static void playlist_pref_destroy(GtkWidget * container);
135 static GtkBuilder *playlist_pref_xml = NULL;
137 void ck_search_as_you_type(GtkToggleButton * but);
140 /* Get the type of the selected row..
141 * -1 means no row selected
143 int pl3_cat_get_selected_browser(void)
145 return old_type;
152 * Extras for better integration
155 void init_extra_playlist_state(void);
156 void enable_extra_playlist(GtkToggleAction *action);
158 /**************************************************
159 * Category Tree
161 static void pl3_initialize_tree(void)
163 int i;
164 GtkTreePath *path;
165 GtkTreeSelection *sel;
166 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
168 INIT_TIC_TAC()
170 path = gtk_tree_path_new_from_string("0");
171 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml, "cat_tree")));
172 TEC("Get selection");
173 for (i = 0; i < num_plugins; i++)
175 if (gmpc_plugin_is_browser(plugins[i]))
177 if (gmpc_plugin_get_enabled(plugins[i]))
179 gmpc_plugin_browser_add(plugins[i], cat_tree);
182 TEC("setup %s", gmpc_plugin_get_name(plugins[i]))
185 gtk_tree_view_set_cursor(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml, "cat_tree")), path, NULL, FALSE);
186 TEC("set cursor");
187 gtk_tree_path_free(path);
188 TEC("finish set");
193 * Function to handle a change in category.
195 static void pl3_cat_sel_changed(GtkTreeSelection * selec, gpointer * userdata)
197 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
198 GtkTreeModel *model = gtk_tree_view_get_model(tree);
199 GtkTreeIter iter;
200 GtkWidget *container = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "browser_container"));
201 if (!model)
202 return;
203 if (gtk_tree_selection_get_selected(selec, &model, &iter))
205 gint type;
207 gtk_tree_model_get(model, &iter, PL3_CAT_TYPE, &type, -1);
211 * Start switching side view (if type changed )
213 if (old_type != -1)
215 gmpc_plugin_browser_unselected(plugins[plugin_get_pos(old_type)], container);
217 old_type = -1;
218 if(type > -1)
220 /** if type changed give a selected signal */
221 if ((old_type != type))
223 gmpc_plugin_browser_selected(plugins[plugin_get_pos(type)], container);
228 * update old value, so get_selected_category is correct before calling selection_changed
230 old_type = type;
232 } else
234 if (old_type != -1)
236 gmpc_plugin_browser_unselected(plugins[plugin_get_pos(old_type)], container);
238 old_type = -1;
239 gtk_tree_model_get_iter_first(model, &iter);
240 gtk_tree_selection_select_iter(selec, &iter);
242 pl3_option_menu_activate();
246 /* handle right mouse clicks on the cat tree view */
247 /* gonna be a big function*/
248 int pl3_cat_tree_button_press_event(GtkTreeView * tree, GdkEventButton * event)
250 GtkTreeSelection *sel = gtk_tree_view_get_selection(tree);
251 if (event->button != 3 || gtk_tree_selection_count_selected_rows(sel) < 2 || !mpd_check_connected(connection))
253 return FALSE;
255 return TRUE;
260 void pl3_option_menu_activate(void)
263 GtkWidget *tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
264 int i;
265 gint type = pl3_cat_get_selected_browser();
266 int menu_items = 0;
267 GdkEventButton *event = NULL;
268 GtkWidget *menu = NULL;
269 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
270 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_option"));
272 //gtk_menu_item_set_submenu(m_item, NULL);
274 if (!mpd_check_connected(connection) || type == -1)
275 return;
277 menu = gtk_menu_new();
279 for (i = 0; i < num_plugins; i++)
281 if (gmpc_plugin_is_browser(plugins[i]))
283 menu_items += gmpc_plugin_browser_cat_right_mouse_menu(plugins[i], menu, type, tree, event);
286 if (menu_items)
288 gtk_widget_show_all(menu);
289 gtk_menu_item_set_submenu(m_item, menu);
290 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), TRUE);
291 } else
293 g_object_ref_sink(menu);
294 g_object_unref(menu);
295 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), FALSE);
301 int pl3_cat_tree_button_release_event(GtkTreeView * tree, GdkEventButton * event)
303 int i;
304 gint type = pl3_cat_get_selected_browser();
305 int menu_items = 0;
306 GtkWidget *menu = NULL;
308 if (type == -1 || !mpd_check_connected(connection) || event->button != 3)
310 /* no selections, or no usefull one.. so propagate the signal */
311 return FALSE;
314 menu = gtk_menu_new();
316 for (i = 0; i < num_plugins; i++)
318 if (gmpc_plugin_is_browser(plugins[i]))
320 menu_items += gmpc_plugin_browser_cat_right_mouse_menu(plugins[i], menu, type, GTK_WIDGET(tree), event);
324 if (menu_items)
326 gtk_widget_show_all(menu);
327 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
328 /*event->button */ 0, event->time);
329 } else
331 g_object_ref_sink(menu);
332 g_object_unref(menu);
334 return TRUE;
337 void pl3_sidebar_plugins_init(void)
339 int i;
340 for (i = 0; i < num_plugins; i++)
342 // This is implicitely done inside sidebar_init
343 // if (gmpc_plugin_is_sidebar(plugins[i]))
345 gmpc_plugin_sidebar_init(plugins[i]);
350 /**********************************************************
351 * MISC
353 static GtkWidget *control_window = NULL;
354 static gboolean pl3_win_state_event(GtkWidget * window, GdkEventWindowState * event, gpointer data)
356 GtkWidget *vbox1 = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox1"));
357 GtkWidget *p = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "alignment1"));
358 GtkWidget *h = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox1"));
359 GtkWidget *b = (GTK_WIDGET(gtk_builder_get_object(pl3_xml, "menubartest")));
360 if (((event->new_window_state) & GDK_WINDOW_STATE_FULLSCREEN))
362 if(control_window == NULL) {
363 control_window = create_control_window(window);
364 gtk_box_pack_start(GTK_BOX(vbox1), control_window, FALSE, FALSE, 0);
366 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
367 gtk_widget_hide(p);
368 gtk_widget_hide(h);
369 gtk_widget_hide(b);
370 } else if ((event->changed_mask) & GDK_WINDOW_STATE_FULLSCREEN)
372 control_window_destroy(control_window);
373 control_window = NULL;
374 playlist_zoom_level_changed();
375 gtk_widget_show(p);
376 gtk_widget_show(h);
377 gtk_widget_show(b);
379 return FALSE;
383 * This avoids the 'keybinding help' to become sticky when moving the window, or chainging
384 * focus to other window.
386 gboolean pl3_window_focus_out_event(GtkWidget *window, GdkEventFocus *event, gpointer data)
388 return FALSE;
392 gboolean pl3_window_is_fullscreen(void)
394 GtkWidget *win = playlist3_get_window();
395 GdkWindowState state = 0;
396 if (gtk_widget_get_window(win))
397 state = gdk_window_get_state(gtk_widget_get_window(win));
398 return (state & GDK_WINDOW_STATE_FULLSCREEN) ? TRUE : FALSE;
402 gboolean pl3_window_fullscreen(void)
404 GtkWidget *win = playlist3_get_window();
406 if (pl3_zoom < PLAYLIST_MINI)
408 if (pl3_window_is_fullscreen())
410 gtk_window_unfullscreen(GTK_WINDOW(win));
411 } else
413 gtk_window_fullscreen(GTK_WINDOW(win));
416 return FALSE;
420 int pl3_window_key_release_event(GtkWidget * mw, GdkEventKey * event)
422 return FALSE;
424 static int pl3_window_browser_cycle_backwards()
426 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
427 GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cat_tree));
428 GtkTreeIter iter;
429 GtkTreeModel *model;
430 if(gtk_tree_selection_get_selected(select, &model, &iter))
432 while(gtk_tree_model_iter_previous(model, &iter)) {
433 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
434 if(pl3_cat_select_function(select, model, path, FALSE,NULL)) {
435 gtk_tree_selection_select_iter(select, &iter);
436 gtk_tree_path_free(path);
437 return TRUE;
439 gtk_tree_path_free(path);
441 // Get last one
442 gtk_tree_model_iter_nth_child(model, &iter, NULL,
443 gtk_tree_model_iter_n_children(model, NULL)-1);
444 gtk_tree_selection_select_iter(select, &iter);
445 return FALSE;
448 static int pl3_window_browser_cycle_forward()
450 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
451 GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cat_tree));
452 GtkTreeIter iter;
453 GtkTreeModel *model;
454 if(gtk_tree_selection_get_selected(select, &model, &iter))
456 while(gtk_tree_model_iter_next(model, &iter)) {
457 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
458 if(pl3_cat_select_function(select, model, path, FALSE,NULL)) {
459 gtk_tree_selection_select_iter(select, &iter);
460 gtk_tree_path_free(path);
461 return TRUE;
463 gtk_tree_path_free(path);
465 // Cycle to front.
466 gtk_tree_model_get_iter_first(model, &iter);
467 gtk_tree_selection_select_iter(select, &iter);
468 return FALSE;
470 return FALSE;
472 int pl3_window_key_press_event(GtkWidget * mw, GdkEventKey * event)
474 int i = 0;
475 gint type = pl3_cat_get_selected_browser();
477 * Following key's are only valid when connected
479 if (!mpd_check_connected(connection))
481 return FALSE;
483 for (i = 0; i < num_plugins; i++)
485 if (gmpc_plugin_is_browser(plugins[i]))
487 gmpc_plugin_browser_key_press_event(plugins[i], mw, event, type);
490 if(event->keyval == GDK_KEY_colon)
492 show_command_line();
493 return TRUE;
495 else if (event->keyval == GDK_KEY_less &&
496 (event->state&GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
497 song_fastbackward();
499 else if (event->keyval == GDK_KEY_greater &&
500 (event->state&GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
501 song_fastforward();
503 else if(event->keyval == GDK_KEY_Tab && (event->state&GDK_CONTROL_MASK) > 0)
505 return pl3_window_browser_cycle_forward();
507 else if(event->keyval == GDK_KEY_ISO_Left_Tab && (event->state&GDK_CONTROL_MASK) > 0)
509 return pl3_window_browser_cycle_backwards();
511 if((event->state&GDK_MOD1_MASK) > 0)
513 guint kev = event->keyval;
514 if(kev >= GDK_KEY_0 && kev <= GDK_KEY_9)
516 guint i_index = 0;
517 GtkTreeIter iter;
518 kev-=GDK_KEY_0;
519 if (gtk_tree_model_get_iter_first(pl3_tree, &iter))
521 if(kev == 0) kev+=10;
523 gint new_type =0 ;
524 gtk_tree_model_get(pl3_tree, &iter, PL3_CAT_TYPE, &new_type, -1);
525 if(new_type >= 0) i_index++;
526 if(i_index == kev && new_type >= 0)
528 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
529 GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cat_tree));
531 // if this is allready selected, do +10. this allows us to go up to 20 browsers.
532 if(new_type == old_type && gtk_tree_selection_iter_is_selected(select, &iter)) {
533 kev+=10;
534 }else{
535 gtk_tree_selection_select_iter(select, &iter);
536 return TRUE;
539 }while(gtk_tree_model_iter_next(pl3_tree, &iter));
544 /* don't propagate */
545 return FALSE;
549 * Close the playlist and save position/size
551 gboolean pl3_close(void)
553 /* only save when window is PLAYLIST_SMALL or NO ZOOM */
554 if (pl3_xml != NULL)
556 GtkWidget *window = playlist3_get_window();
557 int maximized = FALSE;
558 if (gtk_widget_get_window(window))
560 GdkWindowState state = gdk_window_get_state(gtk_widget_get_window(window));
561 maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
563 cfg_set_single_value_as_int(config, "playlist", "maximized", maximized);
565 gtk_window_get_position(GTK_WINDOW(window), &pl3_wsize.x, &pl3_wsize.y);
567 cfg_set_single_value_as_int(config, "playlist", "xpos", pl3_wsize.x);
568 cfg_set_single_value_as_int(config, "playlist", "ypos", pl3_wsize.y);
570 if (pl3_zoom <= PLAYLIST_SMALL)
572 gtk_window_get_size(GTK_WINDOW(window), &pl3_wsize.width, &pl3_wsize.height);
573 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "pl3_close: save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
574 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
575 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
579 if (cfg_get_single_value_as_int_with_default(config, "playlist", "hide-on-close", FALSE))
581 if (tray_icon2_get_available())
583 pl3_toggle_hidden();
584 return TRUE;
586 gtk_window_iconify(GTK_WINDOW(playlist3_get_window()));
587 return TRUE;
591 * Quit the program
593 main_quit();
594 return TRUE;
599 * Hide the playlist.
600 * Before hiding save current size and position
602 int pl3_hide(void)
604 GtkWidget *pl3_win = playlist3_get_window();
605 if (!tray_icon2_get_available())
607 gtk_window_iconify(GTK_WINDOW(pl3_win));
608 return 1;
610 if (pl3_xml != NULL && !pl3_hidden)
612 GtkWidget *window = playlist3_get_window();
613 int maximized = FALSE;
614 if (gtk_widget_get_window(window))
616 GdkWindowState state = gdk_window_get_state(gtk_widget_get_window(window));
617 maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
619 cfg_set_single_value_as_int(config, "playlist", "maximized", maximized);
620 /** Save position
622 gtk_window_get_position(GTK_WINDOW(pl3_win), &pl3_wsize.x, &pl3_wsize.y);
623 cfg_set_single_value_as_int(config, "playlist", "xpos", pl3_wsize.x);
624 cfg_set_single_value_as_int(config, "playlist", "ypos", pl3_wsize.y);
625 /* save size, only when in SMALL or no zoom mode
627 if (pl3_zoom <= PLAYLIST_SMALL)
629 gtk_window_get_size(GTK_WINDOW(pl3_win), &pl3_wsize.width, &pl3_wsize.height);
630 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "pl3_hide: save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
631 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
632 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
634 gtk_widget_hide(pl3_win);
635 pl3_hidden = TRUE;
637 #ifdef HAVE_APP_INDICATOR
638 tray_icon2_update_menu();
639 #endif
640 return TRUE;
644 /* create the playlist view
645 * This is done only once, for the rest its hidden, but still there
647 void pl3_show_and_position_window(void)
649 GtkWidget *pl3_win;
650 if (!pl3_xml)
651 return;
652 pl3_win = playlist3_get_window();
653 if (pl3_wsize.x > 0 || pl3_wsize.y > 0)
655 gtk_window_move(GTK_WINDOW(pl3_win), pl3_wsize.x, pl3_wsize.y);
657 if (pl3_wsize.height > 0 && pl3_wsize.width > 0)
659 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
660 gtk_window_resize(GTK_WINDOW(pl3_win), pl3_wsize.width, pl3_wsize.height);
662 gtk_widget_show(pl3_win);
663 gtk_window_present(GTK_WINDOW(pl3_win));
668 gboolean playlist3_window_is_hidden(void)
670 return pl3_hidden;
674 void pl3_toggle_hidden(void)
676 if (pl3_hidden)
678 create_playlist3();
679 } else
681 pl3_hide();
686 static void playlist3_source_drag_data_recieved(GtkWidget * widget,
687 GdkDragContext * context,
688 gint x,
689 gint y, GtkSelectionData * data, guint info, guint time_recieved)
691 if (info != 99)
693 int found = 0;
694 const guchar *url_data = gtk_selection_data_get_data(data);
695 int i;
696 if (url_data)
699 gchar **url = g_uri_list_extract_uris(url_data);
700 for (i = 0; url && url[i]; i++)
702 gchar *scheme = g_uri_parse_scheme(url[i]);
703 /* Don't add lines withouth an actual scheme. */
704 if (scheme)
706 gchar *fu = g_uri_unescape_string(url[i], NULL);
707 url_start_real(fu);
708 g_free(fu);
709 g_free(scheme);
712 if (url)
713 g_strfreev(url);
716 gtk_drag_finish(context, found, FALSE, time_recieved);
717 } else
719 MpdData *mdata;
720 gchar **stripped;
721 int i;
722 guchar *odata = gtk_selection_data_get_text(data);
723 stripped = g_strsplit((gchar *) odata, "\n", 0);
724 g_free(odata);
725 if (gdk_drag_context_get_actions(context)== GDK_ACTION_MOVE)
727 mpd_playlist_clear(connection);
729 mpd_database_search_start(connection, TRUE);
730 for (i = 0; stripped && stripped[i]; i++)
732 gchar **request = g_strsplit(stripped[i], ":", 2);
733 mpd_database_search_add_constraint(connection, mpd_misc_get_tag_by_name(request[0]), request[1]);
734 g_strfreev(request);
736 mdata = mpd_database_search_commit(connection);
737 for (; mdata; mdata = mpd_data_get_next(mdata))
739 mpd_playlist_queue_add(connection, mdata->song->file);
741 mpd_playlist_queue_commit(connection);
742 if (gdk_drag_context_get_actions(context)== GDK_ACTION_MOVE)
744 mpd_player_play(connection);
747 g_strfreev(stripped);
748 gtk_drag_finish(context, TRUE, FALSE, time_recieved);
754 * Progresbar
756 void pl3_pb_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data)
758 mpd_player_seek(connection, (int)seek_time);
763 static void about_dialog_activate(GtkWidget * dialog, const gchar * uri, gpointer data)
765 open_uri(uri);
769 /***
770 * Handle a connect/Disconnect
772 static void playlist_connection_changed(MpdObj * mi, int connect, gpointer data)
774 GtkWidget *pl3_win = playlist3_get_window();
775 /* Set menu items */
776 if (connect)
778 char **handlers;
779 gboolean found = FALSE;
780 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")), TRUE);
781 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")), TRUE);
783 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConnect")), FALSE);
784 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDDisconnect")), TRUE);
785 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPassword")), TRUE);
786 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_view")), TRUE);
787 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), TRUE);
789 /* Check if MPD supports 'file://' (so local files). */
790 /* TODO: make this a separate function */
791 handlers = mpd_server_get_url_handlers(connection);
792 if (handlers)
794 int i=0;
795 for(; !found && handlers != NULL && handlers[i] != NULL; i++) {
796 if(g_utf8_collate(handlers[i], "file://") == 0) {
797 found = TRUE;
800 g_strfreev(handlers);
802 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "open_local_file")), found);
803 } else
805 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")), FALSE);
806 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")), FALSE);
808 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConnect")), TRUE);
809 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDDisconnect")), FALSE);
810 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPassword")), FALSE);
811 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_view")), FALSE);
812 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), FALSE);
813 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "open_local_file")), FALSE);
815 /** Set back to the current borwser, and update window title */
816 if (connect)
818 gchar *string = NULL;
819 GtkTreeIter iter;
820 GtkTreeSelection *selec = gtk_tree_view_get_selection((GtkTreeView *) gtk_builder_get_object(pl3_xml,
821 "cat_tree"));
822 GtkTreeModel *model = GTK_TREE_MODEL(pl3_tree);
823 if (gtk_tree_model_get_iter_first(model, &iter))
825 gtk_tree_selection_select_iter(selec, &iter);
827 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
829 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
830 if (id)
832 string =
833 g_strdup_printf("[%s] %s - %s %s", gmpc_profiles_get_name(gmpc_profiles, id), _("GMPC"),
834 _("Connected to"), mpd_get_hostname(mi));
835 g_free(id);
838 if (!string)
839 string = g_strdup_printf("%s - %s %s", _("GMPC"), _("Connected to"), mpd_get_hostname(mi));
840 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
841 g_free(string);
842 } else
844 gchar *string = NULL;
846 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
848 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
849 if (id)
851 string =
852 g_strdup_printf("[%s] %s - %s", gmpc_profiles_get_name(gmpc_profiles, id), _("GMPC"),
853 _("Disconnected"));
854 g_free(id);
857 if (!string)
858 string = g_strdup_printf("%s - %s", _("GMPC"), _("Disconnected"));
859 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
860 g_free(string);
864 * make the playlist update itself
866 playlist_status_changed(connection,
867 MPD_CST_STATE | MPD_CST_SONGID | MPD_CST_NEXTSONG |
868 MPD_CST_ELAPSED_TIME | MPD_CST_VOLUME |
869 MPD_CST_REPEAT | MPD_CST_RANDOM | MPD_CST_PERMISSION
870 | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE | MPD_CST_UPDATING, NULL);
873 * Also need updating
875 pl3_option_menu_activate();
876 pl3_tool_menu_update();
878 playlist3_fill_server_menu();
881 * update interface
882 * items that are caused by the plugin.
884 pl3_update_go_menu();
888 void pl3_style_set_event( GtkWidget *widget,
889 GtkStyle *previous_style,
890 gpointer user_data)
892 if (cfg_get_single_value_as_int_with_default(config, "Default", "use-dark-style-header", TRUE))
894 gtk_rc_parse_string("widget \"*header*\" style \"dark\"");
897 static gboolean pl3_cat_select_function(GtkTreeSelection *select, GtkTreeModel *model, GtkTreePath *path, gboolean cur_select, gpointer data)
899 GtkTreeIter iter;
900 if(gtk_tree_model_get_iter(model, &iter, path))
902 gint type =0 ;
903 gtk_tree_model_get(model, &iter, PL3_CAT_TYPE, &type, -1);
904 if(type >= 0) return TRUE;
906 return FALSE;
909 void create_playlist3(void)
911 GtkWidget *pb,*ali;
912 GtkCellRenderer *renderer;
913 GtkWidget *tree;
914 GtkTreeSelection *sel;
915 GtkTreeViewColumn *column = NULL;
916 gchar *path = NULL;
917 GtkTreeIter iter;
918 GError *error = NULL;
919 INIT_TIC_TAC();
920 /* indicate that the playlist is not hidden */
921 pl3_hidden = FALSE;
924 * If the playlist already exists,
925 * It is probably coming from a hidden state,
926 * so re-position the window
928 if (pl3_xml != NULL)
930 pl3_show_and_position_window();
931 return;
938 /** Ambiance / Radiance theme "dark" header */
939 if (cfg_get_single_value_as_int_with_default(config, "Default", "use-dark-style-header", TRUE))
941 gtk_rc_parse_string("widget \"*header*\" style \"dark\"");
944 /** use background color for the sidebar treeview cells */
945 gtk_rc_parse_string (
946 "style \"sidebar-treeview\"\n"
947 "{\n"
948 " GtkTreeView::odd-row-color = @bg_color\n"
949 " GtkTreeView::even-row-color = @bg_color\n"
950 "}\n"
951 "widget \"*.sidebar.*\" style \"sidebar-treeview\"");
953 /** menubar */
954 gtk_rc_parse_string (
955 "style \"menubar-style\"\n"
956 "{\n"
957 " GtkMenuBar::shadow-type = none\n"
958 "}\n"
959 "widget \"*.menubar\" style \"menubar-style\"\n");
961 /* initial, setting the url hook */
962 // TODO
963 // gtk_about_dialog_set_url_hook((GtkAboutDialogActivateLinkFunc) about_dialog_activate, NULL, NULL);
964 TEC("Setup dialog url hook")
965 /* load gui desciption */
966 path = gmpc_get_full_glade_path("playlist3.ui");
967 TEC("get path")
968 pl3_xml = gtk_builder_new();
969 TEC("create builder")
970 if(gtk_builder_add_from_file(pl3_xml, path,&error) == 0)
973 * Check if the file is loaded, if not then show an error message and abort the program
974 if (pl3_xml == NULL)
977 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Failed to open playlist3.glade: %s\n", error->message);
978 abort();
980 g_free(path);
984 // update style.
985 GtkWidget *widget = (GtkWidget *)gtk_builder_get_object(pl3_xml, "cat_tree");
986 GtkStyleContext *ct = gtk_widget_get_style_context(widget);
987 gtk_style_context_add_class(ct, GTK_STYLE_CLASS_SIDEBAR);
989 TEC("Load builder file")
991 /* create tree store for the "category" view */
992 if (pl3_tree == NULL)
994 GType types[] =
996 G_TYPE_INT, /* row type, see free_type struct */
997 G_TYPE_STRING, /* display name */
998 G_TYPE_STRING, /* full path and stuff for backend */
999 G_TYPE_STRING, /* icon id */
1000 G_TYPE_INT, /* ordering */
1001 G_TYPE_INT, /* Bold */
1002 G_TYPE_STRING, /* stock id */
1003 G_TYPE_BOOLEAN /* Show text */
1005 /* song id, song title */
1006 pl3_tree = (GtkTreeModel *) gmpc_tools_liststore_sort_new();
1007 gtk_list_store_set_column_types(GTK_LIST_STORE(pl3_tree), PL3_CAT_NROWS, types);
1009 TEC("Setup pl3_tree")
1011 tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
1012 gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
1013 pl3_cat_select_function, pl3_tree, NULL);
1015 gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(pl3_tree));
1016 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1017 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(sel), GTK_SELECTION_BROWSE);
1018 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree), TRUE);
1019 // Enable tooltip on the treeview.
1020 gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(tree), PL3_CAT_TITLE);
1022 sidebar_text = renderer = GTK_CELL_RENDERER(my_cell_renderer_new());
1023 g_object_set(G_OBJECT(renderer), "xalign", 0.5,NULL);
1024 column = gtk_tree_view_column_new();
1025 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1027 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1028 g_object_set(G_OBJECT(renderer), "stock-size", GTK_ICON_SIZE_MENU, NULL);
1030 int w, h;
1031 if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h))
1033 g_object_set(G_OBJECT(renderer), "height", h+10, NULL);
1034 g_object_set(G_OBJECT(renderer), "image-width", w,NULL);
1037 gtk_tree_view_column_set_attributes(column, renderer,
1038 "icon-name", PL3_CAT_ICON_ID,
1039 "stock-id", PL3_CAT_STOCK_ID,
1040 "text", PL3_CAT_TITLE,
1041 "weight", PL3_CAT_BOLD,
1042 "show_text", PL3_CAT_SHOW_TEXT, NULL);
1043 g_object_set(renderer, "weight-set", TRUE, NULL);
1045 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
1046 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree), PL3_CAT_TITLE);
1047 g_signal_connect_after(G_OBJECT(sel), "changed", G_CALLBACK(pl3_cat_sel_changed), NULL);
1049 TEC("setup cat_tree");
1051 /* initialize the category view */
1052 pl3_initialize_tree();
1054 TEC("Init category tree")
1055 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")));
1058 * The new progress bar
1060 pb = (GtkWidget *) gtk_builder_get_object(pl3_xml, "hbox_progress");
1061 gtk_widget_show(pb);
1062 g_signal_connect(G_OBJECT(pb), "seek-event", G_CALLBACK(pl3_pb_seek_event), NULL);
1064 new_pb = pb;
1066 TEC("Init progress bar")
1067 /* Make sure change is applied */
1069 playlist3_new_header();
1071 pl3_sidebar_plugins_init();
1073 TEC("Init header")
1074 if (!cfg_get_single_value_as_int_with_default(config, "Interface", "hide-favorites-icon", FALSE))
1076 favorites_button = gmpc_favorites_button_new();
1077 ali = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
1078 gtk_container_add(GTK_CONTAINER(ali), GTK_WIDGET(favorites_button));
1079 gtk_box_pack_start(GTK_BOX(gtk_builder_get_object(pl3_xml, "hbox10")), GTK_WIDGET(ali), FALSE, FALSE, 0);
1080 gtk_widget_show_all(GTK_WIDGET(ali));
1081 TEC("Init fav icon")
1083 playlist_status_changed(connection,
1084 MPD_CST_STATE | MPD_CST_SONGID | MPD_CST_NEXTSONG |
1085 MPD_CST_ELAPSED_TIME | MPD_CST_VOLUME |
1086 MPD_CST_REPEAT | MPD_CST_RANDOM | MPD_CST_PERMISSION
1087 | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE, NULL);
1088 g_signal_connect(G_OBJECT(gtk_builder_get_object(pl3_xml, "volume_button")),
1089 "value_changed", G_CALLBACK(playlist_player_volume_changed), NULL);
1091 TEC("Signal setup")
1093 /* Restore values from config */
1094 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION
1095 (gtk_builder_get_object
1096 (pl3_xml, "ViewShowArtistImage")),
1097 cfg_get_single_value_as_int_with_default
1098 (config, "playlist", "cover-image-enable", 0));
1100 /* connect signals that are defined in the gui description */
1101 gtk_builder_connect_signals(pl3_xml,NULL);
1103 TEC("connect signals")
1105 /* select the current playlist */
1106 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_tree), &iter))
1108 gtk_tree_selection_select_iter(sel, &iter);
1111 TEC("Select view")
1113 * Insert new custom widget
1115 metaimage_album_art = gmpc_metaimage_new(META_ALBUM_ART);
1117 /* Hide when requested. */
1118 if (cfg_get_single_value_as_int_with_default(config, "Interface", "hide-album-art", FALSE))
1120 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_album_art), FALSE);
1122 gtk_box_pack_start(GTK_BOX
1123 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")), metaimage_album_art, FALSE, TRUE, 0);
1125 gtk_box_reorder_child(GTK_BOX
1126 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")), metaimage_album_art, 0);
1127 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_album_art), ALBUM_SIZE);
1128 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(metaimage_album_art), (char *)"gmpc");
1129 gmpc_metaimage_set_connection(GMPC_METAIMAGE(metaimage_album_art), connection);
1130 /** make sure size is updated */
1131 gmpc_metaimage_set_cover_na(GMPC_METAIMAGE(metaimage_album_art));
1133 metaimage_artist_art = gmpc_metaimage_new(META_ARTIST_ART);
1134 gtk_container_add(GTK_CONTAINER(gtk_builder_get_object(pl3_xml, "sidebar_artist_image_alignment")), metaimage_artist_art);
1136 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(metaimage_artist_art), (char *)"no-artist");
1137 gmpc_metaimage_set_loading_cover_icon(GMPC_METAIMAGE(metaimage_artist_art), (char *)"fetching-artist");
1138 gmpc_metaimage_set_connection(GMPC_METAIMAGE(metaimage_artist_art), connection);
1139 if (!cfg_get_single_value_as_int_with_default(config, "playlist", "cover-image-enable", FALSE))
1141 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1143 gmpc_metaimage_set_squared(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1144 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_artist_art), 145);
1146 TEC("Setup metaimages")
1147 /* restore the window's position and size, if the user wants this. */
1148 if (cfg_get_single_value_as_int_with_default(config, "playlist", "savepossize", 1))
1150 int maximized = cfg_get_single_value_as_int_with_default(config, "playlist", "maximized", 0);
1151 /* Load values from config file */
1152 pl3_wsize.x = cfg_get_single_value_as_int_with_default(config, "playlist", "xpos", 0);
1153 pl3_wsize.y = cfg_get_single_value_as_int_with_default(config, "playlist", "ypos", 0);
1154 pl3_wsize.width = cfg_get_single_value_as_int_with_default(config, "playlist", "width", 0);
1155 pl3_wsize.height = cfg_get_single_value_as_int_with_default(config, "playlist", "height", 0);
1156 TEC("get settings")
1157 /* restore location + position */
1158 /*pl3_show_and_position_window(); */
1160 if (pl3_wsize.x > 0 || pl3_wsize.y > 0)
1162 gtk_window_move(GTK_WINDOW(playlist3_get_window()), pl3_wsize.x, pl3_wsize.y);
1164 TEC("move window settings")
1165 if (pl3_wsize.height > 0 && pl3_wsize.width > 0)
1167 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
1168 gtk_window_resize(GTK_WINDOW(playlist3_get_window()), pl3_wsize.width, pl3_wsize.height);
1170 TEC("set pane window settings")
1171 if (maximized)
1172 gtk_window_maximize(GTK_WINDOW(playlist3_get_window()));
1173 TEC("maximize pane window settings")
1175 * restore zoom level
1178 gtk_widget_show(playlist3_get_window());
1179 TEC("Show window")
1180 pl3_zoom = cfg_get_single_value_as_int_with_default(config, "playlist", "zoomlevel", PLAYLIST_NO_ZOOM);
1181 playlist_zoom_level_changed();
1182 TEC("zoom level")
1184 #ifdef HAVE_APP_INDICATOR
1185 tray_icon2_update_menu();
1186 #endif
1188 TEC("Restore state")
1189 pl3_update_go_menu();
1190 TEC("Go menu")
1191 /* make it update itself */
1192 pl3_update_profiles_menu(gmpc_profiles, GMPC_PROFILES_ACTION_ADDED, -1, NULL);
1193 g_signal_connect(G_OBJECT(gmpc_profiles), "changed", G_CALLBACK(pl3_update_profiles_menu), NULL);
1194 g_signal_connect(G_OBJECT(gmpc_profiles), "changed", G_CALLBACK(pl3_profiles_changed), NULL);
1196 TEC("Update profiles")
1198 * Set as drag destination
1200 gtk_drag_dest_set(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox_playlist_player")),
1201 GTK_DEST_DEFAULT_ALL,
1202 target_table, 6, GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_DEFAULT | GDK_ACTION_MOVE);
1203 g_signal_connect(G_OBJECT
1204 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")),
1205 "drag_data_received", G_CALLBACK (playlist3_source_drag_data_recieved), NULL);
1207 TEC("setup drag")
1211 playlist_connection_changed(connection, FALSE, NULL);
1213 g_signal_connect(G_OBJECT(playlist3_get_window()), "window-state-event", G_CALLBACK(pl3_win_state_event), NULL);
1215 TEC("signal connn changed")
1217 g_signal_connect(G_OBJECT(playlist3_get_window()), "style-set", G_CALLBACK(pl3_style_set_event), NULL);
1220 * Add status icons
1222 main_window_init_default_status_icons();
1223 main_window_update_status_icons();
1225 TEC("Update status icon")
1226 /* Update extra */
1227 init_extra_playlist_state();
1228 TEC("Setup extra playlist")
1230 // Add window to GtkApplication.
1231 gtk_application_add_window(gmpc_application, playlist3_get_window());
1236 * Helper functions
1238 GtkListStore *playlist3_get_category_tree_store(void)
1240 if (pl3_xml == NULL)
1241 return NULL;
1242 return GTK_LIST_STORE(pl3_tree);
1246 GtkTreeView *playlist3_get_category_tree_view(void)
1248 if (pl3_xml == NULL)
1249 return NULL;
1250 return (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
1253 GtkWidget* playlist3_get_widget_by_id(const char *id) {
1254 return (GtkWidget *) gtk_builder_get_object(pl3_xml, id);
1258 /****************************************************************************************
1259 * PREFERENCES *
1260 ****************************************************************************************/
1261 /* prototyping for glade */
1262 void ck_stop_on_exit_toggled_cb(GtkToggleButton * but, gpointer data);
1263 void ck_show_tooltip_enable_tb(GtkToggleButton * but);
1265 G_MODULE_EXPORT void show_cover_case_tb(GtkToggleButton * but)
1267 int bool1 = gtk_toggle_button_get_active(but);
1268 cfg_set_single_value_as_int(config, "metaimage", "addcase", bool1);
1269 pixbuf_cache_clear();
1270 gmpc_meta_watcher_force_reload_cb(gmw);
1274 G_MODULE_EXPORT void ck_stop_on_exit_toggled_cb(GtkToggleButton * but, gpointer data)
1276 int bool1 = gtk_toggle_button_get_active(but);
1277 cfg_set_single_value_as_int(config, "connection", "stop-on-exit", bool1);
1281 G_MODULE_EXPORT void hide_on_close_enable_tb(GtkToggleButton * but)
1283 int bool1 = gtk_toggle_button_get_active(but);
1284 cfg_set_single_value_as_int(config, "playlist", "hide-on-close", bool1);
1288 G_MODULE_EXPORT void cur_song_center_enable_tb(GtkToggleButton * but)
1290 int bool1 = gtk_toggle_button_get_active(but);
1291 cfg_set_single_value_as_int(config, "playlist", "st_cur_song", bool1);
1295 G_MODULE_EXPORT void save_possize_enable_tb(GtkToggleButton * but)
1297 int bool1 = gtk_toggle_button_get_active(but);
1298 cfg_set_single_value_as_int(config, "playlist", "savepossize", bool1);
1302 G_MODULE_EXPORT void ck_show_tooltip_enable_tb(GtkToggleButton * but)
1304 int bool1 = gtk_toggle_button_get_active(but);
1305 cfg_set_single_value_as_int(config, "GmpcTreeView", "show-tooltip", bool1);
1309 G_MODULE_EXPORT void ck_search_as_you_type(GtkToggleButton * but)
1311 int bool1 = gtk_toggle_button_get_active(but);
1312 cfg_set_single_value_as_int(config, "general", "search-as-you-type", bool1);
1316 static void playlist_pref_destroy(GtkWidget * container)
1318 if (playlist_pref_xml)
1320 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(playlist_pref_xml,
1321 "playlist-vbox");
1322 gtk_container_remove(GTK_CONTAINER(container), vbox);
1323 g_object_unref(playlist_pref_xml);
1324 playlist_pref_xml = NULL;
1329 void playlist_pref_construct(GtkWidget * container)
1331 GError *error = NULL;
1332 gchar *path = gmpc_get_full_glade_path("preferences-playlist.ui");
1333 playlist_pref_xml = gtk_builder_new();
1335 gtk_builder_add_from_file(playlist_pref_xml, path, &error);
1336 if(error) {
1337 g_warning("Failed to open builder file: %s", error->message);
1338 g_error_free(error);
1339 return;
1341 if (playlist_pref_xml)
1343 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(playlist_pref_xml,
1344 "playlist-vbox");
1345 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1346 (gtk_builder_get_object
1347 (playlist_pref_xml, "ck_ps")),
1348 cfg_get_single_value_as_int_with_default(config, "playlist", "st_cur_song", 0));
1349 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1350 (gtk_builder_get_object
1351 (playlist_pref_xml, "ck_possize")),
1352 cfg_get_single_value_as_int_with_default(config, "playlist", "savepossize", 1));
1353 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1354 (gtk_builder_get_object
1355 (playlist_pref_xml, "ck_hide_on_close")),
1356 cfg_get_single_value_as_int_with_default(config, "playlist", "hide-on-close", 0));
1358 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1359 (gtk_builder_get_object
1360 (playlist_pref_xml, "ck_stop_on_exit")),
1361 cfg_get_single_value_as_int_with_default(config, "connection", "stop-on-exit", 0));
1363 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1364 (gtk_builder_get_object
1365 (playlist_pref_xml, "ck_cover_case")),
1366 cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase", TRUE));
1368 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1369 (gtk_builder_get_object
1370 (playlist_pref_xml, "ck_show_tooltip")),
1371 cfg_get_single_value_as_int_with_default
1372 (config, "GmpcTreeView", "show-tooltip", TRUE));
1374 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1375 (gtk_builder_get_object
1376 (playlist_pref_xml, "ck_search_as_you_type")),
1377 cfg_get_single_value_as_int_with_default(config, "general", "search-as-you-type",
1378 0));
1379 gtk_container_add(GTK_CONTAINER(container), vbox);
1380 gtk_widget_show_all(vbox);
1381 gtk_builder_connect_signals(playlist_pref_xml, NULL);
1383 g_free(path);
1388 * Menu Callback functions
1391 void playlist_menu_repeat_changed(GtkToggleAction * action)
1393 int active = gtk_toggle_action_get_active(action);
1394 if (active != mpd_player_get_repeat(connection))
1396 mpd_player_set_repeat(connection, active);
1401 void playlist_menu_random_changed(GtkToggleAction *action)
1403 int active = gtk_toggle_action_get_active(action);
1404 if (active != mpd_player_get_random(connection))
1406 mpd_player_set_random(connection, active);
1411 void playlist_menu_single_mode_changed(GtkToggleAction * action)
1413 int active = gtk_toggle_action_get_active(action);
1414 if (active != mpd_player_get_single(connection))
1416 mpd_player_set_single(connection, active);
1421 void playlist_menu_consume_changed(GtkToggleAction * action)
1423 int active = gtk_toggle_action_get_active(action);
1424 if (active != mpd_player_get_consume(connection))
1426 mpd_player_set_consume(connection, active);
1432 * This is artist image
1433 * FIXME: Rename
1435 void playlist_menu_artist_image_changed(GtkToggleAction *ta)
1437 int active = gtk_toggle_action_get_active(ta);
1438 cfg_set_single_value_as_int(config, "playlist", "cover-image-enable", active);
1439 if(pl3_zoom < PLAYLIST_SMALL)
1441 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), active);
1442 if (active)
1443 gtk_widget_show(metaimage_artist_art);
1448 /***
1449 * Zooming functions
1451 void playlist_zoom_out(void)
1453 /* Do not change zoom level when fullscreen */
1454 if(pl3_window_is_fullscreen())
1455 return;
1456 if ((pl3_zoom + 1) >= PLAYLIST_ZOOM_LEVELS)
1457 return;
1458 pl3_old_zoom = pl3_zoom;
1459 pl3_zoom++;
1460 playlist_zoom_level_changed();
1464 void playlist_zoom_in(void)
1466 /* Do not change zoom level when fullscreen */
1467 if(pl3_window_is_fullscreen())
1468 return;
1469 if (pl3_zoom <= PLAYLIST_NO_ZOOM)
1470 return;
1471 pl3_old_zoom = pl3_zoom;
1472 pl3_zoom--;
1473 playlist_zoom_level_changed();
1475 static void update_show_text(gboolean state)
1477 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
1478 GtkTreeModel *model = gtk_tree_view_get_model(tree);
1479 GtkTreeIter iter;
1480 if(gtk_tree_model_get_iter_first(model, &iter))
1483 gtk_list_store_set(GTK_LIST_STORE(model), &iter, PL3_CAT_SHOW_TEXT, state, -1);
1484 }while(gtk_tree_model_iter_next(model, &iter));
1489 * FIXME: Needs propper grouping and cleaning up
1491 static void playlist_zoom_level_changed(void)
1493 gboolean st_shown;
1494 GtkWidget *pl3_win = playlist3_get_window();
1495 printf("playlist3 zoom level changed\n");
1497 if (pl3_old_zoom <= PLAYLIST_SMALL)
1499 gtk_window_get_size(GTK_WINDOW(pl3_win), &pl3_wsize.width, &pl3_wsize.height);
1500 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
1501 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
1502 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
1505 if (pl3_old_zoom == PLAYLIST_MINI && pl3_zoom != PLAYLIST_MINI)
1507 GtkWidget *box =GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box"));
1508 GtkWidget *top = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10"));
1509 GtkWidget *vtop = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player"));
1510 /* add my own reference */
1511 g_object_ref(box);
1512 gtk_container_remove(GTK_CONTAINER(vtop), box);
1513 gtk_box_pack_end(GTK_BOX(top), box, FALSE, TRUE, 0);
1514 gtk_box_reorder_child(GTK_BOX(top), box, 0);
1515 /* release my reference */
1516 g_object_unref(box);
1517 gtk_widget_show(box);
1518 gmpc_progress_set_hide_text(GMPC_PROGRESS(new_pb), FALSE);
1520 if (pl3_old_zoom != PLAYLIST_MINI && pl3_zoom == PLAYLIST_MINI)
1522 GtkWidget *box = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box"));
1523 GtkWidget *top = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10"));
1524 GtkWidget *vtop = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player"));
1525 /* add my own reference */
1526 g_object_ref(box);
1527 gtk_container_remove(GTK_CONTAINER(top), box);
1528 gtk_box_pack_end(GTK_BOX(vtop), box, FALSE, TRUE, 3);
1529 /* release my reference */
1530 g_object_unref(box);
1531 gtk_widget_show(box);
1533 gmpc_progress_set_hide_text(GMPC_PROGRESS(new_pb), TRUE);
1536 /* Show full view */
1537 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")));
1538 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox1")));
1539 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10")));
1540 /** Menu Bar */
1541 /** BUTTON BOX */
1542 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box")));
1544 gtk_window_set_resizable(GTK_WINDOW(pl3_win), TRUE);
1545 if (pl3_wsize.width > 0 && pl3_wsize.height > 0 && pl3_old_zoom == PLAYLIST_MINI)
1547 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
1548 gtk_window_resize(GTK_WINDOW(pl3_win), pl3_wsize.width, pl3_wsize.height);
1550 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1552 if (cfg_get_single_value_as_int_with_default(config, "playlist", "cover-image-enable", FALSE))
1554 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), TRUE);
1555 gtk_widget_show(metaimage_artist_art);
1557 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")),TRUE);
1558 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")),TRUE);
1560 update_show_text(TRUE);
1561 gmpc_sidebar_plugins_update_state(GMPC_PLUGIN_SIDEBAR_STATE_FULL);
1563 /* Now start hiding */
1564 switch (pl3_zoom)
1566 case PLAYLIST_NO_ZOOM:
1567 break;
1568 case PLAYLIST_MINI:
1569 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")));
1570 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")),FALSE);
1571 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")),FALSE);
1572 if (pl3_win)
1574 if (gdk_window_get_state(gtk_widget_get_window(pl3_win)) & GDK_WINDOW_STATE_MAXIMIZED)
1576 gtk_window_unmaximize(GTK_WINDOW(pl3_win));
1579 if (gdk_window_get_state(gtk_widget_get_window(pl3_win)) & GDK_WINDOW_STATE_FULLSCREEN)
1581 gtk_window_unfullscreen(GTK_WINDOW(pl3_win));
1584 gtk_window_set_resizable(GTK_WINDOW(pl3_win), FALSE);
1586 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1587 break;
1588 case PLAYLIST_SMALL:
1589 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1590 update_show_text(FALSE);
1591 gmpc_sidebar_plugins_update_state(GMPC_PLUGIN_SIDEBAR_STATE_COLLAPSED);
1592 gtk_widget_grab_focus(pl3_win);
1593 default:
1594 break;
1596 /** Save zoom level
1598 cfg_set_single_value_as_int(config, "playlist", "zoomlevel", pl3_zoom);
1603 * Update the window to status changes in mpd
1605 static void playlist_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata)
1607 char buffer[1024];
1608 GtkWidget *pl3_win = playlist3_get_window();
1610 * if the window isn't there yet, return
1612 if (!pl3_xml)
1613 return;
1614 control_window_status_update(mi, what, control_window);
1616 * Player state changed
1618 if (what & MPD_CST_STATE)
1620 mpd_Song *song = mpd_playlist_get_current_song(connection);
1621 int state = mpd_player_get_state(mi);
1622 switch (state)
1624 case MPD_PLAYER_PLAY:
1626 gchar *markup = cfg_get_single_value_as_string_with_default(config,
1627 "playlist", /* Category */
1628 "window-markup",/* Key */
1629 /* default value */
1630 "[%title% - &[%artist%]]|%name%|%shortfile%"
1633 * Update the image in the menu
1635 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-pause");
1636 gtk_image_set_from_stock(GTK_IMAGE
1637 (gtk_builder_get_object
1638 (pl3_xml, "play_button_image")), "gtk-media-pause",
1639 GTK_ICON_SIZE_MENU);
1642 * Update window title
1644 mpd_song_markup(buffer, 1024, markup, mpd_playlist_get_current_song(connection));
1646 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1648 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1649 if (id)
1651 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1652 id), buffer);
1653 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1654 g_free(id);
1655 g_free(string);
1657 } else
1658 gtk_window_set_title(GTK_WINDOW(pl3_win), buffer);
1660 g_free(markup);
1661 break;
1663 case MPD_PLAYER_PAUSE:
1665 gchar *markup = cfg_get_single_value_as_string_with_default(config,
1666 "playlist", /* Category */
1667 "window-markup",/* Key */
1668 /* default value */
1669 "[%title% - &[%artist%]]|%name%|%shortfile%"
1671 /** Update menu and button images */
1673 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-play");
1674 gtk_image_set_from_stock(GTK_IMAGE
1675 (gtk_builder_get_object
1676 (pl3_xml, "play_button_image")), "gtk-media-play",
1677 GTK_ICON_SIZE_MENU);
1679 * Set paused in Window string
1681 mpd_song_markup(buffer, 1024 - strlen(_("paused") - 4),
1682 markup, mpd_playlist_get_current_song(connection));
1683 /* Append translated paused */
1684 strcat(buffer, " (");
1685 strcat(buffer, _("paused"));
1686 strcat(buffer, ")");
1688 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1690 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1691 if (id)
1693 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1694 id), buffer);
1695 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1696 g_free(id);
1697 g_free(string);
1699 } else
1700 gtk_window_set_title(GTK_WINDOW(pl3_win), buffer);
1701 g_free(markup);
1702 break;
1704 default:
1705 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-play");
1706 /* Make sure it's reset correctly */
1707 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), 0, 0);
1709 gtk_image_set_from_stock(GTK_IMAGE
1710 (gtk_builder_get_object
1711 (pl3_xml, "play_button_image")), "gtk-media-play",
1712 GTK_ICON_SIZE_MENU);
1713 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1715 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1716 if (id)
1718 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1719 id), _("GMPC"));
1720 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1721 g_free(id);
1722 g_free(string);
1724 } else
1725 gtk_window_set_title(GTK_WINDOW(pl3_win), _("GMPC"));
1727 playlist3_update_header();
1729 if(favorites_button != NULL)
1731 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
1733 gmpc_favorites_button_set_song(favorites_button, song);
1734 } else
1736 gmpc_favorites_button_set_song(favorites_button, NULL);
1741 * Handle song change or Playlist change
1742 * Anything that can change metadta
1744 if (what & MPD_CST_SONGID || what & MPD_CST_SONGPOS || what & MPD_CST_PLAYLIST)
1746 playlist3_update_header();
1747 /* make is update markups and stuff */
1748 playlist_status_changed(mi, MPD_CST_STATE, NULL);
1751 * set repeat buttons in menu correct
1753 if (what & MPD_CST_REPEAT)
1755 if (mpd_check_connected(connection))
1757 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDRepeat")),
1758 mpd_player_get_repeat(connection));
1762 if (what & MPD_CST_RANDOM)
1764 if (mpd_check_connected(connection))
1766 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDRandom")),
1767 mpd_player_get_random(connection));
1770 if (what & (MPD_CST_RANDOM | MPD_CST_REPEAT | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE))
1772 main_window_update_status_icons();
1774 if (what & MPD_CST_SINGLE_MODE)
1776 if (mpd_check_connected(connection))
1778 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDSingleMode")),
1779 mpd_player_get_single(connection));
1783 if (what & MPD_CST_CONSUME_MODE)
1785 if (mpd_check_connected(connection))
1787 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDConsumeMode")),
1788 mpd_player_get_consume(connection));
1791 if (what & MPD_CST_ELAPSED_TIME)
1793 if (mpd_check_connected(connection))
1795 int totalTime = mpd_status_get_total_song_time(connection);
1796 int elapsedTime = mpd_status_get_elapsed_song_time(connection);
1797 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), totalTime, elapsedTime);
1798 } else
1801 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), 0, 0);
1804 if (what & MPD_CST_PERMISSION)
1806 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDSingleMode")),
1808 mpd_check_connected(connection) &&
1809 mpd_server_check_command_allowed(connection, "single") == MPD_SERVER_COMMAND_ALLOWED
1812 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConsumeMode")),
1814 mpd_check_connected(connection) &&
1815 mpd_server_check_command_allowed(connection, "consume") == MPD_SERVER_COMMAND_ALLOWED
1818 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")),
1820 mpd_check_connected(connection) &&
1821 mpd_server_check_command_allowed(connection, "play") == MPD_SERVER_COMMAND_ALLOWED
1824 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDNext")),
1826 mpd_check_connected(connection) &&
1827 mpd_server_check_command_allowed(connection, "next") == MPD_SERVER_COMMAND_ALLOWED
1830 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPrevious")),
1832 mpd_check_connected(connection) &&
1833 mpd_server_check_command_allowed(connection, "previous") == MPD_SERVER_COMMAND_ALLOWED
1836 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDStop")),
1838 mpd_check_connected(connection) &&
1839 mpd_server_check_command_allowed(connection, "stop") == MPD_SERVER_COMMAND_ALLOWED
1842 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDRepeat")),
1844 mpd_check_connected(connection) &&
1845 mpd_server_check_command_allowed(connection, "repeat") == MPD_SERVER_COMMAND_ALLOWED
1848 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDRandom")),
1850 mpd_check_connected(connection)&&
1851 mpd_server_check_command_allowed(connection, "random") == MPD_SERVER_COMMAND_ALLOWED
1854 /* Also update volume stuff */
1855 what = what|MPD_CST_VOLUME;
1858 if (what & MPD_CST_VOLUME)
1860 GtkWidget *volume_button = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "volume_button"));
1861 int new_volume = mpd_status_get_volume(connection);
1862 if (new_volume >= 0 &&
1863 mpd_server_check_command_allowed(connection, "setvol") == MPD_SERVER_COMMAND_ALLOWED
1866 int volume = gtk_scale_button_get_value(GTK_SCALE_BUTTON(volume_button))/100.0;
1867 gtk_widget_show(GTK_WIDGET(volume_button));
1868 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDMuted")),
1869 TRUE
1871 /* don't do anything if nothing is changed */
1872 if (new_volume != volume)
1874 gtk_scale_button_set_value(GTK_SCALE_BUTTON(volume_button),new_volume/100.0f);
1876 } else
1878 gtk_scale_button_set_value(GTK_SCALE_BUTTON(volume_button),0);
1879 gtk_widget_hide(GTK_WIDGET(volume_button));
1880 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDMuted")),
1881 FALSE
1885 if (what & MPD_CST_SERVER_ERROR)
1887 gchar *error = mpd_status_get_mpd_error(mi);
1888 if (error)
1890 gchar *mes = g_markup_printf_escaped("%s: '%s'",
1891 _("MPD Reported the following error"),
1892 error);
1893 playlist3_show_error_message(mes, ERROR_WARNING);
1894 g_free(mes);
1895 g_free(error);
1898 if (what & MPD_CST_OUTPUT)
1900 playlist3_fill_server_menu();
1902 if (what & MPD_CST_NEXTSONG)
1905 GtkWidget *next_button = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "next_button"));
1906 if (next_button)
1908 int i = mpd_player_get_next_song_id(mi);
1909 if (i >= 0)
1911 mpd_Song *song = mpd_playlist_get_song(mi, i);
1912 if (song)
1914 mpd_song_markup(buffer, 1024, "[%title% - &[%artist%]]|%shortfile%", song);
1915 gtk_widget_set_tooltip_text(next_button, buffer);
1916 mpd_freeSong(song);
1917 } else
1918 gtk_widget_set_tooltip_text(next_button, "");
1919 } else
1920 gtk_widget_set_tooltip_text(next_button, "");
1925 gboolean playlist_player_volume_changed(GtkWidget * vol_but, double new_vol)
1927 int volume = new_vol*100; //gtk_scale_button_get_value(GTK_SCALE_BUTTON(vol_but)) * 100;
1928 int new_volume = mpd_status_get_volume(connection);
1929 if (new_volume >= 0 && new_volume != volume)
1931 mpd_status_set_volume(connection, volume);
1932 return FALSE;
1934 return FALSE;
1938 void about_window(void)
1940 gchar *path = gmpc_get_full_glade_path("aboutdialog.ui");
1941 GtkBuilder *xml = gtk_builder_new();
1942 GtkWidget *dialog = NULL;
1943 gtk_builder_add_from_file(xml, path, NULL);
1944 dialog = (GtkWidget *) gtk_builder_get_object(xml, "aboutdialog");
1946 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(playlist3_get_window()));
1947 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1948 g_free(path);
1950 if (strlen(revision))
1952 path = g_strdup_printf("%s\nRevision: %s", VERSION, revision);
1953 } else
1955 path = g_strdup_printf("%s\n%s\n", VERSION, GMPC_TAGLINE);
1957 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), GMPC_COPYRIGHT);
1958 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), _("Gnome Music Player Client"));
1959 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), GMPC_WEBSITE);
1960 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), path);
1962 g_free(path);
1963 gtk_widget_show(dialog);
1964 gtk_dialog_run(GTK_DIALOG(dialog));
1965 gtk_widget_destroy(dialog);
1966 g_object_unref(xml);
1970 /****************************************************
1971 * Interface stuff
1973 void pl3_update_go_menu(void)
1975 int i = 0;
1976 int items = 0;
1977 GtkWidget *menu = NULL;
1978 GtkAccelGroup *group = playlist3_get_accel_group();
1979 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
1980 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_go"));
1981 /***
1982 * Remove any old menu
1984 gtk_menu_item_set_submenu(m_item, NULL);
1986 * Create a new menu
1988 menu = gtk_menu_new();
1989 gtk_menu_set_accel_group(GTK_MENU(menu), group);
1990 if (mpd_check_connected(connection))
1992 for (i = 0; i < num_plugins; i++)
1994 if (gmpc_plugin_is_browser(plugins[i]))
1996 items += gmpc_plugin_browser_add_go_menu(plugins[i], menu);
2002 * Attach menu
2004 if (items)
2006 gtk_widget_show_all(menu);
2007 gtk_menu_item_set_submenu(m_item, menu);
2008 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")), TRUE);
2009 } else
2011 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")), FALSE);
2012 g_object_ref_sink(menu);
2013 g_object_unref(menu);
2018 static void pl3_profile_selected(GtkRadioMenuItem * radio, gpointer data)
2020 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(radio)))
2022 gchar *uid = g_object_get_data(G_OBJECT(radio), "uid");
2023 if (!uid)
2025 return;
2027 connection_set_current_profile(uid);
2028 if (mpd_check_connected(connection))
2030 mpd_disconnect(connection);
2031 connect_to_mpd();
2037 static void pl3_profiles_changed(GmpcProfiles * prof, const int changed, const int col, const gchar * id)
2039 if (!mpd_check_connected(connection))
2041 playlist_connection_changed(connection, 0, NULL);
2046 static void pl3_update_profiles_menu(GmpcProfiles * prof, const int changed, const int col, const gchar * id)
2048 int items = 0;
2049 GtkWidget *menu = NULL;
2050 gchar *current = gmpc_profiles_get_current(gmpc_profiles);
2051 GList *iter, *mult;
2052 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2053 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_music/menu_profiles"));
2054 /* check if there is anything changed that is important for us. */
2056 if (changed == GMPC_PROFILES_ACTION_COL_CHANGED && col != GMPC_PROFILES_COLUMN_NAME)
2058 g_free(current);
2059 return;
2061 /***
2062 * Remove any old menu
2064 gtk_menu_item_set_submenu(m_item, NULL);
2066 * Create a new menu
2068 menu = gtk_menu_new();
2070 mult = gmpc_profiles_get_profiles_ids(gmpc_profiles);
2071 if (mult)
2073 GSList *group = NULL;
2074 iter = mult;
2077 /** Get profile name */
2078 const gchar *value = gmpc_profiles_get_name(gmpc_profiles, (char *)iter->data);
2079 GtkWidget *item = gtk_radio_menu_item_new_with_label(group, value);
2080 /* get new group */
2081 group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
2082 /* add to the menu */
2083 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2085 /* check the current profile */
2086 if (!strcmp((char *)(iter->data), current))
2088 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
2092 * Attach click handler
2094 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_profile_selected), NULL);
2096 /** Attach the uid to the handler */
2097 value = g_strdup((char *)(iter->data));
2098 g_object_set_data_full(G_OBJECT(item), "uid", (gpointer) value, g_free);
2100 items++;
2101 } while ((iter = g_list_next(iter)));
2102 g_list_free(mult);
2107 * Attach menu
2109 if (items)
2111 gtk_widget_show_all(menu);
2112 gtk_menu_item_set_submenu(m_item , menu);
2113 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_profiles")), TRUE);
2114 } else
2116 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_profiles")), FALSE);
2117 g_object_ref_sink(menu);
2118 g_object_unref(menu);
2120 g_free(current);
2124 static void playlist3_server_output_changed(GtkWidget * item, gpointer data)
2126 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "id"));
2127 int state = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
2128 mpd_server_set_output_device(connection, id, state);
2133 void playlist3_server_update_db(void)
2135 mpd_database_update_dir(connection, "/");
2139 static GList *server_menu_items = NULL;
2140 static void playlist3_fill_server_menu(void)
2142 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2143 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_server"));
2144 /** Clear old items */
2145 if(server_menu_items != NULL)
2147 g_list_foreach(server_menu_items, (GFunc)gtk_widget_destroy, NULL);
2148 g_list_free(server_menu_items);
2149 server_menu_items = NULL;
2152 /* if connected fill with items */
2153 if (mpd_check_connected(connection))
2155 GtkWidget *menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(m_item));
2156 GtkWidget *menu_item = NULL;
2157 int i = 0;
2158 MpdData *data = NULL;
2160 data = mpd_server_get_output_devices(connection);
2161 if(data)
2163 menu_item = gtk_separator_menu_item_new();
2164 server_menu_items = g_list_append(server_menu_items, menu_item);
2165 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
2167 for (; data; data = mpd_data_get_next(data))
2169 menu_item = gtk_check_menu_item_new_with_label(data->output_dev->name);
2170 server_menu_items = g_list_append(server_menu_items, menu_item);
2171 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), data->output_dev->enabled ? TRUE : FALSE);
2172 gtk_widget_add_accelerator(menu_item, "activate",
2173 gtk_ui_manager_get_accel_group(GTK_UI_MANAGER(ui)),
2174 GDK_KEY_1 + i, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
2176 g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(playlist3_server_output_changed), NULL);
2177 g_object_set_data(G_OBJECT(menu_item), "id", GINT_TO_POINTER(data->output_dev->id));
2178 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
2179 i++;
2181 gtk_widget_show_all(menu);
2182 /* Server Menu Item */
2183 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_server")), TRUE);
2184 } else
2186 /* Server Menu Item */
2187 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_server")), FALSE);
2193 * new header
2195 /* glue code */
2198 void info2_activate(void)
2200 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
2201 gmpc_browsers_metadata_select_browser(browsers_metadata, tree);
2205 void info2_fill_song_view(mpd_Song * song)
2207 info2_activate();
2208 gmpc_browsers_metadata_set_song(browsers_metadata, song);
2212 void info2_fill_artist_view(const gchar * artist)
2214 info2_activate();
2215 gmpc_browsers_metadata_set_artist(browsers_metadata, artist);
2219 void info2_fill_album_view(const gchar * artist, const gchar * album)
2221 info2_activate();
2222 gmpc_browsers_metadata_set_album(browsers_metadata, artist, album);
2226 void playlist3_insert_browser(GtkTreeIter * iter, gint position)
2228 GtkTreeIter it, *sib = NULL;
2229 gint pos = 0;
2230 GtkTreeModel *model = GTK_TREE_MODEL(pl3_tree);
2231 if (gtk_tree_model_get_iter_first(model, &it))
2235 gtk_tree_model_get(model, &it, PL3_CAT_ORDER, &pos, -1);
2236 if (position <= pos)
2237 sib = &it;
2238 } while (sib == NULL && gtk_tree_model_iter_next(model, &it));
2241 // first check breaks recursion. Do not check for header when adding a header.
2242 // Next check checks if the header is allready there.
2243 if(position%1000 != 0 && (pos-pos%1000) != (position-position%1000))
2245 // insert category
2246 pos = position-position%1000;
2248 if(pos == PL3_CAT_BROWSER_LIBRARY)
2250 playlist3_insert_browser(&it, PL3_CAT_BROWSER_LIBRARY);
2251 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &it,
2252 PL3_CAT_TYPE,-1, PL3_CAT_TITLE, _("Library"),PL3_CAT_BOLD, PANGO_WEIGHT_ULTRABOLD,-1);
2253 sib = &it;
2254 gtk_list_store_insert_after(GTK_LIST_STORE(pl3_tree), iter, sib);
2256 else if (pos == PL3_CAT_BROWSER_ONLINE_MEDIA)
2258 playlist3_insert_browser(&it, PL3_CAT_BROWSER_ONLINE_MEDIA);
2259 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &it,
2260 PL3_CAT_TYPE,-1, PL3_CAT_TITLE, _("Online Media"),PL3_CAT_BOLD, PANGO_WEIGHT_ULTRABOLD,-1);
2261 sib = &it;
2262 gtk_list_store_insert_after(GTK_LIST_STORE(pl3_tree), iter, sib);
2264 else if (pos == PL3_CAT_BROWSER_MISC)
2266 playlist3_insert_browser(&it, PL3_CAT_BROWSER_MISC);
2267 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &it,
2268 PL3_CAT_TYPE,-1, PL3_CAT_TITLE, _("Misc."),PL3_CAT_BOLD, PANGO_WEIGHT_ULTRABOLD,-1);
2269 sib = &it;
2270 gtk_list_store_insert_after(GTK_LIST_STORE(pl3_tree), iter, sib);
2272 else
2274 // Insert item.
2275 gtk_list_store_insert_before(GTK_LIST_STORE(pl3_tree), iter, sib);
2278 else
2280 gtk_list_store_insert_before(GTK_LIST_STORE(pl3_tree), iter, sib);
2282 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), iter, PL3_CAT_ORDER, position, PL3_CAT_BOLD, PANGO_WEIGHT_NORMAL, -1);
2287 * Category editing
2290 void playlist3_destroy(void)
2292 GtkWidget *win = playlist3_get_window();
2293 if(server_menu_items) g_list_free(server_menu_items);
2294 gtk_widget_destroy(win);
2295 g_object_unref(pl3_xml);
2298 GtkWidget *playlist3_get_window(void)
2300 return GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_win"));
2304 /***
2305 * Help menu
2307 /* Make glade happy */
2308 void url_visit_website(void);
2309 void url_getting_help(void);
2311 void url_visit_website(void)
2313 open_uri(GMPC_WEBSITE);
2317 void url_getting_help(void)
2319 open_uri(GMPC_BUGTRACKER);
2323 gmpcPrefPlugin playlist_gpp =
2325 .construct = playlist_pref_construct,
2326 .destroy = playlist_pref_destroy
2329 gmpcPlugin playlist_plug =
2331 .name = N_("Interface"),
2332 .version = {1, 1, 1},
2333 .plugin_type = GMPC_INTERNALL,
2334 .mpd_status_changed = &playlist_status_changed,
2335 .mpd_connection_changed = &playlist_connection_changed,
2336 .pref = &playlist_gpp,
2341 * Tool menu
2344 void pl3_tool_menu_update(void)
2346 int i;
2347 int menu_items = 0;
2348 GtkWidget *menu = NULL;
2349 GtkAccelGroup *group = gtk_accel_group_new();
2350 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2351 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_tool"));
2352 gtk_menu_item_set_submenu(m_item, NULL);
2353 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_tool")), FALSE);
2354 if (!mpd_check_connected(connection))
2355 return;
2357 menu = gtk_menu_new();
2358 gtk_menu_set_accel_group(GTK_MENU(menu), group);
2359 g_object_unref(group);
2360 gtk_window_add_accel_group(GTK_WINDOW(playlist3_get_window()), group);
2361 for (i = 0; i < num_plugins; i++)
2363 menu_items += gmpc_plugin_tool_menu_integration(plugins[i], GTK_MENU(menu));
2365 if (menu_items)
2367 gtk_widget_show_all(menu);
2368 gtk_menu_item_set_submenu(m_item, menu);
2369 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_tool")), TRUE);
2370 } else
2372 g_object_ref_sink(menu);
2373 g_object_unref(menu);
2378 void easy_command_help_window(void)
2380 if (gmpc_easy_command)
2381 gmpc_easy_command_help_window(gmpc_easy_command, NULL);
2387 * Extra wrappings for menu
2389 extern gmpcPlugin extraplaylist_plugin;
2390 void enable_extra_playlist(GtkToggleAction *action)
2392 gboolean state = gtk_toggle_action_get_active(action);
2393 if(extraplaylist_plugin.set_enabled)
2395 if(extraplaylist_plugin.get_enabled() != state)
2397 extraplaylist_plugin.set_enabled(state);
2400 preferences_window_update();
2404 void init_extra_playlist_state(void)
2406 GtkToggleAction *action = GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "ViewExtraPlaylist"));
2407 if(extraplaylist_plugin.get_enabled)
2409 gtk_toggle_action_set_active(action, extraplaylist_plugin.get_enabled());
2413 GtkAccelGroup *playlist3_get_accel_group(void)
2415 static GtkAccelGroup *group = NULL;
2416 if(group == NULL) {
2417 group = gtk_accel_group_new();
2418 gtk_window_add_accel_group(GTK_WINDOW(playlist3_get_window()), group);
2420 return group;
2423 void open_local_file(void)
2425 char **handlers;
2426 gboolean found = FALSE;
2427 if(!mpd_check_connected(connection))
2428 return;
2430 /* Check if MPD supports 'file://' (so local files). */
2431 handlers = mpd_server_get_url_handlers(connection);
2432 if (handlers)
2434 int i=0;
2435 for(; !found && handlers != NULL && handlers[i] != NULL; i++) {
2436 if(g_utf8_collate(handlers[i], "file://") == 0) {
2437 found = TRUE;
2440 g_strfreev(handlers);
2442 /* error message or file open */
2443 if(!found) {
2444 /* Message not found */
2445 GtkWidget *gmd = gtk_message_dialog_new(
2446 (GtkWindow*)playlist3_get_window(),
2447 GTK_DIALOG_MODAL,
2448 GTK_MESSAGE_ERROR,
2449 GTK_BUTTONS_CLOSE,
2451 "To playback local files, you need to be connected "
2452 "using unix socket.\n"
2453 "See the MPD website for more information."
2456 gtk_dialog_run(GTK_DIALOG(gmd));
2457 gtk_widget_destroy(GTK_WIDGET(gmd));
2458 }else {
2459 GtkWidget *fmd = gtk_file_chooser_dialog_new(
2460 "Select a local file",
2461 (GtkWindow*)playlist3_get_window(),
2462 GTK_FILE_CHOOSER_ACTION_OPEN,
2463 GTK_STOCK_CLOSE,
2464 GTK_RESPONSE_CLOSE,
2465 GTK_STOCK_OPEN,
2466 GTK_RESPONSE_OK,
2467 NULL);
2468 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fmd), TRUE);
2469 switch(gtk_dialog_run(GTK_DIALOG(fmd)))
2471 case GTK_RESPONSE_OK:
2473 GSList *iter;
2474 GSList *uris = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(fmd));
2475 for(iter = uris;
2476 iter != NULL;
2477 iter = g_slist_next(iter))
2479 char *uri = g_uri_unescape_string(iter->data,NULL);
2480 url_start_real(uri);
2481 g_free(uri);
2483 g_slist_foreach (uris, (GFunc) g_free, NULL);
2484 g_slist_free (uris);
2485 break;
2487 default:
2488 break;
2490 gtk_widget_destroy(GTK_WIDGET(fmd));
2494 void show_user_manual(void);
2495 void show_user_manual(void)
2497 open_help("ghelp:gmpc");
2500 GmpcPluginSidebarState playlist3_get_sidebar_state(void)
2502 return pl3_zoom == PLAYLIST_NO_ZOOM ? GMPC_PLUGIN_SIDEBAR_STATE_FULL:GMPC_PLUGIN_SIDEBAR_STATE_COLLAPSED;
2504 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=80: */