(gtk) #772, #753: added `watch dir' for automatically adding torrents. delete files to trashcan, rather than unlinking them. These features require 2.15.5 or higher.

This commit is contained in:
Charles Kerr 2008-03-09 15:27:08 +00:00
parent e85a328b1b
commit e4562bcd7b
11 changed files with 180 additions and 21 deletions

View File

@ -10,10 +10,12 @@ AC_CONFIG_SRCDIR(libtransmission/transmission.h)
AM_INIT_AUTOMAKE([1.9 tar-ustar])
AC_PROG_LIBTOOL
GIO_MINIMUM=2.15.5
GLIB_MINIMUM=2.6.0
GTK_MINIMUM=2.6.0
WX_MINIMUM=2.6.0
LIBNOTIFY_MINIMUM=0.4.4
AC_SUBST(GIO_MINIMUM)
AC_SUBST(GLIB_MINIMUM)
AC_SUBST(GTK_MINIMUM)
AC_SUBST(WX_MINIMUM)
@ -94,6 +96,16 @@ AM_CONDITIONAL([BUILD_GTK],[test "x$build_gtk" = "xyes"])
AC_SUBST(GTK_LIBS)
AC_SUBST(GTK_CFLAGS)
PKG_CHECK_MODULES([GIO],
[gio-2.0 >= $GIO_MINIMUM],
[use_gio=yes],
[use_gio=no])
AC_SUBST(GIO_LIBS)
AC_SUBST(GIO_CFLAGS)
if test "x$use_gio" = "xyes"; then
AC_DEFINE([HAVE_GIO], 1)
fi
PKG_CHECK_MODULES([LIBNOTIFY],
[libnotify >= $LIBNOTIFY_MINIMUM],
[use_libnotify=yes],
@ -277,6 +289,7 @@ Configuration:
Build BeOS client: ${build_beos}
Build GTK+ client: ${build_gtk}
... libnotify support: ${use_libnotify}
... gio support: ${use_gio}
Build OS X client: ${build_darwin}
Build wxWidgets client: ${build_wx}

View File

@ -10,6 +10,7 @@ AM_CFLAGS = \
$(GTK_CFLAGS) \
$(OPENSSL_CFLAGS) \
$(PTHREAD_CFLAGS) \
$(GIO_CFLAGS) \
$(LIBNOTIFY_CFLAGS)
noinst_HEADERS = \
@ -71,6 +72,7 @@ transmission_LDADD = \
$(top_builddir)/third-party/miniupnp/libminiupnp.a \
$(top_builddir)/third-party/libnatpmp/libnatpmp.a \
$(GTK_LIBS) \
$(GIO_LIBS) \
$(LIBNOTIFY_LIBS) \
$(OPENSSL_LIBS) \
$(PTHREAD_LIBS) -lm

View File

@ -153,8 +153,10 @@ promptfordir( GtkWindow * parent, TrCore * core, GList * files, tr_ctor * ctor )
v = gtk_vbox_new( FALSE, GUI_PAD );
flag = 0;
w = gtk_check_button_new_with_mnemonic( _( "_Delete original torrent file" ) );
w = gtk_check_button_new_with_mnemonic( _( "_Trash original torrent files" ) );
g_signal_connect( w, "toggled", G_CALLBACK( deleteToggled ), ctor );
if( tr_ctorGetDeleteSource( ctor, &flag ) )
g_assert_not_reached( );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );

View File

@ -33,6 +33,7 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h> /* g_unlink */
#include <libevent/evutil.h>
@ -359,8 +360,8 @@ ipc_sendquit_blocking( void )
static void
rmsock(void) {
if(NULL != gl_sockpath) {
unlink(gl_sockpath);
if( gl_sockpath) {
g_unlink(gl_sockpath);
g_free(gl_sockpath);
}
}
@ -463,10 +464,10 @@ serv_bind(struct constate *con) {
strncpy(sa.sun_path, gl_sockpath, sizeof(sa.sun_path) - 1);
/* unlink any existing socket file before trying to create ours */
unlink(gl_sockpath);
g_unlink(gl_sockpath);
if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa))) {
/* bind may fail if there was already a socket, so try twice */
unlink(gl_sockpath);
g_unlink(gl_sockpath);
if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa)))
goto fail;
}

