Changeset 12656 for trunk/gtk/main.c


Ignore:
Timestamp:
Aug 9, 2011, 2:30:31 AM (11 years ago)
Author:
jordan
Message:

(trunk gtk) first cut at using GApplication. This lets glib replace hundreds of lines of homegrown code. Whee!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/main.c

    r12655 r12656  
    7474struct cbdata
    7575{
     76    char                      * config_dir;
     77    gboolean                    start_paused;
    7678    gboolean                    is_iconified;
     79
    7780    guint                       timer;
    7881    guint                       update_model_soon_tag;
     
    349352***/
    350353
    351 static void app_setup( TrWindow       * wind,
    352                        GSList         * torrent_files,
    353                        struct cbdata  * cbdata,
    354                        gboolean         paused,
    355                        gboolean         minimized );
     354static void app_setup( TrWindow * wind, struct cbdata  * cbdata );
    356355
    357356static void main_window_setup( struct cbdata * cbdata, TrWindow * wind );
     
    561560}
    562561
    563 static void
    564 setupsighandlers( void )
    565 {
    566     signal( SIGINT, signal_handler );
    567     signal( SIGKILL, signal_handler );
    568 }
    569 
    570 /***
    571 ****
    572 ***/
    573 
    574 static GSList *
    575 checkfilenames( int argc, char **argv )
    576 {
    577     int i;
    578     GSList * ret = NULL;
    579     char * pwd = g_get_current_dir( );
    580 
    581     for( i=0; i<argc; ++i )
    582     {
    583         const char * arg = argv[i];
    584 
    585         if( gtr_is_supported_url( arg ) || gtr_is_magnet_link( arg ) )
    586         {
    587             ret = g_slist_prepend( ret, g_strdup( arg ) );
    588         }
    589         else /* local file */
    590         {
    591             char * filename;
    592 
    593             if( g_path_is_absolute( arg ) )
    594                 filename = g_strdup( arg );
    595             else {
    596                 filename = g_filename_from_uri( arg, NULL, NULL );
    597 
    598                 if( filename == NULL )
    599                     filename = g_build_filename( pwd, arg, NULL );
    600             }
    601 
    602             if( g_file_test( filename, G_FILE_TEST_EXISTS ) )
    603                 ret = g_slist_prepend( ret, filename );
    604             else {
    605                 if( gtr_is_hex_hashcode( argv[i] ) )
    606                     ret = g_slist_prepend( ret, g_strdup_printf( "magnet:?xt=urn:btih:%s", argv[i] ) );
    607                 g_free( filename );
    608             }
    609         }
    610     }
    611 
    612     g_free( pwd );
    613     return g_slist_reverse( ret );
    614 }
    615 
    616562/****
    617563*****
     
    619565****/
    620566
     567static void
     568on_startup( GApplication * application, gpointer user_data )
     569{
     570    const char * str;
     571    GtkWindow * win;
     572    GtkUIManager * ui_manager;
     573    tr_session * session;
     574    struct cbdata * cbdata = user_data;
     575
     576    signal( SIGINT, signal_handler );
     577    signal( SIGKILL, signal_handler );
     578
     579    sighandler_cbdata = cbdata;
     580
     581    /* ensure the directories are created */
     582    if(( str = gtr_pref_string_get( TR_PREFS_KEY_DOWNLOAD_DIR )))
     583        g_mkdir_with_parents( str, 0777 );
     584    if(( str = gtr_pref_string_get( TR_PREFS_KEY_INCOMPLETE_DIR )))
     585        g_mkdir_with_parents( str, 0777 );
     586
     587    /* initialize the libtransmission session */
     588    session = tr_sessionInit( "gtk", cbdata->config_dir, TRUE, gtr_pref_get_all( ) );
     589
     590    gtr_pref_flag_set( TR_PREFS_KEY_ALT_SPEED_ENABLED, tr_sessionUsesAltSpeed( session ) );
     591    gtr_pref_int_set( TR_PREFS_KEY_PEER_PORT, tr_sessionGetPeerPort( session ) );
     592    cbdata->core = gtr_core_new( session );
     593
     594    /* init the ui manager */
     595    ui_manager = gtk_ui_manager_new ( );
     596    gtr_actions_init ( ui_manager, cbdata );
     597    gtk_ui_manager_add_ui_from_string ( ui_manager, fallback_ui_file, -1, NULL );
     598    gtk_ui_manager_ensure_update ( ui_manager );
     599
     600    /* create main window now to be a parent to any error dialogs */
     601    win = GTK_WINDOW( gtr_window_new( ui_manager, cbdata->core ) );
     602    g_signal_connect( win, "size-allocate", G_CALLBACK( on_main_window_size_allocated ), cbdata );
     603    g_application_hold( application );
     604    g_object_weak_ref( G_OBJECT( win ), (GWeakNotify)g_application_release, application );
     605    app_setup( win, cbdata );
     606    tr_sessionSetRPCCallback( session, on_rpc_changed, cbdata );
     607
     608    /* check & see if it's time to update the blocklist */
     609    if( gtr_pref_flag_get( TR_PREFS_KEY_BLOCKLIST_ENABLED ) ) {
     610        if( gtr_pref_flag_get( PREF_KEY_BLOCKLIST_UPDATES_ENABLED ) ) {
     611            const int64_t last_time = gtr_pref_int_get( "blocklist-date" );
     612            const int SECONDS_IN_A_WEEK = 7 * 24 * 60 * 60;
     613            const time_t now = time( NULL );
     614        if( last_time + SECONDS_IN_A_WEEK < now )
     615            gtr_core_blocklist_update( cbdata->core );
     616        }
     617    }
     618
     619    /* if there's no magnet link handler registered, register us */
     620    register_magnet_link_handler( );
     621}
     622
     623static void
     624on_activate( GApplication * app UNUSED, gpointer unused UNUSED )
     625{
     626    gtr_action_activate( "present-main-window" );
     627}
     628
     629static void
     630open_files( GSList * files, gpointer gdata )
     631{
     632    struct cbdata * cbdata = gdata;
     633    const gboolean do_start = gtr_pref_flag_get( TR_PREFS_KEY_START ) && !cbdata->start_paused;
     634    const gboolean do_prompt = gtr_pref_flag_get( PREF_KEY_OPTIONS_PROMPT );
     635    const gboolean do_notify = TRUE;
     636
     637    gtr_core_add_files( cbdata->core, files, do_start, do_prompt, do_notify );
     638}
     639
     640static void
     641on_open (GApplication  * application UNUSED,
     642         GFile        ** f,
     643         gint            file_count,
     644         gchar         * hint UNUSED,
     645         gpointer        gdata )
     646{
     647    int i;
     648    GSList * files = NULL;
     649
     650    for( i=0; i<file_count; ++i )
     651        files = g_slist_append( files, f[i] );
     652
     653    open_files( files, gdata );
     654
     655    g_slist_free( files );
     656}
     657
     658/***
     659****
     660***/
     661
    621662int
    622663main( int argc, char ** argv )
    623664{
    624     char * err = NULL;
    625     GSList * argfiles;
    626     GError * gerr;
    627     gboolean didinit = FALSE;
    628     gboolean didlock = FALSE;
    629     gboolean showversion = FALSE;
    630     gboolean startpaused = FALSE;
    631     gboolean startminimized = FALSE;
    632     const char * domain = MY_READABLE_NAME;
    633     char * configDir = NULL;
    634     gtr_lockfile_state_t tr_state;
    635 
    636     GOptionEntry entries[] = {
    637         { "paused",     'p', 0, G_OPTION_ARG_NONE,
    638           &startpaused, _( "Start with all torrents paused" ), NULL },
    639         { "version",    '\0', 0, G_OPTION_ARG_NONE,
    640           &showversion, _( "Show version number and exit" ), NULL },
    641         { "minimized",  'm', 0, G_OPTION_ARG_NONE,
    642           &startminimized,
    643           _( "Start minimized in notification area" ), NULL },
    644         { "config-dir", 'g', 0, G_OPTION_ARG_FILENAME, &configDir,
    645           _( "Where to look for configuration files" ), NULL },
     665    int ret;
     666    struct stat sb;
     667    char * application_id;
     668    GApplication * app;
     669    GOptionContext * option_context;
     670    bool show_version = false;
     671    GError * error = NULL;
     672    struct cbdata cbdata;
     673
     674    GOptionEntry option_entries[] = {
     675        { "config-dir", 'g', 0, G_OPTION_ARG_FILENAME, &cbdata.config_dir, _( "Where to look for configuration files" ), NULL },
     676        { "paused",     'p', 0, G_OPTION_ARG_NONE, &cbdata.start_paused, _( "Start with all torrents paused" ), NULL },
     677        { "minimized",  'm', 0, G_OPTION_ARG_NONE, &cbdata.is_iconified, _( "Start minimized in notification area" ), NULL },
     678        { "version",    'v', 0, G_OPTION_ARG_NONE, &show_version, _( "Show version number and exit" ), NULL },
    646679        { NULL, 0,   0, 0, NULL, NULL, NULL }
    647680    };
    648681
    649     /* bind the gettext domain */
     682    /* default settings */
     683    memset( &cbdata, 0, sizeof( struct cbdata ) );
     684    cbdata.config_dir = (char*) tr_getDefaultConfigDir( MY_CONFIG_NAME );
     685
     686    /* init i18n */
    650687    setlocale( LC_ALL, "" );
    651     bindtextdomain( domain, TRANSMISSIONLOCALEDIR );
    652     bind_textdomain_codeset( domain, "UTF-8" );
    653     textdomain( domain );
    654     g_set_application_name( _( "Transmission" ) );
     688    bindtextdomain( MY_READABLE_NAME, TRANSMISSIONLOCALEDIR );
     689    bind_textdomain_codeset( MY_READABLE_NAME, "UTF-8" );
     690    textdomain( MY_READABLE_NAME );
     691
     692    /* init glib/gtk */
     693    g_thread_init (NULL);
     694    g_type_init ();
     695    gtk_init (&argc, &argv);
     696    g_set_application_name (_( "Transmission" ));
     697    gtk_window_set_default_icon_name (MY_CONFIG_NAME);
     698
     699
     700    /* parse the command line */
     701    option_context = g_option_context_new( _( "[torrent files or urls]" ) );
     702    g_option_context_add_main_entries( option_context, option_entries, GETTEXT_PACKAGE );
     703    g_option_context_set_translation_domain( option_context, GETTEXT_PACKAGE );
     704    if( !g_option_context_parse( option_context, &argc, &argv, &error ) ) {
     705        g_print (_("%s\nRun '%s --help' to see a full list of available command line options.\n"), error->message, argv[0]);
     706        g_error_free (error);
     707        g_option_context_free (option_context);
     708        return 1;
     709    }
     710    g_option_context_free (option_context);
     711
     712    /* handle the trivial "version" option */
     713    if( show_version ) {
     714        fprintf( stderr, "%s %s\n", MY_READABLE_NAME, LONG_VERSION_STRING );
     715        return 0;
     716    }
     717
     718    /* init the unit formatters */
    655719    tr_formatter_mem_init( mem_K, _(mem_K_str), _(mem_M_str), _(mem_G_str), _(mem_T_str) );
    656720    tr_formatter_size_init( disk_K, _(disk_K_str), _(disk_M_str), _(disk_G_str), _(disk_T_str) );
    657721    tr_formatter_speed_init( speed_K, _(speed_K_str), _(speed_M_str), _(speed_G_str), _(speed_T_str) );
    658722
    659     /* initialize gtk */
    660     if( !g_thread_supported( ) )
    661         g_thread_init( NULL );
    662 
    663     gerr = NULL;
    664     if( !gtk_init_with_args( &argc, &argv, (char*)_( "[torrent files or urls]" ), entries,
    665                              (char*)domain, &gerr ) )
    666     {
    667         fprintf( stderr, "%s\n", gerr->message );
    668         g_clear_error( &gerr );
    669         return 0;
    670     }
    671 
    672     if( showversion )
    673     {
    674         fprintf( stderr, "%s %s\n", MY_READABLE_NAME, LONG_VERSION_STRING );
    675         return 0;
    676     }
    677 
    678     if( configDir == NULL )
    679         configDir = (char*) tr_getDefaultConfigDir( MY_CONFIG_NAME );
    680 
    681     didinit = cf_init( configDir, NULL ); /* must come before actions_init */
    682 
    683     setupsighandlers( ); /* set up handlers for fatal signals */
    684 
    685     didlock = cf_lock( &tr_state, &err );
    686     argfiles = checkfilenames( argc - 1, argv + 1 );
    687 
    688     if( !didlock && argfiles )
    689     {
    690         /* We have torrents to add but there's another copy of Transmsision
    691          * running... chances are we've been invoked from a browser, etc.
    692          * So send the files over to the "real" copy of Transmission, and
    693          * if that goes well, then our work is done. */
    694         GSList * l;
    695         gboolean delegated = FALSE;
    696         const gboolean trash_originals = gtr_pref_flag_get( TR_PREFS_KEY_TRASH_ORIGINAL );
    697 
    698         for( l=argfiles; l!=NULL; l=l->next )
    699         {
    700             const char * filename = l->data;
    701             const gboolean added = gtr_dbus_add_torrent( filename );
    702 
    703             if( added && trash_originals )
    704                 gtr_file_trash_or_remove( filename );
    705 
    706             delegated |= added;
    707         }
    708 
    709         if( delegated ) {
    710             g_slist_foreach( argfiles, (GFunc)g_free, NULL );
    711             g_slist_free( argfiles );
    712             argfiles = NULL;
    713 
    714             if( err ) {
    715                 g_free( err );
    716                 err = NULL;
    717             }
    718         }
    719     }
    720     else if( ( !didlock ) && ( tr_state == GTR_LOCKFILE_ELOCK ) )
    721     {
    722         /* There's already another copy of Transmission running,
    723          * so tell it to present its window to the user */
    724         err = NULL;
    725         if( !gtr_dbus_present_window( ) )
    726             err = g_strdup( _( "Transmission is already running, but is not responding. To start a new session, you must first close the existing Transmission process." ) );
    727     }
    728 
    729     if( didlock && ( didinit || cf_init( configDir, &err ) ) )
    730     {
    731         /* No other copy of Transmission running...
    732          * so we're going to be the primary. */
    733 
    734         const char * str;
    735         GtkWindow * win;
    736         GtkUIManager * myUIManager;
    737         tr_session * session;
    738         struct cbdata * cbdata = g_new0( struct cbdata, 1 );
    739 
    740         sighandler_cbdata = cbdata;
    741 
    742         /* ensure the directories are created */
    743         if(( str = gtr_pref_string_get( TR_PREFS_KEY_DOWNLOAD_DIR )))
    744             g_mkdir_with_parents( str, 0777 );
    745         if(( str = gtr_pref_string_get( TR_PREFS_KEY_INCOMPLETE_DIR )))
    746             g_mkdir_with_parents( str, 0777 );
    747 
    748         /* initialize the libtransmission session */
    749         session = tr_sessionInit( "gtk", configDir, TRUE, gtr_pref_get_all( ) );
    750 
    751         gtr_pref_flag_set( TR_PREFS_KEY_ALT_SPEED_ENABLED, tr_sessionUsesAltSpeed( session ) );
    752         gtr_pref_int_set( TR_PREFS_KEY_PEER_PORT, tr_sessionGetPeerPort( session ) );
    753         cbdata->core = gtr_core_new( session );
    754 
    755         /* init the ui manager */
    756         myUIManager = gtk_ui_manager_new ( );
    757         gtr_actions_init ( myUIManager, cbdata );
    758         gtk_ui_manager_add_ui_from_string ( myUIManager, fallback_ui_file, -1, NULL );
    759         gtk_ui_manager_ensure_update ( myUIManager );
    760         gtk_window_set_default_icon_name ( MY_CONFIG_NAME );
    761 
    762         /* create main window now to be a parent to any error dialogs */
    763         win = GTK_WINDOW( gtr_window_new( myUIManager, cbdata->core ) );
    764         g_signal_connect( win, "size-allocate", G_CALLBACK( on_main_window_size_allocated ), cbdata );
    765 
    766         app_setup( win, argfiles, cbdata, startpaused, startminimized );
    767         tr_sessionSetRPCCallback( session, on_rpc_changed, cbdata );
    768 
    769         /* on startup, check & see if it's time to update the blocklist */
    770         if( gtr_pref_flag_get( TR_PREFS_KEY_BLOCKLIST_ENABLED ) ) {
    771             if( gtr_pref_flag_get( PREF_KEY_BLOCKLIST_UPDATES_ENABLED ) ) {
    772                 const int64_t last_time = gtr_pref_int_get( "blocklist-date" );
    773                 const int SECONDS_IN_A_WEEK = 7 * 24 * 60 * 60;
    774                 const time_t now = time( NULL );
    775                 if( last_time + SECONDS_IN_A_WEEK < now )
    776                     gtr_core_blocklist_update( cbdata->core );
    777             }
    778         }
    779 
    780         /* if there's no magnet link handler registered, register us */
    781         register_magnet_link_handler( );
    782 
    783         gtk_main( );
    784     }
    785     else if( err )
    786     {
    787         const char * primary_text = _( "Transmission cannot be started." );
    788         GtkWidget * w = gtk_message_dialog_new( NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, primary_text, NULL );
    789         gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ), "%s", err );
    790         g_signal_connect( w, "response", G_CALLBACK(gtk_main_quit), NULL );
    791         gtk_widget_show( w );
    792         g_free( err );
    793         gtk_main( );
    794     }
    795 
    796     return 0;
     723    /* set up the config dir */
     724    gtr_pref_init( cbdata.config_dir );
     725    g_mkdir_with_parents( cbdata.config_dir, 0755 );
     726
     727    /* init the application for the specified config dir */
     728    stat( cbdata.config_dir, &sb );
     729    application_id = g_strdup_printf( "com.transmissionbt.transmission_%lu_%lu", (unsigned long)sb.st_dev, (unsigned long)sb.st_ino );
     730    app = g_application_new( application_id, G_APPLICATION_HANDLES_OPEN );
     731    g_signal_connect( app, "open", G_CALLBACK(on_open), &cbdata );
     732    g_signal_connect( app, "startup", G_CALLBACK(on_startup), &cbdata );
     733    g_signal_connect( app, "activate", G_CALLBACK(on_activate), &cbdata );
     734    ret = g_application_run (app, argc, argv);
     735    g_object_unref( app );
     736    return ret;
    797737}
    798738
     
    804744
    805745static void
    806 app_setup( TrWindow      * wind,
    807            GSList        * files,
    808            struct cbdata * cbdata,
    809            gboolean        pause_all,
    810            gboolean        is_iconified )
    811 {
    812     const gboolean do_start = gtr_pref_flag_get( TR_PREFS_KEY_START ) && !pause_all;
    813     const gboolean do_prompt = gtr_pref_flag_get( PREF_KEY_OPTIONS_PROMPT );
    814     const gboolean do_notify = TRUE;
    815 
    816     cbdata->is_iconified = is_iconified;
    817 
    818     if( is_iconified )
     746app_setup( TrWindow * wind, struct cbdata * cbdata )
     747{
     748    if( cbdata->is_iconified )
    819749        gtr_pref_flag_set( PREF_KEY_SHOW_TRAY_ICON, TRUE );
    820750
     
    828758
    829759    /* add torrents from command-line and saved state */
    830     gtr_core_load( cbdata->core, pause_all );
    831     gtr_core_add_list( cbdata->core, files, do_start, do_prompt, do_notify );
    832     files = NULL;
     760    gtr_core_load( cbdata->core, cbdata->start_paused );
    833761    gtr_core_torrents_added( cbdata->core );
    834762
     
    844772
    845773    /* either show the window or iconify it */
    846     if( !is_iconified )
     774    if( !cbdata->is_iconified )
    847775        gtk_widget_show( GTK_WIDGET( wind ) );
    848776    else
     
    955883                       gpointer            gdata )
    956884{
    957     int i;
    958     gboolean success = FALSE;
     885    guint i;
     886    char ** uris = gtk_selection_data_get_uris( selection_data );
     887    const guint file_count = g_strv_length( uris );
    959888    GSList * files = NULL;
    960     struct cbdata * data = gdata;
    961     char ** uris = gtk_selection_data_get_uris( selection_data );
    962 
    963     /* try to add the filename URIs... */
    964     for( i=0; uris && uris[i]; ++i )
    965     {
    966         const char * uri = uris[i];
    967         char * filename = g_filename_from_uri( uri, NULL, NULL );
    968 
    969         if( filename && g_file_test( filename, G_FILE_TEST_EXISTS ) )
    970         {
    971             files = g_slist_append( files, g_strdup( filename ) );
    972             success = TRUE;
    973         }
    974         else if( tr_urlIsValid( uri, -1 ) || gtr_is_magnet_link( uri ) )
    975         {
    976             gtr_core_add_from_url( data->core, uri );
    977             success = TRUE;
    978         }
    979 
    980         g_free( filename );
    981     }
    982 
    983     if( files )
    984         gtr_core_add_list_defaults( data->core, g_slist_reverse( files ), TRUE );
    985 
    986     gtr_core_torrents_added( data->core );
    987     gtk_drag_finish( drag_context, success, FALSE, time_ );
     889
     890    for( i=0; i<file_count; ++i )
     891        files = g_slist_append( files, g_file_new_for_uri( uris[i] ) );
     892
     893    open_files( files, gdata );
    988894
    989895    /* cleanup */
     896    g_slist_foreach( files, (GFunc)g_object_unref, NULL );
     897    g_slist_free( files );
    990898    g_strfreev( uris );
     899
     900    gtk_drag_finish( drag_context, true, FALSE, time_ );
    991901}
    992902
     
    1038948    g_slist_foreach( cbdata->duplicates_list, (GFunc)g_free, NULL );
    1039949    g_slist_free( cbdata->duplicates_list );
    1040     g_free( cbdata );
    1041 
    1042     gtk_main_quit( );
    1043950
    1044951    return FALSE;
Note: See TracChangeset for help on using the changeset viewer.