Codebase list gkrellm-gkrellmpc / 5f6aa7d1-3dd9-42d9-afe3-3688a4ccdf40/main playlist.c
5f6aa7d1-3dd9-42d9-afe3-3688a4ccdf40/main

Tree @5f6aa7d1-3dd9-42d9-afe3-3688a4ccdf40/main (Download .tar.gz)

playlist.c @5f6aa7d1-3dd9-42d9-afe3-3688a4ccdf40/mainraw · history · blame

/*
 * $Header: /cvsroot/gkrellmpc/playlist.c,v 1.22 2005/03/06 02:29:07 mina Exp $
 *
 * Holds all the function for playlist manipulation
 */

#include "globals.h"
#include "playlist.h"
#include "mpd.h"
#include "addlist.h"
#include <gdk/gdkkeysyms.h>

GtkWidget    * mpc_playlist = NULL;
gint           mpc_playlist_width = -1;
gint           mpc_playlist_height = 350;
gint           mpc_playlistversion = -1;
GtkListStore * mpc_playlist_store = NULL;
GtkWidget    * mpc_playlist_tree = NULL;
enum mpc_playlist_columns {
	  MPC_PLAYLIST_COLUMN_BOLD = 0
	, MPC_PLAYLIST_COLUMN_ID
	, MPC_PLAYLIST_COLUMN_ARTIST
	, MPC_PLAYLIST_COLUMN_TITLE
	, MPC_PLAYLIST_COLUMNS
};

/*
 * Creates (or activates) the playlist window
 */
void mpc_playlist_create(void) {
	GtkWidget * scrollwindow;
	GtkTreeSelection * selection;
	GtkWidget *vbox;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkWidget * buttonbar;
	GtkWidget * button;


	if (!mpc_playlist) {

		/*
		 * Create the playlist window
		 */
		mpc_playlist = gtk_window_new(GTK_WINDOW_TOPLEVEL);
		gtk_window_set_wmclass(GTK_WINDOW(mpc_playlist), "playlist", "gkrellmpc");
		gtk_window_set_title(GTK_WINDOW(mpc_playlist), _("MPD PLAYLIST"));
		gtk_container_border_width (GTK_CONTAINER(mpc_playlist), 10);
		gtk_window_set_default_size(GTK_WINDOW(mpc_playlist), mpc_playlist_width, mpc_playlist_height);
		gtk_window_set_position(GTK_WINDOW(mpc_playlist), GTK_WIN_POS_CENTER);
		g_signal_connect(GTK_OBJECT(mpc_playlist), "configure_event", G_CALLBACK(mpc_playlist_configure_event), NULL);
		g_signal_connect(GTK_OBJECT(mpc_playlist), "delete_event", G_CALLBACK(mpc_playlist_delete_event), NULL);
		g_signal_connect(GTK_OBJECT(mpc_playlist), "destroy", G_CALLBACK(mpc_playlist_destroy_event), NULL);
		g_signal_connect(mpc_playlist, "key-release-event", G_CALLBACK(mpc_cb_playlist_key), NULL);

		/*
		 * Create the data store
		 */
		mpc_playlist_store = gtk_list_store_new(MPC_PLAYLIST_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING);

		/*
		 * Create playlist tree
		 */
		mpc_playlist_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mpc_playlist_store));
		gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mpc_playlist_tree), TRUE);
		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mpc_playlist_tree));
		gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
		g_signal_connect(mpc_playlist_tree, "row-activated", G_CALLBACK(mpc_cb_playlist_row), NULL);
		g_signal_connect(mpc_playlist_tree, "key-release-event", G_CALLBACK(mpc_cb_playlist_key), NULL);

		/*
		 * Create the scrollwindow the playlist goes in
		 */
		scrollwindow = gtk_scrolled_window_new (NULL, NULL);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
		gtk_container_add (GTK_CONTAINER(scrollwindow), mpc_playlist_tree);

		/*
		 * Create the visual columns
		 */

		renderer = gtk_cell_renderer_text_new ();
		g_object_set(renderer
				, "weight", 700
				, "weight-set", FALSE
				, NULL
		);
		column = gtk_tree_view_column_new_with_attributes (_("Artist"), renderer
				, "weight-set", MPC_PLAYLIST_COLUMN_BOLD
				, "text", MPC_PLAYLIST_COLUMN_ARTIST
				, NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW(mpc_playlist_tree), column);

		renderer = gtk_cell_renderer_text_new ();
		g_object_set(renderer
				, "weight", 700
				, "weight-set", FALSE
				, NULL
		);
		column = gtk_tree_view_column_new_with_attributes (_("Title"), renderer
				, "weight-set", MPC_PLAYLIST_COLUMN_BOLD
				, "text", MPC_PLAYLIST_COLUMN_TITLE
				, NULL);
		gtk_tree_view_set_search_column(GTK_TREE_VIEW(mpc_playlist_tree), MPC_PLAYLIST_COLUMN_TITLE);
		gtk_tree_view_append_column(GTK_TREE_VIEW(mpc_playlist_tree), column);

		/*
		 * Create the bottom buttons
		 */
		buttonbar = gtk_hbutton_box_new();

		button = gtk_button_new_from_stock(GTK_STOCK_ADD);
		g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(mpc_cb_playlist_button_add), NULL);
		gtk_container_add(GTK_CONTAINER(buttonbar), button);

		button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
		g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(mpc_cb_playlist_button_remove), NULL);
		gtk_container_add(GTK_CONTAINER(buttonbar), button);

		button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
		g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(mpc_cb_playlist_button_clear), NULL);
		gtk_container_add(GTK_CONTAINER(buttonbar), button);

		button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
		g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(mpc_cb_playlist_button_close), NULL);
		gtk_container_add(GTK_CONTAINER(buttonbar), button);


		/*
		 * And pack everything
		 */
		vbox = gtk_vbox_new(FALSE, 8);
		gtk_box_pack_start(GTK_BOX(vbox), scrollwindow, 1, 1, 0);
		gtk_box_pack_start(GTK_BOX(vbox), buttonbar, 0, 0, 0);
		gtk_container_add(GTK_CONTAINER(mpc_playlist), vbox);

		/*
		 * Update the playlist
		 */
		mpc_playlist_update();

		/*
		 * Finally show everything
		 */
		gtk_widget_show_all(mpc_playlist);
	}
	else {

		/*
		 * Make the playlist window the foreground window
		 */
		gtk_window_present(GTK_WINDOW(mpc_playlist));
	}
}

