From 6982880f199dda54b194408f5b4fb3c42c734e79 Mon Sep 17 00:00:00 2001 Message-Id: <6982880f199dda54b194408f5b4fb3c42c734e79.1719115190.git.mdw@distorted.org.uk> From: Mark Wooding Date: Thu, 12 Jun 2008 11:18:39 +0100 Subject: [PATCH] Start on popup menu for Disobedience choose tab. Mostly this is restructing; the per-tab callbacks for the edit menu are now shared with the popup menu, eliminating a lot of fiddly shims, and various things are split out into their own files. Organization: Straylight/Edgeware From: Richard Kettlewell --- disobedience/Makefile.am | 5 +- disobedience/added.c | 3 +- disobedience/choose-menu.c | 132 +++++++++++++++++++++++++++++++++++ disobedience/choose.c | 79 +++------------------ disobedience/choose.h | 66 ++++++++++++++++++ disobedience/disobedience.h | 9 ++- disobedience/menu.c | 6 +- disobedience/popup.c | 85 ++++++++++++++++++++++ disobedience/popup.h | 62 ++++++++++++++++ disobedience/queue-generic.c | 1 + disobedience/queue-generic.h | 36 ++-------- disobedience/queue-menu.c | 103 ++++++--------------------- disobedience/queue.c | 3 +- disobedience/recent.c | 3 +- 14 files changed, 402 insertions(+), 191 deletions(-) create mode 100644 disobedience/choose-menu.c create mode 100644 disobedience/choose.h create mode 100644 disobedience/popup.c create mode 100644 disobedience/popup.h diff --git a/disobedience/Makefile.am b/disobedience/Makefile.am index 93d7096..ab085f2 100644 --- a/disobedience/Makefile.am +++ b/disobedience/Makefile.am @@ -27,8 +27,9 @@ PNGS:=$(shell export LC_COLLATE=C;echo ${top_srcdir}/images/*.png) disobedience_SOURCES=disobedience.h disobedience.c client.c queue.c \ recent.c added.c queue-generic.c queue-generic.h queue-menu.c \ - choose.c misc.c control.c properties.c menu.c log.c progress.c \ - login.c rtp.c help.c ../lib/memgc.c settings.c users.c + choose.c choose-menu.c popup.c misc.c control.c properties.c \ + menu.c log.c progress.c login.c rtp.c help.c ../lib/memgc.c \ + settings.c users.c disobedience_LDADD=../lib/libdisorder.a $(LIBPCRE) $(LIBGC) $(LIBGCRYPT) \ $(LIBASOUND) $(COREAUDIO) $(LIBDB) disobedience_LDFLAGS=$(GTK_LIBS) diff --git a/disobedience/added.c b/disobedience/added.c index 038c439..e3c41c2 100644 --- a/disobedience/added.c +++ b/disobedience/added.c @@ -18,6 +18,7 @@ * USA */ #include "disobedience.h" +#include "popup.h" #include "queue-generic.h" /** @brief Called with an updated list of newly-added tracks @@ -77,7 +78,7 @@ static const struct queue_column added_columns[] = { }; /** @brief Pop-up menu for new tracks list */ -static struct queue_menuitem added_menuitems[] = { +static struct menuitem added_menuitems[] = { { "Track properties", ql_properties_activate, ql_properties_sensitive, 0, 0 }, { "Play track", ql_play_activate, ql_play_sensitive, 0, 0 }, { "Select all tracks", ql_selectall_activate, ql_selectall_sensitive, 0, 0 }, diff --git a/disobedience/choose-menu.c b/disobedience/choose-menu.c new file mode 100644 index 0000000..8ba78e7 --- /dev/null +++ b/disobedience/choose-menu.c @@ -0,0 +1,132 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2008 Richard Kettlewell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#include "disobedience.h" +#include "popup.h" +#include "choose.h" + +/** @brief Popup menu */ +static GtkWidget *choose_menu; + +static int choose_selectall_sensitive(void attribute((unused)) *extra) { + return TRUE; +} + +static void choose_selectall_activate(GtkMenuItem attribute((unused)) *item, + gpointer attribute((unused)) userdata) { + gtk_tree_selection_select_all(choose_selection); +} + +static int choose_selectnone_sensitive(void attribute((unused)) *extra) { + return gtk_tree_selection_count_selected_rows(choose_selection) > 0; +} + +static void choose_selectnone_activate(GtkMenuItem attribute((unused)) *item, + gpointer attribute((unused)) userdata) { + gtk_tree_selection_unselect_all(choose_selection); +} + +static int choose_play_sensitive(void attribute((unused)) *extra) { + return FALSE; /* TODO */ +} + +static void choose_play_activate(GtkMenuItem attribute((unused)) *item, + gpointer attribute((unused)) userdata) { + /* TODO */ +} + +static int choose_properties_sensitive(void attribute((unused)) *extra) { + return FALSE; /* TODO */ +} + +static void choose_properties_activate(GtkMenuItem attribute((unused)) *item, + gpointer attribute((unused)) userdata) { + /* TODO */ +} + +/** @brief Pop-up menu for choose */ +static struct menuitem choose_menuitems[] = { + { + "Play track", + choose_play_activate, + choose_play_sensitive, + 0, + 0 + }, + { + "Track properties", + choose_properties_activate, + choose_properties_sensitive, + 0, + 0 + }, + { + "Select all tracks", + choose_selectall_activate, + choose_selectall_sensitive, + 0, + 0 + }, + { + "Deselect all tracks", + choose_selectnone_activate, + choose_selectnone_sensitive, + 0, + 0 + }, +}; + +const struct tabtype choose_tabtype = { + choose_properties_sensitive, + choose_selectall_sensitive, + choose_selectnone_sensitive, + choose_properties_activate, + choose_selectall_activate, + choose_selectnone_activate, + 0, + 0 +}; + +/** @brief Called when a mouse button is pressed or released */ +gboolean choose_button_event(GtkWidget attribute((unused)) *widget, + GdkEventButton *event, + gpointer attribute((unused)) user_data) { + if(event->type == GDK_BUTTON_RELEASE && event->button == 2) { + /* Middle click release - play track */ + //ensure_selected(choose_view, event); + /* TODO */ + } else if(event->type == GDK_BUTTON_PRESS && event->button == 3) { + /* Right click press - pop up the menu */ + ensure_selected(GTK_TREE_VIEW(choose_view), event); + popup(&choose_menu, event, + choose_menuitems, sizeof choose_menuitems / sizeof *choose_menuitems, + 0); + return TRUE; + } + return FALSE; +} + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/disobedience/choose.c b/disobedience/choose.c index 569b8b7..1a51a06 100644 --- a/disobedience/choose.c +++ b/disobedience/choose.c @@ -38,54 +38,28 @@ * TODO: * - sweep up contracted nodes * - update when content may have changed (e.g. after a rescan) - * - popup menu + * - popup menu (partially implemented now) * - playing state * - display length of tracks */ #include "disobedience.h" - -/** @brief Extra data at each node */ -struct choosedata { - /** @brief Node type */ - int type; - - /** @brief Full track or directory name */ - gchar *track; - - /** @brief Sort key */ - gchar *sort; -}; - -/** @brief Track name column number */ -#define NAME_COLUMN 0 - -/** @brief Hidden column number */ -#define CHOOSEDATA_COLUMN 1 - -/** @brief @ref choosedata node is a file */ -#define CHOOSE_FILE 0 - -/** @brief @ref choosedata node is a directory */ -#define CHOOSE_DIRECTORY 1 +#include "choose.h" /** @brief The current selection tree */ -static GtkTreeStore *choose_store; +GtkTreeStore *choose_store; /** @brief The view onto the selection tree */ -static GtkWidget *choose_view; +GtkWidget *choose_view; /** @brief The selection tree's selection */ -static GtkTreeSelection *choose_selection; - -/** @brief Popup menu */ -//static GtkWidget *choose_menu; +GtkTreeSelection *choose_selection; /** @brief Map choosedata types to names */ static const char *const choose_type_map[] = { "track", "dir" }; /** @brief Return the choosedata given an interator */ -static struct choosedata *choose_iter_to_data(GtkTreeIter *iter) { +struct choosedata *choose_iter_to_data(GtkTreeIter *iter) { GValue v[1]; memset(v, 0, sizeof v); gtk_tree_model_get_value(GTK_TREE_MODEL(choose_store), iter, CHOOSEDATA_COLUMN, v); @@ -275,41 +249,6 @@ static void choose_row_expanded(GtkTreeView attribute((unused)) *treeview, /* The row references are destroyed in the _completed handlers. */ } -static int choose_tab_selectall_sensitive(void attribute((unused)) *extra) { - return TRUE; -} - -static void choose_tab_selectall_activate(void attribute((unused)) *extra) { - gtk_tree_selection_select_all(choose_selection); -} - -static int choose_tab_selectnone_sensitive(void attribute((unused)) *extra) { - return gtk_tree_selection_count_selected_rows(choose_selection) > 0; -} - -static void choose_tab_selectnone_activate(void attribute((unused)) *extra) { - gtk_tree_selection_unselect_all(choose_selection); -} - -static int choose_tab_properties_sensitive(void attribute((unused)) *extra) { - return TRUE; -} - -static void choose_tab_properties_activate(void attribute((unused)) *extra) { - fprintf(stderr, "TODO choose_tab_properties_activate\n"); -} - -static const struct tabtype choose_tabtype = { - choose_tab_properties_sensitive, - choose_tab_selectall_sensitive, - choose_tab_selectnone_sensitive, - choose_tab_properties_activate, - choose_tab_selectall_activate, - choose_tab_selectnone_activate, - 0, - 0 -}; - /** @brief Create the choose tab */ GtkWidget *choose_widget(void) { /* Create the tree store. */ @@ -334,8 +273,10 @@ GtkWidget *choose_widget(void) { gtk_tree_selection_set_mode(choose_selection, GTK_SELECTION_MULTIPLE); /* Catch button presses */ - /*g_signal_connect(choose_view, "button-press-event", - G_CALLBACK(choose_button_release), 0);*/ + g_signal_connect(choose_view, "button-press-event", + G_CALLBACK(choose_button_event), 0); + g_signal_connect(choose_view, "button-release-event", + G_CALLBACK(choose_button_event), 0); /* Catch row expansions so we can fill in placeholders */ g_signal_connect(choose_view, "row-expanded", G_CALLBACK(choose_row_expanded), 0); diff --git a/disobedience/choose.h b/disobedience/choose.h new file mode 100644 index 0000000..cb968c5 --- /dev/null +++ b/disobedience/choose.h @@ -0,0 +1,66 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2008 Richard Kettlewell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#ifndef CHOOSE_H +#define CHOOSE_H + +/** @brief Extra data at each node */ +struct choosedata { + /** @brief Node type */ + int type; + + /** @brief Full track or directory name */ + gchar *track; + + /** @brief Sort key */ + gchar *sort; +}; + +/** @brief Track name column number */ +#define NAME_COLUMN 0 + +/** @brief Hidden column number */ +#define CHOOSEDATA_COLUMN 1 + +/** @brief @ref choosedata node is a file */ +#define CHOOSE_FILE 0 + +/** @brief @ref choosedata node is a directory */ +#define CHOOSE_DIRECTORY 1 + +extern GtkTreeStore *choose_store; +extern GtkWidget *choose_view; +extern GtkTreeSelection *choose_selection; +extern const struct tabtype choose_tabtype; + +struct choosedata *choose_iter_to_data(GtkTreeIter *iter); +gboolean choose_button_event(GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +#endif /* CHOOSE_H */ + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index 21f3bf6..e18c082 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -90,9 +90,12 @@ struct tabtype { int (*properties_sensitive)(void *extra); int (*selectall_sensitive)(void *extra); int (*selectnone_sensitive)(void *extra); - void (*properties_activate)(void *extra); - void (*selectall_activate)(void *extra); - void (*selectnone_activate)(void *extra); + void (*properties_activate)(GtkMenuItem *menuitem, + gpointer user_data); + void (*selectall_activate)(GtkMenuItem *menuitem, + gpointer user_data); + void (*selectnone_activate)(GtkMenuItem *menuitem, + gpointer user_data); void (*selected)(void); void *extra; }; diff --git a/disobedience/menu.c b/disobedience/menu.c index 8dcae3c..7cf65c0 100644 --- a/disobedience/menu.c +++ b/disobedience/menu.c @@ -59,7 +59,7 @@ static void select_all(gpointer attribute((unused)) callback_data, const struct tabtype *t = g_object_get_data(G_OBJECT(tab), "type"); if(t->selectall_activate) - t->selectall_activate(t->extra); + t->selectall_activate(NULL, t->extra); } /** @brief Called when the select none option is activated @@ -74,7 +74,7 @@ static void select_none(gpointer attribute((unused)) callback_data, const struct tabtype *t = g_object_get_data(G_OBJECT(tab), "type"); if(t->selectnone_activate) - t->selectnone_activate(t->extra); + t->selectnone_activate(NULL, t->extra); } /** @brief Called when the track properties option is activated @@ -89,7 +89,7 @@ static void properties_item(gpointer attribute((unused)) callback_data, const struct tabtype *t = g_object_get_data(G_OBJECT(tab), "type"); if(t->properties_activate) - t->properties_activate(t->extra); + t->properties_activate(NULL, t->extra); } /** @brief Called when the login option is activated */ diff --git a/disobedience/popup.c b/disobedience/popup.c new file mode 100644 index 0000000..ce17a73 --- /dev/null +++ b/disobedience/popup.c @@ -0,0 +1,85 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2008 Richard Kettlewell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#include "disobedience.h" +#include "popup.h" + +void popup(GtkWidget **menup, + GdkEventButton *event, + struct menuitem *items, + int nitems, + void *extra) { + GtkWidget *menu = *menup; + + /* Create the menu if it does not yet exist */ + if(!menu) { + menu = *menup = gtk_menu_new(); + g_signal_connect(menu, "destroy", + G_CALLBACK(gtk_widget_destroyed), menup); + for(int n = 0; n < nitems; ++n) { + items[n].w = gtk_menu_item_new_with_label(items[n].name); + gtk_menu_attach(GTK_MENU(menu), items[n].w, 0, 1, n, n + 1); + } + set_tool_colors(menu); + } + /* Configure item sensitivity */ + for(int n = 0; n < nitems; ++n) { + if(items[n].handlerid) + g_signal_handler_disconnect(items[n].w, + items[n].handlerid); + gtk_widget_set_sensitive(items[n].w, + items[n].sensitive(extra)); + items[n].handlerid = g_signal_connect(items[n].w, + "activate", + G_CALLBACK(items[n].activate), + extra); + } + /* Pop up the menu */ + gtk_widget_show_all(menu); + gtk_menu_popup(GTK_MENU(menu), 0, 0, 0, 0, + event->button, event->time); +} + +/** @brief Make sure that something is selected + * @param widget Tree view + * @param event Mouse event (the hovered row will be selected) + */ +void ensure_selected(GtkTreeView *treeview, + GdkEventButton *event) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + if(gtk_tree_selection_count_selected_rows(selection) == 0) { + GtkTreePath *path; + if(gtk_tree_view_get_path_at_pos(treeview, + event->x, event->y, + &path, + NULL, + NULL, NULL)) + gtk_tree_selection_select_path(selection, path); + gtk_tree_path_free(path); + } +} + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/disobedience/popup.h b/disobedience/popup.h new file mode 100644 index 0000000..165f69b --- /dev/null +++ b/disobedience/popup.h @@ -0,0 +1,62 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2008 Richard Kettlewell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#ifndef POPUP_H +#define POPUP_H + +/** @brief A popup menu item */ +struct menuitem { + /** @brief Menu item name */ + const char *name; + + /** @brief Called to activate the menu item */ + void (*activate)(GtkMenuItem *menuitem, + gpointer user_data); + + /** @brief Called to determine whether the menu item is usable. + * + * Returns @c TRUE if it should be sensitive and @c FALSE otherwise. + */ + int (*sensitive)(void *extra); + + /** @brief Signal handler ID */ + gulong handlerid; + + /** @brief Widget for menu item */ + GtkWidget *w; +}; + +void popup(GtkWidget **menup, + GdkEventButton *event, + struct menuitem *items, + int nitems, + void *extra); +void ensure_selected(GtkTreeView *treeview, + GdkEventButton *event); + +#endif /* POPUP_H */ + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/disobedience/queue-generic.c b/disobedience/queue-generic.c index 633b174..e6971ab 100644 --- a/disobedience/queue-generic.c +++ b/disobedience/queue-generic.c @@ -40,6 +40,7 @@ * - display playing row in a different color? */ #include "disobedience.h" +#include "popup.h" #include "queue-generic.h" static struct queuelike *const queuelikes[] = { diff --git a/disobedience/queue-generic.h b/disobedience/queue-generic.h index 8b2acaf..8f5b59f 100644 --- a/disobedience/queue-generic.h +++ b/disobedience/queue-generic.h @@ -45,28 +45,6 @@ struct queue_column { /** @brief Right-algin column */ #define COL_RIGHT 0x0004 -/** @brief An item in the queue's popup menu */ -struct queue_menuitem { - /** @brief Menu item name */ - const char *name; - - /** @brief Called to activate the menu item */ - void (*activate)(GtkMenuItem *menuitem, - gpointer user_data); - - /** @brief Called to determine whether the menu item is usable. - * - * Returns @c TRUE if it should be sensitive and @c FALSE otherwise. - */ - int (*sensitive)(struct queuelike *ql); - - /** @brief Signal handler ID */ - gulong handlerid; - - /** @brief Widget for menu item */ - GtkWidget *w; -}; - /** @brief Definition of a queue-like window */ struct queuelike { @@ -85,7 +63,7 @@ struct queuelike { int ncolumns; /** @brief Items for popup menu */ - struct queue_menuitem *menuitems; + struct menuitem *menuitems; /** @brief Number of menu items */ int nmenuitems; @@ -119,22 +97,22 @@ extern struct queuelike ql_added; extern time_t last_playing; -int ql_selectall_sensitive(struct queuelike *ql); +int ql_selectall_sensitive(void *extra); void ql_selectall_activate(GtkMenuItem *menuitem, gpointer user_data); -int ql_selectnone_sensitive(struct queuelike *ql); +int ql_selectnone_sensitive(void *extra); void ql_selectnone_activate(GtkMenuItem *menuitem, gpointer user_data); -int ql_properties_sensitive(struct queuelike *ql); +int ql_properties_sensitive(void *extra); void ql_properties_activate(GtkMenuItem *menuitem, gpointer user_data); -int ql_scratch_sensitive(struct queuelike *ql); +int ql_scratch_sensitive(void *extra); void ql_scratch_activate(GtkMenuItem *menuitem, gpointer user_data); -int ql_remove_sensitive(struct queuelike *ql); +int ql_remove_sensitive(void *extra); void ql_remove_activate(GtkMenuItem *menuitem, gpointer user_data); -int ql_play_sensitive(struct queuelike *ql); +int ql_play_sensitive(void *extra); void ql_play_activate(GtkMenuItem *menuitem, gpointer user_data); gboolean ql_button_release(GtkWidget *widget, diff --git a/disobedience/queue-menu.c b/disobedience/queue-menu.c index ac3479a..fcc34bf 100644 --- a/disobedience/queue-menu.c +++ b/disobedience/queue-menu.c @@ -18,11 +18,13 @@ * USA */ #include "disobedience.h" +#include "popup.h" #include "queue-generic.h" /* Select All */ -int ql_selectall_sensitive(struct queuelike *ql) { +int ql_selectall_sensitive(void *extra) { + struct queuelike *ql = extra; return !!ql->q; } @@ -35,7 +37,8 @@ void ql_selectall_activate(GtkMenuItem attribute((unused)) *menuitem, /* Select None */ -int ql_selectnone_sensitive(struct queuelike *ql) { +int ql_selectnone_sensitive(void *extra) { + struct queuelike *ql = extra; return gtk_tree_selection_count_selected_rows(ql->selection) > 0; } @@ -48,7 +51,8 @@ void ql_selectnone_activate(GtkMenuItem attribute((unused)) *menuitem, /* Properties */ -int ql_properties_sensitive(struct queuelike *ql) { +int ql_properties_sensitive(void *extra) { + struct queuelike *ql = extra; return gtk_tree_selection_count_selected_rows(ql->selection) > 0; } @@ -71,7 +75,7 @@ void ql_properties_activate(GtkMenuItem attribute((unused)) *menuitem, /* Scratch */ -int ql_scratch_sensitive(struct queuelike attribute((unused)) *ql) { +int ql_scratch_sensitive(void attribute((unused)) *extra) { return !!(last_state & DISORDER_PLAYING) && right_scratchable(last_rights, config->username, playing_track); } @@ -100,7 +104,8 @@ static void ql_remove_sensitive_callback(GtkTreeModel *model, ++counts[removable]; } -int ql_remove_sensitive(struct queuelike *ql) { +int ql_remove_sensitive(void *extra) { + struct queuelike *ql = extra; int counts[2] = { 0, 0 }; gtk_tree_selection_selected_foreach(ql->selection, ql_remove_sensitive_callback, @@ -135,7 +140,8 @@ void ql_remove_activate(GtkMenuItem attribute((unused)) *menuitem, /* Play */ -int ql_play_sensitive(struct queuelike *ql) { +int ql_play_sensitive(void *extra) { + struct queuelike *ql = extra; return (last_rights & RIGHT_PLAY) && gtk_tree_selection_count_selected_rows(ql->selection) > 0; } @@ -162,38 +168,8 @@ void ql_play_activate(GtkMenuItem attribute((unused)) *menuitem, 0); } -/** @brief Create @c ql->menu if it does not already exist */ -static void ql_create_menu(struct queuelike *ql) { - if(ql->menu) - return; - ql->menu = gtk_menu_new(); - g_signal_connect(ql->menu, "destroy", - G_CALLBACK(gtk_widget_destroyed), &ql->menu); - for(int n = 0; n < ql->nmenuitems; ++n) { - ql->menuitems[n].w = gtk_menu_item_new_with_label(ql->menuitems[n].name); - gtk_menu_attach(GTK_MENU(ql->menu), ql->menuitems[n].w, 0, 1, n, n + 1); - } - set_tool_colors(ql->menu); -} - -/** @brief Configure @c ql->menu */ -static void ql_configure_menu(struct queuelike *ql) { - /* Set the sensitivity of each menu item and (re-)establish the signal - * handlers */ - for(int n = 0; n < ql->nmenuitems; ++n) { - if(ql->menuitems[n].handlerid) - g_signal_handler_disconnect(ql->menuitems[n].w, - ql->menuitems[n].handlerid); - gtk_widget_set_sensitive(ql->menuitems[n].w, - ql->menuitems[n].sensitive(ql)); - ql->menuitems[n].handlerid = g_signal_connect - (ql->menuitems[n].w, "activate", - G_CALLBACK(ql->menuitems[n].activate), ql); - } -} - /** @brief Called when a button is released over a queuelike */ -gboolean ql_button_release(GtkWidget*widget, +gboolean ql_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { struct queuelike *ql = user_data; @@ -201,59 +177,22 @@ gboolean ql_button_release(GtkWidget*widget, if(event->type == GDK_BUTTON_PRESS && event->button == 3) { /* Right button click. */ - if(gtk_tree_selection_count_selected_rows(ql->selection) == 0) { - /* Nothing is selected, select whatever is under the pointer */ - GtkTreePath *path; - if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), - event->x, event->y, - &path, - NULL, - NULL, NULL)) - gtk_tree_selection_select_path(ql->selection, path); - } - ql_create_menu(ql); - ql_configure_menu(ql); - gtk_widget_show_all(ql->menu); - gtk_menu_popup(GTK_MENU(ql->menu), 0, 0, 0, 0, - event->button, event->time); + ensure_selected(GTK_TREE_VIEW(widget), event); + popup(&ql->menu, event, ql->menuitems, ql->nmenuitems, ql); return TRUE; /* hide the click from other widgets */ } return FALSE; } -static int ql_tab_selectall_sensitive(void *extra) { - return ql_selectall_sensitive(extra); -} - -static void ql_tab_selectall_activate(void *extra) { - ql_selectall_activate(NULL, extra); -} - -static int ql_tab_selectnone_sensitive(void *extra) { - return ql_selectnone_sensitive(extra); -} - -static void ql_tab_selectnone_activate(void *extra) { - ql_selectnone_activate(NULL, extra); -} - -static int ql_tab_properties_sensitive(void *extra) { - return ql_properties_sensitive(extra); -} - -static void ql_tab_properties_activate(void *extra) { - ql_properties_activate(NULL, extra); -} - struct tabtype *ql_tabtype(struct queuelike *ql) { static const struct tabtype ql_tabtype = { - ql_tab_properties_sensitive, - ql_tab_selectall_sensitive, - ql_tab_selectnone_sensitive, - ql_tab_properties_activate, - ql_tab_selectall_activate, - ql_tab_selectnone_activate, + ql_properties_sensitive, + ql_selectall_sensitive, + ql_selectnone_sensitive, + ql_properties_activate, + ql_selectall_activate, + ql_selectnone_activate, 0, 0 }; diff --git a/disobedience/queue.c b/disobedience/queue.c index 2c68a68..fe9e707 100644 --- a/disobedience/queue.c +++ b/disobedience/queue.c @@ -18,6 +18,7 @@ * USA */ #include "disobedience.h" +#include "popup.h" #include "queue-generic.h" /** @brief The actual queue */ @@ -156,7 +157,7 @@ static const struct queue_column queue_columns[] = { }; /** @brief Pop-up menu for queue */ -static struct queue_menuitem queue_menuitems[] = { +static struct menuitem queue_menuitems[] = { { "Track properties", ql_properties_activate, ql_properties_sensitive, 0, 0 }, { "Select all tracks", ql_selectall_activate, ql_selectall_sensitive, 0, 0 }, { "Deselect all tracks", ql_selectnone_activate, ql_selectnone_sensitive, 0, 0 }, diff --git a/disobedience/recent.c b/disobedience/recent.c index 01647ab..49333e7 100644 --- a/disobedience/recent.c +++ b/disobedience/recent.c @@ -18,6 +18,7 @@ * USA */ #include "disobedience.h" +#include "popup.h" #include "queue-generic.h" /** @brief Update the recently played list */ @@ -75,7 +76,7 @@ static const struct queue_column recent_columns[] = { }; /** @brief Pop-up menu for recently played list */ -static struct queue_menuitem recent_menuitems[] = { +static struct menuitem recent_menuitems[] = { { "Track properties", ql_properties_activate, ql_properties_sensitive,0, 0 }, { "Select all tracks", ql_selectall_activate, ql_selectall_sensitive, 0, 0 }, { "Deselect all tracks", ql_selectnone_activate, ql_selectnone_sensitive, 0, 0 }, -- [mdw]