/* Screem: support.c, * some useful functions * * Copyright (C) 1999, 2000 David A Knight * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * * For contact information with the author of this source code please see * the AUTHORS file. If there is no AUTHORS file present then check the * about box under the help menu for a contact address */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fileops.h" #include "support.h" #include "readtags.h" #include "screem-application.h" /** * change_state: * * toggles widget sensitivity * * return values: none */ void change_state( GtkWidget *widget, gpointer data ) { gtk_widget_set_sensitive( widget, !GTK_WIDGET_IS_SENSITIVE( widget ) ); } void change_visible( GtkWidget *widget, gpointer data ) { if( GTK_WIDGET_VISIBLE( widget ) ) { gtk_widget_hide( widget ); } else { gtk_widget_show( widget ); } } gchar *screem_support_ctags( const gchar *dirname, const gchar *word, gchar **pattern ) { gchar *ret; tagFile *file; tagFileInfo *info; tagEntry *entry; gchar *tagfile; if( ! word ) { return NULL; } info = g_new0( tagFileInfo, 1 ); entry = g_new0( tagEntry, 1 ); ret = NULL; tagfile = g_strconcat( dirname, G_DIR_SEPARATOR_S, "tags", NULL ); file = tagsOpen( tagfile, info ); if( ! file ) { g_free( tagfile ); tagfile = g_strconcat( dirname, G_DIR_SEPARATOR_S, "TAGS", NULL ); file = tagsOpen( tagfile, info ); } g_free( tagfile ); if( file ) { if(tagsFind(file, entry, word, TAG_OBSERVECASE | TAG_FULLMATCH) == TagSuccess) { ret = g_strconcat( dirname, G_DIR_SEPARATOR_S, entry->file, NULL ); if( pattern ) { if( entry->address.pattern ) { *pattern = screem_support_escape_regexp( entry->address.pattern ); } else { *pattern = NULL; } } } } g_free( entry ); g_free( info ); return ret; } /* process regexp, strip leading and trailing '/' characters, escape ( ) { } $ * + ? */ gchar *screem_support_escape_regexp( const gchar *pattern ) { gchar *ret; GString *temp; g_return_val_if_fail( pattern != NULL, NULL ); g_return_val_if_fail( *pattern == '/', NULL ); /* will need at least strlen( pattern ) */ temp = g_string_sized_new( strlen( pattern ) ); pattern ++; while( *pattern != '\0' && ( *pattern != '/' || *( pattern - 1 ) == '\\' ) ) { gchar p; gchar c; p = *( pattern - 1 ); c = *pattern; if( p != '\\' && ( c == '(' || c == ')' || c == '{' || c == '}' || c == '*' || c == '+' || c == '?' ) ) { g_string_append_c( temp, '\\' ); g_string_append_c( temp, c ); } else if( p != '\\' && c == '$' && *(pattern+1) != '/' ) { g_string_append_c( temp, '\\' ); g_string_append_c( temp, c ); } else { g_string_append_c( temp, c ); } pattern ++; } if( temp->len ) { ret = g_strdup( temp->str ); } else { ret = NULL; } g_string_free( temp, TRUE ); return ret; } gboolean screem_gtk_list_store_find( GtkListStore *store, GtkTreeIter *iter, guint col, GValue *value, GCompareFunc compare ) { GtkTreeModel *model; GValue mvalue = { 0 }; gboolean ret; g_return_val_if_fail( iter != NULL, FALSE ); g_return_val_if_fail( value != NULL, FALSE ); g_return_val_if_fail( compare != NULL, FALSE ); model = GTK_TREE_MODEL( store ); g_return_val_if_fail( gtk_tree_model_get_column_type( model, col ) == G_VALUE_TYPE( value ), FALSE ); ret = gtk_tree_model_get_iter_first( model, iter ); while( ret ) { gtk_tree_model_get_value( model, iter, col, &mvalue ); if( ! compare( value, &mvalue ) ) { g_value_unset( &mvalue ); break; } g_value_unset( &mvalue ); ret = gtk_tree_model_iter_next( model, iter ); } return ret; } static gint screem_g_type_string_compare( GValue *a, GValue *b ) { const gchar *astr; const gchar *bstr; gint ret; g_assert( G_VALUE_TYPE( a ) == G_TYPE_STRING ); g_assert( G_VALUE_TYPE( b ) == G_TYPE_STRING ); astr = g_value_get_string( a ); bstr = g_value_get_string( b ); if( astr && bstr ) { ret = strcmp( astr, bstr ); } else { ret = ( astr - bstr ); } return ret; } gboolean screem_gtk_list_store_find_string( GtkListStore *store, GtkTreeIter *iter, guint col, const gchar *value ) { GValue val = { 0 }; gboolean ret; g_value_init( &val, G_TYPE_STRING ); g_value_set_string( &val, value ); ret = screem_gtk_list_store_find( store, iter, col, &val, (GCompareFunc)screem_g_type_string_compare ); g_value_unset( &val ); return ret; } static gint find_pattern( GValue *a, GValue *b ) { const gchar *astr; const gchar *bstr; gint ret; g_assert( G_VALUE_TYPE( a ) == G_TYPE_STRING ); g_assert( G_VALUE_TYPE( b ) == G_TYPE_STRING ); astr = g_value_get_string( a ); bstr = g_value_get_string( b ); g_assert( astr ); g_assert( bstr ); if( ! strncmp( "regex:", bstr, strlen( "regex:" ) ) ) { /* regexp pattern */ g_warning( "regex: pattern match not supported yet\n" ); ret = -1; } else if( ! strncmp( "glob:", bstr, strlen( "glob:" ) ) ) { /* glob */ ret = fnmatch( bstr + strlen( "glob:" ), astr, 0 ); } else { ret = strcmp( bstr, astr ); } return ret; } gboolean screem_gtk_list_store_find_pattern( GtkListStore *store, GtkTreeIter *iter, guint col, const gchar *value ) { GValue val = { 0 }; gboolean ret; g_value_init( &val, G_TYPE_STRING ); g_value_set_string( &val, value ); ret = screem_gtk_list_store_find( store, iter, col, &val, (GCompareFunc)find_pattern ); g_value_unset( &val ); return ret; } static gint screem_mime_type_compare_types( GValue *a, GValue *b ) { const gchar *astr; const gchar *bstr; gint ret; GnomeVFSMimeEquivalence eq; g_assert( G_VALUE_TYPE( a ) == G_TYPE_STRING ); g_assert( G_VALUE_TYPE( b ) == G_TYPE_STRING ); astr = g_value_get_string( a ); bstr = g_value_get_string( b ); g_assert( astr ); g_assert( bstr ); eq = gnome_vfs_mime_type_get_equivalence( astr, bstr ); if( eq == GNOME_VFS_MIME_IDENTICAL ) { ret = 0; } else { ret = strcmp( astr, bstr ); } return ret; } gboolean screem_gtk_list_store_find_mime_type( GtkListStore *store, GtkTreeIter *iter, guint col, const gchar *value ) { GValue val = { 0 }; gboolean ret; g_value_init( &val, G_TYPE_STRING ); g_value_set_string( &val, value ); ret = screem_gtk_list_store_find( store, iter, col, &val, (GCompareFunc)screem_mime_type_compare_types ); g_value_unset( &val ); return ret; } static gint screem_pointer_compare_types( GValue *a, GValue *b ) { gint ret; g_assert( G_VALUE_TYPE( a ) == G_TYPE_POINTER ); g_assert( G_VALUE_TYPE( b ) == G_TYPE_POINTER ); ret = 0; if( a && b ) { if( a < b ) { ret = -1; } else if( a > b ) { ret = 1; } } else if( a ) { ret = 1; } else { ret = -1; } return ret; } gboolean screem_gtk_list_store_find_pointer( GtkListStore *store, GtkTreeIter *iter, guint col, const gpointer value ) { GValue val = { 0 }; gboolean ret; g_value_init( &val, G_TYPE_POINTER ); g_value_set_pointer( &val, value ); ret = screem_gtk_list_store_find( store, iter, col, &val, (GCompareFunc)screem_pointer_compare_types ); g_value_unset( &val ); return ret; } gchar *screem_support_charset_convert( const gchar *data, guint len, gchar **data_charset ) { #define BOM (gunichar2)0xFEFF #define ANTIBOM (gunichar2)0xFFFE const gunichar2 *utf16data; GConfClient *client; const gchar *end; gchar *ret; gchar *default_charset; client = gconf_client_get_default(); default_charset = gconf_client_get_string( client, "/apps/screem/editor/default_charset", NULL ); ret = NULL; utf16data = (const gunichar2*)data; if( data_charset ) { *data_charset = NULL; } if( ! data ) { } else if( utf16data[ 0 ] == BOM || utf16data[ 0 ] == ANTIBOM ) { /* UTF-16 LE / UTF-16 BE, * code from ximian bugzilla attach_id=7551 */ gunichar2 *it; gchar *temp; if( utf16data[ 0 ] == ANTIBOM ) { /* WARNING: should really be changing * a const string */ for( it = utf16data; *it != '\0'; it ++ ) { *it = GUINT16_SWAP_LE_BE( *it ); } } if( utf16data[ 0 ] == BOM ) { utf16data ++; len -= 2; } temp = g_utf16_to_utf8( utf16data, len / 2, NULL, NULL, NULL ); if( temp ) { ret = temp; if( data_charset ) { *data_charset = g_strdup( "UTF-16" ); } } } else if( ! g_utf8_validate( data, len, &end ) ) { gchar *temp = NULL; const gchar *charset; gboolean utf8; /* FIXME: perform charset detection based on markup * rules, * e.g. meta, etc. * * can't use screem_markup_get_charset() here as * it only deals with utf-8 input * */ utf8 = g_get_charset( &charset ); if( ! utf8 ) { temp = screem_support_charset_convert_to( data, "UTF-8", charset ); if( temp && data_charset ) { *data_charset = g_strdup( charset ); } } if( ( ! temp ) && default_charset ) { temp = screem_support_charset_convert_to( data, "UTF-8", default_charset ); if( temp && data_charset ) { *data_charset = g_strdup( default_charset ); } } if( ( ! temp ) && g_ascii_strcasecmp( charset, "ISO-8859-1" ) ) { temp = screem_support_charset_convert_to( data, "UTF-8", "ISO-8859-1" ); if( temp && data_charset ) { *data_charset = g_strdup( "ISO-8859-1" ); } } ret = temp; } else { ret = g_strndup( data, len ); if( data_charset ) { *data_charset = g_strdup( "UTF-8" ); } } g_free( default_charset ); g_object_unref( client ); return ret; } gchar *screem_support_charset_convert_to( const gchar *data, const gchar *charset, const gchar *from ) { gchar *ret; ret = NULL; g_return_val_if_fail( from != NULL, NULL ); g_return_val_if_fail( charset != NULL, NULL ); if( g_strcasecmp( from, charset ) ) { /* need to convert from UTF-8 to charset */ gchar *temp; temp = g_convert( data, strlen( data ), charset, from, NULL, NULL, NULL ); ret = temp; } return ret; } /* HACK due to the huge annoyance of gnome-vfs mime data * determining that anything starting mime_type; } else { /* failed to get file info, fall back to a safe * default mime type */ type = "application/octet-stream"; } ret = screem_get_mime_type_override( filename, type ); gnome_vfs_file_info_unref( info ); return ret; } const gchar *screem_get_mime_type_override( const gchar *filename, const gchar *type ) { static GStringChunk *cache = NULL; const gchar *ext; gchar *ret; if( ( ! filename ) && ( ! type ) && cache ) { g_string_chunk_free( cache ); return NULL; } if( ! cache ) { cache = g_string_chunk_new( 128 ); } ret = NULL; if( type ) { ext = strrchr( filename, '.' ); if( ! ext ) { ret = g_string_chunk_insert_const( cache, type ); } else if( ! strcmp( ".screem", ext ) ) { ret = g_string_chunk_insert_const( cache, "application/x-screem" ); } else if( ! strcmp( ".tagtree", ext ) ) { ret = g_string_chunk_insert_const( cache, "application/x-screem-tag-tree" ); } else if( ! strcmp( ".wml", ext ) ) { ret = g_string_chunk_insert_const( cache, "text/vnd.wap.wml" ); } else if( ! strcmp( ".wmls", ext ) ) { ret = g_string_chunk_insert_const( cache, "text/vnd.wap.wmlscript" ); } else if( ! strcmp( ".wmlb", ext ) ) { ret = g_string_chunk_insert_const( cache, "text/vnd.wap.wmlb" ); } else if( ! strcmp( ".wmlc", ext ) ) { ret = g_string_chunk_insert_const( cache, "text/vnd.wap.wmlc" ); } else if( ! strcmp( ".wmlsc", ext ) ) { ret = g_string_chunk_insert_const( cache, "text/vnd.wap.wmlscriptc" ); } else if( ! strcmp( ".php", ext ) ) { ret = g_string_chunk_insert_const( cache, "application/x-php" ); } else if( ! strcmp( ".phps", ext ) ) { ret = g_string_chunk_insert_const( cache, "application/x-php-souce" ); } else { ret = g_string_chunk_insert_const( cache, type ); } } return ret; } const gchar *screem_utf8_skip_space( const gchar *txt ) { gunichar c; g_return_val_if_fail( txt != NULL, NULL ); do { c = g_utf8_get_char( txt ); } while( c != '\0' && g_unichar_isspace( c ) && ( txt = g_utf8_next_char( txt ) ) ); return txt; } const gchar *screem_utf8_skip_to_space( const gchar *txt ) { gunichar c; g_return_val_if_fail( txt != NULL, NULL ); do { c = g_utf8_get_char( txt ); } while( c != '\0' && ! g_unichar_isspace( c ) && ( txt = g_utf8_next_char( txt ) ) ); return txt; } /* ripped out of gedit2 */ gchar* screem_escape_underlines( const gchar* text ) { GString *str; gint length; const gchar *p; const gchar *end; g_return_val_if_fail( text != NULL, NULL ); length = strlen( text ); /* result will be at least length in size, so alloc * that much space to start with */ str = g_string_sized_new( length ); p = text; end = text + length; while( p != end ) { const gchar *next; next = g_utf8_next_char( p ); switch( *p ) { case '_': g_string_append( str, "__" ); break; default: g_string_append_len( str, p, next - p ); break; } p = next; } return g_string_free( str, FALSE ); } gboolean screem_execute_default_app( const gchar *uri ) { const gchar *mime; GnomeVFSMimeApplication *app; gchar *url; gchar *exstr; gchar *temp; mime = gnome_vfs_get_mime_type( uri ); app = gnome_vfs_mime_get_default_application( mime ); if( app ) { url = NULL; if( ! app->expects_uris ) { url = gnome_vfs_get_local_path_from_uri( uri ); } else { /* FIXME check app supports the method uri is using */ } if( ! url ) { url = g_strdup( uri ); } uri = strstr( app->command, "%s" ); if( ! uri ) { exstr = g_strconcat( app->command, " \"", url, "\"", NULL ); } else { temp = g_strndup( app->command, uri - app->command ); exstr = g_strconcat( temp, url, uri + strlen( "%s" ), NULL ); g_free( temp ); } if( app->requires_terminal ) { gnome_execute_terminal_shell( NULL, exstr ); } else { gnome_execute_shell( NULL, exstr ); } g_free( exstr ); } return ( app != NULL ); } void g_string_append_utf8_len( GString *str, const gchar *utf8, guint len ) { gunichar c; while( len ) { c = g_utf8_get_char( utf8 ); g_string_append_unichar( str, c ); utf8 = g_utf8_next_char( utf8 ); len --; } } GtkPositionType screem_get_tab_position( void ) { GConfClient *client; static const GConfEnumStringPair positions[] = { { GTK_POS_LEFT, "left" }, { GTK_POS_RIGHT, "right" }, { GTK_POS_TOP, "top" }, { GTK_POS_BOTTOM, "bottom" }, { GTK_POS_TOP, "" }, { GTK_POS_TOP, NULL } }; gchar *pos; gint position; client = gconf_client_get_default(); pos = gconf_client_get_string( client, "/apps/screem/ui/tab_position", NULL ); if( ! pos ) { pos = g_strdup( "top" ); } gconf_string_to_enum( positions, pos, &position ); g_free( pos ); g_object_unref( client ); return position; } void screem_set_cursor( GtkWidget *widget, GdkCursorType type ) { GdkDisplay *display; GdkCursor *cursor; cursor = NULL; display = NULL; if( widget ) { display = gtk_widget_get_display( GTK_WIDGET( widget ) ); } if( type != GDK_LAST_CURSOR ) { if( display ) { cursor = gdk_cursor_new_for_display( display, type ); } else { cursor = gdk_cursor_new( type ); } } if( widget && widget->window ) { gdk_window_set_cursor( widget->window, cursor ); } if( cursor ) { gdk_cursor_unref( cursor ); } gdk_threads_leave(); gdk_flush(); gdk_threads_enter(); } /** * screem_popup_menu_do_popup_modal, based off * gnome_popup_menu_do_popup_modal */ void screem_popup_menu_do_popup_modal( GtkWidget *popup, GtkMenuPositionFunc pos_func, gpointer pos_data, GdkEventButton *event, gpointer user_data, GtkWidget *for_widget ) { guint id; guint button; guint32 timestamp; id = g_signal_connect( popup, "deactivate", G_CALLBACK( gtk_main_quit ), NULL ); if( event ) { button = event->button; timestamp = event->time; } else { button = 0; timestamp = GDK_CURRENT_TIME; } #ifdef HAVE_GTK_MULTIHEAD gtk_menu_set_screen( GTK_MENU( popup ), gtk_widget_get_screen( for_widget ) ); #endif gtk_menu_popup( GTK_MENU( popup ), NULL, NULL, pos_func, pos_data, button, timestamp ); gtk_grab_add( popup ); gtk_main(); gtk_grab_remove( popup ); g_signal_handler_disconnect( G_OBJECT( popup ), id ); } static gboolean add_filter_type( gpointer key, gpointer value, gpointer data ) { gtk_file_filter_add_mime_type( GTK_FILE_FILTER( data ), (const gchar *)value ); return FALSE; } static gboolean filter_mime_wildcard( const GtkFileFilterInfo *info, gpointer data ) { gboolean ret; ret = FALSE; if( info->contains & GTK_FILE_FILTER_MIME_TYPE ) { ret = g_pattern_match_string( (GPatternSpec *)data, info->mime_type ); } return ret; } static gboolean filter_mime_inherits( const GtkFileFilterInfo *info, gpointer data ) { gboolean ret; ret = FALSE; if( ! data ) { g_warning( "Hmm, NULL path given to filter_mime_inherits()\n" ); return FALSE; } if( info->contains & GTK_FILE_FILTER_MIME_TYPE ) { if( info->mime_type ) { ret = ! strcmp( (gchar*)data, info->mime_type ); if( ! ret ) { ret = ( gnome_vfs_mime_type_get_equivalence( info->mime_type, (gchar*)data ) == GNOME_VFS_MIME_PARENT ); } } else { g_warning( "NULL mime type in mime type filter\n" ); } } return ret; } GtkFileFilter *screem_get_file_filter( const gchar *name ) { static GHashTable *filters = NULL; GtkSourceLanguagesManager* lm; GHashTable *features; GHashTable *feature; GtkFileFilter *filter = NULL; if( ! name ) { return NULL; } /* cleanup mode */ if( (void*)name == (void*)0x1 ) { if( filters ) { g_hash_table_destroy( filters ); filters = NULL; } return NULL; } if( ! filters ) { filters = g_hash_table_new_full( g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_object_unref ); } filter = g_hash_table_lookup( filters, name ); if( ! filter ) { lm = screem_application_load_syntax_tables(); features = g_object_get_data( G_OBJECT( lm ), "features" ); filter = gtk_file_filter_new(); gtk_file_filter_set_name( filter, name ); if( ! strcmp( _( "All Files" ), name ) ) { gtk_file_filter_add_pattern( filter, "*" ); } else if( ! strcmp( _( "Markup Files" ), name ) ) { /* get markup types */ feature = g_hash_table_lookup( features, "markup" ); g_assert( feature ); g_hash_table_foreach( feature, (GHFunc)add_filter_type, filter ); /* we also want to handle text/xml types, * also add application/+xml types for * those that don't correctly set what * they inherit from */ gtk_file_filter_add_custom( filter, GTK_FILE_FILTER_MIME_TYPE, (GtkFileFilterFunc)filter_mime_inherits, "text/xml", NULL ); gtk_file_filter_add_custom( filter, GTK_FILE_FILTER_MIME_TYPE, (GtkFileFilterFunc)filter_mime_wildcard, g_pattern_spec_new( "application/*+xml" ), (GDestroyNotify)g_pattern_spec_free); } else if( ! strcmp( _( "CSS Files" ), name ) ) { gtk_file_filter_add_mime_type( filter, "text/css" ); } else if( ! strcmp( _( "Javascript Files" ), name ) ) { gtk_file_filter_add_mime_type( filter, "text/javascript" ); gtk_file_filter_add_mime_type( filter, "text/x-javascript" ); } else if( ! strcmp( _( "All Text Files" ), name ) ) { gtk_file_filter_add_custom( filter, GTK_FILE_FILTER_MIME_TYPE, (GtkFileFilterFunc)filter_mime_wildcard, g_pattern_spec_new( "text/*" ), (GDestroyNotify)g_pattern_spec_free); gtk_file_filter_add_custom( filter, GTK_FILE_FILTER_MIME_TYPE, (GtkFileFilterFunc)filter_mime_inherits, "text/plain", NULL ); } else { /* unknown filter requested */ g_assert( FALSE ); } g_object_ref( filter ); g_hash_table_insert( filters, g_strdup( name ), filter ); } return filter; } /* override a GnomeFileEntry widgets browser button, horrible * hack but it gets us the ability to place / size the dialog + * use non local volumes */ void screem_file_entry_browse( GtkWidget *entry, gpointer data ) { gchar *title; gchar *dir; GtkFileChooserAction action; gboolean isdir; gchar *filename; GtkWidget *widget; g_signal_stop_emission_by_name( G_OBJECT( entry ), "browse_clicked" ); g_object_get( G_OBJECT( entry ), "browse_dialog_title", &title, "default_path", &dir, "filechooser_action", &action, "gtk_entry", &widget, "directory_entry", &isdir, NULL ); if( isdir ) { switch( action ) { case GTK_FILE_CHOOSER_ACTION_SAVE: action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; break; case GTK_FILE_CHOOSER_ACTION_OPEN: action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; break; default: break; } } filename = screem_fileselect( title, NULL, action, dir, NULL, FALSE ); if( filename ) { gtk_entry_set_text( GTK_ENTRY( widget ), filename ); g_free( filename ); } g_free( title ); g_free( dir ); g_object_unref( G_OBJECT( widget ) ); } static gboolean find_accel( GtkAccelKey *key, GClosure *closure, GdkEventKey *event ) { gboolean ret; ret = ( key->accel_key == event->keyval ); if( ret ) { ret = ( key->accel_mods & event->state ); } return ret; } gboolean screem_find_accel( GtkAccelGroup *group, GdkEventKey *event ) { return ( gtk_accel_group_find( group, (GtkAccelGroupFindFunc)find_accel, event ) != NULL ); } gint screem_mime_type_compare( gconstpointer a, gconstpointer b ) { const gchar *showa; const gchar *showb; showa = gnome_vfs_mime_get_description( a ); showb = gnome_vfs_mime_get_description( b ); if( ! showa ) { showa = a; } if( ! showb ) { showb = b; } return g_strcasecmp( showa, showb ); } void screem_hig_alert( GtkMessageType type, GtkButtonsType buttons, const gchar *primary, const gchar *secondary, GtkWidget *parent ) { GtkWidget *widget; widget = gtk_message_dialog_new( GTK_WINDOW( parent ), GTK_DIALOG_MODAL, type, buttons, primary ); gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( widget ), secondary ); gtk_widget_show_all( widget ); if( parent ) { gtk_window_set_transient_for( GTK_WINDOW( widget ), GTK_WINDOW( parent ) ); } gtk_dialog_run( GTK_DIALOG( widget ) ); gtk_widget_destroy( widget ); } GtkListStore *screem_support_get_mime_types_store( void ) { GtkTreeModel *list; GSList *types; const GSList *langs; GtkSourceLanguagesManager *lm; GtkTreeIter it; list = GTK_TREE_MODEL( gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_STRING ) ); types = NULL; lm = screem_application_load_syntax_tables(); langs = gtk_source_languages_manager_get_available_languages( lm ); while( langs ) { GtkSourceLanguage *lang; GSList *tmp; lang = GTK_SOURCE_LANGUAGE( langs->data ); tmp = gtk_source_language_get_mime_types( lang ); tmp = g_slist_copy( tmp ); if( types ) { types = g_slist_concat( types, tmp ); } else { types = tmp; } langs = langs->next; } /* add plain text */ types = g_slist_prepend( types, "text/plain" ); types = g_slist_sort( types, (GCompareFunc)screem_mime_type_compare ); for( langs = types; langs; langs = langs->next ) { const gchar *showtype; showtype = gnome_vfs_mime_get_description( langs->data ); if( showtype && ! screem_gtk_list_store_find_mime_type( GTK_LIST_STORE( list ), &it, 1, langs->data ) && ! screem_gtk_list_store_find_string( GTK_LIST_STORE( list ), &it, 0, showtype ) ) { gtk_list_store_append( GTK_LIST_STORE( list ), &it ); gtk_list_store_set( GTK_LIST_STORE( list ), &it, 0, showtype, 1, langs->data, -1 ); } } return GTK_LIST_STORE( list ); } gchar *screem_gdk_color_to_string( const GdkColor *colour, gboolean eightbit ) { guint16 r; guint16 g; guint16 b; gchar *ret; r = colour->red; g = colour->green; b = colour->blue; if( eightbit ) { r = r >> 8; g = g >> 8; b = b >> 8; ret = g_strdup_printf( "#%.2x%.2x%.2x", r, g, b ); } else { ret = g_strdup_printf( "#%04x%04x%04x", r, g, b ); } return ret; } gchar* screem_escape_char( const gchar* text, gchar c ) { GString *str; gint length; const gchar *p; const gchar *end; g_return_val_if_fail( text != NULL, NULL ); length = strlen( text ); /* will need at least strlen( text ) */ str = g_string_sized_new( strlen( text ) ); p = text; end = text + length; while( p != end ) { const gchar *next; next = g_utf8_next_char( p ); if( *p == c ) { g_string_append_c( str, '_' ); } else { g_string_append_len( str, p, next - p ); } p = next; } return g_string_free( str, FALSE ); } void screem_gtk_add_history( GtkWidget *widget ) { const gchar *name; GtkTreeModel *model; const gchar *gconf_base = "/apps/gnome-settings/screem/"; gchar *path; GConfClient *client; GSList *values; GSList *tmp; GtkTreeIter it; GtkEntryCompletion *completion; name = gtk_widget_get_name( widget ); model = NULL; if( GTK_IS_COMBO_BOX_ENTRY( widget ) ) { model = gtk_combo_box_get_model( GTK_COMBO_BOX( widget ) ); if( model ) { return; } /* create a new model */ model = GTK_TREE_MODEL( gtk_list_store_new( 1, G_TYPE_STRING ) ); gtk_combo_box_set_model( GTK_COMBO_BOX( widget ), model ); /* get history */ client = gconf_client_get_default(); path = g_strconcat( gconf_base, "history-", name, NULL ); values = gconf_client_get_list( client, path, GCONF_VALUE_STRING, NULL ); /* add to model */ for( tmp = values; tmp; tmp = tmp->next ) { gtk_list_store_append( GTK_LIST_STORE( model ), &it ); gtk_list_store_set( GTK_LIST_STORE( model ), &it, 0, tmp->data, -1 ); g_free( tmp->data ); } g_slist_free( values ); g_free( path ); g_object_unref( client ); gtk_combo_box_entry_set_text_column( GTK_COMBO_BOX_ENTRY( widget ), 0 ); /* get GtkEntry so we can add a GtkEntryCompletion, * and listen for changes so we can add new * items to the model if needed */ widget = GTK_BIN( widget )->child; } if( GTK_IS_ENTRY( widget ) ) { if( ! model ) { model = GTK_TREE_MODEL( gtk_list_store_new( 1, G_TYPE_STRING ) ); } completion = gtk_entry_completion_new(); gtk_entry_completion_set_model( completion, model ); gtk_entry_completion_set_text_column( completion, 0 ); gtk_entry_set_completion( GTK_ENTRY( widget ), completion ); g_object_unref( completion ); g_object_unref( model ); } } /* * string1 = title, string2 = "filter,filter,filter" * int1 = GtkFileChooserAction value * int2 = 1 if we want a preview * */ GtkWidget *screem_create_gtk_file_chooser_button( gchar *name, const gchar *title, const gchar *filters_str, gint action, gint preview ) { GtkWidget *dialog; GtkWidget *button; GtkFileChooserAction chooser_action; gchar **filter_names; gchar **tmp; GSList *filters; GtkFileFilter *filter; switch( action ) { case 3: chooser_action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; break; case 2: chooser_action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; break; case 1: chooser_action = GTK_FILE_CHOOSER_ACTION_SAVE; break; case 0: default: chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN; break; } filter_names = NULL; filters = NULL; if( filters_str ) { filter_names = g_strsplit( filters_str, ",", 0 ); } for( tmp = filter_names; tmp && *tmp; tmp ++ ) { g_strstrip( *tmp ); filter = screem_get_file_filter( gettext( *tmp ) ); filters = g_slist_prepend( filters, (gpointer)filter ); } g_strfreev( filter_names ); dialog = screem_file_dialog_create( title, NULL, chooser_action, FALSE, NULL, filters, preview ); g_slist_free( filters ); g_signal_connect( G_OBJECT( dialog ), "show", G_CALLBACK( screem_gtk_file_chooser_button_show ), NULL ); g_signal_connect( G_OBJECT( dialog ), "response", G_CALLBACK( screem_gtk_file_chooser_button_response ), NULL ); button = gtk_file_chooser_button_new_with_dialog( dialog ); gtk_file_chooser_set_action( GTK_FILE_CHOOSER( button ), chooser_action ); gtk_widget_set_name( button, name ); gtk_widget_show_all( button ); return button; } /* modified from gnome-desktop-item.c */ gchar *screem_lookup_icon( GtkIconTheme *icon_theme, const gchar *icon, gint desired_size, gint flags ) { GtkIconInfo *info; gchar *full = NULL; if( icon == NULL || *icon == '\0' ) { return NULL; } else if( g_path_is_absolute( icon ) ) { if( g_file_test( icon, G_FILE_TEST_EXISTS ) ) { return g_strdup( icon ); } else { return NULL; } } else { gchar *icon_no_extension; gchar *p; if( icon_theme == NULL ) { icon_theme = gtk_icon_theme_get_default(); } else { g_object_ref( icon_theme ); } icon_no_extension = g_strdup( icon ); p = strrchr( icon_no_extension, '.' ); if( p && ( strcmp (p, ".png" ) == 0 || strcmp (p, ".xpm" ) == 0 || strcmp (p, ".svg" ) == 0 ) ) { *p = 0; } info = gtk_icon_theme_lookup_icon( icon_theme, icon_no_extension, desired_size, flags ); if( info ) { full = (gchar*)gtk_icon_info_get_filename( info ); if( full ) { full = g_strdup( full ); } gtk_icon_info_free( info ); } g_object_unref( icon_theme ); g_free( icon_no_extension ); } if( ! full ) { /* Fall back on old Gnome code */ full = gnome_program_locate_file( NULL, GNOME_FILE_DOMAIN_PIXMAP, icon, TRUE /* only_if_exists */, NULL /* ret_locations */); if( ! full ) { full = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP, icon, TRUE /* only_if_exists */, NULL /* ret_locations */); } } return full; } gchar *screem_strip_extra_space( const gchar *str ) { gchar *ret; GString *tmp; gunichar c; g_return_val_if_fail( str != NULL, NULL ); /* this will be too long if we do strip space, but * avoids reallocs */ tmp = g_string_sized_new( strlen( str ) ); c = g_utf8_get_char( str ); while( c != '\0' ) { if( c == '\t' || c == '\r' || c == '\n' ) { c = ' '; } g_string_append_unichar( tmp, c ); if( g_unichar_isspace( c ) ) { str = screem_utf8_skip_space( str ); } else { str = g_utf8_next_char( str ); } c = g_utf8_get_char( str ); } ret = tmp->str; g_string_free( tmp, FALSE ); return ret; }