Add signal mechanism for reporting error from TrCore.
Use error signal for errors when adding torrents and saving state.
This commit is contained in:
parent
544c0c1dc4
commit
cc1394b1d6
91
gtk/main.c
91
gtk/main.c
|
@ -72,6 +72,7 @@ struct cbdata {
|
|||
guint timer;
|
||||
gboolean msgwinopen;
|
||||
gboolean closing;
|
||||
GList * errqueue;
|
||||
};
|
||||
|
||||
struct exitdata {
|
||||
|
@ -164,6 +165,9 @@ gotdrag(GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
|
|||
GtkSelectionData *sel, guint info, guint time, gpointer gdata);
|
||||
|
||||
static void
|
||||
coreerr( TrCore * core, enum tr_core_err code, const char * msg,
|
||||
gpointer gdata );
|
||||
static void
|
||||
readinitialprefs( struct cbdata * cbdata );
|
||||
static void
|
||||
prefschanged( GtkWidget * widget, int id, gpointer data );
|
||||
|
@ -184,8 +188,6 @@ static void
|
|||
addtorrents(void *vdata, void *state, GList *files,
|
||||
const char *dir, guint flags);
|
||||
static void
|
||||
savetorrents(struct cbdata *data);
|
||||
static void
|
||||
safepipe(void);
|
||||
static void
|
||||
setupsighandlers(void);
|
||||
|
@ -382,6 +384,10 @@ appsetup( TrWindow * wind, benc_val_t * state, GList * args, gboolean paused )
|
|||
cbdata->timer = 0;
|
||||
cbdata->msgwinopen = FALSE;
|
||||
cbdata->closing = FALSE;
|
||||
cbdata->errqueue = NULL;
|
||||
|
||||
/* set up error message handler */
|
||||
g_signal_connect( cbdata->core, "error", G_CALLBACK( coreerr ), cbdata );
|
||||
|
||||
/* apply a few prefs */
|
||||
readinitialprefs( cbdata );
|
||||
|
@ -575,6 +581,11 @@ exitcheck( gpointer gdata )
|
|||
g_object_unref( cbdata->icon );
|
||||
}
|
||||
g_assert( 0 == cbdata->timer );
|
||||
if( NULL != cbdata->errqueue )
|
||||
{
|
||||
g_list_foreach( cbdata->errqueue, (GFunc) g_free, NULL );
|
||||
g_list_free( cbdata->errqueue );
|
||||
}
|
||||
g_free( cbdata );
|
||||
gtk_main_quit();
|
||||
|
||||
|
@ -679,6 +690,42 @@ setupdrag(GtkWidget *widget, struct cbdata *data) {
|
|||
ALEN(targets), GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
}
|
||||
|
||||
static void
|
||||
coreerr( TrCore * core SHUTUP, enum tr_core_err code, const char * msg,
|
||||
gpointer gdata )
|
||||
{
|
||||
struct cbdata * cbdata = gdata;
|
||||
char * joined;
|
||||
|
||||
switch( code )
|
||||
{
|
||||
case TR_CORE_ERR_ADD_TORRENT:
|
||||
cbdata->errqueue = g_list_append( cbdata->errqueue,
|
||||
g_strdup( msg ) );
|
||||
return;
|
||||
case TR_CORE_ERR_NO_MORE_TORRENTS:
|
||||
if( NULL != cbdata->errqueue )
|
||||
{
|
||||
joined = joinstrlist( cbdata->errqueue, "\n" );
|
||||
errmsg( cbdata->wind,
|
||||
ngettext( "Failed to load torrent file:\n%s",
|
||||
"Failed to load torrent files:\n%s",
|
||||
g_list_length( cbdata->errqueue ) ),
|
||||
joined );
|
||||
g_list_foreach( cbdata->errqueue, (GFunc) g_free, NULL );
|
||||
g_list_free( cbdata->errqueue );
|
||||
cbdata->errqueue = NULL;
|
||||
g_free( joined );
|
||||
}
|
||||
return;
|
||||
case TR_CORE_ERR_SAVE_STATE:
|
||||
errmsg( cbdata->wind, "%s", msg );
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static void
|
||||
readinitialprefs( struct cbdata * cbdata )
|
||||
{
|
||||
|
@ -958,8 +1005,8 @@ handleaction( struct cbdata * data, int act )
|
|||
g_list_free(rows);
|
||||
|
||||
if(changed) {
|
||||
savetorrents(data);
|
||||
updatemodel(data);
|
||||
tr_core_save( data->core );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -967,17 +1014,14 @@ static void
|
|||
addtorrents(void *vdata, void *state, GList *files,
|
||||
const char *dir, guint flags) {
|
||||
struct cbdata *data = vdata;
|
||||
GList *errlist, *ii;
|
||||
char *errstr;
|
||||
const char * pref;
|
||||
int added;
|
||||
|
||||
errlist = NULL;
|
||||
added = 0;
|
||||
|
||||
if( NULL != state )
|
||||
{
|
||||
added += tr_core_load( data->core, state, &errlist );
|
||||
added += tr_core_load( data->core, state );
|
||||
}
|
||||
|
||||
if(NULL != files) {
|
||||
|
@ -991,47 +1035,24 @@ addtorrents(void *vdata, void *state, GList *files,
|
|||
}
|
||||
dir = getdownloaddir();
|
||||
}
|
||||
for(ii = g_list_first(files); NULL != ii; ii = ii->next) {
|
||||
errstr = NULL;
|
||||
if( tr_core_add_torrent( data->core, ii->data, dir, flags, &errstr ) )
|
||||
for( files = g_list_first( files ); NULL != files; files = files->next )
|
||||
{
|
||||
if( tr_core_add_torrent( data->core, files->data, dir, flags ) )
|
||||
{
|
||||
added++;
|
||||
}
|
||||
if(NULL != errstr)
|
||||
errlist = g_list_append(errlist, errstr);
|
||||
}
|
||||
}
|
||||
|
||||
if(NULL != errlist) {
|
||||
errstr = joinstrlist(errlist, "\n");
|
||||
errmsg( data->wind, ngettext( "Failed to load torrent file:\n%s",
|
||||
"Failed to load torrent files:\n%s",
|
||||
g_list_length( errlist ) ), errstr );
|
||||
g_list_foreach(errlist, (GFunc)g_free, NULL);
|
||||
g_list_free(errlist);
|
||||
g_free(errstr);
|
||||
}
|
||||
tr_core_torrents_added( data->core );
|
||||
|
||||
if( 0 < added )
|
||||
{
|
||||
updatemodel(data);
|
||||
savetorrents(data);
|
||||
tr_core_save( data->core );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
savetorrents( struct cbdata *data )
|
||||
{
|
||||
char * errstr;
|
||||
|
||||
tr_core_save( data->core, &errstr );
|
||||
if( NULL != errstr )
|
||||
{
|
||||
errmsg( data->wind, "%s", errstr );
|
||||
g_free( errstr );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
safepipe(void) {
|
||||
struct sigaction sa;
|
||||
|
|
118
gtk/tr_core.c
118
gtk/tr_core.c
|
@ -43,6 +43,9 @@ tr_core_init( GTypeInstance * instance, gpointer g_class );
|
|||
static void
|
||||
tr_core_class_init( gpointer g_class, gpointer g_class_data );
|
||||
static void
|
||||
tr_core_marshal_err( GClosure * closure, GValue * ret, guint count,
|
||||
const GValue * vals, gpointer hint, gpointer marshal );
|
||||
static void
|
||||
tr_core_dispose( GObject * obj );
|
||||
static int
|
||||
tr_core_check_torrents( TrCore * self );
|
||||
|
@ -50,6 +53,8 @@ static int
|
|||
tr_core_check_zombies( TrCore * self );
|
||||
static void
|
||||
tr_core_insert( TrCore * self, TrTorrent * tor );
|
||||
static void
|
||||
tr_core_errsig( TrCore * self, enum tr_core_err type, const char * msg );
|
||||
|
||||
GType
|
||||
tr_core_get_type( void )
|
||||
|
@ -81,9 +86,41 @@ void
|
|||
tr_core_class_init( gpointer g_class, gpointer g_class_data SHUTUP )
|
||||
{
|
||||
GObjectClass * gobject_class;
|
||||
TrCoreClass * core_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS( g_class );
|
||||
gobject_class->dispose = tr_core_dispose;
|
||||
|
||||
core_class = TR_CORE_CLASS( g_class );
|
||||
core_class->errsig = g_signal_new( "error", G_TYPE_FROM_CLASS( g_class ),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
|
||||
tr_core_marshal_err, G_TYPE_NONE,
|
||||
2, G_TYPE_INT, G_TYPE_STRING );
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_marshal_err( GClosure * closure, GValue * ret SHUTUP, guint count,
|
||||
const GValue * vals, gpointer hint SHUTUP,
|
||||
gpointer marshal )
|
||||
{
|
||||
typedef void (*TRMarshalErr) ( gpointer, enum tr_core_err, const char *,
|
||||
gpointer );
|
||||
TRMarshalErr callback;
|
||||
GCClosure * cclosure = (GCClosure*) closure;
|
||||
enum tr_core_err errcode;
|
||||
const char * errstr;
|
||||
gpointer inst, gdata;
|
||||
|
||||
g_return_if_fail( 3 == count );
|
||||
|
||||
inst = g_value_peek_pointer( vals );
|
||||
errcode = g_value_get_int( vals + 1 );
|
||||
errstr = g_value_get_string( vals + 2 );
|
||||
gdata = closure->data;
|
||||
|
||||
callback = (TRMarshalErr) ( NULL == marshal ?
|
||||
cclosure->callback : marshal );
|
||||
callback( inst, errcode, errstr, gdata );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -325,12 +362,14 @@ tr_core_check_zombies( TrCore * self )
|
|||
}
|
||||
|
||||
void
|
||||
tr_core_save( TrCore * self, char ** error )
|
||||
tr_core_save( TrCore * self )
|
||||
{
|
||||
benc_val_t state;
|
||||
benc_val_t state, * item;
|
||||
int count;
|
||||
GtkTreeIter iter;
|
||||
TrTorrent * tor;
|
||||
char * errstr;
|
||||
GList * saved, * ii;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
|
@ -346,41 +385,54 @@ tr_core_save( TrCore * self, char ** error )
|
|||
tr_bencInit( &state, TYPE_LIST );
|
||||
if( tr_bencListReserve( &state, count ) )
|
||||
{
|
||||
if( NULL != error )
|
||||
{
|
||||
*error = g_strdup( "malloc failure" );
|
||||
}
|
||||
tr_core_errsig( self, TR_CORE_ERR_SAVE_STATE, "malloc failure" );
|
||||
return;
|
||||
}
|
||||
|
||||
saved = NULL;
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
do
|
||||
{
|
||||
item = tr_bencListAdd( &state );
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_get_state( tor, tr_bencListAdd( &state ) );
|
||||
if( tr_torrent_get_state( tor, item ) )
|
||||
{
|
||||
saved = g_list_append( saved, tor );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_bencFree( item );
|
||||
tr_bencInitStr( item, NULL, 0, 1 );
|
||||
}
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
cf_savestate( &state, error );
|
||||
errstr = NULL;
|
||||
cf_savestate( &state, &errstr );
|
||||
tr_bencFree( &state );
|
||||
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
if( NULL != errstr )
|
||||
{
|
||||
do
|
||||
tr_core_errsig( self, TR_CORE_ERR_SAVE_STATE, errstr );
|
||||
g_free( errstr );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( ii = saved; NULL != ii; ii = ii->next )
|
||||
{
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_state_saved( tor );
|
||||
g_object_unref( tor );
|
||||
tr_torrent_state_saved( ii->data );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
if( NULL != saved )
|
||||
{
|
||||
g_list_free( saved );
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tr_core_load( TrCore * self, benc_val_t * state, GList ** errors )
|
||||
tr_core_load( TrCore * self, benc_val_t * state )
|
||||
{
|
||||
int ii, count;
|
||||
char * errstr;
|
||||
|
@ -399,12 +451,14 @@ tr_core_load( TrCore * self, benc_val_t * state, GList ** errors )
|
|||
errstr = NULL;
|
||||
tor = tr_torrent_new_with_state( self->handle, state->val.l.vals + ii,
|
||||
0, &errstr );
|
||||
if( NULL != errstr )
|
||||
if( NULL == tor )
|
||||
{
|
||||
*errors = g_list_append( *errors, errstr );
|
||||
tr_core_errsig( self, TR_CORE_ERR_ADD_TORRENT, errstr );
|
||||
g_free( errstr );
|
||||
}
|
||||
if( NULL != tor )
|
||||
else
|
||||
{
|
||||
g_assert( NULL == errstr );
|
||||
tr_core_insert( self, tor );
|
||||
count++;
|
||||
}
|
||||
|
@ -415,23 +469,36 @@ tr_core_load( TrCore * self, benc_val_t * state, GList ** errors )
|
|||
|
||||
gboolean
|
||||
tr_core_add_torrent( TrCore * self, const char * torrent, const char * dir,
|
||||
guint flags, char ** err )
|
||||
guint flags )
|
||||
{
|
||||
TrTorrent * tor;
|
||||
char * errstr;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
tor = tr_torrent_new( self->handle, torrent, dir, flags, err );
|
||||
errstr = NULL;
|
||||
tor = tr_torrent_new( self->handle, torrent, dir, flags, &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_errsig( self, TR_CORE_ERR_NO_MORE_TORRENTS, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter )
|
||||
{
|
||||
|
@ -523,3 +590,12 @@ tr_core_update( TrCore * self )
|
|||
tr_core_check_zombies( self );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_errsig( TrCore * self, enum tr_core_err type, const char * msg )
|
||||
{
|
||||
TrCoreClass * class;
|
||||
|
||||
class = g_type_class_peek( TR_CORE_TYPE );
|
||||
g_signal_emit( self, class->errsig, 0, type, msg );
|
||||
}
|
||||
|
|
|
@ -66,6 +66,17 @@ struct _TrCore
|
|||
struct _TrCoreClass
|
||||
{
|
||||
GObjectClass parent;
|
||||
/* "error" signal:
|
||||
void handler( TrCore *, enum tr_core_err, const char *, gpointer ) */
|
||||
int errsig;
|
||||
};
|
||||
|
||||
enum tr_core_err
|
||||
{
|
||||
TR_CORE_ERR_ADD_TORRENT, /* adding a torrent failed */
|
||||
/* no more torrents to be added, used for grouping torrent add errors */
|
||||
TR_CORE_ERR_NO_MORE_TORRENTS,
|
||||
TR_CORE_ERR_SAVE_STATE /* error saving state */
|
||||
};
|
||||
|
||||
GType
|
||||
|
@ -90,22 +101,24 @@ tr_core_shutdown( TrCore * self );
|
|||
gboolean
|
||||
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. */
|
||||
/* Save state. May trigger "error" signal with TR_CORE_ERR_SAVE_STATE */
|
||||
void
|
||||
tr_core_save( TrCore * self, char ** error );
|
||||
tr_core_save( TrCore * self );
|
||||
|
||||
/* Load saved state, return number of torrents added. If errors is not
|
||||
NULL then a char* is appended for each error which occurs, these
|
||||
must be freed. */
|
||||
/* 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, benc_val_t * state, GList ** errors );
|
||||
tr_core_load( TrCore * self, benc_val_t * state );
|
||||
|
||||
/* Add a torrent. Torrent, dir, flags, and err arguments are the same
|
||||
as tr_torrent_new() */
|
||||
/* Add a torrent. Torrent, dir and flags arguments are the same as
|
||||
tr_torrent_new(). May trigger "error" signal with TR_CORE_ERR_ADD_TORRENT */
|
||||
gboolean
|
||||
tr_core_add_torrent( TrCore * self, const char * torrent, const char * dir,
|
||||
guint flags, char ** err );
|
||||
guint flags );
|
||||
|
||||
/* Trigger "error" signal with TR_CORE_ERR_NO_MORE_TORRENTS */
|
||||
void
|
||||
tr_core_torrents_added( TrCore * self );
|
||||
|
||||
/* remove a torrent, waiting for it to pause if necessary */
|
||||
void
|
||||
|
|
|
@ -401,38 +401,42 @@ tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
|
|||
return tr_torrent_new( back, torrent, dir, flags, err );
|
||||
}
|
||||
|
||||
#define SETSTRVAL(vv, ss) \
|
||||
do { \
|
||||
(vv)->type = TYPE_STR; \
|
||||
(vv)->val.s.s = g_strdup((ss)); \
|
||||
(vv)->val.s.i = strlen((ss)); \
|
||||
} while(0)
|
||||
gboolean
|
||||
tr_torrent_get_state( TrTorrent * tor, benc_val_t * state )
|
||||
{
|
||||
tr_info_t * inf;
|
||||
|
||||
void
|
||||
tr_torrent_get_state(TrTorrent *tor, benc_val_t *state) {
|
||||
tr_info_t *in = tr_torrentInfo(tor->handle);
|
||||
TR_IS_TORRENT( tor );
|
||||
|
||||
TR_IS_TORRENT(tor);
|
||||
if( tor->severed )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(tor->severed)
|
||||
return;
|
||||
inf = tr_torrentInfo( tor->handle );
|
||||
|
||||
state->type = TYPE_DICT;
|
||||
state->val.l.vals = g_new0(benc_val_t, 6);
|
||||
state->val.l.alloc = state->val.l.count = 6;
|
||||
tr_bencInit( state, TYPE_DICT );
|
||||
if( tr_bencDictReserve( state, 3 ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(TR_FLAG_SAVE & in->flags) {
|
||||
SETSTRVAL(state->val.l.vals + 0, "hash");
|
||||
SETSTRVAL(state->val.l.vals + 1, in->hashString);
|
||||
} else {
|
||||
SETSTRVAL(state->val.l.vals + 0, "torrent");
|
||||
SETSTRVAL(state->val.l.vals + 1, in->torrent);
|
||||
}
|
||||
SETSTRVAL(state->val.l.vals + 2, "dir");
|
||||
SETSTRVAL(state->val.l.vals + 3, tr_torrentGetFolder(tor->handle));
|
||||
SETSTRVAL(state->val.l.vals + 4, "paused");
|
||||
state->val.l.vals[5].type = TYPE_INT;
|
||||
state->val.l.vals[5].val.i = tr_torrent_paused(tor);
|
||||
if( TR_FLAG_SAVE & inf->flags )
|
||||
{
|
||||
tr_bencInitStr( tr_bencDictAdd( state, "hash" ),
|
||||
inf->hashString, -1, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_bencInitStr( tr_bencDictAdd( state, "torrent" ),
|
||||
inf->torrent, -1, 1 );
|
||||
}
|
||||
tr_bencInitStr( tr_bencDictAdd( state, "dir" ),
|
||||
tr_torrentGetFolder( tor->handle ), -1, 1 );
|
||||
tr_bencInitInt( tr_bencDictAdd( state, "paused" ),
|
||||
( tr_torrent_paused( tor ) ? 1 : 0 ) );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* XXX this should probably be done with a signal */
|
||||
|
|
|
@ -96,8 +96,8 @@ TrTorrent *
|
|||
tr_torrent_new_with_state( tr_handle_t * handle, benc_val_t * state,
|
||||
guint flags, char ** err );
|
||||
|
||||
void
|
||||
tr_torrent_get_state(TrTorrent *tor, benc_val_t *state);
|
||||
gboolean
|
||||
tr_torrent_get_state( TrTorrent * tor, benc_val_t * state );
|
||||
|
||||
void
|
||||
tr_torrent_state_saved(TrTorrent *tor);
|
||||
|
|
Loading…
Reference in New Issue