2006-08-13 00:26:52 +00:00
/******************************************************************************
* $ Id $
*
2011-01-19 13:48:47 +00:00
* Copyright ( c ) Transmission authors and contributors
2006-08-13 00:26:52 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-16 19:39:23 +00:00
2008-07-28 22:06:53 +00:00
# include <locale.h>
2006-07-16 19:39:23 +00:00
# include <signal.h>
# include <string.h>
# include <stdio.h>
2012-12-05 17:29:46 +00:00
# include <stdlib.h> /* exit () */
2006-07-16 19:39:23 +00:00
# include <time.h>
2010-12-23 22:31:28 +00:00
2006-07-16 19:39:23 +00:00
# include <glib/gi18n.h>
# include <glib/gstdio.h>
2011-08-07 16:42:38 +00:00
# include <gio/gio.h>
2011-07-24 16:01:14 +00:00
# include <gtk/gtk.h>
2006-07-16 19:39:23 +00:00
2008-09-01 04:47:02 +00:00
# include <libtransmission/transmission.h>
2008-12-03 05:15:17 +00:00
# include <libtransmission/rpcimpl.h>
2008-09-01 04:47:02 +00:00
# include <libtransmission/utils.h>
2008-05-06 19:27:42 +00:00
# include <libtransmission/version.h>
2007-06-18 03:40:41 +00:00
# include "actions.h"
2006-07-16 19:39:23 +00:00
# include "conf.h"
2008-02-19 03:57:03 +00:00
# include "details.h"
2006-07-16 19:39:23 +00:00
# include "dialogs.h"
2008-03-13 20:47:58 +00:00
# include "hig.h"
2007-06-18 03:40:41 +00:00
# include "makemeta-ui.h"
2006-08-20 22:45:29 +00:00
# include "msgwin.h"
2011-12-10 19:00:50 +00:00
# include "notify.h"
2011-01-20 19:57:42 +00:00
# include "open-dialog.h"
2009-05-13 15:54:04 +00:00
# include "relocate.h"
2007-11-27 03:29:51 +00:00
# include "stats.h"
2008-02-26 19:58:03 +00:00
# include "tr-core.h"
# include "tr-icon.h"
# include "tr-prefs.h"
# include "tr-window.h"
2006-07-16 19:39:23 +00:00
# include "util.h"
2010-08-05 13:24:46 +00:00
# define MY_CONFIG_NAME "transmission"
# define MY_READABLE_NAME "transmission-gtk"
2008-12-13 23:17:36 +00:00
2012-09-07 17:18:17 +00:00
# define TR_RESOURCE_PATH " / com / transmissionbt / transmission / "
2011-04-12 11:13:41 +00:00
# define SHOW_LICENSE
2008-09-23 19:11:04 +00:00
static const char * LICENSE =
2014-01-21 03:10:30 +00:00
" Copyright 2005-2014. All code is copyrighted by the respective authors. \n "
" \n "
2014-01-21 03:15:33 +00:00
" Transmission can be redistributed and/or modified under the terms of the "
2014-01-21 03:10:30 +00:00
" GNU GPL versions 2 or 3 or by any future license endorsed by Mnemosyne LLC. \n "
" \n "
" In addition, linking to and/or using OpenSSL is allowed. \n "
" \n "
2014-01-21 03:15:33 +00:00
" This program is distributed in the hope that it will be useful, "
" but WITHOUT ANY WARRANTY; without even the implied warranty of "
2014-01-21 03:10:30 +00:00
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \n "
" \n "
2014-01-21 03:15:33 +00:00
" Some of Transmission's source files have more permissive licenses. "
2014-01-21 03:10:30 +00:00
" Those files may, of course, be used on their own under their own terms. \n " ;
2007-06-09 15:20:32 +00:00
2008-01-28 22:18:43 +00:00
struct cbdata
{
2012-12-05 17:29:46 +00:00
char * config_dir ;
gboolean start_paused ;
gboolean is_iconified ;
2013-02-04 16:11:08 +00:00
gboolean is_closing ;
2012-12-05 17:29:46 +00:00
guint activation_count ;
guint timer ;
guint update_model_soon_tag ;
guint refresh_actions_tag ;
gpointer icon ;
GtkWindow * wind ;
TrCore * core ;
GtkWidget * msgwin ;
GtkWidget * prefs ;
GSList * error_list ;
GSList * duplicates_list ;
GSList * details ;
GtkTreeSelection * sel ;
2006-07-16 19:39:23 +00:00
} ;
2010-12-23 22:31:28 +00:00
static void
2012-12-05 17:29:46 +00:00
gtr_window_present ( GtkWindow * window )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
gtk_window_present_with_time ( window , gtk_get_current_event_time ( ) ) ;
2010-12-23 22:31:28 +00:00
}
/***
* * * *
* * * * DETAILS DIALOGS MANAGEMENT
* * * *
* * */
2009-12-08 20:34:46 +00:00
static int
2012-12-05 17:29:46 +00:00
compare_integers ( gconstpointer a , gconstpointer b )
2009-12-08 20:34:46 +00:00
{
2012-12-05 17:29:46 +00:00
return GPOINTER_TO_INT ( a ) - GPOINTER_TO_INT ( b ) ;
2009-12-08 20:34:46 +00:00
}
static char *
2012-12-05 17:29:46 +00:00
get_details_dialog_key ( GSList * id_list )
2009-12-08 20:34:46 +00:00
{
2012-12-05 17:29:46 +00:00
GSList * l ;
GSList * tmp = g_slist_sort ( g_slist_copy ( id_list ) , compare_integers ) ;
GString * gstr = g_string_new ( NULL ) ;
2009-12-08 20:34:46 +00:00
2012-12-05 17:29:46 +00:00
for ( l = tmp ; l ! = NULL ; l = l - > next )
g_string_append_printf ( gstr , " %d " , GPOINTER_TO_INT ( l - > data ) ) ;
2009-12-08 20:34:46 +00:00
2012-12-05 17:29:46 +00:00
g_slist_free ( tmp ) ;
return g_string_free ( gstr , FALSE ) ;
2009-12-08 20:34:46 +00:00
}
2011-08-13 05:47:32 +00:00
static void
2012-12-05 17:29:46 +00:00
get_selected_torrent_ids_foreach ( GtkTreeModel * model ,
2011-08-13 05:47:32 +00:00
GtkTreePath * p UNUSED ,
GtkTreeIter * iter ,
2012-12-05 17:29:46 +00:00
gpointer gdata )
2009-12-08 20:34:46 +00:00
{
2012-12-05 17:29:46 +00:00
int id ;
GSList * * ids = gdata ;
gtk_tree_model_get ( model , iter , MC_TORRENT_ID , & id , - 1 ) ;
* ids = g_slist_append ( * ids , GINT_TO_POINTER ( id ) ) ;
2011-08-13 05:47:32 +00:00
}
2009-12-08 20:34:46 +00:00
static GSList *
2012-12-05 17:29:46 +00:00
get_selected_torrent_ids ( struct cbdata * data )
2009-12-08 20:34:46 +00:00
{
2012-12-05 17:29:46 +00:00
GSList * ids = NULL ;
gtk_tree_selection_selected_foreach ( data - > sel ,
get_selected_torrent_ids_foreach ,
& ids ) ;
return ids ;
2009-12-08 20:34:46 +00:00
}
2010-12-23 22:31:28 +00:00
static void
2012-12-05 17:29:46 +00:00
on_details_dialog_closed ( gpointer gdata , GObject * dead )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * data = gdata ;
2010-12-23 22:31:28 +00:00
2012-12-05 17:29:46 +00:00
data - > details = g_slist_remove ( data - > details , dead ) ;
2010-12-23 22:31:28 +00:00
}
static void
2012-12-05 17:29:46 +00:00
show_details_dialog_for_selected_torrents ( struct cbdata * data )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * dialog = NULL ;
GSList * l ;
GSList * ids = get_selected_torrent_ids ( data ) ;
char * key = get_details_dialog_key ( ids ) ;
2011-08-13 05:47:32 +00:00
2012-12-05 17:29:46 +00:00
for ( l = data - > details ; dialog = = NULL & & l ! = NULL ; l = l - > next )
2013-02-14 15:17:42 +00:00
if ( ! g_strcmp0 ( key , g_object_get_data ( l - > data , " key " ) ) )
2012-12-05 17:29:46 +00:00
dialog = l - > data ;
2011-08-13 05:47:32 +00:00
2012-12-05 17:29:46 +00:00
if ( dialog = = NULL )
2011-08-13 05:47:32 +00:00
{
2012-12-05 17:29:46 +00:00
dialog = gtr_torrent_details_dialog_new ( GTK_WINDOW ( data - > wind ) , data - > core ) ;
gtr_torrent_details_dialog_set_torrents ( dialog , ids ) ;
g_object_set_data_full ( G_OBJECT ( dialog ) , " key " , g_strdup ( key ) , g_free ) ;
g_object_weak_ref ( G_OBJECT ( dialog ) , on_details_dialog_closed , data ) ;
data - > details = g_slist_append ( data - > details , dialog ) ;
gtk_widget_show ( dialog ) ;
2010-12-23 22:31:28 +00:00
}
2011-08-13 05:47:32 +00:00
2012-12-05 17:29:46 +00:00
gtr_window_present ( GTK_WINDOW ( dialog ) ) ;
g_free ( key ) ;
g_slist_free ( ids ) ;
2010-12-23 22:31:28 +00:00
}
/****
* * * * *
* * * * * ON SELECTION CHANGED
* * * * *
* * * */
struct counts_data
{
2012-12-05 17:29:46 +00:00
int total_count ;
int queued_count ;
int stopped_count ;
2010-12-23 22:31:28 +00:00
} ;
static void
2012-12-05 17:29:46 +00:00
get_selected_torrent_counts_foreach ( GtkTreeModel * model , GtkTreePath * path UNUSED ,
GtkTreeIter * iter , gpointer user_data )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
int activity = 0 ;
struct counts_data * counts = user_data ;
2010-12-23 22:31:28 +00:00
2012-12-05 17:29:46 +00:00
+ + counts - > total_count ;
2010-12-23 22:31:28 +00:00
2012-12-05 17:29:46 +00:00
gtk_tree_model_get ( model , iter , MC_ACTIVITY , & activity , - 1 ) ;
2010-12-23 22:31:28 +00:00
2012-12-05 17:29:46 +00:00
if ( ( activity = = TR_STATUS_DOWNLOAD_WAIT ) | | ( activity = = TR_STATUS_SEED_WAIT ) )
+ + counts - > queued_count ;
2011-08-01 22:24:24 +00:00
2012-12-05 17:29:46 +00:00
if ( activity = = TR_STATUS_STOPPED )
+ + counts - > stopped_count ;
2010-12-23 22:31:28 +00:00
}
static void
2012-12-05 17:29:46 +00:00
get_selected_torrent_counts ( struct cbdata * data , struct counts_data * counts )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
counts - > total_count = 0 ;
counts - > queued_count = 0 ;
counts - > stopped_count = 0 ;
2010-12-23 22:31:28 +00:00
2012-12-05 17:29:46 +00:00
gtk_tree_selection_selected_foreach ( data - > sel , get_selected_torrent_counts_foreach , counts ) ;
2010-12-23 22:31:28 +00:00
}
static void
2012-12-05 17:29:46 +00:00
count_updatable_foreach ( GtkTreeModel * model , GtkTreePath * path UNUSED ,
GtkTreeIter * iter , gpointer accumulated_status )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
tr_torrent * tor ;
gtk_tree_model_get ( model , iter , MC_TORRENT , & tor , - 1 ) ;
* ( int * ) accumulated_status | = tr_torrentCanManualUpdate ( tor ) ;
2010-12-23 22:31:28 +00:00
}
static gboolean
2012-12-05 17:29:46 +00:00
refresh_actions ( gpointer gdata )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * data = gdata ;
2013-02-04 18:34:39 +00:00
if ( ! data - > is_closing )
{
int canUpdate ;
struct counts_data sel_counts ;
const size_t total = gtr_core_get_torrent_count ( data - > core ) ;
const size_t active = gtr_core_get_active_torrent_count ( data - > core ) ;
const int torrent_count = gtk_tree_model_iter_n_children ( gtr_core_model ( data - > core ) , NULL ) ;
bool has_selection ;
get_selected_torrent_counts ( data , & sel_counts ) ;
has_selection = sel_counts . total_count > 0 ;
gtr_action_set_sensitive ( " select-all " , torrent_count ! = 0 ) ;
gtr_action_set_sensitive ( " deselect-all " , torrent_count ! = 0 ) ;
gtr_action_set_sensitive ( " pause-all-torrents " , active ! = 0 ) ;
gtr_action_set_sensitive ( " start-all-torrents " , active ! = total ) ;
gtr_action_set_sensitive ( " torrent-stop " , ( sel_counts . stopped_count < sel_counts . total_count ) ) ;
gtr_action_set_sensitive ( " torrent-start " , ( sel_counts . stopped_count ) > 0 ) ;
gtr_action_set_sensitive ( " torrent-start-now " , ( sel_counts . stopped_count + sel_counts . queued_count ) > 0 ) ;
gtr_action_set_sensitive ( " torrent-verify " , has_selection ) ;
gtr_action_set_sensitive ( " remove-torrent " , has_selection ) ;
gtr_action_set_sensitive ( " delete-torrent " , has_selection ) ;
gtr_action_set_sensitive ( " relocate-torrent " , has_selection ) ;
gtr_action_set_sensitive ( " queue-move-top " , has_selection ) ;
gtr_action_set_sensitive ( " queue-move-up " , has_selection ) ;
gtr_action_set_sensitive ( " queue-move-down " , has_selection ) ;
gtr_action_set_sensitive ( " queue-move-bottom " , has_selection ) ;
gtr_action_set_sensitive ( " show-torrent-properties " , has_selection ) ;
gtr_action_set_sensitive ( " open-torrent-folder " , sel_counts . total_count = = 1 ) ;
gtr_action_set_sensitive ( " copy-magnet-link-to-clipboard " , sel_counts . total_count = = 1 ) ;
canUpdate = 0 ;
gtk_tree_selection_selected_foreach ( data - > sel , count_updatable_foreach , & canUpdate ) ;
gtr_action_set_sensitive ( " torrent-reannounce " , canUpdate ! = 0 ) ;
}
2012-12-05 17:29:46 +00:00
data - > refresh_actions_tag = 0 ;
2013-01-04 16:36:52 +00:00
return G_SOURCE_REMOVE ;
2010-12-23 22:31:28 +00:00
}
static void
2012-12-05 17:29:46 +00:00
refresh_actions_soon ( gpointer gdata )
2010-12-23 22:31:28 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * data = gdata ;
2010-12-23 22:31:28 +00:00
2013-02-04 16:11:08 +00:00
if ( ! data - > is_closing & & ! data - > refresh_actions_tag )
2012-12-05 17:29:46 +00:00
data - > refresh_actions_tag = gdk_threads_add_idle ( refresh_actions , data ) ;
2010-12-23 22:31:28 +00:00
}
2011-07-30 13:28:03 +00:00
static void
2012-12-05 17:29:46 +00:00
on_selection_changed ( GtkTreeSelection * s UNUSED , gpointer gdata )
2011-07-30 13:28:03 +00:00
{
2012-12-05 17:29:46 +00:00
refresh_actions_soon ( gdata ) ;
2011-07-30 13:28:03 +00:00
}
2009-11-29 20:28:35 +00:00
/***
* * * *
* * */
2013-07-08 19:34:58 +00:00
static gboolean
has_magnet_link_handler ( void )
{
GAppInfo * app_info = g_app_info_get_default_for_uri_scheme ( " magnet " ) ;
const gboolean has_handler = app_info ! = NULL ;
g_clear_object ( & app_info ) ;
return has_handler ;
}
2009-11-29 20:28:35 +00:00
static void
2012-12-05 17:29:46 +00:00
register_magnet_link_handler ( void )
2009-11-29 20:28:35 +00:00
{
2013-07-08 19:34:58 +00:00
GError * error ;
GAppInfo * app ;
const char * const content_type = " x-scheme-handler/magnet " ;
error = NULL ;
app = g_app_info_create_from_commandline ( " transmission-gtk " ,
" transmission-gtk " ,
G_APP_INFO_CREATE_SUPPORTS_URIS ,
& error ) ;
g_app_info_set_as_default_for_type ( app , content_type , & error ) ;
if ( error ! = NULL )
2012-12-05 17:29:46 +00:00
{
2013-07-08 19:34:58 +00:00
g_warning ( _ ( " Error registering Transmission as a %s handler: %s " ) ,
content_type ,
error - > message ) ;
g_error_free ( error ) ;
2009-11-29 20:28:35 +00:00
}
2013-07-08 19:34:58 +00:00
g_clear_object ( & app ) ;
}
static void
ensure_magnet_handler_exists ( void )
{
if ( ! has_magnet_link_handler ( ) )
register_magnet_link_handler ( ) ;
2009-11-29 20:28:35 +00:00
}
2008-04-21 20:58:39 +00:00
static void
2012-12-05 17:29:46 +00:00
on_main_window_size_allocated ( GtkWidget * gtk_window ,
2011-03-03 01:59:25 +00:00
GtkAllocation * alloc UNUSED ,
2012-12-05 17:29:46 +00:00
gpointer gdata UNUSED )
2008-04-21 20:58:39 +00:00
{
2012-12-05 17:29:46 +00:00
GdkWindow * gdk_window = gtk_widget_get_window ( gtk_window ) ;
const gboolean isMaximized = ( gdk_window ! = NULL )
& & ( gdk_window_get_state ( gdk_window ) & GDK_WINDOW_STATE_MAXIMIZED ) ;
2008-04-21 20:58:39 +00:00
2012-12-22 20:35:19 +00:00
gtr_pref_int_set ( TR_KEY_main_window_is_maximized , isMaximized ) ;
2009-06-11 22:36:45 +00:00
2012-12-05 17:29:46 +00:00
if ( ! isMaximized )
2008-04-21 20:58:39 +00:00
{
2012-12-05 17:29:46 +00:00
int x , y , w , h ;
gtk_window_get_position ( GTK_WINDOW ( gtk_window ) , & x , & y ) ;
gtk_window_get_size ( GTK_WINDOW ( gtk_window ) , & w , & h ) ;
2012-12-22 20:35:19 +00:00
gtr_pref_int_set ( TR_KEY_main_window_x , x ) ;
gtr_pref_int_set ( TR_KEY_main_window_y , y ) ;
gtr_pref_int_set ( TR_KEY_main_window_width , w ) ;
gtr_pref_int_set ( TR_KEY_main_window_height , h ) ;
2008-04-21 20:58:39 +00:00
}
}
2011-03-03 01:59:25 +00:00
/***
* * * * listen to changes that come from RPC
* * */
2008-02-28 17:51:54 +00:00
2013-01-04 06:35:08 +00:00
struct on_rpc_changed_struct
2010-04-21 04:38:54 +00:00
{
2012-12-05 17:29:46 +00:00
TrCore * core ;
2013-01-04 06:35:08 +00:00
tr_rpc_callback_type type ;
int torrent_id ;
2010-04-21 04:38:54 +00:00
} ;
static gboolean
2013-01-04 06:35:08 +00:00
on_rpc_changed_idle ( gpointer gdata )
2011-02-05 05:03:00 +00:00
{
2012-12-05 17:29:46 +00:00
tr_torrent * tor ;
2013-01-04 06:35:08 +00:00
struct on_rpc_changed_struct * data = gdata ;
2012-12-05 17:29:46 +00:00
2013-01-04 06:35:08 +00:00
switch ( data - > type )
2012-12-05 17:29:46 +00:00
{
case TR_RPC_SESSION_CLOSE :
gtr_action_activate ( " quit " ) ;
break ;
2013-01-04 06:35:08 +00:00
case TR_RPC_TORRENT_ADDED :
if ( ( tor = gtr_core_find_torrent ( data - > core , data - > torrent_id ) ) )
gtr_core_add_torrent ( data - > core , tor , true ) ;
2012-12-05 17:29:46 +00:00
break ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
case TR_RPC_TORRENT_REMOVING :
2013-01-04 06:35:08 +00:00
gtr_core_remove_torrent ( data - > core , data - > torrent_id , false ) ;
break ;
case TR_RPC_TORRENT_TRASHING :
gtr_core_remove_torrent ( data - > core , data - > torrent_id , true ) ;
2012-12-05 17:29:46 +00:00
break ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
case TR_RPC_SESSION_CHANGED : {
int i ;
2012-12-14 04:34:42 +00:00
tr_variant tmp ;
tr_variant * newval ;
tr_variant * oldvals = gtr_pref_get_all ( ) ;
2012-12-22 20:35:19 +00:00
tr_quark key ;
2012-12-05 17:29:46 +00:00
GSList * l ;
GSList * changed_keys = NULL ;
2013-01-04 06:35:08 +00:00
tr_session * session = gtr_core_session ( data - > core ) ;
2012-12-14 04:34:42 +00:00
tr_variantInitDict ( & tmp , 100 ) ;
2012-12-05 17:29:46 +00:00
tr_sessionGetSettings ( session , & tmp ) ;
2012-12-14 04:34:42 +00:00
for ( i = 0 ; tr_variantDictChild ( & tmp , i , & key , & newval ) ; + + i )
2012-12-05 17:29:46 +00:00
{
bool changed ;
2012-12-14 04:34:42 +00:00
tr_variant * oldval = tr_variantDictFind ( oldvals , key ) ;
2012-12-05 17:29:46 +00:00
if ( ! oldval )
{
changed = true ;
}
else
{
2012-12-14 04:34:42 +00:00
char * a = tr_variantToStr ( oldval , TR_VARIANT_FMT_BENC , NULL ) ;
char * b = tr_variantToStr ( newval , TR_VARIANT_FMT_BENC , NULL ) ;
2013-02-14 15:17:42 +00:00
changed = g_strcmp0 ( a , b ) ! = 0 ;
2012-12-05 17:29:46 +00:00
tr_free ( b ) ;
tr_free ( a ) ;
}
if ( changed )
2012-12-22 20:35:19 +00:00
changed_keys = g_slist_append ( changed_keys , GINT_TO_POINTER ( key ) ) ;
2012-12-05 17:29:46 +00:00
}
tr_sessionGetSettings ( session , oldvals ) ;
for ( l = changed_keys ; l ! = NULL ; l = l - > next )
2013-01-04 06:35:08 +00:00
gtr_core_pref_changed ( data - > core , GPOINTER_TO_INT ( l - > data ) ) ;
2012-12-05 17:29:46 +00:00
g_slist_free ( changed_keys ) ;
2012-12-14 04:34:42 +00:00
tr_variantFree ( & tmp ) ;
2012-12-05 17:29:46 +00:00
break ;
}
2010-02-27 18:00:24 +00:00
2012-12-05 17:29:46 +00:00
case TR_RPC_TORRENT_CHANGED :
case TR_RPC_TORRENT_MOVED :
case TR_RPC_TORRENT_STARTED :
case TR_RPC_TORRENT_STOPPED :
case TR_RPC_SESSION_QUEUE_POSITIONS_CHANGED :
/* nothing interesting to do here */
break ;
2008-05-18 16:44:30 +00:00
}
2013-01-04 06:35:08 +00:00
g_free ( data ) ;
return G_SOURCE_REMOVE ;
}
static tr_rpc_callback_status
on_rpc_changed ( tr_session * session G_GNUC_UNUSED ,
tr_rpc_callback_type type ,
struct tr_torrent * tor ,
void * gdata )
{
struct cbdata * cbdata = gdata ;
struct on_rpc_changed_struct * data ;
data = g_new ( struct on_rpc_changed_struct , 1 ) ;
data - > core = cbdata - > core ;
data - > type = type ;
data - > torrent_id = tr_torrentId ( tor ) ;
gdk_threads_add_idle ( on_rpc_changed_idle , data ) ;
return TR_RPC_NOREMOVE ;
2008-05-18 16:44:30 +00:00
}
2011-03-03 01:59:25 +00:00
/***
* * * * signal handling
* * */
static sig_atomic_t global_sigcount = 0 ;
static struct cbdata * sighandler_cbdata = NULL ;
static void
2012-12-05 17:29:46 +00:00
signal_handler ( int sig )
2011-03-03 01:59:25 +00:00
{
2012-12-05 17:29:46 +00:00
if ( + + global_sigcount > 1 )
2011-03-03 01:59:25 +00:00
{
2012-12-05 17:29:46 +00:00
signal ( sig , SIG_DFL ) ;
raise ( sig ) ;
2011-03-03 01:59:25 +00:00
}
2012-12-05 17:29:46 +00:00
else if ( ( sig = = SIGINT ) | | ( sig = = SIGTERM ) )
2011-03-03 01:59:25 +00:00
{
2012-12-05 17:29:46 +00:00
g_message ( _ ( " Got signal %d; trying to shut down cleanly. Do it again if it gets stuck. " ) , sig ) ;
gtr_actions_handler ( " quit " , sighandler_cbdata ) ;
2011-03-03 01:59:25 +00:00
}
}
2011-08-09 02:30:31 +00:00
/****
* * * * *
* * * * *
* * * */
2012-12-05 17:29:46 +00:00
static void app_setup ( GtkWindow * wind , struct cbdata * cbdata ) ;
2011-08-13 05:52:36 +00:00
2011-03-03 01:59:25 +00:00
static void
2012-12-05 17:29:46 +00:00
on_startup ( GApplication * application , gpointer user_data )
2011-03-03 01:59:25 +00:00
{
2012-12-05 17:29:46 +00:00
GError * error ;
const char * str ;
GtkWindow * win ;
GtkUIManager * ui_manager ;
tr_session * session ;
struct cbdata * cbdata = user_data ;
signal ( SIGINT , signal_handler ) ;
signal ( SIGTERM , signal_handler ) ;
sighandler_cbdata = cbdata ;
/* ensure the directories are created */
2012-12-22 20:35:19 +00:00
if ( ( str = gtr_pref_string_get ( TR_KEY_download_dir ) ) )
2012-12-05 17:29:46 +00:00
g_mkdir_with_parents ( str , 0777 ) ;
2012-12-22 20:35:19 +00:00
if ( ( str = gtr_pref_string_get ( TR_KEY_incomplete_dir ) ) )
2012-12-05 17:29:46 +00:00
g_mkdir_with_parents ( str , 0777 ) ;
/* initialize the libtransmission session */
session = tr_sessionInit ( " gtk " , cbdata - > config_dir , TRUE , gtr_pref_get_all ( ) ) ;
2012-12-22 20:35:19 +00:00
gtr_pref_flag_set ( TR_KEY_alt_speed_enabled , tr_sessionUsesAltSpeed ( session ) ) ;
gtr_pref_int_set ( TR_KEY_peer_port , tr_sessionGetPeerPort ( session ) ) ;
2012-12-05 17:29:46 +00:00
cbdata - > core = gtr_core_new ( session ) ;
/* init the ui manager */
error = NULL ;
ui_manager = gtk_ui_manager_new ( ) ;
gtr_actions_init ( ui_manager , cbdata ) ;
gtk_ui_manager_add_ui_from_resource ( ui_manager , TR_RESOURCE_PATH " transmission-ui.xml " , & error ) ;
g_assert_no_error ( error ) ;
gtk_ui_manager_ensure_update ( ui_manager ) ;
/* create main window now to be a parent to any error dialogs */
win = GTK_WINDOW ( gtr_window_new ( GTK_APPLICATION ( application ) , ui_manager , cbdata - > core ) ) ;
g_signal_connect ( win , " size-allocate " , G_CALLBACK ( on_main_window_size_allocated ) , cbdata ) ;
g_application_hold ( application ) ;
g_object_weak_ref ( G_OBJECT ( win ) , ( GWeakNotify ) g_application_release , application ) ;
app_setup ( win , cbdata ) ;
tr_sessionSetRPCCallback ( session , on_rpc_changed , cbdata ) ;
/* check & see if it's time to update the blocklist */
2012-12-22 20:35:19 +00:00
if ( gtr_pref_flag_get ( TR_KEY_blocklist_enabled ) )
2012-12-05 17:29:46 +00:00
{
2012-12-22 20:35:19 +00:00
if ( gtr_pref_flag_get ( TR_KEY_blocklist_updates_enabled ) )
2012-12-05 17:29:46 +00:00
{
2012-12-22 20:35:19 +00:00
const int64_t last_time = gtr_pref_int_get ( TR_KEY_blocklist_date ) ;
2012-12-05 17:29:46 +00:00
const int SECONDS_IN_A_WEEK = 7 * 24 * 60 * 60 ;
const time_t now = time ( NULL ) ;
if ( last_time + SECONDS_IN_A_WEEK < now )
gtr_core_blocklist_update ( cbdata - > core ) ;
}
2011-08-09 02:30:31 +00:00
}
2011-03-03 01:59:25 +00:00
2012-12-05 17:29:46 +00:00
/* if there's no magnet link handler registered, register us */
2013-07-08 19:34:58 +00:00
ensure_magnet_handler_exists ( ) ;
2011-08-09 02:30:31 +00:00
}
static void
2012-12-05 17:29:46 +00:00
on_activate ( GApplication * app UNUSED , struct cbdata * cbdata )
2009-12-18 05:56:41 +00:00
{
2012-12-05 17:29:46 +00:00
cbdata - > activation_count + + ;
2011-10-30 18:27:45 +00:00
2012-12-05 17:29:46 +00:00
/* GApplication emits an 'activate' signal when bootstrapping the primary.
* Ordinarily we handle that by presenting the main window , but if the user
* user started Transmission minimized , ignore that initial signal . . . */
if ( cbdata - > is_iconified & & ( cbdata - > activation_count = = 1 ) )
return ;
2011-10-30 18:27:45 +00:00
2012-12-05 17:29:46 +00:00
gtr_action_activate ( " present-main-window " ) ;
2011-08-09 02:30:31 +00:00
}
2009-12-18 05:56:41 +00:00
2011-08-09 02:30:31 +00:00
static void
2012-12-05 17:29:46 +00:00
open_files ( GSList * files , gpointer gdata )
2011-08-09 02:30:31 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * cbdata = gdata ;
2012-12-22 20:35:19 +00:00
const gboolean do_start = gtr_pref_flag_get ( TR_KEY_start_added_torrents ) & & ! cbdata - > start_paused ;
const gboolean do_prompt = gtr_pref_flag_get ( TR_KEY_show_options_window ) ;
2012-12-05 17:29:46 +00:00
const gboolean do_notify = TRUE ;
2011-06-24 18:16:12 +00:00
2012-12-05 17:29:46 +00:00
gtr_core_add_files ( cbdata - > core , files , do_start , do_prompt , do_notify ) ;
2011-08-09 02:30:31 +00:00
}
2011-06-24 18:16:12 +00:00
2011-08-09 02:30:31 +00:00
static void
on_open ( GApplication * application UNUSED ,
GFile * * f ,
gint file_count ,
gchar * hint UNUSED ,
2012-12-05 17:29:46 +00:00
gpointer gdata )
2011-08-09 02:30:31 +00:00
{
2012-12-05 17:29:46 +00:00
int i ;
GSList * files = NULL ;
2011-06-24 18:16:12 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < file_count ; i + + )
files = g_slist_prepend ( files , f [ i ] ) ;
2009-12-18 05:56:41 +00:00
2012-12-05 17:29:46 +00:00
open_files ( files , gdata ) ;
2009-12-18 05:56:41 +00:00
2012-12-05 17:29:46 +00:00
g_slist_free ( files ) ;
2009-12-18 05:56:41 +00:00
}
2011-08-09 02:30:31 +00:00
/***
* * * *
* * */
2011-04-13 06:18:30 +00:00
2006-07-16 19:39:23 +00:00
int
2012-12-05 17:29:46 +00:00
main ( int argc , char * * argv )
2007-02-19 22:09:05 +00:00
{
2012-12-05 17:29:46 +00:00
int ret ;
struct stat sb ;
char * application_id ;
GtkApplication * app ;
GOptionContext * option_context ;
bool show_version = false ;
GError * error = NULL ;
struct cbdata cbdata ;
GOptionEntry option_entries [ ] = {
{ " config-dir " , ' g ' , 0 , G_OPTION_ARG_FILENAME , & cbdata . config_dir , _ ( " Where to look for configuration files " ) , NULL } ,
{ " paused " , ' p ' , 0 , G_OPTION_ARG_NONE , & cbdata . start_paused , _ ( " Start with all torrents paused " ) , NULL } ,
{ " minimized " , ' m ' , 0 , G_OPTION_ARG_NONE , & cbdata . is_iconified , _ ( " Start minimized in notification area " ) , NULL } ,
{ " version " , ' v ' , 0 , G_OPTION_ARG_NONE , & show_version , _ ( " Show version number and exit " ) , NULL } ,
{ NULL , 0 , 0 , 0 , NULL , NULL , NULL }
} ;
/* default settings */
memset ( & cbdata , 0 , sizeof ( struct cbdata ) ) ;
cbdata . config_dir = ( char * ) tr_getDefaultConfigDir ( MY_CONFIG_NAME ) ;
/* init i18n */
setlocale ( LC_ALL , " " ) ;
bindtextdomain ( MY_READABLE_NAME , TRANSMISSIONLOCALEDIR ) ;
bind_textdomain_codeset ( MY_READABLE_NAME , " UTF-8 " ) ;
textdomain ( MY_READABLE_NAME ) ;
/* init glib/gtk */
2013-01-25 23:34:20 +00:00
# if !GLIB_CHECK_VERSION(2,35,4)
2012-12-05 17:29:46 +00:00
g_type_init ( ) ;
2013-01-25 23:34:20 +00:00
# endif
2012-12-05 17:29:46 +00:00
gtk_init ( & argc , & argv ) ;
g_set_application_name ( _ ( " Transmission " ) ) ;
gtk_window_set_default_icon_name ( MY_CONFIG_NAME ) ;
/* parse the command line */
option_context = g_option_context_new ( _ ( " [torrent files or urls] " ) ) ;
g_option_context_add_main_entries ( option_context , option_entries , GETTEXT_PACKAGE ) ;
g_option_context_set_translation_domain ( option_context , GETTEXT_PACKAGE ) ;
if ( ! g_option_context_parse ( option_context , & argc , & argv , & error ) )
{
g_print ( _ ( " %s \n Run '%s --help' to see a full list of available command line options. \n " ) , error - > message , argv [ 0 ] ) ;
g_error_free ( error ) ;
g_option_context_free ( option_context ) ;
return 1 ;
}
g_option_context_free ( option_context ) ;
/* handle the trivial "version" option */
if ( show_version )
{
fprintf ( stderr , " %s %s \n " , MY_READABLE_NAME , LONG_VERSION_STRING ) ;
return 0 ;
}
/* init the unit formatters */
tr_formatter_mem_init ( mem_K , _ ( mem_K_str ) , _ ( mem_M_str ) , _ ( mem_G_str ) , _ ( mem_T_str ) ) ;
tr_formatter_size_init ( disk_K , _ ( disk_K_str ) , _ ( disk_M_str ) , _ ( disk_G_str ) , _ ( disk_T_str ) ) ;
tr_formatter_speed_init ( speed_K , _ ( speed_K_str ) , _ ( speed_M_str ) , _ ( speed_G_str ) , _ ( speed_T_str ) ) ;
/* set up the config dir */
gtr_pref_init ( cbdata . config_dir ) ;
g_mkdir_with_parents ( cbdata . config_dir , 0755 ) ;
/* init notifications */
gtr_notify_init ( ) ;
/* init the application for the specified config dir */
stat ( cbdata . config_dir , & sb ) ;
application_id = g_strdup_printf ( " com.transmissionbt.transmission_%lu_%lu " , ( unsigned long ) sb . st_dev , ( unsigned long ) sb . st_ino ) ;
app = gtk_application_new ( application_id , G_APPLICATION_HANDLES_OPEN ) ;
g_signal_connect ( app , " open " , G_CALLBACK ( on_open ) , & cbdata ) ;
g_signal_connect ( app , " startup " , G_CALLBACK ( on_startup ) , & cbdata ) ;
g_signal_connect ( app , " activate " , G_CALLBACK ( on_activate ) , & cbdata ) ;
ret = g_application_run ( G_APPLICATION ( app ) , argc , argv ) ;
g_object_unref ( app ) ;
g_free ( application_id ) ;
return ret ;
2007-02-19 22:09:05 +00:00
}
2006-07-16 19:39:23 +00:00
2010-06-26 15:55:19 +00:00
static void
2012-12-05 17:29:46 +00:00
on_core_busy ( TrCore * core UNUSED , gboolean busy , struct cbdata * c )
2010-06-26 15:55:19 +00:00
{
2012-12-05 17:29:46 +00:00
gtr_window_set_busy ( c - > wind , busy ) ;
2010-06-26 15:55:19 +00:00
}
2012-12-05 17:29:46 +00:00
static void on_core_error ( TrCore * , guint , const char * , struct cbdata * ) ;
static void on_add_torrent ( TrCore * , tr_ctor * , gpointer ) ;
2012-12-22 20:35:19 +00:00
static void on_prefs_changed ( TrCore * core , const tr_quark key , gpointer ) ;
2012-12-05 17:29:46 +00:00
static void main_window_setup ( struct cbdata * cbdata , GtkWindow * wind ) ;
static gboolean update_model_loop ( gpointer gdata ) ;
static gboolean update_model_once ( gpointer gdata ) ;
2011-08-13 05:52:36 +00:00
2007-02-19 22:09:05 +00:00
static void
2012-12-05 17:29:46 +00:00
app_setup ( GtkWindow * wind , struct cbdata * cbdata )
2007-02-19 22:09:05 +00:00
{
2012-12-05 17:29:46 +00:00
if ( cbdata - > is_iconified )
2012-12-22 20:35:19 +00:00
gtr_pref_flag_set ( TR_KEY_show_notification_area_icon , TRUE ) ;
2012-12-05 17:29:46 +00:00
gtr_actions_set_core ( cbdata - > core ) ;
/* set up core handlers */
g_signal_connect ( cbdata - > core , " busy " , G_CALLBACK ( on_core_busy ) , cbdata ) ;
g_signal_connect ( cbdata - > core , " add-error " , G_CALLBACK ( on_core_error ) , cbdata ) ;
g_signal_connect ( cbdata - > core , " add-prompt " , G_CALLBACK ( on_add_torrent ) , cbdata ) ;
g_signal_connect ( cbdata - > core , " prefs-changed " , G_CALLBACK ( on_prefs_changed ) , cbdata ) ;
/* add torrents from command-line and saved state */
gtr_core_load ( cbdata - > core , cbdata - > start_paused ) ;
gtr_core_torrents_added ( cbdata - > core ) ;
/* set up main window */
main_window_setup ( cbdata , wind ) ;
/* set up the icon */
2012-12-22 20:35:19 +00:00
on_prefs_changed ( cbdata - > core , TR_KEY_show_notification_area_icon , cbdata ) ;
2012-12-05 17:29:46 +00:00
/* start model update timer */
cbdata - > timer = gdk_threads_add_timeout_seconds ( MAIN_WINDOW_REFRESH_INTERVAL_SECONDS , update_model_loop , cbdata ) ;
update_model_once ( cbdata ) ;
/* either show the window or iconify it */
if ( ! cbdata - > is_iconified )
{
gtk_widget_show ( GTK_WIDGET ( wind ) ) ;
}
else
{
gtk_window_set_skip_taskbar_hint ( cbdata - > wind ,
cbdata - > icon ! = NULL ) ;
cbdata - > is_iconified = FALSE ; // ensure that the next toggle iconifies
gtr_action_set_toggled ( " toggle-main-window " , FALSE ) ;
}
2012-12-22 20:35:19 +00:00
if ( ! gtr_pref_flag_get ( TR_KEY_user_has_given_informed_consent ) )
2012-12-05 17:29:46 +00:00
{
GtkWidget * w = gtk_message_dialog_new ( GTK_WINDOW ( wind ) ,
GTK_DIALOG_DESTROY_WITH_PARENT ,
2013-01-16 20:55:08 +00:00
GTK_MESSAGE_OTHER ,
2012-12-05 17:29:46 +00:00
GTK_BUTTONS_NONE ,
" %s " ,
2013-01-16 20:55:08 +00:00
_ ( " Transmission is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility. " ) ) ;
gtk_dialog_add_button ( GTK_DIALOG ( w ) , GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT ) ;
gtk_dialog_add_button ( GTK_DIALOG ( w ) , _ ( " I _Agree " ) , GTK_RESPONSE_ACCEPT ) ;
2012-12-05 17:29:46 +00:00
gtk_dialog_set_default_response ( GTK_DIALOG ( w ) , GTK_RESPONSE_ACCEPT ) ;
switch ( gtk_dialog_run ( GTK_DIALOG ( w ) ) )
{
case GTK_RESPONSE_ACCEPT :
/* only show it once */
2012-12-22 20:35:19 +00:00
gtr_pref_flag_set ( TR_KEY_user_has_given_informed_consent , TRUE ) ;
2012-12-05 17:29:46 +00:00
gtk_widget_destroy ( w ) ;
break ;
default :
exit ( 0 ) ;
2009-10-02 21:03:55 +00:00
}
}
2008-02-03 01:43:47 +00:00
}
static void
2012-12-05 17:29:46 +00:00
presentMainWindow ( struct cbdata * cbdata )
2008-02-03 01:43:47 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWindow * window = cbdata - > wind ;
2008-02-07 01:10:34 +00:00
2012-12-05 17:29:46 +00:00
if ( cbdata - > is_iconified )
2008-02-07 01:10:34 +00:00
{
2012-12-05 17:29:46 +00:00
cbdata - > is_iconified = false ;
2011-08-07 16:42:38 +00:00
2012-12-05 17:29:46 +00:00
gtk_window_set_skip_taskbar_hint ( window , FALSE ) ;
2008-02-07 01:10:34 +00:00
}
2011-08-07 16:42:38 +00:00
2012-12-05 17:29:46 +00:00
if ( ! gtk_widget_get_visible ( GTK_WIDGET ( window ) ) )
2008-02-07 01:10:34 +00:00
{
2012-12-22 20:35:19 +00:00
gtk_window_resize ( window , gtr_pref_int_get ( TR_KEY_main_window_width ) ,
gtr_pref_int_get ( TR_KEY_main_window_height ) ) ;
gtk_window_move ( window , gtr_pref_int_get ( TR_KEY_main_window_x ) ,
gtr_pref_int_get ( TR_KEY_main_window_y ) ) ;
2012-12-05 17:29:46 +00:00
gtr_widget_set_visible ( GTK_WIDGET ( window ) , TRUE ) ;
2010-07-11 06:46:46 +00:00
}
2012-12-05 17:29:46 +00:00
gtr_window_present ( window ) ;
2013-01-04 23:25:17 +00:00
gdk_window_raise ( gtk_widget_get_window ( GTK_WIDGET ( window ) ) ) ;
2011-08-07 16:42:38 +00:00
}
static void
2012-12-05 17:29:46 +00:00
hideMainWindow ( struct cbdata * cbdata )
2011-08-07 16:42:38 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWindow * window = cbdata - > wind ;
gtk_window_set_skip_taskbar_hint ( window , TRUE ) ;
gtr_widget_set_visible ( GTK_WIDGET ( window ) , FALSE ) ;
cbdata - > is_iconified = true ;
2011-08-07 16:42:38 +00:00
}
static void
2012-12-05 17:29:46 +00:00
toggleMainWindow ( struct cbdata * cbdata )
2011-08-07 16:42:38 +00:00
{
2012-12-05 17:29:46 +00:00
if ( cbdata - > is_iconified )
presentMainWindow ( cbdata ) ;
else
hideMainWindow ( cbdata ) ;
2010-07-11 06:46:46 +00:00
}
2012-12-05 17:29:46 +00:00
static void on_app_exit ( gpointer vdata ) ;
2011-08-13 05:52:36 +00:00
2007-06-18 03:40:41 +00:00
static gboolean
2012-12-05 17:29:46 +00:00
winclose ( GtkWidget * w UNUSED ,
2008-09-23 19:11:04 +00:00
GdkEvent * event UNUSED ,
2012-12-05 17:29:46 +00:00
gpointer gdata )
2007-02-07 07:35:33 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * cbdata = gdata ;
2007-02-19 22:09:05 +00:00
2012-12-05 17:29:46 +00:00
if ( cbdata - > icon ! = NULL )
gtr_action_activate ( " toggle-main-window " ) ;
else
on_app_exit ( cbdata ) ;
2007-02-19 22:09:05 +00:00
2012-12-05 17:29:46 +00:00
return TRUE ; /* don't propagate event further */
2007-02-19 22:09:05 +00:00
}
static void
2012-12-05 17:29:46 +00:00
rowChangedCB ( GtkTreeModel * model UNUSED ,
2008-12-03 05:15:17 +00:00
GtkTreePath * path ,
2008-09-23 19:11:04 +00:00
GtkTreeIter * iter UNUSED ,
2012-12-05 17:29:46 +00:00
gpointer gdata )
2007-02-19 22:09:05 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * data = gdata ;
2011-07-30 13:28:03 +00:00
2012-12-05 17:29:46 +00:00
if ( gtk_tree_selection_path_is_selected ( data - > sel , path ) )
refresh_actions_soon ( data ) ;
2007-02-19 22:09:05 +00:00
}
static void
2012-12-05 17:29:46 +00:00
on_drag_data_received ( GtkWidget * widget UNUSED ,
2010-08-02 22:31:31 +00:00
GdkDragContext * drag_context ,
gint x UNUSED ,
gint y UNUSED ,
GtkSelectionData * selection_data ,
guint info UNUSED ,
guint time_ ,
2012-12-05 17:29:46 +00:00
gpointer gdata )
2007-02-19 22:09:05 +00:00
{
2012-12-05 17:29:46 +00:00
guint i ;
char * * uris = gtk_selection_data_get_uris ( selection_data ) ;
const guint file_count = g_strv_length ( uris ) ;
GSList * files = NULL ;
2010-08-02 22:31:31 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < file_count ; + + i )
files = g_slist_prepend ( files , g_file_new_for_uri ( uris [ i ] ) ) ;
2010-08-02 22:31:31 +00:00
2012-12-05 17:29:46 +00:00
open_files ( files , gdata ) ;
2010-08-02 22:31:31 +00:00
2012-12-05 17:29:46 +00:00
/* cleanup */
g_slist_foreach ( files , ( GFunc ) g_object_unref , NULL ) ;
g_slist_free ( files ) ;
g_strfreev ( uris ) ;
2011-08-09 02:30:31 +00:00
2012-12-05 17:29:46 +00:00
gtk_drag_finish ( drag_context , true , FALSE , time_ ) ;
2010-08-02 22:31:31 +00:00
}
static void
2012-12-05 17:29:46 +00:00
main_window_setup ( struct cbdata * cbdata , GtkWindow * wind )
2010-08-02 22:31:31 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * w ;
GtkTreeModel * model ;
GtkTreeSelection * sel ;
g_assert ( NULL = = cbdata - > wind ) ;
cbdata - > wind = wind ;
cbdata - > sel = sel = GTK_TREE_SELECTION ( gtr_window_get_selection ( cbdata - > wind ) ) ;
g_signal_connect ( sel , " changed " , G_CALLBACK ( on_selection_changed ) , cbdata ) ;
on_selection_changed ( sel , cbdata ) ;
model = gtr_core_model ( cbdata - > core ) ;
g_signal_connect ( model , " row-changed " , G_CALLBACK ( rowChangedCB ) , cbdata ) ;
g_signal_connect ( wind , " delete-event " , G_CALLBACK ( winclose ) , cbdata ) ;
refresh_actions ( cbdata ) ;
/* register to handle URIs that get dragged onto our main window */
w = GTK_WIDGET ( wind ) ;
gtk_drag_dest_set ( w , GTK_DEST_DEFAULT_ALL , NULL , 0 , GDK_ACTION_COPY ) ;
gtk_drag_dest_add_uri_targets ( w ) ;
g_signal_connect ( w , " drag-data-received " , G_CALLBACK ( on_drag_data_received ) , cbdata ) ;
2006-07-16 19:39:23 +00:00
}
2009-11-30 04:58:03 +00:00
static gboolean
2012-12-05 17:29:46 +00:00
on_session_closed ( gpointer gdata )
2007-02-19 22:09:05 +00:00
{
2012-12-05 17:29:46 +00:00
GSList * tmp ;
struct cbdata * cbdata = gdata ;
tmp = g_slist_copy ( cbdata - > details ) ;
g_slist_foreach ( tmp , ( GFunc ) gtk_widget_destroy , NULL ) ;
g_slist_free ( tmp ) ;
if ( cbdata - > prefs )
gtk_widget_destroy ( GTK_WIDGET ( cbdata - > prefs ) ) ;
if ( cbdata - > wind )
gtk_widget_destroy ( GTK_WIDGET ( cbdata - > wind ) ) ;
g_object_unref ( cbdata - > core ) ;
if ( cbdata - > icon )
g_object_unref ( cbdata - > icon ) ;
g_slist_foreach ( cbdata - > error_list , ( GFunc ) g_free , NULL ) ;
g_slist_free ( cbdata - > error_list ) ;
g_slist_foreach ( cbdata - > duplicates_list , ( GFunc ) g_free , NULL ) ;
g_slist_free ( cbdata - > duplicates_list ) ;
2013-01-04 16:36:52 +00:00
return G_SOURCE_REMOVE ;
2009-11-30 04:58:03 +00:00
}
2013-01-04 06:57:39 +00:00
struct session_close_struct
{
tr_session * session ;
struct cbdata * cbdata ;
} ;
/* since tr_sessionClose () is a blocking function,
* delegate its call to another thread here . . . when it ' s done ,
* punt the GUI teardown back to the GTK + thread */
2009-11-30 04:58:03 +00:00
static gpointer
2012-12-05 17:29:46 +00:00
session_close_threadfunc ( gpointer gdata )
2009-11-30 04:58:03 +00:00
{
2013-01-04 06:57:39 +00:00
struct session_close_struct * data = gdata ;
tr_sessionClose ( data - > session ) ;
gdk_threads_add_idle ( on_session_closed , data - > cbdata ) ;
g_free ( data ) ;
2012-12-05 17:29:46 +00:00
return NULL ;
2007-11-09 16:11:10 +00:00
}
2007-12-14 18:36:19 +00:00
static void
2012-12-05 17:29:46 +00:00
exit_now_cb ( GtkWidget * w UNUSED , gpointer data UNUSED )
2007-12-14 18:36:19 +00:00
{
2012-12-05 17:29:46 +00:00
exit ( 0 ) ;
2007-12-14 18:36:19 +00:00
}
2007-11-09 16:11:10 +00:00
static void
2012-12-05 17:29:46 +00:00
on_app_exit ( gpointer vdata )
2007-11-09 16:11:10 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * r , * p , * b , * w , * c ;
2013-02-04 16:11:08 +00:00
struct cbdata * cbdata = vdata ;
2013-01-04 06:57:39 +00:00
struct session_close_struct * session_close_data ;
2007-11-09 16:11:10 +00:00
2013-08-05 02:39:30 +00:00
if ( cbdata - > is_closing )
return ;
2013-02-04 16:11:08 +00:00
cbdata - > is_closing = true ;
2012-12-05 17:29:46 +00:00
/* stop the update timer */
if ( cbdata - > timer )
2008-09-23 19:11:04 +00:00
{
2012-12-05 17:29:46 +00:00
g_source_remove ( cbdata - > timer ) ;
cbdata - > timer = 0 ;
2007-11-09 16:11:10 +00:00
}
2013-02-04 16:11:08 +00:00
/* stop the refresh-actions timer */
if ( cbdata - > refresh_actions_tag )
{
g_source_remove ( cbdata - > refresh_actions_tag ) ;
cbdata - > refresh_actions_tag = 0 ;
}
2012-12-05 17:29:46 +00:00
c = GTK_WIDGET ( cbdata - > wind ) ;
gtk_container_remove ( GTK_CONTAINER ( c ) , gtk_bin_get_child ( GTK_BIN ( c ) ) ) ;
2007-12-14 18:36:19 +00:00
2012-12-05 17:29:46 +00:00
r = gtk_alignment_new ( 0.5 , 0.5 , 0.01 , 0.01 ) ;
gtk_container_add ( GTK_CONTAINER ( c ) , r ) ;
2007-12-14 18:36:19 +00:00
2012-12-05 17:29:46 +00:00
p = gtk_grid_new ( ) ;
gtk_grid_set_column_spacing ( GTK_GRID ( p ) , GUI_PAD_BIG ) ;
gtk_container_add ( GTK_CONTAINER ( r ) , p ) ;
2007-12-14 18:36:19 +00:00
2012-12-05 17:29:46 +00:00
w = gtk_image_new_from_stock ( GTK_STOCK_NETWORK , GTK_ICON_SIZE_DIALOG ) ;
gtk_grid_attach ( GTK_GRID ( p ) , w , 0 , 0 , 1 , 2 ) ;
2007-12-14 18:36:19 +00:00
2012-12-05 17:29:46 +00:00
w = gtk_label_new ( NULL ) ;
gtk_label_set_markup ( GTK_LABEL ( w ) , _ ( " <b>Closing Connections</b> " ) ) ;
gtk_misc_set_alignment ( GTK_MISC ( w ) , 0.0 , 0.5 ) ;
gtk_grid_attach ( GTK_GRID ( p ) , w , 1 , 0 , 1 , 1 ) ;
2008-03-13 20:47:58 +00:00
2012-12-05 17:29:46 +00:00
w = gtk_label_new ( _ ( " Sending upload/download totals to tracker… " ) ) ;
gtk_misc_set_alignment ( GTK_MISC ( w ) , 0.0 , 0.5 ) ;
gtk_grid_attach ( GTK_GRID ( p ) , w , 1 , 1 , 1 , 1 ) ;
2007-12-14 18:36:19 +00:00
2012-12-05 17:29:46 +00:00
b = gtk_alignment_new ( 0.0 , 1.0 , 0.01 , 0.01 ) ;
w = gtk_button_new_with_mnemonic ( _ ( " _Quit Now " ) ) ;
g_signal_connect ( w , " clicked " , G_CALLBACK ( exit_now_cb ) , NULL ) ;
gtk_container_add ( GTK_CONTAINER ( b ) , w ) ;
gtk_grid_attach ( GTK_GRID ( p ) , b , 1 , 2 , 1 , 1 ) ;
2007-12-14 18:36:19 +00:00
2012-12-05 17:29:46 +00:00
gtk_widget_show_all ( r ) ;
gtk_widget_grab_focus ( w ) ;
2007-11-29 02:32:10 +00:00
2012-12-05 17:29:46 +00:00
/* clear the UI */
gtr_core_clear ( cbdata - > core ) ;
2007-11-29 02:32:10 +00:00
2012-12-05 17:29:46 +00:00
/* ensure the window is in its previous position & size.
* this seems to be necessary because changing the main window ' s
* child seems to unset the size */
2012-12-22 20:35:19 +00:00
gtk_window_resize ( cbdata - > wind , gtr_pref_int_get ( TR_KEY_main_window_width ) ,
gtr_pref_int_get ( TR_KEY_main_window_height ) ) ;
gtk_window_move ( cbdata - > wind , gtr_pref_int_get ( TR_KEY_main_window_x ) ,
gtr_pref_int_get ( TR_KEY_main_window_y ) ) ;
2009-06-11 22:36:45 +00:00
2012-12-05 17:29:46 +00:00
/* shut down libT */
2013-01-04 06:57:39 +00:00
session_close_data = g_new ( struct session_close_struct , 1 ) ;
session_close_data - > cbdata = cbdata ;
session_close_data - > session = gtr_core_close ( cbdata - > core ) ;
g_thread_new ( " shutdown-thread " , session_close_threadfunc , session_close_data ) ;
2006-07-16 19:39:23 +00:00
}
2008-07-09 16:33:00 +00:00
static void
2012-12-05 17:29:46 +00:00
show_torrent_errors ( GtkWindow * window , const char * primary , GSList * * files )
2008-07-09 16:33:00 +00:00
{
2012-12-05 17:29:46 +00:00
GSList * l ;
GtkWidget * w ;
GString * s = g_string_new ( NULL ) ;
const char * leader = g_slist_length ( * files ) > 1
? gtr_get_unicode_string ( GTR_UNICODE_BULLET )
: " " ;
for ( l = * files ; l ! = NULL ; l = l - > next )
g_string_append_printf ( s , " %s %s \n " , leader , ( const char * ) l - > data ) ;
w = gtk_message_dialog_new ( window ,
GTK_DIALOG_DESTROY_WITH_PARENT ,
GTK_MESSAGE_ERROR ,
GTK_BUTTONS_CLOSE ,
" %s " , primary ) ;
gtk_message_dialog_format_secondary_text ( GTK_MESSAGE_DIALOG ( w ) ,
" %s " , s - > str ) ;
g_signal_connect_swapped ( w , " response " ,
G_CALLBACK ( gtk_widget_destroy ) , w ) ;
gtk_widget_show ( w ) ;
g_string_free ( s , TRUE ) ;
g_slist_foreach ( * files , ( GFunc ) g_free , NULL ) ;
g_slist_free ( * files ) ;
* files = NULL ;
2008-07-09 16:33:00 +00:00
}
static void
2012-12-05 17:29:46 +00:00
flush_torrent_errors ( struct cbdata * cbdata )
2008-07-09 16:33:00 +00:00
{
2012-12-05 17:29:46 +00:00
if ( cbdata - > error_list )
show_torrent_errors ( cbdata - > wind ,
ngettext ( " Couldn't add corrupt torrent " ,
" Couldn't add corrupt torrents " ,
g_slist_length ( cbdata - > error_list ) ) ,
& cbdata - > error_list ) ;
if ( cbdata - > duplicates_list )
show_torrent_errors ( cbdata - > wind ,
ngettext ( " Couldn't add duplicate torrent " ,
" Couldn't add duplicate torrents " ,
g_slist_length ( cbdata - > duplicates_list ) ) ,
& cbdata - > duplicates_list ) ;
2008-07-09 16:33:00 +00:00
}
2007-05-23 17:59:35 +00:00
static void
2012-12-05 17:29:46 +00:00
on_core_error ( TrCore * core UNUSED , guint code , const char * msg , struct cbdata * c )
2007-05-23 17:59:35 +00:00
{
2012-12-05 17:29:46 +00:00
switch ( code )
2007-05-23 17:59:35 +00:00
{
2012-12-05 17:29:46 +00:00
case TR_PARSE_ERR :
c - > error_list = g_slist_append ( c - > error_list , g_path_get_basename ( msg ) ) ;
break ;
2008-07-09 16:33:00 +00:00
2012-12-05 17:29:46 +00:00
case TR_PARSE_DUPLICATE :
c - > duplicates_list = g_slist_append ( c - > duplicates_list , g_strdup ( msg ) ) ;
break ;
2008-07-09 16:33:00 +00:00
2012-12-05 17:29:46 +00:00
case TR_CORE_ERR_NO_MORE_TORRENTS :
flush_torrent_errors ( c ) ;
break ;
2008-07-09 16:33:00 +00:00
2012-12-05 17:29:46 +00:00
default :
g_assert_not_reached ( ) ;
break ;
2007-05-23 17:59:35 +00:00
}
}
2011-01-25 04:26:10 +00:00
static gboolean
2012-12-05 17:29:46 +00:00
on_main_window_focus_in ( GtkWidget * widget UNUSED ,
2008-09-23 19:11:04 +00:00
GdkEventFocus * event UNUSED ,
2012-12-05 17:29:46 +00:00
gpointer gdata )
2008-02-19 05:52:37 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * cbdata = gdata ;
if ( cbdata - > wind )
gtk_window_set_urgency_hint ( cbdata - > wind , FALSE ) ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
return FALSE ;
2008-02-19 05:52:37 +00:00
}
2008-09-23 19:11:04 +00:00
2008-02-13 03:00:21 +00:00
static void
2012-12-05 17:29:46 +00:00
on_add_torrent ( TrCore * core , tr_ctor * ctor , gpointer gdata )
2007-05-24 10:37:07 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * cbdata = gdata ;
GtkWidget * w = gtr_torrent_options_dialog_new ( cbdata - > wind , core , ctor ) ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
g_signal_connect ( w , " focus-in-event " ,
G_CALLBACK ( on_main_window_focus_in ) , cbdata ) ;
if ( cbdata - > wind )
gtk_window_set_urgency_hint ( cbdata - > wind , TRUE ) ;
2010-12-22 03:06:06 +00:00
2012-12-05 17:29:46 +00:00
gtk_widget_show ( w ) ;
2007-05-24 02:50:28 +00:00
}
2007-02-19 22:09:05 +00:00
static void
2012-12-22 20:35:19 +00:00
on_prefs_changed ( TrCore * core UNUSED , const tr_quark key , gpointer data )
2007-02-19 22:09:05 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * cbdata = data ;
tr_session * tr = gtr_core_session ( cbdata - > core ) ;
2007-02-19 22:09:05 +00:00
2012-12-22 20:35:19 +00:00
switch ( key )
2008-12-14 22:41:44 +00:00
{
2012-12-22 20:35:19 +00:00
case TR_KEY_encryption :
tr_sessionSetEncryption ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_download_dir :
tr_sessionSetDownloadDir ( tr , gtr_pref_string_get ( key ) ) ;
break ;
case TR_KEY_message_level :
2013-01-25 23:34:20 +00:00
tr_logSetLevel ( gtr_pref_int_get ( key ) ) ;
2012-12-22 20:35:19 +00:00
break ;
case TR_KEY_peer_port :
tr_sessionSetPeerPort ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_blocklist_enabled :
2012-12-05 17:29:46 +00:00
tr_blocklistSetEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
2012-12-22 20:35:19 +00:00
break ;
case TR_KEY_blocklist_url :
2012-12-05 17:29:46 +00:00
tr_blocklistSetURL ( tr , gtr_pref_string_get ( key ) ) ;
2012-12-22 20:35:19 +00:00
break ;
case TR_KEY_show_notification_area_icon :
{
const bool show = gtr_pref_flag_get ( key ) ;
if ( show & & ! cbdata - > icon )
cbdata - > icon = gtr_icon_new ( cbdata - > core ) ;
else if ( ! show & & cbdata - > icon )
g_clear_object ( & cbdata - > icon ) ;
break ;
}
case TR_KEY_speed_limit_down_enabled :
tr_sessionLimitSpeed ( tr , TR_DOWN , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_speed_limit_down :
tr_sessionSetSpeedLimit_KBps ( tr , TR_DOWN , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_speed_limit_up_enabled :
tr_sessionLimitSpeed ( tr , TR_UP , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_speed_limit_up :
tr_sessionSetSpeedLimit_KBps ( tr , TR_UP , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_ratio_limit_enabled :
tr_sessionSetRatioLimited ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_ratio_limit :
tr_sessionSetRatioLimit ( tr , gtr_pref_double_get ( key ) ) ;
break ;
case TR_KEY_idle_seeding_limit :
tr_sessionSetIdleLimit ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_idle_seeding_limit_enabled :
tr_sessionSetIdleLimited ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_port_forwarding_enabled :
tr_sessionSetPortForwardingEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_pex_enabled :
tr_sessionSetPexEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_rename_partial_files :
tr_sessionSetIncompleteFileNamingEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_download_queue_size :
tr_sessionSetQueueSize ( tr , TR_DOWN , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_queue_stalled_minutes :
tr_sessionSetQueueStalledMinutes ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_dht_enabled :
tr_sessionSetDHTEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_utp_enabled :
tr_sessionSetUTPEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_lpd_enabled :
tr_sessionSetLPDEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_rpc_port :
tr_sessionSetRPCPort ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_rpc_enabled :
tr_sessionSetRPCEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_rpc_whitelist :
tr_sessionSetRPCWhitelist ( tr , gtr_pref_string_get ( key ) ) ;
break ;
case TR_KEY_rpc_whitelist_enabled :
tr_sessionSetRPCWhitelistEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_rpc_username :
tr_sessionSetRPCUsername ( tr , gtr_pref_string_get ( key ) ) ;
break ;
case TR_KEY_rpc_password :
tr_sessionSetRPCPassword ( tr , gtr_pref_string_get ( key ) ) ;
break ;
case TR_KEY_rpc_authentication_required :
tr_sessionSetRPCPasswordEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_alt_speed_up :
tr_sessionSetAltSpeed_KBps ( tr , TR_UP , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_alt_speed_down :
2012-12-05 17:29:46 +00:00
tr_sessionSetAltSpeed_KBps ( tr , TR_DOWN , gtr_pref_int_get ( key ) ) ;
2012-12-22 20:35:19 +00:00
break ;
case TR_KEY_alt_speed_enabled :
{
const bool b = gtr_pref_flag_get ( key ) ;
tr_sessionUseAltSpeed ( tr , b ) ;
gtr_action_set_toggled ( tr_quark_get_string ( key , NULL ) , b ) ;
break ;
}
case TR_KEY_alt_speed_time_begin :
tr_sessionSetAltSpeedBegin ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_alt_speed_time_end :
tr_sessionSetAltSpeedEnd ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_alt_speed_time_enabled :
tr_sessionUseAltSpeedTime ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_alt_speed_time_day :
tr_sessionSetAltSpeedDay ( tr , gtr_pref_int_get ( key ) ) ;
break ;
case TR_KEY_peer_port_random_on_start :
tr_sessionSetPeerPortRandomOnStart ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_incomplete_dir :
tr_sessionSetIncompleteDir ( tr , gtr_pref_string_get ( key ) ) ;
break ;
case TR_KEY_incomplete_dir_enabled :
tr_sessionSetIncompleteDirEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_script_torrent_done_enabled :
tr_sessionSetTorrentDoneScriptEnabled ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_script_torrent_done_filename :
tr_sessionSetTorrentDoneScript ( tr , gtr_pref_string_get ( key ) ) ;
break ;
case TR_KEY_start_added_torrents :
tr_sessionSetPaused ( tr , ! gtr_pref_flag_get ( key ) ) ;
break ;
case TR_KEY_trash_original_torrent_files :
tr_sessionSetDeleteSource ( tr , gtr_pref_flag_get ( key ) ) ;
break ;
default :
break ;
2010-03-17 19:23:03 +00:00
}
2007-02-19 22:09:05 +00:00
}
2008-08-11 19:05:02 +00:00
static gboolean
2012-12-05 17:29:46 +00:00
update_model_once ( gpointer gdata )
2008-07-13 18:14:24 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * data = gdata ;
2006-07-16 19:39:23 +00:00
2012-12-05 17:29:46 +00:00
/* update the torrent data in the model */
gtr_core_update ( data - > core ) ;
2006-07-16 19:39:23 +00:00
2012-12-05 17:29:46 +00:00
/* refresh the main window's statusbar and toolbar buttons */
if ( data - > wind ! = NULL )
gtr_window_refresh ( data - > wind ) ;
2006-07-16 19:39:23 +00:00
2012-12-05 17:29:46 +00:00
/* update the actions */
refresh_actions ( data ) ;
2009-11-18 06:21:01 +00:00
2012-12-05 17:29:46 +00:00
/* update the status tray icon */
if ( data - > icon ! = NULL )
gtr_icon_refresh ( data - > icon ) ;
2011-07-30 13:28:03 +00:00
2012-12-05 17:29:46 +00:00
data - > update_model_soon_tag = 0 ;
2013-01-04 16:36:52 +00:00
return G_SOURCE_REMOVE ;
2011-07-30 13:28:03 +00:00
}
static void
2012-12-05 17:29:46 +00:00
update_model_soon ( gpointer gdata )
2011-07-30 13:28:03 +00:00
{
2012-12-05 17:29:46 +00:00
struct cbdata * data = gdata ;
2011-07-30 13:28:03 +00:00
2012-12-05 17:29:46 +00:00
if ( data - > update_model_soon_tag = = 0 )
data - > update_model_soon_tag = gdk_threads_add_idle ( update_model_once , data ) ;
2011-07-30 13:28:03 +00:00
}
static gboolean
2012-12-05 17:29:46 +00:00
update_model_loop ( gpointer gdata )
2011-07-30 13:28:03 +00:00
{
2012-12-05 17:29:46 +00:00
const gboolean done = global_sigcount ;
2011-07-30 13:28:03 +00:00
2012-12-05 17:29:46 +00:00
if ( ! done )
update_model_once ( gdata ) ;
2006-07-16 19:39:23 +00:00
2012-12-05 17:29:46 +00:00
return ! done ;
2006-07-16 19:39:23 +00:00
}
2007-06-09 15:20:32 +00:00
static void
2012-12-05 17:29:46 +00:00
show_about_dialog ( GtkWindow * parent )
2007-06-09 15:20:32 +00:00
{
2012-12-05 17:29:46 +00:00
const char * uri = " http://www.transmissionbt.com/ " ;
const char * authors [ ] = { " Jordan Lee (Backend; GTK+) " ,
" Mitchell Livingston (Backend; OS X) " ,
NULL } ;
gtk_show_about_dialog ( parent ,
" authors " , authors ,
" comments " , _ ( " A fast and easy BitTorrent client " ) ,
" copyright " , _ ( " Copyright (c) The Transmission Project " ) ,
" logo-icon-name " , MY_CONFIG_NAME ,
" name " , g_get_application_name ( ) ,
/* Translators: translate "translator-credits" as your name
to have it appear in the credits in the " About "
dialog */
" translator-credits " , _ ( " translator-credits " ) ,
" version " , LONG_VERSION_STRING ,
" website " , uri ,
" website-label " , uri ,
2007-06-09 17:08:25 +00:00
# ifdef SHOW_LICENSE
2012-12-05 17:29:46 +00:00
" license " , LICENSE ,
" wrap-license " , TRUE ,
2007-06-09 17:08:25 +00:00
# endif
2012-12-05 17:29:46 +00:00
NULL ) ;
2007-06-09 15:20:32 +00:00
}
2007-02-07 07:35:33 +00:00
static void
2012-12-05 17:29:46 +00:00
append_id_to_benc_list ( GtkTreeModel * m , GtkTreePath * path UNUSED ,
GtkTreeIter * iter , gpointer list )
2007-02-07 07:35:33 +00:00
{
2012-12-05 17:29:46 +00:00
tr_torrent * tor = NULL ;
gtk_tree_model_get ( m , iter , MC_TORRENT , & tor , - 1 ) ;
2012-12-14 04:34:42 +00:00
tr_variantListAddInt ( list , tr_torrentId ( tor ) ) ;
2007-06-18 03:40:41 +00:00
}
2010-02-21 23:56:01 +00:00
static gboolean
2012-12-05 17:29:46 +00:00
call_rpc_for_selected_torrents ( struct cbdata * data , const char * method )
2007-06-18 03:40:41 +00:00
{
2012-12-14 04:34:42 +00:00
tr_variant top , * args , * ids ;
2012-12-05 17:29:46 +00:00
gboolean invoked = FALSE ;
GtkTreeSelection * s = data - > sel ;
tr_session * session = gtr_core_session ( data - > core ) ;
2008-09-23 19:11:04 +00:00
2012-12-14 04:34:42 +00:00
tr_variantInitDict ( & top , 2 ) ;
2012-12-22 20:35:19 +00:00
tr_variantDictAddStr ( & top , TR_KEY_method , method ) ;
args = tr_variantDictAddDict ( & top , TR_KEY_arguments , 1 ) ;
ids = tr_variantDictAddList ( args , TR_KEY_ids , 0 ) ;
2012-12-05 17:29:46 +00:00
gtk_tree_selection_selected_foreach ( s , append_id_to_benc_list , ids ) ;
2007-06-18 03:40:41 +00:00
2012-12-14 04:34:42 +00:00
if ( tr_variantListSize ( ids ) ! = 0 )
2010-02-21 23:56:01 +00:00
{
2012-12-05 17:29:46 +00:00
int json_len ;
2012-12-14 04:34:42 +00:00
char * json = tr_variantToStr ( & top , TR_VARIANT_FMT_JSON_LEAN , & json_len ) ;
2012-12-05 17:29:46 +00:00
tr_rpc_request_exec_json ( session , json , json_len , NULL , NULL ) ;
g_free ( json ) ;
invoked = TRUE ;
2010-02-21 23:56:01 +00:00
}
2008-09-23 19:11:04 +00:00
2012-12-14 04:34:42 +00:00
tr_variantFree ( & top ) ;
2012-12-05 17:29:46 +00:00
return invoked ;
2007-07-30 17:11:00 +00:00
}
2008-04-11 02:21:33 +00:00
static void
2012-12-05 17:29:46 +00:00
open_folder_foreach ( GtkTreeModel * model , GtkTreePath * path UNUSED ,
GtkTreeIter * iter , gpointer core )
2008-04-11 02:21:33 +00:00
{
2012-12-05 17:29:46 +00:00
int id ;
gtk_tree_model_get ( model , iter , MC_TORRENT_ID , & id , - 1 ) ;
gtr_core_open_folder ( core , id ) ;
2008-04-11 02:21:33 +00:00
}
2008-09-23 19:11:04 +00:00
static gboolean
2012-12-05 17:29:46 +00:00
on_message_window_closed ( void )
2007-09-21 16:29:09 +00:00
{
2012-12-05 17:29:46 +00:00
gtr_action_set_toggled ( " toggle-message-log " , FALSE ) ;
return FALSE ;
2007-09-21 16:29:09 +00:00
}
2008-03-02 15:54:58 +00:00
static void
2012-12-05 17:29:46 +00:00
accumulate_selected_torrents ( GtkTreeModel * model , GtkTreePath * path UNUSED ,
GtkTreeIter * iter , gpointer gdata )
2008-03-02 15:54:58 +00:00
{
2012-12-05 17:29:46 +00:00
int id ;
GSList * * data = gdata ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
gtk_tree_model_get ( model , iter , MC_TORRENT_ID , & id , - 1 ) ;
* data = g_slist_append ( * data , GINT_TO_POINTER ( id ) ) ;
2008-03-02 15:54:58 +00:00
}
2008-03-07 16:58:44 +00:00
static void
2012-12-05 17:29:46 +00:00
remove_selected ( struct cbdata * data , gboolean delete_files )
2008-03-02 15:54:58 +00:00
{
2012-12-05 17:29:46 +00:00
GSList * l = NULL ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
gtk_tree_selection_selected_foreach ( data - > sel , accumulate_selected_torrents , & l ) ;
2010-06-25 19:24:26 +00:00
2012-12-05 17:29:46 +00:00
if ( l ! = NULL )
gtr_confirm_remove ( data - > wind , data - > core , l , delete_files ) ;
2008-03-02 15:54:58 +00:00
}
2009-02-18 18:40:38 +00:00
static void
2012-12-05 17:29:46 +00:00
start_all_torrents ( struct cbdata * data )
2009-02-18 18:40:38 +00:00
{
2012-12-05 17:29:46 +00:00
tr_session * session = gtr_core_session ( data - > core ) ;
const char * cmd = " { \" method \" : \" torrent-start \" } " ;
tr_rpc_request_exec_json ( session , cmd , strlen ( cmd ) , NULL , NULL ) ;
2009-02-18 18:40:38 +00:00
}
2008-12-03 05:15:17 +00:00
static void
2012-12-05 17:29:46 +00:00
pause_all_torrents ( struct cbdata * data )
2008-12-03 05:15:17 +00:00
{
2012-12-05 17:29:46 +00:00
tr_session * session = gtr_core_session ( data - > core ) ;
const char * cmd = " { \" method \" : \" torrent-stop \" } " ;
tr_rpc_request_exec_json ( session , cmd , strlen ( cmd ) , NULL , NULL ) ;
2008-12-03 05:15:17 +00:00
}
2009-05-13 15:54:04 +00:00
static tr_torrent *
2012-12-05 17:29:46 +00:00
get_first_selected_torrent ( struct cbdata * data )
2009-05-13 15:54:04 +00:00
{
2012-12-05 17:29:46 +00:00
tr_torrent * tor = NULL ;
GtkTreeModel * m ;
GList * l = gtk_tree_selection_get_selected_rows ( data - > sel , & m ) ;
if ( l ! = NULL )
{
GtkTreePath * p = l - > data ;
GtkTreeIter i ;
if ( gtk_tree_model_get_iter ( m , & i , p ) )
gtk_tree_model_get ( m , & i , MC_TORRENT , & tor , - 1 ) ;
}
g_list_foreach ( l , ( GFunc ) gtk_tree_path_free , NULL ) ;
g_list_free ( l ) ;
return tor ;
2009-05-13 15:54:04 +00:00
}
2009-11-29 18:23:06 +00:00
static void
2012-12-05 17:29:46 +00:00
copy_magnet_link_to_clipboard ( GtkWidget * w , tr_torrent * tor )
2009-11-29 18:23:06 +00:00
{
2012-12-05 17:29:46 +00:00
char * magnet = tr_torrentGetMagnetLink ( tor ) ;
GdkDisplay * display = gtk_widget_get_display ( w ) ;
GdkAtom selection ;
GtkClipboard * clipboard ;
/* this is The Right Thing for copy/paste... */
selection = GDK_SELECTION_CLIPBOARD ;
clipboard = gtk_clipboard_get_for_display ( display , selection ) ;
gtk_clipboard_set_text ( clipboard , magnet , - 1 ) ;
/* ...but people using plain ol' X need this instead */
selection = GDK_SELECTION_PRIMARY ;
clipboard = gtk_clipboard_get_for_display ( display , selection ) ;
gtk_clipboard_set_text ( clipboard , magnet , - 1 ) ;
/* cleanup */
tr_free ( magnet ) ;
2009-11-29 18:23:06 +00:00
}
2007-06-18 03:40:41 +00:00
void
2012-12-05 17:29:46 +00:00
gtr_actions_handler ( const char * action_name , gpointer user_data )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
gboolean changed = FALSE ;
struct cbdata * data = user_data ;
2007-06-18 03:40:41 +00:00
2013-02-14 15:17:42 +00:00
if ( ! g_strcmp0 ( action_name , " open-torrent-from-url " ) )
2009-11-22 16:20:22 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * w = gtr_torrent_open_from_url_dialog_new ( data - > wind , data - > core ) ;
gtk_widget_show ( w ) ;
2009-11-22 16:20:22 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " open-torrent-menu " )
| | ! g_strcmp0 ( action_name , " open-torrent-toolbar " ) )
2007-05-23 00:49:31 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * w = gtr_torrent_open_from_file_dialog_new ( data - > wind , data - > core ) ;
gtk_widget_show ( w ) ;
2006-07-16 19:39:23 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " show-stats " ) )
2007-11-27 03:29:51 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * dialog = gtr_stats_dialog_new ( data - > wind , data - > core ) ;
gtk_widget_show ( dialog ) ;
2007-11-27 03:29:51 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " donate " ) )
2009-09-10 17:39:44 +00:00
{
2012-12-05 17:29:46 +00:00
gtr_open_uri ( " http://www.transmissionbt.com/donate.php " ) ;
2009-09-10 17:39:44 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " pause-all-torrents " ) )
2008-12-03 05:15:17 +00:00
{
2012-12-05 17:29:46 +00:00
pause_all_torrents ( data ) ;
2008-12-03 05:15:17 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " start-all-torrents " ) )
2009-02-18 18:40:38 +00:00
{
2012-12-05 17:29:46 +00:00
start_all_torrents ( data ) ;
2009-02-18 18:40:38 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " copy-magnet-link-to-clipboard " ) )
2009-11-29 18:23:06 +00:00
{
2012-12-05 17:29:46 +00:00
tr_torrent * tor = get_first_selected_torrent ( data ) ;
if ( tor ! = NULL )
2009-11-29 18:23:06 +00:00
{
2012-12-05 17:29:46 +00:00
copy_magnet_link_to_clipboard ( GTK_WIDGET ( data - > wind ) , tor ) ;
2009-11-29 18:23:06 +00:00
}
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " relocate-torrent " ) )
2009-05-13 15:54:04 +00:00
{
2012-12-05 17:29:46 +00:00
GSList * ids = get_selected_torrent_ids ( data ) ;
if ( ids ! = NULL )
2009-05-13 15:54:04 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWindow * parent = data - > wind ;
GtkWidget * w = gtr_relocate_dialog_new ( parent , data - > core , ids ) ;
gtk_widget_show ( w ) ;
2009-05-13 15:54:04 +00:00
}
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " torrent-start " )
| | ! g_strcmp0 ( action_name , " torrent-start-now " )
| | ! g_strcmp0 ( action_name , " torrent-stop " )
| | ! g_strcmp0 ( action_name , " torrent-reannounce " )
| | ! g_strcmp0 ( action_name , " torrent-verify " )
| | ! g_strcmp0 ( action_name , " queue-move-top " )
| | ! g_strcmp0 ( action_name , " queue-move-up " )
| | ! g_strcmp0 ( action_name , " queue-move-down " )
| | ! g_strcmp0 ( action_name , " queue-move-bottom " ) )
2011-08-01 22:24:24 +00:00
{
2012-12-05 17:29:46 +00:00
changed | = call_rpc_for_selected_torrents ( data , action_name ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " open-torrent-folder " ) )
2008-04-11 02:21:33 +00:00
{
2012-12-05 17:29:46 +00:00
gtk_tree_selection_selected_foreach ( data - > sel , open_folder_foreach , data - > core ) ;
2008-04-11 02:21:33 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " show-torrent-properties " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
show_details_dialog_for_selected_torrents ( data ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " new-torrent " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * w = gtr_torrent_creation_dialog_new ( data - > wind , data - > core ) ;
gtk_widget_show ( w ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " remove-torrent " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
remove_selected ( data , FALSE ) ;
2008-03-02 15:54:58 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " delete-torrent " ) )
2008-03-02 15:54:58 +00:00
{
2012-12-05 17:29:46 +00:00
remove_selected ( data , TRUE ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " quit " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
on_app_exit ( data ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " select-all " ) )
2007-07-30 15:51:37 +00:00
{
2012-12-05 17:29:46 +00:00
gtk_tree_selection_select_all ( data - > sel ) ;
2007-07-30 15:51:37 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " deselect-all " ) )
2007-07-30 15:51:37 +00:00
{
2012-12-05 17:29:46 +00:00
gtk_tree_selection_unselect_all ( data - > sel ) ;
2007-07-30 15:51:37 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " edit-preferences " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
if ( NULL = = data - > prefs )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
data - > prefs = gtr_prefs_dialog_new ( data - > wind , G_OBJECT ( data - > core ) ) ;
g_signal_connect ( data - > prefs , " destroy " ,
G_CALLBACK ( gtk_widget_destroyed ) , & data - > prefs ) ;
2007-06-18 03:40:41 +00:00
}
2012-12-05 17:29:46 +00:00
gtr_window_present ( GTK_WINDOW ( data - > prefs ) ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " toggle-message-log " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! data - > msgwin )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
GtkWidget * win = gtr_message_log_window_new ( data - > wind , data - > core ) ;
g_signal_connect ( win , " destroy " , G_CALLBACK ( on_message_window_closed ) , NULL ) ;
data - > msgwin = win ;
2007-09-21 16:29:09 +00:00
}
2012-12-05 17:29:46 +00:00
else
2007-09-21 16:29:09 +00:00
{
2012-12-05 17:29:46 +00:00
gtr_action_set_toggled ( " toggle-message-log " , FALSE ) ;
gtk_widget_destroy ( data - > msgwin ) ;
data - > msgwin = NULL ;
2007-06-18 03:40:41 +00:00
}
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " show-about-dialog " ) )
2012-12-05 17:29:46 +00:00
{
show_about_dialog ( data - > wind ) ;
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " help " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
gtr_open_uri ( gtr_get_help_uri ( ) ) ;
2007-06-18 03:40:41 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " toggle-main-window " ) )
2008-05-06 19:20:19 +00:00
{
2012-12-05 17:29:46 +00:00
toggleMainWindow ( data ) ;
2008-05-06 19:20:19 +00:00
}
2013-02-14 15:17:42 +00:00
else if ( ! g_strcmp0 ( action_name , " present-main-window " ) )
2007-06-18 03:40:41 +00:00
{
2012-12-05 17:29:46 +00:00
presentMainWindow ( data ) ;
2007-06-18 03:40:41 +00:00
}
2012-12-05 17:29:46 +00:00
else
2011-08-07 16:42:38 +00:00
{
2012-12-05 17:29:46 +00:00
g_error ( " Unhandled action: %s " , action_name ) ;
2011-08-07 16:42:38 +00:00
}
2006-07-16 19:39:23 +00:00
2012-12-05 17:29:46 +00:00
if ( changed )
update_model_soon ( data ) ;
2006-07-16 19:39:23 +00:00
}