diff --git a/gtk/main.c b/gtk/main.c index c6cfd1bfd..cafa5b61c 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -98,21 +98,29 @@ listclick(GtkWidget *widget, GdkEventButton *event, gpointer gdata); gboolean listpopup(GtkWidget *widget, gpointer gdata); void -dopopupmenu(GdkEventButton *event, struct cbdata *data, GtkTreeIter *iter); +dopopupmenu(GdkEventButton *event, struct cbdata *data, + GList *ids, int status); +void +killmenu(GtkWidget *menu, gpointer *gdata SHUTUP); void actionclick(GtkWidget *widget, gpointer gdata); +void +doubleclick(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, + gpointer gdata); gboolean addtorrent(tr_handle_t *tr, GtkWindow *parentwind, const char *torrent, const char *dir, gboolean paused); void addedtorrents(void *vdata); -const char * -statusstr(int status); -void -makeinfowind(struct cbdata *data, int index); gboolean savetorrents(tr_handle_t *tr, GtkWindow *wind, int count, tr_stat_t *stat); +void +orstatus(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer gdata); +void +makeidlist(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer gdata); #define TR_TYPE_PIECES_NAME "tr-type-pieces" #define TR_TYPE_PIECES ((const GType)tr_type_pieces) @@ -124,7 +132,8 @@ enum listact { ACT_OPEN, ACT_START, ACT_STOP, ACT_DELETE, ACT_INFO, ACT_PREF }; #define LIST_ACTION_FROM "torrent-list-action-from" enum listfrom { FROM_BUTTON, FROM_POPUP }; -#define LIST_INDEX "torrent-list-index" +#define LIST_INDEX "torrent-list-indexes" +#define LIST_MENU_WIDGET "torrent-list-popup-menu-widget" struct { const gchar *name; const gchar *id; enum listact act; gboolean nomenu; int avail; const char *ttext; const char *tpriv; } @@ -445,11 +454,13 @@ makewind_list(struct cbdata *data) { gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - gtk_tree_selection_set_mode(GTK_TREE_SELECTION(sel), GTK_SELECTION_SINGLE); + gtk_tree_selection_set_mode(GTK_TREE_SELECTION(sel), GTK_SELECTION_MULTIPLE); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(fixbuttons), data); g_signal_connect(G_OBJECT(view), "button-press-event", G_CALLBACK(listclick), data); g_signal_connect(G_OBJECT(view), "popup-menu", G_CALLBACK(listpopup), data); + g_signal_connect(G_OBJECT(view), "row-activated", + G_CALLBACK(doubleclick), data); gtk_widget_show_all(view); return view; @@ -468,16 +479,15 @@ stylekludge(GObject *obj, GParamSpec *spec, gpointer gdata) { void fixbuttons(GtkTreeSelection *sel, gpointer gdata) { struct cbdata *data = gdata; - GtkTreeModel *model; - GtkTreeIter iter; gboolean selected; unsigned int ii; int status; if(NULL == sel) sel = gtk_tree_view_get_selection(data->view); - if((selected = gtk_tree_selection_get_selected(sel, &model, &iter))) - gtk_tree_model_get(model, &iter, MC_STAT, &status, -1); + status = 0; + gtk_tree_selection_selected_foreach(sel, orstatus, &status); + selected = (0 < gtk_tree_selection_count_selected_rows(sel)); for(ii = 0; ii < ALEN(actionitems); ii++) if(actionitems[ii].avail) @@ -619,19 +629,42 @@ updatemodel(gpointer gdata) { return TRUE; } +/* show a popup menu for a right-click on the list */ gboolean listclick(GtkWidget *widget SHUTUP, GdkEventButton *event, gpointer gdata) { struct cbdata *data = gdata; + GtkTreeSelection *sel = gtk_tree_view_get_selection(data->view); GtkTreePath *path; GtkTreeIter iter; + int index, status; + GList *ids; if(GDK_BUTTON_PRESS == event->type && 3 == event->button) { + /* find what row, if any, the user clicked on */ if(!gtk_tree_view_get_path_at_pos(data->view, event->x, event->y, &path, NULL, NULL, NULL)) - dopopupmenu(event, data, NULL); + /* no row was clicked, do the popup with no torrent IDs or status */ + dopopupmenu(event, data, NULL, 0); else { - if(gtk_tree_model_get_iter(GTK_TREE_MODEL(data->model), &iter, path)) - dopopupmenu(event, data, &iter); + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(data->model), &iter, path)) { + /* get ID and status for the right-clicked row */ + gtk_tree_model_get(GTK_TREE_MODEL(data->model), &iter, + MC_ROW_INDEX, &index, MC_STAT, &status, -1); + /* get a list of selected IDs */ + ids = NULL; + gtk_tree_selection_selected_foreach(sel, makeidlist, &ids); + /* is the clicked row selected? */ + if(NULL == g_list_find(ids, GINT_TO_POINTER(index))) { + /* no, do the popup for just the clicked row */ + g_list_free(ids); + dopopupmenu(event, data, g_list_append(NULL, GINT_TO_POINTER(index)), + status); + } else { + /* yes, do the popup for all the selected rows */ + gtk_tree_selection_selected_foreach(sel, orstatus, &status); + dopopupmenu(event, data, ids, status); + } + } gtk_tree_path_free(path); } return TRUE; @@ -645,47 +678,58 @@ listpopup(GtkWidget *widget SHUTUP, gpointer gdata) { struct cbdata *data = gdata; GtkTreeSelection *sel = gtk_tree_view_get_selection(data->view); GtkTreeModel *model; - GtkTreeIter iter; + GList *ids; + int status; - if(!gtk_tree_selection_get_selected(sel, &model, &iter)) - dopopupmenu(NULL, data, NULL); + if(0 >= gtk_tree_selection_count_selected_rows(sel)) + dopopupmenu(NULL, data, NULL, 0); else { assert(model == GTK_TREE_MODEL(data->model)); - dopopupmenu(NULL, data, &iter); + status = 0; + gtk_tree_selection_selected_foreach(sel, orstatus, &status); + ids = NULL; + gtk_tree_selection_selected_foreach(sel, makeidlist, &ids); + dopopupmenu(NULL, data, ids, status); } return TRUE; } void -dopopupmenu(GdkEventButton *event, struct cbdata *data, GtkTreeIter *iter) { +dopopupmenu(GdkEventButton *event, struct cbdata *data, + GList *ids, int status) { GtkWidget *menu = gtk_menu_new(); GtkWidget *item; unsigned int ii; - int index, status; - index = -1; - if(NULL != iter) - gtk_tree_model_get(GTK_TREE_MODEL(data->model), iter, - MC_ROW_INDEX, &index, MC_STAT, &status, -1); - - /* XXX am I leaking references here? */ for(ii = 0; ii < ALEN(actionitems); ii++) { if(actionitems[ii].nomenu || (actionitems[ii].avail && - (0 > index || !(actionitems[ii].avail & status)))) + (NULL == ids || !(actionitems[ii].avail & status)))) continue; item = gtk_menu_item_new_with_label(actionitems[ii].name); + /* set the action for the menu item */ g_object_set_data(G_OBJECT(item), LIST_ACTION, GINT_TO_POINTER(actionitems[ii].act)); + /* show that this action came from a popup menu */ g_object_set_data(G_OBJECT(item), LIST_ACTION_FROM, GINT_TO_POINTER(FROM_POPUP)); - g_object_set_data(G_OBJECT(item), LIST_INDEX, GINT_TO_POINTER(index)); + /* set a glist of selected torrent's IDs */ + g_object_set_data(G_OBJECT(item), LIST_INDEX, ids); + /* set the menu widget, so the activate handler can destroy it */ + g_object_set_data(G_OBJECT(item), LIST_MENU_WIDGET, menu); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(actionclick), data); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } + /* set up the glist to be freed when the menu is destroyed */ + g_object_set_data_full(G_OBJECT(menu), LIST_INDEX, ids, + (GDestroyNotify)g_list_free); + + /* destroy the menu if the user doesn't select anything */ + g_signal_connect(menu, "selection-done", G_CALLBACK(killmenu), NULL); + gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, @@ -693,18 +737,28 @@ dopopupmenu(GdkEventButton *event, struct cbdata *data, GtkTreeIter *iter) { gdk_event_get_time((GdkEvent*)event)); } +void +killmenu(GtkWidget *menu, gpointer *gdata SHUTUP) { + gtk_widget_destroy(menu); +} + void actionclick(GtkWidget *widget, gpointer gdata) { struct cbdata *data = gdata; GtkTreeSelection *sel = gtk_tree_view_get_selection(data->view); - GtkTreeModel *model; - GtkTreeIter iter; enum listact act = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), LIST_ACTION)); enum listfrom from = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), LIST_ACTION_FROM)); - int index; + int index, count; + unsigned int actindex; tr_stat_t *sb; + GList *ids, *ii; + gboolean updatesave; + + /* destroy the popup menu, if any */ + if(FROM_POPUP == from) + gtk_widget_destroy(g_object_get_data(G_OBJECT(widget), LIST_MENU_WIDGET)); switch(act) { case ACT_OPEN: @@ -717,54 +771,89 @@ actionclick(GtkWidget *widget, gpointer gdata) { break; } - index = -1; switch(from) { case FROM_BUTTON: - if(gtk_tree_selection_get_selected(sel, &model, &iter)) - gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, - MC_ROW_INDEX, &index, -1); + ids = NULL; + gtk_tree_selection_selected_foreach(sel, makeidlist, &ids); /* XXX should I assert(0 <= index) to insure a row was selected? */ break; case FROM_POPUP: - index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), LIST_INDEX)); + ids = g_object_get_data(G_OBJECT(widget), LIST_INDEX); break; default: assert(!"unknown action source"); break; } - if(0 <= index) { + for(actindex = 0; actindex < ALEN(actionitems); actindex++) + if(actionitems[actindex].act == act) + break; + assert(actindex < ALEN(actionitems)); + + updatesave = FALSE; + count = tr_torrentStat(data->tr, &sb); + + for(ii = g_list_first(ids); NULL != ii; ii = ii->next) { + index = GPOINTER_TO_INT(ii->data); + if(index >= count) { + assert(!"illegal torrent id"); + continue; + } + /* check if this action is valid for this torrent */ + if(actionitems[actindex].nomenu || + (actionitems[actindex].avail && + !(actionitems[actindex].avail & sb[index].status))) + continue; + switch(act) { case ACT_START: - tr_torrentStart(data->tr, index); - savetorrents(data->tr, data->wind, -1, NULL); - updatemodel(data); + if(TR_STATUS_STOPPING & sb[index].status) + fprintf(stderr, "XXX still running\n"); + else + tr_torrentStart(data->tr, index); + updatesave = TRUE; break; case ACT_STOP: tr_torrentStop(data->tr, index); - savetorrents(data->tr, data->wind, -1, NULL); - updatemodel(data); + updatesave = TRUE; break; case ACT_DELETE: - /* XXX need to be able to stat just one torrent */ - if(index >= tr_torrentStat(data->tr, &sb)) { - assert(!"XXX i'm tired"); - } if(TR_TORRENT_NEEDS_STOP(sb[index].status)) tr_torrentStop(data->tr, index); - free(sb); tr_torrentClose(data->tr, index); - savetorrents(data->tr, data->wind, -1, NULL); - updatemodel(data); + updatesave = TRUE; break; case ACT_INFO: - makeinfowind(data, index); + makeinfowind(data->wind, data->tr, index); break; default: assert(!"unknown type"); break; } } + free(sb); + + if(updatesave) { + savetorrents(data->tr, data->wind, -1, NULL); + updatemodel(data); + } + + if(FROM_BUTTON == from) + g_list_free(ids); +} + +void +doubleclick(GtkWidget *widget SHUTUP, GtkTreePath *path, + GtkTreeViewColumn *col SHUTUP, gpointer gdata) { + struct cbdata *data = gdata; + GtkTreeIter iter; + int index; + + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(data->model), &iter, path)) { + gtk_tree_model_get(GTK_TREE_MODEL(data->model), &iter, + MC_ROW_INDEX, &index, -1); + makeinfowind(data->wind, data->tr, index); + } } gboolean @@ -811,138 +900,6 @@ addedtorrents(void *vdata) { savetorrents(data->tr, data->wind, -1, NULL); } -const char * -statusstr(int status) { - switch(status) { - case TR_STATUS_CHECK: return "check"; - case TR_STATUS_DOWNLOAD: return "download"; - case TR_STATUS_SEED: return "seed"; - case TR_STATUS_STOPPING: return "stopping"; - case TR_STATUS_STOPPED: return "stopped"; - case TR_STATUS_PAUSE: return "pause"; - case TR_TRACKER_ERROR: return "error"; - default: - assert(!"unknown status code"); - return NULL; - } -} - -void -makeinfowind(struct cbdata *data, int index) { - tr_stat_t *sb; - GtkWidget *wind, *table, *name, *value; - char buf[32]; - - if(index >= tr_torrentStat(data->tr, &sb)) { - assert(!"XXX i'm tired"); - } - wind = gtk_dialog_new_with_buttons(sb[index].info.name, data->wind, - GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); - - table = gtk_table_new(21, 2, FALSE); - - name = gtk_label_new("Torrent File"); - value = gtk_label_new(sb[index].info.torrent); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 0, 1); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 0, 1); - name = gtk_label_new("Name"); - value = gtk_label_new(sb[index].info.name); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 1, 2); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 1, 2); - name = gtk_label_new("Tracker Address"); - value = gtk_label_new(sb[index].info.trackerAddress); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 2, 3); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 2, 3); - name = gtk_label_new("Tracker Port"); - snprintf(buf, sizeof buf, "%i", sb[index].info.trackerPort); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 3, 4); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 3, 4); - name = gtk_label_new("Tracker Announce URL"); - value = gtk_label_new(sb[index].info.trackerAnnounce); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 4, 5); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 4, 5); - name = gtk_label_new("Piece Size"); - snprintf(buf, sizeof buf, "%i", sb[index].info.pieceSize); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 5, 6); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 5, 6); - name = gtk_label_new("Piece Count"); - snprintf(buf, sizeof buf, "%i", sb[index].info.pieceCount); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 6, 7); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 6, 7); - name = gtk_label_new("Total Size"); - snprintf(buf, sizeof buf, "%llu", sb[index].info.totalSize); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 7, 8); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 7, 8); - name = gtk_label_new("File Count"); - snprintf(buf, sizeof buf, "%i", sb[index].info.fileCount); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 8, 9); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 8, 9); - name = gtk_label_new("Status"); - value = gtk_label_new(statusstr(sb[index].status)); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 9, 10); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 9, 10); - name = gtk_label_new("Error"); - value = gtk_label_new(sb[index].error); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 10, 11); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 10, 11); - name = gtk_label_new("Progress"); - snprintf(buf, sizeof buf, "%f", sb[index].progress); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 11, 12); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 11, 12); - name = gtk_label_new("Download Rate"); - value = gtk_label_new(buf); - snprintf(buf, sizeof buf, "%f", sb[index].rateDownload); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 12, 13); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 12, 13); - name = gtk_label_new("Upload Rate"); - snprintf(buf, sizeof buf, "%f", sb[index].rateUpload); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 13, 14); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 13, 14); - name = gtk_label_new("ETA"); - snprintf(buf, sizeof buf, "%i", sb[index].eta); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 14, 15); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 14, 15); - name = gtk_label_new("Total Peers"); - snprintf(buf, sizeof buf, "%i", sb[index].peersTotal); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 15, 16); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 15, 16); - name = gtk_label_new("Uploading Peers"); - snprintf(buf, sizeof buf, "%i", sb[index].peersUploading); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 16, 17); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 16, 17); - name = gtk_label_new("Downloading Peers"); - snprintf(buf, sizeof buf, "%i", sb[index].peersDownloading); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 17, 18); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 17, 18); - name = gtk_label_new("Downloaded"); - snprintf(buf, sizeof buf, "%llu", sb[index].downloaded); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 18, 19); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 18, 19); - name = gtk_label_new("Uploaded"); - snprintf(buf, sizeof buf, "%llu", sb[index].uploaded); - value = gtk_label_new(buf); - gtk_table_attach_defaults(GTK_TABLE(table), name, 0, 1, 19, 20); - gtk_table_attach_defaults(GTK_TABLE(table), value, 1, 2, 19, 20); - - gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table); - g_signal_connect(G_OBJECT(wind), "response", - G_CALLBACK(gtk_widget_destroy), NULL); - gtk_widget_show_all(wind); - free(sb); -} - gboolean savetorrents(tr_handle_t *tr, GtkWindow *wind, int count, tr_stat_t *stat) { char *errstr; @@ -966,3 +923,24 @@ savetorrents(tr_handle_t *tr, GtkWindow *wind, int count, tr_stat_t *stat) { return ret; } + +/* use with gtk_tree_selection_selected_foreach to | status of selected rows */ +void +orstatus(GtkTreeModel *model, GtkTreePath *path SHUTUP, GtkTreeIter *iter, + gpointer gdata) { + int *allstatus = gdata; + int status; + + gtk_tree_model_get(model, iter, MC_STAT, &status, -1); + *allstatus |= status; +} + +void +makeidlist(GtkTreeModel *model, GtkTreePath *path SHUTUP, GtkTreeIter *iter, + gpointer gdata) { + GList **ids = gdata; + int index; + + gtk_tree_model_get(model, iter, MC_ROW_INDEX, &index, -1); + *ids = g_list_append(*ids, GINT_TO_POINTER(index)); +} diff --git a/gtk/prefs.c b/gtk/prefs.c index 8cd37e534..527b50e8c 100644 --- a/gtk/prefs.c +++ b/gtk/prefs.c @@ -24,6 +24,7 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -306,3 +307,98 @@ addresp(GtkWidget *widget, gint resp, gpointer gdata) { gtk_widget_destroy(widget); } + +#define INFOLINE(tab, ii, nam, val) \ + do { \ + GtkWidget *wid = gtk_label_new(NULL); \ + gtk_misc_set_alignment(GTK_MISC(wid), 1, .5); \ + gtk_label_set_markup(GTK_LABEL(wid), "" nam ":"); \ + gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \ + wid = gtk_label_new(val); \ + gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \ + gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \ + ii++; \ + } while(0); + +#define INFOLINEF(tab, ii, fmt, nam, val) \ + do { \ + char *buf = g_strdup_printf(fmt, val); \ + INFOLINE(tab, ii, nam, buf); \ + g_free(buf); \ + } while(0); + +#define INFOLINEA(tab, ii, nam, val) \ + do { \ + char *buf = val; \ + INFOLINE(tab, ii, nam, buf); \ + g_free(buf); \ + } while(0); + +#define INFOSEP(tab, ii) \ + do { \ + GtkWidget *wid = gtk_hseparator_new(); \ + gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \ + ii++; \ + } while(0); + +#define INFOSTATUS(st) \ + (TR_STATUS_CHECK & (st) ? "check" : \ + (TR_STATUS_DOWNLOAD & (st) ? "download" : \ + (TR_STATUS_SEED & (st) ? "seed" : \ + (TR_STATUS_STOPPING & (st) ? "stopping" : \ + (TR_STATUS_STOPPED & (st) ? "stopped" : \ + (TR_STATUS_PAUSE & (st) ? "pause" : \ + "???")))))) + +void +makeinfowind(GtkWindow *parent, tr_handle_t *tr, int id) { + tr_stat_t *sb; + GtkWidget *wind, *table, *label; + int ii; + char *str; + const int rowcount = 11; + + /* XXX would be nice to be able to stat just one */ + if(id >= tr_torrentStat(tr, &sb)) + assert(!"XXX "); + str = g_strdup_printf("%s Properties", sb[id].info.name); + wind = gtk_dialog_new_with_buttons(str, parent, + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); + g_free(str); + + table = gtk_table_new(rowcount, 2, FALSE); + gtk_table_set_col_spacings(GTK_TABLE(table), 10); + gtk_table_set_row_spacings(GTK_TABLE(table), 10); + + label = gtk_label_new(NULL); + str = g_markup_printf_escaped("%s", sb[id].info.name); + gtk_label_set_markup(GTK_LABEL(label), str); + g_free(str); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1); + + ii = 1; + + INFOSEP(table, ii); + + INFOLINEA(table, ii, "Tracker", g_strdup_printf("http://%s:%i", + sb[id].info.trackerAddress, sb[id].info.trackerPort)); + INFOLINE(table, ii, "Announce", sb[id].info.trackerAnnounce); + INFOLINEA(table, ii, "Piece Size", readablesize(sb[id].info.pieceSize, 1)); + INFOLINEF(table, ii, "%i", "Pieces", sb[id].info.pieceCount); + INFOLINEA(table, ii, "Total Size", readablesize(sb[id].info.totalSize, 1)); + + INFOSEP(table, ii); + + INFOLINE(table, ii, "Directory", sb[id].folder); + INFOLINEA(table, ii, "Downloaded", readablesize(sb[id].downloaded, 1)); + INFOLINEA(table, ii, "Uploaded", readablesize(sb[id].uploaded, 1)); + + assert(rowcount == ii); + + gtk_container_set_border_width(GTK_CONTAINER(table), 10); + gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table); + g_signal_connect(G_OBJECT(wind), "response", + G_CALLBACK(gtk_widget_destroy), NULL); + gtk_widget_show_all(wind); + free(sb); +} diff --git a/gtk/prefs.h b/gtk/prefs.h index 3c83a0e43..c1dc8cbb2 100644 --- a/gtk/prefs.h +++ b/gtk/prefs.h @@ -52,4 +52,8 @@ void makeaddwind(add_torrent_func_t addfunc, GtkWindow *parent, tr_handle_t *tr, torrents_added_func_t donefunc, void *donedata); +/* show the info window for a torrent */ +void +makeinfowind(GtkWindow *parent, tr_handle_t *tr, int index); + #endif /* TG_PREFS_H */