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$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -500,7 +500,11 @@ cf_savestate(benc_val_t *state, char **errstr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cf_freestate(benc_val_t *state) {
|
cf_freestate( benc_val_t * state )
|
||||||
tr_bencFree(state);
|
{
|
||||||
g_free(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
|
void
|
||||||
cf_freestate(benc_val_t *state);
|
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 */
|
#endif /* TG_CONF_H */
|
||||||
|
|
478
gtk/dialogs.c
478
gtk/dialogs.c
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* $Id$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -31,26 +31,14 @@
|
||||||
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "dialogs.h"
|
#include "dialogs.h"
|
||||||
#include "transmission.h"
|
#include "tr_icon.h"
|
||||||
|
#include "tr_prefs.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "transmission.h"
|
||||||
|
|
||||||
#define PREFNAME "transmission-dialog-pref-name"
|
#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 {
|
struct addcb {
|
||||||
add_torrents_func_t addfunc;
|
add_torrents_func_t addfunc;
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -68,12 +56,12 @@ struct dirdata
|
||||||
guint flags;
|
guint flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct quitdata
|
||||||
clicklimitbox(GtkWidget *widget, gpointer gdata);
|
{
|
||||||
static void
|
callbackfunc_t func;
|
||||||
freedata(gpointer gdata, GClosure *closure);
|
void * cbdata;
|
||||||
static void
|
};
|
||||||
clickdialog(GtkWidget *widget, int resp, gpointer gdata);
|
|
||||||
static void
|
static void
|
||||||
autoclick(GtkWidget *widget, gpointer gdata);
|
autoclick(GtkWidget *widget, gpointer gdata);
|
||||||
static void
|
static void
|
||||||
|
@ -82,401 +70,8 @@ static void
|
||||||
addresp(GtkWidget *widget, gint resp, gpointer gdata);
|
addresp(GtkWidget *widget, gint resp, gpointer gdata);
|
||||||
static void
|
static void
|
||||||
promptresp( GtkWidget * widget, gint resp, gpointer data );
|
promptresp( GtkWidget * widget, gint resp, gpointer data );
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setupprefwidget(GtkWidget *widget, const char *prefname, ...) {
|
quitresp( GtkWidget * widget, gint resp, gpointer data );
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
makeaddwind(GtkWindow *parent, add_torrents_func_t addfunc, void *cbdata) {
|
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();
|
GtkFileFilter *unfilter = gtk_file_filter_new();
|
||||||
GtkWidget *getdir = gtk_file_chooser_button_new(
|
GtkWidget *getdir = gtk_file_chooser_button_new(
|
||||||
_("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
_("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
||||||
const char *pref;
|
|
||||||
|
|
||||||
data->addfunc = addfunc;
|
data->addfunc = addfunc;
|
||||||
data->data = cbdata;
|
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_box_pack_start_defaults(GTK_BOX(vbox), bbox);
|
||||||
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
|
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 ),
|
||||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
|
getdownloaddir() );
|
||||||
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
|
||||||
gtk_widget_set_sensitive(getdir, 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)
|
for(ii = files; NULL != ii; ii = ii->next)
|
||||||
stupidgtk = g_list_append(stupidgtk, ii->data);
|
stupidgtk = g_list_append(stupidgtk, ii->data);
|
||||||
flags = ( data->autostart ? TR_TORNEW_RUNNING : TR_TORNEW_PAUSED );
|
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 );
|
data->addfunc( data->data, NULL, stupidgtk, dir, flags );
|
||||||
if(NULL != dir)
|
if(NULL != dir)
|
||||||
g_free(dir);
|
g_free(dir);
|
||||||
|
@ -693,7 +287,7 @@ makeinfowind(GtkWindow *parent, TrTorrent *tor) {
|
||||||
|
|
||||||
void
|
void
|
||||||
promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
||||||
GList * files, guint flags, const char * defaultdir )
|
GList * files, guint flags )
|
||||||
{
|
{
|
||||||
struct dirdata * stuff;
|
struct dirdata * stuff;
|
||||||
GtkWidget * wind;
|
GtkWidget * wind;
|
||||||
|
@ -711,7 +305,8 @@ promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
||||||
NULL );
|
NULL );
|
||||||
gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( wind ), TRUE );
|
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_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_signal_connect( G_OBJECT( wind ), "response",
|
||||||
G_CALLBACK( promptresp ), stuff );
|
G_CALLBACK( promptresp ), stuff );
|
||||||
|
@ -740,3 +335,40 @@ promptresp( GtkWidget * widget, gint resp, gpointer data )
|
||||||
g_free( stuff );
|
g_free( stuff );
|
||||||
gtk_widget_destroy( widget );
|
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 */
|
/* prompt for a download directory for torrents, then add them */
|
||||||
void
|
void
|
||||||
promptfordir( GtkWindow * parent, add_torrents_func_t addfunc, void *cbdata,
|
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 */
|
#endif /* TG_PREFS_H */
|
||||||
|
|
138
gtk/ipc.c
138
gtk/ipc.c
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* $Id$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -40,6 +40,7 @@
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
|
#include "tr_prefs.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define PROTOVERS 1 /* IPC protocol version */
|
#define PROTOVERS 1 /* IPC protocol version */
|
||||||
|
@ -48,20 +49,26 @@
|
||||||
#define MSG_VERSION ("version")
|
#define MSG_VERSION ("version")
|
||||||
/* list of strings, full paths to torrent files to load */
|
/* list of strings, full paths to torrent files to load */
|
||||||
#define MSG_ADDFILES ("addfiles")
|
#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 {
|
struct constate_serv {
|
||||||
void *wind;
|
void *wind;
|
||||||
add_torrents_func_t addfunc;
|
add_torrents_func_t addfunc;
|
||||||
|
callbackfunc_t quitfunc;
|
||||||
void *cbdata;
|
void *cbdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct constate_addfile {
|
enum client_cmd { CCMD_ADD, CCMD_QUIT };
|
||||||
|
|
||||||
|
struct constate_client {
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
enum client_cmd cmd;
|
||||||
GList *files;
|
GList *files;
|
||||||
gboolean *succeeded;
|
gboolean *succeeded;
|
||||||
unsigned int addid;
|
unsigned int msgid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct constate;
|
struct constate;
|
||||||
|
@ -75,14 +82,10 @@ struct constate {
|
||||||
enum contype type;
|
enum contype type;
|
||||||
union {
|
union {
|
||||||
struct constate_serv serv;
|
struct constate_serv serv;
|
||||||
struct constate_addfile addfile;
|
struct constate_client client;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
|
||||||
ipc_socket_setup(void *parent, add_torrents_func_t addfunc, void *cbdata);
|
|
||||||
gboolean
|
|
||||||
ipc_sendfiles_blocking(GList *files);
|
|
||||||
static void
|
static void
|
||||||
serv_bind(struct constate *con);
|
serv_bind(struct constate *con);
|
||||||
static void
|
static void
|
||||||
|
@ -105,16 +108,19 @@ all_io_closed(GSource *source, void *vdata);
|
||||||
static void
|
static void
|
||||||
srv_addfile(struct constate *con, const char *name, benc_val_t *val);
|
srv_addfile(struct constate *con, const char *name, benc_val_t *val);
|
||||||
static void
|
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);
|
afc_version(struct constate *con, const char *name, benc_val_t *val);
|
||||||
static void
|
static void
|
||||||
afc_io_sent(GSource *source, unsigned int id, void *vdata);
|
afc_io_sent(GSource *source, unsigned int id, void *vdata);
|
||||||
|
|
||||||
static const struct handlerdef gl_funcs_serv[] = {
|
static const struct handlerdef gl_funcs_serv[] = {
|
||||||
{MSG_ADDFILES, srv_addfile},
|
{MSG_ADDFILES, srv_addfile},
|
||||||
|
{MSG_QUIT, srv_quit},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct handlerdef gl_funcs_addfile[] = {
|
static const struct handlerdef gl_funcs_client[] = {
|
||||||
{MSG_VERSION, afc_version},
|
{MSG_VERSION, afc_version},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@ -123,7 +129,9 @@ static const struct handlerdef gl_funcs_addfile[] = {
|
||||||
static char *gl_sockpath = NULL;
|
static char *gl_sockpath = NULL;
|
||||||
|
|
||||||
void
|
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;
|
struct constate *con;
|
||||||
|
|
||||||
con = g_new0(struct constate, 1);
|
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->type = CON_SERV;
|
||||||
con->u.serv.wind = parent;
|
con->u.serv.wind = parent;
|
||||||
con->u.serv.addfunc = addfunc;
|
con->u.serv.addfunc = addfunc;
|
||||||
|
con->u.serv.quitfunc = quitfunc;
|
||||||
con->u.serv.cbdata = cbdata;
|
con->u.serv.cbdata = cbdata;
|
||||||
|
|
||||||
serv_bind(con);
|
serv_bind(con);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static gboolean
|
||||||
ipc_sendfiles_blocking(GList *files) {
|
blocking_client( enum client_cmd cmd, GList * files )
|
||||||
|
{
|
||||||
|
|
||||||
struct constate *con;
|
struct constate *con;
|
||||||
char *path;
|
char *path;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
@ -147,12 +158,13 @@ ipc_sendfiles_blocking(GList *files) {
|
||||||
con = g_new0(struct constate, 1);
|
con = g_new0(struct constate, 1);
|
||||||
con->source = NULL;
|
con->source = NULL;
|
||||||
con->fd = -1;
|
con->fd = -1;
|
||||||
con->funcs = gl_funcs_addfile;
|
con->funcs = gl_funcs_client;
|
||||||
con->type = CON_ADDFILE;
|
con->type = CON_CLIENT;
|
||||||
con->u.addfile.loop = g_main_loop_new(NULL, TRUE);
|
con->u.client.loop = g_main_loop_new(NULL, TRUE);
|
||||||
con->u.addfile.files = files;
|
con->u.client.cmd = cmd;
|
||||||
con->u.addfile.succeeded = &ret;
|
con->u.client.files = files;
|
||||||
con->u.addfile.addid = 0;
|
con->u.client.succeeded = &ret;
|
||||||
|
con->u.client.msgid = 0;
|
||||||
|
|
||||||
path = cf_sockname();
|
path = cf_sockname();
|
||||||
if(!client_connect(path, con)) {
|
if(!client_connect(path, con)) {
|
||||||
|
@ -161,11 +173,23 @@ ipc_sendfiles_blocking(GList *files) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_main_loop_run(con->u.addfile.loop);
|
g_main_loop_run(con->u.client.loop);
|
||||||
|
|
||||||
return ret;
|
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 */
|
/* open a local socket for clients connections */
|
||||||
static void
|
static void
|
||||||
serv_bind(struct constate *con) {
|
serv_bind(struct constate *con) {
|
||||||
|
@ -356,9 +380,9 @@ destroycon(struct constate *con) {
|
||||||
switch(con->type) {
|
switch(con->type) {
|
||||||
case CON_SERV:
|
case CON_SERV:
|
||||||
break;
|
break;
|
||||||
case CON_ADDFILE:
|
case CON_CLIENT:
|
||||||
freestrlist(con->u.addfile.files);
|
freestrlist(con->u.client.files);
|
||||||
g_main_loop_quit(con->u.addfile.loop);
|
g_main_loop_quit(con->u.client.loop);
|
||||||
break;
|
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;
|
struct constate_serv *srv = &con->u.serv;
|
||||||
GList *files;
|
GList *files;
|
||||||
int ii;
|
int ii;
|
||||||
|
guint flags;
|
||||||
|
|
||||||
if(TYPE_LIST == val->type) {
|
if(TYPE_LIST == val->type) {
|
||||||
files = NULL;
|
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 */
|
/* XXX somehow escape invalid utf-8 */
|
||||||
g_utf8_validate(val->val.l.vals[ii].val.s.s, -1, NULL))
|
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);
|
files = g_list_append(files, val->val.l.vals[ii].val.s.s);
|
||||||
srv->addfunc(srv->cbdata, NULL, files, NULL,
|
flags = addactionflag( tr_prefs_get( PREF_ID_ADDIPC ) );
|
||||||
addactionflag(cf_getpref(PREF_ADDIPC)));
|
srv->addfunc( srv->cbdata, NULL, files, NULL, flags );
|
||||||
g_list_free(files);
|
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
|
static void
|
||||||
afc_version(struct constate *con, const char *name SHUTUP, benc_val_t *val) {
|
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;
|
GList *file;
|
||||||
benc_val_t list, *str;
|
benc_val_t list, *str;
|
||||||
|
|
||||||
if(TYPE_INT != val->type || PROTOVERS != val->val.i) {
|
if(TYPE_INT != val->type || PROTOVERS != val->val.i) {
|
||||||
fprintf(stderr, _("bad IPC protocol version\n"));
|
fprintf(stderr, _("bad IPC protocol version\n"));
|
||||||
destroycon(con);
|
destroycon(con);
|
||||||
} else {
|
return;
|
||||||
/* XXX handle getting a non-version tag, invalid data,
|
}
|
||||||
or nothing (read timeout) */
|
|
||||||
bzero(&list, sizeof(list));
|
/* XXX handle getting a non-version tag, invalid data,
|
||||||
list.type = TYPE_LIST;
|
or nothing (read timeout) */
|
||||||
list.val.l.alloc = g_list_length(afc->files);
|
switch( afc->cmd )
|
||||||
list.val.l.vals = g_new0(benc_val_t, list.val.l.alloc);
|
{
|
||||||
for(file = afc->files; NULL != file; file = file->next) {
|
case CCMD_ADD:
|
||||||
str = list.val.l.vals + list.val.l.count;
|
list.type = TYPE_LIST;
|
||||||
str->type = TYPE_STR;
|
list.val.l.alloc = g_list_length(afc->files);
|
||||||
str->val.s.i = strlen(file->data);
|
list.val.l.count = 0;
|
||||||
str->val.s.s = file->data;
|
list.val.l.vals = g_new0(benc_val_t, list.val.l.alloc);
|
||||||
list.val.l.count++;
|
for(file = afc->files; NULL != file; file = file->next) {
|
||||||
}
|
str = list.val.l.vals + list.val.l.count;
|
||||||
g_list_free(afc->files);
|
str->type = TYPE_STR;
|
||||||
afc->files = NULL;
|
str->val.s.i = strlen(file->data);
|
||||||
afc->addid = send_msg(con, MSG_ADDFILES, &list);
|
str->val.s.s = file->data;
|
||||||
tr_bencFree(&list);
|
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
|
static void
|
||||||
afc_io_sent(GSource *source SHUTUP, unsigned int id, void *vdata) {
|
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;
|
*(afc->succeeded) = TRUE;
|
||||||
destroycon(vdata);
|
destroycon(vdata);
|
||||||
}
|
}
|
||||||
|
|
10
gtk/ipc.h
10
gtk/ipc.h
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* $Id$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -28,9 +28,13 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
void
|
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
|
gboolean
|
||||||
ipc_sendfiles_blocking(GList *files);
|
ipc_sendfiles_blocking( GList * files );
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ipc_sendquit_blocking( void );
|
||||||
|
|
||||||
#endif /* TG_IPC_H */
|
#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$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "msgwin.h"
|
#include "msgwin.h"
|
||||||
|
#include "tr_prefs.h"
|
||||||
#include "transmission.h"
|
#include "transmission.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -60,8 +61,7 @@ msgwin_create( void ) {
|
||||||
GtkWidget * win, * vbox, * scroll, * text;
|
GtkWidget * win, * vbox, * scroll, * text;
|
||||||
GtkWidget * frame, * bbox, * save, * clear, * menu;
|
GtkWidget * frame, * bbox, * save, * clear, * menu;
|
||||||
PangoFontDescription * desc;
|
PangoFontDescription * desc;
|
||||||
unsigned int ii;
|
int ii, curlevel;
|
||||||
int curlevel;
|
|
||||||
|
|
||||||
if( NULL == textbuf )
|
if( NULL == textbuf )
|
||||||
textbuf = gtk_text_buffer_new( NULL );
|
textbuf = gtk_text_buffer_new( NULL );
|
||||||
|
@ -126,7 +126,7 @@ changelevel( GtkWidget * widget, gpointer data SHUTUP ) {
|
||||||
if( 0 <= index && (int) ALEN( levels ) > index &&
|
if( 0 <= index && (int) ALEN( levels ) > index &&
|
||||||
tr_getMessageLevel() != levels[index].id ) {
|
tr_getMessageLevel() != levels[index].id ) {
|
||||||
tr_setMessageLevel( 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 );
|
cf_saveprefs( &ignored );
|
||||||
g_free( ignored );
|
g_free( ignored );
|
||||||
msgwin_update();
|
msgwin_update();
|
||||||
|
@ -196,10 +196,10 @@ doclear( GtkWidget * widget SHUTUP, gpointer data SHUTUP ) {
|
||||||
void
|
void
|
||||||
msgwin_loadpref( void ) {
|
msgwin_loadpref( void ) {
|
||||||
const char * pref;
|
const char * pref;
|
||||||
unsigned int ii;
|
int ii;
|
||||||
|
|
||||||
tr_setMessageQueuing( 1 );
|
tr_setMessageQueuing( 1 );
|
||||||
pref = cf_getpref( PREF_MSGLEVEL );
|
pref = tr_prefs_get( PREF_ID_MSGLEVEL );
|
||||||
if( NULL == pref )
|
if( NULL == pref )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -216,9 +216,8 @@ msgwin_update( void ) {
|
||||||
tr_msg_list_t * msgs, * ii;
|
tr_msg_list_t * msgs, * ii;
|
||||||
GtkTextIter iter, front;
|
GtkTextIter iter, front;
|
||||||
char * label, * line;
|
char * label, * line;
|
||||||
int count;
|
int count, jj;
|
||||||
struct tm * tm;
|
struct tm * tm;
|
||||||
unsigned int jj;
|
|
||||||
|
|
||||||
if( NULL == textbuf )
|
if( NULL == textbuf )
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* $Id$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -220,7 +220,9 @@ tr_backend_save_state(TrBackend *back, char **errstr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *
|
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;
|
GList *ret = NULL;
|
||||||
int ii;
|
int ii;
|
||||||
TrTorrent *tor;
|
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++) {
|
for(ii = 0; ii < state->val.l.count; ii++) {
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
tor = tr_torrent_new_with_state(G_OBJECT(back), state->val.l.vals + ii,
|
tor = tr_torrent_new_with_state( G_OBJECT( back ), state->val.l.vals + ii,
|
||||||
&errstr);
|
flags, &errstr );
|
||||||
if(NULL != errstr)
|
if(NULL != errstr)
|
||||||
*errors = g_list_append(*errors, errstr);
|
*errors = g_list_append(*errors, errstr);
|
||||||
if(NULL != tor)
|
if(NULL != tor)
|
||||||
|
@ -273,20 +275,25 @@ tr_backend_stop_torrents(TrBackend *back) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
tr_backend_torrents_stopped(TrBackend *back) {
|
tr_backend_torrents_stopped( TrBackend * back, gboolean timeout )
|
||||||
GList *ii, *list;
|
{
|
||||||
tr_stat_t *st;
|
GList * ii, * list;
|
||||||
gboolean ret = TRUE;
|
tr_stat_t * st;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
TR_IS_BACKEND(back);
|
TR_IS_BACKEND( back );
|
||||||
|
|
||||||
list = g_list_copy(back->torrents);
|
ret = TRUE;
|
||||||
for(ii = list; NULL != ii; ii = ii->next) {
|
list = g_list_copy( back->torrents );
|
||||||
st = tr_torrent_stat_polite(ii->data);
|
for( ii = list; NULL != ii; ii = ii->next )
|
||||||
if(NULL == st || !(TR_STATUS_PAUSE & st->status))
|
{
|
||||||
ret = FALSE;
|
st = tr_torrent_stat_polite( ii->data, timeout );
|
||||||
}
|
if( NULL == st || !( TR_STATUS_PAUSE & st->status ) )
|
||||||
g_list_free(list);
|
{
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_list_free( list );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* $Id$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -70,13 +70,14 @@ void
|
||||||
tr_backend_save_state(TrBackend *back, char **errstr);
|
tr_backend_save_state(TrBackend *back, char **errstr);
|
||||||
|
|
||||||
GList *
|
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
|
void
|
||||||
tr_backend_stop_torrents(TrBackend *back);
|
tr_backend_stop_torrents(TrBackend *back);
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
tr_backend_torrents_stopped(TrBackend *back);
|
tr_backend_torrents_stopped( TrBackend * back, gboolean timeout );
|
||||||
|
|
||||||
#ifdef TR_WANT_BACKEND_PRIVATE
|
#ifdef TR_WANT_BACKEND_PRIVATE
|
||||||
void
|
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 *
|
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;
|
int ii;
|
||||||
benc_val_t *name, *data;
|
benc_val_t *name, *data;
|
||||||
char *torrent, *hash, *dir;
|
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;
|
flags |= TR_TORNEW_LOAD_SAVED;
|
||||||
torrent = hash;
|
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);
|
return tr_torrent_new(backend, torrent, dir, flags, err);
|
||||||
}
|
}
|
||||||
|
@ -448,20 +456,26 @@ tr_torrent_stop_politely(TrTorrent *tor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_stat_t *
|
tr_stat_t *
|
||||||
tr_torrent_stat_polite(TrTorrent *tor) {
|
tr_torrent_stat_polite( TrTorrent * tor, gboolean timeout )
|
||||||
TrTorrentClass *klass;
|
{
|
||||||
tr_stat_t *st;
|
TrTorrentClass * klass;
|
||||||
|
tr_stat_t * st;
|
||||||
|
|
||||||
if(tor->disposed)
|
TR_IS_TORRENT( tor );
|
||||||
return NULL;
|
|
||||||
|
|
||||||
st = tr_torrentStat(tor->handle);
|
if( tor->disposed )
|
||||||
if(tor->closing && TR_STATUS_PAUSE & st->status) {
|
{
|
||||||
tor->closing = FALSE;
|
return NULL;
|
||||||
klass = g_type_class_peek(TR_TORRENT_TYPE);
|
}
|
||||||
g_signal_emit(tor, klass->paused_signal_id, 0, NULL);
|
|
||||||
return tr_torrent_stat_polite(tor);
|
|
||||||
}
|
|
||||||
|
|
||||||
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$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* 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);
|
guint flags, char **err);
|
||||||
|
|
||||||
TrTorrent *
|
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
|
void
|
||||||
tr_torrent_stop_politely(TrTorrent *tor);
|
tr_torrent_stop_politely(TrTorrent *tor);
|
||||||
|
|
||||||
tr_stat_t *
|
tr_stat_t *
|
||||||
tr_torrent_stat_polite(TrTorrent *tor);
|
tr_torrent_stat_polite( TrTorrent * tor, gboolean timeout );
|
||||||
|
|
||||||
#ifdef TR_WANT_TORRENT_PRIVATE
|
#ifdef TR_WANT_TORRENT_PRIVATE
|
||||||
void
|
void
|
||||||
|
|
|
@ -90,33 +90,8 @@ void
|
||||||
tr_window_update( TrWindow * wind, float downspeed, float upspeed );
|
tr_window_update( TrWindow * wind, float downspeed, float upspeed );
|
||||||
|
|
||||||
/* some evil magic to show the window with a nice initial window size */
|
/* some evil magic to show the window with a nice initial window size */
|
||||||
|
/* note that the gtk main loop runs in this function */
|
||||||
void
|
void
|
||||||
tr_window_size_hack( TrWindow * wind );
|
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
|
#endif
|
||||||
|
|
|
@ -3,9 +3,8 @@ Encoding=UTF-8
|
||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Transmission
|
Name=Transmission
|
||||||
Name[ru]=Передача
|
Name[ru]=Передача
|
||||||
GenericName=BitTorrent Client
|
|
||||||
Type=Application
|
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
|
Exec=transmission-gtk %F
|
||||||
TryExec=transmission-gtk
|
TryExec=transmission-gtk
|
||||||
Icon=transmission.png
|
Icon=transmission.png
|
||||||
|
|
77
gtk/util.c
77
gtk/util.c
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* $Id$
|
* $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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "tr_prefs.h"
|
||||||
#include "tr_torrent.h"
|
#include "tr_torrent.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ static const char *sizestrs[] = {
|
||||||
|
|
||||||
char *
|
char *
|
||||||
readablesize(guint64 size) {
|
readablesize(guint64 size) {
|
||||||
unsigned int ii;
|
int ii;
|
||||||
double small = size;
|
double small = size;
|
||||||
|
|
||||||
for(ii = 0; ii + 1 < ALEN(sizestrs) && 1024.0 <= small / 1024.0; ii++)
|
for(ii = 0; ii + 1 < ALEN(sizestrs) && 1024.0 <= small / 1024.0; ii++)
|
||||||
|
@ -308,34 +309,68 @@ makeglist(void *ptr, ...) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *
|
const char *
|
||||||
errmsg(GtkWindow *wind, const char *format, ...) {
|
getdownloaddir( void )
|
||||||
GtkWidget *dialog;
|
{
|
||||||
va_list ap;
|
static char * wd = NULL;
|
||||||
|
const char * dir;
|
||||||
|
|
||||||
va_start(ap, format);
|
dir = tr_prefs_get( PREF_ID_DIR );
|
||||||
dialog = verrmsg(wind, NULL, NULL, format, ap);
|
if( NULL == dir )
|
||||||
va_end(ap);
|
{
|
||||||
|
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 *
|
GtkWidget *
|
||||||
errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
|
errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||||
const char *format, ...) {
|
const char * format, ... )
|
||||||
GtkWidget *dialog;
|
{
|
||||||
va_list ap;
|
GtkWidget * dialog;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start( ap, format );
|
||||||
dialog = verrmsg(wind, func, data, format, ap);
|
dialog = verrmsg_full( wind, func, data, format, ap );
|
||||||
va_end(ap);
|
va_end( ap );
|
||||||
|
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
|
verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||||
const char *format, va_list ap) {
|
const char * format, va_list ap )
|
||||||
|
{
|
||||||
GtkWidget *dialog;
|
GtkWidget *dialog;
|
||||||
char *msg;
|
char *msg;
|
||||||
GList *funcdata;
|
GList *funcdata;
|
||||||
|
@ -355,8 +390,6 @@ verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
|
||||||
else
|
else
|
||||||
funcdata = g_list_append(g_list_append(NULL, func), data);
|
funcdata = g_list_append(g_list_append(NULL, func), data);
|
||||||
g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
|
g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
|
||||||
if(NULL != wind)
|
|
||||||
gtk_widget_show(dialog);
|
|
||||||
g_free(msg);
|
g_free(msg);
|
||||||
|
|
||||||
return dialog;
|
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);
|
typedef void (*add_torrents_func_t)(void*,void*,GList*,const char*,guint);
|
||||||
|
|
||||||
/* return number of items in array */
|
/* return number of items in array */
|
||||||
#define ALEN(a) (sizeof(a) / sizeof((a)[0]))
|
#define ALEN( a ) ( ( signed )( sizeof(a) / sizeof( (a)[0] ) ) )
|
||||||
|
|
||||||
#define ISA(o, t) (g_type_is_a(G_OBJECT_TYPE(G_OBJECT(o)), (t)))
|
|
||||||
|
|
||||||
/* used for a callback function with a data parameter */
|
/* used for a callback function with a data parameter */
|
||||||
typedef void (*callbackfunc_t)(void*);
|
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 */
|
/* try to interpret a string as a textual representation of a boolean */
|
||||||
/* note that this isn't localized */
|
/* note that this isn't localized */
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -101,28 +124,35 @@ addactionname(guint flag);
|
||||||
GList *
|
GList *
|
||||||
makeglist(void *ptr, ...);
|
makeglist(void *ptr, ...);
|
||||||
|
|
||||||
|
/* retrieve the global download directory */
|
||||||
|
const char *
|
||||||
|
getdownloaddir( void );
|
||||||
|
|
||||||
#ifdef GTK_MAJOR_VERSION
|
#ifdef GTK_MAJOR_VERSION
|
||||||
|
|
||||||
/* if wind is NULL then you must call gtk_widget_show on the returned widget */
|
/* create an error dialog, if wind is NULL or mapped then show dialog now,
|
||||||
|
otherwise show it when wind becomes mapped */
|
||||||
GtkWidget *
|
void
|
||||||
errmsg(GtkWindow *wind, const char *format, ...)
|
errmsg( GtkWindow * wind, const char * format, ... )
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
__attribute__ ((format (printf, 2, 3)))
|
__attribute__ (( format ( printf, 2, 3 ) ))
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* create an error dialog but do not gtk_widget_show() it,
|
||||||
|
calls func( data ) when the dialog is closed */
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
|
errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||||
const char *format, ...)
|
const char * format, ... )
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
__attribute__ ((format (printf, 4, 5)))
|
__attribute__ (( format ( printf, 4, 5 ) ))
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* varargs version of errmsg_full() */
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
|
verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
|
||||||
const char *format, va_list ap);
|
const char * format, va_list ap );
|
||||||
|
|
||||||
#endif /* GTK_MAJOR_VERSION */
|
#endif /* GTK_MAJOR_VERSION */
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
include ../mk/config.mk
|
include ../mk/config.mk
|
||||||
include ../mk/common.mk
|
include ../mk/common.mk
|
||||||
|
|
||||||
SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c tr_backend.c tr_torrent.c \
|
SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c tr_backend.c \
|
||||||
tr_cell_renderer_progress.c tr_window.c util.c
|
tr_cell_renderer_progress.c tr_icon.c tr_prefs.c tr_torrent.c \
|
||||||
|
tr_window.c util.c
|
||||||
OBJS = $(SRCS:%.c=%.o)
|
OBJS = $(SRCS:%.c=%.o)
|
||||||
|
|
||||||
CFLAGS += $(CFLAGS_GTK) -I../libtransmission
|
CFLAGS += $(CFLAGS_GTK) -I../libtransmission
|
||||||
|
|
Loading…
Reference in New Issue