Untangle the gordian references between TrCore and TrTorrent.
This commit is contained in:
parent
4567bc0b3f
commit
787e17135a
18
gtk/main.c
18
gtk/main.c
|
@ -517,7 +517,7 @@ wannaquit( void * vdata )
|
|||
data->timer = 0;
|
||||
|
||||
/* pause torrents and stop nat traversal */
|
||||
tr_core_quit( data->core );
|
||||
tr_core_shutdown( data->core );
|
||||
|
||||
/* set things up to wait for torrents to stop */
|
||||
edata = g_new0(struct exitdata, 1);
|
||||
|
@ -546,17 +546,12 @@ exitcheck( gpointer gdata )
|
|||
/* keep waiting until we're ready to quit or we hit the exit timeout */
|
||||
if( time( NULL ) - edata->started < TRACKER_EXIT_TIMEOUT )
|
||||
{
|
||||
if( !tr_core_did_quit( cbdata->core ) )
|
||||
if( !tr_core_quiescent( cbdata->core ) )
|
||||
{
|
||||
updatemodel( cbdata );
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* oh well */
|
||||
tr_core_force_quit( cbdata->core );
|
||||
}
|
||||
|
||||
/* exit otherwise */
|
||||
if( 0 < edata->timer )
|
||||
|
@ -574,7 +569,6 @@ exitcheck( gpointer gdata )
|
|||
{
|
||||
gtk_widget_destroy( GTK_WIDGET( cbdata->wind ) );
|
||||
}
|
||||
tr_core_clear( cbdata->core ); /* XXX god these circular references suck */
|
||||
g_object_unref( cbdata->core );
|
||||
if( NULL != cbdata->icon )
|
||||
{
|
||||
|
@ -803,12 +797,6 @@ updatemodel(gpointer gdata) {
|
|||
tr_window_update( TR_WINDOW( data->wind ), down, up );
|
||||
}
|
||||
|
||||
/* check for stopped torrents unless we're exiting */
|
||||
if( !data->closing )
|
||||
{
|
||||
tr_core_reap( data->core );
|
||||
}
|
||||
|
||||
/* update the message window */
|
||||
msgwin_update();
|
||||
|
||||
|
@ -942,7 +930,7 @@ handleaction( struct cbdata * data, int act )
|
|||
changed = TRUE;
|
||||
break;
|
||||
case ACT_DELETE:
|
||||
tr_core_delete_torrent( data->core, tor, &iter );
|
||||
tr_core_delete_torrent( data->core, &iter );
|
||||
changed = TRUE;
|
||||
break;
|
||||
case ACT_INFO:
|
||||
|
|
281
gtk/tr_core.c
281
gtk/tr_core.c
|
@ -44,10 +44,10 @@ static void
|
|||
tr_core_class_init( gpointer g_class, gpointer g_class_data );
|
||||
static void
|
||||
tr_core_dispose( GObject * obj );
|
||||
static void
|
||||
tr_core_torrent_finalized( gpointer gdata, GObject * tor );
|
||||
static int
|
||||
tr_core_check_torrents( TrCore * self, gboolean timeout );
|
||||
tr_core_check_torrents( TrCore * self );
|
||||
static int
|
||||
tr_core_check_zombies( TrCore * self );
|
||||
static void
|
||||
tr_core_insert( TrCore * self, TrTorrent * tor );
|
||||
|
||||
|
@ -108,13 +108,17 @@ tr_core_init( GTypeInstance * instance, gpointer g_class SHUTUP )
|
|||
TR_TRACKER_BOXED_TYPE, TR_TORRENT_TYPE,
|
||||
};
|
||||
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "core %p init\n", self );
|
||||
#endif
|
||||
|
||||
/* create the model used to store torrent data */
|
||||
g_assert( ALEN( types ) == MC_ROW_COUNT );
|
||||
store = gtk_list_store_newv( MC_ROW_COUNT, types );
|
||||
|
||||
self->model = GTK_TREE_MODEL( store );
|
||||
self->handle = tr_init( "gtk" );
|
||||
self->torrents = NULL;
|
||||
self->zombies = NULL;
|
||||
self->quitting = FALSE;
|
||||
self->disposed = FALSE;
|
||||
}
|
||||
|
@ -124,7 +128,9 @@ tr_core_dispose( GObject * obj )
|
|||
{
|
||||
TrCore * self = (TrCore *) obj;
|
||||
GObjectClass * parent;
|
||||
GtkTreeIter iter;
|
||||
GList * ii;
|
||||
TrTorrent * tor;
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
|
@ -132,22 +138,39 @@ tr_core_dispose( GObject * obj )
|
|||
}
|
||||
self->disposed = TRUE;
|
||||
|
||||
if( NULL != self->model )
|
||||
{
|
||||
g_object_unref( self->model );
|
||||
self->model = NULL;
|
||||
}
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "core %p dispose\n", self );
|
||||
#endif
|
||||
|
||||
if( NULL != self->torrents )
|
||||
/* sever all remaining torrents in the model */
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter ) )
|
||||
{
|
||||
for( ii = g_list_first( self->torrents ); NULL != ii; ii = ii->next )
|
||||
do
|
||||
{
|
||||
g_object_weak_unref( ii->data, tr_core_torrent_finalized, self );
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_sever( tor );
|
||||
g_object_unref( tor );
|
||||
}
|
||||
g_list_free( self->torrents );
|
||||
self->torrents = NULL;
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
g_object_unref( self->model );
|
||||
|
||||
/* sever and unref all remaining zombie torrents */
|
||||
if( NULL != self->zombies )
|
||||
{
|
||||
for( ii = g_list_first( self->zombies ); NULL != ii; ii = ii->next )
|
||||
{
|
||||
tr_torrent_sever( ii->data );
|
||||
g_object_unref( ii->data );
|
||||
}
|
||||
g_list_free( self->zombies );
|
||||
}
|
||||
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "core %p dead\n", self );
|
||||
#endif
|
||||
|
||||
/* close the libtransmission instance */
|
||||
tr_close( self->handle );
|
||||
|
||||
/* Chain up to the parent class */
|
||||
|
@ -155,16 +178,6 @@ tr_core_dispose( GObject * obj )
|
|||
parent->dispose( obj );
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_torrent_finalized( gpointer gdata, GObject * tor )
|
||||
{
|
||||
TrCore * self = gdata;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
self->torrents = g_list_remove( self->torrents, tor );
|
||||
}
|
||||
|
||||
TrCore *
|
||||
tr_core_new( void )
|
||||
{
|
||||
|
@ -176,6 +189,11 @@ tr_core_model( TrCore * self )
|
|||
{
|
||||
TR_IS_CORE( self );
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
|
@ -184,122 +202,149 @@ tr_core_handle( TrCore * self )
|
|||
{
|
||||
TR_IS_CORE( self );
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self->handle;
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_quit( TrCore * self )
|
||||
tr_core_shutdown( TrCore * self )
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
TrTorrent * tor;
|
||||
GList * ii;
|
||||
tr_stat_t * st;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert( !self->quitting );
|
||||
self->quitting = TRUE;
|
||||
|
||||
/*
|
||||
Add a reference to all torrents in the list, which will be
|
||||
removed when the politely-stopped signal is emitted. This is
|
||||
necessary because a reference is added when a torrent is removed
|
||||
from the model and tr_torrent_stop_polite() is called on it.
|
||||
*/
|
||||
/* try to stop all the torrents nicely */
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
st = tr_torrent_stat( tor );
|
||||
if( TR_STATUS_ACTIVE & st->status )
|
||||
{
|
||||
tr_torrentStop( tr_torrent_handle( tor ) );
|
||||
}
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
/* try to politely stop all the torrents */
|
||||
for( ii = g_list_first( self->torrents ); NULL != ii; ii = ii->next )
|
||||
{
|
||||
tr_torrent_stop_politely( ii->data );
|
||||
}
|
||||
|
||||
/* shut down nat traversal */
|
||||
tr_natTraversalEnable( self->handle, 0 );
|
||||
}
|
||||
|
||||
gboolean
|
||||
tr_core_did_quit( TrCore * self )
|
||||
tr_core_quiescent( TrCore * self )
|
||||
{
|
||||
tr_handle_status_t * hstat;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
g_assert( self->quitting );
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( 0 < tr_core_check_torrents( self ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hstat = tr_handleStatus( self->handle );
|
||||
|
||||
return ( 0 == tr_core_check_torrents( self, FALSE ) &&
|
||||
TR_NAT_TRAVERSAL_DISABLED == hstat->natTraversalStatus );
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_force_quit( TrCore * self )
|
||||
{
|
||||
TR_IS_CORE( self );
|
||||
g_assert( self->quitting );
|
||||
|
||||
/* time the remaining torrents out so they signal politely-stopped */
|
||||
tr_core_check_torrents( self, TRUE );
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_clear( TrCore * self )
|
||||
{
|
||||
TR_IS_CORE( self );
|
||||
|
||||
if( NULL != self->model )
|
||||
{
|
||||
g_object_unref( self->model );
|
||||
self->model = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_reap( TrCore * self )
|
||||
{
|
||||
TR_IS_CORE( self );
|
||||
|
||||
tr_core_check_torrents( self, FALSE );
|
||||
return TR_NAT_TRAVERSAL_DISABLED == hstat->natTraversalStatus;
|
||||
}
|
||||
|
||||
int
|
||||
tr_core_check_torrents( TrCore * self, gboolean timeout )
|
||||
tr_core_check_torrents( TrCore * self )
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
tr_stat_t * st;
|
||||
GList * ii, * list;
|
||||
int count;
|
||||
TrTorrent * tor;
|
||||
|
||||
g_assert( !self->disposed && self->quitting );
|
||||
|
||||
count = 0;
|
||||
list = g_list_copy( self->torrents );
|
||||
for( ii = g_list_first( list ); NULL != ii; ii = ii->next )
|
||||
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
st = tr_torrent_stat_polite( ii->data, timeout );
|
||||
if( NULL == st || !( TR_STATUS_PAUSE & st->status ) )
|
||||
do
|
||||
{
|
||||
count++;
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
st = tr_torrent_stat( tor );
|
||||
if( !( TR_STATUS_PAUSE & st->status ) )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
g_list_free( list );
|
||||
|
||||
count += tr_core_check_zombies( self );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
tr_core_check_zombies( TrCore * self )
|
||||
{
|
||||
GList * ii, * next;
|
||||
tr_stat_t * st;
|
||||
|
||||
for( ii = g_list_first( self->zombies ); NULL != ii; ii = next )
|
||||
{
|
||||
next = ii->next;
|
||||
st = tr_torrent_stat( ii->data );
|
||||
if( TR_STATUS_PAUSE & st->status )
|
||||
{
|
||||
tr_torrent_sever( ii->data );
|
||||
g_object_unref( ii->data );
|
||||
/* XXX is this safe to do? */
|
||||
self->zombies = g_list_delete_link( self->zombies, ii );
|
||||
}
|
||||
}
|
||||
|
||||
return g_list_length( self->zombies );
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_save( TrCore * self, char ** error )
|
||||
{
|
||||
benc_val_t state;
|
||||
GList * ii;
|
||||
benc_val_t state;
|
||||
int count;
|
||||
GtkTreeIter iter;
|
||||
TrTorrent * tor;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
do
|
||||
{
|
||||
count++;
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
tr_bencInit( &state, TYPE_LIST );
|
||||
if( tr_bencListReserve( &state, g_list_length( self->torrents ) ) )
|
||||
if( tr_bencListReserve( &state, count ) )
|
||||
{
|
||||
if( NULL != error )
|
||||
{
|
||||
|
@ -308,17 +353,29 @@ tr_core_save( TrCore * self, char ** error )
|
|||
return;
|
||||
}
|
||||
|
||||
for( ii = g_list_first( self->torrents ); NULL != ii; ii = ii->next )
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
tr_torrent_get_state( ii->data, tr_bencListAdd( &state ) );
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_get_state( tor, tr_bencListAdd( &state ) );
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
cf_savestate( &state, error );
|
||||
tr_bencFree( &state );
|
||||
|
||||
for( ii = g_list_first( self->torrents ); NULL != ii; ii = ii->next )
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
tr_torrent_state_saved( ii->data );
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_state_saved( tor );
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,8 +397,8 @@ tr_core_load( TrCore * self, benc_val_t * state, GList ** errors )
|
|||
for( ii = 0; ii < state->val.l.count; ii++ )
|
||||
{
|
||||
errstr = NULL;
|
||||
tor = tr_torrent_new_with_state( G_OBJECT( self ),
|
||||
state->val.l.vals + ii, 0, &errstr );
|
||||
tor = tr_torrent_new_with_state( self->handle, state->val.l.vals + ii,
|
||||
0, &errstr );
|
||||
if( NULL != errstr )
|
||||
{
|
||||
*errors = g_list_append( *errors, errstr );
|
||||
|
@ -364,7 +421,7 @@ tr_core_add_torrent( TrCore * self, const char * torrent, const char * dir,
|
|||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
tor = tr_torrent_new( G_OBJECT( self ), torrent, dir, flags, err );
|
||||
tor = tr_torrent_new( self->handle, torrent, dir, flags, err );
|
||||
if( NULL == tor )
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -376,19 +433,32 @@ tr_core_add_torrent( TrCore * self, const char * torrent, const char * dir,
|
|||
}
|
||||
|
||||
void
|
||||
tr_core_delete_torrent( TrCore * self, void * torrent,
|
||||
GtkTreeIter * iter )
|
||||
tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter )
|
||||
{
|
||||
TrTorrent * tor;
|
||||
tr_stat_t * st;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
/* tor will be unref'd in the politely_stopped handler */
|
||||
g_object_ref( torrent );
|
||||
tr_torrent_stop_politely( torrent );
|
||||
if( TR_FLAG_SAVE & tr_torrent_info( torrent )->flags )
|
||||
{
|
||||
tr_torrentRemoveSaved( tr_torrent_handle( torrent ) );
|
||||
}
|
||||
gtk_tree_model_get( self->model, iter, MC_TORRENT, &tor, -1 );
|
||||
|
||||
gtk_list_store_remove( GTK_LIST_STORE( self->model ), iter );
|
||||
if( TR_FLAG_SAVE & tr_torrent_info( tor )->flags )
|
||||
{
|
||||
tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
|
||||
}
|
||||
|
||||
st = tr_torrent_stat( tor );
|
||||
if( TR_STATUS_ACTIVE & st->status )
|
||||
{
|
||||
tr_torrentStop( tr_torrent_handle( tor ) );
|
||||
self->zombies = g_list_append( self->zombies, tor );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_torrent_sever( tor );
|
||||
g_object_unref( tor );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -397,23 +467,13 @@ tr_core_insert( TrCore * self, TrTorrent * tor )
|
|||
GtkTreeIter iter;
|
||||
tr_info_t * inf;
|
||||
|
||||
g_object_weak_ref( G_OBJECT( tor ), tr_core_torrent_finalized, self );
|
||||
self->torrents = g_list_append( self->torrents, tor );
|
||||
|
||||
gtk_list_store_append( GTK_LIST_STORE( self->model ), &iter );
|
||||
inf = tr_torrent_info( tor );
|
||||
|
||||
/* inserting the torrent into the model adds a reference */
|
||||
gtk_list_store_set( GTK_LIST_STORE( self->model ), &iter,
|
||||
MC_NAME, inf->name,
|
||||
MC_SIZE, inf->totalSize,
|
||||
MC_TORRENT, tor,
|
||||
-1);
|
||||
|
||||
/* we will always ref a torrent before politely stopping it */
|
||||
g_signal_connect( tor, "politely_stopped",
|
||||
G_CALLBACK( g_object_unref ), NULL );
|
||||
|
||||
g_object_unref( tor );
|
||||
}
|
||||
|
||||
|
@ -457,4 +517,9 @@ tr_core_update( TrCore * self )
|
|||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
if( !self->quitting )
|
||||
{
|
||||
tr_core_check_zombies( self );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,14 +58,14 @@ struct _TrCore
|
|||
GObject parent;
|
||||
GtkTreeModel * model;
|
||||
tr_handle_t * handle;
|
||||
GList * torrents;
|
||||
GList * zombies;
|
||||
gboolean quitting;
|
||||
gboolean disposed;
|
||||
};
|
||||
|
||||
struct _TrCoreClass
|
||||
{
|
||||
GObjectClass parent;
|
||||
GObjectClass parent;
|
||||
};
|
||||
|
||||
GType
|
||||
|
@ -84,23 +84,11 @@ tr_core_handle( TrCore * self );
|
|||
|
||||
/* Try to politely stop all torrents and nat traversal */
|
||||
void
|
||||
tr_core_quit( TrCore * self );
|
||||
tr_core_shutdown( TrCore * self );
|
||||
|
||||
/* Returns true if tr_core_quit() has been called and we are ready to quit */
|
||||
/* Returns true if the shutdown has completed */
|
||||
gboolean
|
||||
tr_core_did_quit( TrCore * self );
|
||||
|
||||
/* Destroy any torrents that haven't stopped already */
|
||||
void
|
||||
tr_core_force_quit( TrCore * self );
|
||||
|
||||
/* XXX temporary hack to deal with circular references */
|
||||
void
|
||||
tr_core_clear( TrCore * self );
|
||||
|
||||
/* Check for stopped torrents */
|
||||
void
|
||||
tr_core_reap( TrCore * self );
|
||||
tr_core_quiescent( TrCore * self );
|
||||
|
||||
/* Save state. If error is not NULL is will be set to any error which
|
||||
occurs, this must be freed. */
|
||||
|
@ -121,9 +109,9 @@ tr_core_add_torrent( TrCore * self, const char * torrent, const char * dir,
|
|||
|
||||
/* remove a torrent, waiting for it to pause if necessary */
|
||||
void
|
||||
tr_core_delete_torrent( TrCore * self, void * torrent,
|
||||
GtkTreeIter * iter /* XXX */ );
|
||||
tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter /* XXX */ );
|
||||
|
||||
/* update the model with current torrent status */
|
||||
void
|
||||
tr_core_update( TrCore * self );
|
||||
|
||||
|
|
141
gtk/tr_torrent.c
141
gtk/tr_torrent.c
|
@ -34,14 +34,12 @@
|
|||
/* XXX */
|
||||
#define TR_WANT_TORRENT_PRIVATE
|
||||
|
||||
#include "tr_core.h"
|
||||
#include "tr_prefs.h"
|
||||
#include "tr_torrent.h"
|
||||
#include "util.h"
|
||||
|
||||
enum {
|
||||
TR_TORRENT_HANDLE = 1,
|
||||
TR_TORRENT_BACKEND,
|
||||
TR_TORRENT_DIR,
|
||||
TR_TORRENT_PAUSED,
|
||||
};
|
||||
|
@ -114,7 +112,6 @@ tr_torrent_get_type(void) {
|
|||
static void
|
||||
tr_torrent_class_init(gpointer g_class, gpointer g_class_data SHUTUP) {
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
|
||||
TrTorrentClass *klass = TR_TORRENT_CLASS(g_class);
|
||||
GParamSpec *pspec;
|
||||
|
||||
gobject_class->set_property = tr_torrent_set_property;
|
||||
|
@ -126,12 +123,6 @@ tr_torrent_class_init(gpointer g_class, gpointer g_class_data SHUTUP) {
|
|||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
g_object_class_install_property(gobject_class, TR_TORRENT_HANDLE, pspec);
|
||||
|
||||
pspec = g_param_spec_object("backend", "Backend",
|
||||
"Libtransmission backend object",
|
||||
TR_CORE_TYPE,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
g_object_class_install_property(gobject_class, TR_TORRENT_BACKEND, pspec);
|
||||
|
||||
pspec = g_param_spec_string("download-directory", "Download directory",
|
||||
"Directory to download files to", NULL,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
|
@ -141,23 +132,20 @@ tr_torrent_class_init(gpointer g_class, gpointer g_class_data SHUTUP) {
|
|||
"Is the torrent paused or running", TRUE,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property(gobject_class, TR_TORRENT_PAUSED, pspec);
|
||||
|
||||
klass->paused_signal_id = g_signal_newv("politely-stopped",
|
||||
G_TYPE_FROM_CLASS(g_class),
|
||||
G_SIGNAL_RUN_LAST, NULL, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tr_torrent_init(GTypeInstance *instance, gpointer g_class SHUTUP) {
|
||||
TrTorrent *self = (TrTorrent *)instance;
|
||||
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "torrent %p init\n", self );
|
||||
#endif
|
||||
|
||||
self->handle = NULL;
|
||||
self->core = NULL;
|
||||
self->dir = NULL;
|
||||
self->closing = FALSE;
|
||||
self->delfile = NULL;
|
||||
self->severed = FALSE;
|
||||
self->disposed = FALSE;
|
||||
}
|
||||
|
||||
|
@ -166,7 +154,7 @@ tr_torrent_set_property(GObject *object, guint property_id,
|
|||
const GValue *value, GParamSpec *pspec) {
|
||||
TrTorrent *self = (TrTorrent*)object;
|
||||
|
||||
if(self->disposed)
|
||||
if(self->severed)
|
||||
return;
|
||||
|
||||
switch(property_id) {
|
||||
|
@ -176,10 +164,6 @@ tr_torrent_set_property(GObject *object, guint property_id,
|
|||
if(NULL != self->handle && NULL != self->dir)
|
||||
tr_torrent_set_folder(self);
|
||||
break;
|
||||
case TR_TORRENT_BACKEND:
|
||||
g_assert(NULL == self->core);
|
||||
self->core = g_object_ref( g_value_get_object( value ) );
|
||||
break;
|
||||
case TR_TORRENT_DIR:
|
||||
g_assert(NULL == self->dir);
|
||||
self->dir = g_value_dup_string(value);
|
||||
|
@ -203,16 +187,13 @@ tr_torrent_get_property(GObject *object, guint property_id,
|
|||
GValue *value, GParamSpec *pspec) {
|
||||
TrTorrent *self = (TrTorrent*)object;
|
||||
|
||||
if(self->disposed)
|
||||
if(self->severed)
|
||||
return;
|
||||
|
||||
switch(property_id) {
|
||||
case TR_TORRENT_HANDLE:
|
||||
g_value_set_pointer(value, self->handle);
|
||||
break;
|
||||
case TR_TORRENT_BACKEND:
|
||||
g_value_set_object( value, self->core );
|
||||
break;
|
||||
case TR_TORRENT_DIR:
|
||||
g_value_set_string(value, (NULL != self->dir ? self->dir :
|
||||
tr_torrentGetFolder(self->handle)));
|
||||
|
@ -235,17 +216,13 @@ tr_torrent_dispose(GObject *obj) {
|
|||
return;
|
||||
self->disposed = TRUE;
|
||||
|
||||
if(NULL != self->handle) {
|
||||
if(!tr_torrent_paused(self))
|
||||
tr_torrentStop(self->handle);
|
||||
tr_torrentClose( self->handle );
|
||||
self->handle = NULL;
|
||||
}
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "torrent %p dispose\n", self );
|
||||
#endif
|
||||
|
||||
if( NULL != self->core )
|
||||
if( !self->severed )
|
||||
{
|
||||
g_object_unref( self->core );
|
||||
self->core = NULL;
|
||||
tr_torrent_sever( self );
|
||||
}
|
||||
|
||||
if(NULL != self->delfile)
|
||||
|
@ -255,11 +232,39 @@ tr_torrent_dispose(GObject *obj) {
|
|||
parent->dispose(obj);
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrent_sever( TrTorrent * self )
|
||||
{
|
||||
TR_IS_TORRENT( self );
|
||||
|
||||
if( self->severed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "torrent %p sever\n", self );
|
||||
#endif
|
||||
|
||||
if( NULL == self->handle )
|
||||
{
|
||||
self->severed = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !tr_torrent_paused( self ) )
|
||||
{
|
||||
tr_torrentStop( self->handle );
|
||||
}
|
||||
tr_torrentClose( self->handle );
|
||||
self->severed = TRUE;
|
||||
}
|
||||
|
||||
tr_torrent_t *
|
||||
tr_torrent_handle(TrTorrent *tor) {
|
||||
TR_IS_TORRENT(tor);
|
||||
|
||||
if(tor->disposed)
|
||||
if(tor->severed)
|
||||
return NULL;
|
||||
|
||||
return tor->handle;
|
||||
|
@ -269,7 +274,7 @@ tr_stat_t *
|
|||
tr_torrent_stat(TrTorrent *tor) {
|
||||
TR_IS_TORRENT(tor);
|
||||
|
||||
if(tor->disposed)
|
||||
if(tor->severed)
|
||||
return NULL;
|
||||
|
||||
return tr_torrentStat(tor->handle);
|
||||
|
@ -279,27 +284,24 @@ tr_info_t *
|
|||
tr_torrent_info(TrTorrent *tor) {
|
||||
TR_IS_TORRENT(tor);
|
||||
|
||||
if(tor->disposed)
|
||||
if(tor->severed)
|
||||
return NULL;
|
||||
|
||||
return tr_torrentInfo(tor->handle);
|
||||
}
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new( GObject * core, const char *torrent, const char *dir,
|
||||
tr_torrent_new( tr_handle_t * back, const char *torrent, const char *dir,
|
||||
guint flags, char **err) {
|
||||
TrTorrent *ret;
|
||||
tr_torrent_t *handle;
|
||||
tr_handle_t *back;
|
||||
int errcode, trflags;
|
||||
gboolean boolval;
|
||||
|
||||
TR_IS_CORE( core );
|
||||
g_assert(NULL != dir);
|
||||
|
||||
*err = NULL;
|
||||
|
||||
back = tr_core_handle( TR_CORE( core ) );
|
||||
trflags = 0;
|
||||
if((TR_TORNEW_SAVE_COPY|TR_TORNEW_SAVE_MOVE) & flags)
|
||||
trflags |= TR_FLAG_SAVE;
|
||||
|
@ -331,7 +333,7 @@ tr_torrent_new( GObject * core, const char *torrent, const char *dir,
|
|||
tr_torrentDisablePex( handle, !boolval );
|
||||
|
||||
ret = g_object_new(TR_TORRENT_TYPE, "torrent-handle", handle,
|
||||
"backend", core, "download-directory", dir, NULL);
|
||||
"download-directory", dir, NULL);
|
||||
|
||||
g_object_set(ret, "paused", (TR_TORNEW_PAUSED & flags ? TRUE : FALSE), NULL);
|
||||
|
||||
|
@ -342,7 +344,7 @@ tr_torrent_new( GObject * core, const char *torrent, const char *dir,
|
|||
}
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new_with_state( GObject * core, benc_val_t * state,
|
||||
tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
|
||||
guint forcedflags, char ** err)
|
||||
{
|
||||
int ii;
|
||||
|
@ -396,7 +398,7 @@ tr_torrent_new_with_state( GObject * core, benc_val_t * state,
|
|||
flags |= forcedflags;
|
||||
}
|
||||
|
||||
return tr_torrent_new( core, torrent, dir, flags, err );
|
||||
return tr_torrent_new( back, torrent, dir, flags, err );
|
||||
}
|
||||
|
||||
#define SETSTRVAL(vv, ss) \
|
||||
|
@ -412,10 +414,7 @@ tr_torrent_get_state(TrTorrent *tor, benc_val_t *state) {
|
|||
|
||||
TR_IS_TORRENT(tor);
|
||||
|
||||
if(tor->disposed)
|
||||
return;
|
||||
|
||||
if(tor->closing)
|
||||
if(tor->severed)
|
||||
return;
|
||||
|
||||
state->type = TYPE_DICT;
|
||||
|
@ -441,7 +440,7 @@ void
|
|||
tr_torrent_state_saved(TrTorrent *tor) {
|
||||
TR_IS_TORRENT(tor);
|
||||
|
||||
if(tor->disposed)
|
||||
if(tor->severed)
|
||||
return;
|
||||
|
||||
if(NULL != tor->delfile) {
|
||||
|
@ -471,45 +470,3 @@ tr_torrent_paused(TrTorrent *tor) {
|
|||
|
||||
return (TR_STATUS_INACTIVE & st->status ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrent_stop_politely(TrTorrent *tor) {
|
||||
tr_stat_t *st;
|
||||
|
||||
TR_IS_TORRENT(tor);
|
||||
|
||||
if(tor->disposed)
|
||||
return;
|
||||
|
||||
if(!tor->closing) {
|
||||
st = tr_torrent_stat(tor);
|
||||
tor->closing = TRUE;
|
||||
if(TR_STATUS_ACTIVE & st->status)
|
||||
tr_torrentStop(tor->handle);
|
||||
}
|
||||
}
|
||||
|
||||
tr_stat_t *
|
||||
tr_torrent_stat_polite( TrTorrent * tor, gboolean timeout )
|
||||
{
|
||||
TrTorrentClass * klass;
|
||||
tr_stat_t * st;
|
||||
|
||||
TR_IS_TORRENT( tor );
|
||||
|
||||
if( tor->disposed )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -54,16 +54,14 @@ typedef struct _TrTorrentClass TrTorrentClass;
|
|||
struct _TrTorrent {
|
||||
GObject parent;
|
||||
tr_torrent_t *handle;
|
||||
GObject *core;
|
||||
char *dir;
|
||||
gboolean closing;
|
||||
char *delfile;
|
||||
gboolean severed;
|
||||
gboolean disposed;
|
||||
};
|
||||
|
||||
struct _TrTorrentClass {
|
||||
GObjectClass parent;
|
||||
int paused_signal_id;
|
||||
};
|
||||
|
||||
GType
|
||||
|
@ -91,25 +89,22 @@ tr_torrent_info(TrTorrent *tor);
|
|||
#ifdef TR_WANT_TORRENT_PRIVATE
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new(GObject *backend, const char *torrent, const char *dir,
|
||||
guint flags, char **err);
|
||||
tr_torrent_new( tr_handle_t * handle, const char *torrent, const char *dir,
|
||||
guint flags, char **err);
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new_with_state( GObject * backend, benc_val_t * state,
|
||||
tr_torrent_new_with_state( tr_handle_t * handle, benc_val_t * state,
|
||||
guint flags, char ** err );
|
||||
|
||||
void
|
||||
tr_torrent_stop_politely(TrTorrent *tor);
|
||||
|
||||
tr_stat_t *
|
||||
tr_torrent_stat_polite( TrTorrent * tor, gboolean timeout );
|
||||
|
||||
void
|
||||
tr_torrent_get_state(TrTorrent *tor, benc_val_t *state);
|
||||
|
||||
void
|
||||
tr_torrent_state_saved(TrTorrent *tor);
|
||||
|
||||
void
|
||||
tr_torrent_sever( TrTorrent * tor );
|
||||
|
||||
#endif /* TR_WANT_TORRENT_PRIVATE */
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue