(gtk) new "add torrent" popup to let users choose which files to download, file priority, add paused, delete source .torrent, etc

This commit is contained in:
Charles Kerr 2008-02-13 03:00:21 +00:00
parent e581d5228e
commit 85c49dbbee
18 changed files with 672 additions and 793 deletions

View File

@ -23,6 +23,7 @@ noinst_HEADERS = \
logo.h \
makemeta-ui.h \
msgwin.h \
open.h \
stats.h \
sexy-icon-entry.h \
torrent-cell-renderer.h \
@ -48,6 +49,7 @@ transmission_SOURCES = \
main.c \
makemeta-ui.c \
msgwin.c \
open.c \
sexy-icon-entry.c \
stats.c \
torrent-cell-renderer.c \

View File

@ -22,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
@ -36,186 +31,62 @@
#include "dialogs.h"
#include "hig.h"
#include "tr_core.h"
#include "tr_icon.h"
#include "tr_prefs.h"
#include "util.h"
#define UPDATE_INTERVAL 1000
#define PREFNAME "transmission-dialog-pref-name"
#define FILESWIND_EXTRA_INDENT 4
#define STRIPROOT( path ) \
( g_path_is_absolute( (path) ) ? g_path_skip_root( (path) ) : (path) )
struct addcb
{
GtkWidget * widget;
TrCore * core;
gboolean autostart;
gboolean usingaltdir;
GtkFileChooser *altdir;
GtkButtonBox *altbox;
};
struct dirdata
{
GtkWidget * widget;
TrCore * core;
GList * files;
uint8_t * data;
size_t size;
enum tr_torrent_action action;
gboolean paused;
GtkWidget * widget;
TrCore * core;
GList * files;
tr_ctor * ctor;
};
static void
addwindnocore( gpointer gdata, GObject * core );
static void
autoclick(GtkWidget *widget, gpointer gdata);
static void
dirclick(GtkWidget *widget, gpointer gdata);
static void
addresp(GtkWidget *widget, gint resp, gpointer gdata);
static void
promptdirnocore( gpointer gdata, GObject * core );
static void
promptresp( GtkWidget * widget, gint resp, gpointer data );
void
makeaddwind( GtkWindow * parent, TrCore * core )
promptdirnocore( gpointer gdata, GObject * core UNUSED )
{
GtkWidget *wind = gtk_file_chooser_dialog_new(_("Open Torrent"), parent,
GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
struct addcb *data = g_new(struct addcb, 1);
GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
GtkWidget *bbox = gtk_hbutton_box_new();
GtkWidget *autocheck = gtk_check_button_new_with_mnemonic(
_("Automatically _start torrent"));
GtkWidget *dircheck = gtk_check_button_new_with_mnemonic(
_("Use alternate _download directory"));
GtkFileFilter *filter = gtk_file_filter_new();
GtkFileFilter *unfilter = gtk_file_filter_new();
GtkWidget *getdir = gtk_file_chooser_button_new(
_("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
char * pref;
data->widget = wind;
data->core = core;
data->autostart = TRUE;
data->usingaltdir = FALSE;
data->altdir = GTK_FILE_CHOOSER(getdir);
data->altbox = GTK_BUTTON_BOX(bbox);
g_object_weak_ref( G_OBJECT( core ), addwindnocore, data );
gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
pref = pref_string_get( PREF_KEY_DIR_DEFAULT );
if( pref != NULL ) {
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( wind ), pref );
g_free( pref );
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
gtk_widget_set_sensitive(getdir, FALSE);
gtk_file_filter_set_name(filter, _("Torrent files"));
gtk_file_filter_add_pattern(filter, "*.torrent");
gtk_file_filter_set_name(unfilter, _("All files"));
gtk_file_filter_add_pattern(unfilter, "*");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
gtk_widget_show_all(wind);
}
void
addwindnocore( gpointer gdata, GObject * core UNUSED )
{
struct addcb * data = gdata;
struct dirdata * stuff = gdata;
/* prevent the response callback from trying to remove the weak
reference which no longer exists */
data->core = NULL;
stuff->core = NULL;
gtk_dialog_response( GTK_DIALOG( data->widget ), GTK_RESPONSE_NONE );
gtk_dialog_response( GTK_DIALOG( stuff->widget ), GTK_RESPONSE_NONE );
}
static void
autoclick(GtkWidget *widget, gpointer gdata) {
struct addcb *data = gdata;
promptresp( GtkWidget * widget, gint resp, gpointer data )
{
struct dirdata * stuff;
data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
stuff = data;
static void
dirclick(GtkWidget *widget, gpointer gdata) {
struct addcb *data = gdata;
data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
gtk_widget_set_sensitive(GTK_WIDGET(data->altdir), data->usingaltdir);
}
static void
addresp(GtkWidget *widget, gint resp, gpointer gdata) {
struct addcb *data = gdata;
GSList *files, *ii;
GList *stupidgtk;
char *dir;
enum tr_torrent_action action;
if(GTK_RESPONSE_ACCEPT == resp) {
dir = NULL;
if(data->usingaltdir)
dir = gtk_file_chooser_get_filename(data->altdir);
files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
action = tr_prefs_get_action( PREF_KEY_ADDSTD );
if( NULL == dir )
if( GTK_RESPONSE_ACCEPT == resp )
{
stupidgtk = NULL;
for( ii = files; NULL != ii; ii = ii->next )
{
stupidgtk = g_list_append( stupidgtk, ii->data );
}
tr_core_add_list( data->core, stupidgtk, action, !data->autostart );
freestrlist(stupidgtk);
}
else
{
for( ii = files; NULL != ii; ii = ii->next )
{
tr_core_add_dir( data->core, ii->data, dir,
action, !data->autostart );
g_free( ii->data );
}
char * dir;
GList * l;
/* update the destination */
dir = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( widget ) );
tr_ctorSetDestination( stuff->ctor, TR_FORCE, dir );
g_free( dir );
/* if there's metainfo in the ctor already, use it */
if( !tr_ctorGetMetainfo( stuff->ctor, NULL ) )
tr_core_add_ctor( stuff->core, stuff->ctor );
/* if there's a list of files, use them too */
for( l=stuff->files; l!=NULL; l=l->next )
if( !tr_ctorSetMetainfoFromFile( stuff->ctor, l->data ) )
tr_core_add_ctor( stuff->core, stuff->ctor );
}
tr_core_torrents_added( data->core );
g_slist_free(files);
}
if( NULL != data->core )
{
g_object_weak_unref( G_OBJECT( data->core ), addwindnocore, data );
}
if( stuff->core )
g_object_weak_unref( G_OBJECT( stuff->core ), promptdirnocore, stuff );
g_free( data );
gtk_widget_destroy(widget);
gtk_widget_destroy( widget );
freestrlist( stuff->files );
tr_ctorFree( stuff->ctor );
g_free( stuff );
}
void
@ -234,28 +105,32 @@ fmtpeercount( GtkLabel * label, int count )
}
}
void
promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data,
size_t size, enum tr_torrent_action act, gboolean paused )
static void
deleteToggled( GtkToggleButton * tb, gpointer ctor )
{
char * path;
tr_ctorSetDeleteSource( ctor, gtk_toggle_button_get_active( tb ) );
}
static void
startToggled( GtkToggleButton * tb, gpointer ctor )
{
tr_ctorSetPaused( ctor, TR_FORCE, !gtk_toggle_button_get_active( tb ) );
}
void
promptfordir( GtkWindow * parent, TrCore * core, GList * files, tr_ctor * ctor )
{
uint8_t flag = 0;
const char * str;
struct dirdata * stuff;
GtkWidget * wind;
GtkWidget * v;
GtkWidget * w;
stuff = g_new0( struct dirdata, 1 );
stuff->core = core;
if( NULL != files )
{
stuff->files = dupstrlist( files );
}
if( NULL != data )
{
stuff->data = g_new( uint8_t, size );
memcpy( stuff->data, data, size );
stuff->size = size;
}
stuff->action = act;
stuff->paused = paused;
stuff->core = core;
stuff->ctor = ctor;
stuff->files = dupstrlist( files );
g_object_weak_ref( G_OBJECT( core ), promptdirnocore, stuff );
@ -266,9 +141,24 @@ promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data,
NULL );
gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( wind ), TRUE );
gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( wind ), FALSE );
path = getdownloaddir( );
gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ), path );
g_free( path );
tr_ctorGetDestination( ctor, TR_FORCE, &str );
gtk_file_chooser_set_uri( GTK_FILE_CHOOSER( wind ), str );
v = gtk_vbox_new( FALSE, GUI_PAD );
w = gtk_check_button_new_with_mnemonic( _( "_Delete original torrent file" ) );
g_signal_connect( w, "toggled", G_CALLBACK( deleteToggled ), ctor );
tr_ctorGetDeleteSource( ctor, &flag );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
w = gtk_check_button_new_with_mnemonic( _( "_Start when added" ) );
g_signal_connect( w, "toggled", G_CALLBACK( startToggled ), ctor );
tr_ctorGetPaused( ctor, TR_FORCE, &flag );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( wind ), v );
stuff->widget = wind;
@ -278,57 +168,6 @@ promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data,
gtk_widget_show_all(wind);
}
void
promptdirnocore( gpointer gdata, GObject * core UNUSED )
{
struct dirdata * stuff = gdata;
/* prevent the response callback from trying to remove the weak
reference which no longer exists */
stuff->core = NULL;
gtk_dialog_response( GTK_DIALOG( stuff->widget ), GTK_RESPONSE_NONE );
}
static void
promptresp( GtkWidget * widget, gint resp, gpointer data )
{
struct dirdata * stuff;
char * dir;
GList * ii;
stuff = data;
if( GTK_RESPONSE_ACCEPT == resp )
{
dir = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( widget ) );
/* it seems that we will always get a directory */
g_assert( NULL != dir );
for( ii = g_list_first( stuff->files ); NULL != ii; ii = ii->next )
{
tr_core_add_dir( stuff->core, ii->data, dir,
stuff->action, stuff->paused );
}
if( NULL != stuff->data )
{
tr_core_add_data_dir( stuff->core, stuff->data, stuff->size, dir,
stuff->paused );
}
tr_core_torrents_added( stuff->core );
g_free( dir );
}
if( NULL != stuff->core )
{
g_object_weak_unref( G_OBJECT( stuff->core ), promptdirnocore, stuff );
}
freestrlist( stuff->files );
g_free( stuff->data );
g_free( stuff );
gtk_widget_destroy( widget );
}
/***
****
***/
@ -345,9 +184,11 @@ static void
quitresp( GtkWidget * widget, int response, gpointer data )
{
struct quitdata * stuff = data;
GtkToggleButton * tb = GTK_TOGGLE_BUTTON( stuff->dontask );
pref_flag_set( PREF_KEY_ASKQUIT,
!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(stuff->dontask) ) );
tr_core_set_pref_bool( stuff->core,
PREF_KEY_ASKQUIT,
!gtk_toggle_button_get_active( tb ) );
if( response == GTK_RESPONSE_ACCEPT )
stuff->func( stuff->cbdata );

