[GmpcMetaImage] Fix the instant apply off addcase.
[gmpc.git] / src / playlist3.c
blobee3dde061561bed3119b155a7e89eaf7551c8a9b
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 // Collapsed mode.
39 #define SIDEBAR_SMALL 32
40 // Default size.
41 #define SIDEBAR_LARGE -1
43 #ifndef GDK_KEY_0
44 #define GDK_KEY_0 GDK_0
45 #endif
47 #ifndef GDK_KEY_1
48 #define GDK_KEY_1 GDK_1
49 #endif
51 #ifndef GDK_KEY_2
52 #define GDK_KEY_2 GDK_2
53 #endif
56 #ifndef GDK_KEY_3
57 #define GDK_KEY_3 GDK_3
58 #endif
60 #ifndef GDK_KEY_4
61 #define GDK_KEY_4 GDK_4
62 #endif
65 #ifndef GDK_KEY_5
66 #define GDK_KEY_5 GDK_5
67 #endif
70 #ifndef GDK_KEY_6
71 #define GDK_KEY_6 GDK_6
72 #endif
75 #ifndef GDK_KEY_7
76 #define GDK_KEY_7 GDK_7
77 #endif
80 #ifndef GDK_KEY_8
81 #define GDK_KEY_8 GDK_8
82 #endif
85 #ifndef GDK_KEY_9
86 #define GDK_KEY_9 GDK_9
87 #endif
91 #define ALBUM_SIZE 42
93 #define LOG_DOMAIN "Playlist"
95 /* Drag and drop Target table */
96 static GtkTargetEntry target_table[] =
98 {(gchar *) "x-url/http", 0, 0},
99 {(gchar *) "_NETSCAPE_URL", 0, 1},
100 {(gchar *) "text/uri-list", 0, 2},
101 {(gchar *) "audio/*", 0, 3},
102 {(gchar *) "audio/x-scpls", 0, 4},
103 {(gchar *) "internal-drop", 0, 99}
106 GtkWidget *metaimage_album_art = NULL;
107 GtkWidget *metaimage_artist_art = NULL;
108 GmpcFavoritesButton *favorites_button = NULL;
110 GtkCellRenderer *sidebar_text = NULL;
112 * Widgets used in the header.
113 * and the new progresbar
115 static GtkWidget *new_pb = NULL;
118 * Indicates the zoom level and the previous zoom level.
120 int pl3_zoom = PLAYLIST_NO_ZOOM;
121 int pl3_old_zoom = PLAYLIST_NO_ZOOM;
123 static void playlist_zoom_level_changed(void);
124 void playlist_zoom_in(void);
125 void playlist_zoom_out(void);
128 void pl3_pb_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data);
130 void set_browser_format(void);
131 void set_playlist_format(void);
133 gboolean playlist_player_volume_changed(GtkWidget * vol_but, int new_vol);
135 /* Glade declarations, otherwise these would be static */
136 void about_window(void);
137 int pl3_cat_tree_button_press_event(GtkTreeView *, GdkEventButton *);
138 int pl3_cat_tree_button_release_event(GtkTreeView *, GdkEventButton *);
139 int pl3_window_key_release_event(GtkWidget * mw, GdkEventKey * event);
141 void cur_song_center_enable_tb(GtkToggleButton *);
142 void show_cover_case_tb(GtkToggleButton * but);
143 void save_possize_enable_tb(GtkToggleButton *);
144 void playlist_menu_repeat_changed(GtkToggleAction *);
145 void playlist_menu_single_mode_changed(GtkToggleAction * );
146 void playlist_menu_consume_changed(GtkToggleAction * );
148 void playlist_menu_random_changed(GtkToggleAction *);
149 void playlist_menu_artist_image_changed(GtkToggleAction *);
150 void hide_on_close_enable_tb(GtkToggleButton * but);
151 gboolean pl3_close(void);
152 static void pl3_update_profiles_menu(GmpcProfiles * prof, const int changed, const int col, const gchar * id);
153 gboolean playlist3_enter_notify_event(GtkWidget * wid, GdkEventCrossing * event, gpointer data);
154 gboolean playlist3_leave_notify_event(GtkWidget * wid, GdkEventCrossing * event, gpointer data);
155 gboolean pl3_window_focus_out_event(GtkWidget *window, GdkEventFocus *event, gpointer data);
157 static void pl3_profiles_changed(GmpcProfiles * prof, const int changed, const int col, const gchar * id);
158 static void playlist3_server_output_changed(GtkWidget * item, gpointer data);
159 static void playlist3_fill_server_menu(void);
160 void playlist3_server_update_db(void);
162 void easy_command_help_window(void);
164 void pl3_style_set_event(GtkWidget *widget, GtkStyle *previous_style, gpointer user_data);
166 void pl3_sidebar_plugins_init(void);
168 /* Old category browser style */
169 static int old_type = -1;
171 /* interface description */
172 GtkBuilder *pl3_xml = NULL;
173 /* category treeview-store */
174 GtkTreeModel *pl3_tree = NULL;
176 /* size */
177 static GtkAllocation pl3_wsize = { 0, 0, 0, 0 };
179 static int pl3_hidden = TRUE;
181 static void playlist_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata);
183 /* Playlist "Plugin" */
184 static void playlist_pref_construct(GtkWidget * container);
185 static void playlist_pref_destroy(GtkWidget * container);
187 static GtkBuilder *playlist_pref_xml = NULL;
189 void ck_search_as_you_type(GtkToggleButton * but);
192 /* Get the type of the selected row..
193 * -1 means no row selected
195 int pl3_cat_get_selected_browser(void)
197 return old_type;
204 * Extras for better integration
207 void init_extra_playlist_state(void);
208 void enable_extra_playlist(GtkToggleAction *action);
210 /**************************************************
211 * Category Tree
213 static void pl3_initialize_tree(void)
215 int i;
216 GtkTreePath *path;
217 GtkTreeSelection *sel;
218 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
220 INIT_TIC_TAC()
222 path = gtk_tree_path_new_from_string("0");
223 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml, "cat_tree")));
224 TEC("Get selection");
225 for (i = 0; i < num_plugins; i++)
227 if (gmpc_plugin_is_browser(plugins[i]))
229 if (gmpc_plugin_get_enabled(plugins[i]))
231 gmpc_plugin_browser_add(plugins[i], cat_tree);
234 TEC("setup %s", gmpc_plugin_get_name(plugins[i]))
237 gtk_tree_view_set_cursor(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml, "cat_tree")), path, NULL, FALSE);
238 TEC("set cursor");
239 gtk_tree_path_free(path);
240 TEC("finish set");
245 * Function to handle a change in category.
247 static void pl3_cat_sel_changed(GtkTreeSelection * selec, gpointer * userdata)
249 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
250 GtkTreeModel *model = gtk_tree_view_get_model(tree);
251 GtkTreeIter iter;
252 GtkWidget *container = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "browser_container"));
253 if (!model)
254 return;
255 if (gtk_tree_selection_get_selected(selec, &model, &iter))
257 gint type;
259 gtk_tree_model_get(model, &iter, PL3_CAT_TYPE, &type, -1);
263 * Start switching side view (if type changed )
265 if (old_type != -1)
267 gmpc_plugin_browser_unselected(plugins[plugin_get_pos(old_type)], container);
269 old_type = -1;
270 if(type > -1)
272 /** if type changed give a selected signal */
273 if ((old_type != type))
275 gmpc_plugin_browser_selected(plugins[plugin_get_pos(type)], container);
280 * update old value, so get_selected_category is correct before calling selection_changed
282 old_type = type;
284 } else
286 if (old_type != -1)
288 gmpc_plugin_browser_unselected(plugins[plugin_get_pos(old_type)], container);
290 old_type = -1;
291 gtk_tree_model_get_iter_first(model, &iter);
292 gtk_tree_selection_select_iter(selec, &iter);
294 pl3_option_menu_activate();
298 /* handle right mouse clicks on the cat tree view */
299 /* gonna be a big function*/
300 int pl3_cat_tree_button_press_event(GtkTreeView * tree, GdkEventButton * event)
302 GtkTreeSelection *sel = gtk_tree_view_get_selection(tree);
303 if (event->button != 3 || gtk_tree_selection_count_selected_rows(sel) < 2 || !mpd_check_connected(connection))
305 return FALSE;
307 return TRUE;
312 void pl3_option_menu_activate(void)
315 GtkWidget *tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
316 int i;
317 gint type = pl3_cat_get_selected_browser();
318 int menu_items = 0;
319 GdkEventButton *event = NULL;
320 GtkWidget *menu = NULL;
321 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
322 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_option"));
324 //gtk_menu_item_set_submenu(m_item, NULL);
326 if (!mpd_check_connected(connection) || type == -1)
327 return;
329 menu = gtk_menu_new();
331 for (i = 0; i < num_plugins; i++)
333 if (gmpc_plugin_is_browser(plugins[i]))
335 menu_items += gmpc_plugin_browser_cat_right_mouse_menu(plugins[i], menu, type, tree, event);
338 if (menu_items)
340 gtk_widget_show_all(menu);
341 gtk_menu_item_set_submenu(m_item, menu);
342 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), TRUE);
343 } else
345 g_object_ref_sink(menu);
346 g_object_unref(menu);
347 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), FALSE);
353 int pl3_cat_tree_button_release_event(GtkTreeView * tree, GdkEventButton * event)
355 int i;
356 gint type = pl3_cat_get_selected_browser();
357 int menu_items = 0;
358 GtkWidget *menu = NULL;
360 if (type == -1 || !mpd_check_connected(connection) || event->button != 3)
362 /* no selections, or no usefull one.. so propagate the signal */
363 return FALSE;
366 menu = gtk_menu_new();
368 for (i = 0; i < num_plugins; i++)
370 if (gmpc_plugin_is_browser(plugins[i]))
372 menu_items += gmpc_plugin_browser_cat_right_mouse_menu(plugins[i], menu, type, GTK_WIDGET(tree), event);
376 if (menu_items)
378 gtk_widget_show_all(menu);
379 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
380 /*event->button */ 0, event->time);
381 } else
383 g_object_ref_sink(menu);
384 g_object_unref(menu);
386 return TRUE;
389 void pl3_sidebar_plugins_init(void)
391 int i;
392 for (i = 0; i < num_plugins; i++)
394 // This is implicitely done inside sidebar_init
395 // if (gmpc_plugin_is_sidebar(plugins[i]))
397 gmpc_plugin_sidebar_init(plugins[i]);
402 /**********************************************************
403 * MISC
405 static GtkWidget *control_window = NULL;
406 static gboolean pl3_win_state_event(GtkWidget * window, GdkEventWindowState * event, gpointer data)
408 GtkWidget *vbox1 = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox1"));
409 GtkWidget *p = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "alignment1"));
410 GtkWidget *h = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox1"));
411 GtkWidget *b = (GTK_WIDGET(gtk_builder_get_object(pl3_xml, "menubartest")));
412 if (((event->new_window_state) & GDK_WINDOW_STATE_FULLSCREEN))
414 if(control_window == NULL) {
415 control_window = create_control_window(window);
416 gtk_box_pack_start(GTK_BOX(vbox1), control_window, FALSE, FALSE, 0);
418 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
419 gtk_widget_hide(p);
420 gtk_widget_hide(h);
421 gtk_widget_hide(b);
422 } else if ((event->changed_mask) & GDK_WINDOW_STATE_FULLSCREEN)
424 control_window_destroy(control_window);
425 control_window = NULL;
426 playlist_zoom_level_changed();
427 gtk_widget_show(p);
428 gtk_widget_show(h);
429 gtk_widget_show(b);
431 return FALSE;
434 gboolean alt_button_pressed = FALSE;
436 * This avoids the 'keybinding help' to become sticky when moving the window, or chainging
437 * focus to other window.
439 gboolean pl3_window_focus_out_event(GtkWidget *window, GdkEventFocus *event, gpointer data)
441 GmpcToolsBindingOverlayNotify *p = (GmpcToolsBindingOverlayNotify *)gtk_builder_get_object(pl3_xml, "binding_overlay_notify");
442 if(alt_button_pressed)
444 GtkWidget *tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
445 alt_button_pressed = FALSE;
446 gtk_widget_queue_draw(GTK_WIDGET(tree));
448 gmpc_tools_binding_overlay_notify_key_released(p,GDK_MOD1_MASK|GDK_CONTROL_MASK);
449 return FALSE;
453 gboolean pl3_window_is_fullscreen(void)
455 GtkWidget *win = playlist3_get_window();
456 GdkWindowState state = 0;
457 if (win->window)
458 state = gdk_window_get_state(win->window);
459 return (state & GDK_WINDOW_STATE_FULLSCREEN) ? TRUE : FALSE;
463 void pl3_window_fullscreen(void)
465 GtkWidget *win = playlist3_get_window();
467 if (pl3_zoom < PLAYLIST_MINI)
469 if (pl3_window_is_fullscreen())
471 gtk_window_unfullscreen(GTK_WINDOW(win));
472 } else
474 gtk_window_fullscreen(GTK_WINDOW(win));
480 int pl3_window_key_release_event(GtkWidget * mw, GdkEventKey * event)
482 if(event->keyval == GDK_KEY_Alt_L || event->keyval == GDK_KEY_Alt_R || event->keyval == GDK_KEY_Meta_L|| event->keyval == GDK_KEY_Meta_R) {
483 GmpcToolsBindingOverlayNotify *p = (GmpcToolsBindingOverlayNotify *)gtk_builder_get_object(pl3_xml, "binding_overlay_notify");
484 GtkWidget *tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
485 alt_button_pressed = FALSE;
486 gtk_widget_queue_draw(GTK_WIDGET(tree));
487 gmpc_tools_binding_overlay_notify_key_released(p,GDK_MOD1_MASK);
489 if(event->keyval == GDK_KEY_Control_L || event->keyval == GDK_KEY_Control_R) {
490 GmpcToolsBindingOverlayNotify *p =(GmpcToolsBindingOverlayNotify *) gtk_builder_get_object(pl3_xml, "binding_overlay_notify");
491 gmpc_tools_binding_overlay_notify_key_released(p,GDK_CONTROL_MASK);
493 return FALSE;
495 int pl3_window_key_press_event(GtkWidget * mw, GdkEventKey * event)
497 int i = 0;
498 gint type = pl3_cat_get_selected_browser();
499 if(event->keyval == GDK_KEY_Alt_L || event->keyval == GDK_KEY_Alt_R) {
500 GmpcToolsBindingOverlayNotify *p = (GmpcToolsBindingOverlayNotify *)gtk_builder_get_object(pl3_xml, "binding_overlay_notify");
501 GtkWidget *tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
502 alt_button_pressed = TRUE;
503 gtk_widget_queue_draw(GTK_WIDGET(tree));
504 gmpc_tools_binding_overlay_notify_key_pressed(p,GDK_MOD1_MASK);
506 if(event->keyval == GDK_KEY_Control_L || event->keyval == GDK_KEY_Control_R)
508 GmpcToolsBindingOverlayNotify *p =(GmpcToolsBindingOverlayNotify *) gtk_builder_get_object(pl3_xml, "binding_overlay_notify");
509 gmpc_tools_binding_overlay_notify_key_pressed(p,GDK_CONTROL_MASK);
512 * Following key's are only valid when connected
514 if (!mpd_check_connected(connection))
516 return FALSE;
518 for (i = 0; i < num_plugins; i++)
520 if (gmpc_plugin_is_browser(plugins[i]))
522 gmpc_plugin_browser_key_press_event(plugins[i], mw, event, type);
525 if((event->state&GDK_MOD1_MASK) > 0)
527 guint kev = event->keyval;
528 if(kev >= GDK_KEY_0 && kev <= GDK_KEY_9)
530 guint i_index = 0;
531 GtkTreeIter iter;
532 kev-=GDK_KEY_0;
533 if (gtk_tree_model_get_iter_first(pl3_tree, &iter))
535 if(kev == 0) kev+=10;
537 gint new_type =0 ;
538 gtk_tree_model_get(pl3_tree, &iter, PL3_CAT_TYPE, &new_type, -1);
539 if(new_type >= 0) i_index++;
540 if(i_index == kev && new_type >= 0)
542 GtkWidget *cat_tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
543 GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cat_tree));
545 // if this is allready selected, do +10. this allows us to go up to 20 browsers.
546 if(new_type == old_type && gtk_tree_selection_iter_is_selected(select, &iter)) {
547 kev+=10;
548 }else{
549 gtk_tree_selection_select_iter(select, &iter);
550 return FALSE;
553 }while(gtk_tree_model_iter_next(pl3_tree, &iter));
558 /* don't propagate */
559 return FALSE;
563 * Close the playlist and save position/size
565 gboolean pl3_close(void)
567 /* only save when window is PLAYLIST_SMALL or NO ZOOM */
568 if (pl3_xml != NULL)
570 GtkWidget *window = playlist3_get_window();
571 int maximized = FALSE;
572 if (window->window)
574 GdkWindowState state = gdk_window_get_state(window->window);
575 maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
577 cfg_set_single_value_as_int(config, "playlist", "maximized", maximized);
579 gtk_window_get_position(GTK_WINDOW(window), &pl3_wsize.x, &pl3_wsize.y);
581 cfg_set_single_value_as_int(config, "playlist", "xpos", pl3_wsize.x);
582 cfg_set_single_value_as_int(config, "playlist", "ypos", pl3_wsize.y);
584 if (pl3_zoom <= PLAYLIST_SMALL)
586 gtk_window_get_size(GTK_WINDOW(window), &pl3_wsize.width, &pl3_wsize.height);
587 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "pl3_close: save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
588 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
589 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
593 if (cfg_get_single_value_as_int_with_default(config, "playlist", "hide-on-close", FALSE))
595 if (tray_icon2_get_available())
597 pl3_toggle_hidden();
598 return TRUE;
600 gtk_window_iconify(GTK_WINDOW(playlist3_get_window()));
601 return TRUE;
605 * Quit the program
607 main_quit();
608 return TRUE;
613 * Hide the playlist.
614 * Before hiding save current size and position
616 int pl3_hide(void)
618 GtkWidget *pl3_win = playlist3_get_window();
619 if (!tray_icon2_get_available())
621 gtk_window_iconify(GTK_WINDOW(pl3_win));
622 return 1;
624 if (pl3_xml != NULL && !pl3_hidden)
626 GtkWidget *window = playlist3_get_window();
627 int maximized = FALSE;
628 if (window->window)
630 GdkWindowState state = gdk_window_get_state(window->window);
631 maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
633 cfg_set_single_value_as_int(config, "playlist", "maximized", maximized);
634 /** Save position
636 gtk_window_get_position(GTK_WINDOW(pl3_win), &pl3_wsize.x, &pl3_wsize.y);
637 cfg_set_single_value_as_int(config, "playlist", "xpos", pl3_wsize.x);
638 cfg_set_single_value_as_int(config, "playlist", "ypos", pl3_wsize.y);
639 /* save size, only when in SMALL or no zoom mode
641 if (pl3_zoom <= PLAYLIST_SMALL)
643 gtk_window_get_size(GTK_WINDOW(pl3_win), &pl3_wsize.width, &pl3_wsize.height);
644 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "pl3_hide: save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
645 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
646 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
648 gtk_widget_hide(pl3_win);
649 pl3_hidden = TRUE;
651 #ifdef HAVE_APP_INDICATOR
652 tray_icon2_update_menu();
653 #endif
654 return TRUE;
658 /* create the playlist view
659 * This is done only once, for the rest its hidden, but still there
661 static void pl3_show_and_position_window(void)
663 GtkWidget *pl3_win;
664 if (!pl3_xml)
665 return;
666 pl3_win = playlist3_get_window();
667 if (pl3_wsize.x > 0 || pl3_wsize.y > 0)
669 gtk_window_move(GTK_WINDOW(pl3_win), pl3_wsize.x, pl3_wsize.y);
671 if (pl3_wsize.height > 0 && pl3_wsize.width > 0)
673 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
674 gtk_window_resize(GTK_WINDOW(pl3_win), pl3_wsize.width, pl3_wsize.height);
676 gtk_widget_show(pl3_win);
677 gtk_window_present(GTK_WINDOW(pl3_win));
682 gboolean playlist3_window_is_hidden(void)
684 return pl3_hidden;
688 void pl3_toggle_hidden(void)
690 if (pl3_hidden)
692 create_playlist3();
693 } else
695 pl3_hide();
700 static void playlist3_source_drag_data_recieved(GtkWidget * widget,
701 GdkDragContext * context,
702 gint x,
703 gint y, GtkSelectionData * data, guint info, guint time_recieved)
705 if (info != 99)
707 int found = 0;
708 const gchar *url_data = (gchar *) data->data;
709 int i;
710 if (url_data)
713 gchar **url = g_uri_list_extract_uris(url_data);
714 for (i = 0; url && url[i]; i++)
716 gchar *scheme = g_uri_parse_scheme(url[i]);
717 /* Don't add lines withouth an actual scheme. */
718 if (scheme)
720 gchar *fu = g_uri_unescape_string(url[i], NULL);
721 url_start_real(fu);
722 g_free(fu);
723 g_free(scheme);
726 if (url)
727 g_strfreev(url);
730 gtk_drag_finish(context, found, FALSE, time_recieved);
731 } else
733 MpdData *mdata;
734 gchar **stripped;
735 int i;
736 guchar *odata = gtk_selection_data_get_text(data);
737 stripped = g_strsplit((gchar *) odata, "\n", 0);
738 g_free(odata);
739 if (context->action == GDK_ACTION_MOVE)
741 mpd_playlist_clear(connection);
743 mpd_database_search_start(connection, TRUE);
744 for (i = 0; stripped && stripped[i]; i++)
746 gchar **request = g_strsplit(stripped[i], ":", 2);
747 mpd_database_search_add_constraint(connection, mpd_misc_get_tag_by_name(request[0]), request[1]);
748 g_strfreev(request);
750 mdata = mpd_database_search_commit(connection);
751 for (; mdata; mdata = mpd_data_get_next(mdata))
753 mpd_playlist_queue_add(connection, mdata->song->file);
755 mpd_playlist_queue_commit(connection);
756 if (context->action == GDK_ACTION_MOVE)
758 mpd_player_play(connection);
761 g_strfreev(stripped);
762 gtk_drag_finish(context, TRUE, FALSE, time_recieved);
768 * Progresbar
770 void pl3_pb_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data)
772 mpd_player_seek(connection, (int)seek_time);
777 static void about_dialog_activate(GtkWidget * dialog, const gchar * uri, gpointer data)
779 open_uri(uri);
783 /***
784 * Handle a connect/Disconnect
786 static void playlist_connection_changed(MpdObj * mi, int connect, gpointer data)
788 GtkWidget *pl3_win = playlist3_get_window();
789 /* Set menu items */
790 if (connect)
792 char **handlers;
793 gboolean found = FALSE;
794 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")), TRUE);
795 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")), TRUE);
797 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConnect")), FALSE);
798 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDDisconnect")), TRUE);
799 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPassword")), TRUE);
800 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_view")), TRUE);
801 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), TRUE);
803 /* Check if MPD supports 'file://' (so local files). */
804 /* TODO: make this a separate function */
805 handlers = mpd_server_get_url_handlers(connection);
806 if (handlers)
808 int i=0;
809 for(; !found && handlers != NULL && handlers[i] != NULL; i++) {
810 if(g_utf8_collate(handlers[i], "file://") == 0) {
811 found = TRUE;
814 g_strfreev(handlers);
816 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "open_local_file")), found);
817 } else
819 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")), FALSE);
820 gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")), FALSE);
822 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConnect")), TRUE);
823 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDDisconnect")), FALSE);
824 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPassword")), FALSE);
825 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_view")), FALSE);
826 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")), FALSE);
827 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "open_local_file")), FALSE);
829 /** Set back to the current borwser, and update window title */
830 if (connect)
832 gchar *string = NULL;
833 GtkTreeIter iter;
834 GtkTreeSelection *selec = gtk_tree_view_get_selection((GtkTreeView *) gtk_builder_get_object(pl3_xml,
835 "cat_tree"));
836 GtkTreeModel *model = GTK_TREE_MODEL(pl3_tree);
837 if (gtk_tree_model_get_iter_first(model, &iter))
839 gtk_tree_selection_select_iter(selec, &iter);
841 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
843 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
844 if (id)
846 string =
847 g_strdup_printf("[%s] %s - %s %s", gmpc_profiles_get_name(gmpc_profiles, id), _("GMPC"),
848 _("Connected to"), mpd_get_hostname(mi));
849 g_free(id);
852 if (!string)
853 string = g_strdup_printf("%s - %s %s", _("GMPC"), _("Connected to"), mpd_get_hostname(mi));
854 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
855 g_free(string);
856 } else
858 gchar *string = NULL;
860 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
862 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
863 if (id)
865 string =
866 g_strdup_printf("[%s] %s - %s", gmpc_profiles_get_name(gmpc_profiles, id), _("GMPC"),
867 _("Disconnected"));
868 g_free(id);
871 if (!string)
872 string = g_strdup_printf("%s - %s", _("GMPC"), _("Disconnected"));
873 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
874 g_free(string);
878 * make the playlist update itself
880 playlist_status_changed(connection,
881 MPD_CST_STATE | MPD_CST_SONGID | MPD_CST_NEXTSONG |
882 MPD_CST_ELAPSED_TIME | MPD_CST_VOLUME |
883 MPD_CST_REPEAT | MPD_CST_RANDOM | MPD_CST_PERMISSION
884 | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE | MPD_CST_UPDATING, NULL);
887 * Also need updating
889 pl3_option_menu_activate();
890 pl3_tool_menu_update();
892 playlist3_fill_server_menu();
895 * update interface
896 * items that are caused by the plugin.
898 pl3_update_go_menu();
902 void pl3_style_set_event( GtkWidget *widget,
903 GtkStyle *previous_style,
904 gpointer user_data)
906 if (cfg_get_single_value_as_int_with_default(config, "Default", "use-dark-style-header", TRUE))
908 gtk_rc_parse_string("widget \"*header*\" style \"dark\"");
911 static gboolean pl3_cat_select_function(GtkTreeSelection *select, GtkTreeModel *model, GtkTreePath *path, gboolean cur_select, gpointer data)
913 GtkTreeIter iter;
914 if(gtk_tree_model_get_iter(model, &iter, path))
916 gint type =0 ;
917 gtk_tree_model_get(model, &iter, PL3_CAT_TYPE, &type, -1);
918 if(type >= 0) return TRUE;
920 return FALSE;
922 static void pl3_sidebar_text_get_key_number( GtkTreeViewColumn *column,
923 GtkCellRenderer *renderer,
924 GtkTreeModel *model,
925 GtkTreeIter *d_iter,
926 gpointer data)
928 int number = 0;
929 GtkTreeIter iter;
930 GtkTreePath *pa1 = NULL;
932 if(!alt_button_pressed) {
933 g_object_set(G_OBJECT(renderer), "show-number", FALSE, NULL);
934 return;
937 pa1 = gtk_tree_model_get_path(model, d_iter);
938 if (gtk_tree_model_get_iter_first(pl3_tree, &iter))
941 gint type =0 ;
942 gtk_tree_model_get(pl3_tree, &iter, PL3_CAT_TYPE, &type, -1);
943 if(type >= 0) number++;
944 if( type >= 0)
946 GtkTreePath *pa2 = gtk_tree_model_get_path(model, &iter);
947 if(gtk_tree_path_compare(pa2, pa1) == 0){
948 g_object_set(G_OBJECT(renderer), "number", number%10, NULL);
949 g_object_set(G_OBJECT(renderer), "show-number", TRUE, NULL);
950 gtk_tree_path_free(pa2);
951 gtk_tree_path_free(pa1);
952 return;
954 gtk_tree_path_free(pa2);
956 }while(gtk_tree_model_iter_next(pl3_tree, &iter));
958 gtk_tree_path_free(pa1);
959 g_object_set(G_OBJECT(renderer), "number", number, NULL);
960 g_object_set(G_OBJECT(renderer), "show-number", FALSE, NULL);
963 void create_playlist3(void)
965 GtkWidget *pb,*ali;
966 GtkCellRenderer *renderer;
967 GtkWidget *tree;
968 GtkTreeSelection *sel;
969 GtkTreeViewColumn *column = NULL;
970 gchar *path = NULL;
971 GtkTreeIter iter;
972 GError *error = NULL;
973 INIT_TIC_TAC();
974 /* indicate that the playlist is not hidden */
975 pl3_hidden = FALSE;
978 * If the playlist already exists,
979 * It is probably coming from a hidden state,
980 * so re-position the window
982 if (pl3_xml != NULL)
984 pl3_show_and_position_window();
985 return;
988 /** Ambiance / Radiance theme "dark" header */
989 if (cfg_get_single_value_as_int_with_default(config, "Default", "use-dark-style-header", TRUE))
991 gtk_rc_parse_string("widget \"*header*\" style \"dark\"");
994 /** use background color for the sidebar treeview cells */
995 gtk_rc_parse_string (
996 "style \"sidebar-treeview\"\n"
997 "{\n"
998 " GtkTreeView::odd-row-color = @bg_color\n"
999 " GtkTreeView::even-row-color = @bg_color\n"
1000 "}\n"
1001 "widget \"*.sidebar.*\" style \"sidebar-treeview\"");
1003 /** menubar */
1004 gtk_rc_parse_string (
1005 "style \"menubar-style\"\n"
1006 "{\n"
1007 " GtkMenuBar::shadow-type = none\n"
1008 "}\n"
1009 "widget \"*.menubar\" style \"menubar-style\"\n");
1011 /* initial, setting the url hook */
1012 gtk_about_dialog_set_url_hook((GtkAboutDialogActivateLinkFunc) about_dialog_activate, NULL, NULL);
1013 TEC("Setup dialog url hook")
1014 /* load gui desciption */
1015 path = gmpc_get_full_glade_path("playlist3.ui");
1016 TEC("get path")
1017 pl3_xml = gtk_builder_new();
1018 TEC("create builder")
1019 if(gtk_builder_add_from_file(pl3_xml, path,&error) == 0)
1022 * Check if the file is loaded, if not then show an error message and abort the program
1023 if (pl3_xml == NULL)
1026 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Failed to open playlist3.glade: %s\n", error->message);
1027 abort();
1029 g_free(path);
1030 TEC("Load builder file")
1032 /* create tree store for the "category" view */
1033 if (pl3_tree == NULL)
1035 GType types[] =
1037 G_TYPE_INT, /* row type, see free_type struct */
1038 G_TYPE_STRING, /* display name */
1039 G_TYPE_STRING, /* full path and stuff for backend */
1040 G_TYPE_STRING, /* icon id */
1041 G_TYPE_INT, /* ordering */
1042 G_TYPE_INT, /* Bold */
1043 G_TYPE_STRING /* stock id */
1045 /* song id, song title */
1046 pl3_tree = (GtkTreeModel *) gmpc_tools_liststore_sort_new();
1047 gtk_list_store_set_column_types(GTK_LIST_STORE(pl3_tree), PL3_CAT_NROWS, types);
1049 TEC("Setup pl3_tree")
1051 tree = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "cat_tree"));
1052 gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
1053 pl3_cat_select_function, pl3_tree, NULL);
1055 gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(pl3_tree));
1056 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1057 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(sel), GTK_SELECTION_BROWSE);
1058 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree), TRUE);
1059 // Enable tooltip on the treeview.
1060 gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(tree), PL3_CAT_TITLE);
1062 sidebar_text = renderer = GTK_CELL_RENDERER(my_cell_renderer_new());
1063 g_object_set(G_OBJECT(renderer), "xalign", 0.5,NULL);
1064 column = gtk_tree_view_column_new();
1067 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1068 gtk_tree_view_column_set_cell_data_func(column, sidebar_text, pl3_sidebar_text_get_key_number, NULL, NULL);
1069 g_object_set(G_OBJECT(renderer), "stock-size", GTK_ICON_SIZE_MENU, NULL);
1071 int w, h;
1072 if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h))
1074 g_object_set(G_OBJECT(renderer), "height", h+10, NULL);
1075 g_object_set(G_OBJECT(renderer), "image-width", w,NULL);
1078 gtk_tree_view_column_set_attributes(column, renderer,
1079 "icon-name", PL3_CAT_ICON_ID,
1080 "stock-id", PL3_CAT_STOCK_ID,
1081 "text", PL3_CAT_TITLE,
1082 "weight", PL3_CAT_BOLD, NULL);
1083 g_object_set(renderer, "weight-set", TRUE, NULL);
1085 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
1086 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree), PL3_CAT_TITLE);
1087 g_signal_connect_after(G_OBJECT(sel), "changed", G_CALLBACK(pl3_cat_sel_changed), NULL);
1089 TEC("setup cat_tree");
1091 /* initialize the category view */
1092 pl3_initialize_tree();
1094 TEC("Init category tree")
1095 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player")));
1098 * The new progress bar
1100 pb = (GtkWidget *) gtk_builder_get_object(pl3_xml, "hbox_progress");
1101 gtk_widget_show(pb);
1102 g_signal_connect(G_OBJECT(pb), "seek-event", G_CALLBACK(pl3_pb_seek_event), NULL);
1104 new_pb = pb;
1106 TEC("Init progress bar")
1107 /* Make sure change is applied */
1109 playlist3_new_header();
1111 pl3_sidebar_plugins_init();
1113 TEC("Init header")
1114 if (!cfg_get_single_value_as_int_with_default(config, "Interface", "hide-favorites-icon", FALSE))
1116 favorites_button = gmpc_favorites_button_new();
1117 ali = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
1118 gtk_container_add(GTK_CONTAINER(ali), GTK_WIDGET(favorites_button));
1119 gtk_box_pack_start(GTK_BOX(gtk_builder_get_object(pl3_xml, "hbox10")), GTK_WIDGET(ali), FALSE, FALSE, 0);
1120 gtk_widget_show_all(GTK_WIDGET(ali));
1121 TEC("Init fav icon")
1123 playlist_status_changed(connection,
1124 MPD_CST_STATE | MPD_CST_SONGID | MPD_CST_NEXTSONG |
1125 MPD_CST_ELAPSED_TIME | MPD_CST_VOLUME |
1126 MPD_CST_REPEAT | MPD_CST_RANDOM | MPD_CST_PERMISSION
1127 | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE, NULL);
1128 g_signal_connect(G_OBJECT(gtk_builder_get_object(pl3_xml, "volume_button")),
1129 "value_changed", G_CALLBACK(playlist_player_volume_changed), NULL);
1131 TEC("Signal setup")
1133 /* Restore values from config */
1134 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION
1135 (gtk_builder_get_object
1136 (pl3_xml, "ViewShowArtistImage")),
1137 cfg_get_single_value_as_int_with_default
1138 (config, "playlist", "cover-image-enable", 0));
1140 /* connect signals that are defined in the gui description */
1141 gtk_builder_connect_signals(pl3_xml,NULL);
1143 TEC("connect signals")
1145 /* select the current playlist */
1146 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_tree), &iter))
1148 gtk_tree_selection_select_iter(sel, &iter);
1151 TEC("Select view")
1153 * Insert new custom widget
1155 metaimage_album_art = gmpc_metaimage_new(META_ALBUM_ART);
1157 /* Hide when requested. */
1158 if (cfg_get_single_value_as_int_with_default(config, "Interface", "hide-album-art", FALSE))
1160 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_album_art), FALSE);
1162 gtk_box_pack_start(GTK_BOX
1163 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")), metaimage_album_art, FALSE, TRUE, 0);
1165 gtk_box_reorder_child(GTK_BOX
1166 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")), metaimage_album_art, 0);
1167 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_album_art), ALBUM_SIZE);
1168 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(metaimage_album_art), (char *)"gmpc");
1169 gmpc_metaimage_set_connection(GMPC_METAIMAGE(metaimage_album_art), connection);
1170 /** make sure size is updated */
1171 gmpc_metaimage_set_cover_na(GMPC_METAIMAGE(metaimage_album_art));
1173 metaimage_artist_art = gmpc_metaimage_new(META_ARTIST_ART);
1174 gtk_container_add(GTK_CONTAINER(gtk_builder_get_object(pl3_xml, "sidebar_artist_image_alignment")), metaimage_artist_art);
1176 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(metaimage_artist_art), (char *)"no-artist");
1177 gmpc_metaimage_set_loading_cover_icon(GMPC_METAIMAGE(metaimage_artist_art), (char *)"fetching-artist");
1178 gmpc_metaimage_set_connection(GMPC_METAIMAGE(metaimage_artist_art), connection);
1179 if (!cfg_get_single_value_as_int_with_default(config, "playlist", "cover-image-enable", FALSE))
1181 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1183 gmpc_metaimage_set_squared(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1184 gmpc_metaimage_set_size(GMPC_METAIMAGE(metaimage_artist_art), 145);
1186 TEC("Setup metaimages")
1187 /* restore the window's position and size, if the user wants this. */
1188 if (cfg_get_single_value_as_int_with_default(config, "playlist", "savepossize", 1))
1190 int maximized = cfg_get_single_value_as_int_with_default(config, "playlist", "maximized", 0);
1191 /* Load values from config file */
1192 pl3_wsize.x = cfg_get_single_value_as_int_with_default(config, "playlist", "xpos", 0);
1193 pl3_wsize.y = cfg_get_single_value_as_int_with_default(config, "playlist", "ypos", 0);
1194 pl3_wsize.width = cfg_get_single_value_as_int_with_default(config, "playlist", "width", 0);
1195 pl3_wsize.height = cfg_get_single_value_as_int_with_default(config, "playlist", "height", 0);
1196 TEC("get settings")
1197 /* restore location + position */
1198 /*pl3_show_and_position_window(); */
1200 if (pl3_wsize.x > 0 || pl3_wsize.y > 0)
1202 gtk_window_move(GTK_WINDOW(playlist3_get_window()), pl3_wsize.x, pl3_wsize.y);
1204 TEC("move window settings")
1205 if (pl3_wsize.height > 0 && pl3_wsize.width > 0)
1207 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
1208 gtk_window_resize(GTK_WINDOW(playlist3_get_window()), pl3_wsize.width, pl3_wsize.height);
1210 TEC("resize window settings")
1211 /* restore pane position */
1212 gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(pl3_xml,"sidebar")),
1213 SIDEBAR_LARGE,-1);
1214 TEC("set pane window settings")
1215 if (maximized)
1216 gtk_window_maximize(GTK_WINDOW(playlist3_get_window()));
1217 TEC("maximize pane window settings")
1219 * restore zoom level
1222 gtk_widget_show(playlist3_get_window());
1223 TEC("Show window")
1224 pl3_zoom = cfg_get_single_value_as_int_with_default(config, "playlist", "zoomlevel", PLAYLIST_NO_ZOOM);
1225 playlist_zoom_level_changed();
1226 TEC("zoom level")
1228 #ifdef HAVE_APP_INDICATOR
1229 tray_icon2_update_menu();
1230 #endif
1232 TEC("Restore state")
1233 pl3_update_go_menu();
1234 TEC("Go menu")
1235 /* make it update itself */
1236 pl3_update_profiles_menu(gmpc_profiles, GMPC_PROFILES_ACTION_ADDED, -1, NULL);
1237 g_signal_connect(G_OBJECT(gmpc_profiles), "changed", G_CALLBACK(pl3_update_profiles_menu), NULL);
1238 g_signal_connect(G_OBJECT(gmpc_profiles), "changed", G_CALLBACK(pl3_profiles_changed), NULL);
1240 TEC("Update profiles")
1242 * Set as drag destination
1244 gtk_drag_dest_set(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox_playlist_player")),
1245 GTK_DEST_DEFAULT_ALL,
1246 target_table, 6, GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_DEFAULT | GDK_ACTION_MOVE);
1247 g_signal_connect(G_OBJECT
1248 (gtk_builder_get_object(pl3_xml, "hbox_playlist_player")),
1249 "drag_data_received", GTK_SIGNAL_FUNC(playlist3_source_drag_data_recieved), NULL);
1251 TEC("setup drag")
1255 playlist_connection_changed(connection, FALSE, NULL);
1257 g_signal_connect(G_OBJECT(playlist3_get_window()), "window-state-event", G_CALLBACK(pl3_win_state_event), NULL);
1259 TEC("signal connn changed")
1261 g_signal_connect(G_OBJECT(playlist3_get_window()), "style-set", G_CALLBACK(pl3_style_set_event), NULL);
1264 * Add status icons
1266 main_window_init_default_status_icons();
1267 main_window_update_status_icons();
1269 TEC("Update status icon")
1270 /* Update extra */
1271 init_extra_playlist_state();
1272 TEC("Setup extra playlist")
1277 * Helper functions
1279 GtkListStore *playlist3_get_category_tree_store(void)
1281 if (pl3_xml == NULL)
1282 return NULL;
1283 return GTK_LIST_STORE(pl3_tree);
1287 GtkTreeView *playlist3_get_category_tree_view(void)
1289 if (pl3_xml == NULL)
1290 return NULL;
1291 return (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
1294 GtkWidget* playlist3_get_widget_by_id(const char *id) {
1295 return (GtkWidget *) gtk_builder_get_object(pl3_xml, id);
1299 /****************************************************************************************
1300 * PREFERENCES *
1301 ****************************************************************************************/
1302 /* prototyping for glade */
1303 void ck_stop_on_exit_toggled_cb(GtkToggleButton * but, gpointer data);
1304 void ck_show_tooltip_enable_tb(GtkToggleButton * but);
1306 G_MODULE_EXPORT void show_cover_case_tb(GtkToggleButton * but)
1308 int bool1 = gtk_toggle_button_get_active(but);
1309 cfg_set_single_value_as_int(config, "metaimage", "addcase", bool1);
1310 pixbuf_cache_clear();
1311 gmpc_meta_watcher_force_reload_cb(gmw);
1315 G_MODULE_EXPORT void ck_stop_on_exit_toggled_cb(GtkToggleButton * but, gpointer data)
1317 int bool1 = gtk_toggle_button_get_active(but);
1318 cfg_set_single_value_as_int(config, "connection", "stop-on-exit", bool1);
1322 G_MODULE_EXPORT void hide_on_close_enable_tb(GtkToggleButton * but)
1324 int bool1 = gtk_toggle_button_get_active(but);
1325 cfg_set_single_value_as_int(config, "playlist", "hide-on-close", bool1);
1329 G_MODULE_EXPORT void cur_song_center_enable_tb(GtkToggleButton * but)
1331 int bool1 = gtk_toggle_button_get_active(but);
1332 cfg_set_single_value_as_int(config, "playlist", "st_cur_song", bool1);
1336 G_MODULE_EXPORT void save_possize_enable_tb(GtkToggleButton * but)
1338 int bool1 = gtk_toggle_button_get_active(but);
1339 cfg_set_single_value_as_int(config, "playlist", "savepossize", bool1);
1343 G_MODULE_EXPORT void ck_show_tooltip_enable_tb(GtkToggleButton * but)
1345 int bool1 = gtk_toggle_button_get_active(but);
1346 cfg_set_single_value_as_int(config, "GmpcTreeView", "show-tooltip", bool1);
1350 G_MODULE_EXPORT void ck_search_as_you_type(GtkToggleButton * but)
1352 int bool1 = gtk_toggle_button_get_active(but);
1353 cfg_set_single_value_as_int(config, "general", "search-as-you-type", bool1);
1357 static void playlist_pref_destroy(GtkWidget * container)
1359 if (playlist_pref_xml)
1361 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(playlist_pref_xml,
1362 "playlist-vbox");
1363 gtk_container_remove(GTK_CONTAINER(container), vbox);
1364 g_object_unref(playlist_pref_xml);
1365 playlist_pref_xml = NULL;
1370 void playlist_pref_construct(GtkWidget * container)
1372 GError *error = NULL;
1373 gchar *path = gmpc_get_full_glade_path("preferences-playlist.ui");
1374 playlist_pref_xml = gtk_builder_new();
1376 gtk_builder_add_from_file(playlist_pref_xml, path, &error);
1377 if(error) {
1378 g_warning("Failed to open builder file: %s", error->message);
1379 g_error_free(error);
1380 return;
1382 if (playlist_pref_xml)
1384 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(playlist_pref_xml,
1385 "playlist-vbox");
1386 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1387 (gtk_builder_get_object
1388 (playlist_pref_xml, "ck_ps")),
1389 cfg_get_single_value_as_int_with_default(config, "playlist", "st_cur_song", 0));
1390 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1391 (gtk_builder_get_object
1392 (playlist_pref_xml, "ck_possize")),
1393 cfg_get_single_value_as_int_with_default(config, "playlist", "savepossize", 1));
1394 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1395 (gtk_builder_get_object
1396 (playlist_pref_xml, "ck_hide_on_close")),
1397 cfg_get_single_value_as_int_with_default(config, "playlist", "hide-on-close", 0));
1399 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1400 (gtk_builder_get_object
1401 (playlist_pref_xml, "ck_stop_on_exit")),
1402 cfg_get_single_value_as_int_with_default(config, "connection", "stop-on-exit", 0));
1404 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1405 (gtk_builder_get_object
1406 (playlist_pref_xml, "ck_cover_case")),
1407 cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase", TRUE));
1409 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1410 (gtk_builder_get_object
1411 (playlist_pref_xml, "ck_show_tooltip")),
1412 cfg_get_single_value_as_int_with_default
1413 (config, "GmpcTreeView", "show-tooltip", TRUE));
1415 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1416 (gtk_builder_get_object
1417 (playlist_pref_xml, "ck_search_as_you_type")),
1418 cfg_get_single_value_as_int_with_default(config, "general", "search-as-you-type",
1419 0));
1420 gtk_container_add(GTK_CONTAINER(container), vbox);
1421 gtk_widget_show_all(vbox);
1422 gtk_builder_connect_signals(playlist_pref_xml, NULL);
1424 g_free(path);
1429 * Menu Callback functions
1432 void playlist_menu_repeat_changed(GtkToggleAction * action)
1434 int active = gtk_toggle_action_get_active(action);
1435 if (active != mpd_player_get_repeat(connection))
1437 mpd_player_set_repeat(connection, active);
1442 void playlist_menu_random_changed(GtkToggleAction *action)
1444 int active = gtk_toggle_action_get_active(action);
1445 if (active != mpd_player_get_random(connection))
1447 mpd_player_set_random(connection, active);
1452 void playlist_menu_single_mode_changed(GtkToggleAction * action)
1454 int active = gtk_toggle_action_get_active(action);
1455 if (active != mpd_player_get_single(connection))
1457 mpd_player_set_single(connection, active);
1462 void playlist_menu_consume_changed(GtkToggleAction * action)
1464 int active = gtk_toggle_action_get_active(action);
1465 if (active != mpd_player_get_consume(connection))
1467 mpd_player_set_consume(connection, active);
1473 * This is artist image
1474 * FIXME: Rename
1476 void playlist_menu_artist_image_changed(GtkToggleAction *ta)
1478 int active = gtk_toggle_action_get_active(ta);
1479 cfg_set_single_value_as_int(config, "playlist", "cover-image-enable", active);
1480 if(pl3_zoom < PLAYLIST_SMALL)
1482 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), active);
1483 if (active)
1484 gtk_widget_show(metaimage_artist_art);
1489 /***
1490 * Zooming functions
1492 void playlist_zoom_out(void)
1494 /* Do not change zoom level when fullscreen */
1495 if(pl3_window_is_fullscreen())
1496 return;
1497 if ((pl3_zoom + 1) >= PLAYLIST_ZOOM_LEVELS)
1498 return;
1499 pl3_old_zoom = pl3_zoom;
1500 pl3_zoom++;
1501 playlist_zoom_level_changed();
1505 void playlist_zoom_in(void)
1507 /* Do not change zoom level when fullscreen */
1508 if(pl3_window_is_fullscreen())
1509 return;
1510 if (pl3_zoom <= PLAYLIST_NO_ZOOM)
1511 return;
1512 pl3_old_zoom = pl3_zoom;
1513 pl3_zoom--;
1514 playlist_zoom_level_changed();
1519 * FIXME: Needs propper grouping and cleaning up
1521 static void playlist_zoom_level_changed(void)
1523 gboolean st_shown;
1524 GtkWidget *pl3_win = playlist3_get_window();
1525 printf("playlist3 zoom level changed\n");
1527 if (pl3_old_zoom <= PLAYLIST_SMALL)
1529 gtk_window_get_size(GTK_WINDOW(pl3_win), &pl3_wsize.width, &pl3_wsize.height);
1530 cfg_set_single_value_as_int(config, "playlist", "width", pl3_wsize.width);
1531 cfg_set_single_value_as_int(config, "playlist", "height", pl3_wsize.height);
1532 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "save size: %i %i\n", pl3_wsize.width, pl3_wsize.height);
1535 if (pl3_old_zoom == PLAYLIST_MINI && pl3_zoom != PLAYLIST_MINI)
1537 GtkWidget *box =GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box"));
1538 GtkWidget *top = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10"));
1539 GtkWidget *vtop = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player"));
1540 /* add my own reference */
1541 g_object_ref(box);
1542 gtk_container_remove(GTK_CONTAINER(vtop), box);
1543 gtk_box_pack_end(GTK_BOX(top), box, FALSE, TRUE, 0);
1544 gtk_box_reorder_child(GTK_BOX(top), box, 0);
1545 /* release my reference */
1546 g_object_unref(box);
1547 gtk_widget_show(box);
1548 gmpc_progress_set_hide_text(GMPC_PROGRESS(new_pb), FALSE);
1550 if (pl3_old_zoom != PLAYLIST_MINI && pl3_zoom == PLAYLIST_MINI)
1552 GtkWidget *box = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box"));
1553 GtkWidget *top = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10"));
1554 GtkWidget *vtop = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "vbox_playlist_player"));
1555 /* add my own reference */
1556 g_object_ref(box);
1557 gtk_container_remove(GTK_CONTAINER(top), box);
1558 gtk_box_pack_end(GTK_BOX(vtop), box, FALSE, TRUE, 3);
1559 /* release my reference */
1560 g_object_unref(box);
1561 gtk_widget_show(box);
1563 gmpc_progress_set_hide_text(GMPC_PROGRESS(new_pb), TRUE);
1566 /* Show full view */
1567 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")));
1568 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox1")));
1569 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hbox10")));
1570 /** Menu Bar */
1571 /** BUTTON BOX */
1572 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_button_control_box")));
1574 gtk_window_set_resizable(GTK_WINDOW(pl3_win), TRUE);
1575 if (pl3_wsize.width > 0 && pl3_wsize.height > 0 && pl3_old_zoom == PLAYLIST_MINI)
1577 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "restore size %i %i\n", pl3_wsize.width, pl3_wsize.height);
1578 gtk_window_resize(GTK_WINDOW(pl3_win), pl3_wsize.width, pl3_wsize.height);
1580 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1582 if (cfg_get_single_value_as_int_with_default(config, "playlist", "cover-image-enable", FALSE))
1584 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), TRUE);
1585 gtk_widget_show(metaimage_artist_art);
1587 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")),TRUE);
1588 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")),TRUE);
1590 g_object_get(G_OBJECT(sidebar_text), "show_text", &st_shown, NULL);
1591 if(!st_shown)
1593 /* restore pane position */
1594 g_object_set(sidebar_text, "show_text", TRUE, NULL);
1595 gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(pl3_xml,"sidebar")),
1596 SIDEBAR_LARGE,-1);
1597 gmpc_sidebar_plugins_update_state(GMPC_PLUGIN_SIDEBAR_STATE_FULL);
1600 /* Now start hiding */
1601 switch (pl3_zoom)
1603 case PLAYLIST_NO_ZOOM:
1604 break;
1605 case PLAYLIST_MINI:
1606 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "hpaned1-hbox")));
1607 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_option")),FALSE);
1608 gtk_action_set_visible(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")),FALSE);
1609 if (pl3_win->window)
1611 if (gdk_window_get_state(pl3_win->window) & GDK_WINDOW_STATE_MAXIMIZED)
1613 gtk_window_unmaximize(GTK_WINDOW(pl3_win));
1616 if (gdk_window_get_state(pl3_win->window) & GDK_WINDOW_STATE_FULLSCREEN)
1618 gtk_window_unfullscreen(GTK_WINDOW(pl3_win));
1621 gtk_window_set_resizable(GTK_WINDOW(pl3_win), FALSE);
1623 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pl3_xml, "sidebar")));
1624 break;
1625 case PLAYLIST_SMALL:
1626 gmpc_metaimage_set_is_visible(GMPC_METAIMAGE(metaimage_artist_art), FALSE);
1627 if(st_shown) {
1628 g_object_set(sidebar_text, "show_text", FALSE, NULL);
1629 gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(pl3_xml,"sidebar")),
1630 SIDEBAR_SMALL,-1);
1632 gtk_widget_queue_draw(GTK_WIDGET(gtk_builder_get_object(pl3_xml,"sidebar")));
1633 gmpc_sidebar_plugins_update_state(GMPC_PLUGIN_SIDEBAR_STATE_COLLAPSED);
1635 gtk_widget_grab_focus(pl3_win);
1636 default:
1637 break;
1639 /** Save zoom level
1641 cfg_set_single_value_as_int(config, "playlist", "zoomlevel", pl3_zoom);
1646 * Update the window to status changes in mpd
1648 static void playlist_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata)
1650 char buffer[1024];
1651 GtkWidget *pl3_win = playlist3_get_window();
1653 * if the window isn't there yet, return
1655 if (!pl3_xml)
1656 return;
1657 control_window_status_update(mi, what, control_window);
1659 * Player state changed
1661 if (what & MPD_CST_STATE)
1663 mpd_Song *song = mpd_playlist_get_current_song(connection);
1664 int state = mpd_player_get_state(mi);
1665 switch (state)
1667 case MPD_PLAYER_PLAY:
1669 gchar *markup = cfg_get_single_value_as_string_with_default(config,
1670 "playlist", /* Category */
1671 "window-markup",/* Key */
1672 /* default value */
1673 "[%title% - &[%artist%]]|%name%|%shortfile%"
1676 * Update the image in the menu
1678 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-pause");
1679 gtk_image_set_from_stock(GTK_IMAGE
1680 (gtk_builder_get_object
1681 (pl3_xml, "play_button_image")), "gtk-media-pause",
1682 GTK_ICON_SIZE_MENU);
1685 * Update window title
1687 mpd_song_markup(buffer, 1024, markup, mpd_playlist_get_current_song(connection));
1689 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1691 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1692 if (id)
1694 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1695 id), buffer);
1696 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1697 g_free(id);
1698 g_free(string);
1700 } else
1701 gtk_window_set_title(GTK_WINDOW(pl3_win), buffer);
1703 g_free(markup);
1704 break;
1706 case MPD_PLAYER_PAUSE:
1708 gchar *markup = cfg_get_single_value_as_string_with_default(config,
1709 "playlist", /* Category */
1710 "window-markup",/* Key */
1711 /* default value */
1712 "[%title% - &[%artist%]]|%name%|%shortfile%"
1714 /** Update menu and button images */
1716 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-play");
1717 gtk_image_set_from_stock(GTK_IMAGE
1718 (gtk_builder_get_object
1719 (pl3_xml, "play_button_image")), "gtk-media-play",
1720 GTK_ICON_SIZE_MENU);
1722 * Set paused in Window string
1724 mpd_song_markup(buffer, 1024 - strlen(_("paused") - 4),
1725 markup, mpd_playlist_get_current_song(connection));
1726 /* Append translated paused */
1727 strcat(buffer, " (");
1728 strcat(buffer, _("paused"));
1729 strcat(buffer, ")");
1731 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1733 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1734 if (id)
1736 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1737 id), buffer);
1738 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1739 g_free(id);
1740 g_free(string);
1742 } else
1743 gtk_window_set_title(GTK_WINDOW(pl3_win), buffer);
1744 g_free(markup);
1745 break;
1747 default:
1748 gtk_action_set_stock_id(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")), "gtk-media-play");
1749 /* Make sure it's reset correctly */
1750 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), 0, 0);
1752 gtk_image_set_from_stock(GTK_IMAGE
1753 (gtk_builder_get_object
1754 (pl3_xml, "play_button_image")), "gtk-media-play",
1755 GTK_ICON_SIZE_MENU);
1756 if (gmpc_profiles_get_number_of_profiles(gmpc_profiles) > 1)
1758 gchar *id = gmpc_profiles_get_current(gmpc_profiles);
1759 if (id)
1761 gchar *string = g_strdup_printf("[%s] %s", gmpc_profiles_get_name(gmpc_profiles,
1762 id), _("GMPC"));
1763 gtk_window_set_title(GTK_WINDOW(pl3_win), string);
1764 g_free(id);
1765 g_free(string);
1767 } else
1768 gtk_window_set_title(GTK_WINDOW(pl3_win), _("GMPC"));
1770 playlist3_update_header();
1772 if(favorites_button != NULL)
1774 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
1776 gmpc_favorites_button_set_song(favorites_button, song);
1777 } else
1779 gmpc_favorites_button_set_song(favorites_button, NULL);
1784 * Handle song change or Playlist change
1785 * Anything that can change metadta
1787 if (what & MPD_CST_SONGID || what & MPD_CST_SONGPOS || what & MPD_CST_PLAYLIST)
1789 playlist3_update_header();
1790 /* make is update markups and stuff */
1791 playlist_status_changed(mi, MPD_CST_STATE, NULL);
1794 * set repeat buttons in menu correct
1796 if (what & MPD_CST_REPEAT)
1798 if (mpd_check_connected(connection))
1800 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDRepeat")),
1801 mpd_player_get_repeat(connection));
1805 if (what & MPD_CST_RANDOM)
1807 if (mpd_check_connected(connection))
1809 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDRandom")),
1810 mpd_player_get_random(connection));
1813 if (what & (MPD_CST_RANDOM | MPD_CST_REPEAT | MPD_CST_SINGLE_MODE | MPD_CST_CONSUME_MODE))
1815 main_window_update_status_icons();
1817 if (what & MPD_CST_SINGLE_MODE)
1819 if (mpd_check_connected(connection))
1821 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDSingleMode")),
1822 mpd_player_get_single(connection));
1826 if (what & MPD_CST_CONSUME_MODE)
1828 if (mpd_check_connected(connection))
1830 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "MPDConsumeMode")),
1831 mpd_player_get_consume(connection));
1834 if (what & MPD_CST_ELAPSED_TIME)
1836 if (mpd_check_connected(connection))
1838 int totalTime = mpd_status_get_total_song_time(connection);
1839 int elapsedTime = mpd_status_get_elapsed_song_time(connection);
1840 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), totalTime, elapsedTime);
1841 } else
1844 gmpc_progress_set_time(GMPC_PROGRESS(new_pb), 0, 0);
1847 if (what & MPD_CST_PERMISSION)
1849 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDSingleMode")),
1851 mpd_check_connected(connection) &&
1852 mpd_server_check_command_allowed(connection, "single") == MPD_SERVER_COMMAND_ALLOWED
1855 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDConsumeMode")),
1857 mpd_check_connected(connection) &&
1858 mpd_server_check_command_allowed(connection, "consume") == MPD_SERVER_COMMAND_ALLOWED
1861 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPlayPause")),
1863 mpd_check_connected(connection) &&
1864 mpd_server_check_command_allowed(connection, "play") == MPD_SERVER_COMMAND_ALLOWED
1867 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDNext")),
1869 mpd_check_connected(connection) &&
1870 mpd_server_check_command_allowed(connection, "next") == MPD_SERVER_COMMAND_ALLOWED
1873 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDPrevious")),
1875 mpd_check_connected(connection) &&
1876 mpd_server_check_command_allowed(connection, "previous") == MPD_SERVER_COMMAND_ALLOWED
1879 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDStop")),
1881 mpd_check_connected(connection) &&
1882 mpd_server_check_command_allowed(connection, "stop") == MPD_SERVER_COMMAND_ALLOWED
1885 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDRepeat")),
1887 mpd_check_connected(connection) &&
1888 mpd_server_check_command_allowed(connection, "repeat") == MPD_SERVER_COMMAND_ALLOWED
1891 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDRandom")),
1893 mpd_check_connected(connection)&&
1894 mpd_server_check_command_allowed(connection, "random") == MPD_SERVER_COMMAND_ALLOWED
1897 /* Also update volume stuff */
1898 what = what|MPD_CST_VOLUME;
1901 if (what & MPD_CST_VOLUME)
1903 GtkWidget *volume_button = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "volume_button"));
1904 //gtk_scale_button_get_value(GTK_SCALE_BUTTON(volume_button)) * 100;
1905 int volume = gmpc_widgets_volume_get_volume_level(GMPC_WIDGETS_VOLUME(volume_button));
1906 int new_volume = mpd_status_get_volume(connection);
1907 if (new_volume >= 0 &&
1908 mpd_server_check_command_allowed(connection, "setvol") == MPD_SERVER_COMMAND_ALLOWED
1911 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDMuted")),
1912 TRUE
1914 gtk_widget_set_sensitive(volume_button, TRUE);
1915 /* don't do anything if nothing is changed */
1916 if (new_volume != volume)
1918 gmpc_widgets_volume_set_volume_level(GMPC_WIDGETS_VOLUME(volume_button), new_volume );
1920 } else
1922 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "MPDMuted")),
1923 FALSE
1925 gtk_widget_set_sensitive(volume_button, FALSE);
1928 if (what & MPD_CST_SERVER_ERROR)
1930 gchar *error = mpd_status_get_mpd_error(mi);
1931 if (error)
1933 gchar *mes = g_markup_printf_escaped("%s: '%s'",
1934 _("MPD Reported the following error"),
1935 error);
1936 playlist3_show_error_message(mes, ERROR_WARNING);
1937 g_free(mes);
1938 g_free(error);
1941 if (what & MPD_CST_OUTPUT)
1943 playlist3_fill_server_menu();
1945 if (what & MPD_CST_NEXTSONG)
1948 GtkWidget *next_button = GTK_WIDGET(gtk_builder_get_object(pl3_xml, "next_button"));
1949 if (next_button)
1951 int i = mpd_player_get_next_song_id(mi);
1952 if (i >= 0)
1954 mpd_Song *song = mpd_playlist_get_song(mi, i);
1955 if (song)
1957 mpd_song_markup(buffer, 1024, "[%title% - &[%artist%]]|%shortfile%", song);
1958 gtk_widget_set_tooltip_text(next_button, buffer);
1959 mpd_freeSong(song);
1960 } else
1961 gtk_widget_set_tooltip_text(next_button, "");
1962 } else
1963 gtk_widget_set_tooltip_text(next_button, "");
1968 gboolean playlist_player_volume_changed(GtkWidget * vol_but, int new_vol)
1970 int volume = new_vol; //gtk_scale_button_get_value(GTK_SCALE_BUTTON(vol_but)) * 100;
1971 int new_volume = mpd_status_get_volume(connection);
1972 if (new_volume >= 0 && new_volume != volume)
1974 mpd_status_set_volume(connection, volume);
1975 return FALSE;
1977 return FALSE;
1981 void about_window(void)
1983 gchar *path = gmpc_get_full_glade_path("aboutdialog.ui");
1984 GtkBuilder *xml = gtk_builder_new();
1985 GtkWidget *dialog = NULL;
1986 gtk_builder_add_from_file(xml, path, NULL);
1987 dialog = (GtkWidget *) gtk_builder_get_object(xml, "aboutdialog");
1989 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(playlist3_get_window()));
1990 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1991 g_free(path);
1993 if (strlen(revision))
1995 path = g_strdup_printf("%s\nRevision: %s", VERSION, revision);
1996 } else
1998 path = g_strdup_printf("%s\n%s\n", VERSION, GMPC_TAGLINE);
2000 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), GMPC_COPYRIGHT);
2001 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), _("Gnome Music Player Client"));
2002 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), GMPC_WEBSITE);
2003 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), path);
2005 g_free(path);
2006 gtk_widget_show(dialog);
2007 gtk_dialog_run(GTK_DIALOG(dialog));
2008 gtk_widget_destroy(dialog);
2009 g_object_unref(xml);
2013 /****************************************************
2014 * Interface stuff
2016 void pl3_update_go_menu(void)
2018 int i = 0;
2019 int items = 0;
2020 GtkWidget *menu = NULL;
2021 GtkAccelGroup *group = playlist3_get_accel_group();
2022 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2023 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_go"));
2024 /***
2025 * Remove any old menu
2027 gtk_menu_item_set_submenu(m_item, NULL);
2029 * Create a new menu
2031 menu = gtk_menu_new();
2032 gtk_menu_set_accel_group(GTK_MENU(menu), group);
2033 if (mpd_check_connected(connection))
2035 for (i = 0; i < num_plugins; i++)
2037 if (gmpc_plugin_is_browser(plugins[i]))
2039 items += gmpc_plugin_browser_add_go_menu(plugins[i], menu);
2045 * Attach menu
2047 if (items)
2049 gtk_widget_show_all(menu);
2050 gtk_menu_item_set_submenu(m_item, menu);
2051 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")), TRUE);
2052 } else
2054 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_go")), FALSE);
2055 g_object_ref_sink(menu);
2056 g_object_unref(menu);
2061 static void pl3_profile_selected(GtkRadioMenuItem * radio, gpointer data)
2063 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(radio)))
2065 gchar *uid = g_object_get_data(G_OBJECT(radio), "uid");
2066 if (!uid)
2068 return;
2070 connection_set_current_profile(uid);
2071 if (mpd_check_connected(connection))
2073 mpd_disconnect(connection);
2074 connect_to_mpd();
2080 static void pl3_profiles_changed(GmpcProfiles * prof, const int changed, const int col, const gchar * id)
2082 if (!mpd_check_connected(connection))
2084 playlist_connection_changed(connection, 0, NULL);
2089 static void pl3_update_profiles_menu(GmpcProfiles * prof, const int changed, const int col, const gchar * id)
2091 int items = 0;
2092 GtkWidget *menu = NULL;
2093 gchar *current = gmpc_profiles_get_current(gmpc_profiles);
2094 GList *iter, *mult;
2095 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2096 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_music/menu_profiles"));
2097 /* check if there is anything changed that is important for us. */
2099 if (changed == GMPC_PROFILES_ACTION_COL_CHANGED && col != GMPC_PROFILES_COLUMN_NAME)
2101 g_free(current);
2102 return;
2104 /***
2105 * Remove any old menu
2107 gtk_menu_item_set_submenu(m_item, NULL);
2109 * Create a new menu
2111 menu = gtk_menu_new();
2113 mult = gmpc_profiles_get_profiles_ids(gmpc_profiles);
2114 if (mult)
2116 GSList *group = NULL;
2117 iter = mult;
2120 /** Get profile name */
2121 const gchar *value = gmpc_profiles_get_name(gmpc_profiles, (char *)iter->data);
2122 GtkWidget *item = gtk_radio_menu_item_new_with_label(group, value);
2123 /* get new group */
2124 group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
2125 /* add to the menu */
2126 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2128 /* check the current profile */
2129 if (!strcmp((char *)(iter->data), current))
2131 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
2135 * Attach click handler
2137 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_profile_selected), NULL);
2139 /** Attach the uid to the handler */
2140 value = g_strdup((char *)(iter->data));
2141 g_object_set_data_full(G_OBJECT(item), "uid", (gpointer) value, g_free);
2143 items++;
2144 } while ((iter = g_list_next(iter)));
2145 g_list_free(mult);
2150 * Attach menu
2152 if (items)
2154 gtk_widget_show_all(menu);
2155 gtk_menu_item_set_submenu(m_item , menu);
2156 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_profiles")), TRUE);
2157 } else
2159 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_profiles")), FALSE);
2160 g_object_ref_sink(menu);
2161 g_object_unref(menu);
2163 g_free(current);
2167 static void playlist3_server_output_changed(GtkWidget * item, gpointer data)
2169 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "id"));
2170 int state = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
2171 mpd_server_set_output_device(connection, id, state);
2176 void playlist3_server_update_db(void)
2178 mpd_database_update_dir(connection, "/");
2182 static GList *server_menu_items = NULL;
2183 static void playlist3_fill_server_menu(void)
2185 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2186 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_server"));
2187 /** Clear old items */
2188 if(server_menu_items != NULL)
2190 g_list_foreach(server_menu_items, (GFunc)gtk_widget_destroy, NULL);
2191 g_list_free(server_menu_items);
2192 server_menu_items = NULL;
2195 /* if connected fill with items */
2196 if (mpd_check_connected(connection))
2198 GtkWidget *menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(m_item));
2199 GtkWidget *menu_item = NULL;
2200 int i = 0;
2201 MpdData *data = NULL;
2203 data = mpd_server_get_output_devices(connection);
2204 if(data)
2206 menu_item = gtk_separator_menu_item_new();
2207 server_menu_items = g_list_append(server_menu_items, menu_item);
2208 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
2210 for (; data; data = mpd_data_get_next(data))
2212 menu_item = gtk_check_menu_item_new_with_label(data->output_dev->name);
2213 server_menu_items = g_list_append(server_menu_items, menu_item);
2214 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), data->output_dev->enabled ? TRUE : FALSE);
2215 gtk_widget_add_accelerator(menu_item, "activate",
2216 gtk_ui_manager_get_accel_group(GTK_UI_MANAGER(ui)),
2217 GDK_1 + i, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
2219 g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(playlist3_server_output_changed), NULL);
2220 g_object_set_data(G_OBJECT(menu_item), "id", GINT_TO_POINTER(data->output_dev->id));
2221 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
2222 i++;
2224 gtk_widget_show_all(menu);
2225 /* Server Menu Item */
2226 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_server")), TRUE);
2227 } else
2229 /* Server Menu Item */
2230 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_server")), FALSE);
2236 * new header
2238 /* glue code */
2240 extern GmpcBrowsersMetadata *browsers_metadata;
2242 void info2_activate(void)
2244 GtkTreeView *tree = (GtkTreeView *) gtk_builder_get_object(pl3_xml, "cat_tree");
2245 gmpc_browsers_metadata_select_browser(browsers_metadata, tree);
2249 void info2_fill_song_view(mpd_Song * song)
2251 info2_activate();
2252 gmpc_browsers_metadata_set_song(browsers_metadata, song);
2256 void info2_fill_artist_view(const gchar * artist)
2258 info2_activate();
2259 gmpc_browsers_metadata_set_artist(browsers_metadata, artist);
2263 void info2_fill_album_view(const gchar * artist, const gchar * album)
2265 info2_activate();
2266 gmpc_browsers_metadata_set_album(browsers_metadata, artist, album);
2270 void playlist3_insert_browser(GtkTreeIter * iter, gint position)
2272 GtkTreeIter it, *sib = NULL;
2273 gint pos = 0;
2274 GtkTreeModel *model = GTK_TREE_MODEL(pl3_tree);
2275 if (gtk_tree_model_get_iter_first(model, &it))
2279 gtk_tree_model_get(model, &it, PL3_CAT_ORDER, &pos, -1);
2280 if (position <= pos)
2281 sib = &it;
2282 } while (sib == NULL && gtk_tree_model_iter_next(model, &it));
2285 // first check breaks recursion. Do not check for header when adding a header.
2286 // Next check checks if the header is allready there.
2287 if(position%1000 != 0 && (pos-pos%1000) != (position-position%1000))
2289 // insert category
2290 pos = position-position%1000;
2292 if(pos == PL3_CAT_BROWSER_LIBRARY)
2294 playlist3_insert_browser(&it, PL3_CAT_BROWSER_LIBRARY);
2295 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &it,
2296 PL3_CAT_TYPE,-1, PL3_CAT_TITLE, _("Library"),PL3_CAT_BOLD, PANGO_WEIGHT_ULTRABOLD,-1);
2297 sib = &it;
2298 gtk_list_store_insert_after(GTK_LIST_STORE(pl3_tree), iter, sib);
2300 else if (pos == PL3_CAT_BROWSER_ONLINE_MEDIA)
2302 playlist3_insert_browser(&it, PL3_CAT_BROWSER_ONLINE_MEDIA);
2303 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &it,
2304 PL3_CAT_TYPE,-1, PL3_CAT_TITLE, _("Online Media"),PL3_CAT_BOLD, PANGO_WEIGHT_ULTRABOLD,-1);
2305 sib = &it;
2306 gtk_list_store_insert_after(GTK_LIST_STORE(pl3_tree), iter, sib);
2308 else if (pos == PL3_CAT_BROWSER_MISC)
2310 playlist3_insert_browser(&it, PL3_CAT_BROWSER_MISC);
2311 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &it,
2312 PL3_CAT_TYPE,-1, PL3_CAT_TITLE, _("Misc."),PL3_CAT_BOLD, PANGO_WEIGHT_ULTRABOLD,-1);
2313 sib = &it;
2314 gtk_list_store_insert_after(GTK_LIST_STORE(pl3_tree), iter, sib);
2316 else
2318 // Insert item.
2319 gtk_list_store_insert_before(GTK_LIST_STORE(pl3_tree), iter, sib);
2322 else
2324 gtk_list_store_insert_before(GTK_LIST_STORE(pl3_tree), iter, sib);
2326 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), iter, PL3_CAT_ORDER, position, PL3_CAT_BOLD, PANGO_WEIGHT_NORMAL, -1);
2331 * Category editing
2334 void playlist3_destroy(void)
2336 GtkWidget *win = playlist3_get_window();
2337 if(server_menu_items) g_list_free(server_menu_items);
2338 gtk_widget_destroy(win);
2339 g_object_unref(pl3_xml);
2342 GtkWidget *playlist3_get_window(void)
2344 return GTK_WIDGET(gtk_builder_get_object(pl3_xml, "pl3_win"));
2348 /***
2349 * Help menu
2351 /* Make glade happy */
2352 void url_visit_website(void);
2353 void url_getting_help(void);
2355 void url_visit_website(void)
2357 open_uri(GMPC_WEBSITE);
2361 void url_getting_help(void)
2363 open_uri(GMPC_BUGTRACKER);
2367 gmpcPrefPlugin playlist_gpp =
2369 .construct = playlist_pref_construct,
2370 .destroy = playlist_pref_destroy
2373 gmpcPlugin playlist_plug =
2375 .name = N_("Interface"),
2376 .version = {1, 1, 1},
2377 .plugin_type = GMPC_INTERNALL,
2378 .mpd_status_changed = &playlist_status_changed,
2379 .mpd_connection_changed = &playlist_connection_changed,
2380 .pref = &playlist_gpp,
2385 * Tool menu
2388 void pl3_tool_menu_update(void)
2390 int i;
2391 int menu_items = 0;
2392 GtkWidget *menu = NULL;
2393 GtkAccelGroup *group = gtk_accel_group_new();
2394 GtkUIManager *ui = GTK_UI_MANAGER(gtk_builder_get_object(pl3_xml, "uimanager1"));
2395 GtkMenuItem *m_item = GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui, "/menubartest/menu_tool"));
2396 gtk_menu_item_set_submenu(m_item, NULL);
2397 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_tool")), FALSE);
2398 if (!mpd_check_connected(connection))
2399 return;
2401 menu = gtk_menu_new();
2402 gtk_menu_set_accel_group(GTK_MENU(menu), group);
2403 g_object_unref(group);
2404 gtk_window_add_accel_group(GTK_WINDOW(playlist3_get_window()), group);
2405 for (i = 0; i < num_plugins; i++)
2407 menu_items += gmpc_plugin_tool_menu_integration(plugins[i], GTK_MENU(menu));
2409 if (menu_items)
2411 gtk_widget_show_all(menu);
2412 gtk_menu_item_set_submenu(m_item, menu);
2413 gtk_action_set_sensitive(GTK_ACTION(gtk_builder_get_object(pl3_xml, "menu_tool")), TRUE);
2414 } else
2416 g_object_ref_sink(menu);
2417 g_object_unref(menu);
2422 void easy_command_help_window(void)
2424 if (gmpc_easy_command)
2425 gmpc_easy_command_help_window(gmpc_easy_command, NULL);
2431 * Extra wrappings for menu
2433 extern gmpcPlugin extraplaylist_plugin;
2434 void enable_extra_playlist(GtkToggleAction *action)
2436 gboolean state = gtk_toggle_action_get_active(action);
2437 if(extraplaylist_plugin.set_enabled)
2439 if(extraplaylist_plugin.get_enabled() != state)
2441 extraplaylist_plugin.set_enabled(state);
2444 preferences_window_update();
2448 void init_extra_playlist_state(void)
2450 GtkToggleAction *action = GTK_TOGGLE_ACTION(gtk_builder_get_object(pl3_xml, "ViewExtraPlaylist"));
2451 if(extraplaylist_plugin.get_enabled)
2453 gtk_toggle_action_set_active(action, extraplaylist_plugin.get_enabled());
2457 GtkAccelGroup *playlist3_get_accel_group(void)
2459 static GtkAccelGroup *group = NULL;
2460 if(group == NULL) {
2461 group = gtk_accel_group_new();
2462 gtk_window_add_accel_group(GTK_WINDOW(playlist3_get_window()), group);
2464 return group;
2467 void open_local_file(void)
2469 char **handlers;
2470 gboolean found = FALSE;
2471 if(!mpd_check_connected(connection))
2472 return;
2474 /* Check if MPD supports 'file://' (so local files). */
2475 handlers = mpd_server_get_url_handlers(connection);
2476 if (handlers)
2478 int i=0;
2479 for(; !found && handlers != NULL && handlers[i] != NULL; i++) {
2480 if(g_utf8_collate(handlers[i], "file://") == 0) {
2481 found = TRUE;
2484 g_strfreev(handlers);
2486 /* error message or file open */
2487 if(!found) {
2488 /* Message not found */
2489 GtkWidget *gmd = gtk_message_dialog_new(
2490 (GtkWindow*)playlist3_get_window(),
2491 GTK_DIALOG_MODAL,
2492 GTK_MESSAGE_ERROR,
2493 GTK_BUTTONS_CLOSE,
2495 "To playback local files, you need to be connected "
2496 "using unix socket.\n"
2497 "See the MPD website for more information."
2500 gtk_dialog_run(GTK_DIALOG(gmd));
2501 gtk_widget_destroy(GTK_WIDGET(gmd));
2502 }else {
2503 GtkWidget *fmd = gtk_file_chooser_dialog_new(
2504 "Select a local file",
2505 (GtkWindow*)playlist3_get_window(),
2506 GTK_FILE_CHOOSER_ACTION_OPEN,
2507 GTK_STOCK_CLOSE,
2508 GTK_RESPONSE_CLOSE,
2509 GTK_STOCK_OPEN,
2510 GTK_RESPONSE_OK,
2511 NULL);
2512 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fmd), TRUE);
2513 switch(gtk_dialog_run(GTK_DIALOG(fmd)))
2515 case GTK_RESPONSE_OK:
2517 GSList *iter;
2518 GSList *uris = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(fmd));
2519 for(iter = uris;
2520 iter != NULL;
2521 iter = g_slist_next(iter))
2523 char *uri = g_uri_unescape_string(iter->data,NULL);
2524 url_start_real(uri);
2525 g_free(uri);
2527 g_slist_foreach (uris, (GFunc) g_free, NULL);
2528 g_slist_free (uris);
2529 break;
2531 default:
2532 break;
2534 gtk_widget_destroy(GTK_WIDGET(fmd));
2538 void show_user_manual(void);
2539 void show_user_manual(void)
2541 open_help("ghelp:gmpc");
2544 GmpcPluginSidebarState playlist3_get_sidebar_state(void)
2546 gboolean st_shown;
2547 g_object_get(G_OBJECT(sidebar_text), "show_text", &st_shown, NULL);
2548 return st_shown? GMPC_PLUGIN_SIDEBAR_STATE_FULL:GMPC_PLUGIN_SIDEBAR_STATE_COLLAPSED;
2550 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=80: */