Merge gtkmisc branch.
This commit is contained in:
parent
c7e9f024e0
commit
4943058f72
12
gtk/conf.c
12
gtk/conf.c
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2005-2006 Transmission authors and contributors
|
||||
* Copyright (c) 2005-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -500,7 +500,11 @@ cf_savestate(benc_val_t *state, char **errstr) {
|
|||
}
|
||||
|
||||
void
|
||||
cf_freestate(benc_val_t *state) {
|
||||
tr_bencFree(state);
|
||||
g_free(state);
|
||||
cf_freestate( benc_val_t * state )
|
||||
{
|
||||
if( NULL != state )
|
||||
{
|
||||
tr_bencFree( state );
|
||||
g_free( state );
|
||||
}
|
||||
}
|
||||
|
|
13
gtk/conf.h
13
gtk/conf.h
|
@ -49,17 +49,4 @@ cf_savestate(benc_val_t *state, char **errstr);
|
|||
void
|
||||
cf_freestate(benc_val_t *state);
|
||||
|
||||
/* macros for names of prefs we use */
|
||||
#define PREF_PORT "listening-port"
|
||||
#define PREF_USEDOWNLIMIT "use-download-limit"
|
||||
#define PREF_DOWNLIMIT "download-limit"
|
||||
#define PREF_USEUPLIMIT "use-upload-limit"
|
||||
#define PREF_UPLIMIT "upload-limit"
|
||||
#define PREF_DIR "download-directory"
|
||||
#define PREF_ASKDIR "ask-download-directory"
|
||||
#define PREF_ADDSTD "add-behavior-standard"
|
||||
#define PREF_ADDIPC "add-behavior-ipc"
|
||||
#define PREF_MSGLEVEL "message-level"
|
||||
#define PREF_NAT "use-nat-traversal"
|
||||
|
||||
#endif /* TG_CONF_H */
|
||||
|
|
478
gtk/dialogs.c
478
gtk/dialogs.c
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2005-2006 Transmission authors and contributors
|
||||
* Copyright (c) 2005-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -31,26 +31,14 @@
|
|||
|
||||
#include "conf.h"
|
||||
#include "dialogs.h"
|
||||
#include "transmission.h"
|
||||
#include "tr_icon.h"
|
||||
#include "tr_prefs.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#define PREFNAME "transmission-dialog-pref-name"
|
||||
|
||||
/* default values for a couple prefs */
|
||||
#define DEF_DOWNLIMIT 100
|
||||
#define DEF_USEDOWNLIMIT FALSE
|
||||
#define DEF_UPLIMIT 20
|
||||
#define DEF_USEUPLIMIT TRUE
|
||||
#define DEF_ASKDIR FALSE
|
||||
#define DEF_NAT TRUE
|
||||
|
||||
struct prefdata {
|
||||
GList *prefwidgets;
|
||||
GtkWindow *parent;
|
||||
TrBackend *back;
|
||||
GtkTooltips * tips;
|
||||
};
|
||||
|
||||
struct addcb {
|
||||
add_torrents_func_t addfunc;
|
||||
void *data;
|
||||
|
@ -68,12 +56,12 @@ struct dirdata
|
|||
guint flags;
|
||||
};
|
||||
|
||||
static void
|
||||
clicklimitbox(GtkWidget *widget, gpointer gdata);
|
||||
static void
|
||||
freedata(gpointer gdata, GClosure *closure);
|
||||
static void
|
||||
clickdialog(GtkWidget *widget, int resp, gpointer gdata);
|
||||
struct quitdata
|
||||
{
|
||||
callbackfunc_t func;
|
||||
void * cbdata;
|
||||
};
|
||||
|
||||
static void
|
||||
autoclick(GtkWidget *widget, gpointer gdata);
|
||||
static void
|
||||
|
@ -82,401 +70,8 @@ static void
|
|||
addresp(GtkWidget *widget, gint resp, gpointer gdata);
|
||||
static void
|
||||
promptresp( GtkWidget * widget, gint resp, gpointer data );
|
||||
|
||||
static void
|
||||
setupprefwidget(GtkWidget *widget, const char *prefname, ...) {
|
||||
const char *pref = cf_getpref(prefname);
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
guint prefsflag, modelflag;
|
||||
va_list ap;
|
||||
|
||||
g_object_set_data_full(G_OBJECT(widget), PREFNAME,
|
||||
g_strdup(prefname), (GDestroyNotify)g_free);
|
||||
|
||||
va_start(ap, prefname);
|
||||
|
||||
if(ISA(widget, GTK_TYPE_FILE_CHOOSER)) {
|
||||
if(NULL != pref)
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widget), pref);
|
||||
}
|
||||
else if(ISA(widget, GTK_TYPE_SPIN_BUTTON))
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
|
||||
(NULL == pref ? va_arg(ap, long) : strtol(pref, NULL, 10)));
|
||||
else if(ISA(widget, GTK_TYPE_TOGGLE_BUTTON))
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
|
||||
(NULL == pref ? va_arg(ap, gboolean) : strbool(pref)));
|
||||
else if(ISA(widget, GTK_TYPE_COMBO_BOX)) {
|
||||
model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
|
||||
prefsflag = addactionflag(pref);
|
||||
if(gtk_tree_model_get_iter_first(model, &iter))
|
||||
do {
|
||||
gtk_tree_model_get(model, &iter, 1, &modelflag, -1);
|
||||
if(modelflag == prefsflag) {
|
||||
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(widget), &iter);
|
||||
break;
|
||||
}
|
||||
} while(gtk_tree_model_iter_next(model, &iter));
|
||||
}
|
||||
else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
saveprefwidget(GtkWindow *parent, GtkWidget *widget) {
|
||||
char *prefname;
|
||||
const char *strval;
|
||||
char *freeablestr;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
guint uintval;
|
||||
|
||||
strval = NULL;
|
||||
freeablestr = NULL;
|
||||
if(ISA(widget, GTK_TYPE_FILE_CHOOSER)) {
|
||||
strval = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
|
||||
if(NULL != strval) {
|
||||
if(!mkdir_p(strval, 0777)) {
|
||||
errmsg(parent, _("Failed to create the directory %s:\n%s"),
|
||||
strval, strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ISA(widget, GTK_TYPE_SPIN_BUTTON))
|
||||
freeablestr = g_strdup_printf("%i",
|
||||
gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
|
||||
else if(ISA(widget, GTK_TYPE_TOGGLE_BUTTON))
|
||||
strval = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) ?
|
||||
"yes" : "no");
|
||||
else if(ISA(widget, GTK_TYPE_COMBO_BOX)) {
|
||||
if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter)) {
|
||||
model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
|
||||
gtk_tree_model_get(model, &iter, 1, &uintval, -1);
|
||||
strval = addactionname(uintval);
|
||||
}
|
||||
}
|
||||
else {
|
||||
g_assert_not_reached();
|
||||
return;
|
||||
}
|
||||
|
||||
prefname = g_object_get_data(G_OBJECT(widget), PREFNAME);
|
||||
g_assert(NULL != prefname);
|
||||
|
||||
if(NULL != strval)
|
||||
cf_setpref(prefname, strval);
|
||||
else if(NULL != freeablestr) {
|
||||
cf_setpref(prefname, freeablestr);
|
||||
g_free(freeablestr);
|
||||
}
|
||||
}
|
||||
|
||||
/* wrap a widget in an event box with a tooltip */
|
||||
static GtkWidget *
|
||||
tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip )
|
||||
{
|
||||
GtkWidget * box;
|
||||
|
||||
box = gtk_event_box_new();
|
||||
gtk_container_add( GTK_CONTAINER( box ), widget );
|
||||
gtk_tooltips_set_tip( tips, box, tip, "" );
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
makeprefwindow(GtkWindow *parent, TrBackend *back) {
|
||||
char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name());
|
||||
GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
|
||||
GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
|
||||
const unsigned int rowcount = 10;
|
||||
GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
|
||||
GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
|
||||
GtkWidget *natcheck = gtk_check_button_new_with_mnemonic(
|
||||
_("Au_tomatic port mapping via NAT-PMP or UPnP"));
|
||||
GtkWidget *askdir = gtk_check_button_new_with_mnemonic(
|
||||
_("Al_ways prompt for download directory"));
|
||||
GtkWidget *dirstr = gtk_file_chooser_button_new(
|
||||
_("Choose a download directory"),
|
||||
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
||||
GtkWidget *addstd = gtk_combo_box_new();
|
||||
GtkWidget *addipc = gtk_combo_box_new();
|
||||
GtkWidget *label;
|
||||
GtkWidget **array;
|
||||
struct prefdata *data = g_new0(struct prefdata, 1);
|
||||
struct { GtkWidget *on; GtkWidget *num; GtkWidget *label; gboolean defuse;
|
||||
const char *usepref; const char *numpref; long def;
|
||||
const char *ontip; const char *numtip; } lim[] = {
|
||||
{ gtk_check_button_new_with_mnemonic(_("_Limit download speed")),
|
||||
gtk_spin_button_new_with_range(0, G_MAXLONG, 1),
|
||||
gtk_label_new_with_mnemonic(_("Maximum _download speed:")),
|
||||
DEF_USEDOWNLIMIT, PREF_USEDOWNLIMIT, PREF_DOWNLIMIT, DEF_DOWNLIMIT,
|
||||
N_("Restrict the download rate"),
|
||||
N_("Speed in KiB/sec for restricted download rate")},
|
||||
{ gtk_check_button_new_with_mnemonic(_("Li_mit upload speed")),
|
||||
gtk_spin_button_new_with_range(0, G_MAXLONG, 1),
|
||||
gtk_label_new_with_mnemonic(_("Maximum _upload speed:")),
|
||||
DEF_USEUPLIMIT, PREF_USEUPLIMIT, PREF_UPLIMIT, DEF_UPLIMIT,
|
||||
N_("Restrict the upload rate"),
|
||||
N_("Speed in KiB/sec for restricted upload rate")},
|
||||
};
|
||||
unsigned int ii;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GtkCellRenderer *rend;
|
||||
gboolean boolval;
|
||||
int intval;
|
||||
GtkTooltips * tips;
|
||||
GtkWidget * event;
|
||||
|
||||
g_free(title);
|
||||
gtk_widget_set_name(wind, "TransmissionDialog");
|
||||
gtk_table_set_col_spacings(GTK_TABLE(table), 8);
|
||||
gtk_table_set_row_spacings(GTK_TABLE(table), 8);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_OK);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(table), 6);
|
||||
gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
|
||||
|
||||
tips = gtk_tooltips_new();
|
||||
g_object_ref( tips );
|
||||
gtk_object_sink( GTK_OBJECT( tips ) );
|
||||
gtk_tooltips_enable( tips );
|
||||
|
||||
data->prefwidgets = makeglist(portnum, lim[0].on, lim[0].num, lim[1].on,
|
||||
lim[1].num, askdir, dirstr, addstd, addipc, natcheck, NULL);
|
||||
data->parent = parent;
|
||||
data->back = back;
|
||||
data->tips = tips;
|
||||
g_object_ref(G_OBJECT(back));
|
||||
|
||||
#define RN(n) (n), (n) + 1
|
||||
|
||||
for(ii = 0; ii < ALEN(lim); ii++) {
|
||||
/* limit checkbox */
|
||||
setupprefwidget(lim[ii].on, lim[ii].usepref, (gboolean)lim[ii].defuse);
|
||||
array = g_new(GtkWidget*, 3);
|
||||
g_signal_connect_data(lim[ii].on, "clicked", G_CALLBACK(clicklimitbox),
|
||||
array, (GClosureNotify)g_free, 0);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].on, 0, 2, RN(ii*2));
|
||||
gtk_tooltips_set_tip( tips, lim[ii].on, gettext( lim[ii].ontip ), "" );
|
||||
|
||||
/* limit label and entry */
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(lim[ii].label), lim[ii].num);
|
||||
gtk_misc_set_alignment(GTK_MISC(lim[ii].label), 0, .5);
|
||||
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(lim[ii].num), TRUE);
|
||||
setupprefwidget(lim[ii].num, lim[ii].numpref, (long)lim[ii].def);
|
||||
event = tipbox( lim[ii].label, tips, gettext( lim[ii].numtip ) );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 0,1,RN(ii*2+1));
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].num, 1,2,RN(ii*2+1));
|
||||
array[0] = lim[ii].label;
|
||||
array[1] = lim[ii].num;
|
||||
array[2] = GINT_TO_POINTER( TRUE );
|
||||
clicklimitbox(lim[ii].on, array);
|
||||
gtk_tooltips_set_tip( tips, lim[ii].num, gettext( lim[ii].numtip ), "" );
|
||||
}
|
||||
ii *= 2;
|
||||
|
||||
/* always ask for download dir */
|
||||
setupprefwidget( askdir, PREF_ASKDIR, ( gboolean )DEF_ASKDIR );
|
||||
array = g_new( GtkWidget *, 3 );
|
||||
g_signal_connect_data( askdir, "clicked", G_CALLBACK( clicklimitbox ),
|
||||
array, ( GClosureNotify )g_free, 0 );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), askdir, 0, 2, RN(ii));
|
||||
gtk_tooltips_set_tip( tips, askdir,
|
||||
_("When adding a torrent, always prompt for a directory to download data files into"), "" );
|
||||
ii++;
|
||||
|
||||
/* directory label and chooser */
|
||||
label = gtk_label_new_with_mnemonic(_("Download di_rectory:"));
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(label), dirstr);
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
||||
setupprefwidget(dirstr, PREF_DIR);
|
||||
event = tipbox( label, tips,
|
||||
_("Destination directory for downloaded data files") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 0, 1, RN(ii));
|
||||
event = tipbox( dirstr, tips,
|
||||
_("Destination directory for downloaded data files") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 1, 2, RN(ii));
|
||||
array[0] = label;
|
||||
array[1] = dirstr;
|
||||
array[2] = GINT_TO_POINTER( FALSE );
|
||||
clicklimitbox( askdir, array );
|
||||
ii++;
|
||||
|
||||
/* port label and entry */
|
||||
label = gtk_label_new_with_mnemonic(_("Listening _port:"));
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(label), portnum);
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
||||
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(portnum), TRUE);
|
||||
setupprefwidget(portnum, PREF_PORT, (long)TR_DEFAULT_PORT);
|
||||
event = tipbox( label, tips,
|
||||
_("TCP port number to listen for peer connections") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 0, 1, RN(ii));
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), portnum, 1, 2, RN(ii));
|
||||
gtk_tooltips_set_tip( tips, portnum,
|
||||
_("TCP port number to listen for peer connections"), "" );
|
||||
ii++;
|
||||
|
||||
/* NAT traversal checkbox */
|
||||
intval = tr_handleStatus(tr_backend_handle(back))->natTraversalStatus;
|
||||
boolval = !TR_NAT_TRAVERSAL_IS_DISABLED( intval );
|
||||
setupprefwidget(natcheck, PREF_NAT, boolval);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), natcheck, 0, 2, RN(ii));
|
||||
gtk_tooltips_set_tip( tips, natcheck,
|
||||
_("Attempt to bypass NAT or firewall to allow incoming peer connections"), "" );
|
||||
ii++;
|
||||
|
||||
/* create the model used by the two popup menus */
|
||||
model = GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT));
|
||||
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, 0, 0,
|
||||
_("Use the torrent file where it is"), -1);
|
||||
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, TR_TORNEW_SAVE_COPY, 0,
|
||||
_("Keep a copy of the torrent file"), -1);
|
||||
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, TR_TORNEW_SAVE_MOVE, 0,
|
||||
_("Keep a copy and remove the original"), -1);
|
||||
|
||||
/* std */
|
||||
label = gtk_label_new_with_mnemonic(_("For torrents added _normally:"));
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(label), addstd);
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
||||
gtk_combo_box_set_model(GTK_COMBO_BOX(addstd), model);
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(addstd), rend, TRUE);
|
||||
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(addstd), rend, "text", 0);
|
||||
setupprefwidget(addstd, PREF_ADDSTD);
|
||||
event = tipbox( label, tips,
|
||||
_("Torrent files added via the toolbar, popup menu, and drag-and-drop") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 0, 1, RN(ii));
|
||||
event = tipbox( addstd, tips,
|
||||
_("Torrent files added via the toolbar, popup menu, and drag-and-drop") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 1, 2, RN(ii));
|
||||
ii++;
|
||||
|
||||
/* ipc */
|
||||
label = gtk_label_new_with_mnemonic(
|
||||
_("For torrents added e_xternally\n(via the command-line):"));
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(label), addipc);
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
||||
gtk_combo_box_set_model(GTK_COMBO_BOX(addipc), model);
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(addipc), rend, TRUE);
|
||||
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(addipc), rend, "text", 0);
|
||||
setupprefwidget(addipc, PREF_ADDIPC);
|
||||
event = tipbox( label, tips,
|
||||
_("For torrents added via the command-line only") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 0, 1, RN(ii));
|
||||
event = tipbox( addipc, tips,
|
||||
_("For torrents added via the command-line only") );
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), event, 1, 2, RN(ii));
|
||||
ii++;
|
||||
|
||||
#undef RN
|
||||
g_assert(rowcount == ii);
|
||||
|
||||
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
|
||||
g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog),
|
||||
data, freedata, 0);
|
||||
gtk_widget_show_all(wind);
|
||||
|
||||
return wind;
|
||||
}
|
||||
|
||||
static void
|
||||
clicklimitbox( GtkWidget * widget, gpointer gdata )
|
||||
{
|
||||
GtkWidget ** widgets;
|
||||
gboolean with, active;
|
||||
int ii;
|
||||
|
||||
widgets = gdata;
|
||||
with = ( gboolean )GPOINTER_TO_INT( widgets[2] );
|
||||
|
||||
for(ii = 0; 2 > ii; ii++)
|
||||
{
|
||||
active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( widget ) );
|
||||
gtk_widget_set_sensitive( widgets[ii], ( with ? active : !active ) );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
freedata(gpointer gdata, GClosure *closure SHUTUP) {
|
||||
struct prefdata *data = gdata;
|
||||
|
||||
g_list_free(data->prefwidgets);
|
||||
g_object_unref(G_OBJECT(data->back));
|
||||
g_object_unref( data->tips );
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void
|
||||
clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
|
||||
struct prefdata *data = gdata;
|
||||
char *errstr;
|
||||
GList *ii;
|
||||
|
||||
if(GTK_RESPONSE_APPLY == resp || GTK_RESPONSE_OK == resp) {
|
||||
/* save all the prefs */
|
||||
for(ii = g_list_first(data->prefwidgets); NULL != ii; ii = ii->next)
|
||||
saveprefwidget(data->parent, ii->data);
|
||||
|
||||
/* write prefs to disk */
|
||||
cf_saveprefs(&errstr);
|
||||
if(NULL != errstr) {
|
||||
errmsg(data->parent, "%s", errstr);
|
||||
g_free(errstr);
|
||||
}
|
||||
|
||||
applyprefs(data->back);
|
||||
/* XXX would be nice to have errno strings, are they printed to stdout? */
|
||||
}
|
||||
|
||||
if(GTK_RESPONSE_APPLY != resp)
|
||||
gtk_widget_destroy(widget);
|
||||
}
|
||||
|
||||
void
|
||||
applyprefs(TrBackend *back) {
|
||||
struct { void (*func)(tr_handle_t*, int);
|
||||
const char *use; const char *num; gboolean defuse; long def; } lim[] = {
|
||||
{tr_setGlobalDownloadLimit, PREF_USEDOWNLIMIT, PREF_DOWNLIMIT,
|
||||
DEF_USEDOWNLIMIT, DEF_DOWNLIMIT},
|
||||
{tr_setGlobalUploadLimit, PREF_USEUPLIMIT, PREF_UPLIMIT,
|
||||
DEF_USEUPLIMIT, DEF_UPLIMIT},
|
||||
};
|
||||
const char *pref;
|
||||
int ii;
|
||||
tr_handle_t *tr = tr_backend_handle(back);
|
||||
gboolean boolval;
|
||||
|
||||
/* set upload and download limits */
|
||||
for(ii = 0; ii < (int)ALEN(lim); ii++) {
|
||||
pref = cf_getpref(lim[ii].use);
|
||||
if(!(NULL == pref ? lim[ii].defuse : strbool(pref)))
|
||||
lim[ii].func(tr, -1);
|
||||
else {
|
||||
pref = cf_getpref(lim[ii].num);
|
||||
lim[ii].func(tr, (NULL == pref ? lim[ii].def : strtol(pref, NULL, 10)));
|
||||
}
|
||||
}
|
||||
|
||||
/* set the listening port */
|
||||
if(NULL != (pref = cf_getpref(PREF_PORT)) &&
|
||||
0 < (ii = strtol(pref, NULL, 10)) && 0xffff >= ii)
|
||||
tr_setBindPort(tr, ii);
|
||||
|
||||
/* enable/disable NAT traversal */
|
||||
boolval = (NULL == (pref = cf_getpref(PREF_NAT)) ? DEF_NAT : strbool(pref));
|
||||
tr_natTraversalEnable(tr, boolval);
|
||||
}
|
||||
quitresp( GtkWidget * widget, gint resp, gpointer data );
|
||||
|
||||
void
|
||||
makeaddwind(GtkWindow *parent, add_torrents_func_t addfunc, void *cbdata) {
|
||||
|
@ -494,7 +89,6 @@ makeaddwind(GtkWindow *parent, add_torrents_func_t addfunc, void *cbdata) {
|
|||
GtkFileFilter *unfilter = gtk_file_filter_new();
|
||||
GtkWidget *getdir = gtk_file_chooser_button_new(
|
||||
_("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
||||
const char *pref;
|
||||
|
||||
data->addfunc = addfunc;
|
||||
data->data = cbdata;
|
||||
|
@ -511,8 +105,8 @@ makeaddwind(GtkWindow *parent, add_torrents_func_t addfunc, void *cbdata) {
|
|||
gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
|
||||
if(NULL != (pref = cf_getpref(PREF_DIR)))
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
|
||||
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( getdir ),
|
||||
getdownloaddir() );
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
|
||||
gtk_widget_set_sensitive(getdir, FALSE);
|
||||
|
@ -566,7 +160,7 @@ addresp(GtkWidget *widget, gint resp, gpointer gdata) {
|
|||
for(ii = files; NULL != ii; ii = ii->next)
|
||||
stupidgtk = g_list_append(stupidgtk, ii->data);
|
||||
flags = ( data->autostart ? TR_TORNEW_RUNNING : TR_TORNEW_PAUSED );
|
||||
flags |= addactionflag( cf_getpref( PREF_ADDSTD ) );
|
||||
flags |= addactionflag( tr_prefs_get( PREF_ID_ADDSTD ) );
|
||||
data->addfunc( data->data, NULL, stupidgtk, dir, flags );
|
||||
if(NULL != dir)
|
||||
g_free(dir);
|
||||
|
@ -693,7 +287,7 @@ makeinfowind(GtkWindow *parent, TrTorrent *tor) {
|
|||
|
||||
void
|
||||
promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
||||
GList * files, guint flags, const char * defaultdir )
|
||||
GList * files, guint flags )
|
||||
{
|
||||
struct dirdata * stuff;
|
||||
GtkWidget * wind;
|
||||
|
@ -711,7 +305,8 @@ promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
|||
NULL );
|
||||
gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( wind ), TRUE );
|
||||
gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( wind ), FALSE );
|
||||
gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ), defaultdir );
|
||||
gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ),
|
||||
getdownloaddir() );
|
||||
|
||||
g_signal_connect( G_OBJECT( wind ), "response",
|
||||
G_CALLBACK( promptresp ), stuff );
|
||||
|
@ -740,3 +335,40 @@ promptresp( GtkWidget * widget, gint resp, gpointer data )
|
|||
g_free( stuff );
|
||||
gtk_widget_destroy( widget );
|
||||
}
|
||||
|
||||
void
|
||||
askquit( GtkWindow * parent, callbackfunc_t func, void * cbdata )
|
||||
{
|
||||
struct quitdata * stuff;
|
||||
GtkWidget * wind;
|
||||
|
||||
stuff = g_new( struct quitdata, 1 );
|
||||
stuff->func = func;
|
||||
stuff->cbdata = cbdata;
|
||||
|
||||
wind = gtk_message_dialog_new( parent, GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
|
||||
_("Are you sure you want to quit %s?"),
|
||||
g_get_application_name() );
|
||||
gtk_dialog_set_default_response( GTK_DIALOG( wind ), GTK_RESPONSE_YES );
|
||||
g_signal_connect( G_OBJECT( wind ), "response",
|
||||
G_CALLBACK( quitresp ), stuff );
|
||||
|
||||
gtk_widget_show_all( wind );
|
||||
}
|
||||
|
||||
static void
|
||||
quitresp( GtkWidget * widget, gint resp, gpointer data )
|
||||
{
|
||||
struct quitdata * stuff;
|
||||
|
||||
stuff = data;
|
||||
|
||||
if( GTK_RESPONSE_YES == resp )
|
||||
{
|
||||
stuff->func( stuff->cbdata );
|
||||
}
|
||||
|
||||
g_free( stuff );
|
||||
gtk_widget_destroy( widget );
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ makeinfowind(GtkWindow *parent, TrTorrent *tor);
|
|||
/* prompt for a download directory for torrents, then add them */
|
||||
void
|
||||
promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
||||
GList * files, guint flags, const char * defaultdir );
|
||||
GList * files, guint flags );
|
||||
|
||||
/* prompt if the user wants to quit, calls func with cbdata if they do */
|
||||
void
|
||||
askquit( GtkWindow * parent, callbackfunc_t func, void * cbdata );
|
||||
|
||||
#endif /* TG_PREFS_H */
|
||||
|
|
138
gtk/ipc.c
138
gtk/ipc.c
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -40,6 +40,7 @@
|
|||
#include "conf.h"
|
||||
#include "io.h"
|
||||
#include "ipc.h"
|
||||
#include "tr_prefs.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PROTOVERS 1 /* IPC protocol version */
|
||||
|
@ -48,20 +49,26 @@
|
|||
#define MSG_VERSION ("version")
|
||||
/* list of strings, full paths to torrent files to load */
|
||||
#define MSG_ADDFILES ("addfiles")
|
||||
/* request that the server quit */
|
||||
#define MSG_QUIT ("quit")
|
||||
|
||||
enum contype { CON_SERV, CON_ADDFILE };
|
||||
enum contype { CON_SERV, CON_CLIENT };
|
||||
|
||||
struct constate_serv {
|
||||
void *wind;
|
||||
add_torrents_func_t addfunc;
|
||||
callbackfunc_t quitfunc;
|
||||
void *cbdata;
|
||||
};
|
||||
|
||||
struct constate_addfile {
|
||||
enum client_cmd { CCMD_ADD, CCMD_QUIT };
|
||||
|
||||
struct constate_client {
|
||||
GMainLoop *loop;
|
||||
enum client_cmd cmd;
|
||||
GList *files;
|
||||
gboolean *succeeded;
|
||||
unsigned int addid;
|
||||
unsigned int msgid;
|
||||
};
|
||||
|
||||
struct constate;
|
||||
|
@ -75,14 +82,10 @@ struct constate {
|
|||
enum contype type;
|
||||
union {
|
||||
struct constate_serv serv;
|
||||
struct constate_addfile addfile;
|
||||
struct constate_client client;
|
||||
} u;
|
||||
};
|
||||
|
||||
void
|
||||
ipc_socket_setup(void *parent, add_torrents_func_t addfunc, void *cbdata);
|
||||
gboolean
|
||||
ipc_sendfiles_blocking(GList *files);
|
||||
static void
|
||||
serv_bind(struct constate *con);
|
||||
static void
|
||||
|
@ -105,16 +108,19 @@ all_io_closed(GSource *source, void *vdata);
|
|||
static void
|
||||
srv_addfile(struct constate *con, const char *name, benc_val_t *val);
|
||||
static void
|
||||
srv_quit( struct constate * con, const char * name, benc_val_t * val );
|
||||
static void
|
||||
afc_version(struct constate *con, const char *name, benc_val_t *val);
|
||||
static void
|
||||
afc_io_sent(GSource *source, unsigned int id, void *vdata);
|
||||
|
||||
static const struct handlerdef gl_funcs_serv[] = {
|
||||
{MSG_ADDFILES, srv_addfile},
|
||||
{MSG_QUIT, srv_quit},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const struct handlerdef gl_funcs_addfile[] = {
|
||||
static const struct handlerdef gl_funcs_client[] = {
|
||||
{MSG_VERSION, afc_version},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
@ -123,7 +129,9 @@ static const struct handlerdef gl_funcs_addfile[] = {
|
|||
static char *gl_sockpath = NULL;
|
||||
|
||||
void
|
||||
ipc_socket_setup(void *parent, add_torrents_func_t addfunc, void *cbdata) {
|
||||
ipc_socket_setup( void * parent, add_torrents_func_t addfunc,
|
||||
callbackfunc_t quitfunc, void * cbdata )
|
||||
{
|
||||
struct constate *con;
|
||||
|
||||
con = g_new0(struct constate, 1);
|
||||
|
@ -133,13 +141,16 @@ ipc_socket_setup(void *parent, add_torrents_func_t addfunc, void *cbdata) {
|
|||
con->type = CON_SERV;
|
||||
con->u.serv.wind = parent;
|
||||
con->u.serv.addfunc = addfunc;
|
||||
con->u.serv.quitfunc = quitfunc;
|
||||
con->u.serv.cbdata = cbdata;
|
||||
|
||||
serv_bind(con);
|
||||
}
|
||||
|
||||
gboolean
|
||||
ipc_sendfiles_blocking(GList *files) {
|
||||
static gboolean
|
||||
blocking_client( enum client_cmd cmd, GList * files )
|
||||
{
|
||||
|
||||
struct constate *con;
|
||||
char *path;
|
||||
gboolean ret = FALSE;
|
||||
|
@ -147,12 +158,13 @@ ipc_sendfiles_blocking(GList *files) {
|
|||
con = g_new0(struct constate, 1);
|
||||
con->source = NULL;
|
||||
con->fd = -1;
|
||||
con->funcs = gl_funcs_addfile;
|
||||
con->type = CON_ADDFILE;
|
||||
con->u.addfile.loop = g_main_loop_new(NULL, TRUE);
|
||||
con->u.addfile.files = files;
|
||||
con->u.addfile.succeeded = &ret;
|
||||
con->u.addfile.addid = 0;
|
||||
con->funcs = gl_funcs_client;
|
||||
con->type = CON_CLIENT;
|
||||
con->u.client.loop = g_main_loop_new(NULL, TRUE);
|
||||
con->u.client.cmd = cmd;
|
||||
con->u.client.files = files;
|
||||
con->u.client.succeeded = &ret;
|
||||
con->u.client.msgid = 0;
|
||||
|
||||
path = cf_sockname();
|
||||
if(!client_connect(path, con)) {
|
||||
|
@ -161,11 +173,23 @@ ipc_sendfiles_blocking(GList *files) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
g_main_loop_run(con->u.addfile.loop);
|
||||
g_main_loop_run(con->u.client.loop);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ipc_sendfiles_blocking( GList * files )
|
||||
{
|
||||
return blocking_client( CCMD_ADD, files );
|
||||
}
|
||||
|
||||
gboolean
|
||||
ipc_sendquit_blocking( void )
|
||||
{
|
||||
return blocking_client( CCMD_QUIT, NULL );
|
||||
}
|
||||
|
||||
/* open a local socket for clients connections */
|
||||
static void
|
||||
serv_bind(struct constate *con) {
|
||||
|
@ -356,9 +380,9 @@ destroycon(struct constate *con) {
|
|||
switch(con->type) {
|
||||
case CON_SERV:
|
||||
break;
|
||||
case CON_ADDFILE:
|
||||
freestrlist(con->u.addfile.files);
|
||||
g_main_loop_quit(con->u.addfile.loop);
|
||||
case CON_CLIENT:
|
||||
freestrlist(con->u.client.files);
|
||||
g_main_loop_quit(con->u.client.loop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -375,6 +399,7 @@ srv_addfile(struct constate *con, const char *name SHUTUP, benc_val_t *val) {
|
|||
struct constate_serv *srv = &con->u.serv;
|
||||
GList *files;
|
||||
int ii;
|
||||
guint flags;
|
||||
|
||||
if(TYPE_LIST == val->type) {
|
||||
files = NULL;
|
||||
|
@ -383,47 +408,68 @@ srv_addfile(struct constate *con, const char *name SHUTUP, benc_val_t *val) {
|
|||
/* XXX somehow escape invalid utf-8 */
|
||||
g_utf8_validate(val->val.l.vals[ii].val.s.s, -1, NULL))
|
||||
files = g_list_append(files, val->val.l.vals[ii].val.s.s);
|
||||
srv->addfunc(srv->cbdata, NULL, files, NULL,
|
||||
addactionflag(cf_getpref(PREF_ADDIPC)));
|
||||
flags = addactionflag( tr_prefs_get( PREF_ID_ADDIPC ) );
|
||||
srv->addfunc( srv->cbdata, NULL, files, NULL, flags );
|
||||
g_list_free(files);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
srv_quit( struct constate * con, const char * name SHUTUP,
|
||||
benc_val_t * val SHUTUP )
|
||||
{
|
||||
struct constate_serv * srv;
|
||||
|
||||
srv = &con->u.serv;
|
||||
srv->quitfunc( srv->cbdata );
|
||||
}
|
||||
|
||||
static void
|
||||
afc_version(struct constate *con, const char *name SHUTUP, benc_val_t *val) {
|
||||
struct constate_addfile *afc = &con->u.addfile;
|
||||
struct constate_client *afc = &con->u.client;
|
||||
GList *file;
|
||||
benc_val_t list, *str;
|
||||
|
||||
if(TYPE_INT != val->type || PROTOVERS != val->val.i) {
|
||||
fprintf(stderr, _("bad IPC protocol version\n"));
|
||||
destroycon(con);
|
||||
} else {
|
||||
/* XXX handle getting a non-version tag, invalid data,
|
||||
or nothing (read timeout) */
|
||||
bzero(&list, sizeof(list));
|
||||
list.type = TYPE_LIST;
|
||||
list.val.l.alloc = g_list_length(afc->files);
|
||||
list.val.l.vals = g_new0(benc_val_t, list.val.l.alloc);
|
||||
for(file = afc->files; NULL != file; file = file->next) {
|
||||
str = list.val.l.vals + list.val.l.count;
|
||||
str->type = TYPE_STR;
|
||||
str->val.s.i = strlen(file->data);
|
||||
str->val.s.s = file->data;
|
||||
list.val.l.count++;
|
||||
}
|
||||
g_list_free(afc->files);
|
||||
afc->files = NULL;
|
||||
afc->addid = send_msg(con, MSG_ADDFILES, &list);
|
||||
tr_bencFree(&list);
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX handle getting a non-version tag, invalid data,
|
||||
or nothing (read timeout) */
|
||||
switch( afc->cmd )
|
||||
{
|
||||
case CCMD_ADD:
|
||||
list.type = TYPE_LIST;
|
||||
list.val.l.alloc = g_list_length(afc->files);
|
||||
list.val.l.count = 0;
|
||||
list.val.l.vals = g_new0(benc_val_t, list.val.l.alloc);
|
||||
for(file = afc->files; NULL != file; file = file->next) {
|
||||
str = list.val.l.vals + list.val.l.count;
|
||||
str->type = TYPE_STR;
|
||||
str->val.s.i = strlen(file->data);
|
||||
str->val.s.s = file->data;
|
||||
list.val.l.count++;
|
||||
}
|
||||
g_list_free(afc->files);
|
||||
afc->files = NULL;
|
||||
afc->msgid = send_msg(con, MSG_ADDFILES, &list);
|
||||
tr_bencFree(&list);
|
||||
break;
|
||||
case CCMD_QUIT:
|
||||
bzero( &list, sizeof( list ) );
|
||||
list.type = TYPE_STR;
|
||||
afc->msgid = send_msg( con, MSG_QUIT, &list );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
afc_io_sent(GSource *source SHUTUP, unsigned int id, void *vdata) {
|
||||
struct constate_addfile *afc = &((struct constate*)vdata)->u.addfile;
|
||||
struct constate_client *afc = &((struct constate*)vdata)->u.client;
|
||||
|
||||
if(0 < id && afc->addid == id) {
|
||||
if(0 < id && afc->msgid == id) {
|
||||
*(afc->succeeded) = TRUE;
|
||||
destroycon(vdata);
|
||||
}
|
||||
|
|
10
gtk/ipc.h
10
gtk/ipc.h
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -28,9 +28,13 @@
|
|||
#include "util.h"
|
||||
|
||||
void
|
||||
ipc_socket_setup(void *wind, add_torrents_func_t addfunc, void *cbdata);
|
||||
ipc_socket_setup( void * wind, add_torrents_func_t addfunc,
|
||||
callbackfunc_t quitfunc, void * cbdata );
|
||||
|
||||
gboolean
|
||||
ipc_sendfiles_blocking(GList *files);
|
||||
ipc_sendfiles_blocking( GList * files );
|
||||
|
||||
gboolean
|
||||
ipc_sendquit_blocking( void );
|
||||
|
||||
#endif /* TG_IPC_H */
|
||||
|
|
820
gtk/main.c
820
gtk/main.c
File diff suppressed because it is too large
Load Diff
15
gtk/msgwin.c
15
gtk/msgwin.c
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "conf.h"
|
||||
#include "msgwin.h"
|
||||
#include "tr_prefs.h"
|
||||
#include "transmission.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -60,8 +61,7 @@ msgwin_create( void ) {
|
|||
GtkWidget * win, * vbox, * scroll, * text;
|
||||
GtkWidget * frame, * bbox, * save, * clear, * menu;
|
||||
PangoFontDescription * desc;
|
||||
unsigned int ii;
|
||||
int curlevel;
|
||||
int ii, curlevel;
|
||||
|
||||
if( NULL == textbuf )
|
||||
textbuf = gtk_text_buffer_new( NULL );
|
||||
|
@ -126,7 +126,7 @@ changelevel( GtkWidget * widget, gpointer data SHUTUP ) {
|
|||
if( 0 <= index && (int) ALEN( levels ) > index &&
|
||||
tr_getMessageLevel() != levels[index].id ) {
|
||||
tr_setMessageLevel( levels[index].id );
|
||||
cf_setpref( PREF_MSGLEVEL, levels[index].pref );
|
||||
cf_setpref( tr_prefs_name( PREF_ID_MSGLEVEL ), levels[index].pref );
|
||||
cf_saveprefs( &ignored );
|
||||
g_free( ignored );
|
||||
msgwin_update();
|
||||
|
@ -196,10 +196,10 @@ doclear( GtkWidget * widget SHUTUP, gpointer data SHUTUP ) {
|
|||
void
|
||||
msgwin_loadpref( void ) {
|
||||
const char * pref;
|
||||
unsigned int ii;
|
||||
int ii;
|
||||
|
||||
tr_setMessageQueuing( 1 );
|
||||
pref = cf_getpref( PREF_MSGLEVEL );
|
||||
pref = tr_prefs_get( PREF_ID_MSGLEVEL );
|
||||
if( NULL == pref )
|
||||
return;
|
||||
|
||||
|
@ -216,9 +216,8 @@ msgwin_update( void ) {
|
|||
tr_msg_list_t * msgs, * ii;
|
||||
GtkTextIter iter, front;
|
||||
char * label, * line;
|
||||
int count;
|
||||
int count, jj;
|
||||
struct tm * tm;
|
||||
unsigned int jj;
|
||||
|
||||
if( NULL == textbuf )
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -220,7 +220,9 @@ tr_backend_save_state(TrBackend *back, char **errstr) {
|
|||
}
|
||||
|
||||
GList *
|
||||
tr_backend_load_state(TrBackend *back, benc_val_t *state, GList **errors) {
|
||||
tr_backend_load_state( TrBackend * back, benc_val_t * state,
|
||||
guint flags, GList ** errors )
|
||||
{
|
||||
GList *ret = NULL;
|
||||
int ii;
|
||||
TrTorrent *tor;
|
||||
|
@ -233,8 +235,8 @@ tr_backend_load_state(TrBackend *back, benc_val_t *state, GList **errors) {
|
|||
|
||||
for(ii = 0; ii < state->val.l.count; ii++) {
|
||||
errstr = NULL;
|
||||
tor = tr_torrent_new_with_state(G_OBJECT(back), state->val.l.vals + ii,
|
||||
&errstr);
|
||||
tor = tr_torrent_new_with_state( G_OBJECT( back ), state->val.l.vals + ii,
|
||||
flags, &errstr );
|
||||
if(NULL != errstr)
|
||||
*errors = g_list_append(*errors, errstr);
|
||||
if(NULL != tor)
|
||||
|
@ -273,20 +275,25 @@ tr_backend_stop_torrents(TrBackend *back) {
|
|||
}
|
||||
|
||||
gboolean
|
||||
tr_backend_torrents_stopped(TrBackend *back) {
|
||||
GList *ii, *list;
|
||||
tr_stat_t *st;
|
||||
gboolean ret = TRUE;
|
||||
tr_backend_torrents_stopped( TrBackend * back, gboolean timeout )
|
||||
{
|
||||
GList * ii, * list;
|
||||
tr_stat_t * st;
|
||||
gboolean ret;
|
||||
|
||||
TR_IS_BACKEND(back);
|
||||
TR_IS_BACKEND( back );
|
||||
|
||||
list = g_list_copy(back->torrents);
|
||||
for(ii = list; NULL != ii; ii = ii->next) {
|
||||
st = tr_torrent_stat_polite(ii->data);
|
||||
if(NULL == st || !(TR_STATUS_PAUSE & st->status))
|
||||
ret = FALSE;
|
||||
}
|
||||
g_list_free(list);
|
||||
ret = TRUE;
|
||||
list = g_list_copy( back->torrents );
|
||||
for( ii = list; NULL != ii; ii = ii->next )
|
||||
{
|
||||
st = tr_torrent_stat_polite( ii->data, timeout );
|
||||
if( NULL == st || !( TR_STATUS_PAUSE & st->status ) )
|
||||
{
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
g_list_free( list );
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -70,13 +70,14 @@ void
|
|||
tr_backend_save_state(TrBackend *back, char **errstr);
|
||||
|
||||
GList *
|
||||
tr_backend_load_state(TrBackend *back, benc_val_t *state, GList **errors);
|
||||
tr_backend_load_state( TrBackend * back, benc_val_t * state,
|
||||
guint flags, GList ** errors );
|
||||
|
||||
void
|
||||
tr_backend_stop_torrents(TrBackend *back);
|
||||
|
||||
gboolean
|
||||
tr_backend_torrents_stopped(TrBackend *back);
|
||||
tr_backend_torrents_stopped( TrBackend * back, gboolean timeout );
|
||||
|
||||
#ifdef TR_WANT_BACKEND_PRIVATE
|
||||
void
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "tr_icon.h"
|
||||
#include "util.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ICON = 1,
|
||||
PROP_DOCKED,
|
||||
PROP_CLICK,
|
||||
};
|
||||
|
||||
static void
|
||||
tr_icon_init( GTypeInstance * instance, gpointer g_class );
|
||||
static void
|
||||
tr_icon_set_property( GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec );
|
||||
static void
|
||||
tr_icon_get_property( GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void
|
||||
tr_icon_class_init( gpointer g_class, gpointer g_class_data );
|
||||
static void
|
||||
tr_icon_dispose( GObject * obj );
|
||||
static void
|
||||
tr_icon_finalize( GObject * obj );
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
static void
|
||||
clicked( GObject * obj, gpointer data );
|
||||
#endif
|
||||
|
||||
GType
|
||||
tr_icon_get_type( void )
|
||||
{
|
||||
static GType type = 0;
|
||||
|
||||
if( 0 == type )
|
||||
{
|
||||
static const GTypeInfo info =
|
||||
{
|
||||
sizeof( TrIconClass ),
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
tr_icon_class_init, /* class_init */
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof( TrIcon ),
|
||||
0, /* n_preallocs */
|
||||
tr_icon_init, /* instance_init */
|
||||
NULL,
|
||||
};
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
type = GTK_TYPE_STATUS_ICON;
|
||||
#else
|
||||
type = G_TYPE_OBJECT;
|
||||
#endif
|
||||
type = g_type_register_static( type, "TrIcon", &info, 0 );
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static void
|
||||
tr_icon_class_init( gpointer g_class, gpointer g_class_data SHUTUP )
|
||||
{
|
||||
GObjectClass * gobject_class;
|
||||
TrIconClass * tricon_class;
|
||||
GParamSpec * pspec;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS( g_class );
|
||||
gobject_class->set_property = tr_icon_set_property;
|
||||
gobject_class->get_property = tr_icon_get_property;
|
||||
gobject_class->dispose = tr_icon_dispose;
|
||||
gobject_class->finalize = tr_icon_finalize;
|
||||
|
||||
pspec = g_param_spec_boolean( "icon", _("Icon"),
|
||||
_("Icon has been set from default window icon."),
|
||||
TRUE, G_PARAM_CONSTRUCT|G_PARAM_READWRITE );
|
||||
g_object_class_install_property( gobject_class, PROP_ICON, pspec );
|
||||
|
||||
pspec = g_param_spec_boolean( "docked", _("Docked"),
|
||||
_("Icon is docked in a system tray."),
|
||||
FALSE, G_PARAM_READABLE );
|
||||
g_object_class_install_property( gobject_class, PROP_DOCKED, pspec );
|
||||
|
||||
pspec = g_param_spec_int( "activate-action", _("Activate action"),
|
||||
_("The action id to signal when icon is activated."),
|
||||
G_MININT, G_MAXINT, -1, G_PARAM_READWRITE );
|
||||
g_object_class_install_property( gobject_class, PROP_CLICK, pspec );
|
||||
|
||||
tricon_class = TR_ICON_CLASS( g_class );
|
||||
tricon_class->actionsig =
|
||||
g_signal_new( "action", G_TYPE_FROM_CLASS( g_class ),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__INT,
|
||||
G_TYPE_NONE, 1, G_TYPE_INT );
|
||||
}
|
||||
|
||||
static void
|
||||
tr_icon_init( GTypeInstance * instance, gpointer g_class SHUTUP )
|
||||
{
|
||||
TrIcon * self = ( TrIcon * )instance;
|
||||
|
||||
self->clickact = -1;
|
||||
self->disposed = FALSE;
|
||||
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
g_signal_connect( self, "activate", G_CALLBACK( clicked ), NULL );
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
tr_icon_set_property( GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
TrIcon * self = ( TrIcon * )object;
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch( property_id )
|
||||
{
|
||||
case PROP_ICON:
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
if( g_value_get_boolean( value ) )
|
||||
{
|
||||
GList * icons = gtk_window_get_default_icon_list();
|
||||
if( NULL != icons && NULL != icons->data )
|
||||
{
|
||||
gtk_status_icon_set_from_pixbuf( GTK_STATUS_ICON( self ),
|
||||
icons->data );
|
||||
}
|
||||
g_list_free( icons );
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_status_icon_set_from_pixbuf( GTK_STATUS_ICON( self ),
|
||||
NULL );
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case PROP_CLICK:
|
||||
self->clickact = g_value_get_int( value );
|
||||
break;
|
||||
case PROP_DOCKED:
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tr_icon_get_property( GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec )
|
||||
{
|
||||
TrIcon * self = ( TrIcon * )object;
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
GtkStatusIcon * icon;
|
||||
#endif
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch( property_id )
|
||||
{
|
||||
case PROP_ICON:
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
icon = GTK_STATUS_ICON( self );
|
||||
if( GTK_IMAGE_PIXBUF == gtk_status_icon_get_storage_type( icon ) &&
|
||||
NULL != gtk_status_icon_get_pixbuf( icon ) )
|
||||
{
|
||||
g_value_set_boolean( value, TRUE );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
g_value_set_boolean( value, FALSE );
|
||||
}
|
||||
break;
|
||||
case PROP_DOCKED:
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
if( gtk_status_icon_is_embedded( GTK_STATUS_ICON( self ) ) )
|
||||
{
|
||||
g_value_set_boolean( value, TRUE );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
g_value_set_boolean( value, FALSE );
|
||||
}
|
||||
break;
|
||||
case PROP_CLICK:
|
||||
g_value_set_int( value, self->clickact );
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tr_icon_dispose( GObject * obj )
|
||||
{
|
||||
TrIcon * self = ( TrIcon * )obj;
|
||||
GObjectClass * parent;
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
self->disposed = TRUE;
|
||||
|
||||
/* Chain up to the parent class */
|
||||
parent = g_type_class_peek( g_type_parent( TR_ICON_TYPE ) );
|
||||
parent->dispose( obj );
|
||||
}
|
||||
|
||||
static void
|
||||
tr_icon_finalize( GObject * obj )
|
||||
{
|
||||
GObjectClass * parent;
|
||||
|
||||
/* Chain up to the parent class */
|
||||
parent = g_type_class_peek( g_type_parent( TR_ICON_TYPE ) );
|
||||
parent->finalize( obj );
|
||||
}
|
||||
|
||||
TrIcon *
|
||||
tr_icon_new( void )
|
||||
{
|
||||
return g_object_new( TR_ICON_TYPE, NULL );
|
||||
}
|
||||
|
||||
gboolean
|
||||
tr_icon_docked( TrIcon * self )
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_object_get( self, "docked", &ret, NULL );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
|
||||
static void
|
||||
clicked( GObject * obj, gpointer data SHUTUP )
|
||||
{
|
||||
TrIcon * self;
|
||||
TrIconClass * class;
|
||||
|
||||
TR_IS_ICON( obj );
|
||||
self = TR_ICON( obj );
|
||||
|
||||
if( self->disposed || 0 > self->clickact )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
class = g_type_class_peek( TR_ICON_TYPE );
|
||||
g_signal_emit( self, class->actionsig, 0, self->clickact );
|
||||
}
|
||||
|
||||
#endif /* TR_ICON_SUPPORTED */
|
|
@ -0,0 +1,89 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TR_ICON_H
|
||||
#define TR_ICON_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#if GTK_MAJOR_VERSION > 2 || \
|
||||
( GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 10 )
|
||||
#define TR_ICON_SUPPORTED
|
||||
#define tr_icon_supported() (TRUE)
|
||||
#else
|
||||
#define tr_icon_supported() (FALSE)
|
||||
#endif
|
||||
|
||||
#define TR_ICON_TYPE ( tr_icon_get_type() )
|
||||
|
||||
#define TR_ICON( obj ) \
|
||||
( G_TYPE_CHECK_INSTANCE_CAST( (obj), TR_ICON_TYPE, TrIcon ) )
|
||||
|
||||
#define TR_ICON_CLASS( class ) \
|
||||
( G_TYPE_CHECK_CLASS_CAST( (class), TR_ICON_TYPE, TrIconClass ) )
|
||||
|
||||
#define TR_IS_ICON( obj ) \
|
||||
( G_TYPE_CHECK_INSTANCE_TYPE( (obj), TR_ICON_TYPE ) )
|
||||
|
||||
#define TR_IS_ICON_CLASS( class ) \
|
||||
( G_TYPE_CHECK_CLASS_TYPE( (class), TR_ICON_TYPE ) )
|
||||
|
||||
#define TR_ICON_GET_CLASS( obj ) \
|
||||
( G_TYPE_INSTANCE_GET_CLASS( (obj), TR_ICON_TYPE, TrIconClass ) )
|
||||
|
||||
typedef struct _TrIcon TrIcon;
|
||||
typedef struct _TrIconClass TrIconClass;
|
||||
|
||||
/* treat the contents of this structure as private */
|
||||
struct _TrIcon
|
||||
{
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
GtkStatusIcon parent;
|
||||
#else
|
||||
GObject parent;
|
||||
#endif
|
||||
int clickact;
|
||||
gboolean disposed;
|
||||
};
|
||||
|
||||
struct _TrIconClass
|
||||
{
|
||||
#ifdef TR_ICON_SUPPORTED
|
||||
GtkStatusIconClass parent;
|
||||
#else
|
||||
GObjectClass parent;
|
||||
#endif
|
||||
int actionsig;
|
||||
};
|
||||
|
||||
GType
|
||||
tr_icon_get_type( void );
|
||||
|
||||
TrIcon *
|
||||
tr_icon_new( void );
|
||||
|
||||
gboolean
|
||||
tr_icon_docked( TrIcon * icon );
|
||||
|
||||
#endif
|
|
@ -0,0 +1,950 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2005-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "tr_icon.h"
|
||||
#include "tr_prefs.h"
|
||||
#include "tr_torrent.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
/* used for g_object_set/get_data */
|
||||
#define PREF_CHECK_LINK "tr-prefs-check-link-thingy"
|
||||
#define PREF_SPIN_LAST "tr-prefs-spinbox-last-val"
|
||||
|
||||
/* convenience macros for saving pref id on a widget */
|
||||
#define SETPREFID( wid, id ) \
|
||||
( g_object_set_data( G_OBJECT( (wid) ), "tr-prefs-id", \
|
||||
GINT_TO_POINTER( (id) + 1 ) ) )
|
||||
#define GETPREFID( wid, id ) \
|
||||
do \
|
||||
{ \
|
||||
(id) = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( (wid) ), \
|
||||
"tr-prefs-id" ) ); \
|
||||
g_assert( 0 < (id) ); \
|
||||
(id)--; \
|
||||
} \
|
||||
while( 0 )
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_PARENT = 1,
|
||||
};
|
||||
|
||||
#define PTYPE( id ) \
|
||||
( G_TYPE_NONE == defs[(id)]._type ? \
|
||||
defs[(id)].typefunc() : defs[(id)]._type )
|
||||
|
||||
/* please keep this in sync with the enum in tr_prefs.c */
|
||||
/* don't forget defs_int, defs_bool, and defs_file too */
|
||||
static struct
|
||||
{
|
||||
char * name;
|
||||
GType _type; /* don't access this directly, use PTYPE() */
|
||||
enum { PR_ENABLED, PR_DISABLED, PR_SKIP } status;
|
||||
GType (*typefunc)(void);
|
||||
const char * label;
|
||||
const char * tip;
|
||||
}
|
||||
defs[] =
|
||||
{
|
||||
/* PREF_ID_USEDOWNLIMIT */
|
||||
{ "use-download-limit", G_TYPE_BOOLEAN, PR_ENABLED, NULL,
|
||||
N_("_Limit download speed"),
|
||||
N_("Restrict the download rate") },
|
||||
|
||||
/* PREF_ID_DOWNLIMIT */
|
||||
{ "download-limit", G_TYPE_INT, PR_ENABLED, NULL,
|
||||
N_("Maximum _download speed:"),
|
||||
N_("Speed in KiB/sec for restricted download rate") },
|
||||
|
||||
/* PREF_ID_USEUPLIMIT */
|
||||
{ "use-upload-limit", G_TYPE_BOOLEAN, PR_ENABLED, NULL,
|
||||
N_("Li_mit upload speed"),
|
||||
N_("Restrict the upload rate") },
|
||||
|
||||
/* PREF_ID_UPLIMIT */
|
||||
{ "upload-limit", G_TYPE_INT, PR_ENABLED, NULL,
|
||||
N_("Maximum _upload speed:"),
|
||||
N_("Speed in KiB/sec for restricted upload rate") },
|
||||
|
||||
/* PREF_ID_ASKDIR */
|
||||
{ "ask-download-directory", G_TYPE_BOOLEAN, PR_ENABLED, NULL,
|
||||
N_("Al_ways prompt for download directory"),
|
||||
N_("When adding a torrent, always prompt for a directory to download data files into") },
|
||||
|
||||
/* PREF_ID_DIR */
|
||||
{ "download-directory", G_TYPE_NONE, PR_ENABLED,
|
||||
gtk_file_chooser_get_type,
|
||||
N_("Download di_rectory:"),
|
||||
N_("Destination directory for downloaded data files") },
|
||||
|
||||
/* PREF_ID_PORT */
|
||||
{ "listening-port", G_TYPE_INT, PR_ENABLED, NULL,
|
||||
N_("Listening _port:"),
|
||||
N_("TCP port number to listen for peer connections") },
|
||||
|
||||
/* PREF_ID_NAT */
|
||||
{ "use-nat-traversal", G_TYPE_BOOLEAN, PR_ENABLED, NULL,
|
||||
N_("Au_tomatic port mapping via NAT-PMP or UPnP"),
|
||||
N_("Attempt to bypass NAT or firewall to allow incoming peer connections") },
|
||||
|
||||
/* PREF_ID_ICON */
|
||||
{ "use-tray-icon", G_TYPE_BOOLEAN,
|
||||
( tr_icon_supported() ? PR_ENABLED : PR_DISABLED ), NULL,
|
||||
N_("Display an _icon in the system tray"),
|
||||
N_("Use a system tray / dock / notification area icon") },
|
||||
|
||||
/* PREF_ID_ADDSTD */
|
||||
{ "add-behavior-standard", G_TYPE_NONE, PR_ENABLED,
|
||||
gtk_combo_box_get_type,
|
||||
N_("For torrents added _normally:"),
|
||||
N_("Torrent files added via the toolbar, popup menu, and drag-and-drop") },
|
||||
|
||||
/* PREF_ID_ADDIPC */
|
||||
{ "add-behavior-ipc", G_TYPE_NONE, PR_ENABLED,
|
||||
gtk_combo_box_get_type,
|
||||
N_("For torrents added e_xternally\n(via the command-line):"),
|
||||
N_("For torrents added via the command-line only") },
|
||||
|
||||
/* PREF_ID_MSGLEVEL */
|
||||
{ "message-level", G_TYPE_INT, PR_SKIP, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
long min;
|
||||
long max;
|
||||
long def;
|
||||
}
|
||||
defs_int[] =
|
||||
{
|
||||
{ 0, 0, 0 },
|
||||
/* PREF_ID_DOWNLIMIT */
|
||||
{ 0, G_MAXLONG, 100 },
|
||||
{ 0, 0, 0 },
|
||||
/* PREF_ID_UPLIMIT */
|
||||
{ 0, G_MAXLONG, 20 },
|
||||
{ 0, 0, 0 }, { 0, 0, 0 },
|
||||
/* PREF_ID_PORT */
|
||||
{ 1, 0xffff, TR_DEFAULT_PORT },
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
gboolean def;
|
||||
int link;
|
||||
gboolean enables;
|
||||
}
|
||||
defs_bool[] =
|
||||
{
|
||||
/* PREF_ID_USEDOWNLIMIT */
|
||||
{ FALSE, PREF_ID_DOWNLIMIT, TRUE },
|
||||
{ FALSE, -1, FALSE },
|
||||
/* PREF_ID_USEUPLIMIT */
|
||||
{ TRUE, PREF_ID_UPLIMIT, TRUE },
|
||||
{ FALSE, -1, FALSE },
|
||||
/* PREF_ID_ASKDIR */
|
||||
{ FALSE, PREF_ID_DIR, FALSE },
|
||||
{ FALSE, -1, FALSE }, { FALSE, -1, FALSE },
|
||||
/* PREF_ID_NAT */
|
||||
{ TRUE, -1, FALSE },
|
||||
/* PREF_ID_ICON */
|
||||
{ TRUE, -1, FALSE },
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
const char * title;
|
||||
GtkFileChooserAction act;
|
||||
const char * (*getdef)(void);
|
||||
}
|
||||
defs_file[] =
|
||||
{
|
||||
{ NULL, 0, NULL }, { NULL, 0, NULL }, { NULL, 0, NULL },
|
||||
{ NULL, 0, NULL }, { NULL, 0, NULL },
|
||||
/* PREF_ID_DIR */
|
||||
{ N_("Choose a download directory"),
|
||||
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
getdownloaddir },
|
||||
};
|
||||
|
||||
struct checkctl
|
||||
{
|
||||
GtkToggleButton * check;
|
||||
GtkWidget * wids[2];
|
||||
gboolean enables;
|
||||
};
|
||||
|
||||
static void
|
||||
tr_prefs_init( GTypeInstance * instance, gpointer g_class );
|
||||
static void
|
||||
tr_prefs_set_property( GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec );
|
||||
static void
|
||||
tr_prefs_get_property( GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void
|
||||
tr_prefs_class_init( gpointer g_class, gpointer g_class_data );
|
||||
static void
|
||||
tr_prefs_dispose( GObject * obj );
|
||||
static void
|
||||
gotresp( GtkWidget * widget, int resp, gpointer data );
|
||||
static int
|
||||
countprefs( void );
|
||||
static void
|
||||
makelinks( struct checkctl ** links );
|
||||
static void
|
||||
filllinks( int id, GtkWidget * wid1, GtkWidget * wid2,
|
||||
struct checkctl ** links );
|
||||
static void
|
||||
pokelink( struct checkctl * link );
|
||||
static void
|
||||
addwidget( TrPrefs * self, int id, GtkTable * table, int off,
|
||||
GtkTooltips * tips, struct checkctl ** links );
|
||||
static GtkWidget *
|
||||
tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip );
|
||||
static void
|
||||
addwid_bool( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, struct checkctl ** links );
|
||||
static void
|
||||
checkclick( GtkWidget * widget, gpointer data );
|
||||
static void
|
||||
addwid_int( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, GtkWidget ** wid2 );
|
||||
static gboolean
|
||||
spinfocus( GtkWidget * widget, GdkEventFocus *event, gpointer data );
|
||||
static void
|
||||
spindie( GtkWidget * widget, gpointer data );
|
||||
static void
|
||||
addwid_file( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, GtkWidget ** wid2 );
|
||||
static void
|
||||
filechosen( GtkWidget * widget, gpointer data );
|
||||
static GtkTreeModel *
|
||||
makecombomodel( void );
|
||||
static void
|
||||
addwid_combo( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, GtkWidget ** wid2 );
|
||||
static void
|
||||
combochosen( GtkWidget * widget, gpointer data );
|
||||
static void
|
||||
savepref( TrPrefs * self, int id, const char * val );
|
||||
|
||||
GType
|
||||
tr_prefs_get_type( void )
|
||||
{
|
||||
static GType type = 0;
|
||||
|
||||
if( 0 == type )
|
||||
{
|
||||
static const GTypeInfo info =
|
||||
{
|
||||
sizeof( TrPrefsClass ),
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
tr_prefs_class_init, /* class_init */
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof( TrPrefs ),
|
||||
0, /* n_preallocs */
|
||||
tr_prefs_init, /* instance_init */
|
||||
NULL,
|
||||
};
|
||||
type = g_type_register_static( GTK_TYPE_DIALOG, "TrPrefs", &info, 0 );
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static void
|
||||
tr_prefs_class_init( gpointer g_class, gpointer g_class_data SHUTUP )
|
||||
{
|
||||
GObjectClass * gobject_class;
|
||||
TrPrefsClass * trprefs_class;
|
||||
GParamSpec * pspec;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS( g_class );
|
||||
gobject_class->set_property = tr_prefs_set_property;
|
||||
gobject_class->get_property = tr_prefs_get_property;
|
||||
gobject_class->dispose = tr_prefs_dispose;
|
||||
|
||||
pspec = g_param_spec_object( "parent", _("Parent"),
|
||||
_("The parent GtkWindow."),
|
||||
GTK_TYPE_WINDOW, G_PARAM_READWRITE );
|
||||
g_object_class_install_property( gobject_class, PROP_PARENT, pspec );
|
||||
|
||||
trprefs_class = TR_PREFS_CLASS( g_class );
|
||||
trprefs_class->changesig =
|
||||
g_signal_new( "prefs-changed", G_TYPE_FROM_CLASS( g_class ),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__INT,
|
||||
G_TYPE_NONE, 1, G_TYPE_INT );
|
||||
}
|
||||
|
||||
static void
|
||||
tr_prefs_init( GTypeInstance * instance, gpointer g_class SHUTUP )
|
||||
{
|
||||
struct checkctl * links[ ALEN( defs_bool ) ];
|
||||
TrPrefs * self = ( TrPrefs * )instance;
|
||||
char * title;
|
||||
GtkWidget * table;
|
||||
GtkTooltips * tips;
|
||||
int rows, ii, off;
|
||||
|
||||
self->combomodel = makecombomodel();
|
||||
self->disposed = FALSE;
|
||||
|
||||
title = g_strdup_printf( _("%s Preferences"), g_get_application_name() );
|
||||
gtk_window_set_title( GTK_WINDOW( self ), title );
|
||||
g_free( title );
|
||||
gtk_dialog_set_has_separator( GTK_DIALOG( self ), FALSE );
|
||||
gtk_dialog_add_button( GTK_DIALOG( self ), GTK_STOCK_CLOSE,
|
||||
GTK_RESPONSE_CLOSE );
|
||||
gtk_widget_set_name( GTK_WIDGET( self ), "TransmissionDialog");
|
||||
gtk_dialog_set_default_response( GTK_DIALOG( self ), GTK_RESPONSE_CLOSE );
|
||||
gtk_container_set_border_width( GTK_CONTAINER( self ), 6 );
|
||||
gtk_window_set_resizable( GTK_WINDOW( self ), FALSE );
|
||||
|
||||
rows = countprefs();
|
||||
table = gtk_table_new( rows, 2, FALSE );
|
||||
gtk_table_set_col_spacings( GTK_TABLE( table ), 8 );
|
||||
gtk_table_set_row_spacings( GTK_TABLE( table ), 8 );
|
||||
|
||||
tips = gtk_tooltips_new();
|
||||
g_object_ref( tips );
|
||||
gtk_object_sink( GTK_OBJECT( tips ) );
|
||||
gtk_tooltips_enable( tips );
|
||||
g_signal_connect_swapped( self, "destroy",
|
||||
G_CALLBACK( g_object_unref ), tips );
|
||||
|
||||
memset( links, 0, sizeof( links ) );
|
||||
makelinks( links );
|
||||
off = 0;
|
||||
for( ii = 0; PREF_MAX_ID > ii; ii++ )
|
||||
{
|
||||
if( PR_SKIP != defs[ii].status )
|
||||
{
|
||||
addwidget( self, ii, GTK_TABLE( table ), off, tips, links );
|
||||
off++;
|
||||
}
|
||||
}
|
||||
g_assert( rows == off );
|
||||
for( ii = 0; ALEN( links ) > ii; ii++ )
|
||||
{
|
||||
g_assert( NULL == links[ii] || NULL != links[ii]->check );
|
||||
if( NULL != links[ii] )
|
||||
{
|
||||
pokelink( links[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
gtk_box_pack_start_defaults( GTK_BOX( GTK_DIALOG( self )->vbox ), table );
|
||||
g_signal_connect( self, "response", G_CALLBACK( gotresp ), NULL );
|
||||
gtk_widget_show_all( table );
|
||||
}
|
||||
|
||||
static void
|
||||
tr_prefs_set_property( GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
TrPrefs * self = ( TrPrefs * )object;
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch( property_id )
|
||||
{
|
||||
case PROP_PARENT:
|
||||
gtk_window_set_transient_for( GTK_WINDOW( self ),
|
||||
g_value_get_object( value ) );
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tr_prefs_get_property( GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec )
|
||||
{
|
||||
TrPrefs * self = ( TrPrefs * )object;
|
||||
GtkWindow * trans;
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch( property_id )
|
||||
{
|
||||
case PROP_PARENT:
|
||||
trans = gtk_window_get_transient_for( GTK_WINDOW( self ) );
|
||||
g_value_set_object( value, trans );
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tr_prefs_dispose( GObject * obj )
|
||||
{
|
||||
TrPrefs * self = ( TrPrefs * )obj;
|
||||
GObjectClass * parent;
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
self->disposed = TRUE;
|
||||
|
||||
g_object_unref( self->combomodel );
|
||||
|
||||
/* Chain up to the parent class */
|
||||
parent = g_type_class_peek( g_type_parent( TR_PREFS_TYPE ) );
|
||||
parent->dispose( obj );
|
||||
}
|
||||
|
||||
TrPrefs *
|
||||
tr_prefs_new( void )
|
||||
{
|
||||
return g_object_new( TR_PREFS_TYPE, NULL );
|
||||
}
|
||||
|
||||
TrPrefs *
|
||||
tr_prefs_new_with_parent( GtkWindow * parent )
|
||||
{
|
||||
return g_object_new( TR_PREFS_TYPE, "parent", parent, NULL );
|
||||
}
|
||||
|
||||
const char *
|
||||
tr_prefs_name( int id )
|
||||
{
|
||||
g_assert( 0 <= id && PREF_MAX_ID > id && ALEN( defs ) == PREF_MAX_ID );
|
||||
return defs[id].name;
|
||||
}
|
||||
|
||||
gboolean
|
||||
tr_prefs_get_int( int id, int * val )
|
||||
{
|
||||
const char * str;
|
||||
char * end;
|
||||
int ret;
|
||||
|
||||
str = tr_prefs_get( id );
|
||||
if( NULL == str || '\0' == *str )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
ret = strtol( str, &end, 10 );
|
||||
if( 0 != errno || NULL == end || '\0' != *end )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*val = ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
tr_prefs_get_bool( int id, gboolean * val )
|
||||
{
|
||||
const char * str;
|
||||
|
||||
str = tr_prefs_get( id );
|
||||
if( NULL == str )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*val = strbool( str );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
tr_prefs_get_int_with_default( int id )
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_assert( 0 <= id && ALEN( defs ) > id &&
|
||||
G_TYPE_INT == PTYPE( id ) && ALEN( defs_int ) > id );
|
||||
|
||||
if( tr_prefs_get_int( id, &ret ) )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
return defs_int[id].def;
|
||||
}
|
||||
|
||||
gboolean
|
||||
tr_prefs_get_bool_with_default( int id )
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_assert( 0 <= id && ALEN( defs ) > id &&
|
||||
G_TYPE_BOOLEAN == PTYPE( id ) && ALEN( defs_bool ) > id );
|
||||
|
||||
if( tr_prefs_get_bool( id, &ret ) )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
return defs_bool[id].def;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gotresp( GtkWidget * widget, int resp SHUTUP, gpointer data SHUTUP )
|
||||
{
|
||||
gtk_widget_destroy( widget );
|
||||
}
|
||||
|
||||
static int
|
||||
countprefs( void )
|
||||
{
|
||||
int ii, ret;
|
||||
|
||||
g_assert( ALEN( defs ) == PREF_MAX_ID );
|
||||
ret = 0;
|
||||
for( ii = 0; PREF_MAX_ID > ii; ii++ )
|
||||
{
|
||||
if( PR_SKIP != defs[ii].status )
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
makelinks( struct checkctl ** links )
|
||||
{
|
||||
int ii;
|
||||
|
||||
g_assert( ALEN( defs ) == PREF_MAX_ID );
|
||||
for( ii = 0; PREF_MAX_ID > ii; ii++ )
|
||||
{
|
||||
if( PR_SKIP == defs[ii].status || G_TYPE_BOOLEAN != PTYPE( ii ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
g_assert( ALEN( defs_bool ) > ii );
|
||||
if( 0 <= defs_bool[ii].link )
|
||||
{
|
||||
links[ii] = g_new0( struct checkctl, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
filllinks( int id, GtkWidget * wid1, GtkWidget * wid2,
|
||||
struct checkctl ** links )
|
||||
{
|
||||
int ii;
|
||||
|
||||
g_assert( ALEN( defs ) >= ALEN( defs_bool ) );
|
||||
for( ii = 0; ALEN( defs_bool) > ii; ii++ )
|
||||
{
|
||||
if( NULL == links[ii] )
|
||||
{
|
||||
g_assert( PR_SKIP == defs[ii].status ||
|
||||
G_TYPE_BOOLEAN != PTYPE( ii ) ||
|
||||
0 > defs_bool[ii].link );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert( PR_SKIP != defs[ii].status &&
|
||||
G_TYPE_BOOLEAN == PTYPE( ii ) &&
|
||||
0 <= defs_bool[ii].link );
|
||||
if( id == defs_bool[ii].link )
|
||||
{
|
||||
links[ii]->wids[0] = wid1;
|
||||
links[ii]->wids[1] = wid2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pokelink( struct checkctl * link )
|
||||
{
|
||||
gboolean active;
|
||||
|
||||
active = gtk_toggle_button_get_active( link->check );
|
||||
active = ( link->enables ? active : !active );
|
||||
gtk_widget_set_sensitive( link->wids[0], active );
|
||||
gtk_widget_set_sensitive( link->wids[1], active );
|
||||
}
|
||||
|
||||
static void
|
||||
addwidget( TrPrefs * self, int id, GtkTable * table, int off,
|
||||
GtkTooltips * tips, struct checkctl ** links )
|
||||
{
|
||||
GType type;
|
||||
GtkWidget * add1, * add2;
|
||||
|
||||
g_assert( ALEN( defs ) > id );
|
||||
|
||||
type = PTYPE( id );
|
||||
add1 = NULL;
|
||||
add2 = NULL;
|
||||
if( G_TYPE_BOOLEAN == type )
|
||||
{
|
||||
addwid_bool( self, id, tips, &add1, links );
|
||||
}
|
||||
else if( G_TYPE_INT == type )
|
||||
{
|
||||
addwid_int( self, id, tips, &add1, &add2 );
|
||||
}
|
||||
else if( GTK_TYPE_FILE_CHOOSER == type )
|
||||
{
|
||||
addwid_file( self, id, tips, &add1, &add2 );
|
||||
}
|
||||
else if( GTK_TYPE_COMBO_BOX == type )
|
||||
{
|
||||
addwid_combo( self, id, tips, &add1, &add2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
g_assert( NULL != add1 );
|
||||
filllinks( id, add1, add2, links );
|
||||
if( NULL == add2 )
|
||||
{
|
||||
gtk_table_attach_defaults( table, add1, 0, 2, off, off + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_table_attach_defaults( table, add1, 0, 1, off, off + 1 );
|
||||
gtk_table_attach_defaults( table, add2, 1, 2, off, off + 1 );
|
||||
}
|
||||
if( PR_DISABLED == defs[id].status )
|
||||
{
|
||||
gtk_widget_set_sensitive( add1, FALSE );
|
||||
if( NULL != add2 )
|
||||
{
|
||||
gtk_widget_set_sensitive( add2, FALSE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* wrap a widget in an event box with a tooltip */
|
||||
static GtkWidget *
|
||||
tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip )
|
||||
{
|
||||
GtkWidget * box;
|
||||
|
||||
box = gtk_event_box_new();
|
||||
gtk_container_add( GTK_CONTAINER( box ), widget );
|
||||
gtk_tooltips_set_tip( tips, box, tip, "" );
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
static void
|
||||
addwid_bool( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, struct checkctl ** links )
|
||||
{
|
||||
GtkWidget * check;
|
||||
gboolean active;
|
||||
|
||||
g_assert( ALEN( defs ) > id && G_TYPE_BOOLEAN == PTYPE( id ) );
|
||||
check = gtk_check_button_new_with_mnemonic( gettext( defs[id].label ) );
|
||||
gtk_tooltips_set_tip( tips, check, gettext( defs[id].tip ), "" );
|
||||
if( 0 > defs_bool[id].link )
|
||||
{
|
||||
g_assert( NULL == links[id] );
|
||||
}
|
||||
else
|
||||
{
|
||||
links[id]->check = GTK_TOGGLE_BUTTON( check );
|
||||
links[id]->enables = defs_bool[id].enables;
|
||||
g_object_set_data_full( G_OBJECT( check ), PREF_CHECK_LINK,
|
||||
links[id], g_free );
|
||||
}
|
||||
active = tr_prefs_get_bool_with_default( id );
|
||||
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check ), active );
|
||||
SETPREFID( check, id );
|
||||
g_signal_connect( check, "clicked", G_CALLBACK( checkclick ), self );
|
||||
|
||||
*wid1 = check;
|
||||
}
|
||||
|
||||
static void
|
||||
checkclick( GtkWidget * widget, gpointer data )
|
||||
{
|
||||
TrPrefs * self;
|
||||
struct checkctl * link;
|
||||
int id;
|
||||
gboolean active;
|
||||
|
||||
TR_IS_PREFS( data );
|
||||
self = TR_PREFS( data );
|
||||
link = g_object_get_data( G_OBJECT( widget ), PREF_CHECK_LINK );
|
||||
GETPREFID( widget, id );
|
||||
|
||||
if( NULL != link )
|
||||
{
|
||||
pokelink( link );
|
||||
}
|
||||
|
||||
active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( widget ) );
|
||||
savepref( self, id, ( active ? "yes" : "no" ) );
|
||||
}
|
||||
|
||||
static void
|
||||
addwid_int( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, GtkWidget ** wid2 )
|
||||
{
|
||||
GtkWidget * spin, * label;
|
||||
int val, * last;
|
||||
|
||||
g_assert( ALEN( defs ) > id && G_TYPE_INT == PTYPE( id ) );
|
||||
spin = gtk_spin_button_new_with_range( defs_int[id].min,
|
||||
defs_int[id].max, 1 );
|
||||
label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) );
|
||||
gtk_label_set_mnemonic_widget( GTK_LABEL( label ), spin );
|
||||
gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 );
|
||||
gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin ), TRUE );
|
||||
gtk_tooltips_set_tip( tips, spin, gettext( defs[id].tip ), "" );
|
||||
val = tr_prefs_get_int_with_default( id );
|
||||
gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin ), val );
|
||||
last = g_new( int, 1 );
|
||||
*last = val;
|
||||
g_object_set_data_full( G_OBJECT( spin ), PREF_SPIN_LAST, last, g_free );
|
||||
SETPREFID( spin, id );
|
||||
/* I don't trust that focus-out-event will always work,
|
||||
so save pref on widget destruction too */
|
||||
g_signal_connect( spin, "focus-out-event", G_CALLBACK( spinfocus ), self );
|
||||
g_signal_connect( spin, "destroy", G_CALLBACK( spindie ), self );
|
||||
|
||||
*wid1 = tipbox( label, tips, gettext( defs[id].tip ) );
|
||||
*wid2 = spin;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
spinfocus( GtkWidget * widget, GdkEventFocus *event SHUTUP, gpointer data )
|
||||
{
|
||||
TrPrefs * self;
|
||||
int * last, id, cur;
|
||||
char * str;
|
||||
|
||||
TR_IS_PREFS( data );
|
||||
self = TR_PREFS( data );
|
||||
last = g_object_get_data( G_OBJECT( widget ), PREF_SPIN_LAST );
|
||||
GETPREFID( widget, id );
|
||||
cur = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( widget ) );
|
||||
|
||||
if( cur != *last )
|
||||
{
|
||||
str = g_strdup_printf( "%i", cur );
|
||||
savepref( self, id, str );
|
||||
g_free( str );
|
||||
*last = cur;
|
||||
}
|
||||
|
||||
/* continue propagating the event */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
spindie( GtkWidget * widget, gpointer data )
|
||||
{
|
||||
spinfocus( widget, NULL, data );
|
||||
}
|
||||
|
||||
static void
|
||||
addwid_file( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, GtkWidget ** wid2 )
|
||||
{
|
||||
GtkWidget * file, * label;
|
||||
const char * pref;
|
||||
|
||||
g_assert( ALEN( defs ) > id && GTK_TYPE_FILE_CHOOSER == PTYPE( id ) );
|
||||
file = gtk_file_chooser_button_new( gettext( defs_file[id].title ),
|
||||
defs_file[id].act );
|
||||
label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) );
|
||||
gtk_label_set_mnemonic_widget( GTK_LABEL( label ), file );
|
||||
gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 );
|
||||
pref = tr_prefs_get( id );
|
||||
if( NULL == pref )
|
||||
{
|
||||
pref = defs_file[id].getdef();
|
||||
}
|
||||
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( file ), pref );
|
||||
SETPREFID( file, id );
|
||||
g_signal_connect( file, "selection-changed",
|
||||
G_CALLBACK( filechosen ), self );
|
||||
|
||||
*wid1 = tipbox( label, tips, gettext( defs[id].tip ) );
|
||||
*wid2 = tipbox( file, tips, gettext( defs[id].tip ) );
|
||||
}
|
||||
|
||||
static void
|
||||
filechosen( GtkWidget * widget, gpointer data )
|
||||
{
|
||||
TrPrefs * self;
|
||||
const char * dir;
|
||||
int id;
|
||||
|
||||
TR_IS_PREFS( data );
|
||||
self = TR_PREFS( data );
|
||||
dir = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( widget ) );
|
||||
GETPREFID( widget, id );
|
||||
savepref( self, id, dir );
|
||||
}
|
||||
|
||||
static GtkTreeModel *
|
||||
makecombomodel( void )
|
||||
{
|
||||
GtkListStore * list;
|
||||
GtkTreeIter iter;
|
||||
|
||||
/* create the model used by the two popup menus */
|
||||
list = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
|
||||
gtk_list_store_append( list, &iter );
|
||||
gtk_list_store_set( list, &iter, 1, 0, 0,
|
||||
_("Use the torrent file where it is"), -1 );
|
||||
gtk_list_store_append( list, &iter );
|
||||
gtk_list_store_set( list, &iter, 1, TR_TORNEW_SAVE_COPY, 0,
|
||||
_("Keep a copy of the torrent file"), -1 );
|
||||
gtk_list_store_append( list, &iter );
|
||||
gtk_list_store_set( list, &iter, 1, TR_TORNEW_SAVE_MOVE, 0,
|
||||
_("Keep a copy and remove the original"), -1 );
|
||||
|
||||
return GTK_TREE_MODEL( list );
|
||||
}
|
||||
|
||||
static void
|
||||
addwid_combo( TrPrefs * self, int id, GtkTooltips * tips,
|
||||
GtkWidget ** wid1, GtkWidget ** wid2 )
|
||||
{
|
||||
GtkWidget * combo, * label;
|
||||
GtkCellRenderer * rend;
|
||||
GtkTreeIter iter;
|
||||
guint prefsflag, modelflag;
|
||||
|
||||
g_assert( ALEN( defs ) > id && GTK_TYPE_COMBO_BOX == PTYPE( id ) );
|
||||
combo = gtk_combo_box_new();
|
||||
label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) );
|
||||
gtk_label_set_mnemonic_widget( GTK_LABEL( label ), combo );
|
||||
gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 );
|
||||
gtk_combo_box_set_model( GTK_COMBO_BOX( combo ), self->combomodel );
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), rend, TRUE );
|
||||
gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), rend, "text", 0 );
|
||||
|
||||
prefsflag = addactionflag( tr_prefs_get( id ) );
|
||||
if( gtk_tree_model_get_iter_first( self->combomodel, &iter ) )
|
||||
{
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get( self->combomodel, &iter, 1, &modelflag, -1 );
|
||||
if( modelflag == prefsflag)
|
||||
{
|
||||
gtk_combo_box_set_active_iter( GTK_COMBO_BOX( combo ), &iter );
|
||||
break;
|
||||
}
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->combomodel, &iter ) );
|
||||
}
|
||||
SETPREFID( combo, id );
|
||||
g_signal_connect( combo, "changed", G_CALLBACK( combochosen ), self );
|
||||
|
||||
*wid1 = tipbox( label, tips, gettext( defs[id].tip ) );
|
||||
*wid2 = tipbox( combo, tips, gettext( defs[id].tip ) );
|
||||
}
|
||||
|
||||
static void
|
||||
combochosen( GtkWidget * widget, gpointer data )
|
||||
{
|
||||
TrPrefs * self;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel * model;
|
||||
guint flags;
|
||||
int id;
|
||||
|
||||
TR_IS_PREFS( data );
|
||||
self = TR_PREFS( data );
|
||||
if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX( widget ), &iter ) )
|
||||
{
|
||||
model = gtk_combo_box_get_model( GTK_COMBO_BOX( widget ) );
|
||||
gtk_tree_model_get( model, &iter, 1, &flags, -1 );
|
||||
GETPREFID( widget, id );
|
||||
savepref( self, id, addactionname( flags ) );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
savepref( TrPrefs * self, int id, const char * val )
|
||||
{
|
||||
const char * name, * old;
|
||||
char * errstr;
|
||||
TrPrefsClass * class;
|
||||
|
||||
name = tr_prefs_name( id );
|
||||
old = cf_getpref( name );
|
||||
if( NULL == old )
|
||||
{
|
||||
if( old == val )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( 0 == strcmp( old, val ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
cf_setpref( name, val );
|
||||
|
||||
/* write prefs to disk */
|
||||
cf_saveprefs( &errstr );
|
||||
if( NULL != errstr )
|
||||
{
|
||||
errmsg( GTK_WINDOW( self ), "%s", errstr );
|
||||
g_free( errstr );
|
||||
}
|
||||
|
||||
/* signal a pref change */
|
||||
class = g_type_class_peek( TR_PREFS_TYPE );
|
||||
g_signal_emit( self, class->changesig, 0, id );
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TR_PREFS_H
|
||||
#define TR_PREFS_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
#define TR_PREFS_TYPE ( tr_prefs_get_type() )
|
||||
|
||||
#define TR_PREFS( obj ) \
|
||||
( G_TYPE_CHECK_INSTANCE_CAST( (obj), TR_PREFS_TYPE, TrPrefs ) )
|
||||
|
||||
#define TR_PREFS_CLASS( class ) \
|
||||
( G_TYPE_CHECK_CLASS_CAST( (class), TR_PREFS_TYPE, TrPrefsClass ) )
|
||||
|
||||
#define TR_IS_PREFS( obj ) \
|
||||
( G_TYPE_CHECK_INSTANCE_TYPE( (obj), TR_PREFS_TYPE ) )
|
||||
|
||||
#define TR_IS_PREFS_CLASS( class ) \
|
||||
( G_TYPE_CHECK_CLASS_TYPE( (class), TR_PREFS_TYPE ) )
|
||||
|
||||
#define TR_PREFS_GET_CLASS( obj ) \
|
||||
( G_TYPE_INSTANCE_GET_CLASS( (obj), TR_PREFS_TYPE, TrPrefsClass ) )
|
||||
|
||||
typedef struct _TrPrefs TrPrefs;
|
||||
typedef struct _TrPrefsClass TrPrefsClass;
|
||||
|
||||
/* treat the contents of this structure as private */
|
||||
struct _TrPrefs
|
||||
{
|
||||
GtkDialog parent;
|
||||
GtkTreeModel * combomodel;
|
||||
gboolean disposed;
|
||||
};
|
||||
|
||||
struct _TrPrefsClass
|
||||
{
|
||||
GtkDialogClass parent;
|
||||
int changesig;
|
||||
};
|
||||
|
||||
GType
|
||||
tr_prefs_get_type( void );
|
||||
|
||||
TrPrefs *
|
||||
tr_prefs_new( void );
|
||||
|
||||
TrPrefs *
|
||||
tr_prefs_new_with_parent( GtkWindow * parent );
|
||||
|
||||
/* please keep this in sync with defs in tr_prefs.c */
|
||||
enum
|
||||
{
|
||||
PREF_ID_USEDOWNLIMIT = 0,
|
||||
PREF_ID_DOWNLIMIT,
|
||||
PREF_ID_USEUPLIMIT,
|
||||
PREF_ID_UPLIMIT,
|
||||
PREF_ID_ASKDIR,
|
||||
PREF_ID_DIR,
|
||||
PREF_ID_PORT,
|
||||
PREF_ID_NAT,
|
||||
PREF_ID_ICON,
|
||||
PREF_ID_ADDSTD,
|
||||
PREF_ID_ADDIPC,
|
||||
PREF_ID_MSGLEVEL,
|
||||
PREF_MAX_ID
|
||||
};
|
||||
|
||||
const char *
|
||||
tr_prefs_name( int id );
|
||||
|
||||
/* convenience macros and functions for reading pref by id */
|
||||
#define tr_prefs_get( id ) cf_getpref( tr_prefs_name( (id) ) )
|
||||
|
||||
gboolean
|
||||
tr_prefs_get_int( int id, int * val );
|
||||
|
||||
gboolean
|
||||
tr_prefs_get_bool( int id, gboolean * val );
|
||||
|
||||
int
|
||||
tr_prefs_get_int_with_default( int id );
|
||||
|
||||
gboolean
|
||||
tr_prefs_get_bool_with_default( int id );
|
||||
|
||||
#endif
|
|
@ -308,7 +308,9 @@ tr_torrent_new(GObject *backend, const char *torrent, const char *dir,
|
|||
}
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new_with_state(GObject *backend, benc_val_t *state, char **err) {
|
||||
tr_torrent_new_with_state( GObject * backend, benc_val_t * state,
|
||||
guint forcedflags, char ** err)
|
||||
{
|
||||
int ii;
|
||||
benc_val_t *name, *data;
|
||||
char *torrent, *hash, *dir;
|
||||
|
@ -353,6 +355,12 @@ tr_torrent_new_with_state(GObject *backend, benc_val_t *state, char **err) {
|
|||
flags |= TR_TORNEW_LOAD_SAVED;
|
||||
torrent = hash;
|
||||
}
|
||||
forcedflags &= TR_TORNEW_PAUSED | TR_TORNEW_RUNNING;
|
||||
if( forcedflags )
|
||||
{
|
||||
flags &= ~( TR_TORNEW_PAUSED | TR_TORNEW_RUNNING );
|
||||
flags |= forcedflags;
|
||||
}
|
||||
|
||||
return tr_torrent_new(backend, torrent, dir, flags, err);
|
||||
}
|
||||
|
@ -448,20 +456,26 @@ tr_torrent_stop_politely(TrTorrent *tor) {
|
|||
}
|
||||
|
||||
tr_stat_t *
|
||||
tr_torrent_stat_polite(TrTorrent *tor) {
|
||||
TrTorrentClass *klass;
|
||||
tr_stat_t *st;
|
||||
tr_torrent_stat_polite( TrTorrent * tor, gboolean timeout )
|
||||
{
|
||||
TrTorrentClass * klass;
|
||||
tr_stat_t * st;
|
||||
|
||||
if(tor->disposed)
|
||||
return NULL;
|
||||
TR_IS_TORRENT( tor );
|
||||
|
||||
st = tr_torrentStat(tor->handle);
|
||||
if(tor->closing && TR_STATUS_PAUSE & st->status) {
|
||||
tor->closing = FALSE;
|
||||
klass = g_type_class_peek(TR_TORRENT_TYPE);
|
||||
g_signal_emit(tor, klass->paused_signal_id, 0, NULL);
|
||||
return tr_torrent_stat_polite(tor);
|
||||
}
|
||||
if( tor->disposed )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return st;
|
||||
st = tr_torrentStat( tor->handle );
|
||||
if( tor->closing && ( TR_STATUS_PAUSE & st->status || timeout ) )
|
||||
{
|
||||
tor->closing = FALSE;
|
||||
klass = g_type_class_peek( TR_TORRENT_TYPE );
|
||||
g_signal_emit( tor, klass->paused_signal_id, 0, NULL );
|
||||
return tr_torrent_stat_polite( tor, FALSE );
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
* Copyright (c) 2006-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -88,13 +88,14 @@ tr_torrent_new(GObject *backend, const char *torrent, const char *dir,
|
|||
guint flags, char **err);
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new_with_state(GObject *backend, benc_val_t *state, char **err);
|
||||
tr_torrent_new_with_state( GObject * backend, benc_val_t * state,
|
||||
guint flags, char ** err );
|
||||
|
||||
void
|
||||
tr_torrent_stop_politely(TrTorrent *tor);
|
||||
|
||||
tr_stat_t *
|
||||
tr_torrent_stat_polite(TrTorrent *tor);
|
||||
tr_torrent_stat_polite( TrTorrent * tor, gboolean timeout );
|
||||
|
||||
#ifdef TR_WANT_TORRENT_PRIVATE
|
||||
void
|
||||
|
|
|
@ -90,33 +90,8 @@ void
|
|||
tr_window_update( TrWindow * wind, float downspeed, float upspeed );
|
||||
|
||||
/* some evil magic to show the window with a nice initial window size */
|
||||
/* note that the gtk main loop runs in this function */
|
||||
void
|
||||
tr_window_size_hack( TrWindow * wind );
|
||||
|
||||
/* XXX these should be somewhere else */
|
||||
#define ACTF_TOOL ( 1 << 0 ) /* appear in the toolbar */
|
||||
#define ACTF_MENU ( 1 << 1 ) /* appear in the popup menu */
|
||||
#define ACTF_ALWAYS ( 1 << 2 ) /* available regardless of selection */
|
||||
#define ACTF_ACTIVE ( 1 << 3 ) /* available for active torrent */
|
||||
#define ACTF_INACTIVE ( 1 << 4 ) /* available for inactive torrent */
|
||||
/* appear in the toolbar and the popup menu */
|
||||
#define ACTF_WHEREVER ( ACTF_TOOL | ACTF_MENU )
|
||||
/* available if there is something selected */
|
||||
#define ACTF_WHATEVER ( ACTF_ACTIVE | ACTF_INACTIVE )
|
||||
|
||||
/* XXX this too*/
|
||||
#define ACT_ISAVAIL( flags, status ) \
|
||||
( ( ACTF_ACTIVE & (flags) && TR_STATUS_ACTIVE & (status) ) || \
|
||||
( ACTF_INACTIVE & (flags) && TR_STATUS_INACTIVE & (status) ) || \
|
||||
ACTF_ALWAYS & (flags) )
|
||||
|
||||
/* XXX and this */
|
||||
/* model column names */
|
||||
enum {
|
||||
MC_NAME, MC_SIZE, MC_STAT, MC_ERR, MC_TERR,
|
||||
MC_PROG, MC_DRATE, MC_URATE, MC_ETA, MC_PEERS,
|
||||
MC_UPEERS, MC_DPEERS, MC_DOWN, MC_UP,
|
||||
MC_TORRENT, MC_ROW_COUNT,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,9 +3,8 @@ Encoding=UTF-8
|
|||
Version=1.0
|
||||
Name=Transmission
|
||||
Name[ru]=Передача
|
||||
GenericName=BitTorrent Client
|
||||
Type=Application
|
||||
Comment=A free, lightweight client with a simple, intuitive interface
|
||||
Comment=A free, lightweight BitTorrent client with a simple, intuitive interface
|
||||
Exec=transmission-gtk %F
|
||||
TryExec=transmission-gtk
|
||||
Icon=transmission.png
|
||||
|
|
77
gtk/util.c
77
gtk/util.c
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2005-2006 Transmission authors and contributors
|
||||
* Copyright (c) 2005-2007 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -33,6 +33,7 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "tr_prefs.h"
|
||||
#include "tr_torrent.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -65,7 +66,7 @@ static const char *sizestrs[] = {
|
|||
|
||||
char *
|
||||
readablesize(guint64 size) {
|
||||
unsigned int ii;
|
||||
int ii;
|
||||
double small = size;
|
||||
|
||||
for(ii = 0; ii + 1 < ALEN(sizestrs) && 1024.0 <= small / 1024.0; ii++)
|
||||
|
@ -308,34 +309,68 @@ makeglist(void *ptr, ...) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
errmsg(GtkWindow *wind, const char *format, ...) {
|
||||
GtkWidget *dialog;
|
||||
va_list ap;
|
||||
const char *
|
||||
getdownloaddir( void )
|
||||
{
|
||||
static char * wd = NULL;
|
||||
const char * dir;
|
||||
|
||||
va_start(ap, format);
|
||||
dialog = verrmsg(wind, NULL, NULL, format, ap);
|
||||
va_end(ap);
|
||||
dir = tr_prefs_get( PREF_ID_DIR );
|
||||
if( NULL == dir )
|
||||
{
|
||||
if( NULL == wd )
|
||||
{
|
||||
wd = g_new( char, MAX_PATH_LENGTH + 1 );
|
||||
if( NULL == getcwd( wd, MAX_PATH_LENGTH + 1 ) )
|
||||
{
|
||||
strcpy( wd, "." );
|
||||
}
|
||||
}
|
||||
dir = wd;
|
||||
}
|
||||
|
||||
return dialog;
|
||||
return dir;
|
||||
}
|
||||
|
||||
void
|
||||
errmsg( GtkWindow * wind, const char * format, ... )
|
||||
{
|
||||
GtkWidget * dialog;
|
||||
va_list ap;
|
||||
|
||||
va_start( ap, format );
|
||||
dialog = verrmsg_full( wind, NULL, NULL, format, ap );
|
||||
va_end( ap );
|
||||
|
||||
if( NULL != wind && !GTK_WIDGET_MAPPED( GTK_WIDGET( wind ) ) )
|
||||
{
|
||||
g_signal_connect_swapped( wind, "map",
|
||||
G_CALLBACK( gtk_widget_show ), dialog );
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_show( dialog );
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
|
||||
const char *format, ...) {
|
||||
GtkWidget *dialog;
|
||||
va_list ap;
|
||||
errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||
const char * format, ... )
|
||||
{
|
||||
GtkWidget * dialog;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
dialog = verrmsg(wind, func, data, format, ap);
|
||||
va_end(ap);
|
||||
va_start( ap, format );
|
||||
dialog = verrmsg_full( wind, func, data, format, ap );
|
||||
va_end( ap );
|
||||
|
||||
return dialog;
|
||||
return dialog;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
|
||||
const char *format, va_list ap) {
|
||||
verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||
const char * format, va_list ap )
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
char *msg;
|
||||
GList *funcdata;
|
||||
|
@ -355,8 +390,6 @@ verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
|
|||
else
|
||||
funcdata = g_list_append(g_list_append(NULL, func), data);
|
||||
g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
|
||||
if(NULL != wind)
|
||||
gtk_widget_show(dialog);
|
||||
g_free(msg);
|
||||
|
||||
return dialog;
|
||||
|
|
60
gtk/util.h
60
gtk/util.h
|
@ -38,13 +38,36 @@
|
|||
typedef void (*add_torrents_func_t)(void*,void*,GList*,const char*,guint);
|
||||
|
||||
/* return number of items in array */
|
||||
#define ALEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define ISA(o, t) (g_type_is_a(G_OBJECT_TYPE(G_OBJECT(o)), (t)))
|
||||
#define ALEN( a ) ( ( signed )( sizeof(a) / sizeof( (a)[0] ) ) )
|
||||
|
||||
/* used for a callback function with a data parameter */
|
||||
typedef void (*callbackfunc_t)(void*);
|
||||
|
||||
/* flags indicating where and when an action is valid */
|
||||
#define ACTF_TOOL ( 1 << 0 ) /* appear in the toolbar */
|
||||
#define ACTF_MENU ( 1 << 1 ) /* appear in the popup menu */
|
||||
#define ACTF_ALWAYS ( 1 << 2 ) /* available regardless of selection */
|
||||
#define ACTF_ACTIVE ( 1 << 3 ) /* available for active torrent */
|
||||
#define ACTF_INACTIVE ( 1 << 4 ) /* available for inactive torrent */
|
||||
/* appear in the toolbar and the popup menu */
|
||||
#define ACTF_WHEREVER ( ACTF_TOOL | ACTF_MENU )
|
||||
/* available if there is something selected */
|
||||
#define ACTF_WHATEVER ( ACTF_ACTIVE | ACTF_INACTIVE )
|
||||
|
||||
/* checking action flags against torrent status */
|
||||
#define ACT_ISAVAIL( flags, status ) \
|
||||
( ( ACTF_ACTIVE & (flags) && TR_STATUS_ACTIVE & (status) ) || \
|
||||
( ACTF_INACTIVE & (flags) && TR_STATUS_INACTIVE & (status) ) || \
|
||||
ACTF_ALWAYS & (flags) )
|
||||
|
||||
/* column names for the model used to store torrent information */
|
||||
enum {
|
||||
MC_NAME, MC_SIZE, MC_STAT, MC_ERR, MC_TERR,
|
||||
MC_PROG, MC_DRATE, MC_URATE, MC_ETA, MC_PEERS,
|
||||
MC_UPEERS, MC_DPEERS, MC_DOWN, MC_UP,
|
||||
MC_TORRENT, MC_ROW_COUNT,
|
||||
};
|
||||
|
||||
/* try to interpret a string as a textual representation of a boolean */
|
||||
/* note that this isn't localized */
|
||||
gboolean
|
||||
|
@ -101,28 +124,35 @@ addactionname(guint flag);
|
|||
GList *
|
||||
makeglist(void *ptr, ...);
|
||||
|
||||
/* retrieve the global download directory */
|
||||
const char *
|
||||
getdownloaddir( void );
|
||||
|
||||
#ifdef GTK_MAJOR_VERSION
|
||||
|
||||
/* if wind is NULL then you must call gtk_widget_show on the returned widget */
|
||||
|
||||
GtkWidget *
|
||||
errmsg(GtkWindow *wind, const char *format, ...)
|
||||
/* create an error dialog, if wind is NULL or mapped then show dialog now,
|
||||
otherwise show it when wind becomes mapped */
|
||||
void
|
||||
errmsg( GtkWindow * wind, const char * format, ... )
|
||||
#ifdef __GNUC__
|
||||
__attribute__ ((format (printf, 2, 3)))
|
||||
__attribute__ (( format ( printf, 2, 3 ) ))
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
/* create an error dialog but do not gtk_widget_show() it,
|
||||
calls func( data ) when the dialog is closed */
|
||||
GtkWidget *
|
||||
errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
|
||||
const char *format, ...)
|
||||
errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||
const char * format, ... )
|
||||
#ifdef __GNUC__
|
||||
__attribute__ ((format (printf, 4, 5)))
|
||||
__attribute__ (( format ( printf, 4, 5 ) ))
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
/* varargs version of errmsg_full() */
|
||||
GtkWidget *
|
||||
verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
|
||||
const char *format, va_list ap);
|
||||
verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||
const char * format, va_list ap );
|
||||
|
||||
#endif /* GTK_MAJOR_VERSION */
|
||||
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
include ../mk/config.mk
|
||||
include ../mk/common.mk
|
||||
|
||||
SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c tr_backend.c tr_torrent.c \
|
||||
tr_cell_renderer_progress.c tr_window.c util.c
|
||||
SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c tr_backend.c \
|
||||
tr_cell_renderer_progress.c tr_icon.c tr_prefs.c tr_torrent.c \
|
||||
tr_window.c util.c
|
||||
OBJS = $(SRCS:%.c=%.o)
|
||||
|
||||
CFLAGS += $(CFLAGS_GTK) -I../libtransmission
|
||||
|
|
Loading…
Reference in New Issue