View File

@ -11,7 +11,6 @@
*/
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "file-list.h"
#include "hig.h"
@ -22,7 +21,7 @@ struct OpenData
TrCore * core;
GtkWidget * list;
GtkToggleButton * run_check;
GtkToggleButton * delete_check;
GtkToggleButton * trash_check;
char * filename;
char * destination;
TrTorrent * gtor;
@ -55,8 +54,8 @@ openResponseCB( GtkDialog * dialog, gint response, gpointer gdata )
if( gtk_toggle_button_get_active( data->run_check ) )
tr_torrentStart( tr_torrent_handle( data->gtor ) );
tr_core_add_torrent( data->core, data->gtor );
if( gtk_toggle_button_get_active( data->delete_check ) )
g_unlink( data->filename );
if( gtk_toggle_button_get_active( data->trash_check ) )
tr_file_trash_or_unlink( data->filename );
}
}
@ -221,8 +220,10 @@ makeaddwind( GtkWindow * parent,
++row;
col = 0;
w = gtk_check_button_new_with_mnemonic( _( "_Delete original torrent file" ) );
data->delete_check = GTK_TOGGLE_BUTTON( w );
w = gtk_check_button_new_with_mnemonic( _( "_Trash original torrent file" ) );
data->trash_check = GTK_TOGGLE_BUTTON( w );
if( tr_ctorGetDeleteSource( ctor, &flag ) )
g_assert_not_reached( );
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 );

View File

@ -26,6 +26,9 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#ifdef HAVE_GIO
#include <gio/gio.h>
#endif
#include <libtransmission/transmission.h>
#include <libtransmission/utils.h> /* tr_free */
@ -38,6 +41,9 @@
struct TrCorePrivate
{
#ifdef HAVE_GIO
GFileMonitor * monitor;
#endif
GtkTreeModel * model;
tr_handle * handle;
int nextid;
@ -277,6 +283,74 @@ setSort( TrCore * core, const char * mode, gboolean isReversed )
gtk_tree_sortable_set_sort_column_id( sortable, col, type );
}
#ifdef HAVE_GIO
static void
watchFolderChanged( GFileMonitor * monitor UNUSED,
GFile * file,
GFile * other_type UNUSED,
GFileMonitorEvent event_type,
gpointer gcore )
{
if( event_type == G_FILE_MONITOR_EVENT_CREATED )
{
TrCore * core = TR_CORE( gcore );
char * filename = g_file_get_path( file );
const gboolean isTorrent = g_str_has_suffix( filename, ".torrent" );
if( isTorrent )
{
tr_ctor * ctor = tr_ctorNew( core->priv->handle );
tr_core_add_list( core, g_list_append( NULL, g_strdup( filename ) ), ctor );
}
g_free( filename );
}
}
static void
scanWatchDir( TrCore * core )
{
const gboolean isEnabled = pref_flag_get( PREF_KEY_DIR_WATCH_ENABLED );
if( isEnabled )
{
GList * torrents = NULL;
char * dirname = pref_string_get( PREF_KEY_DIR_WATCH );
GDir * dir = g_dir_open( dirname, 0, NULL );
const char * basename;
while(( basename = g_dir_read_name( dir )))
if( g_str_has_suffix( basename, ".torrent" ) )
torrents = g_list_append( torrents, g_build_filename( dirname, basename, NULL ) );
if( torrents )
tr_core_add_list( core, torrents, tr_ctorNew( core->priv->handle ) );
g_free( dirname );
}
}
static void
updateWatchDir( TrCore * core )
{
char * filename = pref_string_get( PREF_KEY_DIR_WATCH );
const gboolean isEnabled = pref_flag_get( PREF_KEY_DIR_WATCH_ENABLED );
if( core->priv->monitor && !isEnabled )
{
GFileMonitor * m = core->priv->monitor;
core->priv->monitor = NULL;
g_signal_handlers_disconnect_by_func( m, watchFolderChanged, core );
g_file_monitor_cancel( m );
g_object_unref( G_OBJECT( m ) );
}
else if( isEnabled && !core->priv->monitor )
{
GFile * file = g_file_new_for_path( filename );
GFileMonitor * m = g_file_monitor_directory( file, 0, NULL, NULL );
scanWatchDir( core );
g_signal_connect( m, "changed", G_CALLBACK (watchFolderChanged), core );
core->priv->monitor = m;
}
g_free( filename );
}
#endif
static void
prefsChanged( TrCore * core, const char * key, gpointer data UNUSED )
{
@ -293,6 +367,13 @@ prefsChanged( TrCore * core, const char * key, gpointer data UNUSED )
const uint16_t val = pref_int_get( key );
tr_setGlobalPeerLimit( tr_core_handle( core ), val );
}
#ifdef HAVE_GIO
else if( !strcmp( key, PREF_KEY_DIR_WATCH ) ||
!strcmp( key, PREF_KEY_DIR_WATCH_ENABLED ) )
{
updateWatchDir( core );
}
#endif
}
static void
@ -382,6 +463,7 @@ tr_core_new( void )
/* init from prefs & listen to pref changes */
prefsChanged( core, PREF_KEY_SORT_MODE, NULL );
prefsChanged( core, PREF_KEY_SORT_REVERSED, NULL );
prefsChanged( core, PREF_KEY_DIR_WATCH_ENABLED, NULL );
prefsChanged( core, PREF_KEY_MAX_PEERS_GLOBAL, NULL );
g_signal_connect( core, "prefs-changed", G_CALLBACK(prefsChanged), NULL );
@ -499,6 +581,9 @@ 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_TRASH_ORIGINAL ) );
if( tr_ctorGetMaxConnectedPeers( ctor, TR_FORCE, NULL ) )
tr_ctorSetMaxConnectedPeers( ctor, TR_FORCE,
pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );

