Add signal mechanism for reporting error from TrCore.

Use error signal for errors when adding torrents and saving state.
This commit is contained in:
Josh Elsasser 2007-05-23 17:59:35 +00:00
parent 544c0c1dc4
commit cc1394b1d6
5 changed files with 209 additions and 95 deletions

View File

@ -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;

View File

@ -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 );
}

View File

@ -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

View File

@ -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 */

View File

@ -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);