Changeset 2054


Ignore:
Timestamp:
Jun 13, 2007, 12:24:45 AM (15 years ago)
Author:
charles
Message:

gtk: add a popup menu w/priorities to the inspector's file list.
gtk: fairly large changes to switch over to GtkAction? (see actions.c)

Location:
branches/file_selection/gtk
Files:
4 added
12 edited

Legend:

Unmodified
Added
Removed
  • branches/file_selection/gtk/main.c

    r2006 r2054  
    3737#include <glib/gstdio.h>
    3838
     39#include "actions.h"
    3940#include "conf.h"
    4041#include "dialogs.h"
     
    4950#include "tr_window.h"
    5051#include "util.h"
     52#include "ui.h"
    5153
    5254#include "transmission.h"
    5355#include "version.h"
    54 
    55 #include "img_icon_full.h"
    5656
    5757/* time in seconds to wait for torrents to stop when exiting */
     
    9696    GtkWindow    * wind;
    9797    TrCore       * core;
    98     TrIcon       * icon;
     98    GtkWidget    * icon;
    9999    TrPrefs      * prefs;
    100100    guint          timer;
     
    110110};
    111111
    112 enum
    113 {
    114     ACT_OPEN = 0,
    115     ACT_START,
    116     ACT_STOP,
    117     ACT_DELETE,
    118     ACT_SEPARATOR1,
    119     ACT_INFO,
    120     ACT_DEBUG,
    121     ACT_ABOUT,
    122     ACT_SEPARATOR2,
    123     ACT_PREF,
    124     ACT_SEPARATOR3,
    125     ACT_CLOSE,
    126     ACT_QUIT,
    127     ACT_ICON,
    128     ACTION_COUNT,
    129 };
    130 
    131 #if !GTK_CHECK_VERSION(2,8,0)
    132 #define GTK_STOCK_INFO NULL
    133 #endif
    134 
    135 struct
    136 {
    137     const char * label;
    138     const char * icon;
    139     guint        key;
    140     int          flags;
    141     const char * tooltip;
    142 }
    143 actions[] =
    144 {
    145     { NULL,        GTK_STOCK_ADD,       'o', ACTF_WHEREVER | ACTF_ALWAYS,
    146       N_("Add a new torrent") },
    147     { N_("Start"), GTK_STOCK_EXECUTE,     0, ACTF_WHEREVER | ACTF_INACTIVE,
    148       N_("Start a torrent that is not running") },
    149     { NULL,        GTK_STOCK_STOP,        0, ACTF_WHEREVER | ACTF_ACTIVE,
    150       N_("Stop a torrent that is running") },
    151     { NULL,        GTK_STOCK_REMOVE,      0, ACTF_WHEREVER | ACTF_WHATEVER,
    152       N_("Remove a torrent") },
    153     { NULL,        NULL,                  0, ACTF_SEPARATOR, NULL },
    154     { NULL,        GTK_STOCK_PROPERTIES,  0, ACTF_WHEREVER | ACTF_WHATEVER,
    155       N_("Show additional information about a torrent") },
    156     { N_("Open debug window"), GTK_STOCK_INFO,      0, ACTF_MENU     | ACTF_ALWAYS,
    157       NULL },
    158     { NULL,        GTK_STOCK_ABOUT,      0, ACTF_MENU | ACTF_ALWAYS,
    159       N_("About Transmission") },
    160     { NULL,        NULL,                  0, ACTF_SEPARATOR, NULL },
    161     { NULL,        GTK_STOCK_PREFERENCES, 0, ACTF_WHEREVER | ACTF_ALWAYS,
    162       N_("Customize application behavior") },
    163     { NULL,        NULL,                  0, ACTF_SEPARATOR, NULL },
    164     { NULL,        GTK_STOCK_CLOSE,       0, ACTF_MENU     | ACTF_ALWAYS,
    165       N_("Close the main window") },
    166     { NULL,        GTK_STOCK_QUIT,        0, ACTF_MENU     | ACTF_ALWAYS,
    167       N_("Exit the program") },
    168     /* this isn't a terminator for the list, it's ACT_ICON */
    169     { NULL,        NULL,                  0, 0, NULL },
    170 };
    171 
    172112#define CBDATA_PTR              "callback-data-pointer"
     113
     114static GtkUIManager * myUIManager = NULL;
    173115
    174116static sig_atomic_t global_sigcount = 0;
     
    179121sendremote( GList * files, gboolean sendquit );
    180122static void
    181 gtksetup( int * argc, char *** argv );
    182 static void
    183 appsetup( TrWindow * wind, benc_val_t * state, GList * args, gboolean paused );
     123gtksetup( int * argc, char *** argv, struct cbdata* );
     124static void
     125appsetup( TrWindow * wind, benc_val_t * state, GList * args,
     126          struct cbdata * , gboolean paused );
    184127static void
    185128winsetup( struct cbdata * cbdata, TrWindow * wind );
    186129static void
    187 iconclick( struct cbdata * cbdata );
    188 static void
    189130makeicon( struct cbdata * cbdata );
    190 static gboolean
    191 winclose( GtkWidget * widget, GdkEvent * event, gpointer gdata );
    192131static void
    193132wannaquit( void * vdata );
     
    217156static void
    218157boolwindclosed(GtkWidget *widget, gpointer gdata);
    219 static void
    220 windact(GtkWidget *widget, int action, gpointer gdata);
    221158static GList *
    222159getselection( struct cbdata * cbdata );
    223 static void
    224 handleaction( struct cbdata *data, int action );
    225160
    226161static void
     
    230165static void
    231166fatalsig(int sig);
     167
     168static void
     169accumulateStatusForeach (GtkTreeModel * model,
     170                         GtkTreePath  * path UNUSED,
     171                         GtkTreeIter  * iter,
     172                         gpointer       accumulated_status)
     173{
     174    int status = 0;
     175    gtk_tree_model_get( model, iter, MC_STAT, &status, -1 );
     176    *(int*)accumulated_status |= status;
     177}
     178
     179static void
     180refreshTorrentActions( GtkTreeSelection * s )
     181{
     182    int status = 0;
     183    gtk_tree_selection_selected_foreach( s, accumulateStatusForeach, &status );
     184    action_sensitize( "stop-torrent", (status & TR_STATUS_ACTIVE) != 0);
     185    action_sensitize( "start-torrent", (status & TR_STATUS_INACTIVE) != 0);
     186    action_sensitize( "remove-torrent", status != 0);
     187    action_sensitize( "show-torrent-inspector", status != 0);
     188}
     189
     190static void
     191selectionChangedCB( GtkTreeSelection * s, gpointer unused UNUSED )
     192{
     193    refreshTorrentActions( s );
     194}
    232195
    233196int
    234197main( int argc, char ** argv )
    235198{
    236     GtkWindow  * mainwind;
     199    struct cbdata * cbdata = g_new (struct cbdata, 1);
    237200    char       * err;
    238201    benc_val_t * state;
     
    250213    }
    251214    setupsighandlers();         /* set up handlers for fatal signals */
    252     gtksetup( &argc, &argv );   /* set up gtk and gettext */
     215    gtksetup( &argc, &argv, cbdata );   /* set up gtk and gettext */
    253216
    254217    if( ( didinit || cf_init( tr_getPrefsDirectory(), &err ) ) &&
    255218        ( didlock || cf_lock( &err ) ) )
    256219    {
     220        GtkWindow  * mainwind;
     221
    257222        /* create main window now to be a parent to any error dialogs */
    258         mainwind = GTK_WINDOW( tr_window_new() );
     223        mainwind = GTK_WINDOW( tr_window_new( myUIManager ) );
    259224
    260225        /* try to load prefs and saved state */
     
    273238
    274239        msgwin_loadpref();      /* set message level here before tr_init() */
    275         appsetup( TR_WINDOW( mainwind ), state, argfiles, startpaused );
     240        appsetup( mainwind, state, argfiles, cbdata, startpaused );
    276241        cf_freestate( state );
    277242    }
     
    379344
    380345static void
    381 gtksetup( int * argc, char *** argv )
    382 {
    383     GdkPixbuf * icon;
    384 
     346gtksetup( int * argc, char *** argv, struct cbdata * callback_data )
     347{
    385348    gtk_init( argc, argv );
    386349
     
    390353
    391354    g_set_application_name( _("Transmission") );
     355
     356    /* connect up the actions */
     357    myUIManager = gtk_ui_manager_new ();
     358    actions_init ( myUIManager, callback_data );
     359    gtk_ui_manager_add_ui_from_string (myUIManager, fallback_ui_file, -1, NULL);
     360    gtk_ui_manager_ensure_update (myUIManager);
    392361
    393362    /* tweak some style properties in dialogs to get closer to the GNOME HiG */
     
    401370        "widget \"TransmissionDialog\" style \"transmission-standard\"\n" );
    402371
    403     icon = gdk_pixbuf_new_from_inline( -1, tr_icon_full, FALSE, NULL );
    404     gtk_window_set_default_icon( icon );
    405     g_object_unref( icon );
    406 }
    407 
    408 static void
    409 appsetup( TrWindow * wind, benc_val_t * state, GList * args, gboolean paused )
    410 {
    411     struct cbdata        * cbdata;
     372    gtk_window_set_default_icon_name ( "ICON_TRANSMISSION" );
     373}
     374
     375static void
     376appsetup( TrWindow * wind, benc_val_t * state, GList * args,
     377          struct cbdata * cbdata, gboolean paused )
     378{
    412379    enum tr_torrent_action action;
    413380
    414381    /* fill out cbdata */
    415     cbdata = g_new0( struct cbdata, 1 );
    416382    cbdata->wind       = NULL;
    417383    cbdata->core       = tr_core_new();
     
    463429}
    464430
     431static gboolean
     432winclose( GtkWidget * widget UNUSED, GdkEvent * event UNUSED, gpointer gdata )
     433{
     434    struct cbdata * cbdata = (struct cbdata *) gdata;
     435
     436    if( cbdata->icon != NULL )
     437        gtk_widget_hide( GTK_WIDGET( cbdata->wind ) );
     438    else
     439        askquit( cbdata->wind, wannaquit, cbdata );
     440
     441    return TRUE; /* don't propagate event further */
     442}
     443
     444static void
     445rowChangedCB( GtkTreeModel  * model UNUSED,
     446              GtkTreePath   * path UNUSED,
     447              GtkTreeIter   * iter UNUSED,
     448              gpointer        sel)
     449{
     450    refreshTorrentActions( GTK_TREE_SELECTION(sel) );
     451}
     452
    465453static void
    466454winsetup( struct cbdata * cbdata, TrWindow * wind )
    467455{
    468     int ii;
    469     GtkWidget  * drag;
    470 
    471     g_assert( ACTION_COUNT == ALEN( actions ) );
     456    GtkTreeModel * model;
     457    GtkTreeSelection * sel;
     458
    472459    g_assert( NULL == cbdata->wind );
    473460    cbdata->wind = GTK_WINDOW( wind );
    474     for( ii = 0; ii < ALEN( actions ); ii++ )
    475     {
    476         tr_window_action_add( wind, ii, actions[ii].flags,
    477                               gettext( actions[ii].label ), actions[ii].icon,
    478                               gettext( actions[ii].tooltip ),
    479                               actions[ii].key );
    480     }
    481     g_object_set( wind, "model", tr_core_model( cbdata->core ),
    482                         "double-click-action", ACT_INFO, NULL);
    483 
    484     g_signal_connect( wind, "action",       G_CALLBACK( windact  ), cbdata );
     461
     462    sel = tr_window_get_selection( cbdata->wind );
     463    g_signal_connect( sel, "changed", G_CALLBACK(selectionChangedCB), NULL );
     464    selectionChangedCB( sel, NULL );
     465    model = tr_core_model( cbdata->core );
     466    gtk_tree_view_set_model ( gtk_tree_selection_get_tree_view(sel), model );
     467    g_signal_connect( model, "row-changed", G_CALLBACK(rowChangedCB), sel );
    485468    g_signal_connect( wind, "delete-event", G_CALLBACK( winclose ), cbdata );
    486469   
    487     g_object_get( wind, "drag-widget", &drag, NULL );
    488     setupdrag( drag, cbdata );
    489 }
    490 
    491 static void
    492 iconclick( struct cbdata * cbdata )
    493 {
    494     GtkWidget * win;
    495 
    496     if( NULL != cbdata->wind )
    497     {
    498         /* close window  */
    499         winclose( NULL, NULL, cbdata );
    500     }
    501     else
    502     {
    503         /* create window */
    504         win = tr_window_new();
    505         winsetup( cbdata, TR_WINDOW( win ) );
    506         tr_window_show( TR_WINDOW( win ) );
    507     }
     470    setupdrag( GTK_WIDGET(wind), cbdata );
    508471}
    509472
     
    511474makeicon( struct cbdata * cbdata )
    512475{
    513     TrIcon * icon;
    514     int      ii;
    515 
    516     if( NULL != cbdata->icon )
    517     {
    518         return;
    519     }
    520 
    521     icon = tr_icon_new();
    522     for( ii = 0; ii < ALEN( actions ); ii++ )
    523     {
    524         tr_icon_action_add( TR_ICON( icon ), ii, actions[ii].flags,
    525                               gettext( actions[ii].label ), actions[ii].icon );
    526     }
    527     g_object_set( icon, "activate-action", ACT_ICON, NULL);
    528     g_signal_connect( icon, "action", G_CALLBACK( windact ), cbdata );
    529 
    530     cbdata->icon = icon;
    531 }
    532 
    533 static gboolean
    534 winclose( GtkWidget * widget SHUTUP, GdkEvent * event SHUTUP, gpointer gdata )
    535 {
    536     struct cbdata * cbdata;
    537 
    538     cbdata = gdata;
    539 
    540     if( NULL != cbdata->icon && tr_icon_docked( cbdata->icon ) )
    541     {
    542         gtk_widget_destroy( GTK_WIDGET( cbdata->wind ) );
    543         cbdata->wind = NULL;
    544     }
    545     else
    546     {
    547         askquit( cbdata->wind, wannaquit, cbdata );
    548     }
    549 
    550     /* don't propagate event further */
    551     return TRUE;
     476    if( NULL == cbdata->icon )
     477        cbdata->icon = tr_icon_new( );
    552478}
    553479
     
    863789            else if( NULL != cbdata->icon )
    864790            {
     791g_message ("foo");
    865792                g_object_unref( cbdata->icon );
    866793                cbdata->icon = NULL;
     
    910837  {
    911838      tr_torrentRates( tr_core_handle( data->core ), &down, &up );
    912       tr_window_update( TR_WINDOW( data->wind ), down, up );
     839      tr_window_update( data->wind, down, up );
    913840  }
    914841
     
    926853}
    927854
    928 static void
    929 windact( GtkWidget * wind SHUTUP, int action, gpointer gdata )
    930 {
    931     g_assert( 0 <= action );
    932     handleaction( gdata, action );
    933 }
    934 
    935855/* returns a GList containing a GtkTreeRowReference to each selected row */
    936856static GList *
    937857getselection( struct cbdata * cbdata )
    938858{
    939     GtkTreeSelection    * sel;
    940     GList               * rows, * ii;
    941     GtkTreeRowReference * ref;
    942 
    943     if( NULL == cbdata->wind )
    944     {
    945         return NULL;
    946     }
    947     g_object_get( cbdata->wind, "selection", &sel, NULL );
    948     rows = gtk_tree_selection_get_selected_rows( sel, NULL );
    949     for( ii = rows; NULL != ii; ii = ii->next )
    950     {
    951         ref = gtk_tree_row_reference_new( tr_core_model( cbdata->core ), ii->data );
    952         gtk_tree_path_free( ii->data );
    953         ii->data = ref;
     859    GList * rows = NULL;
     860
     861    if( NULL != cbdata->wind )
     862    {
     863        GList * ii;
     864        GtkTreeSelection *s = tr_window_get_selection(cbdata->wind);
     865        GtkTreeModel * model = tr_core_model( cbdata->core );
     866        rows = gtk_tree_selection_get_selected_rows( s, NULL );
     867        for( ii = rows; NULL != ii; ii = ii->next )
     868        {
     869            GtkTreeRowReference * ref = gtk_tree_row_reference_new(
     870                model, ii->data );
     871            gtk_tree_path_free( ii->data );
     872            ii->data = ref;
     873        }
    954874    }
    955875
     
    984904
    985905static void
    986 handleaction( struct cbdata * data, int act )
    987 {
    988   GList *rows, *ii;
    989   GtkTreeModel * model;
    990   GtkTreePath *path;
    991   GtkTreeIter iter;
    992   TrTorrent *tor;
    993   int status;
    994   gboolean changed;
    995   GtkWidget * win;
    996 
    997   g_assert( ACTION_COUNT > act );
    998 
    999   switch( act )
    1000   {
    1001       case ACT_ABOUT:
    1002           about ();
    1003           return;
    1004       case ACT_OPEN:
    1005           makeaddwind( data->wind, data->core );
    1006           return;
    1007       case ACT_PREF:
    1008           if( NULL != data->prefs )
    1009           {
    1010               return;
    1011           }
    1012           data->prefs = tr_prefs_new_with_parent( G_OBJECT( data->core ),
    1013                                                   data->wind );
    1014           g_signal_connect( data->prefs, "destroy",
    1015                             G_CALLBACK( gtk_widget_destroyed ), &data->prefs );
    1016           gtk_widget_show( GTK_WIDGET( data->prefs ) );
    1017           return;
    1018       case ACT_DEBUG:
    1019           if( !data->msgwinopen )
    1020           {
    1021               data->msgwinopen = TRUE;
    1022               win = msgwin_create();
    1023               g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ),
     906startTorrentForeach (GtkTreeModel * model,
     907                     GtkTreePath  * path UNUSED,
     908                     GtkTreeIter  * iter,
     909                     gpointer       data UNUSED)
     910{
     911    TrTorrent * tor = NULL;
     912    gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
     913    tr_torrent_start( tor );
     914}
     915
     916static void
     917stopTorrentForeach (GtkTreeModel * model,
     918                    GtkTreePath  * path UNUSED,
     919                    GtkTreeIter  * iter,
     920                    gpointer       data UNUSED)
     921{
     922    TrTorrent * tor = NULL;
     923    gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
     924    tr_torrent_stop( tor );
     925}
     926
     927static void
     928showInfoForeach (GtkTreeModel * model,
     929                 GtkTreePath  * path UNUSED,
     930                 GtkTreeIter  * iter,
     931                 gpointer       data UNUSED)
     932{
     933    TrTorrent * tor = NULL;
     934    GtkWidget * w;
     935    gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
     936    w = torrent_inspector_new( GTK_WINDOW(data), tor );
     937    gtk_widget_show( w );
     938}
     939
     940void
     941doAction ( const char * action_name, gpointer user_data )
     942{
     943    struct cbdata * data = (struct cbdata *) user_data;
     944    gboolean changed = FALSE;
     945
     946    if (!strcmp (action_name, "add-torrent"))
     947    {
     948        makeaddwind( data->wind, data->core );
     949    }
     950    else if (!strcmp (action_name, "start-torrent"))
     951    {
     952        GtkTreeSelection * s = tr_window_get_selection(data->wind);
     953        gtk_tree_selection_selected_foreach( s, startTorrentForeach, NULL );
     954        changed |= gtk_tree_selection_count_selected_rows( s ) != 0;
     955    }
     956    else if (!strcmp (action_name, "stop-torrent"))
     957    {
     958        GtkTreeSelection * s = tr_window_get_selection(data->wind);
     959        gtk_tree_selection_selected_foreach( s, stopTorrentForeach, NULL );
     960        changed |= gtk_tree_selection_count_selected_rows( s ) != 0;
     961    }
     962    else if (!strcmp (action_name, "show-torrent-inspector"))
     963    {
     964        GtkTreeSelection * s = tr_window_get_selection(data->wind);
     965        gtk_tree_selection_selected_foreach( s, showInfoForeach, data->wind );
     966    }
     967    else if (!strcmp (action_name, "remove-torrent"))
     968    {
     969        /* this modifies the model's contents, so can't use foreach */
     970        GList *l, *sel = getselection( data );
     971        GtkTreeModel *model = tr_core_model( data->core );
     972        for( l=sel; l!=NULL; l=l->next )
     973        {
     974            GtkTreeIter iter;
     975            GtkTreeRowReference * reference = (GtkTreeRowReference *) l->data;
     976            GtkTreePath * path = gtk_tree_row_reference_get_path( reference );
     977            gtk_tree_model_get_iter( model, &iter, path );
     978            tr_core_delete_torrent( data->core, &iter );
     979            gtk_tree_row_reference_free( reference );
     980            changed = TRUE;
     981        }
     982        g_list_free( sel );
     983    }
     984    else if (!strcmp (action_name, "close"))
     985    {
     986        if( data->wind != NULL )
     987            winclose( NULL, NULL, data );
     988    }
     989    else if (!strcmp (action_name, "quit"))
     990    {
     991        askquit( data->wind, wannaquit, data );
     992    }
     993    else if (!strcmp (action_name, "edit-preferences"))
     994    {
     995        if( NULL == data->prefs )
     996        {
     997            data->prefs = tr_prefs_new_with_parent( G_OBJECT( data->core ),
     998                                                    data->wind );
     999            g_signal_connect( data->prefs, "destroy",
     1000                             G_CALLBACK( gtk_widget_destroyed ), &data->prefs );
     1001            gtk_widget_show( GTK_WIDGET( data->prefs ) );
     1002        }
     1003    }
     1004    else if (!strcmp (action_name, "show-debug-window"))
     1005    {
     1006        if( !data->msgwinopen )
     1007        {
     1008            GtkWidget * win = msgwin_create();
     1009            g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ),
    10241010                                &data->msgwinopen );
    1025           }
    1026           return;
    1027       case ACT_ICON:
    1028           iconclick( data );
    1029           return;
    1030       case ACT_CLOSE:
    1031           if( NULL != data->wind )
    1032           {
    1033               winclose( NULL, NULL, data );
    1034           }
    1035           return;
    1036       case ACT_QUIT:
    1037           askquit( data->wind, wannaquit, data );
    1038           return;
    1039       case ACT_SEPARATOR1:
    1040       case ACT_SEPARATOR2:
    1041       case ACT_SEPARATOR3:
    1042           return;
    1043       case ACT_START:
    1044       case ACT_STOP:
    1045       case ACT_DELETE:
    1046       case ACT_INFO:
    1047       case ACTION_COUNT:
    1048           break;
    1049   }
    1050 
    1051   /* get a list of references to selected rows */
    1052   rows = getselection( data );
    1053 
    1054   model = tr_core_model( data->core );
    1055   changed = FALSE;
    1056   for(ii = rows; NULL != ii; ii = ii->next) {
    1057     if(NULL != (path = gtk_tree_row_reference_get_path(ii->data)) &&
    1058        gtk_tree_model_get_iter( model, &iter, path ) )
    1059     {
    1060       gtk_tree_model_get( model , &iter, MC_TORRENT, &tor,
    1061                           MC_STAT, &status, -1 );
    1062       if( ACT_ISAVAIL( actions[act].flags, status ) )
    1063 
    1064       {
    1065           switch( act )
    1066           {
    1067               case ACT_START:
    1068                   tr_torrent_start( tor );
    1069                   changed = TRUE;
    1070                   break;
    1071               case ACT_STOP:
    1072                   tr_torrent_stop( tor );
    1073                   changed = TRUE;
    1074                   break;
    1075               case ACT_DELETE:
    1076                   tr_core_delete_torrent( data->core, &iter );
    1077                   changed = TRUE;
    1078                   break;
    1079               case ACT_INFO:
    1080                   gtk_widget_show (torrent_inspector_new (data->wind, tor));
    1081                   break;
    1082               case ACT_OPEN:
    1083               case ACT_PREF:
    1084               case ACT_DEBUG:
    1085               case ACT_ICON:
    1086               case ACT_CLOSE:
    1087               case ACT_QUIT:
    1088               case ACT_SEPARATOR1:
    1089               case ACT_SEPARATOR2:
    1090               case ACT_SEPARATOR3:
    1091               case ACTION_COUNT:
    1092                   break;
    1093           }
    1094       }
    1095       g_object_unref(tor);
    1096     }
    1097     if(NULL != path)
    1098       gtk_tree_path_free(path);
    1099     gtk_tree_row_reference_free(ii->data);
    1100   }
    1101   g_list_free(rows);
    1102 
    1103   if(changed) {
    1104     updatemodel(data);
    1105     tr_core_save( data->core );
    1106   }
    1107 }
     1011            data->msgwinopen = TRUE;
     1012        }
     1013    }
     1014    else if (!strcmp (action_name, "show-about-dialog"))
     1015    {
     1016        about ();
     1017    }
     1018    else if (!strcmp (action_name, "toggle-main-window"))
     1019    {
     1020        GtkWidget * w = GTK_WIDGET (data->wind);
     1021        if (GTK_WIDGET_VISIBLE(w))
     1022            gtk_widget_hide (w);
     1023        else
     1024            gtk_window_present (GTK_WINDOW(w));
     1025    }
     1026    else g_error ("Unhandled action: %s", action_name );
     1027
     1028    if(changed)
     1029    {
     1030        updatemodel( data );
     1031        tr_core_save( data->core );
     1032    }
     1033}
     1034
    11081035
    11091036static void
  • branches/file_selection/gtk/torrent-inspector.c

    r2005 r2054  
    2727#include <glib/gi18n.h>
    2828#include <gtk/gtk.h>
     29
    2930#include "transmission.h"
    3031#include "platform.h" /* for tr_getTorrentsDirectory */
     32
     33#include "actions.h"
    3134#include "tr_torrent.h"
    3235#include "dot-icons.h"
     
    950953  GtkTreeModel * model; /* same object as store, but recast */
    951954  GtkTreeStore * store; /* same object as model, but recast */
     955  GtkTreeSelection * selection;
    952956}
    953957FileData;
     
    965969}
    966970
    967 static int8_t
     971static tr_priority_t
    968972stringToPriority( const char* str )
    969973{
     
    11451149
    11461150static void
    1147 set_priority (GtkTreeStore * store, GtkTreeIter * parent, tr_torrent_t * tor, int priority, const char * str)
     1151refreshPriorityActions( GtkTreeSelection * sel )
     1152{
     1153    GtkTreeIter iter;
     1154    GtkTreeModel * model;
     1155    const gboolean has_selection = gtk_tree_selection_get_selected( sel, &model, &iter );
     1156
     1157    action_sensitize ( "priority-high", has_selection );
     1158    action_sensitize ( "priority-normal", has_selection );
     1159    action_sensitize ( "priority-low", has_selection );
     1160    action_sensitize ( "priority-dnd", has_selection );
     1161
     1162    if( has_selection )
     1163    {
     1164        /* set the action priority base on the model's values */
     1165        char * pch = NULL;
     1166        const char * key;
     1167        gtk_tree_model_get( model, &iter, FC_PRIORITY, &pch, -1 );
     1168        switch( stringToPriority( pch ) ) {
     1169            case TR_PRI_HIGH:   key = "priority-high";   break;
     1170            case TR_PRI_LOW:    key = "priority-low";    break;
     1171            case TR_PRI_DND:    key = "priority-dnd";    break;
     1172            default:            key = "priority-normal"; break;
     1173        }
     1174        action_toggle( key, TRUE );
     1175        g_free( pch );
     1176    }
     1177}
     1178
     1179static void
     1180set_priority (GtkTreeSelection * selection,
     1181              GtkTreeStore * store,
     1182              GtkTreeIter * iter,
     1183              tr_torrent_t * tor,
     1184              int priority_val,
     1185              const char * priority_str)
    11481186{
    11491187    int index;
    1150     GtkTreeIter iter;
    1151 
    1152     gtk_tree_model_get( GTK_TREE_MODEL(store), parent, FC_INDEX, &index, -1  );
     1188    GtkTreeIter child;
     1189
     1190    gtk_tree_model_get( GTK_TREE_MODEL(store), iter, FC_INDEX, &index, -1  );
    11531191    if (index >= 0)
    1154       tr_torrentSetFilePriority( tor, index, priority );
    1155     gtk_tree_store_set( store, parent, FC_PRIORITY, str, -1 );
    1156 
    1157     if( gtk_tree_model_iter_children( GTK_TREE_MODEL(store), &iter, parent ) ) do
    1158       set_priority (store, &iter, tor, priority, str );
    1159     while( gtk_tree_model_iter_next( GTK_TREE_MODEL(store), &iter ) );
     1192      tr_torrentSetFilePriority( tor, index, priority_val );
     1193    gtk_tree_store_set( store, iter, FC_PRIORITY, priority_str, -1 );
     1194
     1195    if( gtk_tree_model_iter_children( GTK_TREE_MODEL(store), &child, iter ) ) do
     1196      set_priority( selection, store, &child, tor, priority_val, priority_str );
     1197    while( gtk_tree_model_iter_next( GTK_TREE_MODEL(store), &child ) );
     1198
     1199    refreshPriorityActions( selection );
    11601200}
    11611201
     
    11711211  {
    11721212    tr_torrent_t  * tor = tr_torrent_handle( d->gtor );
    1173     const int8_t priority = stringToPriority( value );
    1174     set_priority( d->store, &iter, tor, priority, value );
     1213    const tr_priority_t priority = stringToPriority( value );
     1214    set_priority( d->selection, d->store, &iter, tor, priority, value );
    11751215  }
     1216}
     1217
     1218/* FIXME: NULL this back out when popup goes down */
     1219static GtkWidget * popupView = NULL;
     1220
     1221static void
     1222on_popup_menu ( GtkWidget * view, GdkEventButton * event )
     1223{
     1224    GtkWidget * menu = action_get_widget ( "/file-popup" );
     1225    popupView = view;
     1226    gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
     1227                    (event ? event->button : 0),
     1228                    (event ? event->time : 0));
     1229}
     1230
     1231static void
     1232fileSelectionChangedCB( GtkTreeSelection * sel, gpointer unused UNUSED )
     1233{
     1234    refreshPriorityActions( sel );
     1235}
     1236
     1237void
     1238set_selected_file_priority ( tr_priority_t priority_val )
     1239{
     1240    if( popupView && GTK_IS_TREE_VIEW(popupView) )
     1241    {
     1242        GtkTreeView * view = GTK_TREE_VIEW( popupView );
     1243        tr_torrent_t * tor = (tr_torrent_t*)
     1244            g_object_get_data (G_OBJECT(view), "torrent-handle");
     1245        const char * priority_str = priorityToString( priority_val );
     1246        GtkTreeModel * model;
     1247        GtkTreeIter iter;
     1248        GtkTreeSelection * sel = gtk_tree_view_get_selection (view);
     1249        gtk_tree_selection_get_selected( sel, &model, &iter );
     1250
     1251        set_priority( sel, GTK_TREE_STORE(model), &iter,
     1252                      tor, priority_val, priority_str );
     1253    }
    11761254}
    11771255
     
    11821260    FileData            * data;
    11831261    tr_info_t           * inf;
    1184     const tr_torrent_t  * tor;
     1262    tr_torrent_t        * tor;
    11851263    GtkTreeStore        * store;
    11861264    int                   ii;
     
    12141292    /* create the view */
    12151293    view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) );
     1294    g_object_set_data (G_OBJECT(view), "torrent-handle", tor );
     1295    g_signal_connect( view, "popup-menu",
     1296                      G_CALLBACK(on_popup_menu), NULL );
     1297    g_signal_connect( view, "button-press-event",
     1298                      G_CALLBACK(on_tree_view_button_pressed), on_popup_menu);
     1299
    12161300    /* add file column */
    12171301   
     
    12391323    gtk_tree_view_expand_all( GTK_TREE_VIEW( view ) );
    12401324    gtk_tree_view_set_search_column( GTK_TREE_VIEW( view ), FC_LABEL );
     1325    g_signal_connect( sel, "changed", G_CALLBACK(fileSelectionChangedCB), NULL );
     1326    fileSelectionChangedCB( sel, NULL );
     1327
    12411328
    12421329    /* add priority column */
     
    12701357    data->model = GTK_TREE_MODEL(store);
    12711358    data->store = store;
     1359    data->selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
    12721360    g_object_set_data_full (G_OBJECT(ret), "file-data", data, g_free);
    12731361    g_signal_connect (G_OBJECT(rend), "edited", G_CALLBACK(priority_changed_cb), data);
     
    13761464  hig_workarea_add_section_spacer (t, row, 1);
    13771465
    1378     tb = gtk_check_button_new_with_mnemonic (_("Stop Seeding at Ratio:"));
     1466    tb = gtk_check_button_new_with_mnemonic (_("_Stop Seeding at Ratio:"));
    13791467    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(tb), gtor->seeding_cap_enabled);
    13801468    g_signal_connect (tb, "toggled", G_CALLBACK(seeding_cap_toggled_cb), gtor);
  • branches/file_selection/gtk/torrent-inspector.h

    r1998 r2054  
    2929#include "tr_torrent.h"
    3030
     31struct TrTorrent;
     32
    3133GtkWidget* torrent_inspector_new ( GtkWindow * parent, TrTorrent * tor );
    3234
     35void set_selected_file_priority ( tr_priority_t );
     36
    3337#endif /* TG_PREFS_H */
  • branches/file_selection/gtk/tr_core.c

    r1998 r2054  
    265265
    266266    /* sever all remaining torrents in the model */
    267     if( gtk_tree_model_get_iter_first( self->model, &iter ) )
    268     {
    269         do
    270         {
    271             gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
    272             tr_torrent_sever( tor );
    273             g_object_unref( tor );
    274         }
    275         while( gtk_tree_model_iter_next( self->model, &iter ) );
    276     }
     267    if( gtk_tree_model_get_iter_first( self->model, &iter ) ) do
     268    {
     269        gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
     270        tr_torrent_sever( tor );
     271        g_object_unref( tor );
     272    }
     273    while( gtk_tree_model_iter_next( self->model, &iter ) );
    277274    g_object_unref( self->model );
    278275
     
    309306tr_core_model( TrCore * self )
    310307{
    311     TR_IS_CORE( self );
    312 
    313     if( self->disposed )
    314     {
    315         return NULL;
    316     }
    317 
    318     return self->model;
     308    g_return_val_if_fail (TR_IS_CORE(self), NULL);
     309
     310    return self->disposed ? NULL : self->model;
    319311}
    320312
     
    322314tr_core_handle( TrCore * self )
    323315{
    324     TR_IS_CORE( self );
    325 
    326     if( self->disposed )
    327     {
    328         return NULL;
    329     }
    330 
    331     return self->handle;
     316    g_return_val_if_fail (TR_IS_CORE(self), NULL);
     317
     318    return self->disposed ? NULL : self->handle;
    332319}
    333320
  • branches/file_selection/gtk/tr_icon.c

    r1673 r2054  
    2424
    2525#include <gtk/gtk.h>
    26 #include <glib/gi18n.h>
    27 
     26#include "actions.h"
    2827#include "tr_icon.h"
    2928#include "util.h"
    3029
    31 #define ITEM_ACTION             "tr-icon-item-action"
     30#ifndef STATUS_ICON_SUPPORTED
    3231
    33 enum
     32gpointer
     33tr_icon_new( void )
    3434{
    35     PROP_ICON = 1,
    36     PROP_DOCKED,
    37     PROP_CLICK,
    38 };
     35    return NULL;
     36}
     37
     38#else
    3939
    4040static void
    41 tr_icon_init( GTypeInstance * instance, gpointer g_class );
    42 static void
    43 tr_icon_set_property( GObject * object, guint property_id,
    44                       const GValue * value, GParamSpec * pspec );
    45 static void
    46 tr_icon_get_property( GObject * object, guint property_id,
    47                       GValue * value, GParamSpec * pspec);
    48 static void
    49 tr_icon_class_init( gpointer g_class, gpointer g_class_data );
    50 static void
    51 tr_icon_dispose( GObject * obj );
    52 static void
    53 itemclick( GObject * obj, gpointer data );
    54 static void
    55 emitaction( TrIcon * self, int id );
    56 #ifdef TR_ICON_SUPPORTED
    57 static void
    58 clicked( TrIcon * self, gpointer data );
    59 static void
    60 popup( TrIcon * self, guint button, guint when, gpointer data );
    61 #endif
    62 
    63 GType
    64 tr_icon_get_type( void )
     41activated ( GtkStatusIcon   * self        UNUSED,
     42            gpointer          user_data   UNUSED )
    6543{
    66     static GType type = 0;
    67 
    68     if( 0 == type )
    69     {
    70         static const GTypeInfo info =
    71         {
    72             sizeof( TrIconClass ),
    73             NULL,                       /* base_init */
    74             NULL,                       /* base_finalize */
    75             tr_icon_class_init,         /* class_init */
    76             NULL,                       /* class_finalize */
    77             NULL,                       /* class_data */
    78             sizeof( TrIcon ),
    79             0,                          /* n_preallocs */
    80             tr_icon_init,               /* instance_init */
    81             NULL,
    82         };
    83 #ifdef TR_ICON_SUPPORTED
    84         type = GTK_TYPE_STATUS_ICON;
    85 #else
    86         type = G_TYPE_OBJECT;
    87 #endif
    88         type = g_type_register_static( type, "TrIcon", &info, 0 );
    89     }
    90 
    91     return type;
     44    action_activate ("toggle-main-window");
    9245}
    9346
    9447static void
    95 tr_icon_class_init( gpointer g_class, gpointer g_class_data SHUTUP )
     48popup ( GtkStatusIcon  * self,
     49        guint            button,
     50        guint            when,
     51        gpointer         data    UNUSED )
    9652{
    97     GObjectClass * gobject_class;
    98     TrIconClass  * tricon_class;
    99     GParamSpec   * pspec;
    100 
    101     gobject_class = G_OBJECT_CLASS( g_class );
    102     gobject_class->set_property = tr_icon_set_property;
    103     gobject_class->get_property = tr_icon_get_property;
    104     gobject_class->dispose      = tr_icon_dispose;
    105 
    106     pspec = g_param_spec_boolean( "icon", "Icon",
    107                                   "Icon has been set from default window icon.",
    108                                   TRUE, G_PARAM_CONSTRUCT|G_PARAM_READWRITE );
    109     g_object_class_install_property( gobject_class, PROP_ICON, pspec );
    110 
    111     pspec = g_param_spec_boolean( "docked", "Docked",
    112                                  "Icon is docked in a system tray.",
    113                                   FALSE, G_PARAM_READABLE );
    114     g_object_class_install_property( gobject_class, PROP_DOCKED, pspec );
    115 
    116     pspec = g_param_spec_int( "activate-action", "Activate action",
    117                               "The action id to signal when icon is activated.",
    118                               G_MININT, G_MAXINT, -1, G_PARAM_READWRITE );
    119     g_object_class_install_property( gobject_class, PROP_CLICK, pspec );
    120 
    121     tricon_class = TR_ICON_CLASS( g_class );
    122     tricon_class->actionsig =
    123         g_signal_new( "action", G_TYPE_FROM_CLASS( g_class ),
    124                        G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    125                        g_cclosure_marshal_VOID__INT,
    126                        G_TYPE_NONE, 1, G_TYPE_INT );
     53    GtkWidget * w = action_get_widget( "/icon-popup" );
     54    gtk_menu_popup (GTK_MENU(w), NULL, NULL,
     55                    gtk_status_icon_position_menu,
     56                    self, button, when );
    12757}
    12858
    129 static void
    130 tr_icon_init( GTypeInstance * instance, gpointer g_class SHUTUP )
    131 {
    132     TrIcon * self = ( TrIcon * )instance;
    133 
    134     self->clickact  = -1;
    135     self->menu      = NULL;
    136     self->actions   = NULL;
    137     self->disposed  = FALSE;
    138 
    139 #ifdef TR_ICON_SUPPORTED
    140     self->menu = gtk_menu_new();
    141     gtk_widget_show( self->menu );
    142     g_signal_connect( self, "activate", G_CALLBACK( clicked ), NULL );
    143     g_signal_connect( self, "popup-menu", G_CALLBACK( popup ), NULL );
    144 #endif
    145 }
    146 
    147 static void
    148 tr_icon_set_property( GObject * object, guint property_id,
    149                       const GValue * value, GParamSpec * pspec)
    150 {
    151     TrIcon * self = ( TrIcon * )object;
    152 
    153     if( self->disposed )
    154     {
    155         return;
    156     }
    157 
    158     switch( property_id )
    159     {
    160         case PROP_ICON:
    161 #ifdef TR_ICON_SUPPORTED
    162             if( g_value_get_boolean( value ) )
    163             {
    164                 GList  * icons = gtk_window_get_default_icon_list();
    165                 if( NULL != icons && NULL != icons->data )
    166                 {
    167                     gtk_status_icon_set_from_pixbuf( GTK_STATUS_ICON( self ),
    168                                                      icons->data );
    169                 }
    170                 g_list_free( icons );
    171             }
    172             else
    173             {
    174                 gtk_status_icon_set_from_pixbuf( GTK_STATUS_ICON( self ),
    175                                                  NULL );
    176             }
    177 #endif
    178             break;
    179         case PROP_CLICK:
    180             self->clickact = g_value_get_int( value );
    181             break;
    182         case PROP_DOCKED:
    183         default:
    184             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
    185             break;
    186     }
    187 }
    188 
    189 static void
    190 tr_icon_get_property( GObject * object, guint property_id,
    191                       GValue * value, GParamSpec * pspec )
    192 {
    193     TrIcon * self = ( TrIcon * )object;
    194 #ifdef TR_ICON_SUPPORTED
    195     GtkStatusIcon * icon;
    196 #endif
    197 
    198     if( self->disposed )
    199     {
    200         return;
    201     }
    202 
    203     switch( property_id )
    204     {
    205         case PROP_ICON:
    206 #ifdef TR_ICON_SUPPORTED
    207             icon = GTK_STATUS_ICON( self );
    208             if( GTK_IMAGE_PIXBUF == gtk_status_icon_get_storage_type( icon ) &&
    209                 NULL != gtk_status_icon_get_pixbuf( icon ) )
    210             {
    211                 g_value_set_boolean( value, TRUE );
    212             }
    213             else
    214 #endif
    215             {
    216                 g_value_set_boolean( value, FALSE );
    217             }
    218             break;
    219         case PROP_DOCKED:
    220 #ifdef TR_ICON_SUPPORTED
    221             if( gtk_status_icon_is_embedded( GTK_STATUS_ICON( self ) ) )
    222             {
    223                 g_value_set_boolean( value, TRUE );
    224             }
    225             else
    226 #endif
    227             {
    228                 g_value_set_boolean( value, FALSE );
    229             }
    230             break;
    231         case PROP_CLICK:
    232             g_value_set_int( value, self->clickact );
    233             break;
    234         default:
    235             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
    236             break;
    237     }
    238 }
    239 
    240 static void
    241 tr_icon_dispose( GObject * obj )
    242 {
    243     TrIcon       * self = ( TrIcon * )obj;
    244     GObjectClass * parent;
    245 
    246     if( self->disposed )
    247     {
    248         return;
    249     }
    250     self->disposed = TRUE;
    251 
    252     g_list_foreach( self->actions, ( GFunc )action_free, NULL );
    253     g_list_free( self->actions );
    254 
    255     /* Chain up to the parent class */
    256     parent = g_type_class_peek( g_type_parent( TR_ICON_TYPE ) );
    257     parent->dispose( obj );
    258 }
    259 
    260 TrIcon *
     59gpointer
    26160tr_icon_new( void )
    26261{
    263     return g_object_new( TR_ICON_TYPE, NULL );
    264 }
    265 
    266 gboolean
    267 tr_icon_docked( TrIcon * self )
    268 {
    269     gboolean ret;
    270 
    271     g_object_get( self, "docked", &ret, NULL );
    272 
     62    GtkStatusIcon * ret = gtk_status_icon_new_from_stock ("ICON_TRANSMISSION");
     63    g_signal_connect( ret, "activate", G_CALLBACK( activated ), NULL );
     64    g_signal_connect( ret, "popup-menu", G_CALLBACK( popup ), NULL );
    27365    return ret;
    27466}
    27567
    276 void
    277 tr_icon_action_add( TrIcon * self, int id, int flags, const char * name,
    278                     const char * icon )
    279 {
    280     struct action * act;
    281     GtkWidget     * item;
    282 
    283     TR_IS_ICON( self );
    284     if( self->disposed )
    285     {
    286         return;
    287     }
    288 
    289     act = action_new( id, flags, name, icon );
    290 
    291     if( NULL != self->menu )
    292     {
    293         if( ACTF_MENU & flags && ACTF_ALWAYS & flags )
    294         {
    295             item = action_makemenu( act, ITEM_ACTION, NULL, NULL, 0,
    296                                     G_CALLBACK( itemclick ), self );
    297             gtk_menu_shell_append( GTK_MENU_SHELL( self->menu ), item );
    298             act->menu = item;
    299         }
    300         else if( ACTF_SEPARATOR & flags )
    301         {
    302             item = gtk_separator_menu_item_new();
    303             gtk_widget_show( item );
    304             gtk_menu_shell_append( GTK_MENU_SHELL( self->menu ), item );
    305         }
    306     }
    307 
    308     self->actions = g_list_append( self->actions, act );
    309 }
    310 
    311 static void
    312 itemclick( GObject * obj, gpointer data )
    313 {
    314     TrIcon        * self;
    315     struct action * act;
    316 
    317     TR_IS_ICON( data );
    318     self = TR_ICON( data );
    319     act = g_object_get_data( obj, ITEM_ACTION );
    320 
    321     emitaction( self, act->id );
    322 }
    323 
    324 static void
    325 emitaction( TrIcon * self, int id )
    326 {
    327     TrIconClass * class;
    328 
    329     class = g_type_class_peek( TR_ICON_TYPE );
    330     g_signal_emit( self, class->actionsig, 0, id );
    331 }
    332 
    333 #ifdef TR_ICON_SUPPORTED
    334 
    335 static void
    336 clicked( TrIcon * self, gpointer data SHUTUP )
    337 {
    338     TR_IS_ICON( self );
    339 
    340     if( self->disposed || 0 > self->clickact )
    341     {
    342         return;
    343     }
    344 
    345     emitaction( self, self->clickact );
    346 }
    347 
    348 static void
    349 popup( TrIcon * self, guint button, guint when, gpointer data SHUTUP )
    350 {
    351     TR_IS_ICON( self );
    352 
    353     if( self->disposed )
    354     {
    355         return;
    356     }
    357 
    358     gtk_menu_popup( GTK_MENU( self->menu ), NULL, NULL,
    359                     gtk_status_icon_position_menu, self, button, when );
    360 }
    361 
    362 #endif /* TR_ICON_SUPPORTED */
     68#endif
  • branches/file_selection/gtk/tr_icon.h

    r1515 r2054  
    2828#include <gtk/gtk.h>
    2929
    30 #if GTK_MAJOR_VERSION > 2 || \
    31     ( GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 10 )
    32 #define TR_ICON_SUPPORTED
    33 #define tr_icon_supported()     (TRUE)
     30#if GTK_CHECK_VERSION(2,10,0)
     31#define STATUS_ICON_SUPPORTED
     32#define status_icon_supported() (TRUE)
    3433#else
    35 #define tr_icon_supported()    (FALSE)
     34#define status_icon_supported() (FALSE)
    3635#endif
    3736
    38 #define TR_ICON_TYPE              ( tr_icon_get_type() )
    39 
    40 #define TR_ICON( obj ) \
    41   ( G_TYPE_CHECK_INSTANCE_CAST( (obj),   TR_ICON_TYPE, TrIcon ) )
    42 
    43 #define TR_ICON_CLASS( class ) \
    44   ( G_TYPE_CHECK_CLASS_CAST(    (class), TR_ICON_TYPE, TrIconClass ) )
    45 
    46 #define TR_IS_ICON( obj ) \
    47   ( G_TYPE_CHECK_INSTANCE_TYPE( (obj),   TR_ICON_TYPE ) )
    48 
    49 #define TR_IS_ICON_CLASS( class ) \
    50   ( G_TYPE_CHECK_CLASS_TYPE(    (class), TR_ICON_TYPE ) )
    51 
    52 #define TR_ICON_GET_CLASS( obj ) \
    53   ( G_TYPE_INSTANCE_GET_CLASS(  (obj),   TR_ICON_TYPE, TrIconClass ) )
    54 
    55 typedef struct _TrIcon TrIcon;
    56 typedef struct _TrIconClass TrIconClass;
    57 
    58 /* treat the contents of this structure as private */
    59 struct _TrIcon
    60 {
    61 #ifdef TR_ICON_SUPPORTED
    62     GtkStatusIcon parent;
    63 #else
    64     GObject       parent;
    65 #endif
    66     GtkWidget   * menu;
    67     GList       * actions;
    68     int           clickact;
    69     gboolean      disposed;
    70 };
    71 
    72 struct _TrIconClass
    73 {
    74 #ifdef TR_ICON_SUPPORTED
    75     GtkStatusIconClass parent;
    76 #else
    77     GObjectClass       parent;
    78 #endif
    79     int                actionsig;
    80 };
    81 
    82 GType
    83 tr_icon_get_type( void );
    84 
    85 TrIcon *
    86 tr_icon_new( void );
    87 
    88 gboolean
    89 tr_icon_docked( TrIcon * icon );
    90 
    91 void
    92 tr_icon_action_add( TrIcon * icon, int id, int flags, const char * label,
    93                     const char * stock );
     37gpointer tr_icon_new( void );
    9438
    9539#endif
  • branches/file_selection/gtk/tr_prefs.c

    r2048 r2054  
    128128    /* PREF_ID_ICON */
    129129    { "use-tray-icon",          G_TYPE_BOOLEAN,
    130       ( tr_icon_supported() ? PR_ENABLED : PR_DISABLED ),    NULL,
     130      ( status_icon_supported() ? PR_ENABLED : PR_DISABLED ),    NULL,
    131131      N_("Display an _icon in the system tray"),
    132132      N_("Use a system tray / dock / notification area icon") },
  • branches/file_selection/gtk/tr_window.c

    r1998 r2054  
    3030#include "transmission.h"
    3131
     32#include "actions.h"
     33#include "hig.h"
    3234#include "tr_cell_renderer_progress.h"
    3335#include "tr_core.h"
     
    3638#include "util.h"
    3739
    38 #define ITEM_ACTION             "tr-window-item-action"
    39 
    40 enum
    41 {
    42     PROP_MODEL = 1,
    43     PROP_SELECTION,
    44     PROP_DOUBLECLICK,
    45     PROP_DRAG,
    46 };
    47 
    48 static void
    49 tr_window_init( GTypeInstance * instance, gpointer g_class );
    50 static void
    51 tr_window_set_property( GObject * object, guint property_id,
    52                         const GValue * value, GParamSpec * pspec );
    53 static void
    54 tr_window_get_property( GObject * object, guint property_id,
    55                         GValue * value, GParamSpec * pspec);
    56 static void
    57 tr_window_class_init( gpointer g_class, gpointer g_class_data );
    58 static void
    59 tr_window_dispose( GObject * obj );
    60 static GtkTreeView *
    61 makeview( TrWindow * self );
    62 static void
    63 stylekludge( GObject * obj, GParamSpec * spec, gpointer data );
    64 static void
    65 fixbuttons( GtkTreeSelection *sel, TrWindow * self );
    66 static void
    67 formatname( GtkTreeViewColumn * col, GtkCellRenderer * rend,
    68             GtkTreeModel * model, GtkTreeIter * iter, gpointer data );
    69 static void
    70 formatprog( GtkTreeViewColumn * col, GtkCellRenderer * rend,
    71             GtkTreeModel * model, GtkTreeIter * iter, gpointer data );
    72 static gboolean
    73 listclick( GtkWidget * view, GdkEventButton * event, gpointer data );
    74 static gboolean
    75 listpopup( GtkWidget * view SHUTUP, gpointer data );
    76 static void
    77 popupmenu( TrWindow * self, GdkEventButton * event );
    78 static void
    79 itemclick( GObject * obj, gpointer data );
    80 static void
    81 doubleclick( GtkWidget * view, GtkTreePath * path,
    82              GtkTreeViewColumn * col SHUTUP, gpointer data );
    83 static void
    84 emitaction( TrWindow * self, int id );
    85 static void
    86 orstatus( GtkTreeModel * model, GtkTreePath * path SHUTUP, GtkTreeIter * iter,
    87           gpointer data );
    88 static void
    89 istorsel( GtkTreeModel * model, GtkTreePath * path SHUTUP, GtkTreeIter * iter,
    90           gpointer data );
    91 
    92 GType
    93 tr_window_get_type( void )
    94 {
    95     static GType type = 0;
    96 
    97     if( 0 == type )
    98     {
    99         static const GTypeInfo info =
    100         {
    101             sizeof( TrWindowClass ),
    102             NULL,                       /* base_init */
    103             NULL,                       /* base_finalize */
    104             tr_window_class_init,       /* class_init */
    105             NULL,                       /* class_finalize */
    106             NULL,                       /* class_data */
    107             sizeof( TrWindow ),
    108             0,                          /* n_preallocs */
    109             tr_window_init,             /* instance_init */
    110             NULL,
    111         };
    112         type = g_type_register_static( GTK_TYPE_WINDOW, "TrWindow", &info, 0 );
    113     }
    114 
    115     return type;
    116 }
    117 
    118 static void
    119 tr_window_class_init( gpointer g_class, gpointer g_class_data SHUTUP )
    120 {
    121     GObjectClass  * gobject_class;
    122     TrWindowClass * trwindow_class;
    123     GParamSpec   * pspec;
    124 
    125     gobject_class = G_OBJECT_CLASS( g_class );
    126     gobject_class->set_property = tr_window_set_property;
    127     gobject_class->get_property = tr_window_get_property;
    128     gobject_class->dispose      = tr_window_dispose;
    129 
    130     pspec = g_param_spec_object( "model", "Model",
    131                                  "The GtkTreeModel for the list view.",
    132                                  GTK_TYPE_TREE_MODEL, G_PARAM_READWRITE );
    133     g_object_class_install_property( gobject_class, PROP_MODEL, pspec );
    134 
    135     pspec = g_param_spec_object( "selection", "Selection",
    136                                  "The GtkTreeSelection for the list view.",
    137                                  GTK_TYPE_TREE_SELECTION, G_PARAM_READABLE );
    138     g_object_class_install_property( gobject_class, PROP_SELECTION, pspec );
    139 
    140     pspec = g_param_spec_int( "double-click-action", "Double-click action",
    141                               "The action id to signal on a double click.",
    142                               G_MININT, G_MAXINT, -1, G_PARAM_READWRITE );
    143     g_object_class_install_property( gobject_class, PROP_DOUBLECLICK, pspec );
    144 
    145     pspec = g_param_spec_object( "drag-widget", "Drag widget",
    146                                  "The GtkWidget used for drag-and-drop.",
    147                                  GTK_TYPE_WIDGET, G_PARAM_READABLE );
    148     g_object_class_install_property( gobject_class, PROP_DRAG, pspec );
    149 
    150     trwindow_class = TR_WINDOW_CLASS( g_class );
    151     trwindow_class->actionsig =
    152         g_signal_new( "action", G_TYPE_FROM_CLASS( g_class ),
    153                        G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    154                        g_cclosure_marshal_VOID__INT,
    155                        G_TYPE_NONE, 1, G_TYPE_INT );
    156 }
    157 
    158 static void
    159 tr_window_init( GTypeInstance * instance, gpointer g_class SHUTUP )
    160 {
    161     TrWindow * self = ( TrWindow * )instance;
    162     GtkWidget * vbox, * scroll, * status, * tools, * menu, * file, * item;
    163 
    164     vbox   = gtk_vbox_new( FALSE, 0 );
    165     scroll = gtk_scrolled_window_new( NULL, NULL );
    166     status = gtk_statusbar_new();
    167     tools  = gtk_toolbar_new();
    168     menu   = gtk_menu_bar_new();
    169     file   = gtk_menu_new();
    170     item   = gtk_menu_item_new_with_mnemonic( _("_File") );
    171 
    172     self->scroll          = GTK_SCROLLED_WINDOW( scroll );
    173     self->view            = makeview( self );
    174     self->status          = GTK_STATUSBAR( status );
    175     self->toolbar         = GTK_TOOLBAR( tools );
    176     self->menu            = GTK_MENU_SHELL( file );
    177     /* this should have been set by makeview() */
    178     g_assert( NULL != self->namerend );
    179     self->doubleclick     = -1;
    180     self->actions         = NULL;
    181     self->accel           = gtk_accel_group_new();
    182     self->stupidpopuphack = NULL;
    183     self->disposed        = FALSE;
    184 
    185     gtk_window_add_accel_group( GTK_WINDOW( self ), self->accel );
    186     gtk_menu_set_accel_group( GTK_MENU( self->menu ), self->accel );
    187 
    188     gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), file );
    189     gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
    190     gtk_box_pack_start( GTK_BOX( vbox ), menu, FALSE, FALSE, 0 );
    191 
    192     gtk_toolbar_set_tooltips( self->toolbar, TRUE );
    193     gtk_toolbar_set_show_arrow( self->toolbar, FALSE );
    194     gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( self->toolbar ),
    195                         FALSE, FALSE, 0 );
    196 
    197     gtk_container_add( GTK_CONTAINER( scroll ), GTK_WIDGET( self->view ) );
    198     gtk_box_pack_start( GTK_BOX( vbox ), scroll, TRUE, TRUE, 0 );
    199 
    200     gtk_statusbar_push( self->status, 0, "" );
    201     gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( self->status ),
    202                         FALSE, FALSE, 0 );
    203 
    204     gtk_container_set_focus_child( GTK_CONTAINER( vbox ), scroll );
    205     gtk_widget_show_all( vbox );
    206     gtk_container_add( GTK_CONTAINER( self ), vbox );
    207     gtk_window_set_title( GTK_WINDOW( self ), g_get_application_name());
    208     gtk_window_set_role( GTK_WINDOW( self ), "tr-main" );
    209 }
    210 
    211 static void
    212 tr_window_set_property( GObject * object, guint property_id,
    213                         const GValue * value SHUTUP, GParamSpec * pspec)
    214 {
    215     TrWindow         * self = ( TrWindow * )object;
    216 
    217     if( self->disposed )
    218     {
    219         return;
    220     }
    221 
    222     switch( property_id )
    223     {
    224         case PROP_MODEL:
    225             gtk_tree_view_set_model( self->view, g_value_get_object( value ) );
    226             break;
    227         case PROP_DOUBLECLICK:
    228             self->doubleclick = g_value_get_int( value );
    229             break;
    230         default:
    231             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
    232             break;
    233     }
    234 }
    235 
    236 static void
    237 tr_window_get_property( GObject * object, guint property_id,
    238                         GValue * value SHUTUP, GParamSpec * pspec )
    239 {
    240     TrWindow         * self = ( TrWindow * )object;
    241 
    242     if( self->disposed )
    243     {
    244         return;
    245     }
    246 
    247     switch( property_id )
    248     {
    249         case PROP_MODEL:
    250             g_value_set_object( value, gtk_tree_view_get_model( self->view ) );
    251             break;
    252         case PROP_SELECTION:
    253             g_value_set_object( value,
    254                                 gtk_tree_view_get_selection( self->view ) );
    255             break;
    256         case PROP_DOUBLECLICK:
    257             g_value_set_int( value, self->doubleclick );
    258             break;
    259         case PROP_DRAG:
    260             g_value_set_object( value, self->view );
    261             break;
    262         default:
    263             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
    264             break;
    265     }
    266 }
    267 
    268 static void
    269 tr_window_dispose( GObject * obj )
    270 {
    271     TrWindow     * self = ( TrWindow * )obj;
    272     GObjectClass * parent;
    273 
    274     if( self->disposed )
    275     {
    276         return;
    277     }
    278     self->disposed = TRUE;
    279 
    280     g_list_foreach( self->actions, ( GFunc )action_free, NULL );
    281     g_list_free( self->actions );
    282     g_object_unref( self->accel );
    283     if( NULL != self->stupidpopuphack )
    284     {
    285         gtk_widget_destroy( self->stupidpopuphack );
    286     }
    287     self->stupidpopuphack = NULL;
    288 
    289     /* Chain up to the parent class */
    290     parent = g_type_class_peek( g_type_parent( TR_WINDOW_TYPE ) );
    291     parent->dispose( obj );
    292 }
    293 
    294 GtkWidget *
    295 tr_window_new( void )
    296 {
    297     return g_object_new( TR_WINDOW_TYPE, NULL );
    298 }
    299 
    300 void
    301 tr_window_action_add( TrWindow * self, int id, int flags, const char * name,
    302                       const char * icon, const char * description, guint key )
    303 {
    304     struct action * act;
    305     GtkWidget     * sep;
    306 
    307     TR_IS_WINDOW( self );
    308     if( self->disposed )
    309     {
    310         return;
    311     }
    312 
    313     act = action_new( id, flags, name, icon );
    314 
    315     if( ACTF_TOOL & flags )
    316     {
    317         act->tool = action_maketool( act, ITEM_ACTION,
    318                                      G_CALLBACK( itemclick ), self );
    319         gtk_tool_item_set_tooltip( GTK_TOOL_ITEM( act->tool ),
    320                                    self->toolbar->tooltips, description, "" );
    321         gtk_toolbar_insert( self->toolbar, GTK_TOOL_ITEM( act->tool ), -1 );
    322     }
    323 
    324     if( ACTF_MENU & flags )
    325     {
    326         act->menu = action_makemenu( act, ITEM_ACTION, self->accel,
    327                                      "<transmission-mainwind>/file", key,
    328                                      G_CALLBACK( itemclick ), self );
    329         gtk_menu_shell_append( self->menu, act->menu );
    330     }
    331 
    332     if( ACTF_SEPARATOR & flags )
    333     {
    334         sep = gtk_separator_menu_item_new();
    335         gtk_widget_show( sep );
    336         gtk_menu_shell_append( self->menu, sep );
    337     }
    338 
    339     self->actions = g_list_append( self->actions, act );
    340 }
    341 
    342 void
    343 tr_window_update( TrWindow * self, float downspeed, float upspeed )
    344 {
    345     char * downstr, * upstr, * str;
    346 
    347     TR_IS_WINDOW( self );
    348     if( self->disposed )
    349     {
    350         return;
    351     }
    352 
    353     /* update the status bar */
    354     downstr = readablespeed ( downspeed );
    355     upstr   = readablespeed ( upspeed );
    356     str     = g_strdup_printf( _("     Total DL: %s     Total UL: %s"),
    357                                downstr, upstr );
    358     g_free( downstr );
    359     g_free( upstr );
    360     gtk_statusbar_pop( self->status, 0 );
    361     gtk_statusbar_push( self->status, 0, str );
     40typedef struct
     41{
     42    GtkWidget * scroll;
     43    GtkWidget * view;
     44    GtkWidget * status;
     45    GtkTreeSelection * selection;
     46    GtkCellRenderer * namerend;
     47}
     48PrivateData;
     49
     50#define PRIVATE_DATA_KEY "private-data"
     51
     52PrivateData*
     53get_private_data( TrWindow * w )
     54{
     55    return (PrivateData*) g_object_get_data (G_OBJECT(w), PRIVATE_DATA_KEY);
     56}
     57
     58/***
     59****
     60***/
     61
     62/* kludge to have the progress bars notice theme changes */
     63static void
     64stylekludge( GObject * obj, GParamSpec * spec, gpointer data )
     65{
     66    if( 0 == strcmp( "style", spec->name ) )
     67    {
     68        tr_cell_renderer_progress_reset_style(
     69            TR_CELL_RENDERER_PROGRESS( data ) );
     70        gtk_widget_queue_draw( GTK_WIDGET( obj ) );
     71    }
     72}
     73
     74static void
     75formatname( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
     76            GtkTreeModel * model, GtkTreeIter * iter, gpointer data SHUTUP )
     77{
     78    TrTorrent * gtor;
     79    char  * name, * mb, * str, * top, * bottom;
     80    guint64 size;
     81    int     status, err, eta, tpeers, upeers, dpeers;
     82
     83    gtk_tree_model_get( model, iter, MC_NAME, &name, MC_STAT, &status,
     84                        MC_ERR, &err, MC_SIZE, &size,
     85                        MC_ETA, &eta, MC_PEERS, &tpeers, MC_UPEERS, &upeers,
     86                        MC_DPEERS, &dpeers, MC_TORRENT, &gtor, -1 );
     87
     88    tpeers = MAX( tpeers, 0 );
     89    upeers = MAX( upeers, 0 );
     90    dpeers = MAX( dpeers, 0 );
     91    mb = readablesize(size);
     92
     93    top = tr_torrent_status_str ( gtor );
     94
     95    if( TR_OK != err )
     96    {
     97        char * terr;
     98        gtk_tree_model_get( model, iter, MC_TERR, &terr, -1 );
     99        bottom = g_strconcat( _("Error: "), terr, NULL );
     100        g_free( terr );
     101    }
     102    else if( TR_STATUS_DOWNLOAD & status )
     103    {
     104        bottom = g_strdup_printf( ngettext( "Downloading from %i of %i peer",
     105                                            "Downloading from %i of %i peers",
     106                                            tpeers ), upeers, tpeers );
     107    }
     108    else
     109    {
     110        bottom = NULL;
     111    }
     112
     113    str = g_markup_printf_escaped( "<big>%s (%s)</big>\n<small>%s\n%s</small>",
     114                                   name, mb, top,
     115                                   ( NULL == bottom ? "" : bottom ) );
     116    g_object_set( rend, "markup", str, NULL );
     117    g_free( name );
     118    g_free( mb );
    362119    g_free( str );
    363 
    364     /* the selection's status may have changed so update the buttons */
    365     fixbuttons( NULL, self );
    366 }
    367 
    368 void
    369 tr_window_show( TrWindow * self )
    370 {
    371     TR_IS_WINDOW( self );
    372 
    373     sizingmagic( GTK_WINDOW( self ), self->scroll,
    374                  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
    375     g_object_set( self->namerend, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
    376     gtk_widget_show( GTK_WIDGET( self ) );
    377 }
    378 
    379 static GtkTreeView *
    380 makeview( TrWindow * self )
     120    g_free( top );
     121    g_free( bottom );
     122    g_object_unref( gtor );
     123}
     124
     125static void
     126formatprog( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
     127            GtkTreeModel * model, GtkTreeIter * iter, gpointer data SHUTUP )
     128{
     129    char  * dlstr, * ulstr, * str, * marked;
     130    gfloat  prog, dl, ul;
     131    guint64 down, up;
     132
     133    gtk_tree_model_get( model, iter, MC_PROG, &prog, MC_DRATE, &dl,
     134                        MC_URATE, &ul, MC_DOWN, &down, MC_UP, &up, -1 );
     135    prog = MAX( prog, 0.0 );
     136    prog = MIN( prog, 1.0 );
     137
     138    ulstr = readablespeed (ul);
     139    if( 1.0 == prog )
     140    {
     141        dlstr = ratiostr( down, up );
     142        str = g_strdup_printf( _("Ratio: %s\nUL: %s"), dlstr, ulstr );
     143    }
     144    else
     145    {
     146        dlstr = readablespeed( dl );
     147        str = g_strdup_printf( _("DL: %s\nUL: %s"), dlstr, ulstr );
     148    }
     149    marked = g_markup_printf_escaped( "<small>%s</small>", str );
     150    g_object_set( rend, "markup", str, "progress", prog, NULL );
     151    g_free( dlstr );
     152    g_free( ulstr );
     153    g_free( str );
     154    g_free( marked );
     155}
     156
     157static void
     158on_popup_menu ( GtkWidget * self UNUSED, GdkEventButton * event )
     159{
     160    GtkWidget * menu = action_get_widget ( "/main-window-popup" );
     161    gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
     162                    (event ? event->button : 0),
     163                    (event ? event->time : 0));
     164}
     165
     166static void
     167view_row_activated ( GtkTreeView       * tree_view  UNUSED,
     168                     GtkTreePath       * path       UNUSED,
     169                     GtkTreeViewColumn * column     UNUSED,
     170                     gpointer            user_data  UNUSED )
     171{
     172    action_activate( "show-torrent-inspector" );
     173}
     174
     175static GtkWidget*
     176makeview( PrivateData * p )
    381177{
    382178    GtkWidget         * view;
     
    386182    char              * str;
    387183
    388     TR_IS_WINDOW( self );
    389 
    390184    view     = gtk_tree_view_new();
     185
     186    p->selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(view) );
    391187    namerend = gtk_cell_renderer_text_new();
    392     self->namerend = G_OBJECT( namerend );
     188    p->namerend = namerend;
    393189    /* note that this renderer is set to ellipsize, just not here */
    394190    col = gtk_tree_view_column_new_with_attributes( _("Name"), namerend,
     
    421217                                 GTK_SELECTION_MULTIPLE );
    422218
    423     g_signal_connect( G_OBJECT( sel ), "changed",
    424                       G_CALLBACK( fixbuttons ), self );
    425     g_signal_connect( G_OBJECT( view ), "button-press-event",
    426                       G_CALLBACK( listclick ), self );
    427     g_signal_connect( G_OBJECT( view ), "popup-menu",
    428                       G_CALLBACK( listpopup ), self );
    429     g_signal_connect( G_OBJECT( view ), "row-activated",
    430                       G_CALLBACK( doubleclick ), self );
    431 
    432     return GTK_TREE_VIEW( view );
    433 }
    434 
    435 /* kludge to have the progress bars notice theme changes */
    436 static void
    437 stylekludge( GObject * obj, GParamSpec * spec, gpointer data )
    438 {
    439     if( 0 == strcmp( "style", spec->name ) )
    440     {
    441         tr_cell_renderer_progress_reset_style(
    442             TR_CELL_RENDERER_PROGRESS( data ) );
    443         gtk_widget_queue_draw( GTK_WIDGET( obj ) );
    444     }
    445 }
    446 
    447 /* disable buttons and menuitems the user shouldn't be able to click on */
    448 static void
    449 fixbuttons( GtkTreeSelection *sel, TrWindow * self ) {
    450     gboolean        selected, avail;
    451     GList         * ii;
    452     int             status;
    453     struct action * act;
    454 
    455     TR_IS_WINDOW( self );
    456     if( self->disposed )
    457     {
    458         return;
    459     }
    460 
    461     if( NULL == sel )
    462     {
    463         sel = gtk_tree_view_get_selection( self->view );
    464     }
    465     status = 0;
    466     gtk_tree_selection_selected_foreach( sel, orstatus, &status );
    467     selected = ( 0 < gtk_tree_selection_count_selected_rows( sel ) );
    468 
    469     for( ii = g_list_first( self->actions ); NULL != ii; ii = ii->next )
    470     {
    471         act = ii->data;
    472         if( ACTF_ALWAYS & act->flags )
    473         {
    474             continue;
    475         }
    476         avail = ACT_ISAVAIL( act->flags, status );
    477         if( ACTF_TOOL & act->flags )
    478         {
    479             g_assert( NULL != act->tool );
    480             gtk_widget_set_sensitive( act->tool, selected && avail );
    481         }
    482         if( ACTF_MENU & act->flags )
    483         {
    484             g_assert( NULL != act->menu );
    485             gtk_widget_set_sensitive( act->menu, selected && avail );
    486         }
    487     }
    488 }
    489 
    490 static void
    491 formatname( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
    492             GtkTreeModel * model, GtkTreeIter * iter, gpointer data SHUTUP )
    493 {
    494     TrTorrent * gtor;
    495     char  * name, * mb, * str, * top, * bottom;
    496     guint64 size;
    497     int     status, err, eta, tpeers, upeers, dpeers;
    498 
    499     gtk_tree_model_get( model, iter, MC_NAME, &name, MC_STAT, &status,
    500                         MC_ERR, &err, MC_SIZE, &size,
    501                         MC_ETA, &eta, MC_PEERS, &tpeers, MC_UPEERS, &upeers,
    502                         MC_DPEERS, &dpeers, MC_TORRENT, &gtor, -1 );
    503 
    504     tpeers = MAX( tpeers, 0 );
    505     upeers = MAX( upeers, 0 );
    506     dpeers = MAX( dpeers, 0 );
    507     mb = readablesize(size);
    508 
    509     top = tr_torrent_status_str ( gtor );
    510 
    511     if( TR_OK != err )
    512     {
    513         char * terr;
    514         gtk_tree_model_get( model, iter, MC_TERR, &terr, -1 );
    515         bottom = g_strconcat( _("Error: "), terr, NULL );
    516         g_free( terr );
    517     }
    518     else if( TR_STATUS_DOWNLOAD & status )
    519     {
    520         bottom = g_strdup_printf( ngettext( "Downloading from %i of %i peer",
    521                                             "Downloading from %i of %i peers",
    522                                             tpeers ), upeers, tpeers );
    523     }
    524     else
    525     {
    526         bottom = NULL;
    527     }
    528 
    529     str = g_markup_printf_escaped( "<big>%s (%s)</big>\n<small>%s\n%s</small>",
    530                                    name, mb, top,
    531                                    ( NULL == bottom ? "" : bottom ) );
    532     g_object_set( rend, "markup", str, NULL );
    533     g_free( name );
    534     g_free( mb );
     219    g_signal_connect( view, "popup-menu",
     220                      G_CALLBACK(on_popup_menu), NULL );
     221    g_signal_connect( view, "button-press-event",
     222                      G_CALLBACK(on_tree_view_button_pressed), on_popup_menu);
     223    g_signal_connect( view, "row-activated",
     224                      G_CALLBACK(view_row_activated), NULL);
     225
     226    return view;
     227}
     228
     229/***
     230****  PUBLIC
     231***/
     232
     233GtkWidget *
     234tr_window_new( GtkUIManager * ui_manager )
     235{
     236    PrivateData * p = g_new( PrivateData, 1 );
     237    GtkWidget *vbox, *w, *self;
     238
     239    /* make the window */
     240    self = gtk_window_new (GTK_WINDOW_TOPLEVEL);
     241    g_object_set_data_full(G_OBJECT(self), PRIVATE_DATA_KEY, p, g_free );
     242    gtk_window_set_title( GTK_WINDOW( self ), g_get_application_name());
     243    gtk_window_set_role( GTK_WINDOW( self ), "tr-main" );
     244    gtk_window_add_accel_group (GTK_WINDOW(self),
     245                                gtk_ui_manager_get_accel_group (ui_manager));
     246
     247    /* window's main container */
     248    vbox = gtk_vbox_new (FALSE, 0);
     249    gtk_container_add (GTK_CONTAINER(self), vbox);
     250
     251    /* main menu */
     252    w = action_get_widget( "/main-window-menu" );
     253    gtk_box_pack_start( GTK_BOX(vbox), w, FALSE, FALSE, 0 );
     254
     255    /* toolbar */
     256    w = action_get_widget( "/main-window-toolbar" );
     257    gtk_box_pack_start( GTK_BOX(vbox), w, FALSE, FALSE, 0 );
     258
     259    /* workarea */
     260    p->view = makeview( p );
     261    w = p->scroll = gtk_scrolled_window_new( NULL, NULL );
     262    gtk_container_add( GTK_CONTAINER(w), p->view );
     263    gtk_box_pack_start_defaults( GTK_BOX(vbox), w );
     264    gtk_container_set_focus_child( GTK_CONTAINER( vbox ), w );
     265
     266    /* statusbar */
     267    w = p->status = gtk_statusbar_new ();
     268    gtk_statusbar_push( GTK_STATUSBAR(w), 0, "" );
     269    gtk_box_pack_start( GTK_BOX(vbox), w, FALSE, FALSE, 0 );
     270
     271    /* show all but the window */
     272    gtk_widget_show_all( vbox );
     273
     274    return self;
     275}
     276
     277void
     278tr_window_update( TrWindow * self, float downspeed, float upspeed )
     279{
     280    PrivateData * p = get_private_data( self );
     281    GtkStatusbar * status = GTK_STATUSBAR( p->status );
     282
     283    /* update the status bar */
     284    char * downstr = readablespeed ( downspeed );
     285    char * upstr   = readablespeed ( upspeed );
     286    char * str     = g_strdup_printf( _("     Total DL: %s     Total UL: %s"),
     287                                      downstr, upstr );
     288    g_free( downstr );
     289    g_free( upstr );
     290    gtk_statusbar_pop( status, 0 );
     291    gtk_statusbar_push( status, 0, str );
    535292    g_free( str );
    536     g_free( top );
    537     g_free( bottom );
    538     g_object_unref( gtor );
    539 }
    540 
    541 static void
    542 formatprog( GtkTreeViewColumn * col SHUTUP, GtkCellRenderer * rend,
    543             GtkTreeModel * model, GtkTreeIter * iter, gpointer data SHUTUP )
    544 {
    545     char  * dlstr, * ulstr, * str, * marked;
    546     gfloat  prog, dl, ul;
    547     guint64 down, up;
    548 
    549     gtk_tree_model_get( model, iter, MC_PROG, &prog, MC_DRATE, &dl,
    550                         MC_URATE, &ul, MC_DOWN, &down, MC_UP, &up, -1 );
    551     prog = MAX( prog, 0.0 );
    552     prog = MIN( prog, 1.0 );
    553 
    554     ulstr = readablespeed (ul);
    555     if( 1.0 == prog )
    556     {
    557         dlstr = ratiostr( down, up );
    558         str = g_strdup_printf( _("Ratio: %s\nUL: %s"), dlstr, ulstr );
    559     }
    560     else
    561     {
    562         dlstr = readablespeed( dl );
    563         str = g_strdup_printf( _("DL: %s\nUL: %s"), dlstr, ulstr );
    564     }
    565     marked = g_markup_printf_escaped( "<small>%s</small>", str );
    566     g_object_set( rend, "markup", str, "progress", prog, NULL );
    567     g_free( dlstr );
    568     g_free( ulstr );
    569     g_free( str );
    570     g_free( marked );
    571 }
    572 
    573 /* show a popup menu for a right-click on the list */
    574 static gboolean
    575 listclick( GtkWidget * view, GdkEventButton * event, gpointer data )
    576 {
    577     TrWindow         * self;
    578     GtkTreeSelection * sel;
    579     GtkTreePath      * path;
    580     GtkTreeModel     * model;
    581     GtkTreeIter        iter;
    582     int                status;
    583     TrTorrent        * tor, * issel;
    584 
    585     if( GDK_BUTTON_PRESS != event->type || 3 != event->button )
    586     {
    587         return FALSE;
    588     }
    589 
    590     TR_IS_WINDOW( data );
    591     self = TR_WINDOW( data );
    592     if( self->disposed )
    593     {
    594         return FALSE;
    595     }
    596 
    597     sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
    598     model = gtk_tree_view_get_model( GTK_TREE_VIEW( view ) );
    599 
    600     /* find what row, if any, the user clicked on */
    601     if( gtk_tree_view_get_path_at_pos( GTK_TREE_VIEW( view ),
    602                                         event->x, event->y, &path,
    603                                         NULL, NULL, NULL ) )
    604     {
    605         if( gtk_tree_model_get_iter( model, &iter, path ) )
    606         {
    607             /* get torrent and status for the right-clicked row */
    608             gtk_tree_model_get( model, &iter, MC_TORRENT, &tor,
    609                                 MC_STAT, &status, -1 );
    610             issel = tor;
    611             gtk_tree_selection_selected_foreach( sel, istorsel, &issel );
    612             g_object_unref( tor );
    613             /* if the clicked row isn't selected, select only it */
    614             if( NULL != issel )
    615             {
    616                 gtk_tree_selection_unselect_all( sel );
    617                 gtk_tree_selection_select_iter( sel, &iter );
    618             }
    619         }
    620         gtk_tree_path_free( path );
    621     }
    622     else
    623     {
    624         gtk_tree_selection_unselect_all( sel );
    625     }
    626 
    627     popupmenu( self, event );
    628 
    629     return TRUE;
    630 }
    631 
    632 static gboolean
    633 listpopup( GtkWidget * view SHUTUP, gpointer data )
    634 {
    635     popupmenu( TR_WINDOW( data ), NULL );
    636     return TRUE;
    637 }
    638 
    639 static void
    640 popupmenu( TrWindow * self, GdkEventButton * event )
    641 {
    642     GtkTreeSelection * sel;
    643     int                count, status;
    644     GtkWidget        * menu, * item;
    645     GList            * ii;
    646     struct action    * act;
    647 
    648     TR_IS_WINDOW( self );
    649     if( self->disposed )
    650     {
    651         return;
    652     }
    653 
    654     sel   = gtk_tree_view_get_selection( self->view );
    655     count = gtk_tree_selection_count_selected_rows( sel );
    656     menu  = gtk_menu_new();
    657 
    658     if( NULL != self->stupidpopuphack )
    659     {
    660         gtk_widget_destroy( self->stupidpopuphack );
    661     }
    662     self->stupidpopuphack = menu;
    663 
    664     status = 0;
    665     gtk_tree_selection_selected_foreach( sel, orstatus, &status );
    666 
    667     for( ii = g_list_first( self->actions ); NULL != ii; ii = ii->next )
    668     {
    669         act = ii->data;
    670         if( ACTF_SEPARATOR & act->flags )
    671         {
    672             item = gtk_separator_menu_item_new();
    673             gtk_widget_show( item );
    674             gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
    675         }
    676         else if( ACTF_MENU & act->flags && ACT_ISAVAIL( act->flags, status ) )
    677         {
    678             item = action_makemenu( act, ITEM_ACTION, NULL, NULL, 0,
    679                                     G_CALLBACK( itemclick ), self );
    680             gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
    681         }
    682     }
    683 
    684     gtk_widget_show( menu );
    685 
    686     gtk_menu_popup( GTK_MENU( menu ), NULL, NULL, NULL, NULL,
    687                     ( NULL == event ? 0 : event->button ),
    688                     gdk_event_get_time( (GdkEvent*)event ) );
    689 }
    690 
    691 static void
    692 itemclick( GObject * obj, gpointer data )
    693 {
    694     TrWindow      * self;
    695     struct action * act;
    696 
    697     TR_IS_WINDOW( data );
    698     self = TR_WINDOW( data );
    699     act = g_object_get_data( obj, ITEM_ACTION );
    700 
    701     emitaction( self, act->id );
    702 }
    703 
    704 static void
    705 doubleclick( GtkWidget * view SHUTUP, GtkTreePath * path,
    706              GtkTreeViewColumn * col SHUTUP, gpointer data )
    707 {
    708     TrWindow         * self;
    709     GtkTreeSelection * sel;
    710 
    711     TR_IS_WINDOW( data );
    712     self = TR_WINDOW( data );
    713     if( self->disposed || 0 > self->doubleclick )
    714     {
    715         return;
    716     }
    717 
    718     sel = gtk_tree_view_get_selection( self->view );
    719     gtk_tree_selection_select_path( sel, path );
    720 
    721     emitaction( self, self->doubleclick );
    722 }
    723 
    724 static void
    725 emitaction( TrWindow * self, int id )
    726 {
    727     TrWindowClass * class;
    728 
    729     TR_IS_WINDOW( self );
    730     if( self->disposed )
    731     {
    732         return;
    733     }
    734 
    735     class = g_type_class_peek( TR_WINDOW_TYPE );
    736     g_signal_emit( self, class->actionsig, 0, id );
    737 }
    738 
    739 /* use with gtk_tree_selection_selected_foreach to | status of selected rows */
    740 static void
    741 orstatus( GtkTreeModel * model, GtkTreePath * path SHUTUP, GtkTreeIter * iter,
    742           gpointer data )
    743 {
    744     int * allstatus, thisstatus;
    745 
    746   allstatus = data;
    747   gtk_tree_model_get( model, iter, MC_STAT, &thisstatus, -1 );
    748   *allstatus |= thisstatus;
    749 }
    750 
    751 /* data should be a TrTorrent**, will set torrent to NULL if it's selected */
    752 static void
    753 istorsel( GtkTreeModel * model, GtkTreePath * path SHUTUP, GtkTreeIter * iter,
    754           gpointer data )
    755 {
    756     TrTorrent ** torref, * tor;
    757 
    758     torref = data;
    759     if( NULL != *torref )
    760     {
    761         gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
    762         if( tor == *torref )
    763         {
    764             *torref = NULL;
    765         }
    766         g_object_unref( tor );
    767     }
    768 }
     293}
     294
     295void
     296tr_window_show( TrWindow * self )
     297{
     298    PrivateData * p = get_private_data( self );
     299
     300    sizingmagic( GTK_WINDOW( self ), GTK_SCROLLED_WINDOW(p->scroll),
     301                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
     302    g_object_set( p->namerend, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
     303    gtk_widget_show( GTK_WIDGET( self ) );
     304}
     305
     306GtkTreeSelection*
     307tr_window_get_selection ( TrWindow * w )
     308{
     309    return get_private_data(w)->selection;
     310}
  • branches/file_selection/gtk/tr_window.h

    r1647 r2054  
    2626#define TR_WINDOW_H
    2727
    28 #include <glib-object.h>
    2928#include <gtk/gtk.h>
    3029
    31 #define TR_WINDOW_TYPE            ( tr_window_get_type() )
     30typedef GtkWindow TrWindow;
    3231
    33 #define TR_WINDOW( obj ) \
    34   ( G_TYPE_CHECK_INSTANCE_CAST( (obj),   TR_WINDOW_TYPE, TrWindow ) )
     32GtkTreeSelection * tr_window_get_selection( TrWindow* wind );
    3533
    36 #define TR_WINDOW_CLASS( class ) \
    37   ( G_TYPE_CHECK_CLASS_CAST(    (class), TR_WINDOW_TYPE, TrWindowClass ) )
    38 
    39 #define TR_IS_WINDOW( obj ) \
    40   ( G_TYPE_CHECK_INSTANCE_TYPE( (obj),   TR_WINDOW_TYPE ) )
    41 
    42 #define TR_IS_WINDOW_CLASS( class ) \
    43   ( G_TYPE_CHECK_CLASS_TYPE(    (class), TR_WINDOW_TYPE ) )
    44 
    45 #define TR_WINDOW_GET_CLASS( obj ) \
    46   ( G_TYPE_INSTANCE_GET_CLASS(  (obj),   TR_WINDOW_TYPE, TrWindowClass ) )
    47 
    48 typedef struct _TrWindow TrWindow;
    49 typedef struct _TrWindowClass TrWindowClass;
    50 
    51 /* treat the contents of this structure as private */
    52 struct _TrWindow
    53 {
    54     GtkWindow           parent;
    55     GtkScrolledWindow * scroll;
    56     GtkTreeView       * view;
    57     GtkStatusbar      * status;
    58     GtkToolbar        * toolbar;
    59     GtkMenuShell      * menu;
    60     GObject           * namerend;
    61     int                 doubleclick;
    62     GList             * actions;
    63     GtkAccelGroup     * accel;
    64     GtkWidget         * stupidpopuphack;
    65     gboolean            disposed;
    66 };
    67 
    68 struct _TrWindowClass
    69 {
    70   GtkWindowClass parent;
    71   int            actionsig;
    72 };
    73 
    74 GType
    75 tr_window_get_type( void );
    76 
    77 GtkWidget *
    78 tr_window_new( void );
    79 
    80 void
    81 tr_window_action_add( TrWindow * wind, int id, int flags, const char * name,
    82                       const char * icon, const char * description, guint key );
     34GtkWidget * tr_window_new( GtkUIManager* );
    8335
    8436void
  • branches/file_selection/gtk/transmission-gtk.1

    r1750 r2054  
    7878.An Josh Elsasser Aq josh@elsasser.org ,
    7979.An Eric Petit Aq titer@m0k.org ,
     80.An Mitchell Livingston Aq livings124@gmail.com ,
    8081and
    81 .An Mitchell Livingston Aq livings124@gmail.com .
     82.An Charles Kerr Aq charles@rebelbase.com .
    8283.Sh SEE ALSO
    8384.Xr transmissioncli 1 ,
  • branches/file_selection/gtk/util.c

    r2005 r2054  
    320320}
    321321
     322/**
     323 * don't use more than 50% the height of the screen, nor 80% the width.
     324 * but don't be too small, either -- set the minimums to 500 x 300
     325 */
    322326void
    323 sizingmagic( GtkWindow * wind, GtkScrolledWindow * scroll,
    324              GtkPolicyType hscroll, GtkPolicyType vscroll )
    325 {
     327sizingmagic( GtkWindow         * wind,
     328             GtkScrolledWindow * scroll,
     329             GtkPolicyType       hscroll,
     330             GtkPolicyType       vscroll )
     331{
     332    int width;
     333    int height;
    326334    GtkRequisition req;
    327     GdkScreen    * screen;
    328     int            width, height;
    329 
    330     screen = gtk_widget_get_screen( GTK_WIDGET( wind ) );
     335
     336    GdkScreen * screen = gtk_widget_get_screen( GTK_WIDGET( wind ) );
    331337
    332338    gtk_scrolled_window_set_policy( scroll, GTK_POLICY_NEVER,
    333                                     GTK_POLICY_NEVER );
     339                                            GTK_POLICY_NEVER );
    334340
    335341    gtk_widget_size_request( GTK_WIDGET( wind ), &req );
     342    req.height = MAX( req.height, 300 );
    336343    height = MIN( req.height, gdk_screen_get_height( screen ) / 5 * 4 );
    337344
    338345    gtk_scrolled_window_set_policy( scroll, GTK_POLICY_NEVER, vscroll );
    339 
    340346    gtk_widget_size_request( GTK_WIDGET( wind ), &req );
     347    req.width = MAX( req.width, 500 );
    341348    width = MIN( req.width, gdk_screen_get_width( screen ) / 2 );
    342349
    343350    gtk_window_set_default_size( wind, width, height );
    344 
    345351    gtk_scrolled_window_set_policy( scroll, hscroll, vscroll );
    346 }
    347 
    348 struct action *
    349 action_new( int id, int flags, const char * label, const char * stock )
    350 {
    351     struct action * act;
    352 
    353     act        = g_new0( struct action, 1 );
    354     act->id    = id;
    355     act->flags = flags;
    356     act->label = g_strdup( label );
    357     act->stock = g_strdup( stock );
    358     act->tool  = NULL;
    359     act->menu  = NULL;
    360 
    361     return act;
    362 }
    363 
    364 void
    365 action_free( struct action * act )
    366 {
    367     g_free( act->label );
    368     g_free( act->stock );
    369     g_free( act );
    370 }
    371 
    372 GtkWidget *
    373 action_maketool( struct action * act, const char * key,
    374                  GCallback func, gpointer data )
    375 {
    376     GtkToolItem * item;
    377 
    378     item = gtk_tool_button_new_from_stock( act->stock );
    379     if( NULL != act->label )
    380     {
    381         gtk_tool_button_set_label( GTK_TOOL_BUTTON( item ), act->label );
    382     }
    383     g_object_set_data( G_OBJECT( item ), key, act );
    384     g_signal_connect( item, "clicked", func, data );
    385     gtk_widget_show( GTK_WIDGET( item ) );
    386 
    387     return GTK_WIDGET( item );
    388 }
    389 
    390 GtkWidget *
    391 action_makemenu( struct action * act, const char * actkey,
    392                  GtkAccelGroup * accel, const char * path, guint keyval,
    393                  GCallback func, gpointer data )
    394 {
    395     GtkWidget  * item, * label;
    396     GdkModifierType mod;
    397     GtkStockItem stock;
    398     const char * name;
    399     char       * joined;
    400 
    401     mod = GDK_CONTROL_MASK;
    402     name = act->label;
    403     if( NULL == act->stock )
    404     {
    405         item = gtk_menu_item_new_with_label( act->label );
    406     }
    407     else
    408     {
    409         item = gtk_image_menu_item_new_from_stock( act->stock, NULL );
    410         if( NULL == act->label )
    411         {
    412             if( gtk_stock_lookup( act->stock, &stock ) )
    413             {
    414                 name = stock.label;
    415                 if( 0 == keyval )
    416                 {
    417                     keyval = stock.keyval;
    418                     mod    = stock.modifier;
    419                 }
    420             }
    421         }
    422         else
    423         {
    424             label = gtk_bin_get_child( GTK_BIN( item ) );
    425             gtk_label_set_text( GTK_LABEL( label ), act->label );
    426            
    427         }
    428     }
    429 
    430     if( NULL != accel && 0 < keyval && NULL != name )
    431     {
    432         joined = g_strjoin( "/", path, name, NULL );
    433         gtk_accel_map_add_entry( joined, keyval, mod );
    434         gtk_widget_set_accel_path( item, joined, accel );
    435         g_free( joined );
    436     }
    437     g_object_set_data( G_OBJECT( item ), actkey, act );
    438     g_signal_connect( item, "activate", func, data );
    439     gtk_widget_show( item );
    440 
    441     return item;
    442352}
    443353
     
    520430  gtk_widget_destroy(widget);
    521431}
     432
     433/* pop up the context menu if a user right-clicks.
     434   if the row they right-click on isn't selected, select it. */
     435gboolean
     436on_tree_view_button_pressed (GtkWidget       * view,
     437                             GdkEventButton  * event,
     438                             gpointer          func)
     439{
     440  GtkTreeView * tv = GTK_TREE_VIEW( view );
     441
     442  if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
     443  {
     444    GtkTreeSelection * selection = gtk_tree_view_get_selection(tv);
     445    GtkTreePath *path;
     446    if (gtk_tree_view_get_path_at_pos (tv,
     447                                       (gint) event->x,
     448                                       (gint) event->y,
     449                                       &path, NULL, NULL, NULL))
     450    {
     451      if (!gtk_tree_selection_path_is_selected (selection, path))
     452      {
     453        gtk_tree_selection_unselect_all (selection);
     454        gtk_tree_selection_select_path (selection, path);
     455      }
     456      gtk_tree_path_free(path);
     457    }
     458   
     459    typedef void (PopupFunc)(GtkWidget*, GdkEventButton*);
     460    ((PopupFunc*)func)(view, event);
     461
     462    return TRUE;
     463  }
     464
     465  return FALSE;
     466}
     467
  • branches/file_selection/gtk/util.h

    r1998 r2054  
    4646/* used for a callback function with a data parameter */
    4747typedef void (*callbackfunc_t)(void*);
    48 
    49 /* flags indicating where and when an action is valid */
    50 #define ACTF_TOOL       ( 1 << 0 ) /* appear in the toolbar */
    51 #define ACTF_MENU       ( 1 << 1 ) /* appear in the popup menu */
    52 #define ACTF_ALWAYS     ( 1 << 2 ) /* available regardless of selection */
    53 #define ACTF_ACTIVE     ( 1 << 3 ) /* available for active torrent */
    54 #define ACTF_INACTIVE   ( 1 << 4 ) /* available for inactive torrent */
    55 #define ACTF_SEPARATOR  ( 1 << 5 ) /* dummy action to create menu separator */
    56 /* appear in the toolbar and the popup menu */
    57 #define ACTF_WHEREVER   ( ACTF_TOOL | ACTF_MENU )
    58 /* available if there is something selected */
    59 #define ACTF_WHATEVER   ( ACTF_ACTIVE | ACTF_INACTIVE )
    60 
    61 /* checking action flags against torrent status */
    62 #define ACT_ISAVAIL( flags, status ) \
    63     ( ( ACTF_ACTIVE   & (flags) && TR_STATUS_ACTIVE   & (status) ) || \
    64       ( ACTF_INACTIVE & (flags) && TR_STATUS_INACTIVE & (status) ) || \
    65         ACTF_ALWAYS   & (flags) )
    6648
    6749/* try to interpret a string as a textual representation of a boolean */
     
    132114#ifdef GTK_MAJOR_VERSION
    133115
    134 /* action handling */
    135 struct action
    136 {
    137     int            id;
    138     int            flags;
    139     char         * label;
    140     char         * stock;
    141     GtkWidget    * tool;
    142     GtkWidget    * menu;
    143     callbackfunc_t func;
    144     gpointer       data;
    145 };
    146 struct action *
    147 action_new( int id, int flags, const char * label, const char * stock );
    148 void
    149 action_free( struct action * act );
    150 GtkWidget *
    151 action_maketool( struct action * act, const char * key,
    152                  GCallback func, gpointer data );
    153 GtkWidget *
    154 action_makemenu( struct action * act, const char * actkey,
    155                  GtkAccelGroup * accel, const char * path, guint keyval,
    156                  GCallback func, gpointer data );
    157 
    158116/* here there be dragons */
    159117void
     
    185143              const char * format, va_list ap );
    186144
     145/* pop up the context menu if a user right-clicks.
     146   if the row they right-click on isn't selected, select it. */
     147gboolean
     148on_tree_view_button_pressed (GtkWidget       * view,
     149                             GdkEventButton  * event,
     150                             gpointer          unused);
     151
    187152#endif /* GTK_MAJOR_VERSION */
    188153
Note: See TracChangeset for help on using the changeset viewer.