source: trunk/gtk/torrent-cell-renderer.c @ 7069

Last change on this file since 7069 was 7069, checked in by charles, 10 years ago

more fucking around with the speed measurements.

  • Property svn:keywords set to Date Rev Author Id
File size: 24.1 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: torrent-cell-renderer.c 7069 2008-11-08 02:49:04Z charles $
11 */
12
13#include "assert.h"
14#include <gtk/gtk.h>
15#include <glib/gi18n.h>
16#include <libtransmission/transmission.h>
17#include "hig.h"
18#include "torrent-cell-renderer.h"
19#include "tr-torrent.h"
20#include "util.h"
21
22/* #define TEST_RTL */
23
24enum
25{
26    P_TORRENT = 1,
27    P_BAR_HEIGHT,
28    P_MINIMAL
29};
30
31#define DEFAULT_BAR_HEIGHT 12
32
33/***
34****
35***/
36
37static char*
38getProgressString( const tr_info * info,
39                   const tr_stat * torStat )
40{
41    const int      isDone = torStat->leftUntilDone == 0;
42    const uint64_t haveTotal = torStat->haveUnchecked + torStat->haveValid;
43    const int      isSeed = torStat->haveValid >= info->totalSize;
44    char           buf1[32], buf2[32], buf3[32], buf4[32];
45    char *         str;
46
47    if( !isDone )
48        str = g_strdup_printf(
49            /* %1$s is how much we've got,
50               %2$s is how much we'll have when done,
51               %3$.2f%% is a percentage of the two */
52            _( "%1$s of %2$s (%3$.2f%%)" ),
53            tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
54            tr_strlsize( buf2, torStat->sizeWhenDone, sizeof( buf2 ) ),
55            torStat->percentDone * 100.0 );
56    else if( !isSeed )
57        str = g_strdup_printf(
58            /* %1$s is how much we've got,
59               %2$s is the torrent's total size,
60               %3$.2f%% is a percentage of the two,
61               %4$s is how much we've uploaded,
62               %5$s is our upload-to-download ratio */
63            _( "%1$s of %2$s (%3$.2f%%), uploaded %4$s (Ratio: %5$s)" ),
64            tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
65            tr_strlsize( buf2, info->totalSize, sizeof( buf2 ) ),
66            torStat->percentComplete * 100.0,
67            tr_strlsize( buf3, torStat->uploadedEver, sizeof( buf3 ) ),
68            tr_strlratio( buf4, torStat->ratio, sizeof( buf4 ) ) );
69    else
70        str = g_strdup_printf(
71            /* %1$s is the torrent's total size,
72               %2$s is how much we've uploaded,
73               %3$s is our upload-to-download ratio */
74            _( "%1$s, uploaded %2$s (Ratio: %3$s)" ),
75            tr_strlsize( buf1, info->totalSize, sizeof( buf1 ) ),
76            tr_strlsize( buf2, torStat->uploadedEver, sizeof( buf2 ) ),
77            tr_strlratio( buf3, torStat->ratio, sizeof( buf3 ) ) );
78
79    /* add time when downloading */
80    if( torStat->activity == TR_STATUS_DOWNLOAD )
81    {
82        const int eta = torStat->eta;
83        GString * gstr = g_string_new( str );
84        g_string_append( gstr, " - " );
85        if( eta < 0 )
86            g_string_append( gstr, _( "Remaining time unknown" ) );
87        else
88        {
89            char timestr[128];
90            tr_strltime( timestr, eta, sizeof( timestr ) );
91            /* time remaining */
92            g_string_append_printf( gstr, _( "%s remaining" ), timestr );
93        }
94        g_free( str );
95        str = g_string_free( gstr, FALSE );
96    }
97
98    return str;
99}
100
101static char*
102getShortTransferString( const tr_stat * torStat,
103                        char *          buf,
104                        size_t          buflen )
105{
106    char      downStr[32], upStr[32];
107    const int haveDown = torStat->peersSendingToUs > 0;
108    const int haveUp = torStat->peersGettingFromUs > 0;
109
110    if( haveDown )
111        tr_strlspeed( downStr, torStat->pieceDownloadSpeed, sizeof( downStr ) );
112    if( haveUp )
113        tr_strlspeed( upStr, torStat->pieceUploadSpeed, sizeof( upStr ) );
114
115    if( haveDown && haveUp )
116        /* Translators: do not translate the "speed|" disambiguation prefix.
117           %1$s is the download speed
118           %2$s is the upload speed */
119        g_snprintf( buf, buflen, Q_(
120                        "speed|Down: %1$s, Up: %2$s" ), downStr, upStr );
121    else if( haveDown )
122        /* download speed */
123        g_snprintf( buf, buflen, _( "Down: %s" ), downStr );
124    else if( haveUp )
125        /* upload speed */
126        g_snprintf( buf, buflen, _( "Up: %s" ), upStr );
127    else
128        /* the torrent isn't uploading or downloading */
129        g_strlcpy( buf, _( "Idle" ), buflen );
130
131    return buf;
132}
133
134static char*
135getShortStatusString( const tr_stat * torStat )
136{
137    GString * gstr = g_string_new( NULL );
138
139    switch( torStat->activity )
140    {
141        case TR_STATUS_STOPPED:
142            g_string_assign( gstr, _( "Paused" ) );
143            break;
144
145        case TR_STATUS_CHECK_WAIT:
146            g_string_assign( gstr, _( "Waiting to verify local data" ) );
147            break;
148
149        case TR_STATUS_CHECK:
150            g_string_append_printf( gstr,
151                                    _(
152                                        "Verifying local data (%.1f%% tested)" ),
153                                    torStat->recheckProgress * 100.0 );
154            break;
155
156        case TR_STATUS_DOWNLOAD:
157        case TR_STATUS_SEED:
158        {
159            char buf[128];
160            if( torStat->activity != TR_STATUS_DOWNLOAD )
161            {
162                tr_strlratio( buf, torStat->ratio, sizeof( buf ) );
163                g_string_append_printf( gstr, _( "Ratio: %s" ), buf );
164                g_string_append( gstr, ", " );
165            }
166            getShortTransferString( torStat, buf, sizeof( buf ) );
167            g_string_append( gstr, buf );
168            break;
169        }
170
171        default:
172            break;
173    }
174
175    return g_string_free( gstr, FALSE );
176}
177
178static char*
179getStatusString( const tr_stat * torStat )
180{
181    const int isActive = torStat->activity != TR_STATUS_STOPPED;
182    const int isChecking = torStat->activity == TR_STATUS_CHECK
183                        || torStat->activity == TR_STATUS_CHECK_WAIT;
184
185    GString * gstr = g_string_new( NULL );
186
187    if( torStat->error )
188    {
189        g_string_assign( gstr, torStat->errorString );
190    }
191    else switch( torStat->activity )
192        {
193            case TR_STATUS_STOPPED:
194            case TR_STATUS_CHECK_WAIT:
195            case TR_STATUS_CHECK:
196            {
197                char * pch = getShortStatusString( torStat );
198                g_string_assign( gstr, pch );
199                g_free( pch );
200                break;
201            }
202
203            case TR_STATUS_DOWNLOAD:
204                g_string_append_printf( gstr,
205                    ngettext( "Downloading from %1$'d of %2$'d connected peer",
206                              "Downloading from %1$'d of %2$'d connected peers",
207                              torStat->peersConnected ),
208                    torStat->peersSendingToUs +
209                    torStat->webseedsSendingToUs,
210                    torStat->peersConnected +
211                    torStat->webseedsSendingToUs );
212                break;
213
214            case TR_STATUS_SEED:
215                g_string_append_printf( gstr,
216                    ngettext( "Seeding to %1$'d of %2$'d connected peer",
217                              "Seeding to %1$'d of %2$'d connected peers",
218                              torStat->peersConnected ),
219                    torStat->peersGettingFromUs,
220                    torStat->peersConnected );
221                break;
222        }
223
224    if( isActive && !isChecking )
225    {
226        char buf[256];
227        getShortTransferString( torStat, buf, sizeof( buf ) );
228        g_string_append_printf( gstr, " - %s", buf );
229    }
230
231    return g_string_free( gstr, FALSE );
232}
233
234/***
235****
236***/
237
238static GtkCellRendererClass * parent_class = NULL;
239
240struct TorrentCellRendererPrivate
241{
242    tr_torrent *       tor;
243    GtkCellRenderer *  text_renderer;
244    GtkCellRenderer *  text_renderer_err;
245    GtkCellRenderer *  progress_renderer;
246    int                bar_height;
247    gboolean           minimal;
248};
249
250static void
251torrent_cell_renderer_get_size( GtkCellRenderer * cell,
252                                GtkWidget *       widget,
253                                GdkRectangle *    cell_area,
254                                gint *            x_offset,
255                                gint *            y_offset,
256                                gint *            width,
257                                gint *            height )
258{
259    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
260
261    if( self && self->priv->tor )
262    {
263        const tr_torrent *                  tor = self->priv->tor;
264        const tr_info *                     info = tr_torrentInfo( tor );
265        const char *                        name = info->name;
266        const tr_stat *                     torStat =
267            tr_torrentStatCached( (tr_torrent*)tor );
268        char *                              str;
269        int                                 w = 0, h = 0;
270        struct TorrentCellRendererPrivate * p = self->priv;
271        GtkCellRenderer *                   text_renderer =
272            torStat->error != 0
273            ? p->
274            text_renderer_err
275            : p->
276            text_renderer;
277
278        g_object_set( text_renderer, "ellipsize", PANGO_ELLIPSIZE_NONE,
279                      NULL );
280
281        /* above the progressbar */
282        if( p->minimal )
283        {
284            int    w1, w2, h1, h2;
285            char * shortStatus = getShortStatusString( torStat );
286            g_object_set( text_renderer, "text", name, NULL );
287            gtk_cell_renderer_get_size( text_renderer,
288                                        widget, NULL, NULL, NULL, &w1, &h1 );
289            str = g_markup_printf_escaped( "<small>%s</small>", shortStatus );
290            g_object_set( text_renderer, "markup", str, NULL );
291            gtk_cell_renderer_get_size( text_renderer,
292                                        widget, NULL, NULL, NULL, &w2, &h2 );
293            h += MAX( h1, h2 );
294            w = MAX( w, w1 + GUI_PAD_BIG + w2 );
295            g_free( str );
296            g_free( shortStatus );
297        }
298        else
299        {
300            int    w1, h1;
301            char * progressString = getProgressString( info, torStat );
302            str = g_markup_printf_escaped( "<b>%s</b>\n<small>%s</small>",
303                                           name, progressString );
304            g_object_set( text_renderer, "markup", str, NULL );
305            gtk_cell_renderer_get_size( text_renderer,
306                                        widget, NULL, NULL, NULL, &w1, &h1 );
307            h += h1;
308            w = MAX( w, w1 );
309            g_free( str );
310            g_free( progressString );
311        }
312
313        /* below the progressbar */
314        if( !p->minimal )
315        {
316            int    w1, h1;
317            char * statusString = getStatusString( torStat );
318            str = g_markup_printf_escaped( "<small>%s</small>",
319                                           statusString );
320            g_object_set( text_renderer, "markup", str, NULL );
321            gtk_cell_renderer_get_size( text_renderer,
322                                        widget, NULL, NULL, NULL, &w1, &h1 );
323            h += h1;
324            w = MAX( w, w1 );
325            g_free( str );
326            g_free( statusString );
327        }
328
329        h += p->bar_height;
330
331        if( cell_area )
332        {
333            if( x_offset ) *x_offset = 0;
334            if( y_offset )
335            {
336                *y_offset = 0.5 *
337                            ( cell_area->height - ( h + ( 2 * cell->ypad ) ) );
338                *y_offset = MAX( *y_offset, 0 );
339            }
340        }
341
342        *width = w + cell->xpad * 2;
343        *height = h + cell->ypad * 2;
344    }
345}
346
347static void
348torrent_cell_renderer_render(
349    GtkCellRenderer *                  cell,
350    GdkDrawable *                      window,
351    GtkWidget *                        widget,
352    GdkRectangle *
353                                       background_area,
354    GdkRectangle         * cell_area   UNUSED,
355    GdkRectangle         * expose_area UNUSED,
356    GtkCellRendererState               flags )
357{
358    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
359
360#ifdef TEST_RTL
361    GtkTextDirection      real_dir = gtk_widget_get_direction( widget );
362    gtk_widget_set_direction( widget, GTK_TEXT_DIR_RTL );
363#endif
364
365    if( self && self->priv->tor )
366    {
367        const tr_torrent *                  tor = self->priv->tor;
368        const tr_info *                     info = tr_torrentInfo( tor );
369        const char *                        name = info->name;
370        const tr_stat *                     torStat =
371            tr_torrentStatCached( (tr_torrent*)tor );
372        GdkRectangle                        my_bg;
373        GdkRectangle                        my_cell;
374        GdkRectangle                        my_expose;
375        int                                 w, h;
376        struct TorrentCellRendererPrivate * p = self->priv;
377        GtkCellRenderer * text_renderer = torStat->error != 0
378                                        ? p->text_renderer_err
379                                        : p->text_renderer;
380        const gboolean isActive = torStat->activity != TR_STATUS_STOPPED;
381
382        my_bg = *background_area;
383        my_bg.x += cell->xpad;
384        my_bg.y += cell->ypad;
385        my_bg.width -= cell->xpad * 2;
386        my_cell = my_expose = my_bg;
387
388        g_object_set( text_renderer, "sensitive", isActive, NULL );
389        g_object_set( p->progress_renderer, "sensitive", isActive, NULL );
390
391        /* above the progressbar */
392        if( !p->minimal )
393        {
394            char * progressString = getProgressString( info, torStat );
395            char * str = g_markup_printf_escaped(
396                "<b>%s</b>\n<small>%s</small>",
397                name, progressString );
398            g_object_set( text_renderer, "markup", str,
399                          "ellipsize", PANGO_ELLIPSIZE_NONE,
400                          NULL );
401            gtk_cell_renderer_get_size( text_renderer,
402                                        widget, NULL, NULL, NULL, &w, &h );
403            my_bg.height     =
404                my_cell.height   =
405                    my_expose.height = h;
406            g_object_set( text_renderer, "ellipsize", PANGO_ELLIPSIZE_END,
407                          NULL );
408            gtk_cell_renderer_render( text_renderer,
409                                      window, widget,
410                                      &my_bg, &my_cell, &my_expose, flags );
411            my_bg.y += h;
412            my_cell.y += h;
413            my_expose.y += h;
414
415            g_free( str );
416            g_free( progressString );
417        }
418        else
419        {
420            char *       statusStr = getShortStatusString( torStat );
421            char *       str = g_markup_printf_escaped( "<small>%s</small>",
422                                                        statusStr );
423            int          w1, w2, h1, h2, tmp_h;
424            GdkRectangle tmp_bg, tmp_cell, tmp_expose;
425
426            /* get the dimensions for the name */
427            g_object_set( text_renderer, "text", name,
428                          "ellipsize", PANGO_ELLIPSIZE_NONE,
429                          NULL );
430            gtk_cell_renderer_get_size( text_renderer,
431                                        widget, NULL, NULL, NULL, &w1, &h1 );
432
433            /* get the dimensions for the short status string */
434            g_object_set( text_renderer, "markup", str,
435                          "ellipsize", PANGO_ELLIPSIZE_NONE,
436                          NULL );
437            gtk_cell_renderer_get_size( text_renderer,
438                                        widget, NULL, NULL, NULL, &w2, &h2 );
439
440            tmp_h = MAX( h1, h2 );
441
442            /* short status */
443            tmp_bg.x = my_bg.width - w2;
444            tmp_bg.y = my_bg.y + ( h2 - h1 ) / 2;
445            tmp_bg.width = w2;
446            tmp_bg.height = tmp_h;
447            tmp_expose = tmp_cell = tmp_bg;
448            g_object_set( text_renderer, "markup", str,
449                          "ellipsize", PANGO_ELLIPSIZE_END,
450                          NULL );
451            gtk_cell_renderer_render( text_renderer,
452                                      window, widget,
453                                      &tmp_bg, &tmp_cell, &tmp_expose,
454                                      flags );
455
456            /* name */
457            tmp_bg.x = my_bg.x;
458            tmp_bg.width = my_bg.width - w2 - GUI_PAD_BIG;
459            tmp_expose = tmp_cell = tmp_bg;
460            g_object_set( text_renderer, "text", name,
461                          "ellipsize", PANGO_ELLIPSIZE_END,
462                          NULL );
463            gtk_cell_renderer_render( text_renderer,
464                                      window, widget,
465                                      &tmp_bg, &tmp_cell, &tmp_expose,
466                                      flags );
467
468            my_bg.y = tmp_bg.y + tmp_bg.height;
469            my_cell.y = tmp_cell.y + tmp_cell.height;
470            my_expose.y += tmp_expose.y + tmp_cell.height;
471
472            g_free( str );
473            g_free( statusStr );
474        }
475
476        /* the progressbar */
477        my_cell.height = p->bar_height;
478        if( 1 )
479        {
480            const double percent = MAX( 0.0, torStat->percentDone );
481            g_object_set( p->progress_renderer, "value",
482                          (int)( percent * 100.0 ),
483                          "text", "",
484                          NULL );
485            gtk_cell_renderer_render( p->progress_renderer,
486                                      window, widget,
487                                      &my_cell, &my_cell, &my_cell, flags );
488        }
489        my_bg.y     += my_cell.height;
490        my_cell.y   += my_cell.height;
491        my_expose.y += my_cell.height;
492
493        /* below progressbar */
494        if( !p->minimal )
495        {
496            char * statusString = getStatusString( torStat );
497            char * str = g_markup_printf_escaped( "<small>%s</small>",
498                                                  statusString );
499            g_object_set( text_renderer, "markup", str,
500                          "ellipsize", PANGO_ELLIPSIZE_END,
501                          NULL );
502            gtk_cell_renderer_get_size( text_renderer,
503                                        widget, NULL, NULL, NULL, &w, &h );
504            my_bg.height      =
505                my_cell.height    =
506                    my_expose.height  = h;
507            gtk_cell_renderer_render( text_renderer,
508                                      window, widget,
509                                      &my_bg, &my_cell, &my_expose, flags );
510
511            g_free( str );
512            g_free( statusString );
513        }
514    }
515
516#ifdef TEST_RTL
517    gtk_widget_set_direction( widget, real_dir );
518#endif
519}
520
521static void
522torrent_cell_renderer_set_property( GObject *      object,
523                                    guint          property_id,
524                                    const GValue * v,
525                                    GParamSpec *   pspec )
526{
527    TorrentCellRenderer *               self = TORRENT_CELL_RENDERER(
528        object );
529    struct TorrentCellRendererPrivate * p = self->priv;
530
531    switch( property_id )
532    {
533        case P_TORRENT:
534            p->tor = g_value_get_pointer( v ); break;
535
536        case P_BAR_HEIGHT:
537            p->bar_height = g_value_get_int( v ); break;
538
539        case P_MINIMAL:
540            p->minimal  = g_value_get_boolean( v ); break;
541
542        default:
543            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
544            break;
545    }
546}
547
548static void
549torrent_cell_renderer_get_property( GObject *    object,
550                                    guint        property_id,
551                                    GValue *     v,
552                                    GParamSpec * pspec )
553{
554    const TorrentCellRenderer *         self = TORRENT_CELL_RENDERER(
555        object );
556    struct TorrentCellRendererPrivate * p = self->priv;
557
558    switch( property_id )
559    {
560        case P_TORRENT:
561            g_value_set_pointer( v, p->tor ); break;
562
563        case P_BAR_HEIGHT:
564            g_value_set_int( v, p->bar_height ); break;
565
566        case P_MINIMAL:
567            g_value_set_boolean( v, p->minimal ); break;
568
569        default:
570            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
571            break;
572    }
573}
574
575static void
576torrent_cell_renderer_dispose( GObject * o )
577{
578    TorrentCellRenderer * r = TORRENT_CELL_RENDERER( o );
579    GObjectClass *        parent;
580
581    if( r && r->priv )
582    {
583        g_object_unref( G_OBJECT( r->priv->text_renderer ) );
584        g_object_unref( G_OBJECT( r->priv->text_renderer_err ) );
585        g_object_unref( G_OBJECT( r->priv->progress_renderer ) );
586        r->priv = NULL;
587    }
588
589    parent = g_type_class_peek( g_type_parent( TORRENT_CELL_RENDERER_TYPE ) );
590    parent->dispose( o );
591}
592
593static void
594torrent_cell_renderer_class_init( TorrentCellRendererClass * klass )
595{
596    GObjectClass *         gobject_class = G_OBJECT_CLASS( klass );
597    GtkCellRendererClass * cell_class = GTK_CELL_RENDERER_CLASS( klass );
598
599    g_type_class_add_private( klass,
600                             sizeof( struct TorrentCellRendererPrivate ) );
601
602    parent_class = (GtkCellRendererClass*) g_type_class_peek_parent( klass );
603
604    cell_class->render = torrent_cell_renderer_render;
605    cell_class->get_size = torrent_cell_renderer_get_size;
606    gobject_class->set_property = torrent_cell_renderer_set_property;
607    gobject_class->get_property = torrent_cell_renderer_get_property;
608    gobject_class->dispose = torrent_cell_renderer_dispose;
609
610    g_object_class_install_property( gobject_class, P_TORRENT,
611                                    g_param_spec_pointer( "torrent", NULL,
612                                                          "tr_torrent*",
613                                                          G_PARAM_READWRITE ) );
614
615    g_object_class_install_property( gobject_class, P_BAR_HEIGHT,
616                                    g_param_spec_int( "bar-height", NULL,
617                                                      "Bar Height",
618                                                      1, INT_MAX,
619                                                      DEFAULT_BAR_HEIGHT,
620                                                      G_PARAM_READWRITE ) );
621
622    g_object_class_install_property( gobject_class, P_MINIMAL,
623                                    g_param_spec_boolean( "minimal", NULL,
624                                                          "Minimal Mode",
625                                                          FALSE,
626                                                          G_PARAM_READWRITE ) );
627}
628
629static void
630torrent_cell_renderer_init( GTypeInstance *  instance,
631                            gpointer g_class UNUSED )
632{
633    TorrentCellRenderer *               self = TORRENT_CELL_RENDERER(
634        instance );
635    struct TorrentCellRendererPrivate * p;
636
637    p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE(
638            self,
639            TORRENT_CELL_RENDERER_TYPE,
640            struct
641            TorrentCellRendererPrivate );
642
643    p->tor = NULL;
644    p->text_renderer = gtk_cell_renderer_text_new( );
645    p->text_renderer_err = gtk_cell_renderer_text_new(  );
646    p->progress_renderer = gtk_cell_renderer_progress_new(  );
647    g_object_set( p->text_renderer_err, "foreground", "red", NULL );
648    tr_object_ref_sink( p->text_renderer );
649    tr_object_ref_sink( p->text_renderer_err );
650    tr_object_ref_sink( p->progress_renderer );
651
652    p->bar_height = DEFAULT_BAR_HEIGHT;
653}
654
655GType
656torrent_cell_renderer_get_type( void )
657{
658    static GType type = 0;
659
660    if( !type )
661    {
662        static const GTypeInfo info =
663        {
664            sizeof( TorrentCellRendererClass ),
665            NULL,                                            /* base_init */
666            NULL,                                            /* base_finalize */
667            (GClassInitFunc)torrent_cell_renderer_class_init,
668            NULL,                                            /* class_finalize
669                                                               */
670            NULL,                                            /* class_data */
671            sizeof( TorrentCellRenderer ),
672            0,                                               /* n_preallocs */
673            (GInstanceInitFunc)torrent_cell_renderer_init,
674            NULL
675        };
676
677        type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
678                                       "TorrentCellRenderer",
679                                       &info, (GTypeFlags)0 );
680    }
681
682    return type;
683}
684
685GtkCellRenderer *
686torrent_cell_renderer_new( void )
687{
688    return (GtkCellRenderer *) g_object_new( TORRENT_CELL_RENDERER_TYPE,
689                                             NULL );
690}
691
Note: See TracBrowser for help on using the repository browser.