View File

@ -29,17 +29,10 @@
#include "tr_torrent.h"
#include "util.h"
/* show the "add a torrent" dialog */
void
makeaddwind( GtkWindow * parent, TrCore * core );
/* prompt for a download directory for torrents, then add them */
void
promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data,
size_t size, enum tr_torrent_action act, gboolean paused );
void promptfordir( GtkWindow* parent, TrCore*, GList* filenames, tr_ctor* );
/* prompt if the user wants to quit, calls func with cbdata if they do */
void
askquit( TrCore*, GtkWindow* parent, callbackfunc_t func, void * cbdata );
void askquit( TrCore*, GtkWindow* parent, callbackfunc_t func, void* cbdata );
#endif /* TG_PREFS_H */

View File

@ -374,6 +374,9 @@ static void
torrentDestroyed( gpointer gdata, GObject * deadTorrent UNUSED )
{
FileData * data = gdata;
g_object_weak_unref( G_OBJECT( data->gtor ), torrentDestroyed, data );
file_list_set_torrent( data->top, NULL );
}

View File

@ -579,9 +579,10 @@ smsg_add( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
{
struct constate * con = arg;
struct constate_serv * srv = &con->u.serv;
enum tr_torrent_action action;
benc_val_t * path;
int ii;
tr_ctor * ctor;
GList * list = NULL;
if( NULL == val || TYPE_LIST != val->type )
{
@ -589,7 +590,8 @@ smsg_add( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
return;
}
action = tr_prefs_get_action( PREF_KEY_ADDIPC );
ctor = tr_ctorNew( srv->core );
for( ii = 0; ii < val->val.l.count; ii++ )
{
path = val->val.l.vals + ii;
@ -597,10 +599,14 @@ smsg_add( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
/* XXX somehow escape invalid utf-8 */
g_utf8_validate( path->val.s.s, path->val.s.i, NULL ) )
{
tr_core_add( TR_CORE( srv->core ), path->val.s.s, action, FALSE );
list = g_list_append( list, g_strndup( path->val.s.s, path->val.s.i ) );
}
}
tr_core_torrents_added( TR_CORE( srv->core ) );
if( list ) {
tr_core_add_list( srv->core, list, ctor );
tr_core_torrents_added( TR_CORE( srv->core ) );
}
/* XXX should send info response back with torrent ids */
simpleresp( con, tag, IPC_MSG_OK );
@ -612,9 +618,8 @@ smsg_addone( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag,
{
struct constate * con = arg;
struct constate_serv * srv = &con->u.serv;
enum tr_torrent_action action;
benc_val_t * file, * data, * dir, * start;
gboolean paused;
tr_ctor * ctor;
if( NULL == val || TYPE_DICT != val->type )
{
@ -636,33 +641,18 @@ smsg_addone( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag,
return;
}
action = tr_prefs_get_action( PREF_KEY_ADDIPC );
paused = ( NULL == start || start->val.i ? FALSE : TRUE );
if( NULL != file )
{
if( NULL == dir )
{
tr_core_add( srv->core, file->val.s.s, action, paused );
}
else
{
tr_core_add_dir( srv->core, file->val.s.s, dir->val.s.s,
action, paused );
}
}
else
{
if( NULL == dir )
{
tr_core_add_data( srv->core, (uint8_t *) data->val.s.s,
data->val.s.i, paused );
}
else
{
tr_core_add_data_dir( srv->core, (uint8_t *) data->val.s.s,
data->val.s.i, dir->val.s.s, paused );
}
}
ctor = tr_ctorNew( tr_core_handle( srv->core ) );
if( dir )
tr_ctorSetDestination( ctor, TR_FORCE, dir->val.s.s );
if( file )
tr_ctorSetMetainfoFromFile( ctor, file->val.s.s );
if( data )
tr_ctorSetMetainfo( ctor, (uint8_t*)data->val.s.s, data->val.s.i );
if( start )
tr_ctorSetPaused( ctor, TR_FORCE, !start->val.i );
tr_core_add_ctor( TR_CORE( srv->core ), ctor );
tr_core_torrents_added( TR_CORE( srv->core ) );
/* XXX should send info response back with torrent ids */
@ -998,7 +988,7 @@ smsg_pref( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )
break;
case IPC_MSG_GETDIR:
/* XXX sending back "" when we're prompting is kind of bogus */
pref = pref_flag_get( PREF_KEY_DIR_ASK ) ? "" : getdownloaddir();
pref = pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) ? "" : getdownloaddir();
buf = ipc_mkstr( con->ipc, &size, IPC_MSG_DIR, tag, pref );
break;
case IPC_MSG_GETDOWNLIMIT:

View File

@ -47,6 +47,7 @@
#include "ipc.h"
#include "makemeta-ui.h"
#include "msgwin.h"
#include "open.h"
#include "stats.h"
#include "torrent-inspector.h"
#include "tr_core.h"
@ -146,9 +147,7 @@ static void
coreerr( TrCore * core, enum tr_core_err code, const char * msg,
gpointer gdata );
static void
coreprompt( TrCore *, GList *, enum tr_torrent_action, gboolean, gpointer );
static void
corepromptdata( TrCore *, uint8_t *, size_t, gboolean, gpointer );
coreprompt( TrCore *, GList *, gpointer, gpointer );
static void
initializeFromPrefs( struct cbdata * cbdata );
static void
@ -329,10 +328,8 @@ sendremote( GList * files, gboolean sendquit )
static void
appsetup( TrWindow * wind, GList * args,
struct cbdata * cbdata,
gboolean paused, gboolean minimized )
gboolean forcepause, gboolean minimized )
{
enum tr_torrent_action action;
/* fill out cbdata */
cbdata->wind = NULL;
cbdata->icon = NULL;
@ -349,8 +346,6 @@ appsetup( TrWindow * wind, GList * args,
g_signal_connect( cbdata->core, "error", G_CALLBACK( coreerr ), cbdata );
g_signal_connect( cbdata->core, "directory-prompt",
G_CALLBACK( coreprompt ), cbdata );
g_signal_connect( cbdata->core, "directory-prompt-data",
G_CALLBACK( corepromptdata ), cbdata );
g_signal_connect_swapped( cbdata->core, "quit",
G_CALLBACK( wannaquit ), cbdata );
g_signal_connect( cbdata->core, "prefs-changed",
@ -363,12 +358,14 @@ appsetup( TrWindow * wind, GList * args,
initializeFromPrefs( cbdata );
/* add torrents from command-line and saved state */
tr_core_load( cbdata->core, paused );
tr_core_load( cbdata->core, forcepause );
if( NULL != args )
{
action = tr_prefs_get_action( PREF_KEY_ADDIPC );
tr_core_add_list( cbdata->core, args, action, paused );
tr_ctor * ctor = tr_ctorNew( tr_core_handle( cbdata->core ) );
if( forcepause )
tr_ctorSetPaused( ctor, TR_FORCE, TRUE );
tr_core_add_list( cbdata->core, args, ctor );
}
tr_core_torrents_added( cbdata->core );
@ -625,7 +622,8 @@ gotdrag( GtkWidget * widget UNUSED,
GList * paths = NULL;
GList * freeme = NULL;
#ifdef DND_DEBUG
#if 0
int i;
char *sele = gdk_atom_name(sel->selection);
char *targ = gdk_atom_name(sel->target);
char *type = gdk_atom_name(sel->type);
@ -683,9 +681,9 @@ gotdrag( GtkWidget * widget UNUSED,
/* try to add any torrents we found */
if( paths != NULL )
{
enum tr_torrent_action action = tr_prefs_get_action( PREF_KEY_ADDSTD );
tr_ctor * ctor = tr_ctorNew( tr_core_handle( data->core ) );
paths = g_list_reverse( paths );
tr_core_add_list( data->core, paths, action, FALSE );
tr_core_add_list( data->core, paths, ctor );
tr_core_torrents_added( data->core );
g_list_free( paths );
}
@ -748,22 +746,20 @@ coreerr( TrCore * core UNUSED, enum tr_core_err code, const char * msg,
g_assert_not_reached();
}
void
coreprompt( TrCore * core, GList * paths, enum tr_torrent_action act,
gboolean paused, gpointer gdata )
static void
coreprompt( TrCore * core,
GList * paths,
gpointer ctor,
gpointer gdata )
{
struct cbdata * cbdata = gdata;
promptfordir( cbdata->wind, core, paths, NULL, 0, act, paused );
}
void
corepromptdata( TrCore * core, uint8_t * data, size_t size,
gboolean paused, gpointer gdata )
{
struct cbdata * cbdata = gdata;
promptfordir( cbdata->wind, core, NULL, data, size, TR_TOR_LEAVE, paused );
if( g_list_length( paths ) != 1 )
promptfordir( cbdata->wind, core, paths, ctor );
else {
tr_ctorSetMetainfoFromFile( ctor, paths->data );
makeaddwind( cbdata->wind, core, ctor );
}
}
static void
@ -1013,7 +1009,7 @@ doAction ( const char * action_name, gpointer user_data )
if ( !strcmp (action_name, "open-torrent-menu") || !strcmp( action_name, "open-torrent-toolbar" ))
{
makeaddwind( data->wind, data->core );
makeaddwind( data->wind, data->core, tr_ctorNew( tr_core_handle( data->core ) ) );
}
else if (!strcmp (action_name, "show-stats"))
{

View File

@ -2,4 +2,4 @@
export G_SLICE=always-malloc
export G_DEBUG=gc-friendly
export GLIBCXX_FORCE_NEW=1
valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=64 --log-file=x-valgrind --show-reachable=yes ./transmission
valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=64 --log-file=x-valgrind --show-reachable=yes ./transmission ~/Desktop/*torrent

223
gtk/open.c Normal file
View File

@ -0,0 +1,223 @@
/*
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id: hig.h 4404 2008-01-01 17:20:20Z charles $
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "file-list.h"
#include "hig.h"
#include "open.h"
struct OpenData
{
TrCore * core;
GtkWidget * list;
GtkWidget * run_check;
char * filename;
char * destination;
TrTorrent * gtor;
tr_ctor * ctor;
};
static void
deleteOldTorrent( struct OpenData * data )
{
if( data->gtor )
{
tr_torrent * tor = tr_torrent_handle( data->gtor );
tr_torrentRemoveSaved( tor );
tr_torrentClose( tor );
g_object_unref( G_OBJECT( data->gtor ) );
data->gtor = NULL;
}
}
static void
openResponseCB( GtkDialog * dialog, gint response, gpointer gdata )
{
struct OpenData * data = gdata;
if( data->gtor )
{
if( response != GTK_RESPONSE_ACCEPT )
deleteOldTorrent( data );
else {
if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->run_check ) ) )
tr_torrentStart( tr_torrent_handle( data->gtor ) );
tr_core_add_torrent( data->core, data->gtor );
}
}
tr_ctorFree( data->ctor );
g_free( data->filename );
g_free( data->destination );
g_free( data );
gtk_widget_destroy( GTK_WIDGET( dialog ) );
}
static void
updateTorrent( struct OpenData * data )
{
if( data->gtor )
tr_torrentSetFolder( tr_torrent_handle( data->gtor ), data->destination );
file_list_set_torrent( data->list, data->gtor );
}
static void
sourceChanged( GtkFileChooserButton * b, gpointer gdata )
{
struct OpenData * data = gdata;
deleteOldTorrent( data );
/* update the filename */
g_free( data->filename );
data->filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
/* maybe instantiate a torrent */
if( data->filename ) {
int err = 0;
tr_torrent * torrent;
tr_handle * handle = tr_core_handle( data->core );
tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
tr_ctorSetDestination( data->ctor, TR_FORCE, data->destination );
if(( torrent = tr_torrentNew( handle, data->ctor, &err )))
data->gtor = tr_torrent_new_preexisting( torrent );
}
updateTorrent( data );
}
static void
verifyRequested( GtkButton * button UNUSED, gpointer gdata )
{
struct OpenData * data = gdata;
if( data->gtor )
tr_torrentRecheck( tr_torrent_handle( data->gtor ) );
}
static void
destinationChanged( GtkFileChooserButton * b, gpointer gdata )
{
struct OpenData * data = gdata;
g_free( data->destination );
data->destination = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
updateTorrent( data );
verifyRequested( NULL, data );
}
/****
*****
****/
void
makeaddwind( GtkWindow * parent,
TrCore * core,
tr_ctor * ctor )
{
int row;
int col;
const char * str;
GtkWidget * w;
GtkWidget * d;
GtkWidget * t;
GtkWidget * l;
GtkFileFilter * filter;
struct OpenData * data;
uint8_t flag;
/* make the dialog */
d = gtk_dialog_new_with_buttons( _( "Open Torrent" ),
parent,
GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL );
tr_ctorGetDestination( ctor, TR_FORCE, &str );
data = g_new0( struct OpenData, 1 );
data->core = core;
data->ctor = ctor;
data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
data->destination = g_strdup( str );
g_signal_connect( G_OBJECT( d ), "response", G_CALLBACK( openResponseCB ), data );
t = gtk_table_new( 6, 2, FALSE );
gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
row = col = 0;
l = gtk_label_new_with_mnemonic( _( "_Torrent file:" ) );
gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
gtk_table_attach( GTK_TABLE( t ), l, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
++col;
w = gtk_file_chooser_button_new( _( "Select Torrent" ), GTK_FILE_CHOOSER_ACTION_OPEN );
gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
filter = gtk_file_filter_new( );
gtk_file_filter_set_name( filter, _( "Torrent files" ) );
gtk_file_filter_add_pattern( filter, "*.torrent" );
gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( w ), filter );
filter = gtk_file_filter_new( );
gtk_file_filter_set_name( filter, _( "All files" ) );
gtk_file_filter_add_pattern( filter, "*" );
gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( w ), filter );
g_signal_connect( w, "selection-changed", G_CALLBACK( sourceChanged ), data );
if( data->filename )
gtk_file_chooser_set_uri( GTK_FILE_CHOOSER( w ), data->filename );
++row;
col = 0;
l = gtk_label_new_with_mnemonic( _( "Download _to:" ) );
gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
gtk_table_attach( GTK_TABLE( t ), l, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
++col;
w = gtk_file_chooser_button_new( _( "Destination" ), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
gtk_file_chooser_set_uri( GTK_FILE_CHOOSER( w ), data->destination );
gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
g_signal_connect( w, "selection-changed", G_CALLBACK( destinationChanged ), data );
++row;
col = 0;
w = file_list_new( NULL );
gtk_widget_set_size_request ( w, 466u, 300u );
data->list = w;
gtk_table_attach_defaults( GTK_TABLE( t ), w, col, col+2, row, row+1 );
++row;
col = 0;
w = gtk_button_new_with_mnemonic( _( "Verify Local Data" ) );
gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
g_signal_connect( w, "clicked", G_CALLBACK( verifyRequested ), data );
++row;
col = 0;
w = gtk_check_button_new_with_mnemonic( _( "_Delete original torrent file" ) );
tr_ctorGetDeleteSource( ctor, &flag );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
gtk_table_attach( GTK_TABLE( t ), w, col, col+2, row, row+1, GTK_FILL, 0, 0, 0 );
++row;
col = 0;
w = gtk_check_button_new_with_mnemonic( _( "_Start when added" ) );
data->run_check = w;
tr_ctorGetPaused( ctor, TR_FORCE, &flag );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
gtk_table_attach( GTK_TABLE( t ), w, col, col+2, row, row+1, GTK_FILL, 0, 0, 0 );
gtk_box_pack_start_defaults( GTK_BOX( GTK_DIALOG( d )->vbox ), t );
gtk_widget_show_all( d );
}

23
gtk/open.h Normal file
View File

@ -0,0 +1,23 @@
/*
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id: hig.h 4404 2008-01-01 17:20:20Z charles $
*/
#ifndef TR_GTK_OPEN_DIALOG_H
#define TR_GTK_OPEN_DIALOG_H
#include <gtk/gtkwindow.h>
#include "tr_core.h"
void makeaddwind( GtkWindow * parent,
TrCore * core,
tr_ctor * ctor );
#endif /* TR_GTK_OPEN_DIALOG */

View File

@ -77,53 +77,23 @@ tr_core_marshal_prompt( GClosure * closure, GValue * ret UNUSED, guint count,
const GValue * vals, gpointer hint UNUSED,
gpointer marshal )
{
typedef void (*TRMarshalPrompt)
( gpointer, GList *, enum tr_torrent_action, gboolean, gpointer );
typedef void (*TRMarshalPrompt)( gpointer, GList *, gpointer, gpointer );
TRMarshalPrompt callback;
GCClosure * cclosure = (GCClosure*) closure;
GList * paths;
enum tr_torrent_action action;
gboolean paused;
gpointer ctor;
gpointer inst, gdata;
g_return_if_fail( 4 == count );
g_return_if_fail( 3 == count );
inst = g_value_peek_pointer( vals );
paths = g_value_get_pointer( vals + 1 );
action = g_value_get_int( vals + 2 );
paused = g_value_get_boolean( vals + 3 );
gdata = closure->data;
inst = g_value_peek_pointer( vals );
paths = g_value_get_pointer( vals + 1 );
ctor = g_value_get_pointer( vals + 2 );
gdata = closure->data;
callback = (TRMarshalPrompt) ( NULL == marshal ?
cclosure->callback : marshal );
callback( inst, paths, action, paused, gdata );
}
static void
tr_core_marshal_data( GClosure * closure, GValue * ret UNUSED, guint count,
const GValue * vals, gpointer hint UNUSED,
gpointer marshal )
{
typedef void (*TRMarshalPrompt)
( gpointer, uint8_t *, size_t, gboolean, gpointer );
TRMarshalPrompt callback;
GCClosure * cclosure = (GCClosure*) closure;
uint8_t * data;
size_t size;
gboolean paused;
gpointer inst, gdata;
g_return_if_fail( 4 == count );
inst = g_value_peek_pointer( vals );
data = (uint8_t *) g_value_get_string( vals + 1 );
size = g_value_get_uint( vals + 2 );
paused = g_value_get_boolean( vals + 3 );
gdata = closure->data;
callback = (TRMarshalPrompt) ( NULL == marshal ?
cclosure->callback : marshal );
callback( inst, data, size, paused, gdata );
callback( inst, paths, ctor, gdata );
}
static int
@ -171,14 +141,7 @@ tr_core_class_init( gpointer g_class, gpointer g_class_data UNUSED )
G_TYPE_FROM_CLASS( g_class ),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
tr_core_marshal_prompt, G_TYPE_NONE,
3, G_TYPE_POINTER, G_TYPE_INT,
G_TYPE_BOOLEAN );
core_class->promptdatasig = g_signal_new( "directory-prompt-data",
G_TYPE_FROM_CLASS( g_class ),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
tr_core_marshal_data,
G_TYPE_NONE, 3, G_TYPE_STRING,
G_TYPE_UINT, G_TYPE_BOOLEAN );
2, G_TYPE_POINTER, G_TYPE_POINTER );
core_class->quitsig = g_signal_new( "quit", G_TYPE_FROM_CLASS( g_class ),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
@ -486,14 +449,15 @@ doCollate( const char * in )
return ret;
}
static void
tr_core_insert( TrCore * self, TrTorrent * tor )
void
tr_core_add_torrent( TrCore * self, TrTorrent * tor )
{
const tr_info * inf = tr_torrent_info( tor );
const tr_stat * torStat = tr_torrent_stat( tor );
char * collated = doCollate( inf->name );
GtkListStore * store = GTK_LIST_STORE( tr_core_model( self ) );
GtkTreeIter unused;
gtk_list_store_insert_with_values( store, &unused, 0,
MC_NAME, inf->name,
MC_NAME_COLLATED, collated,
@ -503,8 +467,10 @@ tr_core_insert( TrCore * self, TrTorrent * tor )
MC_STATUS, torStat->status,
MC_ID, self->priv->nextid,
-1);
self->priv->nextid++;
g_object_unref( tor );
++self->priv->nextid;
/* cleanup */
g_object_unref( G_OBJECT( tor ) );
g_free( collated );
}
@ -529,7 +495,7 @@ tr_core_load( TrCore * self, gboolean forcePaused )
torrents = tr_loadTorrents ( tr_core_handle( self ), ctor, &count );
for( i=0; i<count; ++i )
tr_core_insert( self, tr_torrent_new_preexisting( torrents[i] ) );
tr_core_add_torrent( self, tr_torrent_new_preexisting( torrents[i] ) );
tr_free( torrents );
tr_ctorFree( ctor );
@ -538,22 +504,6 @@ tr_core_load( TrCore * self, gboolean forcePaused )
return count;
}
gboolean
tr_core_add( TrCore * self, const char * path, enum tr_torrent_action act,
gboolean paused )
{
GList * list;
int ret;
TR_IS_CORE( self );
list = g_list_append( NULL, (void *) path );
ret = tr_core_add_list( self, list, act, paused );
g_list_free( list );
return 1 == ret;
}
static void
tr_core_errsig( TrCore * self, enum tr_core_err type, const char * msg )
{
@ -563,105 +513,72 @@ tr_core_errsig( TrCore * self, enum tr_core_err type, const char * msg )
g_signal_emit( self, class->errsig, 0, type, msg );
}
gboolean
tr_core_add_dir( TrCore * self, const char * path, const char * dir,
enum tr_torrent_action act, gboolean paused )
static void
tr_core_apply_defaults( tr_ctor * ctor )
{
if( tr_ctorGetPaused( ctor, TR_FORCE, NULL ) )
tr_ctorSetPaused( ctor, TR_FORCE, !pref_flag_get( PREF_KEY_START ) );
if( tr_ctorGetDeleteSource( ctor, NULL ) )
tr_ctorSetDeleteSource( ctor, pref_flag_get( PREF_KEY_DELETE_ORIGINAL ) );
if( tr_ctorGetMaxConnectedPeers( ctor, TR_FORCE, NULL ) )
tr_ctorSetMaxConnectedPeers( ctor, TR_FORCE, pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
if( tr_ctorGetDestination( ctor, TR_FORCE, NULL ) ) {
char * path = pref_string_get( PREF_KEY_DIR_DEFAULT );
tr_ctorSetDestination( ctor, TR_FORCE, path );
g_free( path );
}
}
void
tr_core_add_ctor( TrCore * self, tr_ctor * ctor )
{
TrTorrent * tor;
char * errstr;
TR_IS_CORE( self );
errstr = NULL;
tor = tr_torrent_new( tr_core_handle( self ), path, dir, act, paused, &errstr );
if( NULL == tor )
tr_core_apply_defaults( ctor );
tor = tr_torrent_new_ctor( tr_core_handle( self ), ctor, &errstr );
if( !tor )
{
tr_core_errsig( self, TR_CORE_ERR_ADD_TORRENT, errstr );
g_free( errstr );
return FALSE;
errstr = NULL;
}
else
{
g_assert( !errstr );
tr_core_add_torrent( self, tor );
}
g_assert( NULL == errstr );
tr_core_insert( self, tor );
return TRUE;
}
int
tr_core_add_list( TrCore * self, GList * paths, enum tr_torrent_action act,
gboolean paused )
void
tr_core_add_list( TrCore * self,
GList * paths,
tr_ctor * ctor )
{
char * dir;
int count;
tr_core_apply_defaults( ctor );
TR_IS_CORE( self );
if( pref_flag_get( PREF_KEY_DIR_ASK ) )
if( pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) )
{
TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE );
g_signal_emit( self, class->promptsig, 0, paths, act, paused );
return 0;
g_signal_emit( self, class->promptsig, 0, paths, ctor );
}
dir = getdownloaddir();
count = 0;
for( ; paths; paths=paths->next )
if( tr_core_add_dir( self, paths->data, dir, act, paused ) )
count++;
g_free( dir );
return count;
}
gboolean
tr_core_add_data( TrCore * self, uint8_t * data, size_t size, gboolean paused )
{
gboolean ret;
char * path;
TR_IS_CORE( self );
if( pref_flag_get( PREF_KEY_DIR_ASK ) )
else
{
TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE );
g_signal_emit( self, class->promptdatasig, 0, data, size, paused );
return FALSE;
for( ; paths; paths=paths->next )
if( !tr_ctorSetMetainfoFromFile( ctor, paths->data ) )
tr_core_add_ctor( self, ctor );
tr_ctorFree( ctor );
}
path = getdownloaddir( );
ret = tr_core_add_data_dir( self, data, size, path, paused );
g_free( path );
return ret;
}
gboolean
tr_core_add_data_dir( TrCore * self, uint8_t * data, size_t size,
const char * dir, gboolean paused )
{
TrTorrent * tor;
char * errstr = NULL;
TR_IS_CORE( self );
tor = tr_torrent_new_with_data( tr_core_handle( self ), data, size, dir,
paused, &errstr );
if( NULL == tor )
{
tr_core_errsig( self, TR_CORE_ERR_ADD_TORRENT, errstr );
g_free( errstr );
return FALSE;
}
g_assert( NULL == errstr );
tr_core_insert( self, tor );
return TRUE;
}
void
tr_core_torrents_added( TrCore * self )
{
TR_IS_CORE( self );
tr_core_update( self );
tr_core_errsig( self, TR_CORE_ERR_NO_MORE_TORRENTS, NULL );
}
@ -672,8 +589,6 @@ tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter )
TrTorrent * tor;
GtkTreeModel * model = tr_core_model( self );
TR_IS_CORE( self );
gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
gtk_list_store_remove( GTK_LIST_STORE( model ), iter );
tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
@ -746,11 +661,7 @@ tr_core_update( TrCore * self )
void
tr_core_quit( TrCore * self )
{
TrCoreClass * class;
TR_IS_CORE( self );
class = g_type_class_peek( TR_CORE_TYPE );
TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE );
g_signal_emit( self, class->quitsig, 0 );
}

View File

@ -30,28 +30,17 @@
#include <glib-object.h>
#include <gtk/gtk.h>
#include <libtransmission/bencode.h>
#include <libtransmission/transmission.h>
#include "tr_torrent.h"
#include "util.h"
#define TR_CORE_TYPE ( tr_core_get_type() )
#define TR_CORE( obj ) \
( G_TYPE_CHECK_INSTANCE_CAST( (obj), TR_CORE_TYPE, TrCore ) )
#define TR_CORE_CLASS( class ) \
( G_TYPE_CHECK_CLASS_CAST( (class), TR_CORE_TYPE, TrCoreClass ) )
#define TR_IS_CORE( obj ) \
( G_TYPE_CHECK_INSTANCE_TYPE( (obj), TR_CORE_TYPE ) )
#define TR_IS_CORE_CLASS( class ) \
( G_TYPE_CHECK_CLASS_TYPE( (class), TR_CORE_TYPE ) )
#define TR_CORE_GET_CLASS( obj ) \
( G_TYPE_INSTANCE_GET_CLASS( (obj), TR_CORE_TYPE, TrCoreClass ) )
#define TR_CORE_TYPE (tr_core_get_type())
#define TR_CORE(o) G_TYPE_CHECK_INSTANCE_CAST((o),TR_CORE_TYPE,TrCore)
#define TR_IS_CORE(o) G_TYPE_CHECK_INSTANCE_TYPE((o),TR_CORE_TYPE)
#define TR_CORE_CLASS(k) G_TYPE_CHECK_CLASS_CAST((k),TR_CORE_TYPE,TrCoreClass)
#define TR_IS_CORE_CLASS(k) G_TYPE_CHECK_CLASS_TYPE((k),TR_CORE_TYPE)
#define TR_CORE_GET_CLASS(o) G_TYPE_INSTANCE_GET_CLASS((o),TR_CORE_TYPE,TrCoreClass)
struct core_stats
{
@ -61,7 +50,6 @@ struct core_stats
float clientUploadSpeed;
};
/* treat the contents of this structure as private */
typedef struct TrCore
{
GObject parent;
@ -78,13 +66,9 @@ typedef struct TrCoreClass
int errsig;
/* "directory-prompt" signal:
void handler( TrCore *, GList *, enum tr_torrent_action, gboolean, gpointer ) */
void handler( TrCore *, GList *, gpointer ctor, gpointer userData ) */
int promptsig;
/* "directory-prompt-data" signal:
void handler( TrCore *, uint8_t *, size_t, gboolean, gpointer ) */
int promptdatasig;
/* "quit" signal:
void handler( TrCore *, gpointer ) */
int quitsig;
@ -120,41 +104,45 @@ tr_core_handle( TrCore * self );
const struct core_stats*
tr_core_get_stats( const TrCore * self );
/* Load saved state, return number of torrents added. May trigger one
or more "error" signals with TR_CORE_ERR_ADD_TORRENT */
int
tr_core_load( TrCore * self, gboolean forcepaused );
/******
*******
******/
/* Any the tr_core_add functions below may trigger an "error" signal
with TR_CORE_ERR_ADD_TORRENT */
/**
* Load saved state and return number of torrents added.
* May trigger one or more "error" signals with TR_CORE_ERR_ADD_TORRENT
*/
int tr_core_load( TrCore * self, gboolean forcepaused );
/* Add the torrent at the given path */
gboolean
tr_core_add( TrCore * self, const char * path, enum tr_torrent_action act,
gboolean paused );
/**
* Add a torrent.
* May trigger an "error" signal with TR_CORE_ERR_ADD_TORRENT
* Caller must free the ctor.
*/
void tr_core_add_ctor( TrCore * self, tr_ctor * ctor );
/* Add the torrent at the given path with the given download directory */
gboolean
tr_core_add_dir( TrCore * self, const char * path, const char * dir,
enum tr_torrent_action act, gboolean paused );
/**
* Add a list of torrents.
* May trigger one or more "error" signals with TR_CORE_ERR_ADD_TORRENT
*/
void tr_core_add_list( TrCore * self,
GList * torrentFiles,
tr_ctor * ctor );
/* Add a list of torrents with the given paths */
int
tr_core_add_list( TrCore * self, GList * paths, enum tr_torrent_action act,
gboolean paused );
/**
* Add a torrent.
*/
void tr_core_add_torrent( TrCore*, TrTorrent* );
/* Add the torrent data in the given buffer */
gboolean
tr_core_add_data( TrCore * self, uint8_t * data, size_t size, gboolean paused );
/**
* Notifies listeners that torrents have been added.
* This should be called after one or more tr_core_add*() calls.
*/
void tr_core_torrents_added( TrCore * self );
/* Add the torrent data in the given buffer with the given download directory */
gboolean
tr_core_add_data_dir( TrCore * self, uint8_t * data, size_t size,
const char * dir, gboolean paused );
/* Save state, update model, and signal the end of a torrent cluster */
void
tr_core_torrents_added( TrCore * self );
/******
*******
******/
/* remove a torrent, waiting for it to pause if necessary */
void

View File

@ -42,7 +42,7 @@ tr_prefs_init_global( void )
pref_flag_set_default ( PREF_KEY_UL_LIMIT_ENABLED, FALSE );
pref_int_set_default ( PREF_KEY_UL_LIMIT, 50 );
pref_flag_set_default ( PREF_KEY_DIR_ASK, FALSE );
pref_flag_set_default ( PREF_KEY_OPTIONS_PROMPT, TRUE );
pref_string_set_default ( PREF_KEY_DIR_DEFAULT, g_get_home_dir() );
pref_int_set_default ( PREF_KEY_PORT, TR_DEFAULT_PORT );
@ -53,15 +53,15 @@ tr_prefs_init_global( void )
pref_flag_set_default ( PREF_KEY_ASKQUIT, TRUE );
pref_flag_set_default ( PREF_KEY_ENCRYPTED_ONLY, FALSE );
pref_string_set_default ( PREF_KEY_ADDSTD, toractionname(TR_TOR_COPY) );
pref_string_set_default ( PREF_KEY_ADDIPC, toractionname(TR_TOR_COPY) );
pref_int_set_default ( PREF_KEY_MSGLEVEL, TR_MSG_INF );
pref_string_set_default ( PREF_KEY_SORT_MODE, "sort-by-name" );
pref_flag_set_default ( PREF_KEY_SORT_REVERSED, FALSE );
pref_flag_set_default ( PREF_KEY_MINIMAL_VIEW, FALSE );
pref_flag_set_default ( PREF_KEY_START, TRUE );
pref_flag_set_default ( PREF_KEY_DELETE_ORIGINAL, FALSE );
pref_save( NULL );
}
@ -69,25 +69,6 @@ tr_prefs_init_global( void )
***
**/
int
tr_prefs_get_action( const char * key )
{
char * val = pref_string_get( key );
const int ret = toraddaction( val );
g_free( val );
return ret;
}
void
tr_prefs_set_action( const char * key, int action )
{
pref_string_set( key, toractionname(action) );
}
/**
***
**/
#define PREFS_KEY "prefs-key"
static void
@ -154,66 +135,12 @@ new_path_chooser_button( const char * key, gpointer core )
return w;
}
static void
action_cb( GtkComboBox * w, gpointer core )
{
const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY );
GtkTreeIter iter;
if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(w), &iter ) )
{
int action;
GtkTreeModel * model = gtk_combo_box_get_model( GTK_COMBO_BOX(w) );
gtk_tree_model_get( model, &iter, 1, &action, -1 );
tr_core_set_pref( core, key, toractionname(action) );
}
}
static GtkWidget*
new_action_combo( const char * key, gpointer core )
{
const char * s;
GtkTreeIter iter;
GtkCellRenderer * rend;
GtkListStore * model;
GtkWidget * w;
model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
s = _("Use the torrent file where it is");
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter, 1, TR_TOR_LEAVE, 0, s, -1 );
s = _("Keep a copy of the torrent file");
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter, 1, TR_TOR_COPY, 0, s, -1 );
s = _("Keep a copy and remove the original");
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter, 1, TR_TOR_MOVE, 0, s, -1 );
w = gtk_combo_box_new_with_model( GTK_TREE_MODEL(model) );
gtk_combo_box_set_active( GTK_COMBO_BOX(w), tr_prefs_get_action(key) );
g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free );
rend = gtk_cell_renderer_text_new( );
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(w), rend, TRUE );
gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(w), rend, "text", 0 );
g_signal_connect( w, "changed", G_CALLBACK(action_cb), core );
return w;
}
static void
target_cb( GtkWidget * widget, gpointer target )
{
gtk_widget_set_sensitive( GTK_WIDGET(target), gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ) );
}
static void
target_invert_cb( GtkWidget * widget, gpointer target )
{
gtk_widget_set_sensitive( GTK_WIDGET(target), !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ) );
}
struct test_port_data
{
GtkWidget * label;
@ -267,34 +194,102 @@ dialogDestroyed( gpointer alive, GObject * dialog UNUSED )
*(gboolean*)alive = FALSE;
}
GtkWidget *
tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
static GtkWidget*
generalPage( GObject * core )
{
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w;
t = hig_workarea_create ();
hig_workarea_add_section_title (t, &row, _("Windows"));
s = _("Show an icon in the system _tray");
w = new_check_button( s, PREF_KEY_SYSTRAY, core );
hig_workarea_add_wide_control( t, &row, w );
s = _("Confirm _quit");
w = new_check_button( s, PREF_KEY_ASKQUIT, core );
hig_workarea_add_wide_control( t, &row, w );
hig_workarea_finish (t, &row);
return t;
}
static GtkWidget*
torrentPage( GObject * core )
{
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w;
t = hig_workarea_create ();
hig_workarea_add_section_title( t, &row, _( "Location" ) );
w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
hig_workarea_add_row( t, &row, _( "Default download location:" ), w, NULL );
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title( t, &row, _( "Adding Torrents" ) );
s = _( "Show _options window" );
w = new_check_button( s, PREF_KEY_OPTIONS_PROMPT, core );
hig_workarea_add_wide_control( t, &row, w );
s = _( "_Start transfers when added" );
w = new_check_button( s, PREF_KEY_START, core );
hig_workarea_add_wide_control( t, &row, w );
s = _( "_Delete original torrent file" );
w = new_check_button( s, PREF_KEY_DELETE_ORIGINAL, core );
hig_workarea_add_wide_control( t, &row, w );
hig_workarea_finish (t, &row);
return t;
}
static GtkWidget*
peerPage( GObject * core )
{
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w;
t = hig_workarea_create ();
hig_workarea_add_section_title (t, &row, _("Options"));
s = _("Use peer _exchange if possible");
w = new_check_button( s, PREF_KEY_PEX, core );
hig_workarea_add_wide_control( t, &row, w );
s = _("_Ignore unencrypted peers");
w = new_check_button( s, PREF_KEY_ENCRYPTED_ONLY, core );
hig_workarea_add_wide_control( t, &row, w );
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title( t, &row, _( "Limits" ) );
w = new_spin_button( PREF_KEY_MAX_PEERS_GLOBAL, core, 1, 3000, 5 );
hig_workarea_add_row( t, &row, _( "Total max peers:" ), w, NULL );
w = new_spin_button( PREF_KEY_MAX_PEERS_PER_TORRENT, core, 1, 300, 5 );
hig_workarea_add_row( t, &row, _( "Per-torrent max peers:" ), w, NULL );
hig_workarea_finish (t, &row);
return t;
}
static GtkWidget*
bandwidthPage( GObject * core )
{
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w, * w2;
GtkWidget * l;
GtkWidget * h;
GtkWidget * d;
GtkTooltips * tips;
gboolean * alive;
alive = g_new( gboolean, 1 );
*alive = TRUE;
tips = gtk_tooltips_new( );
d = gtk_dialog_new_with_buttons( _("Preferences"), parent,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL );
gtk_window_set_role( GTK_WINDOW(d), "transmission-preferences-dialog" );
gtk_dialog_set_has_separator( GTK_DIALOG( d ), FALSE );
gtk_container_set_border_width( GTK_CONTAINER( d ), GUI_PAD );
g_object_weak_ref( G_OBJECT( d ), dialogDestroyed, alive );
g_signal_connect( d, "response", G_CALLBACK(response_cb), core );
t = hig_workarea_create ();
@ -314,33 +309,24 @@ tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
g_signal_connect( w, "toggled", G_CALLBACK(target_cb), w2 );
hig_workarea_add_row_w( t, &row, w, w2, NULL );
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title (t, &row, _("Downloads"));
hig_workarea_finish (t, &row);
return t;
}
s = _("P_rompt for download directory");
w = new_check_button( s, PREF_KEY_DIR_ASK, core );
w2 = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
gtk_widget_set_sensitive( GTK_WIDGET(w2), !pref_flag_get( PREF_KEY_DIR_ASK ) );
g_signal_connect( w, "toggled", G_CALLBACK(target_invert_cb), w2 );
hig_workarea_add_row_w( t, &row, w, w2, NULL );
static GtkWidget*
networkPage( GObject * core, gpointer alive )
{
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w, * w2;
GtkWidget * l;
GtkWidget * h;
GtkTooltips * tips;
w = new_action_combo( PREF_KEY_ADDSTD, core );
s = _("For torrents added _normally:");
l = hig_workarea_add_row( t, &row, s, w, NULL );
tips = gtk_tooltips_new( );
w = new_action_combo( PREF_KEY_ADDIPC, core );
s = _("For torrents added from _command-line:");
l = hig_workarea_add_row( t, &row, s, w, NULL );
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title( t, &row, _( "Peer Connections" ) );
w = new_spin_button( PREF_KEY_MAX_PEERS_GLOBAL, core, 1, 3000, 5 );
hig_workarea_add_row( t, &row, _( "Global maximum connected peers:" ), w, NULL );
w = new_spin_button( PREF_KEY_MAX_PEERS_PER_TORRENT, core, 1, 300, 5 );
hig_workarea_add_row( t, &row, _( "Maximum connected peers for new torrents:" ), w, NULL );
hig_workarea_add_section_divider( t, &row );
t = hig_workarea_create ();
hig_workarea_add_section_title (t, &row, _("Network"));
s = _("_Automatically map port" );
@ -363,27 +349,46 @@ tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
g_signal_connect( w, "toggled", G_CALLBACK(toggled_cb), l );
g_signal_connect( w2, "value-changed", G_CALLBACK(testing_port_cb), l );
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title (t, &row, _("Options"));
s = _("Use peer _exchange if possible");
w = new_check_button( s, PREF_KEY_PEX, core );
hig_workarea_add_wide_control( t, &row, w );
s = _("_Ignore unencrypted peers");
w = new_check_button( s, PREF_KEY_ENCRYPTED_ONLY, core );
hig_workarea_add_wide_control( t, &row, w );
s = _("Show an icon in the system _tray");
w = new_check_button( s, PREF_KEY_SYSTRAY, core );
hig_workarea_add_wide_control( t, &row, w );
s = _("Confirm _quit");
w = new_check_button( s, PREF_KEY_ASKQUIT, core );
hig_workarea_add_wide_control( t, &row, w );
hig_workarea_finish (t, &row);
gtk_box_pack_start_defaults( GTK_BOX(GTK_DIALOG(d)->vbox), t );
return t;
}
GtkWidget *
tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
{
GtkWidget * d;
GtkWidget * n;
GtkWidget * w;
gboolean * alive;
alive = g_new( gboolean, 1 );
*alive = TRUE;
d = gtk_dialog_new_with_buttons( _("Preferences"), parent,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL );
gtk_window_set_role( GTK_WINDOW(d), "transmission-preferences-dialog" );
gtk_dialog_set_has_separator( GTK_DIALOG( d ), FALSE );
gtk_container_set_border_width( GTK_CONTAINER( d ), GUI_PAD );
g_object_weak_ref( G_OBJECT( d ), dialogDestroyed, alive );
n = gtk_notebook_new( );
w = torrentPage( core );
gtk_notebook_append_page( GTK_NOTEBOOK( n ), w, gtk_label_new (_("Torrents")) );
w = peerPage( core );
gtk_notebook_append_page( GTK_NOTEBOOK( n ), w, gtk_label_new (_("Peers")) );
w = bandwidthPage( core );
gtk_notebook_append_page( GTK_NOTEBOOK( n ), w, gtk_label_new (_("Bandwidth")) );
w = networkPage( core, alive );
gtk_notebook_append_page( GTK_NOTEBOOK( n ), w, gtk_label_new (_("Network")) );
w = generalPage( core );
gtk_notebook_append_page( GTK_NOTEBOOK( n ), w, gtk_label_new (_("General")) );
g_signal_connect( d, "response", G_CALLBACK(response_cb), core );
gtk_box_pack_start_defaults( GTK_BOX(GTK_DIALOG(d)->vbox), n );
gtk_widget_show_all( GTK_DIALOG(d)->vbox );
return d;
}

