📄 playlist.c
字号:
/*** Sinek (Media Player)** Copyright (c) 2001-2002 Gurer Ozen**** This code is free software; you can redistribute it and/or** modify it under the terms of the GNU General Public License.**** playlist*/#include "common.h"enum{ COL_MRL, COL_ITEM, N_COLS};static gint nr_items;static GtkWidget *list_view;static GtkListStore *list_store;static GtkTreeSelection *list_select;static GtkTreeRowReference *cur_item;typedef struct pl_item_struct{ char *mrl; int time; int format;} pl_item;static void pl_remove(pl_item *item);void pl_sort_by_name(void);void pl_sort_shuffle(void);void pl_sort_reverse(void);static void cb_load(GtkWidget *w, gpointer data);static void cb_save(GtkWidget *w, int to_default);static void cb_play(GtkWidget *w, gpointer data);static void cb_add(GtkWidget *w, gpointer data);static void cb_remove(GtkWidget *w, gpointer data);void pl_load(char *fname);#define BUTTON(title,sigfunc,data) \ but = gtk_button_new_with_label(title); \ gtk_widget_show(but); \ gtk_box_pack_start(GTK_BOX(hb), but, TRUE, TRUE, 4); \ g_signal_connect(G_OBJECT(but), "clicked", G_CALLBACK(sigfunc), (gpointer)data)static void cb_menu(GtkWidget *widget, guint action){ if(sinek.signal_fake) return; execute_cmd((cmd_type)action);}static void find_m3u(gpointer data, gpointer user_data){ char *t; t = strrchr((char *) data, '.'); if(t && strcasecmp(t, ".m3u") == 0) { char **fname = (char **) user_data; if(*fname) g_free(*fname); *fname = g_strdup((char *) data); }}int pl_init(void){ gchar *fname = NULL; sinek.repeat_all = media->conf->register_bool(media->conf, "sinek.repeat_all", -1, NULL, NULL, NULL, NULL); wm_build(pl_build); g_list_foreach(sinek.start_mrls, find_m3u, &fname); if(!fname && !sinek.start_mrls) fname = g_strconcat(g_get_home_dir(), "/.xine/playlist.xml", NULL); if(fname) { pl_load(fname); g_list_foreach(sinek.start_mrls, (GFunc) g_free, NULL); g_list_free(sinek.start_mrls); sinek.start_mrls = NULL; g_free(fname); } return 1;}gboolean play_item(GtkTreeIter *iter, pl_item *item, gboolean can_remove){ GtkTreePath *path; if(video_play(item->mrl)) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(list_store), iter); if(cur_item) gtk_tree_row_reference_free(cur_item); cur_item = gtk_tree_row_reference_new(GTK_TREE_MODEL(list_store), path); gtk_tree_path_free(path); return TRUE; } else if(can_remove) { gtk_list_store_remove(list_store, iter); pl_remove(item); } return FALSE;}void pl_prev(void){ GtkTreePath *path; GtkTreeIter iter; pl_item *item; if(!cur_item) return; path = gtk_tree_row_reference_get_path(cur_item); if(!path) return; gtk_tree_path_prev(path); if(gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store), &iter, path)) { gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); play_item(&iter, item, TRUE); } gtk_tree_path_free(path);}void pl_next(void){ GtkTreePath *path = NULL; GtkTreeIter iter; pl_item *item; if(cur_item) path = gtk_tree_row_reference_get_path(cur_item); if(path) gtk_tree_path_next(path); else path = gtk_tree_path_new_root(); while(nr_items) { if(FALSE == gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store), &iter, path)) { if(sinek.repeat_all == 0) break; if(path) gtk_tree_path_free(path); path = gtk_tree_path_new_root(); continue; } gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); if(play_item(&iter, item, TRUE)) break; } gtk_tree_path_free(path);}char *pl_get_mrl(int row){ pl_item *item = NULL; GtkTreeIter iter; if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter, NULL, row)) gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); if(item) return(item->mrl); return NULL;}void pl_append(char *mrl){ pl_item *item; GtkTreeIter iter; if(!mrl || mrl[0] == 0) return; item = malloc(sizeof(pl_item)); if(!item) return; item->mrl = strdup(mrl); gtk_list_store_append(list_store, &iter); gtk_list_store_set(list_store, &iter, COL_ITEM, (gpointer)item, -1); nr_items++;}static void pl_remove(pl_item *item){ free(item->mrl); free(item); nr_items--;}void pl_remove_all(void){ GtkTreeIter iter; gboolean go; pl_item *item; go = gtk_tree_model_get_iter_root(GTK_TREE_MODEL(list_store), &iter); while(go) { gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); pl_remove(item); go = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); } gtk_list_store_clear(list_store); nr_items = 0;}void pl_load_m3u(char *fname){ gchar buf[2048], *t, *path; FILE *f; f = fopen(fname, "r"); if(f) { while(fgets(buf, 2040, f)) { strtok(buf, "\r\n"); if(buf[0] != '#') { while((t = strchr(buf, '\\')) != NULL) *t = '/'; if(buf[0] != '/' && !strstr(buf, "://")) { path = g_strdup(fname); t = strrchr(path, '/'); if(t) { *t = '\0'; t = g_strdup_printf("%s/%s", path, buf); pl_append(t); free(t); } else { pl_append(buf); } } else { pl_append(buf); } } } fclose(f); }}void pl_load(char *filename){ iks *x, *y; char *mrl; x = iks_load(filename); if(!x || iks_strcmp(iks_name(x), "spl") != 0) return; for(y = iks_child(x); y; y = iks_next(y)) { if(iks_type(y) == IKS_TAG && iks_strcmp(iks_name(y), "media") == 0) { mrl = iks_cdata(iks_child(iks_find(y, "mrl"))); if(mrl) pl_append(mrl); } } iks_delete(x);}void pl_save(char *filename){ iks *x, *y; pl_item *item; GtkTreeIter iter; gboolean go; x = iks_new("spl"); iks_insert_cdata(x, "\n", 1); if(sinek.repeat_all) { iks_insert(x, "repeat"); iks_insert_cdata(x, "\n", 1); } go = gtk_tree_model_get_iter_root(GTK_TREE_MODEL(list_store), &iter); while(go) { gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); y = iks_insert(x, "media"); iks_insert_cdata(y, "\n\t", 2); iks_insert_cdata(iks_insert(y, "mrl"), item->mrl, -1); iks_insert_cdata(y, "\n", 1); iks_insert_cdata(x, "\n", 1); go = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); } iks_save(filename, x); iks_delete(x);} static void cb_load(GtkWidget *w, gpointer data){ select_file(pl_load, _("Load playlist..."));}static void cb_save(GtkWidget *w, int to_default){ gchar *fname; if(to_default) { fname = g_strconcat(g_get_home_dir(), "/.xine/playlist.xml", NULL); pl_save(fname); g_free(fname); } else select_file(pl_save, _("Save playlist as..."));}static void cb_play_file(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gboolean *go){ pl_item *item; if(*go) { gtk_tree_model_get(model, iter, COL_ITEM, &item, -1); if(play_item(iter, item, FALSE)) *go = FALSE; }}static void cb_play(GtkWidget *w, gpointer data){ gboolean go = TRUE; gtk_tree_selection_selected_foreach(list_select, (GtkTreeSelectionForeachFunc)cb_play_file, &go); if(go) { pl_item *item; GtkTreeIter iter; if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter, NULL, 0)) { gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); play_item(&iter, item, FALSE); } }}static gint cb_click(GtkWidget *w, GdkEventButton *ev, gpointer data){ if(ev->type == GDK_2BUTTON_PRESS) { gboolean go = TRUE; gtk_tree_selection_selected_foreach(list_select, (GtkTreeSelectionForeachFunc)cb_play_file, &go); } return FALSE;}static void cb_add(GtkWidget *w, gpointer data){ file_request(TRUE);}static void cb_remove_file(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, int *nr){ pl_item *item; gtk_tree_model_get(model, iter, COL_ITEM, &item, -1); gtk_list_store_set(list_store, iter, COL_ITEM, NULL, -1); pl_remove(item); (*nr)++;}static void cb_remove(GtkWidget *w, gpointer data){ GtkTreeIter iter; gboolean go; pl_item *item; int nr = 0; gtk_tree_selection_selected_foreach(list_select, (GtkTreeSelectionForeachFunc)cb_remove_file, &nr); if(nr == 0) return; go = gtk_tree_model_get_iter_root(GTK_TREE_MODEL(list_store), &iter); while(go && nr) { gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEM, &item, -1); if(item) { go = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); } else { gtk_list_store_remove(list_store, &iter); nr--; } }}static gint sort_func(pl_item **a, pl_item **b, gboolean reverse){ pl_item *item1 = *a; pl_item *item2 = *b; if(reverse) return strcmp(g_basename(item2->mrl), g_basename(item1->mrl)); else return strcmp(g_basename(item1->mrl), g_basename(item2->mrl));}void pl_sort_by_name(void){ sort_list(list_store, COL_ITEM, (GCompareDataFunc)sort_func, (gpointer)FALSE);}void pl_sort_reverse(void){ sort_list(list_store, COL_ITEM, (GCompareDataFunc)sort_func, (gpointer)TRUE);}void pl_sort_shuffle(void){ int *deal, *newdeal; int len = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store), NULL); int i, j; GtkTreeIter iter1, iter2; pl_item *a, *b; if(len < 2) return; deal = g_malloc0(sizeof(int) * len); newdeal = g_malloc0(sizeof(int) * len); for(i = 0; i < len; i++) deal[i] = i; for(i = 0; i < len; i++) { j = (((double)len - i) * rand()) / RAND_MAX; newdeal[i] = deal[j]; if(j != (len - i - 1)) deal[j] = deal[len - i - 1]; } for(i = 0; i < len; i++) { j = newdeal[i]; if(newdeal[j] != -1 && i != j) { gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter1, NULL, i); gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter1, COL_ITEM, &a, -1); gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter2, NULL, j); gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter2, COL_ITEM, &b, -1); gtk_list_store_set(list_store, &iter1, COL_ITEM, b, -1); gtk_list_store_set(list_store, &iter2, COL_ITEM, a, -1);
} newdeal[i] = -1; } g_free(newdeal); g_free(deal);}static void cb_render_mrl(GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data){ pl_item *item; gtk_tree_model_get(model, iter, COL_ITEM, &item, -1); g_object_set(cell, "text", g_basename(item->mrl), NULL);}int pl_build(GtkWidget **win){ GtkItemFactoryEntry menus[] = { { _("/File"), NULL, NULL, 0, "<Branch>" }, { _("/File/Open..."), NULL, cb_load, 0, "<StockItem>", GTK_STOCK_OPEN }, { _("/File/Save as..."), NULL, cb_save, 0, "<StockItem>", GTK_STOCK_SAVE_AS }, { _("/File/Save as Default"), NULL, cb_save, 1, NULL }, { _("/Edit"), NULL, NULL, 0, "<Branch>" }, { _("/Edit/Add..."), NULL, cb_add, 0, "<StockItem>", GTK_STOCK_ADD }, { _("/Edit/Remove"), NULL, cb_remove, 0, "<StockItem>", GTK_STOCK_REMOVE }, { _("/Edit/Clear"), NULL, pl_remove_all, 0, "<StockItem>", GTK_STOCK_CLEAR }, { _("/Sort"), NULL, NULL, 0, "<Branch>" }, { _("/Sort/By Name"), NULL, pl_sort_by_name, 0, NULL }, { _("/Sort/Reverse"), NULL, pl_sort_reverse, 0, NULL }, { _("/Sort/Shuffle"), NULL, pl_sort_shuffle, 0, NULL }, { _("/Modes"), NULL, NULL, 0, "<Branch>" }, { _("/Modes/Repeat"), NULL, cb_menu, CMD_TOGGLE_REPEAT_ALL, "<CheckItem>" } }; GtkItemFactory *fabrika; gint n = sizeof(menus) / sizeof(menus[0]); GtkWidget *w, *vb, *menu, *sw, *hb, *but; GtkCellRenderer *cell; GtkTreeViewColumn *col; w = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(w), _("Sinek Playlist")); gtk_window_set_wmclass(GTK_WINDOW(w), "playlist", "sinek"); gtk_window_set_default_size(GTK_WINDOW(w), 450, 200); vb = gtk_vbox_new(FALSE, 0); gtk_widget_show(vb); gtk_container_add(GTK_CONTAINER(w), vb); gtk_container_set_border_width(GTK_CONTAINER(vb), 4); /* menu */ fabrika = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", NULL); gtk_item_factory_create_items(fabrika, n, menus, NULL); menu = gtk_item_factory_get_widget(fabrika, "<main>"); sinek.repeat_all_chk = gtk_item_factory_get_widget(fabrika, _("/Modes/Repeat")); sinek.signal_fake = 1; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(sinek.repeat_all_chk), sinek.repeat_all); sinek.signal_fake = 0; gtk_widget_show(menu); gtk_box_pack_start(GTK_BOX(vb), menu, FALSE, FALSE, 0); /* playlist */ sw = gtk_scrolled_window_new(NULL, NULL); gtk_widget_show(sw); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vb), sw, TRUE, TRUE, 3); list_store = gtk_list_store_new(N_COLS, G_TYPE_STRING, G_TYPE_POINTER); list_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); list_select = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view)); gtk_tree_selection_set_mode(list_select, GTK_SELECTION_MULTIPLE); cell = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes(_("Media"), cell, NULL); gtk_tree_view_column_set_cell_data_func(col, cell, cb_render_mrl, NULL, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), col); gtk_widget_show(list_view); gtk_container_add(GTK_CONTAINER(sw), list_view); gtk_tree_view_set_reorderable(GTK_TREE_VIEW(list_view), TRUE); g_signal_connect(G_OBJECT(list_view), "button_press_event", G_CALLBACK(cb_click), NULL); /* buttons */ hb = gtk_hbox_new(TRUE, 0); gtk_widget_show(hb); gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, TRUE, 4); gtk_container_set_border_width(GTK_CONTAINER(hb), 5); BUTTON(_("Play"), cb_play, 0); BUTTON(_("Add..."), cb_add, 0); BUTTON(_("Remove"), cb_remove, 0); *win = w; return WM_NORMAL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -