diff --git a/xed/Makefile.am b/xed/Makefile.am index 0fb2d3b..0a68f0a 100644 --- a/xed/Makefile.am +++ b/xed/Makefile.am @@ -59,10 +59,12 @@ NOINST_H_FILES = \ xed-print-preview.h \ xed-session.h \ xed-settings.h \ + xed-status-combo-box.h \ xed-style-scheme-manager.h \ xed-tab-label.h \ xedtextregion.h \ xed-ui.h \ + xed-utils.h \ xed-view-frame.h \ xed-window-private.h @@ -84,9 +86,7 @@ INST_H_FILES = \ xed-progress-message-area.h \ xed-searchbar.h \ xed-statusbar.h \ - xed-status-combo-box.h \ xed-tab.h \ - xed-utils.h \ xed-view.h \ xed-view-activatable.h \ xed-window.h \ diff --git a/xed/xed-commands-file.c b/xed/xed-commands-file.c index 5948ceb..e069444 100644 --- a/xed/xed-commands-file.c +++ b/xed/xed-commands-file.c @@ -257,11 +257,13 @@ load_file_list (XedWindow *window, /** * xed_commands_load_location: * @window: - * @uri: + * @location: * @encoding: (allow-none): * @line_pos: * - * Do nothing if location does not exist + * Ignore non-existing locations + * + * Returns: (transfer container): */ void xed_commands_load_location (XedWindow *window, @@ -290,8 +292,8 @@ xed_commands_load_location (XedWindow *window, /** * xed_commands_load_locations: * @window: - * @uris: - * @encoding: + * @locations: (element-type GLib.File) (transfer none): + * @encoding: (allow-none): * @line_pos: * * Ignore non-existing locations diff --git a/xed/xed-document-loader.c b/xed/xed-document-loader.c index 3233adf..1b21d1b 100644 --- a/xed/xed-document-loader.c +++ b/xed/xed-document-loader.c @@ -437,6 +437,18 @@ close_input_stream_ready_cb (GInputStream *stream, return; } + /* Check if we needed some fallback char, if so, check if there was + a previous error and if not set a fallback used error */ + if ((xed_document_output_stream_get_num_fallbacks (XED_DOCUMENT_OUTPUT_STREAM (async->loader->priv->output)) != 0) && + async->loader->priv->error == NULL) + { + g_set_error_literal (&async->loader->priv->error, + XED_DOCUMENT_ERROR, + XED_DOCUMENT_ERROR_CONVERSION_FALLBACK, + "There was a conversion error and it was " + "needed to use a fallback char"); + } + remote_load_completed_or_failed (async->loader, async); } @@ -544,19 +556,6 @@ async_read_cb (GInputStream *stream, loader->priv->auto_detected_newline_type = xed_document_output_stream_detect_newline_type (XED_DOCUMENT_OUTPUT_STREAM (loader->priv->output)); - /* Check if we needed some fallback char, if so, check if there was - a previous error and if not set a fallback used error */ - /* FIXME Uncomment this when we want to manage conversion fallback */ - /*if ((xed_document_output_stream_get_num_fallbacks (XED_DOCUMENT_OUTPUT_STREAM (loader->priv->ouput)) != 0) && - loader->priv->error == NULL) - { - g_set_error_literal (&loader->priv->error, - XED_DOCUMENT_ERROR, - XED_DOCUMENT_ERROR_CONVERSION_FALLBACK, - "There was a conversion error and it was " - "needed to use a fallback char"); - }*/ - write_complete (async); return; diff --git a/xed/xed-document-output-stream.c b/xed/xed-document-output-stream.c index caabf7e..9f7488a 100644 --- a/xed/xed-document-output-stream.c +++ b/xed/xed-document-output-stream.c @@ -57,6 +57,9 @@ struct _XedDocumentOutputStreamPrivate GSList *encodings; GSList *current_encoding; + gint error_offset; + guint n_fallback_errors; + guint is_utf8 : 1; guint use_first : 1; @@ -175,6 +178,8 @@ xed_document_output_stream_constructed (GObject *object) gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (stream->priv->doc), FALSE); gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (stream->priv->doc)); + + G_OBJECT_CLASS (xed_document_output_stream_parent_class)->constructed (object); } static void @@ -217,6 +222,8 @@ xed_document_output_stream_init (XedDocumentOutputStream *stream) stream->priv->encodings = NULL; stream->priv->current_encoding = NULL; + stream->priv->error_offset = -1; + stream->priv->is_initialized = FALSE; stream->priv->is_closed = FALSE; stream->priv->is_utf8 = FALSE; @@ -240,7 +247,10 @@ get_encoding (XedDocumentOutputStream *stream) return (const XedEncoding *)stream->priv->current_encoding->data; } - return NULL; + stream->priv->use_first = TRUE; + stream->priv->current_encoding = stream->priv->encodings; + + return (const XedEncoding *)stream->priv->current_encoding->data; } static gboolean @@ -486,73 +496,131 @@ xed_document_output_stream_get_guessed (XedDocumentOutputStream *stream) guint xed_document_output_stream_get_num_fallbacks (XedDocumentOutputStream *stream) { - g_return_val_if_fail (XED_IS_DOCUMENT_OUTPUT_STREAM (stream), FALSE); + g_return_val_if_fail (XED_IS_DOCUMENT_OUTPUT_STREAM (stream), 0); - if (stream->priv->charset_conv == NULL) - { - return FALSE; - } - - return g_charset_converter_get_num_fallbacks (stream->priv->charset_conv) != 0; + return stream->priv->n_fallback_errors; } -static gboolean +static void +apply_error_tag (XedDocumentOutputStream *stream) +{ + GtkTextIter start; + + if (stream->priv->error_offset == -1) + { + return; + } + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (stream->priv->doc), &start, stream->priv->error_offset); + + _xed_document_apply_error_style (stream->priv->doc, &start, &stream->priv->pos); + + stream->priv->error_offset = -1; +} + +static void +insert_fallback (XedDocumentOutputStream *stream, + const gchar *buffer) +{ + guint8 out[4]; + guint8 v; + const gchar hex[] = "0123456789ABCDEF"; + + /* if we are here is because we are pointing to an invalid char + * so we substitute it by an hex value */ + v = *(guint8 *)buffer; + out[0] = '\\'; + out[1] = hex[(v & 0xf0) >> 4]; + out[2] = hex[(v & 0x0f) >> 0]; + out[3] = '\0'; + + gtk_text_buffer_insert (GTK_TEXT_BUFFER (stream->priv->doc), &stream->priv->pos, (const gchar *)out, 3); + + stream->priv->n_fallback_errors++; +} + +static void validate_and_insert (XedDocumentOutputStream *stream, const gchar *buffer, gsize count) { - const gchar *end; - gsize nvalid; - gboolean valid; + GtkTextBuffer *text_buffer; + GtkTextIter *iter; gsize len; + text_buffer = GTK_TEXT_BUFFER (stream->priv->doc); + iter = &stream->priv->pos; len = count; - /* validate */ - valid = g_utf8_validate (buffer, len, &end); - nvalid = end - buffer; - - if (!valid) + while (len != 0) { - gsize remainder; + const gchar *end; + gboolean valid; + gsize nvalid; - remainder = len - nvalid; - - if ((remainder < MAX_UNICHAR_LEN) && (g_utf8_get_char_validated (buffer + nvalid, remainder) == (gunichar)-2)) - { - stream->priv->buffer = g_strndup (end, remainder); - stream->priv->buflen = remainder; - len -= remainder; - } - else - { - return FALSE; - } - } - else - { - gchar *ptr; + /* validate */ + valid = g_utf8_validate (buffer, len, &end); + nvalid = end - buffer; /* Note: this is a workaround for a 'bug' in GtkTextBuffer where - inserting first a \r and then in a second insert, a \n, - will result in two lines being added instead of a single - one */ + inserting first a \r and then in a second insert, a \n, + will result in two lines being added instead of a single + one */ - ptr = g_utf8_find_prev_char (buffer, buffer + len); - - if (ptr && *ptr == '\r' && ptr - buffer == len - 1) + if (valid) { - stream->priv->buffer = g_new (gchar, 1); - stream->priv->buffer[0] = '\r'; - stream->priv->buflen = 1; + gchar *ptr; - --len; + ptr = g_utf8_find_prev_char (buffer, buffer + len); + + if (ptr && *ptr == '\r' && ptr - buffer == len - 1) + { + stream->priv->buffer = g_new (gchar, 1); + stream->priv->buffer[0] = '\r'; + stream->priv->buflen = 1; + + /* Decrease also the len so in the check + nvalid == len we get out of this method */ + --nvalid; + --len; + } } + + /* if we've got any valid char we must tag the invalid chars */ + if (nvalid > 0) + { + apply_error_tag (stream); + } + + gtk_text_buffer_insert (text_buffer, iter, buffer, nvalid); + + /* If we inserted all return */ + if (nvalid == len) + { + break; + } + + buffer += nvalid; + len = len - nvalid; + + if ((len < MAX_UNICHAR_LEN) && (g_utf8_get_char_validated (buffer, len) == (gunichar)-2)) + { + stream->priv->buffer = g_strndup (end, len); + stream->priv->buflen = len; + + break; + } + + /* we need the start of the chunk of invalid chars */ + if (stream->priv->error_offset == -1) + { + stream->priv->error_offset = gtk_text_iter_get_offset (&stream->priv->pos); + } + + insert_fallback (stream, buffer); + buffer++; + len--; } - - gtk_text_buffer_insert (GTK_TEXT_BUFFER (stream->priv->doc), &stream->priv->pos, buffer, len); - - return TRUE; } /* If the last char is a newline, remove it from the buffer (otherwise @@ -755,20 +823,7 @@ xed_document_output_stream_write (GOutputStream *stream, } - if (!validate_and_insert (ostream, text, len)) - { - /* TODO: we could escape invalid text and tag it in red - * and make the doc readonly. - */ - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, _("Invalid UTF-8 sequence in input")); - - if (freetext) - { - g_free (text); - } - - return -1; - } + validate_and_insert (ostream, text, len); if (freetext) { @@ -785,14 +840,51 @@ xed_document_output_stream_flush (GOutputStream *stream, { XedDocumentOutputStream *ostream = XED_DOCUMENT_OUTPUT_STREAM (stream); - /* Flush deferred data if some. */ - if (!ostream->priv->is_closed && ostream->priv->is_initialized && - ostream->priv->buflen > 0 && - xed_document_output_stream_write (stream, "", 0, cancellable, error) == -1) + if (ostream->priv->is_closed) { - return FALSE; + return TRUE; } + if (ostream->priv->buflen > 0 && *ostream->priv->buffer != '\r') + { + /* If we reached here is because the last insertion was a half + correct char, which has to be inserted as fallback */ + gchar *text; + + if (ostream->priv->error_offset == -1) + { + ostream->priv->error_offset = gtk_text_iter_get_offset (&ostream->priv->pos); + } + + text = ostream->priv->buffer; + while (ostream->priv->buflen != 0) + { + insert_fallback (ostream, text); + text++; + ostream->priv->buflen--; + } + + g_free (ostream->priv->buffer); + ostream->priv->buffer = NULL; + } + else if (ostream->priv->buflen == 1 && *ostream->priv->buffer == '\r') + { + /* The previous chars can be invalid */ + apply_error_tag (ostream); + + /* See special case above, flush this */ + gtk_text_buffer_insert (GTK_TEXT_BUFFER (ostream->priv->doc), + &ostream->priv->pos, + "\r", + 1); + + g_free (ostream->priv->buffer); + ostream->priv->buffer = NULL; + ostream->priv->buflen = 0; + } + + apply_error_tag (ostream); + return TRUE; } diff --git a/xed/xed-document.c b/xed/xed-document.c index 371fa9e..ec0942e 100644 --- a/xed/xed-document.c +++ b/xed/xed-document.c @@ -88,9 +88,6 @@ static void xed_document_save_real (XedDocument *doc, GFile *location, const XedEncoding *encoding, XedDocumentSaveFlags flags); -static void to_search_region_range (XedDocument *doc, - GtkTextIter *start, - GtkTextIter *end); static void insert_text_cb (XedDocument *doc, GtkTextIter *pos, const gchar *text, @@ -138,15 +135,17 @@ struct _XedDocumentPrivate XedTextRegion *to_search_region; GtkTextTag *found_tag; + GtkTextTag *error_tag; + /* Mount operation factory */ XedMountOperationFactory mount_operation_factory; gpointer mount_operation_userdata; - gint readonly : 1; - gint last_save_was_manually : 1; - gint language_set_by_user : 1; - gint stop_cursor_moved_emission : 1; - gint dispose_has_run : 1; + guint readonly : 1; + guint last_save_was_manually : 1; + guint language_set_by_user : 1; + guint stop_cursor_moved_emission : 1; + guint dispose_has_run : 1; }; enum @@ -281,25 +280,10 @@ xed_document_dispose (GObject *object) g_free (position); } - if (doc->priv->loader) - { - g_object_unref (doc->priv->loader); - doc->priv->loader = NULL; - } - + g_clear_object (&doc->priv->loader); g_clear_object (&doc->priv->editor_settings); - - if (doc->priv->metadata_info != NULL) - { - g_object_unref (doc->priv->metadata_info); - doc->priv->metadata_info = NULL; - } - - if (doc->priv->location != NULL) - { - g_object_unref (doc->priv->location); - doc->priv->location = NULL; - } + g_clear_object (&doc->priv->metadata_info); + g_clear_object (&doc->priv->location); doc->priv->dispose_has_run = TRUE; @@ -383,18 +367,31 @@ xed_document_set_property (GObject *object, switch (prop_id) { - case PROP_ENABLE_SEARCH_HIGHLIGHTING: - xed_document_set_enable_search_highlighting (doc, g_value_get_boolean (value)); - break; - case PROP_NEWLINE_TYPE: - xed_document_set_newline_type (doc, g_value_get_enum (value)); + case PROP_LOCATION: + { + GFile *location; + + location = g_value_get_object (value); + + if (location != NULL) + { + xed_document_set_location (doc, location); + } + break; + } case PROP_SHORTNAME: xed_document_set_short_name_for_display (doc, g_value_get_string (value)); break; case PROP_CONTENT_TYPE: xed_document_set_content_type (doc, g_value_get_string (value)); break; + case PROP_ENABLE_SEARCH_HIGHLIGHTING: + xed_document_set_enable_search_highlighting (doc, g_value_get_boolean (value)); + break; + case PROP_NEWLINE_TYPE: + xed_document_set_newline_type (doc, g_value_get_enum (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -455,10 +452,10 @@ xed_document_class_init (XedDocumentClass *klass) g_object_class_install_property (object_class, PROP_LOCATION, g_param_spec_object ("location", - "LOCATION", + "Location", "The document's location", G_TYPE_FILE, - G_PARAM_READABLE | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_SHORTNAME, @@ -647,7 +644,7 @@ xed_document_class_init (XedDocumentClass *klass) G_TYPE_POINTER); document_signals[SEARCH_HIGHLIGHT_UPDATED] = - g_signal_new ("search_highlight_updated", + g_signal_new ("search-highlight-updated", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (XedDocumentClass, search_highlight_updated), @@ -658,7 +655,7 @@ xed_document_class_init (XedDocumentClass *klass) GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE); - g_type_class_add_private (object_class, sizeof(XedDocumentPrivate)); + g_type_class_add_private (object_class, sizeof (XedDocumentPrivate)); } static void @@ -1097,7 +1094,7 @@ xed_document_get_uri_for_display (XedDocument *doc) } else { - return xed_utils_uri_for_display (doc->priv->location); + return g_file_get_parse_name (doc->priv->location); } } @@ -1193,9 +1190,9 @@ set_readonly (XedDocument *doc, } /** - * xed_document_set_readonly: + * _xed_document_set_readonly: * @doc: a #XedDocument - * @readonly: %TRUE to se the document as read-only + * @readonly: %TRUE to set the document as read-only * * If @readonly is %TRUE sets @doc as read-only. */ @@ -1484,6 +1481,34 @@ xed_document_load_cancel (XedDocument *doc) return xed_document_loader_cancel (doc->priv->loader); } +static gboolean +has_invalid_chars (XedDocument *doc) +{ + GtkTextBuffer *buffer; + GtkTextIter start; + + g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE); + + xed_debug (DEBUG_DOCUMENT); + + if (doc->priv->error_tag == NULL) + { + return FALSE; + } + + buffer = GTK_TEXT_BUFFER (doc); + + gtk_text_buffer_get_start_iter (buffer, &start); + + if (gtk_text_iter_begins_tag (&start, doc->priv->error_tag) || + gtk_text_iter_forward_to_tag_toggle (&start, doc->priv->error_tag)) + { + return TRUE; + } + + return FALSE; +} + static void document_saver_saving (XedDocumentSaver *saver, gboolean completed, @@ -1559,14 +1584,28 @@ xed_document_save_real (XedDocument *doc, { g_return_if_fail (doc->priv->saver == NULL); - /* create a saver, it will be destroyed once saving is complete */ - doc->priv->saver = xed_document_saver_new (doc, location, encoding, doc->priv->newline_type, flags); + if (!(flags & XED_DOCUMENT_SAVE_IGNORE_INVALID_CHARS) && has_invalid_chars (doc)) + { + GError *error = NULL; - g_signal_connect (doc->priv->saver, "saving", G_CALLBACK (document_saver_saving), doc); + g_set_error_literal (&error, + XED_DOCUMENT_ERROR, + XED_DOCUMENT_ERROR_CONVERSION_FALLBACK, + "The document contains invalid characters"); - doc->priv->requested_encoding = encoding; + g_signal_emit (doc, document_signals[SAVED], 0, error); + } + else + { + /* create a saver, it will be destroyed once saving is complete */ + doc->priv->saver = xed_document_saver_new (doc, location, encoding, doc->priv->newline_type, flags); - xed_document_saver_save (doc->priv->saver, &doc->priv->mtime); + g_signal_connect (doc->priv->saver, "saving", G_CALLBACK (document_saver_saving), doc); + + doc->priv->requested_encoding = encoding; + + xed_document_saver_save (doc->priv->saver, &doc->priv->mtime); + } } /** @@ -1603,13 +1642,23 @@ xed_document_save_as (XedDocument *doc, const XedEncoding *encoding, XedDocumentSaveFlags flags) { + GError *error; + g_return_if_fail (XED_IS_DOCUMENT (doc)); g_return_if_fail (G_IS_FILE (location)); g_return_if_fail (encoding != NULL); + if (has_invalid_chars (doc)) + { + g_set_error_literal (&error, + XED_DOCUMENT_ERROR, + XED_DOCUMENT_ERROR_CONVERSION_FALLBACK, + "The document contains invalid chars"); + } + /* priv->mtime refers to the the old location (if any). Thus, it should be * ignored when saving as. */ - g_signal_emit (doc, document_signals[SAVE], 0, location, encoding, flags | XED_DOCUMENT_SAVE_IGNORE_MTIME); + g_signal_emit (doc, document_signals[SAVE], 0, location, encoding, flags | XED_DOCUMENT_SAVE_IGNORE_MTIME, error); } gboolean @@ -1647,7 +1696,7 @@ xed_document_get_deleted (XedDocument *doc) g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE); /* This is done sync, maybe we should do it async? */ - return doc->priv->location && !xed_utils_location_exists (doc->priv->location); + return doc->priv->location && !g_file_query_exists (doc->priv->location, NULL); } /* @@ -1743,6 +1792,36 @@ compute_num_of_lines (const gchar *text) return n; } +static void +to_search_region_range (XedDocument *doc, + GtkTextIter *start, + GtkTextIter *end) +{ + xed_debug (DEBUG_DOCUMENT); + + if (doc->priv->to_search_region == NULL) + { + return; + } + + gtk_text_iter_set_line_offset (start, 0); + gtk_text_iter_forward_to_line_end (end); + + /* + g_print ("+ [%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start), + gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end)); + */ + + /* Add the region to the refresh region */ + xed_text_region_add (doc->priv->to_search_region, start, end); + + /* Notify views of the updated highlight region */ + gtk_text_iter_backward_lines (start, doc->priv->num_of_lines_search_text); + gtk_text_iter_forward_lines (end, doc->priv->num_of_lines_search_text); + + g_signal_emit (doc, document_signals [SEARCH_HIGHLIGHT_UPDATED], 0, start, end); +} + /** * xed_document_set_search_text: * @doc: @@ -1868,7 +1947,9 @@ xed_document_search_forward (XedDocument *doc, return FALSE; } else + { xed_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text); + } if (start == NULL) { @@ -2124,65 +2205,27 @@ xed_document_replace_all (XedDocument *doc, return cont; } -/** - * xed_document_set_language: - * @doc: - * @lang: (allow-none): - **/ -void -xed_document_set_language (XedDocument *doc, - GtkSourceLanguage *lang) -{ - g_return_if_fail (XED_IS_DOCUMENT (doc)); - - set_language (doc, lang, TRUE); -} - -/** - * xed_document_get_language: - * @doc: - * - * Return value: (transfer none): - */ -GtkSourceLanguage * -xed_document_get_language (XedDocument *doc) -{ - g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL); - - return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc)); -} - -const XedEncoding * -xed_document_get_encoding (XedDocument *doc) -{ - g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL); - - return doc->priv->encoding; -} - -glong -_xed_document_get_seconds_since_last_save_or_load (XedDocument *doc) -{ - GTimeVal current_time; - - xed_debug (DEBUG_DOCUMENT); - - g_return_val_if_fail (XED_IS_DOCUMENT (doc), -1); - - g_get_current_time (¤t_time); - - return (current_time.tv_sec - doc->priv->time_of_last_save_or_load.tv_sec); -} - static void -get_search_match_colors (XedDocument *doc, - gboolean *foreground_set, - GdkRGBA *foreground, - gboolean *background_set, - GdkRGBA *background) +get_style_colors (XedDocument *doc, + const gchar *style_name, + gboolean *foreground_set, + GdkRGBA *foreground, + gboolean *background_set, + GdkRGBA *background, + gboolean *line_background_set, + GdkRGBA *line_background, + gboolean *bold_set, + gboolean *bold, + gboolean *italic_set, + gboolean *italic, + gboolean *underline_set, + gboolean *underline, + gboolean *strikethrough_set, + gboolean *strikethrough) { GtkSourceStyleScheme *style_scheme; GtkSourceStyle *style; + gchar *line_bg; gchar *bg; gchar *fg; @@ -2192,7 +2235,7 @@ get_search_match_colors (XedDocument *doc, goto fallback; } - style = gtk_source_style_scheme_get_style (style_scheme, "search-match"); + style = gtk_source_style_scheme_get_style (style_scheme, style_name); if (style == NULL) { goto fallback; @@ -2203,6 +2246,16 @@ get_search_match_colors (XedDocument *doc, "foreground", &fg, "background-set", background_set, "background", &bg, + "line-background-set", line_background_set, + "line-background", &line_bg, + "bold-set", bold_set, + "bold", bold, + "italic-set", italic_set, + "italic", italic, + "underline-set", underline_set, + "underline", underline, + "strikethrough-set", strikethrough_set, + "strikethrough", strikethrough, NULL); if (*foreground_set) @@ -2221,8 +2274,17 @@ get_search_match_colors (XedDocument *doc, } } + if (*line_background_set) + { + if (line_bg == NULL || !gdk_rgba_parse (background, line_bg)) + { + *line_background_set = FALSE; + } + } + g_free (fg); g_free (bg); + g_free (line_bg); return; @@ -2238,24 +2300,61 @@ get_search_match_colors (XedDocument *doc, return; } +static void +sync_tag_style (XedDocument *doc, + GtkTextTag *tag, + const gchar *style_name) +{ + GdkRGBA fg; + GdkRGBA bg; + GdkRGBA line_bg; + gboolean fg_set; + gboolean bg_set; + gboolean line_bg_set; + gboolean bold; + gboolean italic; + gboolean underline; + gboolean strikethrough; + gboolean bold_set; + gboolean italic_set; + gboolean underline_set; + gboolean strikethrough_set; + + xed_debug (DEBUG_DOCUMENT); + + g_return_if_fail (tag != NULL); + + get_style_colors (doc, + style_name, + &fg_set, &fg, + &bg_set, &bg, + &line_bg_set, &line_bg, + &bold_set, &bold, + &italic_set, &italic, + &underline_set, &underline, + &strikethrough_set, &strikethrough); + + g_object_freeze_notify (G_OBJECT (tag)); + + g_object_set (tag, + "foreground-rgba", fg_set ? &fg : NULL, + "background-rgba", bg_set ? &bg : NULL, + "paragraph-background-rgba", line_bg_set ? &line_bg : NULL, + "weight", bold_set && bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, + "style", italic_set && italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL, + "underline", underline_set && underline ? PANGO_UNDERLINE_SINGLE : PANGO_UNDERLINE_NONE, + "strikethrough", strikethrough_set && strikethrough, + NULL); + + g_object_thaw_notify (G_OBJECT (tag)); +} + static void sync_found_tag (XedDocument *doc, GParamSpec *pspec, gpointer data) { - GdkRGBA fg; - GdkRGBA bg; - gboolean fg_set; - gboolean bg_set; - - xed_debug (DEBUG_DOCUMENT); - - g_return_if_fail (GTK_TEXT_TAG (doc->priv->found_tag)); - - get_search_match_colors (doc, &fg_set, &fg, &bg_set, &bg); - - g_object_set (doc->priv->found_tag, "foreground-rgba", fg_set ? &fg : NULL, NULL); - g_object_set (doc->priv->found_tag, "background-rgba", bg_set ? &bg : NULL, NULL); + sync_tag_style (doc, doc->priv->found_tag, "search-match"); } static void @@ -2378,36 +2477,6 @@ search_region (XedDocument *doc, } while (found); } -static void -to_search_region_range (XedDocument *doc, - GtkTextIter *start, - GtkTextIter *end) -{ - xed_debug (DEBUG_DOCUMENT); - - if (doc->priv->to_search_region == NULL) - { - return; - } - - gtk_text_iter_set_line_offset (start, 0); - gtk_text_iter_forward_to_line_end (end); - - /* - g_print ("+ [%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start), - gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end)); - */ - - /* Add the region to the refresh region */ - xed_text_region_add (doc->priv->to_search_region, start, end); - - /* Notify views of the updated highlight region */ - gtk_text_iter_backward_lines (start, doc->priv->num_of_lines_search_text); - gtk_text_iter_forward_lines (end, doc->priv->num_of_lines_search_text); - - g_signal_emit (doc, document_signals [SEARCH_HIGHLIGHT_UPDATED], 0, start, end); -} - void _xed_document_search_region (XedDocument *doc, const GtkTextIter *start, @@ -2494,6 +2563,56 @@ delete_range_cb (XedDocument *doc, to_search_region_range (doc, &d_start, &d_end); } +/** + * xed_document_set_language: + * @doc: + * @lang: (allow-none): + **/ +void +xed_document_set_language (XedDocument *doc, + GtkSourceLanguage *lang) +{ + g_return_if_fail (XED_IS_DOCUMENT (doc)); + + set_language (doc, lang, TRUE); +} + +/** + * xed_document_get_language: + * @doc: + * + * Return value: (transfer none): + */ +GtkSourceLanguage * +xed_document_get_language (XedDocument *doc) +{ + g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL); + + return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc)); +} + +const XedEncoding * +xed_document_get_encoding (XedDocument *doc) +{ + g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL); + + return doc->priv->encoding; +} + +glong +_xed_document_get_seconds_since_last_save_or_load (XedDocument *doc) +{ + GTimeVal current_time; + + xed_debug (DEBUG_DOCUMENT); + + g_return_val_if_fail (XED_IS_DOCUMENT (doc), -1); + + g_get_current_time (¤t_time); + + return (current_time.tv_sec - doc->priv->time_of_last_save_or_load.tv_sec); +} + void xed_document_set_enable_search_highlighting (XedDocument *doc, gboolean enable) @@ -2598,7 +2717,7 @@ gchar * xed_document_get_metadata (XedDocument *doc, const gchar *key) { - gchar *uri; + gchar *value = NULL; g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL); g_return_val_if_fail (key != NULL, NULL); @@ -2637,7 +2756,7 @@ xed_document_set_metadata (XedDocument *doc, if (doc->priv->location != NULL) { - xed_metadata_manager_set (doc->priv->uri, key, value); + xed_metadata_manager_set (doc->priv->location, key, value); } } @@ -2747,3 +2866,39 @@ xed_document_set_metadata (XedDocument *doc, g_object_unref (info); } #endif + +static void +sync_error_tag (XedDocument *doc, + GParamSpec *pspec, + gpointer data) +{ + sync_tag_style (doc, doc->priv->error_tag, "def:error"); +} + +void +_xed_document_apply_error_style (XedDocument *doc, + GtkTextIter *start, + GtkTextIter *end) +{ + GtkTextBuffer *buffer; + + xed_debug (DEBUG_DOCUMENT); + + buffer = GTK_TEXT_BUFFER (doc); + + if (doc->priv->error_tag == NULL) + { + doc->priv->error_tag = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (doc), "error-style", NULL); + + sync_error_tag (doc, NULL, NULL); + + g_signal_connect (doc, "notify::style-scheme", + G_CALLBACK (sync_error_tag), NULL); + } + + /* make sure the 'error' tag has the priority over + * syntax highlighting tags */ + text_tag_set_highest_priority (doc->priv->error_tag, GTK_TEXT_BUFFER (doc)); + + gtk_text_buffer_apply_tag (buffer, doc->priv->error_tag, start, end); +} diff --git a/xed/xed-document.h b/xed/xed-document.h index ae9d6ef..a8d982f 100644 --- a/xed/xed-document.h +++ b/xed/xed-document.h @@ -81,9 +81,10 @@ typedef enum */ typedef enum { - XED_DOCUMENT_SAVE_IGNORE_MTIME = 1 << 0, - XED_DOCUMENT_SAVE_IGNORE_BACKUP = 1 << 1, - XED_DOCUMENT_SAVE_PRESERVE_BACKUP = 1 << 2 + XED_DOCUMENT_SAVE_IGNORE_MTIME = 1 << 0, + XED_DOCUMENT_SAVE_IGNORE_BACKUP = 1 << 1, + XED_DOCUMENT_SAVE_PRESERVE_BACKUP = 1 << 2, + XED_DOCUMENT_SAVE_IGNORE_INVALID_CHARS = 1 << 3 } XedDocumentSaveFlags; /* Private structure type */ @@ -286,6 +287,14 @@ void _xed_document_set_readonly (XedDocument *doc, glong _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc); +void _xed_document_apply_error_style (XedDocument *doc, + GtkTextIter *start, + GtkTextIter *end); + +void _xed_document_apply_error_style (XedDocument *doc, + GtkTextIter *start, + GtkTextIter *end); + /* Note: this is a sync stat: use only on local files */ gboolean _xed_document_check_externally_modified (XedDocument *doc); diff --git a/xed/xed-io-error-message-area.c b/xed/xed-io-error-message-area.c index 0362f0f..096b0e8 100644 --- a/xed/xed-io-error-message-area.c +++ b/xed/xed-io-error-message-area.c @@ -354,7 +354,7 @@ xed_unrecoverable_reverting_error_message_area_new (GFile *location, g_return_val_if_fail (error != NULL, NULL); g_return_val_if_fail ((error->domain == XED_DOCUMENT_ERROR) || (error->domain == G_IO_ERROR), NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -442,19 +442,15 @@ create_conversion_error_message_area (const gchar *primary_text, different from other main menu access keys (Open, Edit, View...) */ _("Edit Any_way"), GTK_RESPONSE_YES); - gtk_info_bar_add_button (GTK_INFO_BAR (message_area), - /* Translators: the access key chosen for this string should be - different from other main menu access keys (Open, Edit, View...) */ - _("D_on't Edit"), - GTK_RESPONSE_NO); gtk_info_bar_set_message_type (GTK_INFO_BAR (message_area), GTK_MESSAGE_WARNING); } else { - gtk_info_bar_add_button (GTK_INFO_BAR (message_area), _("_Cancel"), GTK_RESPONSE_CANCEL); gtk_info_bar_set_message_type (GTK_INFO_BAR (message_area), GTK_MESSAGE_ERROR); } + gtk_info_bar_add_button (GTK_INFO_BAR (message_area), _("_Cancel"), GTK_RESPONSE_CANCEL); + hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); image = gtk_image_new_from_icon_name ("dialog-error-symbolic", GTK_ICON_SIZE_DIALOG); @@ -516,7 +512,7 @@ xed_io_loading_error_message_area_new (GFile *location, (error->domain == XED_DOCUMENT_ERROR) || (error->domain == G_IO_ERROR), NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -559,8 +555,8 @@ xed_io_loading_error_message_area_new (GFile *location, { error_message = g_strdup_printf (_("There was a problem opening the file %s."), uri_for_display); message_details = g_strconcat (_("The file you opened has some invalid characters. " - "If you continue editing this file you could make this " - "document useless."), "\n", + "If you continue editing this file you could corrupt this " + "document."), "\n", _("You can also choose another character encoding and try again."), NULL); edit_anyway = TRUE; @@ -623,7 +619,7 @@ xed_conversion_error_while_saving_message_area_new (GFile *location, error->domain == G_IO_ERROR, NULL); g_return_val_if_fail (encoding != NULL, NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -686,7 +682,7 @@ xed_file_already_open_warning_message_area_new (GFile *location) g_return_val_if_fail (G_IS_FILE (location), NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -776,7 +772,7 @@ xed_externally_modified_saving_error_message_area_new (GFile *location, g_return_val_if_fail (error->domain == XED_DOCUMENT_ERROR, NULL); g_return_val_if_fail (error->code == XED_DOCUMENT_ERROR_EXTERNALLY_MODIFIED, NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -866,7 +862,7 @@ xed_no_backup_saving_error_message_area_new (GFile *location, (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANT_CREATE_BACKUP)), NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -958,7 +954,7 @@ xed_unrecoverable_saving_error_message_area_new (GFile *location, g_return_val_if_fail (error != NULL, NULL); g_return_val_if_fail ((error->domain == XED_DOCUMENT_ERROR) || (error->domain == G_IO_ERROR), NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -1067,7 +1063,7 @@ xed_externally_modified_message_area_new (GFile *location, g_return_val_if_fail (G_IS_FILE (location), NULL); - full_formatted_uri = xed_utils_uri_for_display (location); + full_formatted_uri = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain @@ -1106,3 +1102,84 @@ xed_externally_modified_message_area_new (GFile *location, return message_area; } +GtkWidget * +xed_invalid_character_message_area_new (GFile *location) +{ + GtkWidget *info_bar; + GtkWidget *hbox_content; + GtkWidget *image; + GtkWidget *vbox; + GtkWidget *primary_label; + GtkWidget *secondary_label; + gchar *primary_markup; + gchar *secondary_markup; + gchar *primary_text; + gchar *full_formatted_uri; + gchar *uri_for_display; + gchar *temp_uri_for_display; + const gchar *secondary_text; + + g_return_val_if_fail (G_IS_FILE (location), NULL); + + full_formatted_uri = g_file_get_parse_name (location); + + /* Truncate the URI so it doesn't get insanely wide. Note that even + * though the dialog uses wrapped text, if the URI doesn't contain + * white space then the text-wrapping code is too stupid to wrap it. + */ + temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH); + g_free (full_formatted_uri); + + uri_for_display = g_markup_printf_escaped ("%s", temp_uri_for_display); + g_free (temp_uri_for_display); + + info_bar = gtk_info_bar_new (); + + info_bar_add_button_with_text (GTK_INFO_BAR (info_bar), _("S_ave Anyway"), + "document_save-symbolic", GTK_RESPONSE_YES); + gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), + _("D_on't Save"), + GTK_RESPONSE_CANCEL); + gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING); + + hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); + + image = gtk_image_new_from_stock ("gtk-dialog-warning", GTK_ICON_SIZE_DIALOG); + gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); + + primary_text = g_strdup_printf (_("Some invalid chars have been detected while saving %s"), uri_for_display); + + g_free (uri_for_display); + + primary_markup = g_strdup_printf ("%s", primary_text); + g_free (primary_text); + primary_label = gtk_label_new (primary_markup); + g_free (primary_markup); + gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0); + gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5); + gtk_widget_set_can_focus (primary_label, TRUE); + gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE); + + secondary_text = _("If you continue saving this file you can corrupt the document. " + " Save anyway?"); + secondary_markup = g_strdup_printf ("%s", secondary_text); + secondary_label = gtk_label_new (secondary_markup); + g_free (secondary_markup); + gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0); + gtk_widget_set_can_focus (secondary_label, TRUE); + gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5); + + gtk_widget_show_all (hbox_content); + set_contents (info_bar, hbox_content); + + return info_bar; +} diff --git a/xed/xed-io-error-message-area.h b/xed/xed-io-error-message-area.h index a3c99dc..3bb17ec 100644 --- a/xed/xed-io-error-message-area.h +++ b/xed/xed-io-error-message-area.h @@ -63,6 +63,8 @@ GtkWidget *xed_unrecoverable_saving_error_message_area_new (GFile GtkWidget *xed_externally_modified_message_area_new (GFile *location, gboolean document_modified); +GtkWidget *xed_invalid_character_message_area_new (GFile *location); + G_END_DECLS #endif /* __XED_IO_ERROR_MESSAGE_AREA_H__ */ diff --git a/xed/xed-tab.c b/xed/xed-tab.c index 196ba7e..a74f904 100644 --- a/xed/xed-tab.c +++ b/xed/xed-tab.c @@ -530,11 +530,8 @@ io_loading_error_message_area_response (GtkWidget *message_area, break; case GTK_RESPONSE_YES: /* This means that we want to edit the document anyway */ - set_message_area (tab, NULL); - _xed_document_set_readonly (doc, FALSE); - break; - case GTK_RESPONSE_NO: - /* We don't want to edit the document just show it */ + tab->priv->not_editable = FALSE; + gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE); set_message_area (tab, NULL); break; default: @@ -755,7 +752,7 @@ show_saving_message_area (XedTab *tab) from = short_name; - to = xed_utils_uri_for_display (tab->priv->tmp_save_location); + to = g_file_get_parse_name (tab->priv->tmp_save_location); str = xed_utils_str_middle_truncate (to, MAX (20, MAX_MSG_LENGTH - len)); g_free (to); @@ -956,7 +953,7 @@ document_loaded (XedDocument *document, { GtkWidget *emsg; - _xed_document_set_readonly (document, TRUE); + tab->priv->not_editable = TRUE; emsg = xed_io_loading_error_message_area_new (location, tab->priv->tmp_encoding, error); @@ -1106,6 +1103,39 @@ unrecoverable_saving_error_message_area_response (GtkWidget *message_area, gtk_widget_grab_focus (GTK_WIDGET (view)); } +static void +invalid_character_message_area_response (GtkWidget *info_bar, + gint response_id, + XedTab *tab) +{ + if (response_id == GTK_RESPONSE_YES) + { + XedDocument *doc; + + doc = xed_tab_get_document (tab); + g_return_if_fail (XED_IS_DOCUMENT (doc)); + + set_message_area (tab, NULL); + + g_return_if_fail (tab->priv->tmp_save_location != NULL); + g_return_if_fail (tab->priv->tmp_encoding != NULL); + + xed_tab_set_state (tab, XED_TAB_STATE_SAVING); + + /* don't bug the user again with this... */ + tab->priv->save_flags |= XED_DOCUMENT_SAVE_IGNORE_INVALID_CHARS; + + g_return_if_fail (tab->priv->auto_save_timeout <= 0); + + /* Force saving */ + xed_document_save (doc, tab->priv->save_flags); + } + else + { + unrecoverable_saving_error_message_area_response (info_bar, response_id, tab); + } +} + static void no_backup_error_message_area_response (GtkWidget *message_area, gint response_id, @@ -1225,8 +1255,11 @@ document_saved (XedDocument *document, g_return_if_fail (tab->priv->tmp_encoding != NULL); g_return_if_fail (tab->priv->auto_save_timeout <= 0); - g_timer_destroy (tab->priv->timer); - tab->priv->timer = NULL; + if (tab->priv->timer != NULL) + { + g_timer_destroy (tab->priv->timer); + tab->priv->timer = NULL; + } tab->priv->times_called = 0; set_message_area (tab, NULL); @@ -1260,6 +1293,19 @@ document_saved (XedDocument *document, g_signal_connect (emsg, "response", G_CALLBACK (no_backup_error_message_area_response), tab); } + else if (error->domain == XED_DOCUMENT_ERROR && + error->code == XED_DOCUMENT_ERROR_CONVERSION_FALLBACK) + { + /* If we have any invalid char in the document we must warn the user + as it can make the document useless if it is saved */ + emsg = xed_invalid_character_message_area_new (tab->priv->tmp_save_location); + g_return_if_fail (emsg != NULL); + + set_message_area (tab, emsg); + + g_signal_connect (emsg, "response", + G_CALLBACK (invalid_character_message_area_response), tab); + } else if (error->domain == XED_DOCUMENT_ERROR || (error->domain == G_IO_ERROR && error->code != G_IO_ERROR_INVALID_DATA && diff --git a/xed/xed-utils.c b/xed/xed-utils.c index cb74976..148ba7e 100644 --- a/xed/xed-utils.c +++ b/xed/xed-utils.c @@ -287,25 +287,6 @@ xed_utils_set_atk_relation (GtkWidget *obj1, g_object_unref (G_OBJECT (relation)); } -gboolean -xed_utils_location_exists (GFile *location) -{ - gboolean res; - gchar *uri; - - g_return_val_if_fail (G_IS_FILE (location), FALSE); - - uri = g_file_get_uri (location); - xed_debug_message (DEBUG_UTILS, "text_uri: %s", uri); - g_free (uri); - - res = g_file_query_exists (location, NULL); - - xed_debug_message (DEBUG_UTILS, res ? "TRUE" : "FALSE"); - - return res; -} - gchar * xed_utils_escape_search_text (const gchar* text) { @@ -1344,23 +1325,6 @@ xed_utils_basename_for_display (GFile *location) return name; } -/** - * xed_utils_uri_for_display: - * @location: location to be displayed. - * - * Filter, modify, unescape and change @uri to make it appropriate - * for display to users. - * - * This function is a convenient wrapper for g_file_get_parse_name - * - * Return value: a string which represents @uri and can be displayed. - */ -gchar * -xed_utils_uri_for_display (GFile *location) -{ - return g_file_get_parse_name (location); -} - /** * xed_utils_drop_get_uris: * @selection_data: the #GtkSelectionData from drag_data_received diff --git a/xed/xed-utils.h b/xed/xed-utils.h index 79749f5..669b500 100644 --- a/xed/xed-utils.h +++ b/xed/xed-utils.h @@ -87,8 +87,6 @@ void xed_utils_set_atk_relation (GtkWidget *obj1, GtkWidget *obj2, AtkRelationType rel_type); -gboolean xed_utils_location_exists (GFile *location); - gchar *xed_utils_escape_search_text (const gchar *text); gchar *xed_utils_unescape_search_text (const gchar *text); @@ -127,8 +125,6 @@ gboolean xed_utils_file_has_parent (GFile *gfile); /* Return NULL if str is not a valid URI and/or filename */ gchar *xed_utils_make_canonical_uri_from_shell_arg (const gchar *str); -gchar *xed_utils_uri_for_display (GFile *location); - gchar *xed_utils_basename_for_display (GFile *location); gboolean xed_utils_decode_uri (const gchar *uri, diff --git a/xed/xed-window.c b/xed/xed-window.c index 5b75854..6419cbc 100644 --- a/xed/xed-window.c +++ b/xed/xed-window.c @@ -1078,7 +1078,7 @@ update_recent_files_menu (XedWindow *window) /* gtk_recent_info_get_uri_display (info) is buggy and * works only for local files */ location = g_file_new_for_uri (gtk_recent_info_get_uri (info)); - uri = xed_utils_uri_for_display (location); + uri = g_file_get_parse_name (location); g_object_unref (location); ruri = xed_utils_replace_home_dir_with_tilde (uri); g_free (uri);