patches from Charles Kerr to update the Inspector in GTK and fix some memory leaks

This commit is contained in:
Mitchell Livingston
2007-06-06 00:30:13 +00:00
parent e18549429a
commit 4ada334f57
23 changed files with 2188 additions and 693 deletions
+2
View File
@@ -214,6 +214,7 @@ cf_readfile(const char *file, const char *oldfile, gsize *len,
}
done:
g_free (path);
if(NULL != err)
g_error_free(err);
if(NULL != io)
@@ -280,6 +281,7 @@ cf_loadprefs(char **errstr) {
cf_saveprefs(errstr);
}
tr_bencFree(&val);
g_free(data);
}
-557
View File
@@ -111,36 +111,12 @@ static void
dirclick(GtkWidget *widget, gpointer gdata);
static void
addresp(GtkWidget *widget, gint resp, gpointer gdata);
static GtkWidget *
makeinfotab( TrTorrent * tor, struct infowind * iw );
static void
infoupdate( struct infowind * iw, int force );
static void
fmtpeercount( GtkLabel * label, int count );
static void
promptdirnocore( gpointer gdata, GObject * core );
static void
promptresp( GtkWidget * widget, gint resp, gpointer data );
static void
quitresp( GtkWidget * widget, gint resp, gpointer data );
static GtkWidget *
makefilestab( TrTorrent * tor, GtkTreeModel ** modelret );
static void
stylekludge( GObject * obj, GParamSpec * spec, gpointer data );
static void
infowinddead( GtkWidget * widget, gpointer data );
static void
infotorclosed( gpointer data, GObject * tor );
static void
parsepath( GtkTreeStore * store, GtkTreeIter * ret,
const char * path, int index, uint64_t size );
static uint64_t
getdirtotals( GtkTreeStore * store, GtkTreeIter * parent );
static gboolean
infowindupdate( gpointer data );
static float
updateprogress( GtkTreeModel * model, GtkTreeIter * parent,
uint64_t total, float * progress );
void
makeaddwind( GtkWindow * parent, TrCore * core )
@@ -278,258 +254,6 @@ addresp(GtkWidget *widget, gint resp, gpointer gdata) {
gtk_widget_destroy(widget);
}
void
makeinfowind( GtkWindow * parent, GtkTreeModel * model, GtkTreePath * path,
TrTorrent * tor )
{
struct infowind * iw;
GtkWidget * wind, * box, * label, * sep, * tabs, * page;
tr_info_t * inf;
char * name, * size;
iw = g_new0( struct infowind, 1 );
inf = tr_torrent_info( tor );
name = g_strdup_printf( _("%s - Properties for %s"),
g_get_application_name(), inf->name );
wind = gtk_dialog_new_with_buttons( name, parent,
GTK_DIALOG_DESTROY_WITH_PARENT |
GTK_DIALOG_NO_SEPARATOR,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
NULL );
g_free( name );
gtk_dialog_set_default_response( GTK_DIALOG( wind ), GTK_RESPONSE_ACCEPT );
gtk_window_set_resizable( GTK_WINDOW( wind ), TRUE );
gtk_window_set_role( GTK_WINDOW( wind ), "tr-info" );
gtk_widget_set_name( wind, "TransmissionDialog" );
box = GTK_DIALOG( wind )->vbox;
/* add label with file name and size */
label = gtk_label_new( NULL );
size = readablesize( inf->totalSize );
name = g_markup_printf_escaped( "<big>%s (%s)</big>", inf->name, size );
free( size );
gtk_label_set_markup( GTK_LABEL( label ), name );
g_free( name );
gtk_label_set_selectable( GTK_LABEL( label ), TRUE );
gtk_widget_show( label );
gtk_box_pack_start( GTK_BOX( box ), label, FALSE, FALSE, 6 );
/* add separator */
sep = gtk_hseparator_new();
gtk_widget_show( sep );
gtk_box_pack_start( GTK_BOX( box ), sep, FALSE, FALSE, 6 );
/* add tab bar */
tabs = gtk_notebook_new();
gtk_widget_show( tabs );
gtk_box_pack_start( GTK_BOX( box ), tabs, TRUE, TRUE, 6 );
/* add general tab */
label = gtk_label_new( _("General") );
gtk_widget_show( label );
page = makeinfotab( tor, iw );
gtk_notebook_append_page( GTK_NOTEBOOK( tabs ), page, label );
/* add files tab */
label = gtk_label_new( _("Files") );
gtk_widget_show( label );
/* XXX should use sizingmagic() here */
page = makefilestab( tor, &iw->filesmodel );
gtk_notebook_append_page( GTK_NOTEBOOK( tabs ), page, label );
/* set up the callback data */
iw->widget = wind;
iw->tor = tor;
iw->size = inf->totalSize;
iw->model = model;
iw->row = gtk_tree_row_reference_new( model, path );
iw->timer = g_timeout_add( UPDATE_INTERVAL, infowindupdate, iw );
g_object_ref( model );
g_object_weak_ref( G_OBJECT( tor ), infotorclosed, iw );
g_signal_connect( wind, "destroy", G_CALLBACK( infowinddead ), iw );
g_signal_connect( wind, "response", G_CALLBACK( gtk_widget_destroy ), 0 );
infoupdate( iw, 1 );
infowindupdate( iw );
gtk_widget_show( wind );
}
#define INFOLINE( tab, ii, nam, val ) \
do \
{ \
char * txt = g_markup_printf_escaped( "<b>%s</b>", (nam) ); \
GtkWidget * wid = gtk_label_new( NULL ); \
gtk_misc_set_alignment( GTK_MISC( wid ), 0, .5 ); \
gtk_label_set_markup( GTK_LABEL( wid ), txt ); \
gtk_table_attach( GTK_TABLE( (tab) ), wid, 0, 1, (ii), (ii) + 1, \
GTK_FILL, GTK_FILL, 0, 0 ); \
gtk_label_set_selectable( GTK_LABEL( (val) ), TRUE ); \
gtk_misc_set_alignment( GTK_MISC( (val) ), 0, .5 ); \
gtk_table_attach( GTK_TABLE( (tab) ), (val), 1, 2, (ii), (ii) + 1, \
GTK_FILL, GTK_FILL, 0, 0); \
(ii)++; \
g_free( txt ); \
} while( 0 )
#define INFOLINEF( tab, ii, fmt, nam, val ) \
do \
{ \
char * buf = g_strdup_printf( fmt, val ); \
GtkWidget * lwid = gtk_label_new( buf ); \
g_free( buf ); \
INFOLINE( tab, ii, nam, lwid ); \
} while( 0 )
#define INFOLINEW( tab, ii, nam, val ) \
do \
{ \
GtkWidget * lwid = gtk_label_new( (val) ); \
INFOLINE( (tab), (ii), (nam), lwid ); \
} while( 0 )
#define INFOLINEA( tab, ii, nam, val ) \
do \
{ \
GtkWidget * lwid = gtk_label_new( (val) ); \
g_free( val ); \
INFOLINE( (tab), (ii), (nam), lwid ); \
} while( 0 )
#define INFOLINEU( tab, ii, nam, stor ) \
do \
{ \
GtkWidget * lwid = gtk_label_new( NULL ); \
(stor) = GTK_LABEL( lwid ); \
INFOLINE( (tab), (ii), (nam), lwid); \
} while( 0 )
#define INFOSEP( tab, ii ) \
do \
{ \
GtkWidget * wid = gtk_hseparator_new(); \
gtk_table_attach( GTK_TABLE( (tab) ), wid, 0, 2, (ii), (ii) + 1, \
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0 ); \
(ii)++; \
} while( 0 )
GtkWidget *
makeinfotab( TrTorrent * tor, struct infowind * iw )
{
const int rowcount = 17;
tr_info_t * inf;
int ii;
GtkWidget * table;
inf = tr_torrent_info( tor );
table = gtk_table_new( rowcount, 2, FALSE );
gtk_table_set_col_spacings( GTK_TABLE( table ), 12 );
gtk_table_set_row_spacings( GTK_TABLE( table ), 12 );
gtk_container_set_border_width( GTK_CONTAINER( table ), 6 );
ii = 0;
INFOLINEU( table, ii, _("Tracker:"), iw->inf.trackwid );
INFOLINEU( table, ii, _("Announce:"), iw->inf.annwid );
INFOLINEU( table, ii, _("Scrape:"), iw->inf.scrwid );
INFOSEP( table, ii );
INFOLINEW( table, ii, _("Info Hash:"), inf->hashString );
INFOLINEA( table, ii, _("Piece Size:"), readablesize( inf->pieceSize ) );
INFOLINEF( table, ii, "%i", _("Pieces:"), inf->pieceCount );
INFOLINEA( table, ii, _("Total Size:"), readablesize( inf->totalSize ) );
INFOSEP( table, ii );
INFOLINEU( table, ii, _("Seeders:"), iw->inf.seedwid );
INFOLINEU( table, ii, _("Leechers:"), iw->inf.leechwid );
INFOLINEU( table, ii, _("Completed:"), iw->inf.donewid );
INFOSEP( table, ii );
INFOLINEW( table, ii, _("Directory:"),
tr_torrentGetFolder( tr_torrent_handle( tor ) ) );
INFOLINEU( table, ii, _("Downloaded:"), iw->inf.downwid );
INFOLINEU( table, ii, _("Uploaded:"), iw->inf.upwid );
INFOLINEU( table, ii, _("Remaining:"), iw->inf.leftwid );
g_assert( rowcount == ii );
gtk_widget_show_all( table );
return table;
}
void
infoupdate( struct infowind * iw, int force )
{
int seed, leech, done;
uint64_t up, down, left;
tr_tracker_info_t * track;
GtkTreePath * path;
GtkTreeIter iter;
char * str;
path = gtk_tree_row_reference_get_path( iw->row );
if( NULL == path || !gtk_tree_model_get_iter( iw->model, &iter, path ) )
{
g_free( path );
return;
}
g_free( path );
gtk_tree_model_get( iw->model, &iter, MC_TRACKER, &track,
MC_SEED, &seed, MC_LEECH, &leech, MC_DONE, &done,
MC_DOWN, &down, MC_UP, &up, MC_LEFT, &left, -1 );
if( track != iw->inf.track || force )
{
if( 80 == track->port )
{
str = g_strdup_printf( "http://%s", track->address );
}
else
{
str = g_strdup_printf( "http://%s:%i",
track->address, track->port );
}
gtk_label_set_text( iw->inf.trackwid, str );
g_free( str );
gtk_label_set_text( iw->inf.annwid, track->announce );
gtk_label_set_text( iw->inf.scrwid, track->scrape );
}
if( seed != iw->inf.seed || force )
{
fmtpeercount( iw->inf.seedwid, seed );
iw->inf.seed = seed;
}
if( leech != iw->inf.leech || force )
{
fmtpeercount( iw->inf.leechwid, leech );
iw->inf.leech = leech;
}
if( done != iw->inf.done || force )
{
fmtpeercount( iw->inf.donewid, done );
iw->inf.done = done;
}
if( down != iw->inf.down || force )
{
str = readablesize( down );
gtk_label_set_text( iw->inf.downwid, str );
g_free( str );
iw->inf.down = down;
}
if( up != iw->inf.up || force )
{
str = readablesize( up );
gtk_label_set_text( iw->inf.upwid, str );
g_free( str );
iw->inf.up = up;
}
if( left != iw->inf.left || force )
{
str = readablesize( left );
gtk_label_set_text( iw->inf.leftwid, str );
g_free( str );
iw->inf.left = left;
}
}
void
fmtpeercount( GtkLabel * label, int count )
{
@@ -681,284 +405,3 @@ quitresp( GtkWidget * widget, gint resp, gpointer data )
g_free( stuff );
gtk_widget_destroy( widget );
}
enum filescols
{
FC_STOCK = 0, FC_LABEL, FC_PROG, FC_KEY, FC_INDEX, FC_SIZE, FC__MAX
};
GtkWidget *
makefilestab( TrTorrent * tor, GtkTreeModel ** modelret )
{
GType cols[] =
{
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_FLOAT,
G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT64
};
tr_info_t * inf;
GtkTreeStore * store;
int ii;
GtkWidget * view, * scroll, * frame;
GtkCellRenderer * rend;
GtkTreeViewColumn * col;
GtkTreeSelection * sel;
char * label;
g_assert( ALEN( cols ) == FC__MAX );
/* set up the model */
inf = tr_torrent_info( tor );
store = gtk_tree_store_newv( FC__MAX, cols );
*modelret = GTK_TREE_MODEL( store );
for( ii = 0; ii < inf->fileCount; ii++ )
{
parsepath( store, NULL, STRIPROOT( inf->files[ii].name ),
ii, inf->files[ii].length );
}
getdirtotals( store, NULL );
gtk_tree_sortable_set_sort_column_id( GTK_TREE_SORTABLE( store ),
FC_KEY, GTK_SORT_ASCENDING );
/* create the view */
view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) );
/* add file column */
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_expand( col, TRUE );
gtk_tree_view_column_set_sizing( col, GTK_TREE_VIEW_COLUMN_AUTOSIZE );
gtk_tree_view_column_set_title( col, _("File") );
/* add icon renderer */
rend = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_column_pack_start( col, rend, FALSE );
gtk_tree_view_column_add_attribute( col, rend, "stock-id", FC_STOCK );
/* add text renderer */
rend = gtk_cell_renderer_text_new();
g_object_set( rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
gtk_tree_view_column_pack_start( col, rend, TRUE );
gtk_tree_view_column_add_attribute( col, rend, "markup", FC_LABEL );
gtk_tree_view_append_column( GTK_TREE_VIEW( view ), col );
/* add progress column */
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title( col, _("Progress") );
rend = tr_cell_renderer_progress_new();
/* this string is only used to determine the size of the progress bar */
label = g_markup_printf_escaped( "<small>%s</small>", _(" fnord fnord ") );
g_object_set( rend, "show-text", FALSE, "bar-sizing", label, NULL );
g_free( label );
gtk_tree_view_column_pack_start( col, rend, FALSE );
gtk_tree_view_column_add_attribute( col, rend, "progress", FC_PROG );
gtk_tree_view_append_column( GTK_TREE_VIEW( view ), col );
/* XXX this shouldn't be necessary */
g_signal_connect( view, "notify::style", G_CALLBACK( stylekludge ), rend );
/* set up view */
sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
gtk_tree_selection_set_mode( sel, GTK_SELECTION_NONE );
gtk_tree_view_expand_all( GTK_TREE_VIEW( view ) );
gtk_tree_view_set_search_column( GTK_TREE_VIEW( view ), FC_LABEL );
gtk_widget_show( view );
/* create the scrolled window and stick the view in it */
scroll = gtk_scrolled_window_new( NULL, NULL );
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scroll ),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
gtk_container_add( GTK_CONTAINER( scroll ), view );
gtk_widget_show( scroll );
/* create a frame around the scroll to make it look a little better */
frame = gtk_frame_new( NULL );
gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );
gtk_container_add( GTK_CONTAINER( frame ), scroll );
gtk_widget_show( frame );
return frame;
}
/* kludge to have the progress bars notice theme changes */
static void
stylekludge( GObject * obj, GParamSpec * spec, gpointer data )
{
TrCellRendererProgress * rend = TR_CELL_RENDERER_PROGRESS( data );
if( 0 == strcmp( "style", spec->name ) )
{
tr_cell_renderer_progress_reset_style( rend );
gtk_widget_queue_draw( GTK_WIDGET( obj ) );
}
}
static void
infowinddead( GtkWidget * widget SHUTUP, gpointer data )
{
struct infowind * iw = data;
if( NULL != iw->widget )
{
g_object_weak_unref( G_OBJECT( iw->tor ), infotorclosed, iw );
infotorclosed( iw, G_OBJECT( iw->tor ) );
}
}
static void
infotorclosed( gpointer data, GObject * tor SHUTUP )
{
struct infowind * iw = data;
GtkWidget * widget;
/* neuter the widget's destroy callback */
widget = iw->widget;
iw->widget = NULL;
g_source_remove( iw->timer );
g_object_unref( iw->filesmodel );
g_object_unref( iw->model );
gtk_tree_row_reference_free( iw->row );
gtk_widget_destroy( widget );
g_free( iw );
}
static void
parsepath( GtkTreeStore * store, GtkTreeIter * ret,
const char * path, int index, uint64_t size )
{
GtkTreeModel * model;
GtkTreeIter * parent, start, iter;
char * file, * dir, * lower, * mykey, * modelkey;
const char * stock;
model = GTK_TREE_MODEL( store );
parent = NULL;
file = g_path_get_basename( path );
if( 0 != strcmp( file, path ) )
{
dir = g_path_get_dirname( path );
parsepath( store, &start, dir, index, size );
g_free( dir );
parent = &start;
}
lower = g_utf8_casefold( file, -1 );
mykey = g_utf8_collate_key( lower, -1 );
if( gtk_tree_model_iter_children( model, &iter, parent ) )
{
do
{
gtk_tree_model_get( model, &iter, FC_KEY, &modelkey, -1 );
if( NULL != modelkey && 0 == strcmp( mykey, modelkey ) )
{
goto done;
}
}
while( gtk_tree_model_iter_next( model, &iter ) );
}
gtk_tree_store_append( store, &iter, parent );
if( NULL == ret )
{
stock = GTK_STOCK_FILE;
}
else
{
stock = GTK_STOCK_DIRECTORY;
size = 0;
index = -1;
}
gtk_tree_store_set( store, &iter, FC_INDEX, index, FC_LABEL, file,
FC_KEY, mykey, FC_STOCK, stock, FC_SIZE, size, -1 );
done:
g_free( mykey );
g_free( lower );
g_free( file );
if( NULL != ret )
{
memcpy( ret, &iter, sizeof( iter ) );
}
}
static uint64_t
getdirtotals( GtkTreeStore * store, GtkTreeIter * parent )
{
GtkTreeModel * model;
GtkTreeIter iter;
uint64_t mysize, subsize;
char * sizestr, * name, * label;
model = GTK_TREE_MODEL( store );
mysize = 0;
if( gtk_tree_model_iter_children( model, &iter, parent ) )
{
do
{
if( gtk_tree_model_iter_has_child( model, &iter ) )
{
subsize = getdirtotals( store, &iter );
gtk_tree_store_set( store, &iter, FC_SIZE, subsize, -1 );
}
else
{
gtk_tree_model_get( model, &iter, FC_SIZE, &subsize, -1 );
}
gtk_tree_model_get( model, &iter, FC_LABEL, &name, -1 );
sizestr = readablesize( subsize );
label = g_markup_printf_escaped( "<small>%s (%s)</small>",
name, sizestr );
g_free( sizestr );
g_free( name );
gtk_tree_store_set( store, &iter, FC_LABEL, label, -1 );
g_free( label );
mysize += subsize;
}
while( gtk_tree_model_iter_next( model, &iter ) );
}
return mysize;
}
static gboolean
infowindupdate( gpointer data )
{
struct infowind * iw;
float * progress;
iw = data;
progress = tr_torrentCompletion( tr_torrent_handle( iw->tor ) );
updateprogress( iw->filesmodel, NULL, iw->size, progress );
free( progress );
infoupdate( iw, 0 );
return TRUE;
}
static float
updateprogress( GtkTreeModel * model, GtkTreeIter * parent,
uint64_t total, float * progress )
{
GtkTreeIter iter;
float myprog, subprog;
int index;
uint64_t size;
myprog = 0.0;
if( gtk_tree_model_iter_children( model, &iter, parent ) )
{
do
{
if( gtk_tree_model_iter_has_child( model, &iter ) )
{
gtk_tree_model_get( model, &iter, FC_SIZE, &size, -1 );
subprog = updateprogress( model, &iter, size, progress );
}
else
{
gtk_tree_model_get( model, &iter,
FC_SIZE, &size, FC_INDEX, &index, -1 );
g_assert( 0 <= index );
subprog = progress[index];
}
gtk_tree_store_set( GTK_TREE_STORE( model ), &iter,
FC_PROG, subprog, -1 );
myprog += subprog * ( total ? ( float )size / ( float )total : 1 );
}
while( gtk_tree_model_iter_next( model, &iter ) );
}
return myprog;
}
-5
View File
@@ -33,11 +33,6 @@
void
makeaddwind( GtkWindow * parent, TrCore * core );
/* show the info window for a torrent */
void
makeinfowind( GtkWindow * parent, GtkTreeModel * model, GtkTreePath * path,
TrTorrent * tor );
/* prompt for a download directory for torrents, then add them */
void
promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data,
+185
View File
@@ -0,0 +1,185 @@
/* GdkPixbuf RGBA C-Source image dump */
#ifdef __SUNPRO_C
#pragma align 4 (red_dot)
#endif
#ifdef __GNUC__
const guint8 red_dot[] __attribute__ ((__aligned__ (4))) =
#else
const guint8 red_dot[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
"GdkP"
/* length: header (24) + pixel_data (1024) */
"\0\0\4\30"
/* pixdata_type (0x1010002) */
"\1\1\0\2"
/* rowstride (64) */
"\0\0\0@"
/* width (16) */
"\0\0\0\20"
/* height (16) */
"\0\0\0\20"
/* pixel_data: */
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\1Z\0\0]P\0\0\253O\0\0\346O\0\0\346P\0\0\253Z\0\0]\0\0"
"\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2"
"Z\0\0\201v\2\2\377\271gg\377\323\210\210\377\323\210\210\377\271gg\377"
"v\2\2\377Z\0\0\201\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\2b\0\0`z\1\1\377\320pp\377\353\254\254\377\372\315\315\377\372\315"
"\315\377\353\254\254\377\320pp\377z\1\1\377b\0\0`\0\0\0\2\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\1\0\0\0\6_\0\0\260\245##\377\322__\377\333tt\377\322"
"]]\377\323]]\377\333tt\377\322__\377\245##\377_\0\0\260\0\0\0\6\0\0\0"
"\1\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13f\0\0\350\266\16\16\377\303\35\35"
"\377\31600\377\32200\377\32400\377\31600\377\302\35\35\377\266\16\16"
"\377f\0\0\350\0\0\0\13\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\20n\0\0"
"\351\263\0\0\377\320\17\17\377\332\22\22\377\336\22\22\377\341\22\22"
"\377\341\22\22\377\322\17\17\377\263\0\0\377n\0\0\351\0\0\0\20\0\0\0"
"\2\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\22q\0\0\271\263\0\0\377\345\0\0\377"
"\353\0\0\377\357\0\0\377\362\0\0\377\365\0\0\377\347\0\0\377\262\0\0"
"\377q\0\0\271\0\0\0\22\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\20r\0\0"
"x\266\0\0\377\377\35\35\377\377\10\10\377\377\27\27\377\377\27\27\377"
"\377\14\14\377\377\36\36\377\266\0\0\377r\0\0x\0\0\0\20\0\0\0\2\0\0\0"
"\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0%\244\0\0\236\354\0\0\377\377FF\377"
"\377gg\377\377gg\377\377RR\377\357\0\0\377\251\0\0\236\0\0\0%\0\0\0\13"
"\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\23\0\0\0/\247\0\0\206"
"\333\0\0\303\366\30\30\355\366\30\30\355\333\0\0\303\251\0\0\206\0\0"
"\0/\0\0\0\23\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\5"
"\0\0\0\24\0\0\0(\0\0\0""7\0\0\0\77\0\0\0\77\0\0\0""7\0\0\0(\0\0\0\24"
"\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0"
"\0\5\0\0\0\14\0\0\0\23\0\0\0\27\0\0\0\27\0\0\0\23\0\0\0\14\0\0\0\5\0"
"\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0"};
/* GdkPixbuf RGBA C-Source image dump */
#ifdef __SUNPRO_C
#pragma align 4 (yellow_dot)
#endif
#ifdef __GNUC__
const guint8 yellow_dot[] __attribute__ ((__aligned__ (4))) =
#else
const guint8 yellow_dot[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
"GdkP"
/* length: header (24) + pixel_data (1024) */
"\0\0\4\30"
/* pixdata_type (0x1010002) */
"\1\1\0\2"
/* rowstride (64) */
"\0\0\0@"
/* width (16) */
"\0\0\0\20"
/* height (16) */
"\0\0\0\20"
/* pixel_data: */
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\1\2344\0]\212.\0\253\207-\0\346\207-\0\346\212.\0\253"
"\2344\0]\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\2\2247\0\201\270T\2\377\353\241g\377\374\275\210\377\374\275"
"\210\377\353\241g\377\270T\2\377\2247\0\201\0\0\0\2\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\242B\0`\275[\1\377\375\270p\377\377\335"
"\256\377\377\360\320\377\377\360\320\377\377\335\256\377\375\270p\377"
"\275[\1\377\242B\0`\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\233"
"B\0\260\340\206#\377\375\271a\377\377\307z\377\377\274d\377\377\275d"
"\377\377\307z\377\375\271a\377\340\206#\377\233B\0\260\0\0\0\6\0\0\0"
"\1\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\250L\0\350\357\226\16\377\367\245"
"\40\377\373\2615\377\374\2645\377\375\2665\377\373\2615\377\367\243\40"
"\377\357\226\16\377\250L\0\350\0\0\0\13\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0"
"\2\0\0\0\20\264Y\0\351\356\222\0\377\373\262\22\377\375\271\24\377\377"
"\275\24\377\377\277\24\377\377\277\24\377\373\263\22\377\356\222\0\377"
"\264Y\0\351\0\0\0\20\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\22\267_\0"
"\271\353\231\0\377\377\304\0\377\377\311\0\377\377\314\0\377\377\317"
"\0\377\377\317\0\377\377\304\0\377\353\227\0\377\267_\0\271\0\0\0\22"
"\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\20\252c\0x\353\226\0\377\377\330"
"\0\377\377\333\0\377\377\345\32\377\377\352%\377\377\340\0\377\377\330"
"\0\377\353\226\0\377\252f\0x\0\0\0\20\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\1"
"\0\0\0\13\6\0\0%\301u\0\236\373\262\0\377\377\353H\377\377\375t\377\377"
"\377\204\377\377\357V\377\373\262\0\377\301w\0\236\6\0\0%\0\0\0\13\0"
"\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\23\0\0\0/\255\203\0\206"
"\337\247\0\303\366\313\35\355\366\322,\355\337\252\0\303\255\205\0\206"
"\0\0\0/\0\0\0\23\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0"
"\0\5\0\0\0\24\0\0\0(\0\0\0""7\0\0\0\77\0\0\0\77\0\0\0""7\0\0\0(\0\0\0"
"\24\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0"
"\0\0\5\0\0\0\14\0\0\0\23\0\0\0\27\0\0\0\27\0\0\0\23\0\0\0\14\0\0\0\5"
"\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"};
/* GdkPixbuf RGBA C-Source image dump */
#ifdef __SUNPRO_C
#pragma align 4 (green_dot)
#endif
#ifdef __GNUC__
const guint8 green_dot[] __attribute__ ((__aligned__ (4))) =
#else
const guint8 green_dot[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
"GdkP"
/* length: header (24) + pixel_data (1024) */
"\0\0\4\30"
/* pixdata_type (0x1010002) */
"\1\1\0\2"
/* rowstride (64) */
"\0\0\0@"
/* width (16) */
"\0\0\0\20"
/* height (16) */
"\0\0\0\20"
/* pixel_data: */
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\1\0U\0]\0I\0\253\0F\0\346\0F\0\346\0I\0\253\0U\0]\0\0"
"\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2"
"\1Q\0\201\40n\2\377}\263g\377\232\316\210\377\232\316\210\377}\263g\377"
"\40n\2\377\1Q\0\201\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\2\12\\\0`$s\1\377\214\314p\377\301\351\256\377\335\370\320\377\335"
"\370\320\377\301\351\256\377\214\314p\377$s\1\377\12\\\0`\0\0\0\2\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\17X\0\260P\234#\377\210\315a\377"
"\235\330z\377\214\317d\377\214\317d\377\235\330z\377\210\315a\377P\234"
"#\377\17X\0\260\0\0\0\6\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\27`"
"\0\350M\255\16\377a\274\40\377t\3055\377y\3115\377z\3115\377t\3055\377"
"^\274\40\377M\255\16\377\27`\0\350\0\0\0\13\0\0\0\2\0\0\0\0\0\0\0\0\0"
"\0\0\2\0\0\0\20\37g\0\351;\253\0\377i\307\22\377v\315\24\377}\317\24"
"\377\201\322\24\377\200\322\24\377j\307\22\377;\253\0\377\37g\0\351\0"
"\0\0\20\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\22&l\0\271J\254\0\377z"
"\325\0\377\205\332\0\377\213\333\0\377\220\335\0\377\222\337\0\377~\326"
"\0\377H\253\0\377&l\0\271\0\0\0\22\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\2\0"
"\0\0\20.n\0xX\243\0\377\224\345\0\377\235\351\0\377\260\360\32\377\267"
"\364%\377\245\353\0\377\225\346\0\377X\243\0\377.n\0x\0\0\0\20\0\0\0"
"\2\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0%K\207\0\236z\305\0\377\267"
"\364H\377\330\377t\377\337\377\204\377\276\367V\377}\310\0\377M\211\0"
"\236\0\0\0%\0\0\0\13\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\23"
"\0\0\0/U\220\0\206f\267\0\303|\330\35\355\201\336,\355i\271\0\303U\220"
"\0\206\0\0\0/\0\0\0\23\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\1\0\0\0\5\0\0\0\24\0\0\0(\0\0\0""7\0\0\0\77\0\0\0\77\0\0\0""7\0\0\0"
"(\0\0\0\24\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\1\0\0\0\5\0\0\0\14\0\0\0\23\0\0\0\27\0\0\0\27\0\0\0\23\0\0\0\14"
"\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"};
+166
View File
@@ -0,0 +1,166 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Pan - A Newsreader for Gtk+
* Copyright (C) 2002 Charles Kerr <charles@rebelbase.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <gtk/gtk.h>
#include "hig.h"
GtkWidget*
hig_workarea_create (void)
{
GtkWidget * t = gtk_table_new (4, 100, FALSE);
gtk_table_set_row_spacings (GTK_TABLE(t), 6);
gtk_container_set_border_width (GTK_CONTAINER(t), 12);
return t;
}
void
hig_workarea_add_section_divider (GtkWidget * table,
int * row)
{
GtkWidget * w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
gtk_widget_set_usize (w, 0u, 6u);
gtk_table_attach (GTK_TABLE(table), w, 0, 4, *row, *row+1, 0, 0, 0, 0);
++*row;
}
void
hig_workarea_add_section_title (GtkWidget * table,
int * row,
const char * section_title)
{
char buf[512];
GtkWidget * l;
g_snprintf (buf, sizeof(buf), "<b>%s</b>", section_title);
l = gtk_label_new (buf);
gtk_misc_set_alignment (GTK_MISC(l), 0.0f, 0.5f);
gtk_label_set_use_markup (GTK_LABEL(l), TRUE);
gtk_table_attach (GTK_TABLE(table), l, 0, 4, *row, *row+1, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
++*row;
}
void
hig_workarea_add_section_spacer (GtkWidget * table,
int row,
int items_in_section)
{
GtkWidget * w;
/* spacer to move the fields a little to the right of the name header */
w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
gtk_widget_set_usize (w, 18u, 0u);
gtk_table_attach (GTK_TABLE(table), w, 0, 1, row, row+items_in_section, 0, 0, 0, 0);
/* spacer between the controls and their labels */
w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
gtk_widget_set_usize (w, 12u, 0u);
gtk_table_attach (GTK_TABLE(table), w, 2, 3, row, row+items_in_section, 0, 0, 0, 0);
}
void
hig_workarea_add_wide_control (GtkWidget * table,
int * row,
GtkWidget * w)
{
gtk_table_attach (GTK_TABLE(table), w,
1, 4, *row, *row+1,
GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
++*row;
}
GtkWidget *
hig_workarea_add_wide_checkbutton (GtkWidget * table,
int * row,
const char * mnemonic_string,
gboolean is_active)
{
GtkWidget * w = gtk_check_button_new_with_mnemonic (mnemonic_string);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), is_active);
hig_workarea_add_wide_control (table, row, w);
return w;
}
void
hig_workarea_add_label_w (GtkWidget * table,
int row,
GtkWidget * l)
{
if (GTK_IS_MISC(l))
gtk_misc_set_alignment (GTK_MISC(l), 0.0f, 0.0f);
if (GTK_IS_LABEL(l))
gtk_label_set_use_markup (GTK_LABEL(l), TRUE);
gtk_table_attach (GTK_TABLE(table), l, 1, 2, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
}
GtkWidget*
hig_workarea_add_label (GtkWidget * table,
int row,
const char * mnemonic_string)
{
GtkWidget * l = gtk_label_new_with_mnemonic (mnemonic_string);
hig_workarea_add_label_w (table, row, l);
return l;
}
void
hig_workarea_add_control (GtkWidget * table,
int row,
GtkWidget * control)
{
gtk_table_attach (GTK_TABLE(table), control,
3, 4, row, row+1,
GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
}
void
hig_workarea_add_row_w (GtkWidget * table,
int * row,
GtkWidget * label,
GtkWidget * control,
GtkWidget * mnemonic)
{
hig_workarea_add_label_w (table, *row, label);
hig_workarea_add_control (table, *row, control);
if (GTK_IS_LABEL(label))
gtk_label_set_mnemonic_widget (GTK_LABEL(label),
mnemonic ? mnemonic : control);
++*row;
}
GtkWidget*
hig_workarea_add_row (GtkWidget * table,
int * row,
const char * mnemonic_string,
GtkWidget * control,
GtkWidget * mnemonic)
{
GtkWidget * l = gtk_label_new_with_mnemonic (mnemonic_string);
hig_workarea_add_row_w (table, row, l, control, mnemonic);
return l;
}
void
hig_workarea_finish (GtkWidget * table,
int * row)
{
GtkWidget * w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
gtk_widget_set_size_request (w, 0u, 6u);
gtk_table_attach_defaults (GTK_TABLE(table), w, 0, 4, *row, *row+1);
}
+107
View File
@@ -0,0 +1,107 @@
/******************************************************************************
* $Id:$
*
* Copyright (c) 2007 Transmission authors and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#ifndef __HIG_H__
#define __HIG_H__
#include <gtk/gtkwidget.h>
/**
*** utility code to make it slightly less painful to create
*** dialogs compliant with Gnome's Human Interface Guidelines
**/
GtkWidget* hig_workarea_create (void);
void
hig_workarea_add_section_divider (GtkWidget * table,
int * row);
void
hig_workarea_add_section_title (GtkWidget * table,
int * row,
const char * section_title);
void
hig_workarea_add_section_spacer (GtkWidget * table,
int row,
int items_in_section);
void
hig_workarea_add_wide_control (GtkWidget * table,
int * row,
GtkWidget * w);
GtkWidget*
hig_workarea_add_wide_checkbutton (GtkWidget * table,
int * row,
const char * mnemonic_string,
gboolean is_active);
GtkWidget*
hig_workarea_add_label (GtkWidget * table,
int row,
const char * mnemonic_string);
void
hig_workarea_add_label_w (GtkWidget * table,
int row,
GtkWidget * label_widget);
void
hig_workarea_add_control (GtkWidget * table,
int row,
GtkWidget * control);
GtkWidget*
hig_workarea_add_row (GtkWidget * table,
int * row,
const char * mnemonic_string,
GtkWidget * control,
GtkWidget * mnemonic_or_null_if_control_is_mnemonic);
void
hig_workarea_add_row_w (GtkWidget * table,
int * row,
GtkWidget * label,
GtkWidget * control,
GtkWidget * mnemonic_or_null_if_control_is_mnemonic);
void
hig_workarea_finish (GtkWidget * table,
int * row);
/**
***
**/
enum
{
GUI_PAD_SMALL = 3,
GUI_PAD = 6,
GUI_PAD_BIG = 12,
GUI_PAD_LARGE = 12
};
#endif /* __HIG_H__ */
+3 -1
View File
@@ -40,6 +40,7 @@
#include "dialogs.h"
#include "ipc.h"
#include "msgwin.h"
#include "torrent-inspector.h"
#include "tr_cell_renderer_progress.h"
#include "tr_core.h"
#include "tr_icon.h"
@@ -682,6 +683,7 @@ gotdrag(GtkWidget *widget SHUTUP, GdkDragContext *dc, gint x SHUTUP,
action = toraddaction( tr_prefs_get( PREF_ID_ADDSTD ) );
tr_core_add_list( data->core, paths, action, FALSE );
tr_core_torrents_added( data->core );
g_list_free(paths);
}
freestrlist(freeables);
g_free(files);
@@ -1012,7 +1014,7 @@ handleaction( struct cbdata * data, int act )
changed = TRUE;
break;
case ACT_INFO:
makeinfowind( data->wind, model, path, tor );
gtk_widget_show (torrent_inspector_new (data->wind, tor));
break;
case ACT_OPEN:
case ACT_PREF:
File diff suppressed because it is too large Load Diff
+33
View File
@@ -0,0 +1,33 @@
/******************************************************************************
* $Id:$
*
* Copyright (c) 2005-2007 Transmission authors and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#ifndef GTK_TORRENT_INSPECTOR_H
#define GTK_TORRENT_INSPECTOR_H
#include <gtk/gtkwindow.h>
#include "tr_torrent.h"
GtkWidget* torrent_inspector_new ( GtkWindow * parent, TrTorrent * tor );
#endif /* TG_PREFS_H */
+1
View File
@@ -739,6 +739,7 @@ tr_core_update( TrCore * self )
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
st = tr_torrent_stat( tor );
g_object_unref( tor );
tr_torrent_check_seeding_cap ( tor );
/* XXX find out if setting the same data emits changed signal */
gtk_list_store_set( GTK_LIST_STORE( self->model ), &iter,
+170 -18
View File
@@ -147,6 +147,10 @@ tr_torrent_init(GTypeInstance *instance, gpointer g_class SHUTUP) {
self->delfile = NULL;
self->severed = FALSE;
self->disposed = FALSE;
self->ul_cap_enabled = FALSE;
self->ul_cap = 0;
self->dl_cap_enabled = FALSE;
self->dl_cap = 0;
}
static void
@@ -225,8 +229,8 @@ tr_torrent_dispose(GObject *obj) {
tr_torrent_sever( self );
}
if(NULL != self->delfile)
g_free(self->delfile);
g_free (self->delfile);
g_free (self->dir);
/* Chain up to the parent class */
parent->dispose(obj);
@@ -317,16 +321,19 @@ tr_torrent_stop( TrTorrent * self )
}
static TrTorrent *
maketorrent( tr_torrent_t * handle, const char * dir, gboolean paused )
maketorrent( tr_torrent_t * handle,
const char * dir,
gboolean paused )
{
TrTorrent * tor;
tr_torrentDisablePex( handle,
!tr_prefs_get_bool_with_default( PREF_ID_PEX ) );
tor = g_object_new( TR_TORRENT_TYPE, "torrent-handle", handle,
"download-directory", dir, NULL);
tor = g_object_new( TR_TORRENT_TYPE,
"torrent-handle", handle,
"download-directory", dir,
NULL);
g_object_set( tor, "paused", paused, NULL );
return tor;
@@ -411,11 +418,18 @@ TrTorrent *
tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
gboolean forcedpause, char ** err )
{
TrTorrent * ret;
tr_torrent_t * handle;
int ii, errcode;
benc_val_t *name, *data;
char *torrent, *hash, *dir;
gboolean paused;
gboolean paused = FALSE;
gboolean ul_cap_enabled = FALSE;
gboolean dl_cap_enabled = FALSE;
gboolean seeding_cap_enabled = FALSE;
gint ul_cap = 0;
gint dl_cap = 0;
gdouble seeding_cap = 0.0;
*err = NULL;
@@ -430,15 +444,18 @@ tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
data = state->val.l.vals + ii + 1;
if(TYPE_STR == name->type &&
(TYPE_STR == data->type || TYPE_INT == data->type)) {
if(0 == strcmp("torrent", name->val.s.s))
torrent = data->val.s.s;
if(0 == strcmp("hash", name->val.s.s))
hash = data->val.s.s;
else if(0 == strcmp("dir", name->val.s.s))
dir = data->val.s.s;
else if(0 == strcmp("paused", name->val.s.s)) {
paused = (data->val.i ? TRUE : FALSE);
}
char * key = name->val.s.s;
char * val = data->val.s.s;
if (!strcmp (key, "torrent")) torrent = val;
else if (!strcmp (key, "hash")) hash = val;
else if (!strcmp (key, "dir")) dir = val;
else if (!strcmp (key, "paused")) paused = !!data->val.i;
else if (!strcmp (key, "ul-cap-speed")) ul_cap = data->val.i;
else if (!strcmp (key, "ul-cap-enabled")) ul_cap_enabled = !!data->val.i;
else if (!strcmp (key, "dl-cap-speed")) dl_cap = data->val.i;
else if (!strcmp (key, "dl-cap-enabled")) dl_cap_enabled = !!data->val.i;
else if (!strcmp (key, "seeding-cap-ratio")) seeding_cap = (data->val.i / 100.0);
else if (!strcmp (key, "seeding-cap-enabled")) seeding_cap_enabled = !!data->val.i;
}
}
@@ -467,7 +484,14 @@ tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
return NULL;
}
return maketorrent( handle, dir, paused || forcedpause );
ret = maketorrent( handle, dir, paused || forcedpause );
ret->ul_cap = ul_cap;
ret->ul_cap_enabled = ul_cap_enabled;
ret->dl_cap = dl_cap;
ret->dl_cap_enabled = dl_cap_enabled;
ret->seeding_cap = seeding_cap;
ret->seeding_cap_enabled = seeding_cap_enabled;
return ret;
}
gboolean
@@ -503,7 +527,22 @@ tr_torrent_get_state( TrTorrent * tor, benc_val_t * state )
tr_bencInitStr( tr_bencDictAdd( state, "dir" ),
tr_torrentGetFolder( tor->handle ), -1, 1 );
tr_bencInitInt( tr_bencDictAdd( state, "paused" ),
( tr_torrent_paused( tor ) ? 1 : 0 ) );
tr_torrent_paused( tor ) ? 1 : 0 );
tr_bencInitInt( tr_bencDictAdd( state, "ul-cap-speed" ),
tor->ul_cap );
tr_bencInitInt( tr_bencDictAdd( state, "ul-cap-enabled" ),
tor->ul_cap_enabled ? 1 : 0 );
tr_bencInitInt( tr_bencDictAdd( state, "dl-cap-speed" ),
tor->dl_cap );
tr_bencInitInt( tr_bencDictAdd( state, "dl-cap-enabled" ),
tor->dl_cap_enabled ? 1 : 0);
tr_bencInitInt( tr_bencDictAdd( state, "seeding-cap-ratio" ),
(int)(tor->dl_cap * 100.0)); /* two decimal places */
tr_bencInitInt( tr_bencDictAdd( state, "seeding-cap-enabled" ),
tor->seeding_cap_enabled ? 1 : 0);
return TRUE;
}
@@ -543,3 +582,116 @@ tr_torrent_paused(TrTorrent *tor) {
return (TR_STATUS_INACTIVE & st->status ? TRUE : FALSE);
}
extern void tr_setUseCustomUpload( tr_torrent_t * tor, int limit );
extern void tr_setUseCustomDownload( tr_torrent_t * tor, int limit );
static void refresh_upload_cap ( TrTorrent *gtor ) {
const int cap = gtor->ul_cap_enabled ? gtor->ul_cap : -1;
g_message ("setting upload cap to %d...", cap);
tr_setUseCustomUpload( gtor->handle, gtor->ul_cap_enabled );
tr_setUploadLimit( gtor->handle, cap );
}
void
tr_torrent_set_upload_cap_speed ( TrTorrent *gtor, int KiB_sec ) {
gtor->ul_cap = KiB_sec;
refresh_upload_cap ( gtor );
}
void
tr_torrent_set_upload_cap_enabled ( TrTorrent *gtor, gboolean b ) {
gtor->ul_cap_enabled = b;
refresh_upload_cap ( gtor );
}
static void refresh_download_cap ( TrTorrent *gtor ) {
const int cap = gtor->dl_cap_enabled ? gtor->dl_cap : -1;
tr_setUseCustomDownload( gtor->handle, gtor->dl_cap_enabled );
tr_setDownloadLimit( gtor->handle, cap );
}
void
tr_torrent_set_download_cap_speed ( TrTorrent *gtor, int KiB_sec ) {
gtor->dl_cap = KiB_sec;
refresh_download_cap( gtor );
}
void
tr_torrent_set_download_cap_enabled ( TrTorrent *gtor, gboolean b ) {
gtor->dl_cap_enabled = b;
refresh_download_cap( gtor );
}
void
tr_torrent_check_seeding_cap ( TrTorrent *gtor) {
tr_stat_t * st = tr_torrent_stat( gtor );
if ((gtor->seeding_cap_enabled) && (st->ratio >= gtor->seeding_cap))
tr_torrent_stop (gtor);
}
void
tr_torrent_set_seeding_cap_ratio ( TrTorrent *gtor, gdouble ratio ) {
gtor->seeding_cap = ratio;
tr_torrent_check_seeding_cap (gtor);
}
void
tr_torrent_set_seeding_cap_enabled ( TrTorrent *gtor, gboolean b ) {
if ((gtor->seeding_cap_enabled = b))
tr_torrent_check_seeding_cap (gtor);
}
char *
tr_torrent_status_str ( TrTorrent * gtor )
{
char * top = 0;
tr_stat_t * st = tr_torrent_stat( gtor );
const int tpeers = MAX (st->peersTotal, 0);
const int upeers = MAX (st->peersUploading, 0);
const int eta = st->eta;
const double prog = st->progress * 100.0; /* [0...100] */
const int status = st->status;
if( TR_STATUS_CHECK_WAIT & status )
{
top = g_strdup_printf( _("Waiting to check existing files (%.1f%%)"), prog );
}
else if( TR_STATUS_CHECK & status )
{
top = g_strdup_printf( _("Checking existing files (%.1f%%)"), prog );
}
else if( TR_STATUS_DOWNLOAD & status )
{
if( 0 > eta )
{
top = g_strdup_printf( _("Stalled (%.1f%%)"), prog );
}
else
{
char * timestr = readabletime(eta);
top = g_strdup_printf( _("Finishing in %s (%.1f%%)"),
timestr, prog );
g_free(timestr);
}
}
else if(TR_STATUS_SEED & status)
{
top = g_strdup_printf(
ngettext( "Seeding, uploading to %d of %d peer",
"Seeding, uploading to %d of %d peers", tpeers ),
upeers, tpeers );
}
else if( TR_STATUS_STOPPING & status )
{
top = g_strdup( _("Stopping...") );
}
else if( TR_STATUS_PAUSE & status )
{
top = g_strdup_printf( _("Stopped (%.1f%%)"), prog );
}
else
{
top = g_strdup( "" );
g_assert_not_reached();
}
return top;
}
+28
View File
@@ -58,8 +58,16 @@ struct _TrTorrent {
tr_torrent_t *handle;
char *dir;
char *delfile;
/* FIXME: hm, are these heavyweight enough to deserve their own properties? */
gboolean severed;
gboolean disposed;
gboolean ul_cap_enabled;
gboolean dl_cap_enabled;
gboolean seeding_cap_enabled;
gint ul_cap; /* KiB/sec */
gint dl_cap; /* KiB/sec */
gdouble seeding_cap; /* ratio to stop seeding at */
};
struct _TrTorrentClass {
@@ -84,6 +92,26 @@ tr_torrent_start( TrTorrent * tor );
void
tr_torrent_stop( TrTorrent * tor );
char*
tr_torrent_status_str ( TrTorrent * tor );
void
tr_torrent_set_upload_cap_speed ( TrTorrent*, int KiB_sec );
void
tr_torrent_set_upload_cap_enabled ( TrTorrent*, gboolean );
void
tr_torrent_set_download_cap_speed ( TrTorrent*, int KiB_sec );
void
tr_torrent_set_download_cap_enabled ( TrTorrent*, gboolean );
void
tr_torrent_check_seeding_cap ( TrTorrent* );
void
tr_torrent_set_seeding_cap_ratio ( TrTorrent*, gdouble ratio );
void
tr_torrent_set_seeding_cap_enabled ( TrTorrent*, gboolean );
#ifdef TR_WANT_TORRENT_PRIVATE
TrTorrent *
+14 -54
View File
@@ -351,9 +351,9 @@ tr_window_update( TrWindow * self, float downspeed, float upspeed )
}
/* update the status bar */
downstr = readablesize( downspeed * 1024.0 );
upstr = readablesize( upspeed * 1024.0 );
str = g_strdup_printf( _(" Total DL: %s/s Total UL: %s/s"),
downstr = readablespeed ( downspeed );
upstr = readablespeed ( upspeed );
str = g_strdup_printf( _(" Total DL: %s Total UL: %s"),
downstr, upstr );
g_free( downstr );
g_free( upstr );
@@ -491,67 +491,26 @@ static void
formatname( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
GtkTreeModel * model, GtkTreeIter * iter, gpointer data SHUTUP )
{
char * name, * mb, * terr, * str, * top, * bottom, * timestr;
TrTorrent * gtor;
char * name, * mb, * str, * top, * bottom;
guint64 size;
gfloat prog;
int status, err, eta, tpeers, upeers, dpeers;
gtk_tree_model_get( model, iter, MC_NAME, &name, MC_STAT, &status,
MC_ERR, &err, MC_SIZE, &size, MC_PROG, &prog,
MC_ERR, &err, MC_SIZE, &size,
MC_ETA, &eta, MC_PEERS, &tpeers, MC_UPEERS, &upeers,
MC_DPEERS, &dpeers, -1 );
MC_DPEERS, &dpeers, MC_TORRENT, &gtor, -1 );
tpeers = MAX( tpeers, 0 );
upeers = MAX( upeers, 0 );
dpeers = MAX( dpeers, 0 );
mb = readablesize(size);
prog *= 100;
if( TR_STATUS_CHECK_WAIT & status )
{
top = g_strdup_printf( _("Waiting to check existing files (%.1f%%)"), prog );
}
else if( TR_STATUS_CHECK & status )
{
top = g_strdup_printf( _("Checking existing files (%.1f%%)"), prog );
}
else if( TR_STATUS_DOWNLOAD & status )
{
if( 0 > eta )
{
top = g_strdup_printf( _("Stalled (%.1f%%)"), prog );
}
else
{
timestr = readabletime(eta);
top = g_strdup_printf( _("Finishing in %s (%.1f%%)"),
timestr, prog );
g_free(timestr);
}
}
else if(TR_STATUS_SEED & status)
{
top = g_strdup_printf(
ngettext( "Seeding, uploading to %d of %d peer",
"Seeding, uploading to %d of %d peers", tpeers ),
dpeers, tpeers );
}
else if( TR_STATUS_STOPPING & status )
{
top = g_strdup( _("Stopping...") );
}
else if( TR_STATUS_PAUSE & status )
{
top = g_strdup_printf( _("Stopped (%.1f%%)"), prog );
}
else
{
top = g_strdup( "" );
g_assert_not_reached();
}
top = tr_torrent_status_str ( gtor );
if( TR_OK != err )
{
char * terr;
gtk_tree_model_get( model, iter, MC_TERR, &terr, -1 );
bottom = g_strconcat( _("Error: "), terr, NULL );
g_free( terr );
@@ -576,6 +535,7 @@ formatname( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
g_free( str );
g_free( top );
g_free( bottom );
g_object_unref( gtor );
}
static void
@@ -591,16 +551,16 @@ formatprog( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
prog = MAX( prog, 0.0 );
prog = MIN( prog, 1.0 );
ulstr = readablesize( ul * 1024.0 );
ulstr = readablespeed (ul);
if( 1.0 == prog )
{
dlstr = ratiostr( down, up );
str = g_strdup_printf( _("Ratio: %s\nUL: %s/s"), dlstr, ulstr );
str = g_strdup_printf( _("Ratio: %s\nUL: %s"), dlstr, ulstr );
}
else
{
dlstr = readablesize( dl * 1024.0 );
str = g_strdup_printf( _("DL: %s/s\nUL: %s/s"), dlstr, ulstr );
dlstr = readablespeed( dl );
str = g_strdup_printf( _("DL: %s\nUL: %s"), dlstr, ulstr );
}
marked = g_markup_printf_escaped( "<small>%s</small>", str );
g_object_set( rend, "markup", str, "progress", prog, NULL );
+39 -42
View File
@@ -81,6 +81,17 @@ readablesize(guint64 size) {
gettext(sizestrs[ii]));
}
char *
readablespeed (double KiBps)
{
const guint64 bps = KiBps * 1024;
char * str = readablesize (bps);
char * ret = g_strdup_printf ("%s/s", str);
g_free (str);
return ret;
}
#define SECONDS(s) ((s) % 60)
#define MINUTES(s) ((s) / 60 % 60)
#define HOURS(s) ((s) / 60 / 60 % 24)
@@ -110,6 +121,16 @@ readabletime(int secs) {
DAYS(secs), ngettext("hour", "hours", DAYS(secs)));
}
char *
rfc822date (guint64 epoch_msec)
{
const time_t secs = epoch_msec / 1000;
const struct tm tm = *localtime (&secs);
char buf[128];
strftime (buf, sizeof(buf), "%a, %d %b %Y %T %Z", &tm);
return g_strdup (buf);
}
char *
ratiostr(guint64 down, guint64 up) {
double ratio;
@@ -167,37 +188,23 @@ dupstrlist( GList * list )
}
char *
joinstrlist(GList *list, char *sep) {
GList *ii;
int len;
char *ret, *dest;
if(0 > (len = strlen(sep) * (g_list_length(list) - 1)))
return NULL;
for(ii = g_list_first(list); NULL != ii; ii = ii->next)
len += strlen(ii->data);
dest = ret = g_new(char, len + 1);
for(ii = g_list_first(list); NULL != ii; ii = ii->next) {
dest = g_stpcpy(dest, ii->data);
if(NULL != ii->next)
dest = g_stpcpy(dest, sep);
joinstrlist(GList *list, char *sep)
{
GList *l;
GString *gstr = g_string_new (NULL);
for (l=list; l!=NULL; l=l->next) {
g_string_append (gstr, (char*)l->data);
if (l->next != NULL)
g_string_append (gstr, (sep));
}
return ret;
return g_string_free (gstr, FALSE);
}
void
freestrlist(GList *list) {
GList *ii;
if(NULL != list) {
for(ii = g_list_first(list); NULL != ii; ii = ii->next)
g_free(ii->data);
g_list_free(list);
}
freestrlist(GList *list)
{
g_list_foreach (list, (GFunc)g_free, NULL);
g_list_free (list);
}
char *
@@ -303,22 +310,12 @@ const char *
getdownloaddir( void )
{
static char * wd = NULL;
const char * dir;
dir = tr_prefs_get( PREF_ID_DIR );
if( NULL == dir )
{
if( NULL == wd )
{
wd = g_new( char, MAX_PATH_LENGTH + 1 );
if( NULL == getcwd( wd, MAX_PATH_LENGTH + 1 ) )
{
snprintf( wd, MAX_PATH_LENGTH + 1, "." );
}
}
dir = wd;
const char * dir = tr_prefs_get( PREF_ID_DIR );
if (NULL == dir) {
if (NULL == wd)
wd = g_get_current_dir(),
dir = wd;
}
return dir;
}
+12 -1
View File
@@ -31,15 +31,17 @@
/* macro to shut up "unused parameter" warnings */
#ifdef __GNUC__
#define SHUTUP __attribute__((unused))
#define UNUSED __attribute__((unused))
#else
#define SHUTUP
#define UNUSED
#endif
/* XXX this shouldn't be here */
enum tr_torrent_action { TR_TOR_LEAVE, TR_TOR_COPY, TR_TOR_MOVE };
/* return number of items in array */
#define ALEN( a ) ( ( signed )( sizeof(a) / sizeof( (a)[0] ) ) )
#define ALEN(a) ((signed)G_N_ELEMENTS(a))
/* used for a callback function with a data parameter */
typedef void (*callbackfunc_t)(void*);
@@ -72,11 +74,20 @@ strbool(const char *str);
char *
readablesize(guint64 size);
/* return a human-readable string for the transfer rate given in bytes.
the string must be g_free()d */
char *
readablespeed (double KiBps);
/* return a human-readable string for the time given in seconds.
the string must be g_free()d */
char *
readabletime(int secs);
char *
rfc822date (guint64 epoch_msec);
/* returns a string representing the download ratio.
the string must be g_free()d */
char *
+1
View File
@@ -26,6 +26,7 @@
#define TR_BENCODE_H 1
#include <stdint.h> /* for int64_t */
#include <string.h> /* for memset */
typedef struct benc_val_s
{
+1
View File
@@ -323,5 +323,6 @@ parseUTPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
peer_dbg( "GET extended-pex, no peers" );
}
tr_bencFree( &val );
return TR_OK;
}
+2
View File
@@ -238,6 +238,8 @@ void tr_threadJoin( tr_thread_t * t )
#endif
tr_dbg( "Thread '%s' joined", t->name );
free( t->name );
t->name = NULL;
t->func = NULL;
}
}
+1
View File
@@ -82,6 +82,7 @@ void tr_condWait( tr_cond_t *, tr_lock_t * );
void tr_condSignal( tr_cond_t * );
void tr_condClose( tr_cond_t * );
struct in_addr; /* forward declaration to calm gcc down */
int
tr_getDefaultRoute( struct in_addr * addr );
+11 -13
View File
@@ -189,6 +189,7 @@ static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor,
tor->blockSize;
tor->completion = tr_cpInit( tor );
tor->thread = THREAD_EMPTY;
tr_lockInit( &tor->lock );
tr_condInit( &tor->cond );
@@ -239,7 +240,7 @@ void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
}
}
char * tr_torrentGetFolder( tr_torrent_t * tor )
const char * tr_torrentGetFolder( tr_torrent_t * tor )
{
return tor->destination;
}
@@ -263,11 +264,8 @@ int tr_torrentDuplicateDownload( tr_torrent_t * tor )
void tr_torrentStart( tr_torrent_t * tor )
{
if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
{
/* Join the thread first */
torrentReallyStop( tor );
}
/* Join the thread first */
torrentReallyStop( tor );
/* Don't start if a torrent with the same name and destination is already active */
if( tr_torrentDuplicateDownload( tor ) )
@@ -335,8 +333,11 @@ static void torrentReallyStop( tr_torrent_t * tor )
tor->die = 1;
tr_threadJoin( &tor->thread );
tr_trackerClose( tor->tracker );
tor->tracker = NULL;
if( tor->tracker )
{
tr_trackerClose( tor->tracker );
tor->tracker = NULL;
}
tr_lockLock( &tor->lock );
for( i = 0; i < tor->peerCount; i++ )
@@ -679,11 +680,8 @@ void tr_torrentClose( tr_torrent_t * tor )
tr_handle_t * h = tor->handle;
tr_info_t * inf = &tor->info;
if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
{
/* Join the thread first */
torrentReallyStop( tor );
}
/* Join the thread first */
torrentReallyStop( tor );
tr_sharedLock( h->shared );
+1
View File
@@ -175,6 +175,7 @@ void tr_close( tr_handle_t * h )
tr_sharedClose( h->shared );
tr_fdClose();
free( h->tag );
free( h );
tr_netResolveThreadClose();
+1 -1
View File
@@ -270,7 +270,7 @@ tr_info_t * tr_torrentInfo( tr_torrent_t * );
int tr_torrentScrape( tr_torrent_t *, int * s, int * l, int * d );
void tr_torrentSetFolder( tr_torrent_t *, const char * );
char * tr_torrentGetFolder( tr_torrent_t * );
const char * tr_torrentGetFolder( tr_torrent_t * );
int tr_torrentDuplicateDownload( tr_torrent_t * tor );
+2 -1
View File
@@ -3,7 +3,8 @@
include ../mk/config.mk
include ../mk/common.mk
SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c \
SRCS = conf.c dialogs.c hig.c io.c ipc.c main.c msgwin.c \
torrent-inspector.c \
tr_cell_renderer_progress.c tr_core.c tr_icon.c tr_prefs.c \
tr_torrent.c tr_window.c util.c
OBJS = $(SRCS:%.c=%.o)