Update 2006-01-03

This commit is contained in:
Eric Petit
2006-01-12 19:04:05 +00:00
parent f32ca66210
commit a850cd6910
4 changed files with 157 additions and 20 deletions

View File

@@ -449,9 +449,7 @@ cf_savestate(int count, tr_stat_t *torrents, char **errstr) {
err = NULL;
for(ii = 0; ii < count; ii++) {
/* XXX need a better way to query running/stopped state */
paused = (TR_STATUS_STOPPING == torrents[ii].status ||
TR_STATUS_STOPPED == torrents[ii].status ||
TR_STATUS_PAUSE == torrents[ii].status);
paused = ((TR_STATUS_STOPPING | TR_STATUS_PAUSE) & torrents[ii].status);
torrentfile = g_strescape(torrents[ii].info.torrent, "");
torrentdir = g_strescape(torrents[ii].folder, "");
/* g_strcompress */

View File

@@ -76,6 +76,8 @@ gboolean
winclose(GtkWidget *widget, GdkEvent *event, gpointer gdata);
gboolean
exitcheck(gpointer gdata);
void
stoptransmission(void *tr);
GtkWidget *
makewind_toolbar(struct cbdata *data);
GtkWidget *
@@ -104,6 +106,8 @@ void
killmenu(GtkWidget *menu, gpointer *gdata SHUTUP);
void
actionclick(GtkWidget *widget, gpointer gdata);
gint
intrevcmp(gconstpointer a, gconstpointer b);
void
doubleclick(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col,
gpointer gdata);
@@ -168,6 +172,8 @@ main(int argc, char **argv) {
tr = tr_init();
setuphandlers(stoptransmission, tr);
if(cf_init(tr_getPrefsDirectory(), &err)) {
if(cf_lock(&err)) {
/* create main window now so any error dialogs can be it's children */
@@ -201,12 +207,12 @@ main(int argc, char **argv) {
if(NULL != stateerr)
gtk_widget_show_all(stateerr);
} else {
gtk_widget_show(errmsg_full(NULL, (errfunc_t)gtk_main_quit,
gtk_widget_show(errmsg_full(NULL, (callbackfunc_t)gtk_main_quit,
NULL, "%s", err));
g_free(err);
}
} else {
gtk_widget_show(errmsg_full(NULL, (errfunc_t)gtk_main_quit,
gtk_widget_show(errmsg_full(NULL, (callbackfunc_t)gtk_main_quit,
NULL, "%s", err));
g_free(err);
}
@@ -308,6 +314,8 @@ winclose(GtkWidget *widget SHUTUP, GdkEvent *event SHUTUP, gpointer gdata) {
g_source_remove(data->timer);
data->timer = -1;
blocksigs();
for(ii = tr_torrentStat(data->tr, &st); 0 < ii; ii--) {
if(TR_TORRENT_NEEDS_STOP(st[ii-1].status)) {
/*fprintf(stderr, "quit: stopping %i %s\n", ii, st[ii-1].info.name);*/
@@ -319,6 +327,8 @@ winclose(GtkWidget *widget SHUTUP, GdkEvent *event SHUTUP, gpointer gdata) {
}
free(st);
unblocksigs();
/* XXX should disable widgets or something */
/* try to wait until torrents stop before exiting */
@@ -339,8 +349,10 @@ exitcheck(gpointer gdata) {
tr_stat_t *st;
int ii;
blocksigs();
for(ii = tr_torrentStat(data->cbdata->tr, &st); 0 < ii; ii--) {
if(TR_STATUS_PAUSE == st[ii-1].status) {
if(TR_STATUS_PAUSE & st[ii-1].status) {
/*fprintf(stderr, "quit: closing %i %s\n", ii, st[ii-1].info.name);*/
tr_torrentClose(data->cbdata->tr, ii - 1);
}
@@ -353,23 +365,23 @@ exitcheck(gpointer gdata) {
if(0 < tr_torrentCount(data->cbdata->tr) &&
time(NULL) - data->started < TRACKER_EXIT_TIMEOUT) {
updatemodel(data->cbdata);
unblocksigs();
return TRUE;
}
/*fprintf(stderr, "quit: giving up on %i torrents\n",
tr_torrentCount(data->cbdata->tr));*/
for(ii = tr_torrentCount(data->cbdata->tr); 0 < ii; ii--)
tr_torrentClose(data->cbdata->tr, ii - 1);
/* exit otherwise */
if(0 >= data->timer)
g_source_remove(data->timer);
data->timer = -1;
/*fprintf(stderr, "quit: giving up on %i torrents\n",
tr_torrentCount(data->cbdata->tr));*/
stoptransmission(data->cbdata->tr);
clearhandlers();
unblocksigs();
gtk_widget_destroy(GTK_WIDGET(data->cbdata->wind));
tr_close(data->cbdata->tr);
g_free(data->cbdata);
g_free(data);
gtk_main_quit();
@@ -377,6 +389,13 @@ exitcheck(gpointer gdata) {
return FALSE;
}
void
stoptransmission(void *tr) {
while(0 < tr_torrentCount(tr))
tr_torrentClose(tr, 0);
tr_close(tr);
}
GtkWidget *
makewind_toolbar(struct cbdata *data) {
GtkWidget *bar = gtk_toolbar_new();
@@ -589,6 +608,8 @@ updatemodel(gpointer gdata) {
float up, down;
char *upstr, *downstr, *str;
blocksigs();
max = tr_torrentStat(data->tr, &st);
for(ii = 0; ii < max; ii++) {
if(!(ii ? gtk_tree_model_iter_next(GTK_TREE_MODEL(data->model), &iter) :
@@ -626,6 +647,8 @@ updatemodel(gpointer gdata) {
/* the status of the selected item may have changed, so update the buttons */
fixbuttons(NULL, data);
unblocksigs();
return TRUE;
}
@@ -790,10 +813,11 @@ actionclick(GtkWidget *widget, gpointer gdata) {
break;
assert(actindex < ALEN(actionitems));
blocksigs();
updatesave = FALSE;
count = tr_torrentStat(data->tr, &sb);
for(ii = g_list_first(ids); NULL != ii; ii = ii->next) {
for(ii = g_list_sort(ids, intrevcmp); NULL != ii; ii = ii->next) {
index = GPOINTER_TO_INT(ii->data);
if(index >= count) {
assert(!"illegal torrent id");
@@ -819,6 +843,8 @@ actionclick(GtkWidget *widget, gpointer gdata) {
tr_torrentStop(data->tr, index);
tr_torrentClose(data->tr, index);
updatesave = TRUE;
/* XXX should only unselect deleted rows */
gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(data->view));
break;
case ACT_INFO:
makeinfowind(data->wind, data->tr, index);
@@ -835,10 +861,25 @@ actionclick(GtkWidget *widget, gpointer gdata) {
updatemodel(data);
}
unblocksigs();
if(FROM_BUTTON == from)
g_list_free(ids);
}
gint
intrevcmp(gconstpointer a, gconstpointer b) {
int aint = GPOINTER_TO_INT(a);
int bint = GPOINTER_TO_INT(b);
if(bint > aint)
return 1;
else if(bint < aint)
return -1;
else
return 0;
}
void
doubleclick(GtkWidget *widget SHUTUP, GtkTreePath *path,
GtkTreeViewColumn *col SHUTUP, gpointer gdata) {
@@ -866,7 +907,10 @@ addtorrent(tr_handle_t *tr, GtkWindow *parentwind, const char *torrent,
}
}
blocksigs();
if(0 != tr_torrentInit(tr, torrent)) {
unblocksigs();
/* XXX would be nice to have errno strings, are they printed to stdout? */
errmsg(parentwind, "Failed to open torrent file %s", torrent);
return FALSE;
@@ -886,6 +930,9 @@ addtorrent(tr_handle_t *tr, GtkWindow *parentwind, const char *torrent,
if(!paused)
tr_torrentStart(tr, tr_torrentCount(tr) - 1);
unblocksigs();
return TRUE;
}
@@ -908,7 +955,9 @@ savetorrents(tr_handle_t *tr, GtkWindow *wind, int count, tr_stat_t *stat) {
if(0 <= count)
ret = cf_savestate(count, stat, &errstr);
else {
blocksigs();
count = tr_torrentStat(tr, &st);
unblocksigs();
ret = cf_savestate(count, st, &errstr);
free(st);
}

View File

@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <string.h>
@@ -34,6 +35,8 @@
#include "util.h"
static void
sigexithandler(int sig);
static void
errcb(GtkWidget *wind, int resp, gpointer data);
@@ -98,6 +101,71 @@ mkdir_p(const char *name, mode_t mode) {
return TRUE;
}
static int exit_sigs[] = {SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2};
static callbackfunc_t exit_func = NULL;
static void *exit_data = NULL;
static int exit_block_level = 0;
void
setuphandlers(callbackfunc_t func, void *data) {
struct sigaction sa;
unsigned int ii;
exit_data = data;
exit_func = func;
bzero(&sa, sizeof(sa));
sa.sa_handler = sigexithandler;
for(ii = 0; ii < ALEN(exit_sigs); ii++)
sigaction(exit_sigs[ii], &sa, NULL);
}
void
clearhandlers(void) {
struct sigaction sa;
unsigned int ii;
bzero(&sa, sizeof(sa));
sa.sa_handler = SIG_DFL;
for(ii = 0; ii < ALEN(exit_sigs); ii++)
sigaction(exit_sigs[ii], &sa, NULL);
}
static void
sigexithandler(int sig) {
exit_func(exit_data);
clearhandlers();
raise(sig);
}
void
blocksigs(void) {
sigset_t mask;
unsigned int ii;
if(0 < (exit_block_level++))
return;
sigemptyset(&mask);
for(ii = 0; ii < ALEN(exit_sigs); ii++)
sigaddset(&mask, exit_sigs[ii]);
sigprocmask(SIG_BLOCK, &mask, NULL);
}
void
unblocksigs(void) {
sigset_t mask;
unsigned int ii;
if(0 < (--exit_block_level))
return;
sigemptyset(&mask);
for(ii = 0; ii < ALEN(exit_sigs); ii++)
sigaddset(&mask, exit_sigs[ii]);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
}
GtkWidget *
errmsg(GtkWindow *wind, const char *format, ...) {
GtkWidget *dialog;
@@ -111,7 +179,7 @@ errmsg(GtkWindow *wind, const char *format, ...) {
}
GtkWidget *
errmsg_full(GtkWindow *wind, errfunc_t func, void *data,
errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
const char *format, ...) {
GtkWidget *dialog;
va_list ap;
@@ -124,7 +192,7 @@ errmsg_full(GtkWindow *wind, errfunc_t func, void *data,
}
GtkWidget *
verrmsg(GtkWindow *wind, errfunc_t func, void *data,
verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
const char *format, va_list ap) {
GtkWidget *dialog;
char *msg;
@@ -155,7 +223,7 @@ verrmsg(GtkWindow *wind, errfunc_t func, void *data,
static void
errcb(GtkWidget *widget, int resp SHUTUP, gpointer data) {
GList *funcdata;
errfunc_t func;
callbackfunc_t func;
if(NULL != data) {
funcdata = g_list_first(data);

View File

@@ -40,16 +40,38 @@
/* return number of items in array */
#define ALEN(a) (sizeof(a) / sizeof((a)[0]))
/* used for a callback function with a data parameter */
typedef void (*callbackfunc_t)(void*);
/* try to interpret a string as a textual representation of a boolean */
gboolean
strbool(const char *str);
/* return a human-readable string for the size given in bytes with the
requested number of decimal places. the string must be g_free()d */
char *
readablesize(guint64 size, int decimals);
/* create a directory and any missing parent directories */
gboolean
mkdir_p(const char *name, mode_t mode);
typedef void (*errfunc_t)(void*);
/* set up a handler for various fatal signals */
void
setuphandlers(callbackfunc_t func, void *data);
/* clear the handlers for fatal signals */
void
clearhandlers(void);
/* blocks and unblocks delivery of fatal signals. calls to these
functions can be nested as long as unblocksigs() is called exactly
as many times as blocksigs(). only the first blocksigs() will
block signals and only the last unblocksigs() will unblock them. */
void
blocksigs(void);
void
unblocksigs(void);
/* if wind is NULL then you must call gtk_widget_show on the returned widget */
@@ -61,7 +83,7 @@ errmsg(GtkWindow *wind, const char *format, ...)
;
GtkWidget *
errmsg_full(GtkWindow *wind, errfunc_t func, void *data,
errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 4, 5)))
@@ -69,7 +91,7 @@ errmsg_full(GtkWindow *wind, errfunc_t func, void *data,
;
GtkWidget *
verrmsg(GtkWindow *wind, errfunc_t func, void *data,
verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
const char *format, va_list ap);
#endif /* TG_UTIL_H */