/*
 * Gets called when the window manager tries to close the playlist window
 */
gint mpc_playlist_delete_event(GtkContainer *container, GtkWidget *widget, gpointer user_data) {
	return(FALSE);
}

/*
 * Gets called when the playlist window is about to be destroyed
 */
void mpc_playlist_destroy_event(GtkWidget *widget, gpointer data) {
	/* Blow it up :) */
	gtk_list_store_clear(mpc_playlist_store);
	mpc_playlist = NULL;
	mpc_playlist_store = NULL;
	mpc_playlist_tree = NULL;
	mpc_id = -1;
}

/*
 * If the playlist window exists, updates it with the playlist from mpd
 */
gboolean mpc_playlist_update(void) {
	GPtrArray * list;
	GHashTable * hash;
	GtkTreeIter iter;
	int i;
	gint id;
	gchar * artist;
	gchar * name;
	gchar * title;
	
	if (!mpc_playlist) {
		/*
		 * There's no playlist, so there's nothing to do
		 */
		return(TRUE);
	}
	else {
		/*
		 * Get the playlist from mpd
		 */
		list = mpc_mpd_get_clumps("playlistinfo\n", FALSE);
		if (!list) {
			return (FALSE);
		}

		/*
		 * Populate it
		 */
		gtk_list_store_clear(mpc_playlist_store);
		for (i=0; i < list->len; i++) {

			hash = g_ptr_array_index(list, i);

			/* Add new row to store */
			gtk_list_store_append(mpc_playlist_store, &iter);

			/* Set local vars id, artist, name and title */
			id = g_strtod(g_hash_table_lookup(hash, "id"), NULL);
			artist = g_hash_table_lookup(hash, "artist");
			name = g_hash_table_lookup(hash, "name");
			title = g_hash_table_lookup(hash, "title");
			if (!title) title = g_hash_table_lookup(hash, "file");

			/* Set them in the store */
			gtk_list_store_set(mpc_playlist_store, &iter
					, MPC_PLAYLIST_COLUMN_BOLD, (id == mpc_id ? TRUE : FALSE)
					, MPC_PLAYLIST_COLUMN_ID, id
					, MPC_PLAYLIST_COLUMN_ARTIST, (artist ? artist : name ? name : "")
					, MPC_PLAYLIST_COLUMN_TITLE, title
					, -1);

			g_hash_table_destroy(hash);

		}

		g_ptr_array_free(list, FALSE);

		return (TRUE);
	}
}

/*
 * Called when the "clear" button is clicked in the playlist window
 */