View File

@ -31,6 +31,14 @@ tr_prefs_init_global( void )
cf_check_older_configs( );
#if HAVE_GIO
str = NULL;
if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DESKTOP );
if( !str ) str = g_get_home_dir( );
pref_string_set_default ( PREF_KEY_DIR_WATCH, str );
pref_flag_set_default ( PREF_KEY_DIR_WATCH_ENABLED, FALSE );
#endif
pref_int_set_default ( PREF_KEY_MAX_PEERS_GLOBAL, 200 );
pref_int_set_default ( PREF_KEY_MAX_PEERS_PER_TORRENT, 50 );
@ -47,11 +55,9 @@ tr_prefs_init_global( void )
str = NULL;
#if GLIB_CHECK_VERSION(2,14,0)
if( !str )
str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
#endif
if( !str )
str = g_get_home_dir( );
if( !str ) str = g_get_home_dir( );
pref_string_set_default ( PREF_KEY_DIR_DEFAULT, str );
pref_int_set_default ( PREF_KEY_PORT, TR_DEFAULT_PORT );
@ -70,6 +76,7 @@ tr_prefs_init_global( void )
pref_flag_set_default ( PREF_KEY_MINIMAL_VIEW, FALSE );
pref_flag_set_default ( PREF_KEY_START, TRUE );
pref_flag_set_default ( PREF_KEY_TRASH_ORIGINAL, FALSE );
pref_save( NULL );
}
@ -211,26 +218,40 @@ torrentPage( GObject * core )
const char * s;
GtkWidget * t;
GtkWidget * w;
GtkWidget * l;
t = hig_workarea_create( );
hig_workarea_add_section_title( t, &row, _( "Adding" ) );
w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
hig_workarea_add_row( t, &row, _( "Default destination _folder:" ), w, NULL );
#ifdef HAVE_GIO
s = _( "Automatically add torrents from:" );
l = new_check_button( s, PREF_KEY_DIR_WATCH_ENABLED, core );
w = new_path_chooser_button( PREF_KEY_DIR_WATCH, core );
gtk_widget_set_sensitive( GTK_WIDGET(w), pref_flag_get( PREF_KEY_DIR_WATCH_ENABLED ) );
g_signal_connect( l, "toggled", G_CALLBACK(target_cb), w );
hig_workarea_add_row_w( t, &row, l, w, NULL );
#endif
s = _( "Show _options dialog" );
w = new_check_button( s, PREF_KEY_OPTIONS_PROMPT, core );
hig_workarea_add_wide_control( t, &row, w );
s = _( "_Start when added" );
s = _( "_Start torrents when added" );
w = new_check_button( s, PREF_KEY_START, core );
hig_workarea_add_wide_control( t, &row, w );
s = _( "_Trash original torrent files" );
w = new_check_button( s, PREF_KEY_TRASH_ORIGINAL, core );
hig_workarea_add_wide_control( t, &row, w );
w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
hig_workarea_add_row( t, &row, _( "Default destination _folder:" ), w, NULL );
#ifdef HAVE_LIBNOTIFY
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title( t, &row, _( "Notification" ) );
s = _( "_Popup message when a torrent finishes" );
s = _( "_Display a message when torrents finish" );
w = new_check_button( s, PREF_KEY_NOTIFY, core );
hig_workarea_add_wide_control( t, &row, w );
#endif

