1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-26 09:37:56 +00:00
transmission/gtk/util.c
Jordan Lee aea77bc9f6 (trunk gtk) make "gtr_label_set_text" public and use it everywhere instead of gtk_label_set_text()
Some of the refresh events to the main window's torrent list are caused by main window relayout caused by the toolbar's GtkLabels recalculating their size after being updated once per second. To prevent relayout in some trivial cases, I'm replacing the gtk_label_set_text() calls with gtr_label_set_text() because the latter doesn't update the label widget if the old and new text strings are the same.

There are other changes that can handle more important cases -- I'll test those out next.
2011-01-21 16:32:27 +00:00

954 lines
24 KiB
C

/*
* This file Copyright (C) Mnemosyne LLC
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#include <ctype.h> /* isxdigit() */
#include <errno.h>
#include <math.h> /* pow() */
#include <stdarg.h>
#include <stdlib.h> /* free() */
#include <string.h> /* strcmp() */
#include <sys/types.h> /* for gtr_lockfile()'s open() */
#include <sys/stat.h> /* for gtr_lockfile()'s open() */
#include <fcntl.h> /* for gtr_lockfile()'s open() */
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h> /* g_unlink() */
#ifdef HAVE_GIO
#include <gio/gio.h> /* g_file_trash() */
#endif
#ifdef HAVE_DBUS_GLIB
#include <dbus/dbus-glib.h>
#endif
#include <libtransmission/transmission.h> /* TR_RATIO_NA, TR_RATIO_INF */
#include <libtransmission/utils.h> /* tr_inf */
#include <libtransmission/web.h> /* tr_webResponseStr() */
#include <libtransmission/version.h> /* tr_inf */
#include "conf.h"
#include "hig.h"
#include "tr-prefs.h"
#include "util.h"
/***
**** UNITS
***/
const int mem_K = 1024;
const char * mem_K_str = N_("KiB");
const char * mem_M_str = N_("MiB");
const char * mem_G_str = N_("GiB");
const char * mem_T_str = N_("TiB");
const int disk_K = 1024;
const char * disk_K_str = N_("KiB");
const char * disk_M_str = N_("MiB");
const char * disk_G_str = N_("GiB");
const char * disk_T_str = N_("TiB");
const int speed_K = 1024;
const char * speed_K_str = N_("KiB/s");
const char * speed_M_str = N_("MiB/s");
const char * speed_G_str = N_("GiB/s");
const char * speed_T_str = N_("TiB/s");
/***
****
***/
gtr_lockfile_state_t
gtr_lockfile( const char * filename )
{
gtr_lockfile_state_t ret;
#ifdef WIN32
HANDLE file = CreateFile( filename,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if( file == INVALID_HANDLE_VALUE )
ret = GTR_LOCKFILE_EOPEN;
else if( !LockFile( file, 0, 0, 1, 1 ) )
ret = GTR_LOCKFILE_ELOCK;
else
ret = GTR_LOCKFILE_SUCCESS;
#else
int fd = open( filename, O_RDWR | O_CREAT, 0666 );
if( fd < 0 )
ret = GTR_LOCKFILE_EOPEN;
else {
struct flock lk;
memset( &lk, 0, sizeof( lk ) );
lk.l_start = 0;
lk.l_len = 0;
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
if( -1 == fcntl( fd, F_SETLK, &lk ) )
ret = GTR_LOCKFILE_ELOCK;
else
ret = GTR_LOCKFILE_SUCCESS;
}
#endif
return ret;
}
/***
****
***/
int
gtr_compare_double( const double a, const double b, int decimal_places )
{
const int64_t ia = (int64_t)(a * pow( 10, decimal_places ) );
const int64_t ib = (int64_t)(b * pow( 10, decimal_places ) );
if( ia < ib ) return -1;
if( ia > ib ) return 1;
return 0;
}
/***
****
***/
const char*
gtr_get_unicode_string( int i )
{
switch( i ) {
case GTR_UNICODE_UP: return "\xE2\x86\x91";
case GTR_UNICODE_DOWN: return "\xE2\x86\x93";
case GTR_UNICODE_INF: return "\xE2\x88\x9E";
case GTR_UNICODE_BULLET: return "\xE2\x88\x99";
default: return "err";
}
}
char*
tr_strlratio( char * buf, double ratio, size_t buflen )
{
return tr_strratio( buf, buflen, ratio, gtr_get_unicode_string( GTR_UNICODE_INF ) );
}
char*
tr_strlpercent( char * buf, double x, size_t buflen )
{
return tr_strpercent( buf, x, buflen );
}
char*
tr_strlsize( char * buf, guint64 bytes, size_t buflen )
{
if( !bytes )
g_strlcpy( buf, Q_( "size|None" ), buflen );
else
tr_formatter_size_B( buf, bytes, buflen );
return buf;
}
char*
tr_strltime( char * buf, int seconds, size_t buflen )
{
int days, hours, minutes;
char d[128], h[128], m[128], s[128];
if( seconds < 0 )
seconds = 0;
days = seconds / 86400;
hours = ( seconds % 86400 ) / 3600;
minutes = ( seconds % 3600 ) / 60;
seconds = ( seconds % 3600 ) % 60;
g_snprintf( d, sizeof( d ), gtr_ngettext( "%'d day", "%'d days", days ), days );
g_snprintf( h, sizeof( h ), gtr_ngettext( "%'d hour", "%'d hours", hours ), hours );
g_snprintf( m, sizeof( m ), gtr_ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
g_snprintf( s, sizeof( s ), gtr_ngettext( "%'d second", "%'d seconds", seconds ), seconds );
if( days )
{
if( days >= 4 || !hours )
{
g_strlcpy( buf, d, buflen );
}
else
{
g_snprintf( buf, buflen, "%s, %s", d, h );
}
}
else if( hours )
{
if( hours >= 4 || !minutes )
{
g_strlcpy( buf, h, buflen );
}
else
{
g_snprintf( buf, buflen, "%s, %s", h, m );
}
}
else if( minutes )
{
if( minutes >= 4 || !seconds )
{
g_strlcpy( buf, m, buflen );
}
else
{
g_snprintf( buf, buflen, "%s, %s", m, s );
}
}
else
{
g_strlcpy( buf, s, buflen );
}
return buf;
}
char *
gtr_localtime( time_t time )
{
const struct tm tm = *localtime( &time );
char buf[256], *eoln;
g_strlcpy( buf, asctime( &tm ), sizeof( buf ) );
if( ( eoln = strchr( buf, '\n' ) ) )
*eoln = '\0';
return g_locale_to_utf8( buf, -1, NULL, NULL, NULL );
}
int
gtr_mkdir_with_parents( const char * path, int mode )
{
#if GLIB_CHECK_VERSION( 2, 8, 0 )
return !g_mkdir_with_parents( path, mode );
#else
return !tr_mkdirp( path, mode );
#endif
}
/* pattern-matching text; ie, legaltorrents.com */
char*
gtr_get_host_from_url( const char * url )
{
char * h = NULL;
char * name;
const char * first_dot;
const char * last_dot;
tr_urlParse( url, -1, NULL, &h, NULL, NULL );
first_dot = strchr( h, '.' );
last_dot = strrchr( h, '.' );
if( ( first_dot ) && ( last_dot ) && ( first_dot != last_dot ) )
name = g_strdup( first_dot + 1 );
else
name = g_strdup( h );
tr_free( h );
return name;
}
gboolean
gtr_is_supported_url( const char * str )
{
return !strncmp( str, "ftp://", 6 )
|| !strncmp( str, "http://", 7 )
|| !strncmp( str, "https://", 8 );
}
gboolean
gtr_is_magnet_link( const char * str )
{
return !strncmp( str, "magnet:?", 8 );
}
gboolean
gtr_is_hex_hashcode( const char * str )
{
int i;
if( !str || ( strlen( str ) != 40 ) )
return FALSE;
for( i=0; i<40; ++i )
if( !isxdigit( str[i] ) )
return FALSE;
return TRUE;
}
static GtkWindow *
getWindow( GtkWidget * w )
{
if( w == NULL )
return NULL;
if( GTK_IS_WINDOW( w ) )
return GTK_WINDOW( w );
return GTK_WINDOW( gtk_widget_get_ancestor( w, GTK_TYPE_WINDOW ) );
}
void
gtr_add_torrent_error_dialog( GtkWidget * child, int err, const char * file )
{
char * secondary;
const char * fmt;
GtkWidget * w;
GtkWindow * win = getWindow( child );
switch( err )
{
case TR_PARSE_ERR: fmt = _( "The torrent file \"%s\" contains invalid data." ); break;
case TR_PARSE_DUPLICATE: fmt = _( "The torrent file \"%s\" is already in use." ); break;
default: fmt = _( "The torrent file \"%s\" encountered an unknown error." ); break;
}
secondary = g_strdup_printf( fmt, file );
w = gtk_message_dialog_new( win,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"%s", _( "Error opening torrent" ) );
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ),
"%s", secondary );
g_signal_connect_swapped( w, "response",
G_CALLBACK( gtk_widget_destroy ), w );
gtk_widget_show_all( w );
g_free( secondary );
}
typedef void ( PopupFunc )( GtkWidget*, GdkEventButton* );
/* pop up the context menu if a user right-clicks.
if the row they right-click on isn't selected, select it. */
gboolean
on_tree_view_button_pressed( GtkWidget * view,
GdkEventButton * event,
gpointer func )
{
GtkTreeView * tv = GTK_TREE_VIEW( view );
if( event->type == GDK_BUTTON_PRESS && event->button == 3 )
{
GtkTreeSelection * selection = gtk_tree_view_get_selection( tv );
GtkTreePath * path;
if( gtk_tree_view_get_path_at_pos ( tv,
(gint) event->x,
(gint) event->y,
&path, NULL, NULL, NULL ) )
{
if( !gtk_tree_selection_path_is_selected ( selection, path ) )
{
gtk_tree_selection_unselect_all ( selection );
gtk_tree_selection_select_path ( selection, path );
}
gtk_tree_path_free( path );
}
if( func != NULL )
( (PopupFunc*)func )( view, event );
return TRUE;
}
return FALSE;
}
/* if the user clicked in an empty area of the list,
* clear all the selections. */
gboolean
on_tree_view_button_released( GtkWidget * view,
GdkEventButton * event,
gpointer unused UNUSED )
{
GtkTreeView * tv = GTK_TREE_VIEW( view );
if( !gtk_tree_view_get_path_at_pos ( tv,
(gint) event->x,
(gint) event->y,
NULL, NULL, NULL, NULL ) )
{
GtkTreeSelection * selection = gtk_tree_view_get_selection( tv );
gtk_tree_selection_unselect_all ( selection );
}
return FALSE;
}
gpointer
gtr_object_ref_sink( gpointer object )
{
#if GLIB_CHECK_VERSION( 2, 10, 0 )
g_object_ref_sink( object );
#else
g_object_ref( object );
gtk_object_sink( GTK_OBJECT( object ) );
#endif
return object;
}
int
gtr_strcmp0( const char * str1, const char * str2 )
{
#if GLIB_CHECK_VERSION( 2, 16, 0 )
return g_strcmp0( str1, str2 );
#else
if( str1 && str2 ) return strcmp( str1, str2 );
if( str1 ) return 1;
if( str2 ) return -1;
return 0;
#endif
}
const gchar *
gtr_ngettext( const gchar * msgid,
const gchar * msgid_plural,
gulong n )
{
#if GLIB_CHECK_VERSION( 2, 18, 0 )
return g_dngettext( NULL, msgid, msgid_plural, n );
#else
return ngettext( msgid, msgid_plural, n );
#endif
}
int
gtr_file_trash_or_remove( const char * filename )
{
if( filename && g_file_test( filename, G_FILE_TEST_EXISTS ) )
{
gboolean trashed = FALSE;
#ifdef HAVE_GIO
GError * err = NULL;
GFile * file = g_file_new_for_path( filename );
trashed = g_file_trash( file, NULL, &err );
if( err )
g_message( "Unable to trash file \"%s\": %s", filename, err->message );
g_clear_error( &err );
g_object_unref( G_OBJECT( file ) );
#endif
if( !trashed && g_remove( filename ) )
{
const int err = errno;
g_message( "Unable to remove file \"%s\": %s", filename, g_strerror( err ) );
}
}
return 0;
}
const char*
gtr_get_help_uri( void )
{
static char * uri = NULL;
if( !uri )
{
int major, minor;
const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
uri = g_strdup_printf( fmt, major, minor / 10 );
}
return uri;
}
void
gtr_open_file( const char * path )
{
char * uri = NULL;
#ifdef HAVE_GIO
GFile * file = g_file_new_for_path( path );
uri = g_file_get_uri( file );
g_object_unref( G_OBJECT( file ) );
#else
if( g_path_is_absolute( path ) )
uri = g_strdup_printf( "file://%s", path );
else {
char * cwd = g_get_current_dir();
uri = g_strdup_printf( "file://%s/%s", cwd, path );
g_free( cwd );
}
#endif
gtr_open_uri( uri );
g_free( uri );
}
void
gtr_open_uri( const char * uri )
{
if( uri )
{
gboolean opened = FALSE;
#ifdef HAVE_GIO
if( !opened )
opened = g_app_info_launch_default_for_uri( uri, NULL, NULL );
#endif
if( !opened ) {
char * argv[] = { (char*)"xdg-open", (char*)uri, NULL };
opened = g_spawn_async( NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL, NULL );
}
if( !opened )
g_message( "Unable to open \"%s\"", uri );
}
}
#define VALUE_SERVICE_NAME "com.transmissionbt.Transmission"
#define VALUE_SERVICE_OBJECT_PATH "/com/transmissionbt/Transmission"
#define VALUE_SERVICE_INTERFACE "com.transmissionbt.Transmission"
gboolean
gtr_dbus_add_torrent( const char * filename )
{
/* FIXME: why is this static? */
static gboolean handled = FALSE;
#ifdef HAVE_DBUS_GLIB
char * payload;
gsize file_length;
char * file_contents = NULL;
/* If it's a file, load its contents and send them over the wire...
* it might be a temporary file that's going to disappear. */
if( g_file_get_contents( filename, &file_contents, &file_length, NULL ) )
payload = tr_base64_encode( file_contents, file_length, NULL );
else if( gtr_is_supported_url( filename ) || gtr_is_magnet_link( filename ) )
payload = tr_strdup( filename );
else
payload = NULL;
if( payload != NULL )
{
GError * err = NULL;
DBusGConnection * conn;
DBusGProxy * proxy = NULL;
if(( conn = dbus_g_bus_get( DBUS_BUS_SESSION, &err )))
proxy = dbus_g_proxy_new_for_name (conn, VALUE_SERVICE_NAME,
VALUE_SERVICE_OBJECT_PATH,
VALUE_SERVICE_INTERFACE );
else if( err )
g_message( "err: %s", err->message );
if( proxy )
dbus_g_proxy_call( proxy, "AddMetainfo", &err,
G_TYPE_STRING, payload,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &handled,
G_TYPE_INVALID );
if( err )
g_message( "err: %s", err->message );
if( proxy )
g_object_unref( proxy );
if( conn )
dbus_g_connection_unref( conn );
tr_free( payload );
}
g_free( file_contents );
#endif
return handled;
}
gboolean
gtr_dbus_present_window( void )
{
static gboolean success = FALSE;
#ifdef HAVE_DBUS_GLIB
DBusGProxy * proxy = NULL;
GError * err = NULL;
DBusGConnection * conn;
if( ( conn = dbus_g_bus_get( DBUS_BUS_SESSION, &err ) ) )
proxy = dbus_g_proxy_new_for_name ( conn, VALUE_SERVICE_NAME,
VALUE_SERVICE_OBJECT_PATH,
VALUE_SERVICE_INTERFACE );
else if( err )
g_message( "err: %s", err->message );
if( proxy )
dbus_g_proxy_call( proxy, "PresentWindow", &err,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &success,
G_TYPE_INVALID );
if( err )
g_message( "err: %s", err->message );
g_object_unref( proxy );
dbus_g_connection_unref( conn );
#endif
return success;
}
/***
****
***/
void
gtr_combo_box_set_active_enum( GtkComboBox * combo_box, int value )
{
int i;
int currentValue;
const int column = 0;
GtkTreeIter iter;
GtkTreeModel * model = gtk_combo_box_get_model( combo_box );
/* do the value and current value match? */
if( gtk_combo_box_get_active_iter( combo_box, &iter ) ) {
gtk_tree_model_get( model, &iter, column, &currentValue, -1 );
if( currentValue == value )
return;
}
/* find the one to select */
i = 0;
while(( gtk_tree_model_iter_nth_child( model, &iter, NULL, i++ ))) {
gtk_tree_model_get( model, &iter, column, &currentValue, -1 );
if( currentValue == value ) {
gtk_combo_box_set_active_iter( combo_box, &iter );
return;
}
}
}
GtkWidget *
gtr_combo_box_new_enum( const char * text_1, ... )
{
GtkWidget * w;
GtkCellRenderer * r;
GtkListStore * store;
va_list vl;
const char * text;
va_start( vl, text_1 );
store = gtk_list_store_new( 2, G_TYPE_INT, G_TYPE_STRING );
text = text_1;
if( text != NULL ) do
{
const int val = va_arg( vl, int );
gtk_list_store_insert_with_values( store, NULL, INT_MAX, 0, val, 1, text, -1 );
text = va_arg( vl, const char * );
}
while( text != NULL );
w = gtk_combo_box_new_with_model( GTK_TREE_MODEL( store ) );
r = gtk_cell_renderer_text_new( );
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( w ), r, TRUE );
gtk_cell_layout_set_attributes( GTK_CELL_LAYOUT( w ), r, "text", 1, NULL );
/* cleanup */
g_object_unref( store );
return w;
}
int
gtr_combo_box_get_active_enum( GtkComboBox * combo_box )
{
int value = 0;
GtkTreeIter iter;
if( gtk_combo_box_get_active_iter( combo_box, &iter ) )
gtk_tree_model_get( gtk_combo_box_get_model( combo_box ), &iter, 0, &value, -1 );
return value;
}
GtkWidget *
gtr_priority_combo_new( void )
{
return gtr_combo_box_new_enum( _( "High" ), TR_PRI_HIGH,
_( "Normal" ), TR_PRI_NORMAL,
_( "Low" ), TR_PRI_LOW,
NULL );
}
/***
****
***/
void
gtr_widget_set_tooltip_text( GtkWidget * w, const char * tip )
{
#if GTK_CHECK_VERSION( 2,12,0 )
gtk_widget_set_tooltip_text( w, tip );
#else
static GtkTooltips * tips = NULL;
if( tips == NULL )
tips = gtk_tooltips_new( );
gtk_tooltips_set_tip( tips, w, tip, NULL );
#endif
}
GdkWindow*
gtr_widget_get_window( GtkWidget * w )
{
#if GTK_CHECK_VERSION( 2,14,0 )
return gtk_widget_get_window( w );
#else
return w->window;
#endif
}
gboolean
gtr_widget_get_realized( GtkWidget * w )
{
#if GTK_CHECK_VERSION( 2,20,0 )
return gtk_widget_get_realized( w );
#else
return GTK_WIDGET_REALIZED( w ) != 0;
#endif
}
void
gtr_widget_set_visible( GtkWidget * w, gboolean b )
{
/* toggle the transient children, too */
if( GTK_IS_WINDOW( w ) )
{
GList * l;
GList * windows = gtk_window_list_toplevels( );
GtkWindow * window = GTK_WINDOW( w );
for( l=windows; l!=NULL; l=l->next )
if( GTK_IS_WINDOW( l->data ) )
if( gtk_window_get_transient_for( GTK_WINDOW( l->data ) ) == window )
gtr_widget_set_visible( GTK_WIDGET( l->data ), b );
g_list_free( windows );
}
#if GTK_CHECK_VERSION( 2,18,0 )
gtk_widget_set_visible( w, b );
#else
if( b )
gtk_widget_show( w );
else
gtk_widget_hide( w );
#endif
}
void
gtr_cell_renderer_get_padding( GtkCellRenderer * cell, gint * xpad, gint * ypad )
{
#if GTK_CHECK_VERSION( 2,18,0 )
gtk_cell_renderer_get_padding( cell, xpad, ypad );
#else
if( xpad != NULL ) *xpad = cell->xpad;
if( ypad != NULL ) *ypad = cell->ypad;
#endif
}
static GtkWidget*
gtr_dialog_get_content_area( GtkDialog * dialog )
{
#if GTK_CHECK_VERSION( 2,14,0 )
return gtk_dialog_get_content_area( dialog );
#else
return dialog->vbox;
#endif
}
void
gtr_dialog_set_content( GtkDialog * dialog, GtkWidget * content )
{
GtkWidget * vbox = gtr_dialog_get_content_area( dialog );
gtk_box_pack_start( GTK_BOX( vbox ), content, TRUE, TRUE, 0 );
gtk_widget_show_all( content );
}
/***
****
***/
#if !GTK_CHECK_VERSION( 2,12,0 )
struct gtr_func_data
{
GSourceFunc function;
gpointer data;
};
static void
gtr_func_data_free( gpointer data )
{
#if GTK_CHECK_VERSION( 2,10,0 )
g_slice_free( struct gtr_func_data, data );
#else
g_free( data );
#endif
}
static struct gtr_func_data *
gtr_func_data_new( GSourceFunc function, gpointer data )
{
#if GTK_CHECK_VERSION( 2,10,0 )
struct gtr_func_data * d = g_slice_new( struct gtr_func_data );
#else
struct gtr_func_data * d = g_new( struct gtr_func_data, 1 );
#endif
d->function = function;
d->data = data;
return d;
}
static gboolean
gtr_thread_func( gpointer data )
{
gboolean more;
struct gtr_func_data * idle_data = data;
gdk_threads_enter( );
more = idle_data->function( idle_data->data );
gdk_threads_leave( );
return more;
}
#endif
guint
gtr_idle_add( GSourceFunc function, gpointer data )
{
#if GTK_CHECK_VERSION( 2,12,0 )
return gdk_threads_add_idle( function, data );
#else
return g_idle_add_full( G_PRIORITY_DEFAULT,
gtr_thread_func,
gtr_func_data_new( function, data ),
gtr_func_data_free );
#endif
}
guint
gtr_timeout_add_seconds( guint seconds, GSourceFunc function, gpointer data )
{
#if GTK_CHECK_VERSION( 2,14,0 )
return gdk_threads_add_timeout_seconds( seconds, function, data );
#elif GTK_CHECK_VERSION( 2,12,0 )
return gdk_threads_add_timeout( seconds*1000, function, data );
#else
return g_timeout_add_full( G_PRIORITY_DEFAULT,
seconds * 1000,
gtr_thread_func,
gtr_func_data_new( function, data ),
gtr_func_data_free );
#endif
}
void
gtr_http_failure_dialog( GtkWidget * parent, const char * url, long response_code )
{
GtkWindow * window = getWindow( parent );
GtkWidget * w = gtk_message_dialog_new( window, 0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
_( "Error opening \"%s\"" ), url );
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ),
_( "Server returned \"%1$ld %2$s\"" ),
response_code,
tr_webGetResponseStr( response_code ) );
g_signal_connect_swapped( w, "response", G_CALLBACK( gtk_widget_destroy ), w );
gtk_widget_show( w );
}
void
gtr_unrecognized_url_dialog( GtkWidget * parent, const char * url )
{
const char * xt = "xt=urn:btih";
GtkWindow * window = getWindow( parent );
GString * gstr = g_string_new( NULL );
GtkWidget * w = gtk_message_dialog_new( window, 0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"%s", _( "Unrecognized URL" ) );
g_string_append_printf( gstr, _( "Transmission doesn't know how to use \"%s\"" ), url );
if( gtr_is_magnet_link( url ) && ( strstr( url, xt ) == NULL ) )
{
g_string_append_printf( gstr, "\n \n" );
g_string_append_printf( gstr, _( "This magnet link appears to be intended for something other than BitTorrent. BitTorrent magnet links have a section containing \"%s\"." ), xt );
}
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ), "%s", gstr->str );
g_signal_connect_swapped( w, "response", G_CALLBACK( gtk_widget_destroy ), w );
gtk_widget_show( w );
g_string_free( gstr, TRUE );
}
/***
****
***/
void
gtr_paste_clipboard_url_into_entry( GtkWidget * e )
{
size_t i;
char * text[] = {
gtk_clipboard_wait_for_text( gtk_clipboard_get( GDK_SELECTION_PRIMARY ) ),
gtk_clipboard_wait_for_text( gtk_clipboard_get( GDK_SELECTION_CLIPBOARD ) )
};
for( i=0; i<G_N_ELEMENTS(text); ++i ) {
char * s = text[i];
if( s && ( gtr_is_supported_url( s ) || gtr_is_magnet_link( s ) ) ) {
gtk_entry_set_text( GTK_ENTRY( e ), s );
break;
}
}
for( i=0; i<G_N_ELEMENTS(text); ++i )
g_free( text[i] );
}
/***
****
***/
void
gtr_label_set_text( GtkLabel * lb, const char * newstr )
{
const char * oldstr = gtk_label_get_text( lb );
if( ( oldstr == NULL ) || strcmp( oldstr, newstr ) )
gtk_label_set_text( lb, newstr );
}