From ba429d344132c088177e853cce8ff7181570b221 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 19:42:51 +0200 Subject: Adding upstream version 44.2. Signed-off-by: Daniel Baumann --- gedit/gedit-utils.c | 542 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 gedit/gedit-utils.c (limited to 'gedit/gedit-utils.c') diff --git a/gedit/gedit-utils.c b/gedit/gedit-utils.c new file mode 100644 index 0000000..9fc9e4f --- /dev/null +++ b/gedit/gedit-utils.c @@ -0,0 +1,542 @@ +/* + * gedit-utils.c + * This file is part of gedit + * + * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence + * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi + * Copyright (C) 2003-2005 Paolo Maggi + * + * 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, see . + */ + +#include "gedit-utils.h" +#include +#include +#include +#include "gedit-debug.h" + +gboolean +gedit_utils_menu_position_under_tree_view (GtkTreeView *tree_view, + GdkRectangle *rect) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + gint count_rows; + GList *rows; + gint widget_x, widget_y; + + model = gtk_tree_view_get_model (tree_view); + g_return_val_if_fail (model != NULL, FALSE); + + selection = gtk_tree_view_get_selection (tree_view); + g_return_val_if_fail (selection != NULL, FALSE); + + count_rows = gtk_tree_selection_count_selected_rows (selection); + if (count_rows != 1) + return FALSE; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + gtk_tree_view_get_cell_area (tree_view, (GtkTreePath *)(rows->data), + gtk_tree_view_get_column (tree_view, 0), + rect); + + gtk_tree_view_convert_bin_window_to_widget_coords (tree_view, rect->x, rect->y, &widget_x, &widget_y); + rect->x = widget_x; + rect->y = widget_y; + + g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free); + return TRUE; +} + +/** + * gedit_utils_set_atk_name_description: + * @widget: The Gtk widget for which name/description to be set + * @name: Atk name string + * @description: Atk description string + * + * This function sets up name and description + * for a specified gtk widget. + */ +void +gedit_utils_set_atk_name_description (GtkWidget *widget, + const gchar *name, + const gchar *description) +{ + AtkObject *aobj; + + aobj = gtk_widget_get_accessible (widget); + + if (!(GTK_IS_ACCESSIBLE (aobj))) + return; + + if (name) + atk_object_set_name (aobj, name); + + if (description) + atk_object_set_description (aobj, description); +} + +static gchar * +uri_get_dirname (const gchar *uri) +{ + gchar *res; + gchar *str; + + g_return_val_if_fail (uri != NULL, NULL); + + /* CHECK: does it work with uri chaining? - Paolo */ + str = g_path_get_dirname (uri); + g_return_val_if_fail (str != NULL, g_strdup (".")); + + if ((strlen (str) == 1) && (*str == '.')) + { + g_free (str); + + return NULL; + } + + res = tepl_utils_replace_home_dir_with_tilde (str); + + g_free (str); + + return res; +} + +/** + * gedit_utils_location_get_dirname_for_display: + * @location: the location + * + * Returns a string suitable to be displayed in the UI indicating + * the name of the directory where the file is located. + * For remote files it may also contain the hostname etc. + * For local files it tries to replace the home dir with ~. + * + * Returns: (transfer full): a string to display the dirname + */ +gchar * +gedit_utils_location_get_dirname_for_display (GFile *location) +{ + gchar *uri; + gchar *res; + GMount *mount; + + g_return_val_if_fail (location != NULL, NULL); + + /* we use the parse name, that is either the local path + * or an uri but which is utf8 safe */ + uri = g_file_get_parse_name (location); + + /* FIXME: this is sync... is it a problem? */ + mount = g_file_find_enclosing_mount (location, NULL, NULL); + if (mount != NULL) + { + gchar *mount_name; + gchar *path = NULL; + gchar *dirname; + + mount_name = g_mount_get_name (mount); + g_object_unref (mount); + + /* obtain the "path" part of the uri */ + tepl_utils_decode_uri (uri, + NULL, NULL, + NULL, NULL, + &path); + + if (path == NULL) + { + dirname = uri_get_dirname (uri); + } + else + { + dirname = uri_get_dirname (path); + } + + if (dirname == NULL || strcmp (dirname, ".") == 0) + { + res = mount_name; + } + else + { + res = g_strdup_printf ("%s %s", mount_name, dirname); + g_free (mount_name); + } + + g_free (path); + g_free (dirname); + } + else + { + /* fallback for local files or uris without mounts */ + res = uri_get_dirname (uri); + } + + g_free (uri); + + return res; +} + +static gboolean +is_valid_scheme_character (gchar c) +{ + return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.'; +} + +static gboolean +has_valid_scheme (const gchar *uri) +{ + const gchar *p; + + p = uri; + + if (!is_valid_scheme_character (*p)) + { + return FALSE; + } + + do + { + p++; + } while (is_valid_scheme_character (*p)); + + return *p == ':'; +} + +gboolean +gedit_utils_is_valid_location (GFile *location) +{ + const guchar *p; + gchar *uri; + gboolean is_valid; + + if (location == NULL) + return FALSE; + + uri = g_file_get_uri (location); + + if (!has_valid_scheme (uri)) + { + g_free (uri); + return FALSE; + } + + is_valid = TRUE; + + /* We expect to have a fully valid set of characters */ + for (p = (const guchar *)uri; *p; p++) { + if (*p == '%') + { + ++p; + if (!g_ascii_isxdigit (*p)) + { + is_valid = FALSE; + break; + } + + ++p; + if (!g_ascii_isxdigit (*p)) + { + is_valid = FALSE; + break; + } + } + else + { + if (*p <= 32 || *p >= 128) + { + is_valid = FALSE; + break; + } + } + } + + g_free (uri); + + return is_valid; +} + + +static gchar * +make_canonical_uri_from_shell_arg (const gchar *str) +{ + GFile *gfile; + gchar *uri; + + g_return_val_if_fail (str != NULL, NULL); + g_return_val_if_fail (*str != '\0', NULL); + + /* Note for the future: + * FIXME: is still still relevant? + * + * paolo: and flame whoever tells + * you that file:///gnome/test_files/hëllò + * doesn't work --- that's not a valid URI + * + * federico: well, another solution that + * does not requires patch to _from_shell_args + * is to check that the string returned by it + * contains only ASCII chars + * paolo: hmmmm, isn't there + * gnome_vfs_is_uri_valid() or something? + * : I will use gedit_utils_is_valid_uri () + * + */ + + gfile = g_file_new_for_commandline_arg (str); + + if (gedit_utils_is_valid_location (gfile)) + { + uri = g_file_get_uri (gfile); + g_object_unref (gfile); + return uri; + } + + g_object_unref (gfile); + return NULL; +} + + +/** + * gedit_utils_basename_for_display: + * @location: location for which the basename should be displayed + * + * Returns: (transfer full): the basename of a file suitable for display to users. + */ +gchar * +gedit_utils_basename_for_display (GFile *location) +{ + gchar *name; + gchar *hn; + gchar *uri; + + g_return_val_if_fail (G_IS_FILE (location), NULL); + + uri = g_file_get_uri (location); + + /* First, try to query the display name, but only on local files */ + if (g_file_has_uri_scheme (location, "file")) + { + GFileInfo *info; + + info = g_file_query_info (location, + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + if (info) + { + /* Simply get the display name to use as the basename */ + name = g_strdup (g_file_info_get_display_name (info)); + g_object_unref (info); + } + else + { + /* This is a local file, and therefore we will use + * g_filename_display_basename on the local path */ + gchar *local_path; + + local_path = g_file_get_path (location); + name = g_filename_display_basename (local_path); + g_free (local_path); + } + } + else if (g_file_has_parent (location, NULL) || + !tepl_utils_decode_uri (uri, NULL, NULL, &hn, NULL, NULL)) + { + /* For remote files with a parent (so not just http://foo.com) + or remote file for which the decoding of the host name fails, + use the _parse_name and take basename of that */ + gchar *parse_name; + gchar *base; + + parse_name = g_file_get_parse_name (location); + base = g_filename_display_basename (parse_name); + name = g_uri_unescape_string (base, NULL); + + g_free (base); + g_free (parse_name); + } + else + { + /* display '/ on ' using the decoded host */ + gchar *hn_utf8; + + if (hn != NULL) + { + hn_utf8 = g_utf8_make_valid (hn, -1); + } + else + { + /* we should never get here */ + hn_utf8 = g_strdup ("?"); + } + + /* Translators: '/ on ' */ + name = g_strdup_printf (_("/ on %s"), hn_utf8); + + g_free (hn_utf8); + g_free (hn); + } + + g_free (uri); + + return name; +} + +/** + * gedit_utils_drop_get_uris: + * @selection_data: the #GtkSelectionData from drag_data_received + * + * Create a list of valid uri's from a uri-list drop. + * + * Returns: (transfer full): a string array which will hold the uris or + * %NULL if there were no valid uris. g_strfreev should be used when + * the string array is no longer used + */ +gchar ** +gedit_utils_drop_get_uris (GtkSelectionData *selection_data) +{ + gchar **uris; + gint i; + gint p = 0; + gchar **uri_list; + + uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data)); + uri_list = g_new0(gchar *, g_strv_length (uris) + 1); + + for (i = 0; uris[i] != NULL; i++) + { + gchar *uri; + + uri = make_canonical_uri_from_shell_arg (uris[i]); + + /* Silently ignore malformed URI/filename */ + if (uri != NULL) + uri_list[p++] = uri; + } + + if (*uri_list == NULL) + { + g_free(uri_list); + g_strfreev (uris); + return NULL; + } + + g_strfreev (uris); + return uri_list; +} + +GtkSourceCompressionType +gedit_utils_get_compression_type_from_content_type (const gchar *content_type) +{ + if (content_type == NULL) + { + return GTK_SOURCE_COMPRESSION_TYPE_NONE; + } + + if (g_content_type_is_a (content_type, "application/x-gzip")) + { + return GTK_SOURCE_COMPRESSION_TYPE_GZIP; + } + + return GTK_SOURCE_COMPRESSION_TYPE_NONE; +} + +/* Copied from nautilus */ +static gchar * +get_direct_save_filename (GdkDragContext *context) +{ + guchar *prop_text; + gint prop_len; + + if (!gdk_property_get (gdk_drag_context_get_source_window (context), gdk_atom_intern ("XdndDirectSave0", FALSE), + gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL, + &prop_len, &prop_text) && prop_text != NULL) { + return NULL; + } + + /* Zero-terminate the string */ + prop_text = g_realloc (prop_text, prop_len + 1); + prop_text[prop_len] = '\0'; + + /* Verify that the file name provided by the source is valid */ + if (*prop_text == '\0' || + strchr ((const gchar *) prop_text, G_DIR_SEPARATOR) != NULL) { + gedit_debug_message (DEBUG_UTILS, "Invalid filename provided by XDS drag site"); + g_free (prop_text); + return NULL; + } + + return (gchar *)prop_text; +} + +gchar * +gedit_utils_set_direct_save_filename (GdkDragContext *context) +{ + gchar *uri; + gchar *filename; + + uri = NULL; + filename = get_direct_save_filename (context); + + if (filename != NULL) + { + gchar *tempdir; + gchar *path; + + tempdir = g_dir_make_tmp ("gedit-drop-XXXXXX", NULL); + if (tempdir == NULL) + { + tempdir = g_strdup (g_get_tmp_dir ()); + } + + path = g_build_filename (tempdir, + filename, + NULL); + + uri = g_filename_to_uri (path, NULL, NULL); + + /* Change the property */ + gdk_property_change (gdk_drag_context_get_source_window (context), + gdk_atom_intern ("XdndDirectSave0", FALSE), + gdk_atom_intern ("text/plain", FALSE), 8, + GDK_PROP_MODE_REPLACE, (const guchar *) uri, + strlen (uri)); + + g_free (tempdir); + g_free (path); + g_free (filename); + } + + return uri; +} + +const gchar * +gedit_utils_newline_type_to_string (GtkSourceNewlineType newline_type) +{ + switch (newline_type) + { + case GTK_SOURCE_NEWLINE_TYPE_LF: + return _("Unix/Linux"); + case GTK_SOURCE_NEWLINE_TYPE_CR: + return _("Mac OS Classic"); + case GTK_SOURCE_NEWLINE_TYPE_CR_LF: + return _("Windows"); + } + + return NULL; +} + +/* ex:set ts=8 noet: */ -- cgit v1.2.3