View File

@ -26,7 +26,10 @@ GtkWidget * tr_prefs_dialog_new( GObject * core, GtkWindow * parent );
#define PREF_KEY_UL_LIMIT "upload-limit"
#define PREF_KEY_OPTIONS_PROMPT "show-options-window"
#define PREF_KEY_DIR_DEFAULT "default-download-directory"
#define PREF_KEY_DIR_WATCH "watch-folder"
#define PREF_KEY_DIR_WATCH_ENABLED "watch-folder-enabled"
#define PREF_KEY_START "start-added-torrents"
#define PREF_KEY_TRASH_ORIGINAL "trash-original-torrent-files"
#define PREF_KEY_PORT "listening-port"
#define PREF_KEY_NAT "nat-traversal-enabled"
#define PREF_KEY_PEX "pex-enabled"

View File

@ -27,7 +27,6 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <libtransmission/transmission.h>
@ -204,8 +203,17 @@ tr_torrent_new_ctor( tr_handle * handle,
errcode = -1;
*err = NULL;
tr_ctorSetDeleteSource( ctor, FALSE );
tor = tr_torrentNew( handle, ctor, &errcode );
if( tor )
{
uint8_t doTrash = FALSE;
tr_ctorGetDeleteSource( ctor, &doTrash );
if( doTrash )
tr_file_trash_or_unlink( tr_ctorGetSourceFile( ctor ) );
}
if( !tor )
{
const char * filename = tr_ctorGetSourceFile( ctor );
@ -334,7 +342,7 @@ tr_torrent_delete_files( TrTorrent * gtor )
while( strcmp( stop, file ) && strlen(stop) < strlen(file) )
{
char * swap = g_path_get_dirname( file );
g_unlink( file );
tr_file_trash_or_unlink( file );
g_free( file );
file = swap;
}

View File

@ -28,6 +28,10 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h> /* g_unlink() */
#ifdef HAVE_GIO
#include <gio/gio.h> /* g_file_trash() */
#endif
#include <libevent/evhttp.h>
@ -416,3 +420,20 @@ tr_object_ref_sink( gpointer object )
#endif
return object;
}
void
tr_file_trash_or_unlink( const char * filename )
{
if( filename && *filename )
{
gboolean trashed = FALSE;
#ifdef HAVE_GIO
GError * err = NULL;
GFile * file = g_file_new_for_path( filename );
trashed = g_file_trash( file, NULL, &err );
g_object_unref( G_OBJECT( file ) );
#endif
if( !trashed )
g_unlink( filename );
}
}

View File

@ -110,6 +110,8 @@ on_tree_view_button_pressed (GtkWidget * view,
gpointer tr_object_ref_sink (gpointer object);
void tr_file_trash_or_unlink( const char * filename );
#endif /* GTK_MAJOR_VERSION */
#endif /* TG_UTIL_H */