mirror of
https://github.com/transmission/transmission.git
synced 2026-02-15 07:26:49 +00:00
Update 2005-11-24
This commit is contained in:
2
AUTHORS
2
AUTHORS
@@ -8,7 +8,7 @@ Eric Petit <titer@m0k.org>
|
||||
+ OS X interface
|
||||
|
||||
Josh Elsasser <josh@elsasser.org>
|
||||
+ GTK interface
|
||||
+ GTK+ interface
|
||||
|
||||
Michael Demars <keul@m0k.org>
|
||||
+ OS X interface
|
||||
|
||||
3
Jamfile
3
Jamfile
@@ -6,7 +6,6 @@ ObjectHdrs transmissioncli.c : $(TOP)/libtransmission ;
|
||||
|
||||
if $(OS) = MACOSX
|
||||
{
|
||||
OSXLinks macosx/Frameworks/Growl.framework/Growl ;
|
||||
OSXInfoPlist macosx/Info.plist : macosx/Info.plist.in ;
|
||||
OSXBundle Transmission.app : libtransmission.a
|
||||
macosx/Controller.h
|
||||
@@ -16,7 +15,6 @@ if $(OS) = MACOSX
|
||||
macosx/English.lproj/MainMenu.nib/classes.nib
|
||||
macosx/English.lproj/MainMenu.nib/info.nib
|
||||
macosx/English.lproj/MainMenu.nib/keyedobjects.nib
|
||||
macosx/Frameworks/Growl.framework/Growl
|
||||
macosx/Images/Info.png
|
||||
macosx/Images/Open.png
|
||||
macosx/Images/PauseOff.png
|
||||
@@ -37,6 +35,7 @@ if $(OS) = MACOSX
|
||||
macosx/main.m
|
||||
macosx/TorrentTableView.h
|
||||
macosx/TorrentTableView.m
|
||||
macosx/Transmission.sdef
|
||||
macosx/Transmission.xcodeproj/project.pbxproj
|
||||
macosx/Transmission_Prefix.pch
|
||||
macosx/Utils.h ;
|
||||
|
||||
14
Jamrules
14
Jamrules
@@ -8,7 +8,7 @@ if ! $(DEFINES)
|
||||
VERSION_MAJOR = 0 ;
|
||||
VERSION_MINOR = 4 ;
|
||||
# VERSION_STRING = $(VERSION_MAJOR).$(VERSION_MINOR) ;
|
||||
VERSION_STRING = 0.5-cvs ;
|
||||
VERSION_STRING = CVS-20051124 ;
|
||||
|
||||
DEFINES += VERSION_MAJOR=$(VERSION_MAJOR)
|
||||
VERSION_MINOR=$(VERSION_MINOR)
|
||||
@@ -40,18 +40,6 @@ if $(OS) = MACOSX
|
||||
libtool -static $(>) -o $(<) ;
|
||||
}
|
||||
|
||||
rule OSXLinks
|
||||
{
|
||||
}
|
||||
actions OSXLinks
|
||||
{
|
||||
( cd macosx/Frameworks/Growl.framework/ && \
|
||||
ln -s Versions/Current/Growl && \
|
||||
ln -s Versions/Current/Headers && \
|
||||
ln -s Versions/Current/Resources && \
|
||||
ln -s A Versions/Current )
|
||||
}
|
||||
|
||||
rule OSXInfoPlist
|
||||
{
|
||||
Depends $(1) : $(2) ;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SubDir TOP gtk ;
|
||||
|
||||
GTK_SRC = conf.c main.c util.c ;
|
||||
GTK_SRC = conf.c main.c prefs.c util.c ;
|
||||
|
||||
Main transmission-gtk : $(GTK_SRC) ;
|
||||
LinkLibraries transmission-gtk : libtransmission.a ;
|
||||
|
||||
68
gtk/conf.c
68
gtk/conf.c
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "conf.h"
|
||||
#include "transmission.h"
|
||||
#include "util.h"
|
||||
|
||||
#define FILE_LOCK "gtk_lock"
|
||||
#define FILE_PREFS "gtk_prefs"
|
||||
@@ -159,7 +160,6 @@ cf_loadprefs(char **errstr) {
|
||||
path, err->message);
|
||||
goto done;
|
||||
}
|
||||
/*g_io_channel_set_encoding(io, NULL, NULL);*/
|
||||
g_io_channel_set_line_term(io, &term, 1);
|
||||
|
||||
err = NULL;
|
||||
@@ -209,7 +209,10 @@ cf_setpref(const char *name, const char *value, char **errstr) {
|
||||
|
||||
g_tree_insert(prefs, g_strdup(name), g_strdup(value));
|
||||
|
||||
return writeprefs(errstr);
|
||||
if(NULL != errstr)
|
||||
return writeprefs(errstr);
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct writeinfo {
|
||||
@@ -236,9 +239,14 @@ writeprefs(char **errstr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
ftruncate(fd, 0);
|
||||
#else
|
||||
assert(0 == ftruncate(fd, 0));
|
||||
#endif
|
||||
|
||||
info.err = NULL;
|
||||
io = g_io_channel_unix_new(fd);
|
||||
/*g_io_channel_set_encoding(io, NULL, NULL);*/
|
||||
g_io_channel_set_close_on_unref(io, TRUE);
|
||||
|
||||
info.io = io;
|
||||
@@ -318,7 +326,6 @@ cf_loadstate(char **errstr) {
|
||||
path, err->message);
|
||||
goto done;
|
||||
}
|
||||
/*g_io_channel_set_encoding(io, NULL, NULL);*/
|
||||
g_io_channel_set_line_term(io, &term, 1);
|
||||
|
||||
err = NULL;
|
||||
@@ -367,43 +374,46 @@ static char *
|
||||
getstateval(struct cf_torrentstate *state, char *line) {
|
||||
char *start, *end;
|
||||
|
||||
/* skip any leading whitespace */
|
||||
while(isspace(*line))
|
||||
line++;
|
||||
|
||||
if(NULL == (start = strchr(line, '=')))
|
||||
return NULL;
|
||||
|
||||
while(isspace(*(++start)))
|
||||
/* walk over the key, which may be alphanumerics as well as - or _ */
|
||||
for(start = line; isalnum(*start) || '_' == *start || '-' == *start; start++)
|
||||
;
|
||||
|
||||
if('"' != *start)
|
||||
/* they key must be immediately followed by an = */
|
||||
if('=' != *start)
|
||||
return NULL;
|
||||
*(start++) = '\0';
|
||||
|
||||
/* then the opening quote for the value */
|
||||
if('"' != *(start++))
|
||||
return NULL;
|
||||
|
||||
for(end = ++start; '\0' != *end && '"' != *end; end++)
|
||||
/* walk over the value */
|
||||
for(end = start; '\0' != *end && '"' != *end; end++)
|
||||
/* skip over escaped quotes */
|
||||
if('\\' == *end && '\0' != *(end + 1))
|
||||
end++;
|
||||
|
||||
/* make sure we didn't hit the end of the string */
|
||||
if('"' != *end)
|
||||
return NULL;
|
||||
*end = '\0';
|
||||
|
||||
if(0 == memcmp(line, "torrent", sizeof("torrent") - 1)) {
|
||||
state->ts_torrent = g_new(char, end - start + 1);
|
||||
memcpy(state->ts_torrent, start, end - start);
|
||||
state->ts_torrent[end - start] = '\0';
|
||||
}
|
||||
else if(0 == memcmp(line, "dir", sizeof("dir") - 1)) {
|
||||
state->ts_directory = g_new(char, end - start + 1);
|
||||
memcpy(state->ts_directory, start, end - start);
|
||||
state->ts_directory[end - start] = '\0';
|
||||
}
|
||||
else if(0 == memcmp(line, "paused", sizeof("paused") - 1)) {
|
||||
state->ts_paused = (0 == memcmp("yes", start, end - start));
|
||||
}
|
||||
/* if it's a key we recognize then save the data */
|
||||
if(0 == strcmp(line, "torrent"))
|
||||
state->ts_torrent = g_strcompress(start);
|
||||
else if(0 == strcmp(line, "dir"))
|
||||
state->ts_directory = g_strcompress(start);
|
||||
else if(0 == strcmp(line, "paused"))
|
||||
state->ts_paused = strbool(start);
|
||||
|
||||
/* return a pointer to just past the end of the value */
|
||||
return end + 1;
|
||||
}
|
||||
|
||||
/* XXX need to save download directory, also maybe running/stopped state */
|
||||
gboolean
|
||||
cf_savestate(int count, tr_stat_t *torrents, char **errstr) {
|
||||
char *file = g_build_filename(confdir, FILE_STATE, NULL);
|
||||
@@ -425,11 +435,17 @@ cf_savestate(int count, tr_stat_t *torrents, char **errstr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
ftruncate(fd, 0);
|
||||
#else
|
||||
assert(0 == ftruncate(fd, 0));
|
||||
#endif
|
||||
|
||||
io = g_io_channel_unix_new(fd);
|
||||
/* XXX what the hell should I be doing about unicode? */
|
||||
/*g_io_channel_set_encoding(io, NULL, NULL);*/
|
||||
g_io_channel_set_close_on_unref(io, TRUE);
|
||||
|
||||
/* XXX what the hell should I be doing about unicode? */
|
||||
|
||||
err = NULL;
|
||||
for(ii = 0; ii < count; ii++) {
|
||||
/* XXX need a better way to query running/stopped state */
|
||||
|
||||
@@ -43,6 +43,7 @@ gboolean
|
||||
cf_loadprefs(char **errstr);
|
||||
const char *
|
||||
cf_getpref(const char *name);
|
||||
/* if errstr is NULL then prefs will not be saved */
|
||||
gboolean
|
||||
cf_setpref(const char *name, const char *value, char **errstr);
|
||||
GList *
|
||||
|
||||
156
gtk/main.c
156
gtk/main.c
@@ -24,17 +24,19 @@
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "prefs.h"
|
||||
#include "transmission.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -42,7 +44,7 @@
|
||||
|
||||
struct cbdata {
|
||||
tr_handle_t *tr;
|
||||
GtkWidget *wind;
|
||||
GtkWindow *wind;
|
||||
GtkListStore *model;
|
||||
GtkTreeView *view;
|
||||
guint timer;
|
||||
@@ -58,8 +60,6 @@ struct pieces {
|
||||
char p[120];
|
||||
};
|
||||
|
||||
void
|
||||
readargs(int argc, char **argv, int *port, int *limit);
|
||||
void
|
||||
maketypes(void);
|
||||
gpointer
|
||||
@@ -92,7 +92,7 @@ actionclick(GtkWidget *widget, gpointer gdata);
|
||||
void
|
||||
makeaddwind(struct cbdata *data);
|
||||
gboolean
|
||||
addtorrent(tr_handle_t *tr, GtkWidget *parentwind, const char *torrent,
|
||||
addtorrent(tr_handle_t *tr, GtkWindow *parentwind, const char *torrent,
|
||||
const char *dir, gboolean paused);
|
||||
void
|
||||
fileclick(GtkWidget *widget, gpointer gdata);
|
||||
@@ -101,7 +101,7 @@ statusstr(int status);
|
||||
void
|
||||
makeinfowind(struct cbdata *data, int index);
|
||||
gboolean
|
||||
savetorrents(tr_handle_t *tr, GtkWidget *wind, int count, tr_stat_t *stat);
|
||||
savetorrents(tr_handle_t *tr, GtkWindow *wind, int count, tr_stat_t *stat);
|
||||
|
||||
#define TR_TYPE_PIECES_NAME "tr-type-pieces"
|
||||
#define TR_TYPE_PIECES ((const GType)tr_type_pieces)
|
||||
@@ -109,7 +109,7 @@ savetorrents(tr_handle_t *tr, GtkWidget *wind, int count, tr_stat_t *stat);
|
||||
GType tr_type_pieces;
|
||||
|
||||
#define LIST_ACTION "torrent-list-action"
|
||||
enum listact { ACT_OPEN, ACT_START, ACT_STOP, ACT_DELETE, ACT_INFO };
|
||||
enum listact { ACT_OPEN, ACT_START, ACT_STOP, ACT_DELETE, ACT_INFO, ACT_PREF };
|
||||
#define LIST_ACTION_FROM "torrent-list-action-from"
|
||||
enum listfrom { FROM_BUTTON, FROM_POPUP };
|
||||
|
||||
@@ -128,6 +128,8 @@ actionitems[] = {
|
||||
"Remove a torrent from the list", "XXX"},
|
||||
{4, "Properties", GTK_STOCK_PROPERTIES, ACT_INFO,
|
||||
"Get additional information for a torrent", "XXX"},
|
||||
{5, "Preferences", GTK_STOCK_PREFERENCES, ACT_PREF,
|
||||
"Open preferences dialog", "XXX"},
|
||||
};
|
||||
|
||||
#define CBDATA_PTR "callback-data-pointer"
|
||||
@@ -135,12 +137,12 @@ int
|
||||
main(int argc, char **argv) {
|
||||
GtkWidget *mainwind, *preferr, *stateerr;
|
||||
char *err;
|
||||
int port, limit;
|
||||
tr_handle_t *tr;
|
||||
GList *saved;
|
||||
const char *pref;
|
||||
long intval;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
readargs(argc, argv, &port, &limit);
|
||||
|
||||
tr = tr_init();
|
||||
|
||||
@@ -152,23 +154,22 @@ main(int argc, char **argv) {
|
||||
stateerr = NULL;
|
||||
|
||||
if(!cf_loadprefs(&err)) {
|
||||
preferr = errmsg(mainwind, "%s", err);
|
||||
preferr = errmsg(GTK_WINDOW(mainwind), "%s", err);
|
||||
g_free(err);
|
||||
}
|
||||
saved = cf_loadstate(&err);
|
||||
if(NULL != err) {
|
||||
stateerr = errmsg(mainwind, "%s", err);
|
||||
stateerr = errmsg(GTK_WINDOW(mainwind), "%s", err);
|
||||
g_free(err);
|
||||
}
|
||||
|
||||
/* XXX need to remove port and limit options and make them prefs */
|
||||
/* XXX need prefs gui */
|
||||
/* XXX need default save dir pref */
|
||||
/* set the upload limit */
|
||||
setlimit(tr);
|
||||
|
||||
if(0 != port)
|
||||
tr_setBindPort(tr, port);
|
||||
if(0 != limit)
|
||||
tr_setUploadLimit(tr, limit);
|
||||
/* set the listening port */
|
||||
if(NULL != (pref = cf_getpref(PREF_PORT)) &&
|
||||
0 < (intval = strtol(pref, NULL, 10)) && 0xffff >= intval)
|
||||
tr_setBindPort(tr, intval);
|
||||
|
||||
maketypes();
|
||||
makewind(mainwind, tr, saved);
|
||||
@@ -178,11 +179,13 @@ main(int argc, char **argv) {
|
||||
if(NULL != stateerr)
|
||||
gtk_widget_show_all(stateerr);
|
||||
} else {
|
||||
errmsg_full(NULL, (errfunc_t)gtk_main_quit, NULL, "%s", err);
|
||||
gtk_widget_show(errmsg_full(NULL, (errfunc_t)gtk_main_quit,
|
||||
NULL, "%s", err));
|
||||
g_free(err);
|
||||
}
|
||||
} else {
|
||||
errmsg_full(NULL, (errfunc_t)gtk_main_quit, NULL, "%s", err);
|
||||
gtk_widget_show(errmsg_full(NULL, (errfunc_t)gtk_main_quit,
|
||||
NULL, "%s", err));
|
||||
g_free(err);
|
||||
}
|
||||
|
||||
@@ -191,45 +194,6 @@ main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
readargs(int argc, char **argv, int *port, int *limit) {
|
||||
char *name;
|
||||
int opt, num;
|
||||
|
||||
*port = 0;
|
||||
*limit = 0;
|
||||
|
||||
if(NULL == (name = strrchr(argv[0], '/')) || '\0' == *(++name))
|
||||
name = argv[0];
|
||||
|
||||
for(num = 1; num < argc; num++)
|
||||
if(0 == strcmp(argv[num], "-help") || 0 == strcmp(argv[num], "--help"))
|
||||
goto usage;
|
||||
|
||||
while(0 <= (opt = getopt(argc, argv, "hp:u:"))) {
|
||||
switch(opt) {
|
||||
case 'p':
|
||||
num = atoi(optarg);
|
||||
if(0 < num && 0xffff > num)
|
||||
*port = num;
|
||||
break;
|
||||
case 'u':
|
||||
num = atoi(optarg);
|
||||
if(0 != num)
|
||||
*limit = num;
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
usage:
|
||||
printf("usage: %s [-h] [-p port] [-u limit]\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
maketypes(void) {
|
||||
tr_type_pieces = g_boxed_type_register_static(
|
||||
@@ -257,7 +221,7 @@ makewind(GtkWidget *wind, tr_handle_t *tr, GList *saved) {
|
||||
struct cf_torrentstate *ts;
|
||||
|
||||
data->tr = tr;
|
||||
data->wind = wind;
|
||||
data->wind = GTK_WINDOW(wind);
|
||||
data->timer = -1;
|
||||
/* filled in by makewind_list */
|
||||
data->model = NULL;
|
||||
@@ -277,7 +241,8 @@ makewind(GtkWidget *wind, tr_handle_t *tr, GList *saved) {
|
||||
|
||||
for(ii = g_list_first(saved); NULL != ii; ii = ii->next) {
|
||||
ts = ii->data;
|
||||
addtorrent(tr, wind, ts->ts_torrent, ts->ts_directory, ts->ts_paused);
|
||||
addtorrent(tr, GTK_WINDOW(wind),
|
||||
ts->ts_torrent, ts->ts_directory, ts->ts_paused);
|
||||
cf_freestate(ts);
|
||||
}
|
||||
g_list_free(saved);
|
||||
@@ -322,8 +287,6 @@ winclose(GtkWidget *widget SHUTUP, GdkEvent *event SHUTUP, gpointer gdata) {
|
||||
|
||||
fprintf(stderr, "quit: starting timeout at %i\n", edata->started);
|
||||
|
||||
//exitcheck(edata);
|
||||
|
||||
/* returning FALSE means to destroy the window */
|
||||
return TRUE;
|
||||
}
|
||||
@@ -363,7 +326,7 @@ exitcheck(gpointer gdata) {
|
||||
g_source_remove(data->timer);
|
||||
data->timer = -1;
|
||||
|
||||
gtk_widget_destroy(data->cbdata->wind);
|
||||
gtk_widget_destroy(GTK_WIDGET(data->cbdata->wind));
|
||||
tr_close(data->cbdata->tr);
|
||||
g_free(data->cbdata);
|
||||
g_free(data);
|
||||
@@ -381,7 +344,7 @@ makewind_toolbar(struct cbdata *data) {
|
||||
gtk_toolbar_set_tooltips(GTK_TOOLBAR(bar), TRUE);
|
||||
gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_BOTH);
|
||||
|
||||
for(ii = 0; ii < sizeof(actionitems) / sizeof(actionitems[0]); ii++) {
|
||||
for(ii = 0; ii < ALEN(actionitems); ii++) {
|
||||
item = gtk_tool_button_new_from_stock(actionitems[ii].id);
|
||||
gtk_tool_button_set_label(GTK_TOOL_BUTTON(item), actionitems[ii].name);
|
||||
gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(item), GTK_TOOLBAR(bar)->tooltips,
|
||||
@@ -419,7 +382,7 @@ makewind_list(struct cbdata *data) {
|
||||
GtkCellRenderer *rend;
|
||||
GtkCellRenderer *rendprog;
|
||||
|
||||
assert(MC_ROW_COUNT == sizeof(types) / sizeof(types[0]));
|
||||
assert(MC_ROW_COUNT == ALEN(types));
|
||||
|
||||
model = gtk_list_store_newv(MC_ROW_COUNT, types);
|
||||
view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
||||
@@ -432,30 +395,6 @@ makewind_list(struct cbdata *data) {
|
||||
rendprog = gtk_cell_renderer_progress_new();
|
||||
g_object_set(rendprog, "text", "", NULL);
|
||||
|
||||
/*
|
||||
col = gtk_tree_view_column_new_with_attributes(
|
||||
"Name", rend, "text", MC_NAME, NULL);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_SIZE);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
||||
|
||||
col = gtk_tree_view_column_new_with_attributes(
|
||||
"Status", rend, "text", MC_STAT, NULL);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_ERR);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_DPEERS);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_UPEERS);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
||||
|
||||
col = gtk_tree_view_column_new_with_attributes(
|
||||
"Progress", rendprog, "value", MC_PROG, NULL);
|
||||
gtk_tree_view_column_pack_start(col, rend, TRUE);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_ETA);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_DRATE);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_URATE);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_DOWN);
|
||||
gtk_tree_view_column_add_attribute(col, rend, "text", MC_UP);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
||||
*/
|
||||
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view),
|
||||
gtk_tree_view_column_new_with_attributes("Name", rend,
|
||||
"text", MC_NAME, NULL));
|
||||
@@ -489,9 +428,6 @@ makewind_list(struct cbdata *data) {
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view),
|
||||
gtk_tree_view_column_new_with_attributes("Leechers", rend,
|
||||
"text", MC_DPEERS, NULL));
|
||||
/*gtk_tree_view_append_column(GTK_TREE_VIEW(view),
|
||||
gtk_tree_view_column_new_with_attributes("", rend,
|
||||
"text", MC_PIECES, NULL));*/
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view),
|
||||
gtk_tree_view_column_new_with_attributes("Downloaded", rend,
|
||||
"text", MC_DOWN, NULL));
|
||||
@@ -532,7 +468,7 @@ updatemodel(gpointer gdata) {
|
||||
MC_ERR, st[ii].error, MC_PROG, prog, MC_DRATE, st[ii].rateDownload,
|
||||
MC_URATE, st[ii].rateUpload, MC_ETA, st[ii].eta, MC_PEERS, st[ii].peersTotal,
|
||||
MC_UPEERS, st[ii].peersUploading, MC_DPEERS, st[ii].peersDownloading,
|
||||
/*MC_PIECES, st[ii].pieces,*/ MC_DOWN, st[ii].downloaded, MC_UP, st[ii].uploaded, -1);
|
||||
MC_DOWN, st[ii].downloaded, MC_UP, st[ii].uploaded, -1);
|
||||
}
|
||||
free(st);
|
||||
|
||||
@@ -578,7 +514,7 @@ dopopupmenu(GtkWidget *widget SHUTUP, GdkEventButton *event,
|
||||
|
||||
/* XXX am I leaking references here? */
|
||||
/* XXX can I cache this in cbdata? */
|
||||
for(ii = 0; ii < sizeof(actionitems) / sizeof(actionitems[0]); ii++) {
|
||||
for(ii = 0; ii < ALEN(actionitems); ii++) {
|
||||
item = gtk_menu_item_new_with_label(actionitems[ii].name);
|
||||
g_object_set_data(G_OBJECT(item), LIST_ACTION,
|
||||
GINT_TO_POINTER(actionitems[ii].act));
|
||||
@@ -610,9 +546,15 @@ actionclick(GtkWidget *widget, gpointer gdata) {
|
||||
int index;
|
||||
tr_stat_t *sb;
|
||||
|
||||
if(ACT_OPEN == act) {
|
||||
makeaddwind(data);
|
||||
return;
|
||||
switch(act) {
|
||||
case ACT_OPEN:
|
||||
makeaddwind(data);
|
||||
return;
|
||||
case ACT_PREF:
|
||||
makeprefwindow(data->wind, data->tr);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
@@ -673,17 +615,26 @@ makeaddwind(struct cbdata *data) {
|
||||
G_CALLBACK(fileclick), wind);
|
||||
g_signal_connect_swapped(GTK_FILE_SELECTION(wind)->cancel_button, "clicked",
|
||||
G_CALLBACK(gtk_widget_destroy), wind);
|
||||
gtk_window_set_transient_for(GTK_WINDOW(wind), GTK_WINDOW(data->wind));
|
||||
gtk_window_set_transient_for(GTK_WINDOW(wind), data->wind);
|
||||
gtk_window_set_destroy_with_parent(GTK_WINDOW(wind), TRUE);
|
||||
gtk_window_set_modal(GTK_WINDOW(wind), TRUE);
|
||||
gtk_widget_show_all(wind);
|
||||
}
|
||||
|
||||
gboolean
|
||||
addtorrent(tr_handle_t *tr, GtkWidget *parentwind, const char *torrent,
|
||||
addtorrent(tr_handle_t *tr, GtkWindow *parentwind, const char *torrent,
|
||||
const char *dir, gboolean paused) {
|
||||
char *wd;
|
||||
|
||||
if(NULL == dir) {
|
||||
dir = cf_getpref(PREF_DIR);
|
||||
if(!mkdir_p(dir, 0777)) {
|
||||
errmsg(parentwind, "Failed to create download directory %s:\n%s",
|
||||
dir, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(0 != tr_torrentInit(tr, torrent)) {
|
||||
/* XXX would be nice to have errno strings, are they printed to stdout? */
|
||||
errmsg(parentwind, "Failed to open torrent file %s", torrent);
|
||||
@@ -693,7 +644,6 @@ addtorrent(tr_handle_t *tr, GtkWidget *parentwind, const char *torrent,
|
||||
if(NULL != dir)
|
||||
tr_torrentSetFolder(tr, tr_torrentCount(tr) - 1, dir);
|
||||
else {
|
||||
/* XXX need pref for download directory */
|
||||
wd = g_new(char, MAXPATHLEN + 1);
|
||||
if(NULL == getcwd(wd, MAXPATHLEN + 1))
|
||||
tr_torrentSetFolder(tr, tr_torrentCount(tr) - 1, ".");
|
||||
@@ -747,7 +697,7 @@ makeinfowind(struct cbdata *data, int index) {
|
||||
if(index >= tr_torrentStat(data->tr, &sb)) {
|
||||
assert(!"XXX i'm tired");
|
||||
}
|
||||
wind = gtk_dialog_new_with_buttons(sb[index].info.name, GTK_WINDOW(data->wind),
|
||||
wind = gtk_dialog_new_with_buttons(sb[index].info.name, data->wind,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
|
||||
|
||||
table = gtk_table_new(21, 2, FALSE);
|
||||
@@ -855,7 +805,7 @@ makeinfowind(struct cbdata *data, int index) {
|
||||
}
|
||||
|
||||
gboolean
|
||||
savetorrents(tr_handle_t *tr, GtkWidget *wind, int count, tr_stat_t *stat) {
|
||||
savetorrents(tr_handle_t *tr, GtkWindow *wind, int count, tr_stat_t *stat) {
|
||||
char *errstr;
|
||||
tr_stat_t *st;
|
||||
gboolean ret;
|
||||
|
||||
181
gtk/prefs.c
Normal file
181
gtk/prefs.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
Copyright (c) 2005 Joshua Elsasser. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "prefs.h"
|
||||
#include "transmission.h"
|
||||
#include "util.h"
|
||||
|
||||
struct prefdata {
|
||||
GtkSpinButton *port;
|
||||
GtkCheckButton *uselimit;
|
||||
GtkSpinButton *limit;
|
||||
GtkEntry *dir;
|
||||
GtkWindow *parent;
|
||||
tr_handle_t *tr;
|
||||
};
|
||||
|
||||
static void
|
||||
clicklimitbox(GtkWidget *widget, gpointer gdata);
|
||||
static void
|
||||
clickdialog(GtkWidget *widget, int resp, gpointer gdata);
|
||||
|
||||
void
|
||||
makeprefwindow(GtkWindow *parent, tr_handle_t *tr) {
|
||||
GtkWidget *wind = gtk_dialog_new_with_buttons("Preferences", parent,
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK,
|
||||
GTK_RESPONSE_OK, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
|
||||
GtkWidget *table = gtk_table_new(4, 2, FALSE);
|
||||
GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
|
||||
GtkWidget *limitbox = gtk_check_button_new_with_label("Limit upload speed");
|
||||
GtkWidget *limitnum = gtk_spin_button_new_with_range(0, G_MAXLONG, 1);
|
||||
GtkWidget *dirstr = gtk_entry_new();
|
||||
GtkWidget *label;
|
||||
const char *pref;
|
||||
struct prefdata *data = g_new0(struct prefdata, 1);
|
||||
|
||||
data->port = GTK_SPIN_BUTTON(portnum);
|
||||
data->uselimit = GTK_CHECK_BUTTON(limitbox);
|
||||
data->limit = GTK_SPIN_BUTTON(limitnum);
|
||||
data->dir = GTK_ENTRY(dirstr);
|
||||
data->parent = parent;
|
||||
data->tr = tr;
|
||||
|
||||
/* port label and entry */
|
||||
label = gtk_label_new("Listening port");
|
||||
if(NULL != (pref = cf_getpref(PREF_PORT)))
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum), strtol(pref,NULL,10));
|
||||
else
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum), TR_DEFAULT_PORT);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), portnum, 1, 2, 0, 1);
|
||||
|
||||
/* limit checkbox */
|
||||
pref = cf_getpref(PREF_USELIMIT);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(limitbox),
|
||||
(NULL == pref ? FALSE : strbool(pref)));
|
||||
gtk_widget_set_sensitive(limitnum,
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(limitbox)));
|
||||
g_signal_connect(G_OBJECT(limitbox), "clicked",
|
||||
G_CALLBACK(clicklimitbox), limitnum);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), limitbox, 0, 2, 1, 2);
|
||||
|
||||
/* limit label and entry */
|
||||
label = gtk_label_new("Maximum upload speed");
|
||||
if(NULL != (pref = cf_getpref(PREF_LIMIT)))
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(limitnum), strtol(pref,NULL,10));
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), limitnum, 1, 2, 2, 3);
|
||||
|
||||
/* directory label and entry */
|
||||
label = gtk_label_new("Download directory");
|
||||
if(NULL != (pref = cf_getpref(PREF_DIR)))
|
||||
gtk_entry_set_text(GTK_ENTRY(dirstr), pref);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), dirstr, 1, 2, 3, 4);
|
||||
|
||||
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
|
||||
g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(clickdialog), data);
|
||||
gtk_widget_show_all(wind);
|
||||
}
|
||||
|
||||
static void
|
||||
clicklimitbox(GtkWidget *widget, gpointer gdata) {
|
||||
GtkWidget *entry = gdata;
|
||||
|
||||
gtk_widget_set_sensitive(entry,
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
|
||||
}
|
||||
|
||||
static void
|
||||
clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
|
||||
struct prefdata *data = gdata;
|
||||
int intval;
|
||||
const char *strval;
|
||||
char *strnum;
|
||||
gboolean boolval;
|
||||
|
||||
if(GTK_RESPONSE_OK == resp) {
|
||||
/* check directory */
|
||||
strval = gtk_entry_get_text(data->dir);
|
||||
if(!mkdir_p(strval, 0777)) {
|
||||
errmsg(data->parent, "Failed to create directory %s:\n%s",
|
||||
strval, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/* save port pref */
|
||||
strnum = g_strdup_printf("%i",
|
||||
gtk_spin_button_get_value_as_int(data->port));
|
||||
cf_setpref(PREF_PORT, strnum, NULL);
|
||||
g_free(strnum);
|
||||
/* XXX should I change the port here? is it even possible? */
|
||||
|
||||
/* save uselimit pref */
|
||||
boolval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->uselimit));
|
||||
cf_setpref(PREF_USELIMIT, (boolval ? "yes" : "no"), NULL);
|
||||
|
||||
/* save limit pref */
|
||||
intval = gtk_spin_button_get_value_as_int(data->limit);
|
||||
strnum = g_strdup_printf("%i", intval);
|
||||
cf_setpref(PREF_LIMIT, strnum, NULL);
|
||||
g_free(strnum);
|
||||
|
||||
setlimit(data->tr);
|
||||
|
||||
/*
|
||||
note that prefs aren't written to disk unless we pass a pointer
|
||||
to an error string, so do this for the last call to cf_setpref()
|
||||
*/
|
||||
/* save dir pref */
|
||||
if(!cf_setpref(PREF_DIR, gtk_entry_get_text(data->dir), &strnum)) {
|
||||
errmsg(data->parent, "%s", strnum);
|
||||
g_free(strnum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy(widget);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
void
|
||||
setlimit(tr_handle_t *tr) {
|
||||
const char *pref;
|
||||
|
||||
if(NULL == (pref = cf_getpref(PREF_USELIMIT)) || !strbool(pref))
|
||||
tr_setUploadLimit(tr, -1);
|
||||
else if(NULL != (pref = cf_getpref(PREF_LIMIT)))
|
||||
tr_setUploadLimit(tr, strtol(pref, NULL, 10));
|
||||
else
|
||||
tr_setUploadLimit(tr, -1);
|
||||
}
|
||||
45
gtk/prefs.h
Normal file
45
gtk/prefs.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright (c) 2005 Joshua Elsasser. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TG_PREFS_H
|
||||
#define TG_PREFS_H
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
/* macros for names of prefs we use */
|
||||
#define PREF_PORT "listening-port"
|
||||
#define PREF_USELIMIT "use-upload-limit"
|
||||
#define PREF_LIMIT "upload-limit"
|
||||
#define PREF_DIR "download-directory"
|
||||
|
||||
void
|
||||
makeprefwindow(GtkWindow *parent, tr_handle_t *tr);
|
||||
|
||||
/* set the upload limit based on saved prefs */
|
||||
void
|
||||
setlimit(tr_handle_t *tr);
|
||||
|
||||
#endif /* TG_PREFS_H */
|
||||
45
gtk/util.c
45
gtk/util.c
@@ -24,13 +24,18 @@
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static void
|
||||
errcb(GtkWidget *widget, int resp, gpointer data);
|
||||
errcb(GtkWidget *wind, int resp, gpointer data);
|
||||
|
||||
gboolean
|
||||
strbool(const char *str) {
|
||||
@@ -50,8 +55,34 @@ strbool(const char *str) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
mkdir_p(const char *name, mode_t mode) {
|
||||
struct stat sb;
|
||||
char *parent;
|
||||
gboolean ret;
|
||||
int oerrno;
|
||||
|
||||
if(0 != stat(name, &sb)) {
|
||||
if(ENOENT != errno)
|
||||
return FALSE;
|
||||
parent = g_path_get_dirname(name);
|
||||
ret = mkdir_p(parent, mode);
|
||||
oerrno = errno;
|
||||
g_free(parent);
|
||||
errno = oerrno;
|
||||
return (ret ? (0 == mkdir(name, mode)) : FALSE);
|
||||
}
|
||||
|
||||
if(!S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
errmsg(GtkWidget *wind, const char *format, ...) {
|
||||
errmsg(GtkWindow *wind, const char *format, ...) {
|
||||
GtkWidget *dialog;
|
||||
va_list ap;
|
||||
|
||||
@@ -63,7 +94,7 @@ errmsg(GtkWidget *wind, const char *format, ...) {
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
errmsg_full(GtkWidget *wind, errfunc_t func, void *data,
|
||||
errmsg_full(GtkWindow *wind, errfunc_t func, void *data,
|
||||
const char *format, ...) {
|
||||
GtkWidget *dialog;
|
||||
va_list ap;
|
||||
@@ -76,7 +107,7 @@ errmsg_full(GtkWidget *wind, errfunc_t func, void *data,
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
verrmsg(GtkWidget *wind, errfunc_t func, void *data,
|
||||
verrmsg(GtkWindow *wind, errfunc_t func, void *data,
|
||||
const char *format, va_list ap) {
|
||||
GtkWidget *dialog;
|
||||
char *msg;
|
||||
@@ -88,8 +119,8 @@ verrmsg(GtkWidget *wind, errfunc_t func, void *data,
|
||||
dialog = gtk_message_dialog_new(
|
||||
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
|
||||
else
|
||||
dialog = gtk_message_dialog_new(
|
||||
GTK_WINDOW(wind), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
dialog = gtk_message_dialog_new(wind,
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
|
||||
|
||||
if(NULL == func)
|
||||
@@ -98,7 +129,7 @@ verrmsg(GtkWidget *wind, errfunc_t func, void *data,
|
||||
funcdata = g_list_append(g_list_append(NULL, func), data);
|
||||
g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
|
||||
if(NULL != wind)
|
||||
gtk_widget_show_all(dialog);
|
||||
gtk_widget_show(dialog);
|
||||
g_free(msg);
|
||||
|
||||
return dialog;
|
||||
|
||||
13
gtk/util.h
13
gtk/util.h
@@ -27,6 +27,7 @@
|
||||
#ifndef TG_UTIL_H
|
||||
#define TG_UTIL_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* macro to shut up "unused parameter" warnings */
|
||||
@@ -36,22 +37,28 @@
|
||||
#define SHUTUP
|
||||
#endif
|
||||
|
||||
/* return number of items in array */
|
||||
#define ALEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
gboolean
|
||||
strbool(const char *str);
|
||||
|
||||
gboolean
|
||||
mkdir_p(const char *name, mode_t mode);
|
||||
|
||||
typedef void (*errfunc_t)(void*);
|
||||
|
||||
/* if wind is NULL then you must call gtk_widget_show on the returned widget */
|
||||
|
||||
GtkWidget *
|
||||
errmsg(GtkWidget *wind, const char *format, ...)
|
||||
errmsg(GtkWindow *wind, const char *format, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__ ((format (printf, 2, 3)))
|
||||
#endif
|
||||
;
|
||||
|
||||
GtkWidget *
|
||||
errmsg_full(GtkWidget *wind, errfunc_t func, void *data,
|
||||
errmsg_full(GtkWindow *wind, errfunc_t func, void *data,
|
||||
const char *format, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__ ((format (printf, 4, 5)))
|
||||
@@ -59,7 +66,7 @@ errmsg_full(GtkWidget *wind, errfunc_t func, void *data,
|
||||
;
|
||||
|
||||
GtkWidget *
|
||||
verrmsg(GtkWidget *wind, errfunc_t func, void *data,
|
||||
verrmsg(GtkWindow *wind, errfunc_t func, void *data,
|
||||
const char *format, va_list ap);
|
||||
|
||||
#endif /* TG_UTIL_H */
|
||||
|
||||
@@ -65,7 +65,7 @@ tr_handle_t * tr_init()
|
||||
h->upload = tr_uploadInit();
|
||||
h->fdlimit = tr_fdInit();
|
||||
|
||||
h->bindPort = 9090;
|
||||
h->bindPort = TR_DEFAULT_PORT;
|
||||
|
||||
snprintf( h->prefsDirectory, sizeof( h->prefsDirectory ),
|
||||
"%s/.transmission", getenv( "HOME" ) );
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#define MAX_PATH_LENGTH 1024
|
||||
#define TR_MAX_TORRENT_COUNT 50
|
||||
|
||||
#define TR_DEFAULT_PORT 9090
|
||||
|
||||
/***********************************************************************
|
||||
* tr_init
|
||||
***********************************************************************
|
||||
|
||||
@@ -101,13 +101,13 @@ int tr_uploadCanUpload( tr_upload_t * u )
|
||||
size = 0;
|
||||
now = tr_date();
|
||||
|
||||
/* Check the last four times we sent something and decide if
|
||||
/* Check the last FOO times we sent something and decide if
|
||||
we must wait */
|
||||
for( i = 0; i < FOO; i++ )
|
||||
{
|
||||
size += u->sizes[i];
|
||||
if( (uint64_t) size < 1024ULL *
|
||||
u->limit * ( now - u->dates[i] ) / 1000 )
|
||||
if( (uint64_t) size * 1000 <
|
||||
( now - u->dates[i] ) * u->limit * 1024 )
|
||||
{
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
@@ -42,7 +42,7 @@ static inline uint64_t tr_date()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday( &tv, NULL );
|
||||
return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 );
|
||||
return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
BIN
macosx/Applescript/Torrents_folder_action.scpt
Normal file
BIN
macosx/Applescript/Torrents_folder_action.scpt
Normal file
Binary file not shown.
@@ -26,11 +26,10 @@
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <transmission.h>
|
||||
#include "PrefsController.h"
|
||||
#include <Growl/Growl.h>
|
||||
|
||||
@class TorrentTableView;
|
||||
|
||||
@interface Controller : NSObject <GrowlApplicationBridgeDelegate>
|
||||
@interface Controller : NSObject
|
||||
{
|
||||
tr_handle_t * fHandle;
|
||||
int fCount;
|
||||
@@ -98,8 +97,10 @@
|
||||
- (void) showMainWindow: (id) sender;
|
||||
- (void) linkHomepage: (id) sender;
|
||||
- (void) linkForums: (id) sender;
|
||||
- (void) notifyGrowl: (NSString *) file folder: (NSString *) folder;
|
||||
- (void) revealInFinder: (NSString *) path;
|
||||
- (void) notifyGrowl: (NSString *) file;
|
||||
- (void) finderReveal: (NSString *) path;
|
||||
- (void) finderTrash: (NSString *) path;
|
||||
- (void) growlRegister: (id) sender;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ static void sleepCallBack( void * controller, io_service_t y,
|
||||
}
|
||||
|
||||
/* Register with the growl system */
|
||||
[GrowlApplicationBridge setGrowlDelegate:self];
|
||||
[self growlRegister: self];
|
||||
|
||||
/* Update the interface every 500 ms */
|
||||
fCount = 0;
|
||||
@@ -467,74 +467,16 @@ static void sleepCallBack( void * controller, io_service_t y,
|
||||
deleteTorrent: (BOOL) deleteTorrent
|
||||
deleteData: (BOOL) deleteData
|
||||
{
|
||||
BOOL torrentWarning = ![[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:@"SkipTorrentDeletionWarning"];
|
||||
BOOL dataWarning = ![[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:@"SkipDataDeletionWarning"];
|
||||
|
||||
if ( ( torrentWarning && deleteTorrent ) || (dataWarning && deleteData ) )
|
||||
if( deleteData )
|
||||
{
|
||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||
|
||||
[alert addButtonWithTitle:@"Delete"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setMessageText:@"Do you want to remove this torrent from Transmission?"];
|
||||
|
||||
if ( (deleteTorrent && torrentWarning) &&
|
||||
!( dataWarning && deleteData ) )
|
||||
{
|
||||
/* delete torrent warning YES, delete data warning NO */
|
||||
[alert setInformativeText:@"This will delete the .torrent file only. "
|
||||
"This can not be undone!"];
|
||||
}
|
||||
else if( (deleteData && dataWarning) &&
|
||||
!( torrentWarning && deleteTorrent ) )
|
||||
{
|
||||
/* delete torrent warning NO, delete data warning YES */
|
||||
[alert setInformativeText:@"This will delete the downloaded data. "
|
||||
"This can not be undone!"];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* delete torrent warning YES, delete data warning YES */
|
||||
[alert setInformativeText:@"This will delete the downloaded data and "
|
||||
".torrent file. This can not be undone!"];
|
||||
}
|
||||
|
||||
if ( [alert runModal] == NSAlertSecondButtonReturn )
|
||||
return;
|
||||
[self finderTrash: [NSString stringWithFormat: @"%@/%@",
|
||||
[NSString stringWithUTF8String: fStat[idx].folder],
|
||||
[NSString stringWithUTF8String: fStat[idx].info.name]]];
|
||||
}
|
||||
|
||||
if ( deleteData )
|
||||
if( deleteTorrent )
|
||||
{
|
||||
tr_file_t * files = fStat[idx].info.files;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < fStat[idx].info.fileCount; i++ )
|
||||
{
|
||||
if ( -1 == remove([[NSString stringWithFormat:@"%s/%s",
|
||||
fStat[idx].folder,
|
||||
files[i].name]
|
||||
cString]) )
|
||||
{
|
||||
NSLog(@"remove(%s) failed, errno = %i",
|
||||
files[i].name,
|
||||
errno);
|
||||
}
|
||||
}
|
||||
|
||||
/* in some cases, we should remove fStat[idx].folder also. When? */
|
||||
}
|
||||
|
||||
if ( deleteTorrent )
|
||||
{
|
||||
if ( -1 == remove( fStat[idx].info.torrent ) )
|
||||
{
|
||||
NSLog(@"remove(%s) failed, errno = %i",
|
||||
fStat[idx].info.torrent,
|
||||
errno);
|
||||
}
|
||||
[self finderTrash: [NSString stringWithUTF8String:
|
||||
fStat[idx].info.torrent]];
|
||||
}
|
||||
|
||||
tr_torrentClose( fHandle, idx );
|
||||
@@ -611,8 +553,7 @@ static void sleepCallBack( void * controller, io_service_t y,
|
||||
continue;
|
||||
}
|
||||
[self notifyGrowl: [NSString stringWithUTF8String:
|
||||
fStat[i].info.name] folder: [NSString stringWithUTF8String:
|
||||
fStat[i].folder]];
|
||||
fStat[i].info.name]];
|
||||
tr_setFinished( fHandle, i, 0 );
|
||||
}
|
||||
|
||||
@@ -909,67 +850,108 @@ static void sleepCallBack( void * controller, io_service_t y,
|
||||
URLWithString:@"http://transmission.m0k.org/forum/"]];
|
||||
}
|
||||
|
||||
- (void) notifyGrowl: (NSString * ) file folder: (NSString *) folder
|
||||
- (void) notifyGrowl: (NSString * ) file
|
||||
{
|
||||
[GrowlApplicationBridge
|
||||
notifyWithTitle: @"Download complete."
|
||||
description: [NSString stringWithFormat: @"Seeding: %@", file]
|
||||
notificationName: @"Download complete."
|
||||
iconData: nil
|
||||
priority: 0
|
||||
isSticky: FALSE
|
||||
clickContext: [NSString stringWithFormat: @"%@/%@", folder, file]];
|
||||
}
|
||||
|
||||
- (NSDictionary *)registrationDictionaryForGrowl
|
||||
{
|
||||
NSString *title = [NSString stringWithUTF8String: "Download complete."];
|
||||
NSMutableArray *defNotesArray = [NSMutableArray array];
|
||||
NSMutableArray *allNotesArray = [NSMutableArray array];
|
||||
|
||||
[allNotesArray addObject:title];
|
||||
[defNotesArray addObject:[NSNumber numberWithUnsignedInt:0]];
|
||||
|
||||
NSDictionary *regDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"Transmission", GROWL_APP_NAME,
|
||||
allNotesArray, GROWL_NOTIFICATIONS_ALL,
|
||||
defNotesArray, GROWL_NOTIFICATIONS_DEFAULT,
|
||||
nil];
|
||||
|
||||
return regDict;
|
||||
}
|
||||
|
||||
- (NSString *) applicationNameForGrowl
|
||||
{
|
||||
return [NSString stringWithUTF8String: "Transmission"];
|
||||
}
|
||||
|
||||
- (void) growlNotificationWasClicked: (id) clickContext
|
||||
{
|
||||
[self revealInFinder: (NSString *) clickContext];
|
||||
}
|
||||
|
||||
- (void) revealFromMenu: (id) sender
|
||||
{
|
||||
[fTableView revealInFinder: [fTableView selectedRow]];
|
||||
}
|
||||
|
||||
- (void) revealInFinder: (NSString *) path
|
||||
{
|
||||
NSString * string;
|
||||
NSString * growlScript;
|
||||
NSAppleScript * appleScript;
|
||||
NSDictionary * error;
|
||||
|
||||
string = [NSString stringWithFormat: @"tell application "
|
||||
"\"Finder\"\nactivate\nreveal (POSIX file \"%@\")\nend tell",
|
||||
path];
|
||||
appleScript = [[NSAppleScript alloc] initWithSource: string];
|
||||
growlScript = [NSString stringWithFormat:
|
||||
@"tell application \"System Events\"\n"
|
||||
" if exists application process \"GrowlHelperApp\" then\n"
|
||||
" tell application \"GrowlHelperApp\"\n "
|
||||
" notify with name \"Download Complete\""
|
||||
" title \"Download Complete\""
|
||||
" description \"%@\""
|
||||
" application name \"Transmission\"\n"
|
||||
" end tell\n"
|
||||
" end if\n"
|
||||
"end tell", file];
|
||||
appleScript = [[NSAppleScript alloc] initWithSource: growlScript];
|
||||
if( ![appleScript executeAndReturnError: &error] )
|
||||
{
|
||||
printf( "Reveal in Finder: AppleScript failed\n" );
|
||||
printf( "Growl notify failed\n" );
|
||||
}
|
||||
[appleScript release];
|
||||
}
|
||||
|
||||
- (void) growlRegister: (id) sender
|
||||
{
|
||||
NSString * growlScript;
|
||||
NSAppleScript * appleScript;
|
||||
NSDictionary * error;
|
||||
|
||||
growlScript = [NSString stringWithFormat:
|
||||
@"tell application \"System Events\"\n"
|
||||
" if exists application process \"GrowlHelperApp\" then\n"
|
||||
" tell application \"GrowlHelperApp\"\n"
|
||||
" register as application \"Transmission\" "
|
||||
" all notifications {\"Download Complete\"}"
|
||||
" default notifications {\"Download Complete\"}"
|
||||
" icon of application \"Transmission\"\n"
|
||||
" end tell\n"
|
||||
" end if\n"
|
||||
"end tell"];
|
||||
appleScript = [[NSAppleScript alloc] initWithSource: growlScript];
|
||||
if( ![appleScript executeAndReturnError: &error] )
|
||||
{
|
||||
printf( "Growl registration failed\n" );
|
||||
}
|
||||
[appleScript release];
|
||||
}
|
||||
|
||||
|
||||
- (void) revealFromMenu: (id) sender
|
||||
{
|
||||
int row;
|
||||
|
||||
row = [fTableView selectedRow];
|
||||
if( row < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
[self finderReveal: [NSString stringWithFormat: @"%@/%@",
|
||||
[NSString stringWithUTF8String: fStat[row].folder],
|
||||
[NSString stringWithUTF8String: fStat[row].info.name]]];
|
||||
}
|
||||
|
||||
- (void) finderReveal: (NSString *) path
|
||||
{
|
||||
NSString * string;
|
||||
NSAppleScript * appleScript;
|
||||
NSDictionary * error;
|
||||
|
||||
string = [NSString stringWithFormat:
|
||||
@"tell application \"Finder\"\n"
|
||||
" activate\n"
|
||||
" reveal (POSIX file \"%@\")\n"
|
||||
"end tell", path];
|
||||
|
||||
appleScript = [[NSAppleScript alloc] initWithSource: string];
|
||||
if( ![appleScript executeAndReturnError: &error] )
|
||||
{
|
||||
printf( "finderReveal failed\n" );
|
||||
}
|
||||
[appleScript release];
|
||||
}
|
||||
|
||||
- (void) finderTrash: (NSString *) path
|
||||
{
|
||||
NSString * string;
|
||||
NSAppleScript * appleScript;
|
||||
NSDictionary * error;
|
||||
|
||||
string = [NSString stringWithFormat:
|
||||
@"tell application \"Finder\"\n"
|
||||
" move (POSIX file \"%@\") to trash\n"
|
||||
"end tell", path];
|
||||
|
||||
appleScript = [[NSAppleScript alloc] initWithSource: string];
|
||||
if( ![appleScript executeAndReturnError: &error] )
|
||||
{
|
||||
printf( "finderTrash failed\n" );
|
||||
}
|
||||
[appleScript release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,24 +44,24 @@
|
||||
{
|
||||
NSUserDefaults * defaults;
|
||||
NSDictionary * appDefaults;
|
||||
NSString * desktop, * port;
|
||||
|
||||
fHandle = handle;
|
||||
|
||||
/* Register defaults settings:
|
||||
- Simple bar
|
||||
- Always download to Desktop
|
||||
- Port 9090
|
||||
- Port TR_DEFAULT_PORT
|
||||
- 20 KB/s upload limit */
|
||||
NSString * desktopPath
|
||||
= [NSString stringWithFormat: @"%@/Desktop",
|
||||
NSHomeDirectory()];
|
||||
desktop = [NSHomeDirectory() stringByAppendingString: @"/Desktop"];
|
||||
port = [NSString stringWithFormat: @"%d", TR_DEFAULT_PORT];
|
||||
|
||||
defaults = [NSUserDefaults standardUserDefaults];
|
||||
appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"NO", @"UseAdvancedBar",
|
||||
@"Constant", @"DownloadChoice",
|
||||
desktopPath, @"DownloadFolder",
|
||||
@"9090", @"BindPort",
|
||||
desktop, @"DownloadFolder",
|
||||
port, @"BindPort",
|
||||
@"20", @"UploadLimit",
|
||||
NULL];
|
||||
[defaults registerDefaults: appDefaults];
|
||||
|
||||
@@ -30,12 +30,11 @@
|
||||
{
|
||||
tr_stat_t * fStat;
|
||||
|
||||
NSString * fProgressString;
|
||||
NSString * fDlString;
|
||||
NSString * fUlString;
|
||||
|
||||
NSBitmapImageRep * fBgBmp;
|
||||
NSBitmapImageRep * fBmp;
|
||||
NSBitmapImageRep * fBackgroundBmp;
|
||||
NSBitmapImageRep * fProgressBmp;
|
||||
}
|
||||
- (id) init;
|
||||
- (void) setStat: (tr_stat_t *) stat;
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
|
||||
#include "ProgressCell.h"
|
||||
|
||||
@implementation ProgressCell
|
||||
|
||||
/***********************************************************************
|
||||
* Static tables
|
||||
***********************************************************************
|
||||
* We use these tables to optimize the drawing. They contain packed
|
||||
* RGBA pixels for every color we might need.
|
||||
**********************************************************************/
|
||||
#if 0
|
||||
/* Coefficients for the "3D effect" */
|
||||
static float kBarCoeffs[] =
|
||||
@@ -71,49 +79,63 @@ static uint32_t kGreen[] =
|
||||
0x00C900FF, 0x00C600FF, 0x00D100FF, 0x00DB00FF, 0x00E800FF,
|
||||
0x00ED00FF, 0x00F200FF, 0x00F400FF, 0x00B500FF };
|
||||
|
||||
@implementation ProgressCell
|
||||
|
||||
/***********************************************************************
|
||||
* init
|
||||
***********************************************************************
|
||||
* Prepares the NSBitmapImageReps we are going to need in order to
|
||||
* draw.
|
||||
**********************************************************************/
|
||||
- (id) init
|
||||
{
|
||||
NSImage * bgImg;
|
||||
NSSize size;
|
||||
|
||||
self = [super init];
|
||||
|
||||
/* Have a NSBitmapImageRep ready to draw the progression bar */
|
||||
bgImg = [NSImage imageNamed: @"Progress.png"];
|
||||
fBgBmp = [[bgImg representations] objectAtIndex: 0];
|
||||
size = [bgImg size];
|
||||
fBmp = [[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes: NULL pixelsWide: size.width
|
||||
pixelsHigh: size.height bitsPerSample: 8 samplesPerPixel: 4
|
||||
hasAlpha: YES isPlanar: NO
|
||||
/* Load the background image for the progress bar and get it as a
|
||||
32-bit bitmap */
|
||||
fBackgroundBmp = [[[NSImage imageNamed: @"Progress.png"]
|
||||
representations] objectAtIndex: 0];
|
||||
|
||||
/* Allocate another bitmap of the same size. We will draw the
|
||||
progress bar in it */
|
||||
fProgressBmp = [[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes: NULL pixelsWide:
|
||||
[fBackgroundBmp size].width pixelsHigh:
|
||||
[fBackgroundBmp size].height bitsPerSample: 8
|
||||
samplesPerPixel: 4 hasAlpha: YES isPlanar: NO
|
||||
colorSpaceName: NSCalibratedRGBColorSpace
|
||||
bytesPerRow: 0 bitsPerPixel: 0];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* setStat
|
||||
***********************************************************************
|
||||
* Readies ourselves to draw updated info.
|
||||
**********************************************************************/
|
||||
- (void) setStat: (tr_stat_t *) stat
|
||||
{
|
||||
int i;
|
||||
uint8_t * in, * out;
|
||||
|
||||
fStat = stat;
|
||||
|
||||
fProgressString = [NSString stringWithFormat:
|
||||
@"%.2f %%", 100.0 * fStat->progress];
|
||||
/* Update the strings to be displayed */
|
||||
fDlString = [NSString stringWithFormat:
|
||||
@"DL: %.2f KB/s", fStat->rateDownload];
|
||||
fUlString = [NSString stringWithFormat:
|
||||
@"UL: %.2f KB/s", fStat->rateUpload];
|
||||
|
||||
for( i = 0; i < [fBmp size].height; i++ )
|
||||
/* Reset our bitmap to the background image... */
|
||||
in = [fBackgroundBmp bitmapData];
|
||||
out = [fProgressBmp bitmapData];
|
||||
for( i = 0; i < [fProgressBmp size].height; i++ )
|
||||
{
|
||||
memcpy( [fBmp bitmapData] + i * [fBmp bytesPerRow],
|
||||
[fBgBmp bitmapData] + i * [fBgBmp bytesPerRow],
|
||||
[fBmp size].width * 4 );
|
||||
memcpy( out, in, [fProgressBmp size].width * 4 );
|
||||
in += [fBackgroundBmp bytesPerRow];
|
||||
out += [fProgressBmp bytesPerRow];
|
||||
}
|
||||
|
||||
/* ...and redraw the progress bar on the top of it */
|
||||
if( [[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:@"UseAdvancedBar"])
|
||||
{
|
||||
@@ -125,128 +147,146 @@ static uint32_t kGreen[] =
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* buildSimpleBar
|
||||
**********************************************************************/
|
||||
- (void) buildSimpleBar
|
||||
{
|
||||
int h, w;
|
||||
int h, w, end, pixelsPerRow;
|
||||
uint32_t * p;
|
||||
uint32_t * colors;
|
||||
|
||||
pixelsPerRow = [fProgressBmp bytesPerRow] / 4;
|
||||
|
||||
/* The background image is 124*18 pixels, but the actual
|
||||
progress bar is 120*14 : the first two columns, the last
|
||||
two columns and the last four lines contain the shadow. */
|
||||
|
||||
p = (uint32_t *) [fProgressBmp bitmapData];
|
||||
p += 2;
|
||||
end = lrintf( floor( fStat->progress * 120 ) );
|
||||
colors = ( fStat->status & TR_STATUS_SEED ) ? kGreen : kBlue2;
|
||||
|
||||
for( h = 0; h < 14; h++ )
|
||||
{
|
||||
p = (uint32_t *) ( [fBmp bitmapData] +
|
||||
h * [fBmp bytesPerRow] ) + 2;
|
||||
|
||||
for( w = 0; w < 120; w++ )
|
||||
for( w = 0; w < end; w++ )
|
||||
{
|
||||
if( w >= (int) ( fStat->progress * 120 ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( fStat->status & TR_STATUS_SEED )
|
||||
{
|
||||
*p = kGreen[h];
|
||||
}
|
||||
else
|
||||
{
|
||||
*p = kBlue2[h];
|
||||
}
|
||||
p++;
|
||||
p[w] = colors[h];
|
||||
}
|
||||
p += pixelsPerRow;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* buildAdvancedBar
|
||||
**********************************************************************/
|
||||
- (void) buildAdvancedBar
|
||||
{
|
||||
int h, w;
|
||||
int h, w, end, pixelsPerRow;
|
||||
uint32_t * p;
|
||||
uint32_t * colors;
|
||||
|
||||
for( h = 0; h < 14; h++ )
|
||||
if( fStat->status & TR_STATUS_SEED )
|
||||
{
|
||||
p = (uint32_t *) ( [fBmp bitmapData] +
|
||||
h * [fBmp bytesPerRow] ) + 2;
|
||||
/* All green, same as the simple bar */
|
||||
[self buildSimpleBar];
|
||||
return;
|
||||
}
|
||||
|
||||
for( w = 0; w < 120; w++ )
|
||||
pixelsPerRow = [fProgressBmp bytesPerRow] / 4;
|
||||
|
||||
/* First two lines: dark blue to show progression */
|
||||
p = (uint32_t *) [fProgressBmp bitmapData];
|
||||
p += 2;
|
||||
end = lrintf( floor( fStat->progress * 120 ) );
|
||||
for( h = 0; h < 2; h++ )
|
||||
{
|
||||
for( w = 0; w < end; w++ )
|
||||
{
|
||||
if( fStat->status & TR_STATUS_SEED )
|
||||
{
|
||||
*p = kGreen[h];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Download is not finished yet */
|
||||
if( h < 2 )
|
||||
{
|
||||
/* First two lines: dark blue to show progression */
|
||||
if( w >= (int) ( fStat->progress * 120 ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
*p = kBlue4[h];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lines 2 to X: blue or grey depending on whether
|
||||
we have the piece or not */
|
||||
if( fStat->pieces[w] < 0 )
|
||||
{
|
||||
*p = kGray[h];
|
||||
}
|
||||
else if( fStat->pieces[w] < 1 )
|
||||
{
|
||||
*p = kRed[h];
|
||||
}
|
||||
else if( fStat->pieces[w] < 2 )
|
||||
{
|
||||
*p = kBlue1[h];
|
||||
}
|
||||
else if( fStat->pieces[w] < 3 )
|
||||
{
|
||||
*p = kBlue2[h];
|
||||
}
|
||||
else
|
||||
{
|
||||
*p = kBlue3[h];
|
||||
}
|
||||
}
|
||||
}
|
||||
p[w] = kBlue4[h];
|
||||
}
|
||||
p += pixelsPerRow;
|
||||
}
|
||||
|
||||
p++;
|
||||
/* Lines 2 to 14: blue or grey depending on whether
|
||||
we have the piece or not */
|
||||
for( w = 0; w < 120; w++ )
|
||||
{
|
||||
/* Point to pixel ( 2 + w, 2 ). We will then draw
|
||||
"vertically" */
|
||||
p = (uint32_t *) ( [fProgressBmp bitmapData] +
|
||||
2 * [fProgressBmp bytesPerRow] );
|
||||
p += 2 + w;
|
||||
|
||||
if( fStat->pieces[w] < 0 )
|
||||
{
|
||||
colors = kGray;
|
||||
}
|
||||
else if( fStat->pieces[w] < 1 )
|
||||
{
|
||||
colors = kRed;
|
||||
}
|
||||
else if( fStat->pieces[w] < 2 )
|
||||
{
|
||||
colors = kBlue1;
|
||||
}
|
||||
else if( fStat->pieces[w] < 3 )
|
||||
{
|
||||
colors = kBlue2;
|
||||
}
|
||||
else
|
||||
{
|
||||
colors = kBlue3;
|
||||
}
|
||||
|
||||
for( h = 2; h < 14; h++ )
|
||||
{
|
||||
p[0] = colors[h];
|
||||
p += pixelsPerRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* drawWithFrame
|
||||
***********************************************************************
|
||||
* We have the strings, we have the bitmap. Let's just draw them where
|
||||
* they belong.
|
||||
**********************************************************************/
|
||||
- (void) drawWithFrame: (NSRect) cellFrame inView: (NSView *) view
|
||||
{
|
||||
NSImage * img;
|
||||
NSMutableDictionary * attributes;
|
||||
NSPoint pen;
|
||||
|
||||
if( ![view lockFocusIfCanDraw] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary * attributes;
|
||||
NSPoint pen = cellFrame.origin;
|
||||
pen = cellFrame.origin;
|
||||
|
||||
attributes = [NSMutableDictionary dictionaryWithCapacity: 1];
|
||||
[attributes setObject: [NSFont messageFontOfSize:12.0]
|
||||
forKey: NSFontAttributeName];
|
||||
|
||||
pen.x += 5; pen.y += 5;
|
||||
|
||||
img = [[NSImage alloc] initWithSize: [fBmp size]];
|
||||
[img addRepresentation: fBmp];
|
||||
/* Init an NSImage with our bitmap in order to draw it. We need to
|
||||
do this every time, or for some reason it won't draw if the
|
||||
display is set to thousands of colors when Transmission was
|
||||
started */
|
||||
img = [[NSImage alloc] initWithSize: [fProgressBmp size]];
|
||||
[img addRepresentation: fProgressBmp];
|
||||
[img setFlipped: YES];
|
||||
[img drawAtPoint: pen fromRect:
|
||||
NSMakeRect( 0, 0, [fBmp size].width, [fBmp size].height )
|
||||
|
||||
/* Actually draw the bar */
|
||||
pen.x += 5; pen.y += 5;
|
||||
[img drawAtPoint: pen fromRect: NSMakeRect( 0, 0,
|
||||
[fProgressBmp size].width, [fProgressBmp size].height )
|
||||
operation: NSCompositeSourceOver fraction: 1.0];
|
||||
|
||||
[img release];
|
||||
|
||||
[attributes setObject: [NSFont messageFontOfSize:10.0]
|
||||
forKey: NSFontAttributeName];
|
||||
|
||||
/* Draw the strings with font 10 */
|
||||
attributes = [NSDictionary dictionaryWithObject:
|
||||
[NSFont messageFontOfSize: 10.0] forKey: NSFontAttributeName];
|
||||
pen.x += 5; pen.y += 20;
|
||||
[fDlString drawAtPoint: pen withAttributes: attributes];
|
||||
|
||||
pen.x += 0; pen.y += 15;
|
||||
[fUlString drawAtPoint: pen withAttributes: attributes];
|
||||
|
||||
|
||||
@@ -9,24 +9,6 @@
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
- (void) revealInFinder: (int) row
|
||||
{
|
||||
NSString * string;
|
||||
NSAppleScript * appleScript;
|
||||
NSDictionary * error;
|
||||
|
||||
string = [NSString stringWithFormat: @"tell application "
|
||||
"\"Finder\"\nactivate\nreveal (POSIX file \"%@/%@\")\nend tell",
|
||||
[NSString stringWithUTF8String: fStat[row].folder],
|
||||
[NSString stringWithUTF8String: fStat[row].info.name]];
|
||||
appleScript = [[NSAppleScript alloc] initWithSource: string];
|
||||
if( ![appleScript executeAndReturnError: &error] )
|
||||
{
|
||||
printf( "Reveal in Finder: AppleScript failed\n" );
|
||||
}
|
||||
[appleScript release];
|
||||
}
|
||||
|
||||
- (void) pauseOrResume: (int) row
|
||||
{
|
||||
if( fStat[row].status & TR_STATUS_PAUSE )
|
||||
@@ -106,7 +88,7 @@
|
||||
}
|
||||
else if( [self pointInRevealRect: point] )
|
||||
{
|
||||
[fController revealInFinder: [NSString stringWithFormat:
|
||||
[fController finderReveal: [NSString stringWithFormat:
|
||||
@"%@/%@", [NSString stringWithUTF8String: fStat[row].folder],
|
||||
[NSString stringWithUTF8String: fStat[row].info.name]]];
|
||||
[self display];
|
||||
|
||||
BIN
macosx/Torrents_folder_action.scpt
Normal file
BIN
macosx/Torrents_folder_action.scpt
Normal file
Binary file not shown.
@@ -18,8 +18,6 @@
|
||||
4D6DAAC7090CE00500F43C22 /* RevealOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D6DAAC5090CE00500F43C22 /* RevealOn.png */; };
|
||||
4D752E930913C949008EAAD4 /* Preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D752E920913C949008EAAD4 /* Preferences.png */; };
|
||||
4D813EB508AA43AC00191DB4 /* Progress.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D813EB408AA43AC00191DB4 /* Progress.png */; };
|
||||
4D81E2E4092EF0CB00F24127 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D81E2E3092EF0CB00F24127 /* Growl.framework */; };
|
||||
4D81E309092EF26F00F24127 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4D81E2E3092EF0CB00F24127 /* Growl.framework */; };
|
||||
4DA6FDBA0911233800450CB1 /* PauseOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDB80911233800450CB1 /* PauseOn.png */; };
|
||||
4DA6FDBB0911233800450CB1 /* PauseOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDB90911233800450CB1 /* PauseOff.png */; };
|
||||
4DA6FDC5091141AD00450CB1 /* ResumeOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */; };
|
||||
@@ -62,19 +60,6 @@
|
||||
};
|
||||
/* End PBXBuildStyle section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
4D81E301092EF24500F24127 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
4D81E309092EF26F00F24127 /* Growl.framework in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
@@ -99,7 +84,6 @@
|
||||
4D6DAAC5090CE00500F43C22 /* RevealOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = RevealOn.png; path = Images/RevealOn.png; sourceTree = "<group>"; };
|
||||
4D752E920913C949008EAAD4 /* Preferences.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Preferences.png; path = Images/Preferences.png; sourceTree = "<group>"; };
|
||||
4D813EB408AA43AC00191DB4 /* Progress.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Progress.png; path = Images/Progress.png; sourceTree = "<group>"; };
|
||||
4D81E2E3092EF0CB00F24127 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = Frameworks/Growl.framework; sourceTree = "<group>"; };
|
||||
4DA6FDB80911233800450CB1 /* PauseOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseOn.png; path = Images/PauseOn.png; sourceTree = "<group>"; };
|
||||
4DA6FDB90911233800450CB1 /* PauseOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseOff.png; path = Images/PauseOff.png; sourceTree = "<group>"; };
|
||||
4DA6FDC3091141AD00450CB1 /* ResumeOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOff.png; path = Images/ResumeOff.png; sourceTree = "<group>"; };
|
||||
@@ -122,7 +106,6 @@
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||
4DF0C5AE08991C1600DD8943 /* libtransmission.a in Frameworks */,
|
||||
4D3EA0AA08AE13C600EA10C2 /* IOKit.framework in Frameworks */,
|
||||
4D81E2E4092EF0CB00F24127 /* Growl.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -150,7 +133,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||
4D81E2E3092EF0CB00F24127 /* Growl.framework */,
|
||||
);
|
||||
name = "Linked Frameworks";
|
||||
sourceTree = "<group>";
|
||||
@@ -238,7 +220,6 @@
|
||||
8D1107290486CEB800E47090 /* Resources */,
|
||||
8D11072C0486CEB800E47090 /* Sources */,
|
||||
8D11072E0486CEB800E47090 /* Frameworks */,
|
||||
4D81E301092EF24500F24127 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
||||
@@ -39,14 +39,14 @@
|
||||
" -i, --info Print metainfo and exit\n" \
|
||||
" -s, --scrape Print counts of seeders/leechers and exit\n" \
|
||||
" -v, --verbose <int> Verbose level (0 to 2, default = 0)\n" \
|
||||
" -p, --port <int> Port we should listen on (default = 9090)\n" \
|
||||
" -p, --port <int> Port we should listen on (default = %d)\n" \
|
||||
" -u, --upload <int> Maximum upload rate (-1 = no limit, default = 20)\n"
|
||||
|
||||
static int showHelp = 0;
|
||||
static int showInfo = 0;
|
||||
static int showScrape = 0;
|
||||
static int verboseLevel = 0;
|
||||
static int bindPort = 9090;
|
||||
static int bindPort = TR_DEFAULT_PORT;
|
||||
static int uploadLimit = 20;
|
||||
static char * torrentPath = NULL;
|
||||
static volatile char mustDie = 0;
|
||||
@@ -66,13 +66,13 @@ int main( int argc, char ** argv )
|
||||
/* Get options */
|
||||
if( parseCommandLine( argc, argv ) )
|
||||
{
|
||||
printf( USAGE, argv[0] );
|
||||
printf( USAGE, argv[0], TR_DEFAULT_PORT );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( showHelp )
|
||||
{
|
||||
printf( USAGE, argv[0] );
|
||||
printf( USAGE, argv[0], TR_DEFAULT_PORT );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user