void mpc_cb_playlist_button_clear (GtkButton *button, gpointer user_data) {
	mpc_mpd_do("clear\n");
}

/*
 * Called when the "remove" button is clicked in the playlist window
 */
void mpc_cb_playlist_button_remove (GtkButton *button, gpointer user_data) {
	GtkTreeSelection * selection;
	GArray * selected;
	gint i;
	gchar * command;

	/*
	 * Populate selected with the id of selected rows
	 */
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mpc_playlist_tree));
	selected = g_array_new(FALSE, TRUE, sizeof(gint));
	gtk_tree_selection_selected_foreach(selection, mpc_cb_delete_foreach, selected);

	for (i=0; i < selected->len; i++) {
		command = g_strdup_printf("deleteid %d\n", g_array_index(selected, gint, i));
		mpc_mpd_do(command);
		g_free(command);
	}
	g_array_free(selected, FALSE);
}

/*
 * Gets called from mpc_cb_playlist_button_remove for each selected row
 * It's job is to add the id of that row's song into the given array
 */
void mpc_cb_delete_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
	gint id;
	gtk_tree_model_get(GTK_TREE_MODEL(mpc_playlist_store), iter
			, MPC_PLAYLIST_COLUMN_ID, &id
			, -1);
	g_array_append_val(data, id);
}

/*
 * Called when the "add" button is clicked in the playlist window
 */
void mpc_cb_playlist_button_add (GtkButton *button, gpointer user_data) {
	mpc_addlist_create();
}

/*
 * Called when the "close" button is clicked in the playlist window
 */
void mpc_cb_playlist_button_close (GtkButton *button, gpointer user_data) {
	gtk_widget_destroy(mpc_playlist);
}

/*
 * Called when the user double-clicks/hits enter on a playlist row
 */
void mpc_cb_playlist_row (GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data) {
	GtkTreeIter   iter;
	gint id;
	gchar * command;

	if (gtk_tree_model_get_iter(GTK_TREE_MODEL(mpc_playlist_store), &iter, path)) {
		gtk_tree_model_get(GTK_TREE_MODEL(mpc_playlist_store), &iter
				, MPC_PLAYLIST_COLUMN_ID, &id
				, -1);
		command = g_strdup_printf("playid %d\n", id);
		mpc_mpd_do(command);
		g_free(command);
	}
}

/*
 * Called when a user presses a key in the playlist window or tree
 */
gboolean mpc_cb_playlist_key (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {

	if (widget == mpc_playlist) {

		/*
		 * Key pressed in main window
		 */
		switch (event->keyval) {
			case GDK_Escape:
				/* They pressed Escape - destroy the playlist */
				gtk_widget_destroy(mpc_playlist);
				return (TRUE);
		}
	}
	else if (widget == mpc_playlist_tree) {

		/*
		 * Key pressed in tree
		 */
		switch (event->keyval) {
			case GDK_Delete:
			case GDK_KP_Delete:
				/* They pressed delete - simulate a "Remove" button keypress */
				mpc_cb_playlist_button_remove(NULL, NULL);
				return (TRUE);
		}
	}

	/*
	 * If we've reached here tell GTK to send the key upwards
	 */
	return (FALSE);
}

/*
 * If the playlist window is open, it makes "bold" the song ID in mpc_id
 */
void mpc_playlist_update_bold (void) {
	GtkTreeIter iter;
	gint id;

	if (!mpc_playlist) {
		/* No playlist - nothing to do */
	}
	else {
		if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mpc_playlist_store), &iter)) {
			/* Store is empty */
		}
		else {

			while (1) {

				/* iter points to an entry
				 * get id */
				gtk_tree_model_get(GTK_TREE_MODEL(mpc_playlist_store), &iter
						, MPC_PLAYLIST_COLUMN_ID, &id
						, -1);

				if (id == mpc_id) {
					/* We found the one that should be bold */
					gtk_list_store_set(mpc_playlist_store, &iter, MPC_PLAYLIST_COLUMN_BOLD, TRUE, -1);
				}
				else {
					/* Whatever this is should not be bold */
					gtk_list_store_set(mpc_playlist_store, &iter, MPC_PLAYLIST_COLUMN_BOLD, FALSE, -1);
				}

				if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(mpc_playlist_store), &iter)) {
					/* No more entries in store */
					break;
				}
			}

		}
	}
}

gboolean mpc_playlist_configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) {
	/* Remember width & height */
	mpc_playlist_width = event->width;
	mpc_playlist_height = event->height;
	return(FALSE);
}