Changeset 1475
- Timestamp:
- Feb 7, 2007, 7:35:33 AM (16 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gtk/conf.h
r1468 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2005-200 6Transmission authors and contributors4 * Copyright (c) 2005-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a -
trunk/gtk/dialogs.h
r1468 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2005-200 6Transmission authors and contributors4 * Copyright (c) 2005-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a -
trunk/gtk/main.c
r1472 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2005-200 6Transmission authors and contributors4 * Copyright (c) 2005-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a … … 43 43 #include "tr_torrent.h" 44 44 #include "tr_cell_renderer_progress.h" 45 #include "tr_window.h" 45 46 #include "transmission.h" 46 47 #include "util.h" … … 61 62 GtkWindow *wind; 62 63 GtkTreeModel *model; 63 GtkTreeView *view;64 GtkStatusbar *bar;65 GtkWidget **buttons;66 64 guint timer; 67 65 gboolean prefsopen; 68 66 gboolean msgwinopen; 69 GtkWidget *stupidpopuphack;70 67 gboolean closing; 71 68 }; … … 77 74 }; 78 75 79 GList * 76 enum action 77 { 78 ACT_OPEN = 0, 79 ACT_START, 80 ACT_STOP, 81 ACT_DELETE, 82 ACT_INFO, 83 ACT_PREF, 84 ACT_DEBUG, 85 ACTION_COUNT, 86 }; 87 88 struct 89 { 90 const char * label; 91 const char * icon; 92 int flags; 93 const char * tooltip; 94 } 95 actions[] = 96 { 97 { N_("Add"), GTK_STOCK_ADD, ACTF_WHEREVER | ACTF_ALWAYS, 98 N_("Add a new torrent") }, 99 { N_("Start"), GTK_STOCK_EXECUTE, ACTF_WHEREVER | ACTF_INACTIVE, 100 N_("Start a torrent that is not running") }, 101 { N_("Stop"), GTK_STOCK_STOP, ACTF_WHEREVER | ACTF_ACTIVE, 102 N_("Stop a torrent that is running") }, 103 { N_("Remove"), GTK_STOCK_REMOVE, ACTF_WHEREVER | ACTF_WHATEVER, 104 N_("Remove a torrent") }, 105 { N_("Properties"), GTK_STOCK_PROPERTIES, ACTF_WHEREVER | ACTF_WHATEVER, 106 N_("Show additional information about a torrent") }, 107 { N_("Preferences"), GTK_STOCK_PREFERENCES, ACTF_WHEREVER | ACTF_ALWAYS, 108 N_("Customize application behavior") }, 109 { N_("Open debug window"), NULL, ACTF_MENU | ACTF_ALWAYS, 110 NULL }, 111 }; 112 113 #define CBDATA_PTR "callback-data-pointer" 114 115 #define SIGCOUNT_MAX 3 116 117 static sig_atomic_t global_sigcount = 0; 118 119 static GList * 80 120 readargs(int argc, char **argv); 81 121 82 void83 makewind( GtkWidget*wind, TrBackend *back, benc_val_t *state, GList *args);84 void122 static void 123 makewind(TrWindow *wind, TrBackend *back, benc_val_t *state, GList *args); 124 static void 85 125 quittransmission(struct cbdata *data); 86 GtkWidget * 87 makewind_toolbar(struct cbdata *data); 88 GtkWidget * 89 makewind_list(struct cbdata *data, GObject **sizehack); 90 gboolean 126 static gboolean 91 127 winclose(GtkWidget *widget, GdkEvent *event, gpointer gdata); 92 gboolean128 static gboolean 93 129 exitcheck(gpointer gdata); 94 void130 static void 95 131 setupdrag(GtkWidget *widget, struct cbdata *data); 96 void132 static void 97 133 gotdrag(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, 98 134 GtkSelectionData *sel, guint info, guint time, gpointer gdata); 99 static void 100 stylekludge(GObject *obj, GParamSpec *spec, gpointer gdata); 101 void 102 fixbuttons(GtkTreeSelection *sel, gpointer gdata); 103 void 104 dfname(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, 105 GtkTreeIter *iter, gpointer gdata); 106 void 107 dfprog(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, 108 GtkTreeIter *iter, gpointer gdata); 109 110 gboolean 135 136 static gboolean 111 137 updatemodel(gpointer gdata); 112 gboolean 113 listclick(GtkWidget *widget, GdkEventButton *event, gpointer gdata); 114 gboolean 115 listpopup(GtkWidget *widget, gpointer gdata); 116 void 117 dopopupmenu(GdkEventButton *event, struct cbdata *data); 118 void 138 static void 119 139 boolwindclosed(GtkWidget *widget SHUTUP, gpointer gdata); 120 void 121 actionclick(GtkWidget *widget, gpointer gdata); 122 gint 123 intrevcmp(gconstpointer a, gconstpointer b); 124 void 125 doubleclick(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, 126 gpointer gdata); 127 128 void 140 static void 141 windact(GtkWidget *widget, int action, gpointer gdata); 142 static void 143 handleaction(struct cbdata *data, enum action action); 144 145 static void 129 146 addtorrents(void *vdata, void *state, GList *files, 130 147 const char *dir, guint flags); 131 void148 static void 132 149 savetorrents(struct cbdata *data); 133 void 134 orstatus(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, 135 gpointer gdata); 136 void 137 istorsel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, 138 gpointer gdata); 139 void 150 static void 140 151 safepipe(void); 141 void152 static void 142 153 setupsighandlers(void); 143 void154 static void 144 155 fatalsig(int sig); 145 146 #define LIST_ACTION "torrent-list-action"147 enum listact {148 ACT_OPEN, ACT_START, ACT_STOP, ACT_DELETE, ACT_INFO, ACT_PREF, ACT_DEBUG };149 150 struct { const gchar *name; const gchar *id; enum listact act; gboolean nomenu;151 int avail; const char *ttext; const char *tpriv; }152 actionitems[] = {153 {N_("Add"), GTK_STOCK_ADD, ACT_OPEN, FALSE, 0,154 N_("Add a new torrent"), "XXX"},155 {N_("Start"), GTK_STOCK_EXECUTE, ACT_START, FALSE,156 TR_STATUS_INACTIVE,157 N_("Start a torrent that is not running"), "XXX"},158 {N_("Stop"), GTK_STOCK_STOP, ACT_STOP, FALSE,159 TR_STATUS_ACTIVE,160 N_("Stop a torrent that is running"), "XXX"},161 {N_("Remove"), GTK_STOCK_REMOVE, ACT_DELETE, FALSE, ~0,162 N_("Remove a torrent"), "XXX"},163 {N_("Properties"), GTK_STOCK_PROPERTIES, ACT_INFO, FALSE, ~0,164 N_("Show additional information about a torrent"), "XXX"},165 {N_("Preferences"), GTK_STOCK_PREFERENCES, ACT_PREF, TRUE, 0,166 N_("Customize application behavior"), "XXX"},167 {N_("Open debug window"), NULL, ACT_DEBUG, FALSE, 0, NULL, NULL},168 };169 170 #define CBDATA_PTR "callback-data-pointer"171 172 #define SIGCOUNT_MAX 3173 174 static sig_atomic_t global_sigcount = 0;175 156 176 157 int … … 225 206 226 207 /* create main window now so any error dialogs can be it's children */ 227 mainwind = gtk_window_new(GTK_WINDOW_TOPLEVEL);208 mainwind = tr_window_new(); 228 209 preferr = NULL; 229 210 stateerr = NULL; … … 248 229 applyprefs(back); 249 230 250 makewind( mainwind, back, state, argfiles);231 makewind( TR_WINDOW( mainwind ), back, state, argfiles ); 251 232 252 233 if(NULL != state) … … 307 288 } 308 289 309 void 310 makewind(GtkWidget *wind, TrBackend *back, benc_val_t *state, GList *args) { 311 GtkWidget *vbox = gtk_vbox_new(FALSE, 0); 312 GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); 313 GtkWidget *status = gtk_statusbar_new(); 314 struct cbdata *data = g_new0(struct cbdata, 1); 315 GtkWidget *list; 316 GtkRequisition req; 317 gint width, height; 318 GObject *sizehack; 319 GdkScreen *screen; 320 321 g_object_ref(G_OBJECT(back)); 322 data->back = back; 323 data->wind = GTK_WINDOW(wind); 324 data->timer = 0; 325 /* filled in by makewind_list */ 326 data->model = NULL; 327 data->view = NULL; 328 data->bar = GTK_STATUSBAR(status); 329 data->buttons = NULL; 330 data->prefsopen = FALSE; 331 data->msgwinopen = FALSE; 332 data->stupidpopuphack = NULL; 333 data->closing = FALSE; 334 335 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, 336 GTK_POLICY_ALWAYS); 337 338 gtk_box_pack_start(GTK_BOX(vbox), makewind_toolbar(data), FALSE, FALSE, 0); 339 340 sizehack = NULL; 341 list = makewind_list(data, &sizehack); 342 gtk_container_add(GTK_CONTAINER(scroll), list); 343 gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0); 344 345 gtk_statusbar_push(GTK_STATUSBAR(status), 0, ""); 346 gtk_box_pack_start(GTK_BOX(vbox), status, FALSE, FALSE, 0); 347 348 gtk_container_set_focus_child(GTK_CONTAINER(vbox), scroll); 349 gtk_container_add(GTK_CONTAINER(wind), vbox); 350 gtk_window_set_title(data->wind, g_get_application_name()); 351 g_signal_connect(G_OBJECT(wind), "delete_event", G_CALLBACK(winclose), data); 352 353 setupdrag(list, data); 354 355 addtorrents(data, state, args, NULL, addactionflag(cf_getpref(PREF_ADDIPC))); 356 357 data->timer = g_timeout_add(UPDATE_INTERVAL, updatemodel, data); 358 updatemodel(data); 359 360 /* some evil magic to try to get a nice initial window size */ 361 gtk_widget_show_all(vbox); 362 gtk_widget_realize(wind); 363 gtk_widget_size_request(list, &req); 364 height = req.height; 365 gtk_widget_size_request(scroll, &req); 366 height -= req.height; 367 gtk_widget_size_request(wind, &req); 368 height += req.height; 369 screen = gtk_widget_get_screen(wind); 370 width = MIN(req.width, gdk_screen_get_width(screen) / 2); 371 height = MIN(height, gdk_screen_get_height(screen) / 5 * 4); 372 if(height > req.width) 373 height = MIN(height, width * 8 / 5); 374 else 375 height = MAX(height, width * 5 / 8); 376 height = (height > req.width ? 377 MIN(height, width * 8 / 5) : MAX(height, width * 5 / 8)); 378 g_object_set(sizehack, "ellipsize", PANGO_ELLIPSIZE_END, NULL); 379 gtk_widget_show_now(wind); 380 gtk_window_resize(GTK_WINDOW(wind), width, height); 381 382 /* set up the ipc socket now that we're ready to get torrents from it */ 383 ipc_socket_setup(GTK_WINDOW(wind), addtorrents, data); 384 } 385 386 void 387 quittransmission(struct cbdata *data) { 388 g_object_unref(G_OBJECT(data->back)); 389 gtk_widget_destroy(GTK_WIDGET(data->wind)); 390 if(0 < data->timer) 391 g_source_remove(data->timer); 392 if(NULL != data->stupidpopuphack) 393 gtk_widget_destroy(data->stupidpopuphack); 394 g_free(data->buttons); 395 g_free(data); 396 gtk_main_quit(); 397 } 398 399 GtkWidget * 400 makewind_toolbar(struct cbdata *data) { 401 GtkWidget *bar = gtk_toolbar_new(); 402 GtkToolItem *item; 403 unsigned int ii; 404 405 gtk_toolbar_set_tooltips(GTK_TOOLBAR(bar), TRUE); 406 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(bar), FALSE); 407 408 data->buttons = g_new(GtkWidget*, ALEN(actionitems)); 409 410 for(ii = 0; ii < ALEN(actionitems); ii++) { 411 if( NULL == actionitems[ii].id ) { 412 data->buttons[ii] = NULL; 413 continue; 414 } 415 item = gtk_tool_button_new_from_stock(actionitems[ii].id); 416 data->buttons[ii] = GTK_WIDGET(item); 417 gtk_tool_button_set_label(GTK_TOOL_BUTTON(item), 418 gettext(actionitems[ii].name)); 419 gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(item), GTK_TOOLBAR(bar)->tooltips, 420 gettext(actionitems[ii].ttext), 421 actionitems[ii].tpriv); 422 g_object_set_data(G_OBJECT(item), LIST_ACTION, 423 GINT_TO_POINTER(actionitems[ii].act)); 424 g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(actionclick), data); 425 gtk_toolbar_insert(GTK_TOOLBAR(bar), item, -1); 426 } 427 428 return bar; 429 } 430 431 /* XXX check for unused data in model */ 432 enum { 433 MC_NAME, MC_SIZE, MC_STAT, MC_ERR, MC_TERR, 434 MC_PROG, MC_DRATE, MC_URATE, MC_ETA, MC_PEERS, 435 MC_UPEERS, MC_DPEERS, MC_DOWN, MC_UP, 436 MC_TORRENT, MC_ROW_COUNT, 437 }; 438 439 GtkWidget * 440 makewind_list(struct cbdata *data, GObject **sizehack) { 290 static void 291 makewind( TrWindow * wind, TrBackend * back, benc_val_t * state, GList * args) 292 { 441 293 GType types[] = { 442 294 /* info->name, info->totalSize, status, error, errorString, */ … … 448 300 /* the torrent object */ 449 301 TR_TORRENT_TYPE}; 302 struct cbdata *data = g_new0(struct cbdata, 1); 450 303 GtkListStore *store; 451 GtkWidget *view; 452 GtkTreeViewColumn *col; 453 GtkTreeSelection *sel; 454 GtkCellRenderer *namerend, *progrend; 455 char *str; 304 unsigned int ii; 305 GtkWidget *drag; 456 306 457 307 g_assert(MC_ROW_COUNT == ALEN(types)); 458 459 308 store = gtk_list_store_newv(MC_ROW_COUNT, types); 460 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); 461 /* XXX do I need to worry about reference counts anywhere else? */ 462 g_object_unref(G_OBJECT(store)); 309 310 g_object_ref(G_OBJECT(back)); 311 data->back = back; 312 data->wind = GTK_WINDOW(wind); 313 data->timer = 0; 463 314 data->model = GTK_TREE_MODEL(store); 464 data->view = GTK_TREE_VIEW(view); 465 466 namerend = gtk_cell_renderer_text_new(); 467 *sizehack = G_OBJECT(namerend); 468 /* note that this renderer is set to ellipsize, just not here */ 469 col = gtk_tree_view_column_new_with_attributes(_("Name"), namerend, NULL); 470 gtk_tree_view_column_set_cell_data_func(col, namerend, dfname, NULL, NULL); 471 gtk_tree_view_column_set_expand(col, TRUE); 472 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE); 473 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); 474 475 progrend = tr_cell_renderer_progress_new(); 476 /* this string is only used to determing the size of the progress bar */ 477 str = g_markup_printf_escaped("<big>%s</big>", _(" fnord fnord ")); 478 g_object_set(progrend, "bar-sizing", str, NULL); 479 g_free(str); 480 col = gtk_tree_view_column_new_with_attributes(_("Progress"), progrend, NULL); 481 gtk_tree_view_column_set_cell_data_func(col, progrend, dfprog, NULL, NULL); 482 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE); 483 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); 484 485 /* XXX this shouldn't be necessary */ 486 g_signal_connect(view, "notify", G_CALLBACK(stylekludge), progrend); 487 488 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); 489 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); 490 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(sel), GTK_SELECTION_MULTIPLE); 491 g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(fixbuttons), data); 492 g_signal_connect(G_OBJECT(view), "button-press-event", 493 G_CALLBACK(listclick), data); 494 g_signal_connect(G_OBJECT(view), "popup-menu", G_CALLBACK(listpopup), data); 495 g_signal_connect(G_OBJECT(view), "row-activated", 496 G_CALLBACK(doubleclick), data); 497 gtk_widget_show_all(view); 498 499 return view; 315 data->prefsopen = FALSE; 316 data->msgwinopen = FALSE; 317 data->closing = FALSE; 318 319 g_assert( ACTION_COUNT == ALEN( actions ) ); 320 for( ii = 0; ii < ALEN( actions ); ii++ ) 321 { 322 tr_window_action_add( wind, ii, actions[ii].flags, 323 gettext( actions[ii].label ), 324 actions[ii].icon, 325 gettext( actions[ii].tooltip ) ); 326 } 327 g_object_set( wind, "model", data->model, 328 "double-click-action", ACT_INFO, NULL); 329 330 g_signal_connect( wind, "action", G_CALLBACK( windact ), data ); 331 g_signal_connect( wind, "delete_event", G_CALLBACK( winclose ), data ); 332 333 g_object_get( wind, "drag-widget", &drag, NULL ); 334 setupdrag( drag, data ); 335 336 addtorrents(data, state, args, NULL, addactionflag(cf_getpref(PREF_ADDIPC))); 337 338 data->timer = g_timeout_add(UPDATE_INTERVAL, updatemodel, data); 339 updatemodel(data); 340 341 /* this shows the window */ 342 tr_window_size_hack( wind ); 343 344 /* set up the ipc socket now that we're ready to get torrents from it */ 345 ipc_socket_setup(GTK_WINDOW(wind), addtorrents, data); 346 } 347 348 static void 349 quittransmission( struct cbdata * data ) 350 { 351 g_object_unref( G_OBJECT( data->back ) ); 352 if( NULL != data->wind ) 353 { 354 gtk_widget_destroy( GTK_WIDGET( data->wind ) ); 355 } 356 g_object_unref( data->model ); 357 if( 0 < data->timer ) 358 { 359 g_source_remove( data->timer ); 360 } 361 g_free( data ); 362 gtk_main_quit(); 500 363 } 501 364 … … 504 367 struct cbdata *data = gdata; 505 368 struct exitdata *edata; 506 unsigned int ii;507 369 GtkTreeIter iter; 508 370 TrTorrent *tor; … … 518 380 Add a reference to all torrents in the list, which will be removed 519 381 when the politely-stopped signal is emitted. This is necessary 520 because a ctionclick() adds a reference when it removes a torrent521 from the model and calls tr_torrent_stop_polite()on it.382 because a reference is added when a torrent is removed 383 from the model and tr_torrent_stop_polite() is called on it. 522 384 */ 523 385 if(gtk_tree_model_get_iter_first(data->model, &iter)) { … … 541 403 /* yes, start the exit timer and disable widgets */ 542 404 edata->timer = g_timeout_add(EXIT_CHECK_INTERVAL, exitcheck, edata); 543 for(ii = 0; ii < ALEN(actionitems); ii++) 544 if( NULL != data->buttons[ii] ) 545 gtk_widget_set_sensitive(data->buttons[ii], FALSE); 546 gtk_widget_set_sensitive(GTK_WIDGET(data->view), FALSE); 405 gtk_widget_set_sensitive( GTK_WIDGET( data->wind ), FALSE ); 547 406 } 548 407 … … 576 435 } 577 436 578 void437 static void 579 438 gotdrag(GtkWidget *widget SHUTUP, GdkDragContext *dc, gint x SHUTUP, 580 439 gint y SHUTUP, GtkSelectionData *sel, guint info SHUTUP, guint time, … … 658 517 } 659 518 660 void519 static void 661 520 setupdrag(GtkWidget *widget, struct cbdata *data) { 662 521 GtkTargetEntry targets[] = { … … 670 529 gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL, targets, 671 530 ALEN(targets), GDK_ACTION_COPY | GDK_ACTION_MOVE); 672 }673 674 /* kludge to have the progress bars notice theme changes */675 static void676 stylekludge(GObject *obj, GParamSpec *spec, gpointer gdata) {677 if(0 == strcmp("style", spec->name)) {678 tr_cell_renderer_progress_reset_style(TR_CELL_RENDERER_PROGRESS(gdata));679 gtk_widget_queue_draw(GTK_WIDGET(obj));680 }681 }682 683 /* disable buttons the user shouldn't be able to click on */684 void685 fixbuttons(GtkTreeSelection *sel, gpointer gdata) {686 struct cbdata *data = gdata;687 gboolean selected;688 unsigned int ii;689 int status;690 691 if(NULL == sel)692 sel = gtk_tree_view_get_selection(data->view);693 status = 0;694 gtk_tree_selection_selected_foreach(sel, orstatus, &status);695 selected = (0 < gtk_tree_selection_count_selected_rows(sel));696 697 for(ii = 0; ii < ALEN(actionitems); ii++)698 if(actionitems[ii].avail)699 gtk_widget_set_sensitive(data->buttons[ii],700 (selected && (actionitems[ii].avail & status)));701 }702 703 void704 dfname(GtkTreeViewColumn *col SHUTUP, GtkCellRenderer *rend,705 GtkTreeModel *model, GtkTreeIter *iter, gpointer gdata SHUTUP) {706 char *name, *mb, *terr, *str, *top, *bottom, *timestr;707 guint64 size;708 gfloat prog;709 int status, err, eta, tpeers, upeers, dpeers;710 711 gtk_tree_model_get(model, iter, MC_NAME, &name, MC_STAT, &status,712 MC_ERR, &err, MC_SIZE, &size, MC_PROG, &prog, MC_ETA, &eta,713 MC_PEERS, &tpeers, MC_UPEERS, &upeers, MC_DPEERS, &dpeers, -1);714 715 if(0 > tpeers)716 tpeers = 0;717 if(0 > upeers)718 upeers = 0;719 if(0 > dpeers)720 dpeers = 0;721 mb = readablesize(size);722 prog *= 100;723 724 if(status & TR_STATUS_CHECK)725 top = g_strdup_printf(_("Checking existing files (%.1f%%)"), prog);726 else if(status & TR_STATUS_DOWNLOAD) {727 if(0 > eta)728 top = g_strdup_printf(_("Stalled (%.1f%%)"), prog);729 else {730 timestr = readabletime(eta);731 top = g_strdup_printf(_("Finishing in %s (%.1f%%)"), timestr, prog);732 g_free(timestr);733 }734 }735 else if(status & TR_STATUS_SEED)736 top = g_strdup_printf(ngettext("Seeding, uploading to %d of %d peer",737 "Seeding, uploading to %d of %d peers",738 tpeers), dpeers, tpeers);739 else if(status & TR_STATUS_STOPPING)740 top = g_strdup(_("Stopping..."));741 else if(status & TR_STATUS_PAUSE)742 top = g_strdup_printf(_("Stopped (%.1f%%)"), prog);743 else {744 top = g_strdup("");745 g_assert_not_reached();746 }747 748 if(TR_OK != err) {749 gtk_tree_model_get(model, iter, MC_TERR, &terr, -1);750 bottom = g_strconcat(_("Error: "), terr, NULL);751 g_free(terr);752 }753 else if(status & TR_STATUS_DOWNLOAD)754 bottom = g_strdup_printf(ngettext("Downloading from %i of %i peer",755 "Downloading from %i of %i peers",756 tpeers), upeers, tpeers);757 else758 bottom = NULL;759 760 str = g_markup_printf_escaped("<big>%s (%s)</big>\n<small>%s\n%s</small>",761 name, mb, top, (NULL == bottom ? "" : bottom));762 g_object_set(rend, "markup", str, NULL);763 g_free(name);764 g_free(mb);765 g_free(str);766 g_free(top);767 if(NULL != bottom)768 g_free(bottom);769 }770 771 void772 dfprog(GtkTreeViewColumn *col SHUTUP, GtkCellRenderer *rend,773 GtkTreeModel *model, GtkTreeIter *iter, gpointer gdata SHUTUP) {774 char *dlstr, *ulstr, *str, *marked;775 gfloat prog, dl, ul;776 guint64 down, up;777 778 gtk_tree_model_get(model, iter, MC_PROG, &prog, MC_DRATE, &dl, MC_URATE, &ul,779 MC_DOWN, &down, MC_UP, &up, -1);780 if(0.0 > prog)781 prog = 0.0;782 else if(1.0 < prog)783 prog = 1.0;784 785 ulstr = readablesize(ul * 1024.0);786 if(1.0 == prog) {787 dlstr = ratiostr(down, up);788 str = g_strdup_printf(_("Ratio: %s\nUL: %s/s"), dlstr, ulstr);789 } else {790 dlstr = readablesize(dl * 1024.0);791 str = g_strdup_printf(_("DL: %s/s\nUL: %s/s"), dlstr, ulstr);792 }793 marked = g_markup_printf_escaped("<small>%s</small>", str);794 g_object_set(rend, "markup", str, "progress", prog, NULL);795 g_free(dlstr);796 g_free(ulstr);797 g_free(str);798 g_free(marked);799 531 } 800 532 … … 807 539 GtkTreeIter iter; 808 540 float up, down; 809 char *upstr, *downstr, *str;810 541 811 542 if(0 < global_sigcount) { … … 831 562 } 832 563 833 /* update the status bar */ 834 tr_torrentRates(tr_backend_handle(data->back), &up, &down); 835 downstr = readablesize(down * 1024.0); 836 upstr = readablesize(up * 1024.0); 837 str = g_strdup_printf(_(" Total DL: %s/s Total UL: %s/s"), 838 upstr, downstr); 839 gtk_statusbar_pop(data->bar, 0); 840 gtk_statusbar_push(data->bar, 0, str); 841 g_free(str); 842 g_free(upstr); 843 g_free(downstr); 844 845 /* the status of the selected item may have changed, so update the buttons */ 846 fixbuttons(NULL, data); 564 /* update the main window's statusbar and toolbar buttons */ 565 tr_torrentRates( tr_backend_handle( data->back ), &down, &up ); 566 tr_window_update( TR_WINDOW(data->wind), down, up ); 847 567 848 568 /* check for politely stopped torrents unless we're exiting */ … … 856 576 } 857 577 858 /* show a popup menu for a right-click on the list */ 859 gboolean 860 listclick(GtkWidget *widget SHUTUP, GdkEventButton *event, gpointer gdata) { 861 struct cbdata *data = gdata; 862 GtkTreeSelection *sel = gtk_tree_view_get_selection(data->view); 863 GtkTreePath *path; 864 GtkTreeIter iter; 865 int status; 866 TrTorrent *tor, *issel; 867 868 if(GDK_BUTTON_PRESS == event->type && 3 == event->button) { 869 /* find what row, if any, the user clicked on */ 870 if(!gtk_tree_view_get_path_at_pos(data->view, event->x, event->y, &path, 871 NULL, NULL, NULL)) 872 gtk_tree_selection_unselect_all(sel); 873 else { 874 if(gtk_tree_model_get_iter(data->model, &iter, path)) { 875 /* get torrent and status for the right-clicked row */ 876 gtk_tree_model_get(data->model, &iter, MC_TORRENT, &tor, 877 MC_STAT, &status, -1); 878 issel = tor; 879 gtk_tree_selection_selected_foreach(sel, istorsel, &issel); 880 g_object_unref(tor); 881 /* if the clicked row isn't selected, select only it */ 882 if(NULL != issel) { 883 gtk_tree_selection_unselect_all(sel); 884 gtk_tree_selection_select_iter(sel, &iter); 885 } 886 } 887 gtk_tree_path_free(path); 888 } 889 dopopupmenu(event, data); 890 return TRUE; 891 } 892 893 return FALSE; 894 } 895 896 gboolean 897 listpopup(GtkWidget *widget SHUTUP, gpointer gdata) { 898 dopopupmenu(NULL, gdata); 899 return TRUE; 900 } 901 902 void 903 dopopupmenu(GdkEventButton *event, struct cbdata *data) { 904 GtkTreeSelection *sel = gtk_tree_view_get_selection(data->view); 905 int count = gtk_tree_selection_count_selected_rows(sel); 906 GtkWidget *menu = gtk_menu_new(); 907 GtkWidget *item; 908 unsigned int ii; 909 int status = 0; 910 911 if(NULL != data->stupidpopuphack) 912 gtk_widget_destroy(data->stupidpopuphack); 913 data->stupidpopuphack = menu; 914 915 status = 0; 916 gtk_tree_selection_selected_foreach(sel, orstatus, &status); 917 918 for(ii = 0; ii < ALEN(actionitems); ii++) { 919 if(actionitems[ii].nomenu || 920 (actionitems[ii].avail && 921 (0 == count || !(actionitems[ii].avail & status)))) 922 continue; 923 item = gtk_menu_item_new_with_label(gettext(actionitems[ii].name)); 924 /* set the action for the menu item */ 925 g_object_set_data(G_OBJECT(item), LIST_ACTION, 926 GINT_TO_POINTER(actionitems[ii].act)); 927 g_signal_connect(G_OBJECT(item), "activate", 928 G_CALLBACK(actionclick), data); 929 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 930 } 931 932 gtk_widget_show_all(menu); 933 934 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 935 (NULL == event ? 0 : event->button), 936 gdk_event_get_time((GdkEvent*)event)); 937 } 938 939 void 578 static void 940 579 boolwindclosed(GtkWidget *widget SHUTUP, gpointer gdata) { 941 580 gboolean *preachy_gcc = gdata; … … 944 583 } 945 584 946 void 947 actionclick(GtkWidget *widget, gpointer gdata) { 948 struct cbdata *data = gdata; 949 enum listact act; 585 static void 586 windact( GtkWidget * wind SHUTUP, int action, gpointer gdata ) 587 { 588 g_assert( 0 <= action ); 589 handleaction( gdata, action ); 590 } 591 592 static void 593 handleaction( struct cbdata * data, enum action act ) 594 { 950 595 GtkTreeSelection *sel; 951 596 GList *rows, *ii; … … 954 599 GtkTreeIter iter; 955 600 TrTorrent *tor; 956 unsigned int actoff,status;601 int status; 957 602 gboolean changed; 958 603 GtkWidget * win; 959 604 960 act = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), LIST_ACTION)); 961 962 switch(act) { 963 case ACT_OPEN: 964 makeaddwind(data->wind, addtorrents, data); 965 return; 966 case ACT_PREF: 967 if( !data->prefsopen ) { 968 data->prefsopen = TRUE; 969 win = makeprefwindow( data->wind, data->back ); 970 g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ), 971 &data->prefsopen ); 972 } 973 return; 974 case ACT_DEBUG: 975 if( !data->msgwinopen ) { 976 data->msgwinopen = TRUE; 977 win = msgwin_create(); 978 g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ), 979 &data->msgwinopen ); 980 } 981 return; 982 case ACT_START: 983 case ACT_STOP: 984 case ACT_DELETE: 985 case ACT_INFO: 986 break; 987 } 988 989 sel = gtk_tree_view_get_selection(data->view); 990 rows = gtk_tree_selection_get_selected_rows(sel, NULL); 991 605 g_assert( ACTION_COUNT > act ); 606 607 switch( act ) 608 { 609 case ACT_OPEN: 610 makeaddwind( data->wind, addtorrents, data ); 611 return; 612 case ACT_PREF: 613 if( !data->prefsopen ) 614 { 615 data->prefsopen = TRUE; 616 win = makeprefwindow( data->wind, data->back ); 617 g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ), 618 &data->prefsopen ); 619 } 620 return; 621 case ACT_DEBUG: 622 if( !data->msgwinopen ) 623 { 624 data->msgwinopen = TRUE; 625 win = msgwin_create(); 626 g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ), 627 &data->msgwinopen ); 628 } 629 return; 630 case ACT_START: 631 case ACT_STOP: 632 case ACT_DELETE: 633 case ACT_INFO: 634 case ACTION_COUNT: 635 break; 636 } 637 638 /* get a list of references to selected rows */ 639 g_object_get( data->wind, "selection", &sel, NULL ); 640 rows = gtk_tree_selection_get_selected_rows( sel, NULL ); 992 641 for(ii = rows; NULL != ii; ii = ii->next) { 993 642 ref = gtk_tree_row_reference_new(data->model, ii->data); … … 995 644 ii->data = ref; 996 645 } 997 998 for(actoff = 0; actoff < ALEN(actionitems); actoff++)999 if(actionitems[actoff].act == act)1000 break;1001 g_assert(actoff < ALEN(actionitems));1002 646 1003 647 changed = FALSE; … … 1007 651 gtk_tree_model_get(data->model, &iter, MC_TORRENT, &tor, 1008 652 MC_STAT, &status, -1); 1009 /* check if this action is valid for this torrent */ 1010 if((!actionitems[actoff].avail || actionitems[actoff].avail & status) && 1011 !actionitems[actoff].nomenu) { 1012 switch(act) { 1013 case ACT_START: 1014 tr_torrentStart(tr_torrent_handle(tor)); 1015 changed = TRUE; 1016 break; 1017 case ACT_STOP: 1018 tr_torrentStop(tr_torrent_handle(tor)); 1019 changed = TRUE; 1020 break; 1021 case ACT_DELETE: 1022 /* tor will be unref'd in the politely_stopped signal handler */ 1023 g_object_ref(tor); 1024 tr_torrent_stop_politely(tor); 1025 if(TR_FLAG_SAVE & tr_torrent_info(tor)->flags) 1026 tr_torrentRemoveSaved(tr_torrent_handle(tor)); 1027 gtk_list_store_remove(GTK_LIST_STORE(data->model), &iter); 1028 changed = TRUE; 1029 break; 1030 case ACT_INFO: 1031 makeinfowind(data->wind, tor); 1032 break; 1033 case ACT_OPEN: 1034 case ACT_PREF: 1035 case ACT_DEBUG: 1036 break; 1037 } 653 if( ACT_ISAVAIL( actions[act].flags, status ) ) 654 655 { 656 switch( act ) 657 { 658 case ACT_START: 659 tr_torrentStart( tr_torrent_handle( tor ) ); 660 changed = TRUE; 661 break; 662 case ACT_STOP: 663 tr_torrentStop( tr_torrent_handle( tor ) ); 664 changed = TRUE; 665 break; 666 case ACT_DELETE: 667 /* tor will be unref'd in the politely_stopped handler */ 668 g_object_ref( tor ); 669 tr_torrent_stop_politely( tor ); 670 if( TR_FLAG_SAVE & tr_torrent_info( tor )->flags ) 671 { 672 tr_torrentRemoveSaved( tr_torrent_handle( tor ) ); 673 } 674 gtk_list_store_remove( GTK_LIST_STORE( data->model ), 675 &iter ); 676 changed = TRUE; 677 break; 678 case ACT_INFO: 679 makeinfowind( data->wind, tor ); 680 break; 681 case ACT_OPEN: 682 case ACT_PREF: 683 case ACT_DEBUG: 684 case ACTION_COUNT: 685 break; 686 } 1038 687 } 1039 688 g_object_unref(tor); … … 1048 697 savetorrents(data); 1049 698 updatemodel(data); 1050 }1051 }1052 1053 gint1054 intrevcmp(gconstpointer a, gconstpointer b) {1055 int aint = GPOINTER_TO_INT(a);1056 int bint = GPOINTER_TO_INT(b);1057 1058 if(bint > aint)1059 return 1;1060 else if(bint < aint)1061 return -1;1062 else1063 return 0;1064 }1065 1066 void1067 doubleclick(GtkWidget *widget SHUTUP, GtkTreePath *path,1068 GtkTreeViewColumn *col SHUTUP, gpointer gdata) {1069 struct cbdata *data = gdata;1070 GtkTreeIter iter;1071 TrTorrent *tor;1072 1073 if(gtk_tree_model_get_iter(data->model, &iter, path)) {1074 gtk_tree_model_get(data->model, &iter, MC_TORRENT, &tor, -1);1075 makeinfowind(data->wind, tor);1076 g_object_unref(tor);1077 699 } 1078 700 } … … 1101 723 } 1102 724 1103 void725 static void 1104 726 addtorrents(void *vdata, void *state, GList *files, 1105 727 const char *dir, guint flags) { … … 1166 788 } 1167 789 1168 void 1169 savetorrents(struct cbdata *data) { 1170 char *errstr; 1171 1172 tr_backend_save_state(data->back, &errstr); 1173 if(NULL != errstr) { 1174 errmsg(data->wind, "%s", errstr); 1175 g_free(errstr); 1176 } 1177 } 1178 1179 /* use with gtk_tree_selection_selected_foreach to | status of selected rows */ 1180 void 1181 orstatus(GtkTreeModel *model, GtkTreePath *path SHUTUP, GtkTreeIter *iter, 1182 gpointer gdata) { 1183 int *allstatus = gdata; 1184 int status; 1185 1186 gtk_tree_model_get(model, iter, MC_STAT, &status, -1); 1187 *allstatus |= status; 1188 } 1189 1190 /* data should be a TrTorrent**, will set torrent to NULL if it's selected */ 1191 void 1192 istorsel(GtkTreeModel *model, GtkTreePath *path SHUTUP, GtkTreeIter *iter, 1193 gpointer gdata) { 1194 TrTorrent **torref = gdata; 1195 TrTorrent *tor; 1196 1197 if(NULL != *torref) { 1198 gtk_tree_model_get(model, iter, MC_TORRENT, &tor, -1); 1199 if(tor == *torref) 1200 *torref = NULL; 1201 g_object_unref(tor); 1202 } 1203 } 1204 1205 void 790 static void 791 savetorrents( struct cbdata *data ) 792 { 793 char * errstr; 794 795 tr_backend_save_state( data->back, &errstr ); 796 if( NULL != errstr ) 797 { 798 errmsg( data->wind, "%s", errstr ); 799 g_free( errstr ); 800 } 801 } 802 803 static void 1206 804 safepipe(void) { 1207 805 struct sigaction sa; … … 1212 810 } 1213 811 1214 void812 static void 1215 813 setupsighandlers(void) { 1216 814 int sigs[] = {SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2}; … … 1224 822 } 1225 823 1226 void824 static void 1227 825 fatalsig(int sig) { 1228 826 struct sigaction sa; -
trunk/gtk/tr_cell_renderer_progress.c
r1473 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2006 Transmission authors and contributors4 * Copyright (c) 2006-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a … … 78 78 }; 79 79 type = g_type_register_static(GTK_TYPE_CELL_RENDERER, 80 "TrCellRendererProgress Type", &info, 0);80 "TrCellRendererProgress", &info, 0); 81 81 } 82 82 return type; -
trunk/gtk/tr_cell_renderer_progress.h
r1473 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2006 Transmission authors and contributors4 * Copyright (c) 2006-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a -
trunk/gtk/tr_torrent.c
r1440 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2006 Transmission authors and contributors4 * Copyright (c) 2006-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a … … 79 79 NULL, 80 80 }; 81 type = g_type_register_static(G_TYPE_OBJECT, "TrTorrent Type", &info, 0);81 type = g_type_register_static(G_TYPE_OBJECT, "TrTorrent", &info, 0); 82 82 } 83 83 return type; -
trunk/gtk/util.h
r1468 r1475 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2005-200 6Transmission authors and contributors4 * Copyright (c) 2005-2007 Transmission authors and contributors 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a -
trunk/mk/gtk.mk
r1470 r1475 5 5 6 6 SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c tr_backend.c tr_torrent.c \ 7 tr_cell_renderer_progress.c util.c7 tr_cell_renderer_progress.c tr_window.c util.c 8 8 OBJS = $(SRCS:%.c=%.o) 9 9
Note: See TracChangeset
for help on using the changeset viewer.