View File

@ -24,10 +24,10 @@ GtkWidget * tr_prefs_dialog_new( GObject * core, GtkWindow * parent );
#define PREF_KEY_DL_LIMIT "download-limit"
#define PREF_KEY_UL_LIMIT_ENABLED "upload-limit-enabled"
#define PREF_KEY_UL_LIMIT "upload-limit"
#define PREF_KEY_DIR_ASK "prompt-for-download-directory"
#define PREF_KEY_OPTIONS_PROMPT "show-options-window"
#define PREF_KEY_DIR_DEFAULT "default-download-directory"
#define PREF_KEY_ADDSTD "add-behavior-standard"
#define PREF_KEY_ADDIPC "add-behavior-ipc"
#define PREF_KEY_START "start-added-torrents"
#define PREF_KEY_DELETE_ORIGINAL "delete-original-torrent-files"
#define PREF_KEY_PORT "listening-port"
#define PREF_KEY_NAT "nat-traversal-enabled"
#define PREF_KEY_PEX "pex-enabled"
@ -48,7 +48,4 @@ GtkWidget * tr_prefs_dialog_new( GObject * core, GtkWindow * parent );
void tr_prefs_init_global( void );
int tr_prefs_get_action( const char * key );
void tr_prefs_set_action( const char * key, int action );
#endif

