Fix prev/play/stop/next buttons
[gmpc.git] / src / playlist3.c
blobc6993574e0940730821ecd64d144482b89019868
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2011 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/thv.h"
34 #include "GUI/cmd.h"
35 #include "GUI/status_icon.h"
36 #include "GUI/title_header.h"
37 #include "GUI/control_window.h"
39 #define ALBUM_SIZE_SMALL 42
40 #define ALBUM_SIZE_LARGE 42
42 #define LOG_DOMAIN "Playlist"
44 /* Drag and drop Target table */
45 static GtkTargetEntry target_table[] =
47 {(gchar *) "x-url/http", 0, 0},
48 {(gchar *) "_NETSCAPE_URL", 0, 1},
49 {(gchar *) "text/uri-list", 0, 2},
50 {(gchar *) "audio/*", 0, 3},
51 {(gchar *) "audio/x-scpls", 0, 4},
52 {(gchar *) "internal-drop", 0, 99}
55 GtkWidget *metaimage_album_art = NULL;
56 GtkWidget *metaimage_artist_art = NULL;
57 GmpcFavoritesButton *favorites_button = 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, int 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 *);
87 void cur_song_center_enable_tb(GtkToggleButton *);
88 void show_cover_case_tb(GtkToggleButton * but);
89 void save_possize_enable_tb(GtkToggleButton *);
90 void playlist_menu_repeat_changed(GtkToggleAction *);
91 void playlist_menu_single_mode_changed(GtkToggleAction * );
92 void playlist_menu_consume_changed(GtkToggleAction * );
94 void playlist_menu_random_changed(GtkToggleAction *);
95 void playlist_menu_artist_image_changed(GtkToggleAction *);
96 void hide_on_close_enable_tb(GtkToggleButton * but);
97 gboolean pl3_close(void);
98 static void pl3_update_profiles_menu(GmpcProfiles * prof, const int changed, const int col, const gchar * id);
99 gboolean playlist3_enter_notify_event(GtkWidget * wid, GdkEventCrossing * event, gpointer data);
100 gboolean playlist3_leave_notify_event(GtkWidget * wid, GdkEventCrossing * event, gpointer data);
102 static void pl3_profiles_changed(GmpcProfiles * prof, const int changed, const int col, const gchar * id);
103 static void playlist3_server_output_changed(GtkWidget * item, gpointer data);
104 static void playlist3_fill_server_menu(void);
105 void playlist3_server_update_db(void);
107 void easy_command_help_window(void);
109 void pl3_style_set_event(GtkWidget *widget, GtkStyle *previous_style, gpointer user_data);
111 void pl3_sidebar_plugins_init(void);
113 /* Old category browser style */
114 static int old_type = -1;
116 /* interface description */
117 GtkBuilder *pl3_xml = NULL;
118 /* category treeview-store */
119 GtkTreeModel *pl3_tree = NULL;
121 /* size */
122 static GtkAllocation pl3_wsize = { 0, 0, 0, 0 };
124 static int pl3_hidden = TRUE;
126 static void playlist_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata);
128 /* Playlist "Plugin" */
129 static void playlist_pref_construct(GtkWidget * container);
130 static void playlist_pref_destroy(GtkWidget * container);
132 static GtkBuilder *playlist_pref_xml = NULL;
134 void ck_search_as_you_type(GtkToggleButton * but);
137 /* Get the type of the selected row..
138 * -1 means no row selected
140 int pl3_cat_get_selected_browser(void)
142 return old_type;
149 * Extras for better integration
152 void init_extra_playlist_state(void);
153 void enable_extra_playlist(GtkToggleAction *action);
155 /**************************************************
156 * Category Tree
158 static void pl3_initialize_tree(void)
160 int i;
161 GtkTreePath *path;
162 GtkTreeSelection *sel;
163 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
165 INIT_TIC_TAC()
167 path = gtk_tree_path_new_from_string("0");
168 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml, "cat_tree")));
169 TEC("Get selection");
170 for (i = 0; i < num_plugins; i++)
172 if (gmpc_plugin_is_browser(plugins[i]))
174 if (gmpc_plugin_get_enabled(plugins[i]))
176 gmpc_plugin_browser_add(plugins[i], cat_tree);
179 TEC("setup %s", gmpc_plugin_get_name(plugins[i]))
182 gtk_tree_view_set_cursor(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml, "cat_tree")), path, NULL, FALSE);
183 TEC("set cursor");
184 gtk_tree_path_free(path);
185 TEC("finish set");
189 static void pl3_cat_combo_changed(GtkComboBox * box)
191 GtkTreeIter iter;
192 GtkTreeSelection *selec = gtk_tree_view_get_selection((GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree"));
193 GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree"));
194 if (gtk_combo_box_get_active_iter(box, &iter))
196 GtkTreeIter cat_iter;
197 GtkTreePath *path = NULL;
199 path = gtk_tree_model_get_path(gtk_combo_box_get_model(box), &iter);
200 if (path && gtk_tree_model_get_iter(GTK_TREE_MODEL(pl3_tree), &cat_iter, path))
202 GtkTreeIter piter;
203 if (gtk_tree_selection_get_selected(selec, &model, &piter))
205 GtkTreePath *ppath = gtk_tree_model_get_path(model, &piter);
206 if (ppath && gtk_tree_path_is_descendant(ppath, path))
208 gtk_tree_path_free(path);
209 gtk_tree_path_free(ppath);
210 return;
212 gtk_tree_path_free(ppath);
214 if (gtk_tree_path_get_depth(path) > 0)
216 if (!gtk_tree_selection_iter_is_selected(selec, &cat_iter))
218 gtk_tree_selection_select_iter(selec, &cat_iter);
222 if (path)
223 gtk_tree_path_free(path);
229 * Function to handle a change in category.
231 static void pl3_cat_sel_changed(GtkTreeSelection * selec, gpointer * userdata)
233 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
234 GtkTreeModel *model = gtk_tree_view_get_model(tree);
235 GtkTreeIter iter;
236 GtkWidget *container = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "browser_container"));
237 if (!model)
238 return;
239 thv_set_button_state(-1);
240 if (gtk_tree_selection_get_selected(selec, &model, &iter))
242 gint type;
243 gint *ind;
244 GtkTreePath *path;
246 gtk_tree_model_get(model, &iter, 0, &type, -1);
249 * Reposition the breadcrumb
251 path = gtk_tree_model_get_path(model, &iter);
252 ind = gtk_tree_path_get_indices(path);
253 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(pl3_xml, "cb_cat_selector")), ind[0]);
255 thv_set_button_state(ind[0]);
256 gtk_tree_path_free(path);
259 * Start switching side view (if type changed )
261 if (old_type != -1)
263 gmpc_plugin_browser_unselected(plugins[plugin_get_pos(old_type)], container);
265 old_type = -1;
266 pl3_push_rsb_message("");
267 /** if type changed give a selected signal */
268 if ((old_type != type))
270 gmpc_plugin_browser_selected(plugins[plugin_get_pos(type)], container);
273 * update old value, so get_selected_category is correct before calling selection_changed
275 old_type = type;
277 } else
279 if (old_type != -1)
281 gmpc_plugin_browser_unselected(plugins[plugin_get_pos(old_type)], container);
283 old_type = -1;
284 gtk_tree_model_get_iter_first(model, &iter);
285 gtk_tree_selection_select_iter(selec, &iter);
287 pl3_option_menu_activate();
291 /* handle right mouse clicks on the cat tree view */
292 /* gonna be a big function*/
293 int pl3_cat_tree_button_press_event(GtkTreeView * tree, GdkEventButton * event)
295 GtkTreeSelection *sel = gtk_tree_view_get_selection(tree);
296 if (event->button != 3 || gtk_tree_selection_count_selected_rows(sel) < 2 || !mpd_check_connected(connection))
298 return FALSE;
300 return TRUE;
305 void pl3_option_menu_activate(void)
308 GtkWidget *tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
309 int i;
310 gint type = pl3_cat_get_selected_browser();
311 int menu_items = 0;
312 GdkEventButton *event = NULL;
313 GtkWidget *menu = NULL;
314 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
315 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_option"));
317 //gtk_menu_item_set_submenu(m_item, NULL);
319 if (!mpd_check_connected(connection) || type == -1)
320 return;
322 menu = gtk_menu_new();
324 for (i = 0; i < num_plugins; i++)
326 if (gmpc_plugin_is_browser(plugins[i]))
328 menu_items += gmpc_plugin_browser_cat_right_mouse_menu(plugins[i], menu, type, tree, event);
331 if (menu_items)
333 gtk_widget_show_all(menu);
334 gtk_menu_item_set_submenu(m_item, menu);
335 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), TRUE);
336 } else
338 g_object_ref_sink(menu);
339 g_object_unref(menu);
340 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), FALSE);
346 int pl3_cat_tree_button_release_event(GtkTreeView * tree, GdkEventButton * event)
348 int i;
349 gint type = pl3_cat_get_selected_browser();
350 int menu_items = 0;
351 GtkWidget *menu = NULL;
352 if (type == -1 || !mpd_check_connected(connection) || event->button != 3)
354 /* no selections, or no usefull one.. so propagate the signal */
355 return FALSE;
358 menu = gtk_menu_new();
360 for (i = 0; i < num_plugins; i++)
362 if (gmpc_plugin_is_browser(plugins[i]))
364 menu_items += gmpc_plugin_browser_cat_right_mouse_menu(plugins[i], menu, type, GTK_WIDGET(tree), event);
368 if (menu_items)
370 gtk_widget_show_all(menu);
371 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
372 /*event->button */ 0, event->time);
373 } else
375 g_object_ref_sink(menu);
376 g_object_unref(menu);
378 return TRUE;
381 void pl3_sidebar_plugins_init(void)
383 int i;
384 for (i = 0; i < num_plugins; i++)
386 if (GMPC_PLUGIN_IS_SIDEBAR_IFACE((plugins[i])->new))
388 gmpc_sidebar_plugins_init((GmpcPluginSidebarIface*)(plugins[i])->new);
393 /**********************************************************
394 * MISC
396 static GtkWidget *control_window = NULL;
397 static gboolean pl3_win_state_event(GtkWidget * window, GdkEventWindowState * event, gpointer data)
399 GtkWidget *vbox1 = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox1"));
400 GtkWidget *p = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "alignment1"));
401 GtkWidget *h = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox1"));
402 GtkWidget *b = (GTK_WIDGET(gtk_builder_get_object(pl3_xml, "menubartest")));
403 if (((event->new_window_state) & GDK_WINDOW_STATE_FULLSCREEN))
405 if(control_window == NULL) {
406 control_window = create_control_window(window);
407 gtk_box_pack_start(GTK_BOX(vbox1), control_window, FALSE, FALSE, 0);
408 // gtk_box_reorder_child(GTK_BOX(vbox1), control_window, 0);
410 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "bread_crumb")));
411 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "box_tab_bar")));
412 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
413 gtk_widget_hide(p);
414 gtk_widget_hide(h);
415 gtk_widget_hide(b);
416 } else
418 control_window_destroy(control_window);
419 control_window = NULL;
420 playlist_zoom_level_changed();
421 gtk_widget_show(p);
422 gtk_widget_show(h);
423 gtk_widget_show(b);
425 return FALSE;
429 gboolean pl3_window_is_fullscreen(void)
431 GtkWidget *win = playlist3_get_window();
432 GdkWindowState state = 0;
433 if (win->window)
434 state = gdk_window_get_state(win->window);
435 return (state & GDK_WINDOW_STATE_FULLSCREEN) ? TRUE : FALSE;
439 void pl3_window_fullscreen(void)
441 GtkWidget *win = playlist3_get_window();
443 if (pl3_zoom < PLAYLIST_MINI)
445 if (pl3_window_is_fullscreen())
447 gtk_window_unfullscreen(GTK_WINDOW(win));
448 } else
450 gtk_window_fullscreen(GTK_WINDOW(win));
456 int pl3_window_key_press_event(GtkWidget * mw, GdkEventKey * event)
458 int i = 0;
459 gint type = pl3_cat_get_selected_browser();
461 * Following key's are only valid when connected
463 if (!mpd_check_connected(connection))
465 return FALSE;
467 for (i = 0; i < num_plugins; i++)
469 if (gmpc_plugin_is_browser(plugins[i]))
471 gmpc_plugin_browser_key_press_event(plugins[i], mw, event, type);
475 /* don't propagate */
476 return FALSE;
481 * Remove message from the status bar
482 * Used internally by timeout
484 static int pl3_pop_statusbar_message(gpointer data)
486 return FALSE;
487 gint id = GPOINTER_TO_INT(data);
488 gtk_statusbar_pop(GTK_STATUSBAR(gtk_builder_get_object(pl3_xml, "statusbar1")), id);
489 return FALSE;
494 * Put message on status bar
495 * This will be removed after 5 seconds
497 void pl3_push_statusbar_message(const char *mesg)
499 return;
500 gint id = gtk_statusbar_get_context_id(GTK_STATUSBAR(gtk_builder_get_object(pl3_xml, "statusbar1")), mesg);
501 /* message auto_remove after 5 sec */
502 g_timeout_add_seconds(5, (GSourceFunc) pl3_pop_statusbar_message, GINT_TO_POINTER(id));
503 gtk_statusbar_push(GTK_STATUSBAR(gtk_builder_get_object(pl3_xml, "statusbar1")), id, mesg);
508 * Push message to 2nd status bar
509 * Message overwrites the previous message
511 void pl3_push_rsb_message(const char *string)
513 return;
514 gtk_statusbar_push(GTK_STATUSBAR(gtk_builder_get_object(pl3_xml, "statusbar1")), 0, string);
519 * Close the playlist and save position/size
521 gboolean pl3_close(void)
523 /* only save when window is PLAYLIST_SMALL or NO ZOOM */
524 if (pl3_xml != NULL)
526 GtkWidget *window = playlist3_get_window();
527 int maximized = FALSE;
528 if (window->window)
530 GdkWindowState state = gdk_window_get_state(window->window);
531 maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
533 cfg_set_single_value_as_int(config, "playlist", "maximized", maximized);
535 gtk_window_get_position(GTK_WINDOW(window), &pl3_wsize.x, &pl3_wsize.y);
537 cfg_set_single_value_as_int(config, "playlist", "xpos", pl3_wsize.x);
538 cfg_set_single_value_as_int(config, "playlist", "ypos", pl3_wsize.y);
540 if (pl3_zoom <= PLAYLIST_SMALL)
542 gtk_window_get_size(GTK_WINDOW(window), &pl3_wsize.width, &pl3_wsize.height);
543 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "pl3_close: save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
544 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
545 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
547 if (pl3_zoom < PLAYLIST_SMALL)
549 cfg_set_single_value_as_int(config, "playlist", "pane-pos",
550 gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(pl3_xml, "hpaned1"))));
554 if (cfg_get_single_value_as_int_with_default(config, "playlist", "hide-on-close", FALSE))
556 if (tray_icon2_get_available())
558 pl3_toggle_hidden();
559 return TRUE;
561 gtk_window_iconify(GTK_WINDOW(playlist3_get_window()));
562 return TRUE;
566 * Quit the program
568 main_quit();
569 return TRUE;
574 * Hide the playlist.
575 * Before hiding save current size and position
577 int pl3_hide(void)
579 GtkWidget *pl3_win = playlist3_get_window();
580 if (!tray_icon2_get_available())
582 gtk_window_iconify(GTK_WINDOW(pl3_win));
583 return 1;
585 if (pl3_xml != NULL && !pl3_hidden)
587 GtkWidget *window = playlist3_get_window();
588 int maximized = FALSE;
589 if (window->window)
591 GdkWindowState state = gdk_window_get_state(window->window);
592 maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
594 cfg_set_single_value_as_int(config, "playlist", "maximized", maximized);
595 /** Save position
597 gtk_window_get_position(GTK_WINDOW(pl3_win), &pl3_wsize.x, &pl3_wsize.y);
598 cfg_set_single_value_as_int(config, "playlist", "xpos", pl3_wsize.x);
599 cfg_set_single_value_as_int(config, "playlist", "ypos", pl3_wsize.y);
600 /* save size, only when in SMALL or no zoom mode
602 if (pl3_zoom <= PLAYLIST_SMALL)
604 gtk_window_get_size(GTK_WINDOW(pl3_win), &pl3_wsize.width, &pl3_wsize.height);
605 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "pl3_hide: save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
606 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
607 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
608 cfg_set_single_value_as_int(config, "playlist", "pane-pos",
609 gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(pl3_xml, "hpaned1"))));
611 gtk_widget_hide(pl3_win);
612 pl3_hidden = TRUE;
614 #ifdef HAVE_APP_INDICATOR
615 tray_icon2_update_menu();
616 #endif
617 return TRUE;
621 /* create the playlist view
622 * This is done only once, for the rest its hidden, but still there
624 static void pl3_show_and_position_window(void)
626 GtkWidget *pl3_win;
627 if (!pl3_xml)
628 return;
629 pl3_win = playlist3_get_window();
630 if (pl3_wsize.x > 0 || pl3_wsize.y > 0)
632 gtk_window_move(GTK_WINDOW(pl3_win), pl3_wsize.x, pl3_wsize.y);
634 if (pl3_wsize.height > 0 && pl3_wsize.width > 0)
636 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
637 gtk_window_resize(GTK_WINDOW(pl3_win), pl3_wsize.width, pl3_wsize.height);
639 gtk_widget_show(pl3_win);
640 gtk_window_present(GTK_WINDOW(pl3_win));
645 gboolean playlist3_window_is_hidden(void)
647 return pl3_hidden;
651 void pl3_toggle_hidden(void)
653 if (pl3_hidden)
655 create_playlist3();
656 } else
658 pl3_hide();
663 static void playlist3_source_drag_data_recieved(GtkWidget * widget,
664 GdkDragContext * context,
665 gint x,
666 gint y, GtkSelectionData * data, guint info, guint time_recieved)
668 if (info != 99)
670 int found = 0;
671 const gchar *url_data = (gchar *) data->data;
672 int i;
673 if (url_data)
676 gchar **url = g_uri_list_extract_uris(url_data);
677 for (i = 0; url && url[i]; i++)
679 gchar *scheme = g_uri_parse_scheme(url[i]);
680 /* Don't add lines withouth an actual scheme. */
681 if (scheme)
683 gchar *fu = g_uri_unescape_string(url[i], NULL);
684 url_start_real(fu);
685 g_free(fu);
686 g_free(scheme);
689 if (url)
690 g_strfreev(url);
693 gtk_drag_finish(context, found, FALSE, time_recieved);
694 } else
696 MpdData *mdata;
697 gchar **stripped;
698 int i;
699 guchar *odata = gtk_selection_data_get_text(data);
700 stripped = g_strsplit((gchar *) odata, "\n", 0);
701 g_free(odata);
702 if (context->action == GDK_ACTION_MOVE)
704 mpd_playlist_clear(connection);
706 mpd_database_search_start(connection, TRUE);
707 for (i = 0; stripped && stripped[i]; i++)
709 gchar **request = g_strsplit(stripped[i], ":", 2);
710 mpd_database_search_add_constraint(connection, mpd_misc_get_tag_by_name(request[0]), request[1]);
711 g_strfreev(request);
713 mdata = mpd_database_search_commit(connection);
714 for (; mdata; mdata = mpd_data_get_next(mdata))
716 mpd_playlist_queue_add(connection, mdata->song->file);
718 mpd_playlist_queue_commit(connection);
719 if (context->action == GDK_ACTION_MOVE)
721 mpd_player_play(connection);
724 g_strfreev(stripped);
725 gtk_drag_finish(context, TRUE, FALSE, time_recieved);
731 * Progresbar
733 void pl3_pb_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data)
735 mpd_player_seek(connection, (int)seek_time);
740 * When the position of the slider change, update the artist image
742 static void pl3_win_pane_changed(GtkWidget * panel, GParamSpec * arg1, gpointer data)
744 gint position = 0;
745 gint max_size = cfg_get_single_value_as_int_with_default(config, "playlist",
746 "artist-size", 300);
747 gint size;
748 g_object_get(G_OBJECT(panel), "position", &position, NULL);
749 position -= 6;
750 /* force minimum size 16 */
751 if (position < 6)
752 position = 6;
753 size = ((position) > max_size) ? max_size : (position);
755 if (gmpc_metaimage_get_size(GMPC_METAIMAGE(metaimage_artist_art)) != size)
757 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_artist_art), size);
758 gmpc_metaimage_reload_image(GMPC_METAIMAGE(metaimage_artist_art));
764 static void about_dialog_activate(GtkWidget * dialog, const gchar * uri, gpointer data)
766 open_uri(uri);
770 /***
771 * Handle a connect/Disconnect
773 static void playlist_connection_changed(MpdObj * mi, int connect, gpointer data)
775 GtkWidget *pl3_win = playlist3_get_window();
776 /* Set menu items */
777 if (connect)
779 char **handlers;
780 gboolean found = FALSE;
781 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")), TRUE);
782 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1")), TRUE);
784 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConnect")), FALSE);
785 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDDisconnect")), TRUE);
786 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPassword")), TRUE);
787 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_view")), TRUE);
788 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), TRUE);
790 /* Check if MPD supports 'file://' (so local files). */
791 /* TODO: make this a separate function */
792 handlers = mpd_server_get_url_handlers(connection);
793 if (handlers)
795 int i=0;
796 for(; !found && handlers != NULL && handlers[i] != NULL; i++) {
797 if(g_utf8_collate(handlers[i], "file://") == 0) {
798 found = TRUE;
801 g_strfreev(handlers);
803 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "open_local_file")), found);
804 pl3_push_rsb_message(_("Connected"));
805 } else
807 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")), FALSE);
808 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1")), FALSE);
810 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConnect")), TRUE);
811 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDDisconnect")), FALSE);
812 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPassword")), FALSE);
813 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_view")), FALSE);
814 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), FALSE);
815 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "open_local_file")), FALSE);
816 pl3_push_rsb_message(_("Not Connected"));
818 /** Set back to the current borwser, and update window title */
819 if (connect)
821 gchar *string = NULL;
822 GtkTreeIter iter;
823 GtkTreeSelection *selec = gtk_tree_view_get_selection((GtkTreeView *) gtk_builder_get_object(pl3_xml,
824 "cat_tree"));
825 GtkTreeModel *model = GTK_TREE_MODEL(pl3_tree);
826 if (gtk_tree_model_get_iter_first(model, &iter))
828 gtk_tree_selection_select_iter(selec, &iter);
830 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
832 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
833 if (id)
835 string =
836 g_strdup_printf("[%s] %s - %s %s", gmpc_profiles_get_name(gmpc_profiles, id), _("GMPC"),
837 _("Connected to"), mpd_get_hostname(mi));
838 g_free(id);
841 if (!string)
842 string = g_strdup_printf("%s - %s %s", _("GMPC"), _("Connected to"), mpd_get_hostname(mi));
843 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
844 g_free(string);
845 } else
847 gchar *string = NULL;
849 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
851 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
852 if (id)
854 string =
855 g_strdup_printf("[%s] %s - %s", gmpc_profiles_get_name(gmpc_profiles, id), _("GMPC"),
856 _("Disconnected"));
857 g_free(id);
860 if (!string)
861 string = g_strdup_printf("%s - %s", _("GMPC"), _("Disconnected"));
862 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
863 g_free(string);
867 * make the playlist update itself
869 playlist_status_changed(connection,
870 MPD_CST_STATE | MPD_CST_SONGID | MPD_CST_NEXTSONG |
871 MPD_CST_ELAPSED_TIME | MPD_CST_VOLUME |
872 MPD_CST_REPEAT | MPD_CST_RANDOM | MPD_CST_PERMISSION
873 | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE | MPD_CST_UPDATING, NULL);
876 * Also need updating
878 pl3_option_menu_activate();
879 pl3_tool_menu_update();
881 playlist3_fill_server_menu();
884 * update interface
885 * items that are caused by the plugin.
887 pl3_update_go_menu();
891 void pl3_style_set_event( GtkWidget *widget,
892 GtkStyle *previous_style,
893 gpointer user_data)
895 if (cfg_get_single_value_as_int_with_default(config, "Default", "use-dark-style-header", TRUE))
897 gtk_rc_parse_string("widget \"*header*\" style \"dark\"");
901 void create_playlist3(void)
903 GtkWidget *pb,*ali;
904 GtkListStore *pl3_crumbs = NULL;
905 GtkCellRenderer *renderer;
906 GtkWidget *tree;
907 GtkTreeSelection *sel;
908 GtkTreeViewColumn *column = NULL;
909 //GtkStatusbar *statusbar;
910 gchar *path = NULL;
911 GtkTreeIter iter;
912 GError *error = NULL;
913 INIT_TIC_TAC();
914 /* indicate that the playlist is not hidden */
915 pl3_hidden = FALSE;
918 * If the playlist already exists,
919 * It is probably coming from a hidden state,
920 * so re-position the window
922 if (pl3_xml != NULL)
924 pl3_show_and_position_window();
925 return;
928 /** Ambiance / Radiance theme "dark" header */
929 if (cfg_get_single_value_as_int_with_default(config, "Default", "use-dark-style-header", TRUE))
931 gtk_rc_parse_string("widget \"*header*\" style \"dark\"");
934 /** murrine hack */
935 if (cfg_get_single_value_as_int_with_default(config, "Default", "murrine-hack", FALSE))
937 GdkScreen *screen;
938 GdkColormap *colormap;
939 GtkWidget *win = playlist3_get_window();
941 screen = gtk_window_get_screen(GTK_WINDOW(win));
942 colormap = gdk_screen_get_rgba_colormap(screen);
944 if (colormap)
945 gtk_widget_set_default_colormap(colormap);
946 TEC("Murrine hack")
949 /** use background color for the sidebar treeview cells */
950 gtk_rc_parse_string (
951 "style \"sidebar-treeview\"\n"
952 "{\n"
953 " GtkTreeView::odd-row-color = @bg_color\n"
954 " GtkTreeView::even-row-color = @bg_color\n"
955 "}\n"
956 "widget \"*.sidebar.*\" style \"sidebar-treeview\"");
958 /** set handle size to 1px */
959 gtk_rc_parse_string (
960 "style \"hpaned1-style\"\n"
961 "{\n"
962 " GtkPaned::handle-size = 1\n"
963 "}\n"
964 "widget \"*.hpaned1\" style \"hpaned1-style\"\n");
966 /** menubar */
967 gtk_rc_parse_string (
968 "style \"menubar-style\"\n"
969 "{\n"
970 " GtkMenuBar::shadow-type = none\n"
971 "}\n"
972 "widget \"*.menubar\" style \"menubar-style\"\n");
974 /* initial, setting the url hook */
975 gtk_about_dialog_set_url_hook((GtkAboutDialogActivateLinkFunc) about_dialog_activate, NULL, NULL);
976 TEC("Setup dialog url hook")
977 /* load gui desciption */
978 path = gmpc_get_full_glade_path("playlist3.ui");
979 TEC("get path")
980 pl3_xml = gtk_builder_new();
981 TEC("create builder")
982 if(gtk_builder_add_from_file(pl3_xml, path,&error) == 0)
985 * Check if the file is loaded, if not then show an error message and abort the program
986 if (pl3_xml == NULL)
989 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Failed to open playlist3.glade: %s\n", error->message);
990 abort();
992 g_free(path);
993 TEC("Load builder file")
995 /* create tree store for the "category" view */
996 if (pl3_tree == NULL)
998 GType types[] =
1000 G_TYPE_INT, /* row type, see free_type struct */
1001 G_TYPE_STRING, /* display name */
1002 G_TYPE_STRING, /* full path and stuff for backend */
1003 G_TYPE_STRING, /* icon id */
1004 G_TYPE_INT /* ordering */
1006 /* song id, song title */
1007 pl3_tree = (GtkTreeModel *) gmpc_tools_liststore_sort_new();
1008 gtk_list_store_set_column_types(GTK_LIST_STORE(pl3_tree), PL3_CAT_NROWS, types);
1010 TEC("Setup pl3_tree")
1012 thv_init(pl3_tree);
1013 TEC("thv_init")
1015 tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
1017 gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(pl3_tree));
1018 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1019 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(sel), GTK_SELECTION_BROWSE);
1020 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree), TRUE);
1022 renderer = gtk_cell_renderer_pixbuf_new();
1023 renderer->xalign = 1;
1024 column = gtk_tree_view_column_new();
1025 gtk_tree_view_column_pack_start(column, renderer, FALSE);
1026 g_object_set(G_OBJECT(renderer), "stock-size", GTK_ICON_SIZE_MENU, NULL);
1028 int w, h;
1029 if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h))
1031 g_object_set(G_OBJECT(renderer), "height", h+10, NULL);
1032 g_object_set(G_OBJECT(renderer), "width", w+20, NULL);
1035 gtk_tree_view_column_set_attributes(column, renderer, "icon-name", PL3_CAT_ICON_ID, NULL);
1037 renderer = gtk_cell_renderer_text_new();
1038 /* insert the column in the tree */
1039 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1040 gtk_tree_view_column_set_attributes(column, renderer, "text", PL3_CAT_TITLE, NULL);
1041 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1042 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
1043 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree), PL3_CAT_TITLE);
1045 g_signal_connect_after(G_OBJECT(sel), "changed", G_CALLBACK(pl3_cat_sel_changed), NULL);
1047 TEC("setup cat_tree")
1049 * Bread Crumb system.
1051 pl3_crumbs = (GtkListStore *) (pl3_tree);
1052 gtk_combo_box_set_model(GTK_COMBO_BOX
1053 (gtk_builder_get_object(pl3_xml, "cb_cat_selector")), GTK_TREE_MODEL(pl3_crumbs));
1054 renderer = gtk_cell_renderer_pixbuf_new();
1055 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtk_builder_get_object(pl3_xml, "cb_cat_selector")), renderer, FALSE);
1056 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT
1057 (gtk_builder_get_object
1058 (pl3_xml, "cb_cat_selector")), renderer, "icon-name", PL3_CAT_ICON_ID);
1060 renderer = gtk_cell_renderer_text_new();
1061 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtk_builder_get_object(pl3_xml, "cb_cat_selector")), renderer, TRUE);
1062 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT
1063 (gtk_builder_get_object(pl3_xml, "cb_cat_selector")), renderer, "text", PL3_CAT_TITLE);
1065 g_signal_connect(gtk_builder_get_object(pl3_xml, "cb_cat_selector"),
1066 "changed", G_CALLBACK(pl3_cat_combo_changed), NULL);
1068 TEC("setup breadcrumb")
1069 /* initialize the category view */
1070 pl3_initialize_tree();
1072 TEC("Init category tree")
1073 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")));
1076 * The new progress bar
1078 pb = (GtkWidget *) gtk_builder_get_object(pl3_xml, "hbox_progress");
1079 gtk_widget_show(pb);
1080 g_signal_connect(G_OBJECT(pb), "seek-event", G_CALLBACK(pl3_pb_seek_event), NULL);
1082 new_pb = pb;
1084 TEC("Init progress bar")
1085 /* Make sure change is applied */
1087 playlist3_new_header();
1089 pl3_sidebar_plugins_init();
1091 TEC("Init header")
1092 if (!cfg_get_single_value_as_int_with_default(config, "Interface", "hide-favorites-icon", FALSE))
1094 favorites_button = gmpc_favorites_button_new();
1095 ali = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
1096 gtk_container_add(GTK_CONTAINER(ali), GTK_WIDGET(favorites_button));
1097 gtk_box_pack_start(GTK_BOX(gtk_builder_get_object(pl3_xml, "hbox10")), GTK_WIDGET(ali), FALSE, FALSE, 0);
1098 // gtk_box_reorder_child(GTK_BOX(gtk_builder_get_object(pl3_xml,
1099 // "hbox10")),ali,0);
1100 gtk_widget_show_all(GTK_WIDGET(ali));
1101 TEC("Init fav icon")
1103 playlist_status_changed(connection,
1104 MPD_CST_STATE | MPD_CST_SONGID | MPD_CST_NEXTSONG |
1105 MPD_CST_ELAPSED_TIME | MPD_CST_VOLUME |
1106 MPD_CST_REPEAT | MPD_CST_RANDOM | MPD_CST_PERMISSION
1107 | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE, NULL);
1108 g_signal_connect(G_OBJECT(gtk_builder_get_object(pl3_xml, "volume_button")),
1109 "value_changed", G_CALLBACK(playlist_player_volume_changed), NULL);
1111 TEC("Signal setup")
1113 /* Restore values from config */
1114 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION
1115 (gtk_builder_get_object
1116 (pl3_xml, "ViewShowArtistImage")),
1117 cfg_get_single_value_as_int_with_default
1118 (config, "playlist", "cover-image-enable", 0));
1120 /* connect signals that are defined in the gui description */
1121 gtk_builder_connect_signals(pl3_xml,NULL);
1123 TEC("connect signals")
1125 /* select the current playlist */
1126 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_tree), &iter))
1128 gtk_tree_selection_select_iter(sel, &iter);
1131 TEC("Select view")
1133 * Insert new custom widget
1135 metaimage_album_art = gmpc_metaimage_new(META_ALBUM_ART);
1137 /* Hide when requested. */
1138 if (cfg_get_single_value_as_int_with_default(config, "Interface", "hide-album-art", FALSE))
1140 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_album_art), FALSE);
1142 gtk_box_pack_start(GTK_BOX
1143 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")), metaimage_album_art, FALSE, TRUE, 0);
1145 gtk_box_reorder_child(GTK_BOX
1146 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")), metaimage_album_art, 0);
1147 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_album_art), ALBUM_SIZE_LARGE);
1148 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(metaimage_album_art), (char *)"gmpc");
1149 gmpc_metaimage_set_connection(GMPC_METAIMAGE(metaimage_album_art), connection);
1150 /** make sure size is updated */
1151 gmpc_metaimage_set_cover_na(GMPC_METAIMAGE(metaimage_album_art));
1153 metaimage_artist_art = gmpc_metaimage_new(META_ARTIST_ART);
1154 // gtk_box_pack_start(GTK_BOX(gtk_builder_get_object(pl3_xml, "sidebar_artist_image_alignment")), metaimage_artist_art, FALSE, TRUE, 0);
1155 gtk_container_add(GTK_CONTAINER(gtk_builder_get_object(pl3_xml, "sidebar_artist_image_alignment")), metaimage_artist_art);
1157 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(metaimage_artist_art), (char *)"no-artist");
1158 gmpc_metaimage_set_loading_cover_icon(GMPC_METAIMAGE(metaimage_artist_art), (char *)"fetching-artist");
1159 gmpc_metaimage_set_connection(GMPC_METAIMAGE(metaimage_artist_art), connection);
1160 if (!cfg_get_single_value_as_int_with_default(config, "playlist", "cover-image-enable", FALSE))
1162 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1164 gmpc_metaimage_set_squared(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1165 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_artist_art), 200);
1167 TEC("Setup metaimages")
1168 /* restore the window's position and size, if the user wants this. */
1169 if (cfg_get_single_value_as_int_with_default(config, "playlist", "savepossize", 1))
1171 int maximized = cfg_get_single_value_as_int_with_default(config, "playlist", "maximized", 0);
1172 /* Load values from config file */
1173 pl3_wsize.x = cfg_get_single_value_as_int_with_default(config, "playlist", "xpos", 0);
1174 pl3_wsize.y = cfg_get_single_value_as_int_with_default(config, "playlist", "ypos", 0);
1175 pl3_wsize.width = cfg_get_single_value_as_int_with_default(config, "playlist", "width", 0);
1176 pl3_wsize.height = cfg_get_single_value_as_int_with_default(config, "playlist", "height", 0);
1177 TEC("get settings")
1178 /* restore location + position */
1179 /*pl3_show_and_position_window(); */
1181 if (pl3_wsize.x > 0 || pl3_wsize.y > 0)
1183 gtk_window_move(GTK_WINDOW(playlist3_get_window()), pl3_wsize.x, pl3_wsize.y);
1185 TEC("move window settings")
1186 if (pl3_wsize.height > 0 && pl3_wsize.width > 0)
1188 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
1189 gtk_window_resize(GTK_WINDOW(playlist3_get_window()), pl3_wsize.width, pl3_wsize.height);
1191 TEC("resize window settings")
1192 /* restore pane position */
1193 if (cfg_get_single_value_as_int(config, "playlist", "pane-pos") != CFG_INT_NOT_DEFINED)
1195 gtk_paned_set_position(GTK_PANED
1196 (gtk_builder_get_object(pl3_xml, "hpaned1")),
1197 cfg_get_single_value_as_int(config, "playlist", "pane-pos"));
1199 TEC("set pane window settings")
1200 if (maximized)
1201 gtk_window_maximize(GTK_WINDOW(playlist3_get_window()));
1202 TEC("maximize pane window settings")
1204 * restore zoom level
1207 gtk_widget_show(playlist3_get_window());
1208 TEC("Show window")
1209 pl3_zoom = cfg_get_single_value_as_int_with_default(config, "playlist", "zoomlevel", PLAYLIST_NO_ZOOM);
1210 playlist_zoom_level_changed();
1211 TEC("zoom level")
1213 #ifdef HAVE_APP_INDICATOR
1214 tray_icon2_update_menu();
1215 #endif
1217 TEC("Restore state")
1218 pl3_update_go_menu();
1219 TEC("Go menu")
1220 /* make it update itself */
1221 pl3_update_profiles_menu(gmpc_profiles, PROFILE_ADDED, -1, NULL);
1222 g_signal_connect(G_OBJECT(gmpc_profiles), "changed", G_CALLBACK(pl3_update_profiles_menu), NULL);
1223 g_signal_connect(G_OBJECT(gmpc_profiles), "changed", G_CALLBACK(pl3_profiles_changed), NULL);
1225 TEC("Update profiles")
1227 * Set as drag destination
1229 gtk_drag_dest_set(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox_playlist_player")),
1230 GTK_DEST_DEFAULT_ALL,
1231 target_table, 6, GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_DEFAULT | GDK_ACTION_MOVE);
1232 g_signal_connect(G_OBJECT
1233 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")),
1234 "drag_data_received", GTK_SIGNAL_FUNC(playlist3_source_drag_data_recieved), NULL);
1236 TEC("setup drag")
1237 /* A signal that responses on change of pane position */
1238 g_signal_connect(G_OBJECT(gtk_builder_get_object(pl3_xml, "hpaned1")),
1239 "notify::position", G_CALLBACK(pl3_win_pane_changed), NULL);
1241 /* update it */
1242 pl3_win_pane_changed(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1")), NULL, NULL);
1243 TEC("setup pos notify")
1247 playlist_connection_changed(connection, FALSE, NULL);
1249 g_signal_connect(G_OBJECT(playlist3_get_window()), "window-state-event", G_CALLBACK(pl3_win_state_event), NULL);
1251 TEC("signal connn changed")
1253 g_signal_connect(G_OBJECT(playlist3_get_window()), "style-set", G_CALLBACK(pl3_style_set_event), NULL);
1256 * Add status icons
1258 main_window_init_default_status_icons();
1259 main_window_update_status_icons();
1261 TEC("Update status icon")
1262 /* Update extra */
1263 init_extra_playlist_state();
1264 TEC("Setup extra playlist")
1269 * Helper functions
1271 GtkListStore *playlist3_get_category_tree_store(void)
1273 if (pl3_xml == NULL)
1274 return NULL;
1275 return GTK_LIST_STORE(pl3_tree);
1279 GtkTreeView *playlist3_get_category_tree_view(void)
1281 if (pl3_xml == NULL)
1282 return NULL;
1283 return (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
1286 GtkWidget* playlist3_get_widget_by_id(const char *id) {
1287 return (GtkWidget *) gtk_builder_get_object(pl3_xml, id);
1291 /****************************************************************************************
1292 * PREFERENCES *
1293 ****************************************************************************************/
1294 /* prototyping for glade */
1295 void ck_stop_on_exit_toggled_cb(GtkToggleButton * but, gpointer data);
1296 void ck_show_tooltip_enable_tb(GtkToggleButton * but);
1297 void ck_show_tabbed_heading_enable_cb(GtkToggleButton * but);
1299 G_MODULE_EXPORT void show_cover_case_tb(GtkToggleButton * but)
1301 int bool1 = gtk_toggle_button_get_active(but);
1302 cfg_set_single_value_as_int(config, "metaimage", "addcase", bool1);
1303 gmpc_meta_watcher_force_reload(gmw);
1307 G_MODULE_EXPORT void ck_stop_on_exit_toggled_cb(GtkToggleButton * but, gpointer data)
1309 int bool1 = gtk_toggle_button_get_active(but);
1310 cfg_set_single_value_as_int(config, "connection", "stop-on-exit", bool1);
1314 G_MODULE_EXPORT void hide_on_close_enable_tb(GtkToggleButton * but)
1316 int bool1 = gtk_toggle_button_get_active(but);
1317 cfg_set_single_value_as_int(config, "playlist", "hide-on-close", bool1);
1321 G_MODULE_EXPORT void cur_song_center_enable_tb(GtkToggleButton * but)
1323 int bool1 = gtk_toggle_button_get_active(but);
1324 cfg_set_single_value_as_int(config, "playlist", "st_cur_song", bool1);
1328 G_MODULE_EXPORT void save_possize_enable_tb(GtkToggleButton * but)
1330 int bool1 = gtk_toggle_button_get_active(but);
1331 cfg_set_single_value_as_int(config, "playlist", "savepossize", bool1);
1335 G_MODULE_EXPORT void ck_show_tooltip_enable_tb(GtkToggleButton * but)
1337 int bool1 = gtk_toggle_button_get_active(but);
1338 cfg_set_single_value_as_int(config, "GmpcTreeView", "show-tooltip", bool1);
1342 G_MODULE_EXPORT void ck_show_tabbed_heading_enable_cb(GtkToggleButton * but)
1344 int bool1 = gtk_toggle_button_get_active(but);
1345 int old = cfg_get_single_value_as_int_with_default(config, "playlist",
1346 "button-heading", FALSE);
1347 if (old == FALSE && bool1 == TRUE)
1349 if (pl3_zoom == PLAYLIST_SMALL)
1351 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "bread_crumb")));
1352 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "box_tab_bar")));
1355 if (old == TRUE && bool1 == FALSE)
1357 if (pl3_zoom == PLAYLIST_SMALL)
1359 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "bread_crumb")));
1360 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "box_tab_bar")));
1363 cfg_set_single_value_as_int(config, "playlist", "button-heading", bool1);
1367 G_MODULE_EXPORT void ck_search_as_you_type(GtkToggleButton * but)
1369 int bool1 = gtk_toggle_button_get_active(but);
1370 cfg_set_single_value_as_int(config, "general", "search-as-you-type", bool1);
1374 static void playlist_pref_destroy(GtkWidget * container)
1376 if (playlist_pref_xml)
1378 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(playlist_pref_xml,
1379 "playlist-vbox");
1380 gtk_container_remove(GTK_CONTAINER(container), vbox);
1381 g_object_unref(playlist_pref_xml);
1382 playlist_pref_xml = NULL;
1387 void playlist_pref_construct(GtkWidget * container)
1389 GError *error = NULL;
1390 gchar *path = gmpc_get_full_glade_path("preferences-playlist.ui");
1391 playlist_pref_xml = gtk_builder_new();
1393 gtk_builder_add_from_file(playlist_pref_xml, path, &error);
1394 if(error) {
1395 g_warning("Failed to open builder file: %s", error->message);
1396 g_error_free(error);
1397 return;
1399 if (playlist_pref_xml)
1401 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(playlist_pref_xml,
1402 "playlist-vbox");
1403 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1404 (gtk_builder_get_object
1405 (playlist_pref_xml, "ck_ps")),
1406 cfg_get_single_value_as_int_with_default(config, "playlist", "st_cur_song", 0));
1407 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1408 (gtk_builder_get_object
1409 (playlist_pref_xml, "ck_possize")),
1410 cfg_get_single_value_as_int_with_default(config, "playlist", "savepossize", 1));
1411 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1412 (gtk_builder_get_object
1413 (playlist_pref_xml, "ck_hide_on_close")),
1414 cfg_get_single_value_as_int_with_default(config, "playlist", "hide-on-close", 0));
1416 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1417 (gtk_builder_get_object
1418 (playlist_pref_xml, "ck_stop_on_exit")),
1419 cfg_get_single_value_as_int_with_default(config, "connection", "stop-on-exit", 0));
1421 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1422 (gtk_builder_get_object
1423 (playlist_pref_xml, "ck_cover_case")),
1424 cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase", TRUE));
1426 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1427 (gtk_builder_get_object
1428 (playlist_pref_xml, "ck_show_tooltip")),
1429 cfg_get_single_value_as_int_with_default
1430 (config, "GmpcTreeView", "show-tooltip", TRUE));
1431 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1432 (gtk_builder_get_object
1433 (playlist_pref_xml,
1434 "ck_show_tabbed_heading")),
1435 cfg_get_single_value_as_int_with_default
1436 (config, "playlist", "button-heading", FALSE));
1438 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1439 (gtk_builder_get_object
1440 (playlist_pref_xml, "ck_search_as_you_type")),
1441 cfg_get_single_value_as_int_with_default(config, "general", "search-as-you-type",
1442 0));
1443 gtk_container_add(GTK_CONTAINER(container), vbox);
1444 gtk_widget_show_all(vbox);
1445 gtk_builder_connect_signals(playlist_pref_xml, NULL);
1447 g_free(path);
1452 * Menu Callback functions
1455 void playlist_menu_repeat_changed(GtkToggleAction * action)
1457 int active = gtk_toggle_action_get_active(action);
1458 if (active != mpd_player_get_repeat(connection))
1460 mpd_player_set_repeat(connection, active);
1465 void playlist_menu_random_changed(GtkToggleAction *action)
1467 int active = gtk_toggle_action_get_active(action);
1468 if (active != mpd_player_get_random(connection))
1470 mpd_player_set_random(connection, active);
1475 void playlist_menu_single_mode_changed(GtkToggleAction * action)
1477 int active = gtk_toggle_action_get_active(action);
1478 if (active != mpd_player_get_single(connection))
1480 mpd_player_set_single(connection, active);
1485 void playlist_menu_consume_changed(GtkToggleAction * action)
1487 int active = gtk_toggle_action_get_active(action);
1488 if (active != mpd_player_get_consume(connection))
1490 mpd_player_set_consume(connection, active);
1496 * This is artist image
1497 * FIXME: Rename
1499 void playlist_menu_artist_image_changed(GtkToggleAction *ta)
1501 int active = gtk_toggle_action_get_active(ta);
1502 cfg_set_single_value_as_int(config, "playlist", "cover-image-enable", active);
1504 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), active);
1505 if (active)
1506 gtk_widget_show(metaimage_artist_art);
1510 /***
1511 * Zooming functions
1513 void playlist_zoom_out(void)
1515 /* Do not change zoom level when fullscreen */
1516 if(pl3_window_is_fullscreen())
1517 return;
1518 if ((pl3_zoom + 1) >= PLAYLIST_ZOOM_LEVELS)
1519 return;
1520 pl3_old_zoom = pl3_zoom;
1521 pl3_zoom++;
1522 playlist_zoom_level_changed();
1526 void playlist_zoom_in(void)
1528 /* Do not change zoom level when fullscreen */
1529 if(pl3_window_is_fullscreen())
1530 return;
1531 if (pl3_zoom <= PLAYLIST_NO_ZOOM)
1532 return;
1533 pl3_old_zoom = pl3_zoom;
1534 pl3_zoom--;
1535 playlist_zoom_level_changed();
1540 * FIXME: Needs propper grouping and cleaning up
1542 static void playlist_zoom_level_changed(void)
1544 GtkWidget *pl3_win = playlist3_get_window();
1546 if (pl3_old_zoom <= PLAYLIST_SMALL)
1548 gtk_window_get_size(GTK_WINDOW(pl3_win), &pl3_wsize.width, &pl3_wsize.height);
1549 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
1550 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
1551 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
1554 if (pl3_old_zoom == PLAYLIST_MINI && pl3_zoom != PLAYLIST_MINI)
1556 GtkWidget *box =GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box"));
1557 GtkWidget *top = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10"));
1558 GtkWidget *vtop = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player"));
1559 /* add my own reference */
1560 g_object_ref(box);
1561 gtk_container_remove(GTK_CONTAINER(vtop), box);
1562 gtk_box_pack_end(GTK_BOX(top), box, FALSE, TRUE, 0);
1563 gtk_box_reorder_child(GTK_BOX(top), box, 0);
1564 /* release my reference */
1565 g_object_unref(box);
1566 gtk_widget_show(box);
1567 gmpc_progress_set_hide_text(GMPC_PROGRESS(new_pb), FALSE);
1569 /* Album image only if enabled. */
1570 if(metaimage_album_art != NULL)
1572 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_album_art), ALBUM_SIZE_LARGE);
1573 gmpc_metaimage_reload_image(GMPC_METAIMAGE(metaimage_album_art));
1577 if (pl3_old_zoom != PLAYLIST_MINI && pl3_zoom == PLAYLIST_MINI)
1579 GtkWidget *box =GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box"));
1580 GtkWidget *top = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10"));
1581 GtkWidget *vtop = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player"));
1582 /* add my own reference */
1583 g_object_ref(box);
1584 gtk_container_remove(GTK_CONTAINER(top), box);
1585 gtk_box_pack_end(GTK_BOX(vtop), box, FALSE, TRUE, 3);
1586 /* release my reference */
1587 g_object_unref(box);
1588 gtk_widget_show(box);
1590 gmpc_progress_set_hide_text(GMPC_PROGRESS(new_pb), TRUE);
1592 /* Album image only if enabled. */
1593 if(metaimage_album_art != NULL)
1595 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_album_art), ALBUM_SIZE_SMALL);
1596 gmpc_metaimage_reload_image(GMPC_METAIMAGE(metaimage_album_art));
1601 /* Show full view */
1602 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1")));
1603 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox1")));
1604 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10")));
1605 /** Menu Bar */
1606 /** BUTTON BOX */
1607 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box")));
1609 gtk_window_set_resizable(GTK_WINDOW(pl3_win), TRUE);
1610 if (pl3_wsize.width > 0 && pl3_wsize.height > 0 && pl3_old_zoom == PLAYLIST_MINI)
1612 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
1613 gtk_window_resize(GTK_WINDOW(pl3_win), pl3_wsize.width, pl3_wsize.height);
1615 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1616 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "bread_crumb")));
1617 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "box_tab_bar")));
1618 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")),TRUE);
1619 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")),TRUE);
1621 /* Now start hiding */
1622 switch (pl3_zoom)
1624 case PLAYLIST_NO_ZOOM:
1625 break;
1626 case PLAYLIST_MINI:
1627 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1")));
1628 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")),FALSE);
1629 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")),FALSE);
1630 if (pl3_win->window)
1632 if (gdk_window_get_state(pl3_win->window) & GDK_WINDOW_STATE_MAXIMIZED)
1634 gtk_window_unmaximize(GTK_WINDOW(pl3_win));
1637 if (gdk_window_get_state(pl3_win->window) & GDK_WINDOW_STATE_FULLSCREEN)
1639 gtk_window_unfullscreen(GTK_WINDOW(pl3_win));
1642 gtk_window_set_resizable(GTK_WINDOW(pl3_win), FALSE);
1644 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1645 break;
1646 case PLAYLIST_SMALL:
1647 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1648 if (!cfg_get_single_value_as_int_with_default(config, "playlist", "button-heading", FALSE))
1649 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "bread_crumb")));
1650 else
1651 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "box_tab_bar")));
1653 gtk_widget_grab_focus(pl3_win);
1654 default:
1655 break;
1657 /** Save zoom level
1659 cfg_set_single_value_as_int(config, "playlist", "zoomlevel", pl3_zoom);
1664 * Update the window to status changes in mpd
1666 static void playlist_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata)
1668 char buffer[1024];
1669 GtkWidget *pl3_win = playlist3_get_window();
1671 * if the window isn't there yet, return
1673 if (!pl3_xml)
1674 return;
1675 control_window_status_update(mi, what, control_window);
1677 * Player state changed
1679 if (what & MPD_CST_STATE)
1681 mpd_Song *song = mpd_playlist_get_current_song(connection);
1682 int state = mpd_player_get_state(mi);
1683 switch (state)
1685 case MPD_PLAYER_PLAY:
1687 gchar *markup = cfg_get_single_value_as_string_with_default(config,
1688 "playlist", /* Category */
1689 "window-markup",/* Key */
1690 /* default value */
1691 "[%title% - &[%artist%]]|%name%|%shortfile%"
1694 * Update the image in the menu
1696 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-pause");
1697 gtk_image_set_from_stock(GTK_IMAGE
1698 (gtk_builder_get_object
1699 (pl3_xml, "play_button_image")), "gtk-media-pause",
1700 GTK_ICON_SIZE_MENU);
1703 * Update window title
1705 mpd_song_markup(buffer, 1024, markup, mpd_playlist_get_current_song(connection));
1707 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1709 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1710 if (id)
1712 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1713 id), buffer);
1714 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1715 g_free(id);
1716 g_free(string);
1718 } else
1719 gtk_window_set_title(GTK_WINDOW(pl3_win), buffer);
1721 g_free(markup);
1722 break;
1724 case MPD_PLAYER_PAUSE:
1726 gchar *markup = cfg_get_single_value_as_string_with_default(config,
1727 "playlist", /* Category */
1728 "window-markup",/* Key */
1729 /* default value */
1730 "[%title% - &[%artist%]]|%name%|%shortfile%"
1732 /** Update menu and button images */
1734 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-play");
1735 gtk_image_set_from_stock(GTK_IMAGE
1736 (gtk_builder_get_object
1737 (pl3_xml, "play_button_image")), "gtk-media-play",
1738 GTK_ICON_SIZE_MENU);
1740 * Set paused in Window string
1742 mpd_song_markup(buffer, 1024 - strlen(_("paused") - 4),
1743 markup, mpd_playlist_get_current_song(connection));
1744 /* Append translated paused */
1745 strcat(buffer, " (");
1746 strcat(buffer, _("paused"));
1747 strcat(buffer, ")");
1749 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1751 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1752 if (id)
1754 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1755 id), buffer);
1756 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1757 g_free(id);
1758 g_free(string);
1760 } else
1761 gtk_window_set_title(GTK_WINDOW(pl3_win), buffer);
1762 g_free(markup);
1763 break;
1765 default:
1766 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-play");
1767 /* Make sure it's reset correctly */
1768 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), 0, 0);
1770 gtk_image_set_from_stock(GTK_IMAGE
1771 (gtk_builder_get_object
1772 (pl3_xml, "play_button_image")), "gtk-media-play",
1773 GTK_ICON_SIZE_MENU);
1774 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1776 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1777 if (id)
1779 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1780 id), _("GMPC"));
1781 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1782 g_free(id);
1783 g_free(string);
1785 } else
1786 gtk_window_set_title(GTK_WINDOW(pl3_win), _("GMPC"));
1788 playlist3_update_header();
1790 if(favorites_button != NULL)
1792 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
1794 gmpc_favorites_button_set_song(favorites_button, song);
1795 } else
1797 gmpc_favorites_button_set_song(favorites_button, NULL);
1802 * Handle song change or Playlist change
1803 * Anything that can change metadta
1805 if (what & MPD_CST_SONGID || what & MPD_CST_SONGPOS || what & MPD_CST_PLAYLIST)
1807 playlist3_update_header();
1808 /* make is update markups and stuff */
1809 playlist_status_changed(mi, MPD_CST_STATE, NULL);
1812 * set repeat buttons in menu correct
1814 if (what & MPD_CST_REPEAT)
1816 if (mpd_check_connected(connection))
1818 char *string = g_strdup_printf(_("Repeat: %s"),
1819 (mpd_player_get_repeat(connection)) ? _("On") : _("Off"));
1820 pl3_push_statusbar_message(string);
1821 g_free(string);
1823 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDRepeat")),
1824 mpd_player_get_repeat(connection));
1828 if (what & MPD_CST_RANDOM)
1830 if (mpd_check_connected(connection))
1832 char *string = g_strdup_printf(_("Random: %s"),
1833 (mpd_player_get_random(connection)) ? _("On") : _("Off"));
1834 pl3_push_statusbar_message(string);
1835 g_free(string);
1837 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDRandom")),
1838 mpd_player_get_random(connection));
1841 if (what & (MPD_CST_RANDOM | MPD_CST_REPEAT | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE))
1843 main_window_update_status_icons();
1845 if (what & MPD_CST_SINGLE_MODE)
1847 if (mpd_check_connected(connection))
1849 char *string = g_strdup_printf(_("Single mode: %s"),
1850 (mpd_player_get_single(connection)) ? _("On") : _("Off"));
1851 pl3_push_statusbar_message(string);
1852 g_free(string);
1854 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDSingleMode")),
1855 mpd_player_get_single(connection));
1859 if (what & MPD_CST_CONSUME_MODE)
1861 if (mpd_check_connected(connection))
1863 char *string = g_strdup_printf(_("Consume: %s"),
1864 (mpd_player_get_consume(connection)) ? _("On") : _("Off"));
1865 pl3_push_statusbar_message(string);
1866 g_free(string);
1868 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDConsumeMode")),
1869 mpd_player_get_consume(connection));
1872 if (what & MPD_CST_ELAPSED_TIME)
1874 if (mpd_check_connected(connection))
1876 int totalTime = mpd_status_get_total_song_time(connection);
1877 int elapsedTime = mpd_status_get_elapsed_song_time(connection);
1878 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), totalTime, elapsedTime);
1879 } else
1882 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), 0, 0);
1885 if (what & MPD_CST_PERMISSION)
1887 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDSingleMode")),
1889 mpd_check_connected(connection) &&
1890 mpd_server_check_command_allowed(connection, "single") == MPD_SERVER_COMMAND_ALLOWED
1893 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConsumeMode")),
1895 mpd_check_connected(connection) &&
1896 mpd_server_check_command_allowed(connection, "consume") == MPD_SERVER_COMMAND_ALLOWED
1899 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")),
1901 mpd_check_connected(connection) &&
1902 mpd_server_check_command_allowed(connection, "play") == MPD_SERVER_COMMAND_ALLOWED
1905 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDNext")),
1907 mpd_check_connected(connection) &&
1908 mpd_server_check_command_allowed(connection, "next") == MPD_SERVER_COMMAND_ALLOWED
1911 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPrevious")),
1913 mpd_check_connected(connection) &&
1914 mpd_server_check_command_allowed(connection, "previous") == MPD_SERVER_COMMAND_ALLOWED
1917 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDStop")),
1919 mpd_check_connected(connection) &&
1920 mpd_server_check_command_allowed(connection, "stop") == MPD_SERVER_COMMAND_ALLOWED
1923 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDRepeat")),
1925 mpd_check_connected(connection) &&
1926 mpd_server_check_command_allowed(connection, "repeat") == MPD_SERVER_COMMAND_ALLOWED
1929 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDRandom")),
1931 mpd_check_connected(connection)&&
1932 mpd_server_check_command_allowed(connection, "random") == MPD_SERVER_COMMAND_ALLOWED
1935 /* Also update volume stuff */
1936 what = what|MPD_CST_VOLUME;
1939 if (what & MPD_CST_VOLUME)
1941 GtkWidget *volume_button = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "volume_button"));
1942 //gtk_scale_button_get_value(GTK_SCALE_BUTTON(volume_button)) * 100;
1943 int volume = gmpc_widgets_volume_get_volume_level(GMPC_WIDGETS_VOLUME(volume_button));
1944 int new_volume = mpd_status_get_volume(connection);
1945 if (new_volume >= 0 &&
1946 mpd_server_check_command_allowed(connection, "setvol") == MPD_SERVER_COMMAND_ALLOWED
1949 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDMuted")),
1950 TRUE
1952 gtk_widget_set_sensitive(volume_button, TRUE);
1953 /* don't do anything if nothing is changed */
1954 if (new_volume != volume)
1956 gmpc_widgets_volume_set_volume_level(GMPC_WIDGETS_VOLUME(volume_button), new_volume );
1958 } else
1960 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDMuted")),
1961 FALSE
1963 gtk_widget_set_sensitive(volume_button, FALSE);
1966 if (what & MPD_CST_SERVER_ERROR)
1968 gchar *error = mpd_status_get_mpd_error(mi);
1969 if (error)
1971 gchar *mes = g_markup_printf_escaped("%s: '%s'",
1972 _("MPD Reported the following error"),
1973 error);
1974 playlist3_show_error_message(mes, ERROR_WARNING);
1975 g_free(mes);
1976 g_free(error);
1979 if (what & MPD_CST_OUTPUT)
1981 playlist3_fill_server_menu();
1983 if (what & MPD_CST_NEXTSONG)
1986 GtkWidget *next_button = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "next_button"));
1987 if (next_button)
1989 int i = mpd_player_get_next_song_id(mi);
1990 if (i >= 0)
1992 mpd_Song *song = mpd_playlist_get_song(mi, i);
1993 if (song)
1995 mpd_song_markup(buffer, 1024, "[%title% - &[%artist%]]|%shortfile%", song);
1996 gtk_widget_set_tooltip_text(next_button, buffer);
1997 mpd_freeSong(song);
1998 } else
1999 gtk_widget_set_tooltip_text(next_button, "");
2000 } else
2001 gtk_widget_set_tooltip_text(next_button, "");
2006 gboolean playlist_player_volume_changed(GtkWidget * vol_but, int new_vol)
2008 int volume = new_vol; //gtk_scale_button_get_value(GTK_SCALE_BUTTON(vol_but)) * 100;
2009 int new_volume = mpd_status_get_volume(connection);
2010 if (new_volume >= 0 && new_volume != volume)
2012 mpd_status_set_volume(connection, volume);
2013 return FALSE;
2015 return FALSE;
2019 void about_window(void)
2021 gchar *path = gmpc_get_full_glade_path("aboutdialog.ui");
2022 GtkBuilder *xml = gtk_builder_new();
2023 GtkWidget *dialog = NULL;
2024 gtk_builder_add_from_file(xml, path, NULL);
2025 dialog = (GtkWidget *) gtk_builder_get_object(xml, "aboutdialog");
2027 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(playlist3_get_window()));
2028 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
2029 g_free(path);
2031 if (strlen(revision))
2033 path = g_strdup_printf("%s\nRevision: %s", VERSION, revision);
2034 } else
2036 path = g_strdup_printf("%s\n%s\n", VERSION, GMPC_TAGLINE);
2038 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), GMPC_COPYRIGHT);
2039 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), _("Gnome Music Player Client"));
2040 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), GMPC_WEBSITE);
2041 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), path);
2043 g_free(path);
2044 gtk_widget_show(dialog);
2045 gtk_dialog_run(GTK_DIALOG(dialog));
2046 gtk_widget_destroy(dialog);
2047 g_object_unref(xml);
2051 /****************************************************
2052 * Interface stuff
2054 void pl3_update_go_menu(void)
2056 int i = 0;
2057 int items = 0;
2058 GtkWidget *menu = NULL;
2059 GtkAccelGroup *group = playlist3_get_accel_group();
2060 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2061 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_go"));
2062 /***
2063 * Remove any old menu
2065 gtk_menu_item_set_submenu(m_item, NULL);
2067 * Create a new menu
2069 menu = gtk_menu_new();
2070 gtk_menu_set_accel_group(GTK_MENU(menu), group);
2071 if (mpd_check_connected(connection))
2073 for (i = 0; i < num_plugins; i++)
2075 if (gmpc_plugin_is_browser(plugins[i]))
2077 items += gmpc_plugin_browser_add_go_menu(plugins[i], menu);
2083 * Attach menu
2085 if (items)
2087 gtk_widget_show_all(menu);
2088 gtk_menu_item_set_submenu(m_item, menu);
2089 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")), TRUE);
2090 } else
2092 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")), FALSE);
2093 g_object_ref_sink(menu);
2094 g_object_unref(menu);
2099 static void pl3_profile_selected(GtkRadioMenuItem * radio, gpointer data)
2101 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(radio)))
2103 gchar *uid = g_object_get_data(G_OBJECT(radio), "uid");
2104 if (!uid)
2106 return;
2108 connection_set_current_profile(uid);
2109 if (mpd_check_connected(connection))
2111 mpd_disconnect(connection);
2112 connect_to_mpd();
2118 static void pl3_profiles_changed(GmpcProfiles * prof, const int changed, const int col, const gchar * id)
2120 if (changed == PROFILE_ADDED)
2122 gchar *message = g_strdup_printf("%s '%s' %s ", _("Profile"),
2123 gmpc_profiles_get_name(prof, id), _("added"));
2124 pl3_push_statusbar_message(message);
2125 g_free(message);
2126 } else if (changed == PROFILE_COL_CHANGED && col == PROFILE_COL_HOSTNAME)
2128 gchar *message = g_strdup_printf("%s '%s' %s %s",
2129 _("Profile"),
2130 gmpc_profiles_get_name(prof, id),
2131 _("changed hostname to:"),
2132 gmpc_profiles_get_hostname(prof, id));
2133 pl3_push_statusbar_message(message);
2134 g_free(message);
2136 if (!mpd_check_connected(connection))
2138 playlist_connection_changed(connection, 0, NULL);
2143 static void pl3_update_profiles_menu(GmpcProfiles * prof, const int changed, const int col, const gchar * id)
2145 int items = 0;
2146 GtkWidget *menu = NULL;
2147 gchar *current = gmpc_profiles_get_current(gmpc_profiles);
2148 GList *iter, *mult;
2149 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2150 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_music/menu_profiles"));
2151 /* check if there is anything changed that is important for us. */
2153 if (changed == PROFILE_COL_CHANGED && col != PROFILE_COL_NAME)
2155 g_free(current);
2156 return;
2158 /***
2159 * Remove any old menu
2161 gtk_menu_item_set_submenu(m_item, NULL);
2163 * Create a new menu
2165 menu = gtk_menu_new();
2167 mult = gmpc_profiles_get_profiles_ids(gmpc_profiles);
2168 if (mult)
2170 GSList *group = NULL;
2171 iter = mult;
2174 /** Get profile name */
2175 const gchar *value = gmpc_profiles_get_name(gmpc_profiles, (char *)iter->data);
2176 GtkWidget *item = gtk_radio_menu_item_new_with_label(group, value);
2177 /* get new group */
2178 group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
2179 /* add to the menu */
2180 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2182 /* check the current profile */
2183 if (!strcmp((char *)(iter->data), current))
2185 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
2189 * Attach click handler
2191 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_profile_selected), NULL);
2193 /** Attach the uid to the handler */
2194 value = g_strdup((char *)(iter->data));
2195 g_object_set_data_full(G_OBJECT(item), "uid", (gpointer) value, g_free);
2197 items++;
2198 } while ((iter = g_list_next(iter)));
2199 g_list_foreach(mult, (GFunc) g_free, NULL);
2200 g_list_free(mult);
2205 * Attach menu
2207 if (items)
2209 gtk_widget_show_all(menu);
2210 gtk_menu_item_set_submenu(m_item , menu);
2211 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_profiles")), TRUE);
2212 } else
2214 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_profiles")), FALSE);
2215 g_object_ref_sink(menu);
2216 g_object_unref(menu);
2218 g_free(current);
2222 static void playlist3_server_output_changed(GtkWidget * item, gpointer data)
2224 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "id"));
2225 int state = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
2226 mpd_server_set_output_device(connection, id, state);
2231 void playlist3_server_update_db(void)
2233 mpd_database_update_dir(connection, "/");
2237 static GList *server_menu_items = NULL;
2238 static void playlist3_fill_server_menu(void)
2240 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2241 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_server"));
2242 /** Clear old items */
2243 if(server_menu_items != NULL)
2245 g_list_foreach(server_menu_items, (GFunc)gtk_widget_destroy, NULL);
2246 g_list_free(server_menu_items);
2247 server_menu_items = NULL;
2250 /* if connected fill with items */
2251 if (mpd_check_connected(connection))
2253 GtkWidget *menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(m_item));
2254 GtkWidget *menu_item = NULL;
2255 int i = 0;
2256 MpdData *data = NULL;
2258 data = mpd_server_get_output_devices(connection);
2259 if(data)
2261 menu_item = gtk_separator_menu_item_new();
2262 server_menu_items = g_list_append(server_menu_items, menu_item);
2263 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
2265 for (; data; data = mpd_data_get_next(data))
2267 menu_item = gtk_check_menu_item_new_with_label(data->output_dev->name);
2268 server_menu_items = g_list_append(server_menu_items, menu_item);
2269 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), data->output_dev->enabled ? TRUE : FALSE);
2270 gtk_widget_add_accelerator(menu_item, "activate",
2271 gtk_ui_manager_get_accel_group(GTK_UI_MANAGER(ui)),
2272 GDK_1 + i, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
2274 g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(playlist3_server_output_changed), NULL);
2275 g_object_set_data(G_OBJECT(menu_item), "id", GINT_TO_POINTER(data->output_dev->id));
2276 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
2277 i++;
2279 gtk_widget_show_all(menu);
2280 /* Server Menu Item */
2281 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_server")), TRUE);
2282 } else
2284 /* Server Menu Item */
2285 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_server")), FALSE);
2291 * new header
2293 /* glue code */
2295 extern GmpcBrowsersMetadata *browsers_metadata;
2297 void info2_activate(void)
2299 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
2300 gmpc_browsers_metadata_select_browser(browsers_metadata, tree);
2304 void info2_fill_song_view(mpd_Song * song)
2306 info2_activate();
2307 gmpc_browsers_metadata_set_song(browsers_metadata, song);
2311 void info2_fill_artist_view(const gchar * artist)
2313 info2_activate();
2314 gmpc_browsers_metadata_set_artist(browsers_metadata, artist);
2318 void info2_fill_album_view(const gchar * artist, const gchar * album)
2320 info2_activate();
2321 gmpc_browsers_metadata_set_album(browsers_metadata, artist, album);
2325 void playlist3_insert_browser(GtkTreeIter * iter, gint position)
2327 GtkTreeIter it, *sib = NULL;
2328 gint pos = 0;
2329 GtkTreeModel *model = GTK_TREE_MODEL(pl3_tree);
2330 if (gtk_tree_model_get_iter_first(model, &it))
2334 gtk_tree_model_get(model, &it, PL3_CAT_ORDER, &pos, -1);
2335 if (position <= pos)
2336 sib = &it;
2337 } while (sib == NULL && gtk_tree_model_iter_next(model, &it));
2339 gtk_list_store_insert_before(GTK_LIST_STORE(pl3_tree), iter, sib);
2340 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), iter, PL3_CAT_ORDER, position, -1);
2345 * Category editing
2348 void playlist3_destroy(void)
2350 GtkWidget *win = playlist3_get_window();
2351 if(server_menu_items) g_list_free(server_menu_items);
2352 gtk_widget_destroy(win);
2353 g_object_unref(pl3_xml);
2357 gboolean playlist3_show_playtime(gulong playtime)
2359 if (playtime)
2361 gchar *string = format_time(playtime);
2362 pl3_push_rsb_message(string);
2363 g_free(string);
2364 } else
2366 pl3_push_rsb_message("");
2368 return FALSE;
2372 GtkWidget *playlist3_get_window(void)
2374 return GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_win"));
2378 /***
2379 * Help menu
2381 /* Make glade happy */
2382 void url_visit_website(void);
2383 void url_getting_help(void);
2385 void url_visit_website(void)
2387 open_uri(GMPC_WEBSITE);
2391 void url_getting_help(void)
2393 open_uri(GMPC_BUGTRACKER);
2397 gmpcPrefPlugin playlist_gpp =
2399 .construct = playlist_pref_construct,
2400 .destroy = playlist_pref_destroy
2403 gmpcPlugin playlist_plug =
2405 .name = N_("Interface"),
2406 .version = {1, 1, 1},
2407 .plugin_type = GMPC_INTERNALL,
2408 .mpd_status_changed = &playlist_status_changed,
2409 .mpd_connection_changed = &playlist_connection_changed,
2410 .pref = &playlist_gpp,
2415 * Tool menu
2418 void pl3_tool_menu_update(void)
2420 int i;
2421 int menu_items = 0;
2422 GtkWidget *menu = NULL;
2423 GtkAccelGroup *group = gtk_accel_group_new();
2424 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2425 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_tool"));
2426 gtk_menu_item_set_submenu(m_item, NULL);
2427 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_tool")), FALSE);
2428 if (!mpd_check_connected(connection))
2429 return;
2431 menu = gtk_menu_new();
2432 gtk_menu_set_accel_group(GTK_MENU(menu), group);
2433 g_object_unref(group);
2434 gtk_window_add_accel_group(GTK_WINDOW(playlist3_get_window()), group);
2435 for (i = 0; i < num_plugins; i++)
2437 menu_items += gmpc_plugin_tool_menu_integration(plugins[i], GTK_MENU(menu));
2439 if (menu_items)
2441 gtk_widget_show_all(menu);
2442 gtk_menu_item_set_submenu(m_item, menu);
2443 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_tool")), TRUE);
2444 } else
2446 g_object_ref_sink(menu);
2447 g_object_unref(menu);
2452 void easy_command_help_window(void)
2454 if (gmpc_easy_command)
2455 gmpc_easy_command_help_window(gmpc_easy_command, NULL);
2461 * Extra wrappings for menu
2463 extern gmpcPlugin extraplaylist_plugin;
2464 void enable_extra_playlist(GtkToggleAction *action)
2466 gboolean state = gtk_toggle_action_get_active(action);
2467 if(extraplaylist_plugin.set_enabled)
2469 if(extraplaylist_plugin.get_enabled() != state)
2471 extraplaylist_plugin.set_enabled(state);
2474 preferences_window_update();
2478 void init_extra_playlist_state(void)
2480 GtkToggleAction *action = GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "ViewExtraPlaylist"));
2481 if(extraplaylist_plugin.get_enabled)
2483 gtk_toggle_action_set_active(action, extraplaylist_plugin.get_enabled());
2487 GtkAccelGroup *playlist3_get_accel_group(void)
2489 static GtkAccelGroup *group = NULL;
2490 if(group == NULL) {
2491 group = gtk_accel_group_new();
2492 gtk_window_add_accel_group(GTK_WINDOW(playlist3_get_window()), group);
2494 return group;
2497 void open_local_file(void)
2499 char **handlers;
2500 gboolean found = FALSE;
2501 if(!mpd_check_connected(connection))
2502 return;
2504 /* Check if MPD supports 'file://' (so local files). */
2505 handlers = mpd_server_get_url_handlers(connection);
2506 if (handlers)
2508 int i=0;
2509 for(; !found && handlers != NULL && handlers[i] != NULL; i++) {
2510 if(g_utf8_collate(handlers[i], "file://") == 0) {
2511 found = TRUE;
2514 g_strfreev(handlers);
2516 /* error message or file open */
2517 if(!found) {
2518 /* Message not found */
2519 GtkWidget *gmd = gtk_message_dialog_new(
2520 (GtkWindow*)playlist3_get_window(),
2521 GTK_DIALOG_MODAL,
2522 GTK_MESSAGE_ERROR,
2523 GTK_BUTTONS_CLOSE,
2525 "To playback local files, you need to be connected "
2526 "using unix socket.\n"
2527 "See the MPD website for more information."
2530 gtk_dialog_run(GTK_DIALOG(gmd));
2531 gtk_widget_destroy(GTK_WIDGET(gmd));
2532 }else {
2533 GtkWidget *fmd = gtk_file_chooser_dialog_new(
2534 "Select a local file",
2535 (GtkWindow*)playlist3_get_window(),
2536 GTK_FILE_CHOOSER_ACTION_OPEN,
2537 GTK_STOCK_CLOSE,
2538 GTK_RESPONSE_CLOSE,
2539 GTK_STOCK_OPEN,
2540 GTK_RESPONSE_OK,
2541 NULL);
2542 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fmd), TRUE);
2543 switch(gtk_dialog_run(GTK_DIALOG(fmd)))
2545 case GTK_RESPONSE_OK:
2547 GSList *iter;
2548 GSList *uris = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(fmd));
2549 for(iter = uris;
2550 iter != NULL;
2551 iter = g_slist_next(iter))
2553 char *uri = g_uri_unescape_string(iter->data,NULL);
2554 url_start_real(uri);
2555 g_free(uri);
2557 g_slist_foreach (uris, (GFunc) g_free, NULL);
2558 g_slist_free (uris);
2559 break;
2561 default:
2562 break;
2564 gtk_widget_destroy(GTK_WIDGET(fmd));
2568 void show_user_manual(void);
2569 void show_user_manual(void)
2571 open_uri("ghelp:gmpc");
2573 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=80: */