From e9b70a84ae0e40ea4bcaa6e557f2f67eea57cfd3 Mon Sep 17 00:00:00 2001 From: "rjk@greenend.org.uk" <> Date: Sun, 29 Jul 2007 15:36:28 +0100 Subject: [PATCH] ,commit --- .bzrignore | 1 + disobedience/choose.c | 75 ++++++++++++++++++++++++++++++++++++--------- disobedience/control.c | 28 ++++++++++++++--- disobedience/disobedience.h | 18 +++++++++++ disobedience/misc.c | 3 ++ disobedience/queue.c | 32 +++++++++++++++++-- 6 files changed, 137 insertions(+), 20 deletions(-) diff --git a/.bzrignore b/.bzrignore index 6a51fab..bffd385 100644 --- a/.bzrignore +++ b/.bzrignore @@ -89,3 +89,4 @@ doc/disorder-speaker.8.html core vgcore.* *.tar.gz +TAGS diff --git a/disobedience/choose.c b/disobedience/choose.c index 71256c8..cf22eaf 100644 --- a/disobedience/choose.c +++ b/disobedience/choose.c @@ -22,6 +22,18 @@ /* Choose track ------------------------------------------------------------ */ +WT(label); +WT(event_box); +WT(menu); +WT(menu_item); +WT(layout); +WT(vbox); +WT(arrow); +WT(hbox); +WT(button); +WT(image); +WT(entry); + /* We don't use the built-in tree widgets because they require that you know * the children of a node on demand, and we have to wait for the server to tell * us. */ @@ -197,6 +209,34 @@ static void fill_root_node(struct choosenode *cn) { } } +static void delete_cn_widgets(struct choosenode *cn) { + if(cn->arrow) { + DW(arrow); + gtk_widget_destroy(cn->arrow); + cn->arrow = 0; + } + if(cn->label) { + DW(label); + gtk_widget_destroy(cn->label); + cn->label = 0; + } + if(cn->marker) { + DW(image); + gtk_widget_destroy(cn->marker); + cn->marker = 0; + } + if(cn->hbox) { + DW(hbox); + gtk_widget_destroy(cn->hbox); + cn->hbox = 0; + } + if(cn->container) { + DW(event_box); + gtk_widget_destroy(cn->container); + cn->container = 0; + } +} + /* Clear all the children of CN */ static void clear_children(struct choosenode *cn) { int n; @@ -205,15 +245,7 @@ static void clear_children(struct choosenode *cn) { /* Recursively clear subtrees */ for(n = 0; n < cn->children.nvec; ++n) { clear_children(cn->children.vec[n]); - if(cn->children.vec[n]->container) { - if(cn->children.vec[n]->arrow) - gtk_widget_destroy(cn->children.vec[n]->arrow); - gtk_widget_destroy(cn->children.vec[n]->label); - if(cn->children.vec[n]->marker) - gtk_widget_destroy(cn->children.vec[n]->marker); - gtk_widget_destroy(cn->children.vec[n]->hbox); - gtk_widget_destroy(cn->children.vec[n]->container); - } + delete_cn_widgets(cn->children.vec[n]); } cn->children.nvec = 0; } @@ -330,6 +362,11 @@ static void contract_node(struct choosenode *cn) { cn->flags &= ~CN_EXPANDED; /* Clear selection below this node */ clear_selection(cn); + /* Zot children. We never used to do this but the result would be that over + * time you'd end up with the entire tree pulled into memory. If the server + * is over a slow network it will make interactivity slightly worse; if + * anyone complains we can make it an option. */ + clear_children(cn); /* We can contract a node immediately. */ redisplay_tree(); } @@ -535,10 +572,7 @@ static void clearsearch_clicked(GtkButton attribute((unused)) *button, static void delete_widgets(struct choosenode *cn) { int n; - if(cn->container) { - gtk_widget_destroy(cn->container); - cn->container = 0; - } + delete_cn_widgets(cn); for(n = 0; n < cn->children.nvec; ++n) delete_widgets(cn->children.vec[n]); cn->flags &= ~(CN_DISPLAYED|CN_SELECTED); @@ -590,23 +624,29 @@ static struct displaydata display_tree(struct choosenode *cn, int x, int y) { */ if(!cn->container) { /* Widgets need to be created */ + NW(hbox); cn->hbox = gtk_hbox_new(FALSE, 1); if(cn->flags & CN_EXPANDABLE) { + NW(arrow); cn->arrow = gtk_arrow_new(cn->flags & CN_EXPANDED ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, GTK_SHADOW_NONE); cn->marker = 0; } else { cn->arrow = 0; - if((pb = find_image("notes.png"))) + if((pb = find_image("notes.png"))) { + NW(image); cn->marker = gtk_image_new_from_pixbuf(pb); + } } + NW(label); cn->label = gtk_label_new(cn->display); if(cn->arrow) gtk_container_add(GTK_CONTAINER(cn->hbox), cn->arrow); gtk_container_add(GTK_CONTAINER(cn->hbox), cn->label); if(cn->marker) gtk_container_add(GTK_CONTAINER(cn->hbox), cn->marker); + NW(event_box); cn->container = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(cn->container), cn->hbox); g_signal_connect(cn->container, "button-release-event", @@ -942,15 +982,18 @@ GtkWidget *choose_widget(void) { */ /* Text entry box for search terms */ + NW(entry); searchentry = gtk_entry_new(); g_signal_connect(searchentry, "changed", G_CALLBACK(searchentry_changed), 0); /* Cancel button to clear the search */ + NW(button); clearsearch = gtk_button_new_from_stock(GTK_STOCK_CANCEL); g_signal_connect(G_OBJECT(clearsearch), "clicked", G_CALLBACK(clearsearch_clicked), 0); /* hbox packs the search box and the cancel button together on a line */ + NW(hbox); hbox = gtk_hbox_new(FALSE/*homogeneous*/, 1/*spacing*/); gtk_box_pack_start(GTK_BOX(hbox), searchentry, TRUE/*expand*/, TRUE/*fill*/, 0/*padding*/); @@ -959,15 +1002,18 @@ GtkWidget *choose_widget(void) { /* chooselayout contains the currently visible subset of the track * namespace */ + NW(layout); chooselayout = gtk_layout_new(0, 0); root = newnode(0/*parent*/, "", "All files", "", CN_EXPANDABLE, fill_root_node); realroot = root; expand_node(root); /* will call redisplay_tree */ /* Create the popup menu */ + NW(menu); menu = gtk_menu_new(); g_signal_connect(menu, "destroy", G_CALLBACK(gtk_widget_destroyed), &menu); for(n = 0; n < NMENUITEMS; ++n) { + NW(menu_item); menuitems[n].w = gtk_menu_item_new_with_label(menuitems[n].name); gtk_menu_attach(GTK_MENU(menu), menuitems[n].w, 0, 1, n, n + 1); } @@ -975,6 +1021,7 @@ GtkWidget *choose_widget(void) { scrolled = scroll_widget(GTK_WIDGET(chooselayout), "choose"); /* The scrollable layout and the search hbox go together in a vbox */ + NW(vbox); vbox = gtk_vbox_new(FALSE/*homogenous*/, 1/*spacing*/); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE/*expand*/, FALSE/*fill*/, 0/*padding*/); diff --git a/disobedience/control.c b/disobedience/control.c index 3b6f2ac..5e2e0d3 100644 --- a/disobedience/control.c +++ b/disobedience/control.c @@ -20,7 +20,16 @@ #include "disobedience.h" -/* Forward declartions ----------------------------------------------------- */ +/* Forward declarations ---------------------------------------------------- */ + +WT(adjustment); +WT(hscale); +WT(hbox); +WT(tooltips); +WT(button); +WT(image); +WT(label); +WT(vbox); struct icon; @@ -77,7 +86,7 @@ static struct icon { GtkAdjustment *volume_adj, *balance_adj; /* Create the control bar */ - GtkWidget *control_widget(void) { +GtkWidget *control_widget(void) { GtkWidget *hbox = gtk_hbox_new(FALSE, 1), *vbox; GtkWidget *content; GdkPixbuf *pb; @@ -85,31 +94,42 @@ GtkAdjustment *volume_adj, *balance_adj; GtkTooltips *tips = gtk_tooltips_new(); int n; + NW(hbox); + NW(tooltips); D(("control_widget")); for(n = 0; n < NICONS; ++n) { + NW(button); icons[n].button = gtk_button_new(); - if((pb = find_image(icons[n].icon))) + if((pb = find_image(icons[n].icon))) { + NW(image); content = gtk_image_new_from_pixbuf(pb); - else + } else { + NW(label); content = gtk_label_new(icons[n].icon); + } gtk_container_add(GTK_CONTAINER(icons[n].button), content); gtk_tooltips_set_tip(tips, icons[n].button, icons[n].tip, ""); g_signal_connect(G_OBJECT(icons[n].button), "clicked", G_CALLBACK(icons[n].clicked), &icons[n]); /* pop the icon in a vbox so it doesn't get vertically stretch if there are * taller things in the control bar */ + NW(vbox); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), icons[n].button, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); } /* create the adjustments for the volume control */ + NW(adjustment); volume_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, goesupto, goesupto / 20, goesupto / 20, 0)); + NW(adjustment); balance_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -1, 1, 0.2, 0.2, 0)); /* the volume control */ + NW(hscale); v = gtk_hscale_new(volume_adj); + NW(hscale); b = gtk_hscale_new(balance_adj); gtk_scale_set_digits(GTK_SCALE(v), 10); gtk_scale_set_digits(GTK_SCALE(b), 10); diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index 59cc6e9..3998124 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -167,6 +167,24 @@ GtkWidget *choose_widget(void); void choose_update(void); /* Called when we think the choose tree might need updating */ +/* Widget leakage debugging rubbish ---------------------------------------- */ + +#if MDEBUG +#define NW(what) do { \ + if(++current##what % 100 > max##what) { \ + fprintf(stderr, "%s:%d: %d %s\n", \ + __FILE__, __LINE__, current##what, #what); \ + max##what = current##what; \ + } \ +} while(0) +#define WT(what) static int current##what, max##what +#define DW(what) (--current##what) +#else +#define NW(what) (0) +#define DW(what) (0) +#define WT(what) struct neverused +#endif + #endif /* DISOBEDIENCE_H */ /* diff --git a/disobedience/misc.c b/disobedience/misc.c index 4ce3a43..d0caf3b 100644 --- a/disobedience/misc.c +++ b/disobedience/misc.c @@ -22,6 +22,8 @@ /* Miscellaneous GTK+ stuff ------------------------------------------------ */ +WT(cached_image); + /* Functions */ GtkWidget *scroll_widget(GtkWidget *child, @@ -68,6 +70,7 @@ GdkPixbuf *find_image(const char *name) { error(0, "%s", err->message); return 0; } + NW(cached_image); cache_put(&image_cache_type, name, pb); } return pb; diff --git a/disobedience/queue.c b/disobedience/queue.c index 16cbc4c..f9b9ec8 100644 --- a/disobedience/queue.c +++ b/disobedience/queue.c @@ -55,6 +55,13 @@ /* Queue management -------------------------------------------------------- */ +WT(label); +WT(event_box); +WT(menu); +WT(menu_item); +WT(layout); +WT(vbox); + struct queuelike; static void add_drag_targets(struct queuelike *ql); @@ -361,6 +368,7 @@ static GtkWidget *column_when(const struct queuelike attribute((unused)) *ql, strftime(when, sizeof when, "%H:%M", localtime_r(&t, &tm)); else when[0] = 0; + NW(label); return gtk_label_new(when); } @@ -369,6 +377,7 @@ static GtkWidget *column_who(const struct queuelike attribute((unused)) *ql, const struct queue_entry *q, const char attribute((unused)) *data) { D(("column_who")); + NW(label); return gtk_label_new(q->submitter ? q->submitter : ""); } @@ -378,6 +387,7 @@ static GtkWidget *column_namepart(const struct queuelike const struct queue_entry *q, const char *data) { D(("column_namepart")); + NW(label); return gtk_label_new(namepart(q->track, "display", data)); } @@ -417,13 +427,17 @@ static GtkWidget *column_length(const struct queuelike attribute((unused)) *ql, D(("column_length")); if(q == playing_track) { assert(!playing_length_label); + NW(label); playing_length_label = gtk_label_new(text_length(q)); /* Zot playing_length_label when it is destroyed */ g_signal_connect(playing_length_label, "destroy", G_CALLBACK(gtk_widget_destroyed), &playing_length_label); return playing_length_label; - } else + } else { + NW(label); return gtk_label_new(text_length(q)); + } + } /* Apply a new queue contents, transferring the selection from the old value */ @@ -462,6 +476,7 @@ static GtkWidget *wrap_queue_cell(GtkWidget *label, * background */ gtk_misc_set_padding(GTK_MISC(label), HCELLPADDING, VCELLPADDING); /* Event box is just to hold a background color */ + NW(event_box); bg = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(bg), label); if(wp) { @@ -492,6 +507,7 @@ static GtkWidget *get_queue_cell(struct queuelike *ql, /* Add a padding cell to the end of a row */ static GtkWidget *get_padding_cell(const char *name) { D(("get_padding_cell")); + NW(label); return wrap_queue_cell(gtk_label_new(""), name, 0); } @@ -729,6 +745,7 @@ static gboolean queue_drag_motion(GtkWidget attribute((unused)) *widget, if(!id || q) { if(!ql->dragmark) { + NW(event_box); ql->dragmark = gtk_event_box_new(); g_signal_connect(ql->dragmark, "destroy", G_CALLBACK(gtk_widget_destroyed), &ql->dragmark); @@ -765,6 +782,7 @@ static void add_drag_target(struct queuelike *ql, int y, int row, GtkWidget *eventbox; assert(ql->dropzones[row] == 0); + NW(event_box); eventbox = gtk_event_box_new(); /* Make the target zone invisible */ gtk_event_box_set_visible_window(GTK_EVENT_BOX(eventbox), FALSE); @@ -818,6 +836,7 @@ static void remove_drag_targets(struct queuelike *ql) { for(row = 0; row < ql->nrows; ++row) { if(ql->dropzones[row]) { + DW(event_box); gtk_widget_destroy(ql->dropzones[row]); } assert(ql->dropzones[row] == 0); @@ -843,8 +862,11 @@ static void redisplay_queue(struct queuelike *ql) { c; c = c->next) { /* Destroy both the label and the eventbox */ - if(GTK_BIN(c->data)->child) + if(GTK_BIN(c->data)->child) { + DW(label); gtk_widget_destroy(GTK_BIN(c->data)->child); + } + DW(event_box); gtk_widget_destroy(GTK_WIDGET(c->data)); } /* Adjust the row count */ @@ -992,7 +1014,9 @@ static GtkWidget *queuelike(struct queuelike *ql, ql->mainrowheight = !0; /* else division by 0 */ ql->selection = selection_new(); /* Create the layouts */ + NW(layout); ql->mainlayout = gtk_layout_new(0, 0); + NW(layout); ql->titlelayout = gtk_layout_new(0, 0); /* Scroll the layouts */ ql->mainscroll = mainscroll = scroll_widget(ql->mainlayout, name); @@ -1005,6 +1029,7 @@ static GtkWidget *queuelike(struct queuelike *ql, g_signal_connect(mainadj, "value-changed", G_CALLBACK(queue_scrolled), titleadj); /* Fill the titles and put them anywhere */ for(col = 0; col < NCOLUMNS; ++col) { + NW(label); label = gtk_label_new(columns[col].name); gtk_misc_set_alignment(GTK_MISC(label), columns[col].xalign, 0); ql->titlecells[col] = wrap_queue_cell(label, "row-title", 0); @@ -1013,14 +1038,17 @@ static GtkWidget *queuelike(struct queuelike *ql, ql->titlecells[col] = get_padding_cell("row-title"); gtk_layout_put(GTK_LAYOUT(ql->titlelayout), ql->titlecells[col], 0, 0); /* Pack the lot together in a vbox */ + NW(vbox); vbox = gtk_vbox_new(0, 0); gtk_box_pack_start(GTK_BOX(vbox), titlescroll, 0, 0, 0); gtk_box_pack_start(GTK_BOX(vbox), mainscroll, 1, 1, 0); /* Create the popup menu */ + NW(menu); ql->menu = gtk_menu_new(); g_signal_connect(ql->menu, "destroy", G_CALLBACK(gtk_widget_destroyed), &ql->menu); for(n = 0; menuitems[n].name; ++n) { + NW(menu_item); menuitems[n].w = gtk_menu_item_new_with_label(menuitems[n].name); gtk_menu_attach(GTK_MENU(ql->menu), menuitems[n].w, 0, 1, n, n + 1); } -- 2.11.0