View File

@ -38,7 +38,6 @@
struct TrTorrentPrivate
{
tr_torrent * handle;
char * delfile;
gboolean seeding_cap_enabled;
gdouble seeding_cap; /* ratio to stop seeding at */
};
@ -54,7 +53,6 @@ tr_torrent_init(GTypeInstance *instance, gpointer g_class UNUSED )
TR_TORRENT_TYPE,
struct TrTorrentPrivate );
p->handle = NULL;
p->delfile = NULL;
p->seeding_cap = 2.0;
#ifdef REFDBG
@ -71,35 +69,35 @@ isDisposed( const TrTorrent * self )
static void
tr_torrent_dispose( GObject * o )
{
GObjectClass * parent = g_type_class_peek(g_type_parent(TR_TORRENT_TYPE));
GObjectClass * parent;
TrTorrent * self = TR_TORRENT( o );
if( !isDisposed( self ) )
{
if( self->priv->handle )
tr_torrentClose( self->priv->handle );
g_free( self->priv->delfile );
self->priv = NULL;
}
/* chain up to the parent class */
parent = g_type_class_peek(g_type_parent(TR_TORRENT_TYPE));
parent->dispose( o );
}
static void
tr_torrent_class_init(gpointer g_class, gpointer g_class_data UNUSED )
tr_torrent_class_init( gpointer g_class, gpointer g_class_data UNUSED )
{
GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
gobject_class->dispose = tr_torrent_dispose;
g_type_class_add_private( g_class, sizeof(struct TrTorrentPrivate) );
g_type_class_add_private( g_class, sizeof( struct TrTorrentPrivate ) );
}
GType
tr_torrent_get_type(void)
tr_torrent_get_type( void )
{
static GType type = 0;
if(0 == type) {
if( !type )
{
static const GTypeInfo info = {
sizeof (TrTorrentClass),
NULL, /* base_init */
@ -170,90 +168,41 @@ tr_torrent_new_preexisting( tr_torrent * tor )
}
TrTorrent *
tr_torrent_new( tr_handle * handle,
const char * metainfo_filename,
const char * destination,
enum tr_torrent_action act,
gboolean paused,
char ** err )
tr_torrent_new_ctor( tr_handle * handle,
tr_ctor * ctor,
char ** err )
{
TrTorrent * ret;
tr_torrent * tor;
tr_ctor * ctor;
int errcode = -1;
tr_torrent * tor;
int errcode;
g_assert( destination );
errcode = -1;
*err = NULL;
*err = NULL;
ctor = tr_ctorNew( handle );
tr_ctorSetMetainfoFromFile( ctor, metainfo_filename );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
tr_ctorSetPaused( ctor, TR_FORCE, paused );
tr_ctorSetMaxConnectedPeers( ctor, TR_FORCE, pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
tor = tr_torrentNew( handle, ctor, &errcode );
tr_ctorFree( ctor );
tor = tr_torrentNew( handle, ctor, &errcode );
if( tor == NULL ) {
switch( errcode ) {
case TR_EINVALID:
*err = g_strdup_printf(_("%s: not a valid torrent file"), metainfo_filename );
break;
case TR_EDUPLICATE:
*err = g_strdup_printf(_("%s: torrent is already open"), metainfo_filename );
break;
default:
*err = g_strdup( metainfo_filename );
break;
if( !tor )
{
const char * filename = tr_ctorGetSourceFile( ctor );
if( !filename )
filename = "(null)";
switch( errcode )
{
case TR_EINVALID:
*err = g_strdup_printf( _("%s: not a valid torrent file"), filename );
break;
case TR_EDUPLICATE:
*err = g_strdup_printf( _("%s: torrent is already open"), filename );
break;
default:
*err = g_strdup( filename );
break;
}
return NULL;
}
return NULL;
}
ret = maketorrent( tor );
if( TR_TOR_MOVE == act )
ret->priv->delfile = g_strdup( metainfo_filename );
return ret;
}
TrTorrent *
tr_torrent_new_with_data( tr_handle * handle,
uint8_t * metainfo,
size_t size,
const char * destination,
gboolean paused,
char ** err )
{
tr_torrent * tor;
tr_ctor * ctor;
int errcode = -1;
g_assert( destination );
*err = NULL;
ctor = tr_ctorNew( handle );
tr_ctorSetMetainfo( ctor, metainfo, size );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
tr_ctorSetPaused( ctor, TR_FORCE, paused );
tr_ctorSetMaxConnectedPeers( ctor, TR_FORCE, pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
tor = tr_torrentNew( handle, ctor, &errcode );
if( tor == NULL ) {
switch( errcode ) {
case TR_EINVALID:
*err = g_strdup( _("not a valid torrent file") );
break;
case TR_EDUPLICATE:
*err = g_strdup( _("torrent is already open") );
break;
default:
*err = g_strdup( "" );
break;
}
return NULL;
}
return maketorrent( tor );
return maketorrent( tor );
}
void

View File

@ -87,11 +87,6 @@ TrTorrent *
tr_torrent_new_preexisting( tr_torrent * tor );
TrTorrent *
tr_torrent_new( tr_handle * handle, const char * path, const char * dir,
enum tr_torrent_action act, gboolean paused, char ** err);
TrTorrent *
tr_torrent_new_with_data( tr_handle * handle, uint8_t * data, size_t size,
const char * dir, gboolean paused, char ** err );
tr_torrent_new_ctor( tr_handle * handle, tr_ctor * ctor, char ** err );
#endif

View File

@ -222,34 +222,6 @@ checkfilenames( int argc, char **argv )
return ret;
}
enum tr_torrent_action
toraddaction( const char * action )
{
if( !action || !strcmp( "copy", action ) )
return TR_TOR_COPY;
if( !strcmp( "move", action ) )
return TR_TOR_MOVE;
return TR_TOR_LEAVE;
}
const char *
toractionname( enum tr_torrent_action action )
{
switch( action )
{
case TR_TOR_COPY:
return "copy";
case TR_TOR_MOVE:
return "move";
default:
return "leave";
}
}
char *
getdownloaddir( void )
{

View File

@ -34,9 +34,6 @@
/* NULL-safe version of strcmp */
int tr_strcmp( const char*, const char * );
/* XXX this shouldn't be here */
enum tr_torrent_action { TR_TOR_LEAVE, TR_TOR_COPY, TR_TOR_MOVE };
/* return number of items in array */
#define ALEN(a) ((signed)G_N_ELEMENTS(a))
@ -82,14 +79,6 @@ decode_uri( const char * uri );
GList *
checkfilenames( int argc, char ** argv );
/* returns the flag for an action string */
enum tr_torrent_action
toraddaction( const char * action );
/* returns the action string for a flag */
const char *
toractionname( enum tr_torrent_action action );
/* retrieve the global download directory */
char *
getdownloaddir( void );

View File

@ -3,12 +3,14 @@ gtk/transmission.desktop.in
gtk/actions.c
gtk/conf.c
gtk/dialogs.c
gtk/file-list.c
gtk/hig.c
gtk/io.c
gtk/ipc.c
gtk/main.c
gtk/makemeta-ui.c
gtk/msgwin.c
gtk/open.c
gtk/stats.c
gtk/torrent-cell-renderer.c
gtk/torrent-inspector.c