Updating branch refs/heads/master to 46e78d17d7e5fc5ae16f9e9ee6ae8103e683af53 (commit) from 4ccd1ba30c425214156b07cf6e58b001fa8970d9 (commit)
commit 46e78d17d7e5fc5ae16f9e9ee6ae8103e683af53 Author: Nick Schermer <n...@xfce.org> Date: Fri Apr 6 13:57:06 2007 +0000 * mousepad/mousepad-document.c: Because we don't use invisible characters in the text buffer, I was able to write a custom iter search function that can search in both directions, can be case insensitive, no string duplications and above all: is over 10x faster then the gtk version. This gives a nice performance boost to the highlight function. * mousepad/mousepad-search-bar.c: Connected the last signals and added a wrap around option to the search bar. (Old svn revision: 25402) ChangeLog | 10 ++ configure.in.in | 2 +- mousepad/mousepad-document.c | 202 ++++++++++++++++++++++++++++++-------- mousepad/mousepad-preferences.c | 34 ++++++- mousepad/mousepad-private.h | 2 + mousepad/mousepad-search-bar.c | 105 +++++++++++++++++++- mousepad/mousepad-types.h | 5 +- mousepad/mousepad-window.c | 1 + 8 files changed, 308 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0ebc98e..3c70f4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-04-06 Nick Schermer <n...@xfce.org> + * mousepad/mousepad-document.c: Because we don't use invisible characters in + the text buffer, I was able to write a custom iter search function that can + search in both directions, can be case insensitive, no string duplications + and above all: is over 10x faster then the gtk version. This gives a nice + performance boost to the highlight function. + * mousepad/mousepad-search-bar.c: Connected the last signals and added a + wrap around option to the search bar. + + 2007-04-05 Nick Schermer <n...@xfce.org> * mousepad/mousepad-document.c: Remove unused properties. diff --git a/configure.in.in b/configure.in.in index 66d719b..272e528 100644 --- a/configure.in.in +++ b/configure.in.in @@ -73,7 +73,7 @@ AC_SUBST([MOUSEPAD_VERSION_MICRO]) dnl ********************************** dnl *** Check for standard headers *** dnl ********************************** -AC_CHECK_HEADERS([errno.h fcntl.h memory.h stdlib.h string.h \ +AC_CHECK_HEADERS([ctype.h errno.h fcntl.h memory.h stdlib.h string.h \ sys/mman.h sys/types.h sys/stat.h time.h unistd.h]) dnl ************************************ diff --git a/mousepad/mousepad-document.c b/mousepad/mousepad-document.c index e26cf36..8310f09 100644 --- a/mousepad/mousepad-document.c +++ b/mousepad/mousepad-document.c @@ -30,6 +30,9 @@ #ifdef HAVE_TIME_H #include <time.h> #endif +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif #include <mousepad/mousepad-private.h> #include <mousepad/mousepad-types.h> @@ -45,26 +48,33 @@ -static void mousepad_document_class_init (MousepadDocumentClass *klass); -static void mousepad_document_init (MousepadDocument *document); -static void mousepad_document_finalize (GObject *object); -static void mousepad_document_modified_changed (GtkTextBuffer *buffer, - MousepadDocument *document); -static void mousepad_document_notify_has_selection (GtkTextBuffer *buffer, - GParamSpec *pspec, - MousepadDocument *document); -static void mousepad_document_notify_cursor_position (GtkTextBuffer *buffer, - GParamSpec *pspec, - MousepadDocument *document); -static void mousepad_document_toggle_overwrite (GtkTextView *textview, - GParamSpec *pspec, - MousepadDocument *document); -static void mousepad_document_scroll_to_visible_area (MousepadDocument *document); -static void mousepad_document_update_tab (MousepadDocument *document, - GParamSpec *pspec, - GtkWidget *ebox); -static void mousepad_document_tab_button_clicked (GtkWidget *widget, - MousepadDocument *document); +static void mousepad_document_class_init (MousepadDocumentClass *klass); +static void mousepad_document_init (MousepadDocument *document); +static void mousepad_document_finalize (GObject *object); +static void mousepad_document_modified_changed (GtkTextBuffer *buffer, + MousepadDocument *document); +static void mousepad_document_notify_has_selection (GtkTextBuffer *buffer, + GParamSpec *pspec, + MousepadDocument *document); +static void mousepad_document_notify_cursor_position (GtkTextBuffer *buffer, + GParamSpec *pspec, + MousepadDocument *document); +static void mousepad_document_toggle_overwrite (GtkTextView *textview, + GParamSpec *pspec, + MousepadDocument *document); +static void mousepad_document_scroll_to_visible_area (MousepadDocument *document); +static gboolean mousepad_document_iter_search (const GtkTextIter *start, + const gchar *str, + MousepadSearchFlags flags, + GtkTextIter *match_start, + GtkTextIter *match_end, + const GtkTextIter *limit, + gboolean forward_search); +static void mousepad_document_update_tab (MousepadDocument *document, + GParamSpec *pspec, + GtkWidget *ebox); +static void mousepad_document_tab_button_clicked (GtkWidget *widget, + MousepadDocument *document); @@ -579,21 +589,114 @@ mousepad_document_open_file (MousepadDocument *document, + +static gboolean +mousepad_document_iter_search (const GtkTextIter *start, + const gchar *str, + MousepadSearchFlags flags, + GtkTextIter *match_start, + GtkTextIter *match_end, + const GtkTextIter *limit, + gboolean search_forward) +{ + GtkTextIter iter, begin; + gunichar iter_char, str_char; + gboolean succeed = FALSE; + gboolean continue_search; + guint str_offset = 0; + + _mousepad_return_val_if_fail (start != NULL, FALSE); + _mousepad_return_val_if_fail (limit != NULL, FALSE); + + /* set the start iter */ + iter = *start; + + /* walk from the start to the end iter */ + do + { + /* break when we hit the search limit */ + if (G_UNLIKELY (gtk_text_iter_equal (&iter, limit))) + break; + + /* get the characters we're going to compare */ + iter_char = gtk_text_iter_get_char (&iter); + str_char = g_utf8_get_char (str); + + /* convert the characters to lower case if needed */ + if (flags & MOUSEPAD_SEARCH_CASE_INSENSITIVE) + { + iter_char = tolower (iter_char); + str_char = tolower (str_char); + } + + /* compare the two characters */ + if (iter_char == str_char) + { + /* first character matched, set the begin iter */ + if (str_offset == 0) + begin = iter; + + /* get the next character and increase the offset counter */ + str = g_utf8_next_char (str); + str_offset++; + + /* we've hit the end of the search string, so we had a full match */ + if (G_UNLIKELY (*str == '\0')) + { + /* forward one character */ + if (G_LIKELY (search_forward)) + gtk_text_iter_forward_char (&iter); + else + gtk_text_iter_forward_char (&begin); + + /* set the start and end iters */ + *match_start = begin; + *match_end = iter; + + /* return true and break the loop */ + succeed = TRUE; + break; + } + } + else if (G_UNLIKELY (str_offset > 0)) + { + /* go back to the first character in the string */ + for (;str_offset > 0; str_offset--) + str = g_utf8_prev_char (str); + + /* reset the iter */ + iter = begin; + } + + /* jump to next iter in the buffer */ + if (G_LIKELY (search_forward)) + continue_search = gtk_text_iter_forward_char (&iter); + else + continue_search = gtk_text_iter_backward_char (&iter); + } + while (G_LIKELY (continue_search)); + + return succeed; +} + + + gboolean mousepad_document_find (MousepadDocument *document, const gchar *string, MousepadSearchFlags flags) { - gboolean found; - gboolean already_wrapped = FALSE; - GtkTextIter doc_start, doc_end; - GtkTextIter sel_start, sel_end; - GtkTextIter match_start, match_end; - GtkTextIter start, end; + gboolean found; + gboolean already_wrapped = FALSE; + gchar *reversed = NULL; + GtkTextIter doc_start, doc_end; + GtkTextIter sel_start, sel_end; + GtkTextIter match_start, match_end; + GtkTextIter start, end; _mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), FALSE); _mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (document->buffer), FALSE); - _mousepad_return_val_if_fail (string != NULL, FALSE); + _mousepad_return_val_if_fail (string && g_utf8_validate (string, -1, NULL), FALSE); /* get the bounds */ gtk_text_buffer_get_bounds (document->buffer, &doc_start, &doc_end); @@ -609,6 +712,9 @@ mousepad_document_find (MousepadDocument *document, { start = sel_start; end = doc_start; + + /* reverse the search string */ + reversed = g_utf8_strreverse (string, -1); } else /* type-ahead */ { @@ -619,9 +725,9 @@ mousepad_document_find (MousepadDocument *document, search: /* try to find the next occurence of the string */ if (flags & MOUSEPAD_SEARCH_BACKWARDS) - found = gtk_text_iter_backward_search (&start, string, DEFAULT_SEARCH_FLAGS, &match_start, &match_end, &end); + found = mousepad_document_iter_search (&start, reversed, flags, &match_start, &match_end, &end, FALSE); else - found = gtk_text_iter_forward_search (&start, string, DEFAULT_SEARCH_FLAGS, &match_start, &match_end, &end); + found = mousepad_document_iter_search (&start, string, flags, &match_start, &match_end, &end, TRUE); /* select the occurence */ if (found) @@ -636,7 +742,7 @@ search: mousepad_document_scroll_to_visible_area (document); } /* wrap around */ - else if (already_wrapped == FALSE) + else if (flags & MOUSEPAD_SEARCH_WRAP_AROUND && already_wrapped == FALSE) { /* set the new start and end iter */ if (flags & MOUSEPAD_SEARCH_BACKWARDS) @@ -656,6 +762,14 @@ search: /* search again */ goto search; } + else if (flags & MOUSEPAD_SEARCH_WRAP_AROUND) + { + /* nothing found, we already did the wrap, so just place the cursor where we started */ + gtk_text_buffer_place_cursor (document->buffer, &sel_start); + } + + /* cleanup */ + g_free (reversed); return found; } @@ -684,6 +798,7 @@ mousepad_document_highlight_all (MousepadDocument *document, _mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document)); _mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (document->buffer)); + _mousepad_return_if_fail (string ? g_utf8_validate (string, -1, NULL) : TRUE); /* get the document bounds */ gtk_text_buffer_get_bounds (document->buffer, &doc_start, &doc_end); @@ -699,19 +814,20 @@ mousepad_document_highlight_all (MousepadDocument *document, /* highlight all the occurences of the strings */ do - { - /* search for the next occurence of the string */ - found = gtk_text_iter_forward_search (&iter, string, DEFAULT_SEARCH_FLAGS, &match_start, &match_end, NULL); - - if (G_LIKELY (found)) - { - /* highlight the found occurence */ - gtk_text_buffer_apply_tag (document->buffer, document->tag, &match_start, &match_end); - - /* jump to the end of the highlighted string and continue searching */ - iter = match_end; - } - } while (found); + { + /* search for the next occurence of the string */ + found = mousepad_document_iter_search (&iter, string, flags, &match_start, &match_end, &doc_end, TRUE); + + if (G_LIKELY (found)) + { + /* highlight the found occurence */ + gtk_text_buffer_apply_tag (document->buffer, document->tag, &match_start, &match_end); + + /* jump to the end of the highlighted string and continue searching */ + iter = match_end; + } + } + while (found); } } diff --git a/mousepad/mousepad-preferences.c b/mousepad/mousepad-preferences.c index 8a7c751..cb30743 100644 --- a/mousepad/mousepad-preferences.c +++ b/mousepad/mousepad-preferences.c @@ -49,9 +49,11 @@ enum { PROP_0, PROP_FONT_NAME, + PROP_LAST_MATCH_CASE, + PROP_LAST_STATUSBAR_VISIBLE, PROP_LAST_WINDOW_HEIGHT, PROP_LAST_WINDOW_WIDTH, - PROP_STATUSBAR, + PROP_LAST_WRAP_AROUND, PROP_WORD_WRAP, PROP_MISC_ALWAYS_SHOW_TABS, PROP_MISC_CYCLE_TABS, @@ -190,12 +192,25 @@ mousepad_preferences_class_init (MousepadPreferencesClass *klass) MOUSEPAD_PARAM_READWRITE)); /** - * MousepadPreferences:statusbar + * MousepadPreferences:last-match-case + * + * Whether to enable match case in the search bar. + **/ + g_object_class_install_property (gobject_class, + PROP_LAST_MATCH_CASE, + g_param_spec_boolean ("last-match-case", + "last-match-case", + "last-match-case", + FALSE, + MOUSEPAD_PARAM_READWRITE)); + + /** + * MousepadPreferences:last-statusbar-visible * * Whether to display the statusbar in the Mousepad window. **/ g_object_class_install_property (gobject_class, - PROP_STATUSBAR, + PROP_LAST_STATUSBAR_VISIBLE, g_param_spec_boolean ("last-statusbar-visible", "last-statusbar-visible", "last-statusbar-visible", @@ -231,6 +246,19 @@ mousepad_preferences_class_init (MousepadPreferencesClass *klass) MOUSEPAD_PARAM_READWRITE)); /** + * MousepadPreferences:last-wrap-around + * + * Whether to enable wrap around in the search bar. + **/ + g_object_class_install_property (gobject_class, + PROP_LAST_WRAP_AROUND, + g_param_spec_boolean ("last-wrap-around", + "last-wrap-around", + "last-wrap-around", + TRUE, + MOUSEPAD_PARAM_READWRITE)); + + /** * MousepadPreferences:word-wrap * * Whether word wrapping is enabled. diff --git a/mousepad/mousepad-private.h b/mousepad/mousepad-private.h index 9d74340..e0455b4 100644 --- a/mousepad/mousepad-private.h +++ b/mousepad/mousepad-private.h @@ -37,6 +37,8 @@ G_BEGIN_DECLS g_print ("%s (%d): %f\n", __FUNCTION__, __LINE__, g_timer_elapsed (__FUNCTION__timer, NULL)); \ g_timer_destroy (__FUNCTION__timer); +#define PRINT_LINE g_print ("%d\n", __LINE__); + /* optimize the properties */ #define MOUSEPAD_PARAM_READWRITE (G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB) diff --git a/mousepad/mousepad-search-bar.c b/mousepad/mousepad-search-bar.c index 8f4bc8b..46e197c 100644 --- a/mousepad/mousepad-search-bar.c +++ b/mousepad/mousepad-search-bar.c @@ -29,6 +29,7 @@ #include <mousepad/mousepad-types.h> #include <mousepad/mousepad-enum-types.h> #include <mousepad/mousepad-search-bar.h> +#include <mousepad/mousepad-preferences.h> #include <mousepad/mousepad-window.h> @@ -50,6 +51,10 @@ static void mousepad_search_bar_highlight_toggled (GtkWidget MousepadSearchBar *search_bar); static void mousepad_search_bar_match_case_toggled (GtkWidget *button, MousepadSearchBar *search_bar); +static void mousepad_search_bar_wrap_around_toggled (GtkWidget *button, + MousepadSearchBar *search_bar); +static void mousepad_search_bar_menuitem_toggled (GtkCheckMenuItem *item, + GtkToggleButton *button); static gboolean mousepad_search_bar_highlight_timeout (gpointer user_data); static void mousepad_search_bar_highlight_timeout_destroy (gpointer user_data); static void mousepad_search_bar_nothing_found (MousepadSearchBar *search_bar, @@ -74,10 +79,14 @@ struct _MousepadSearchBar { GtkToolbar __parent__; + MousepadPreferences *preferences; + /* text entry */ GtkWidget *entry; - GtkToolItem *next; - GtkToolItem *previous; + + /* menu entries */ + GtkWidget *match_case_entry; + GtkWidget *wrap_around_entry; /* if something was found */ guint nothing_found : 1; @@ -85,6 +94,7 @@ struct _MousepadSearchBar /* settings */ guint highlight_all : 1; guint match_case : 1; + guint wrap_around : 1; /* timeout for highlighting while typing */ guint highlight_id; @@ -186,10 +196,22 @@ mousepad_search_bar_init (MousepadSearchBar *search_bar) { GtkWidget *label, *image, *check, *menuitem; GtkToolItem *item; + gboolean match_case, wrap_around; + + /* preferences */ + search_bar->preferences = mousepad_preferences_get (); + + /* load some properties */ + g_object_get (G_OBJECT (search_bar->preferences), + "last-match-case", &match_case, + "last-wrap-around", &wrap_around, + NULL); /* init variables */ search_bar->nothing_found = FALSE; search_bar->highlight_id = 0; + search_bar->match_case = match_case; + search_bar->wrap_around = wrap_around; /* the close button */ item = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE); @@ -236,7 +258,7 @@ mousepad_search_bar_init (MousepadSearchBar *search_bar) image = gtk_image_new_from_stock (GTK_STOCK_GO_UP, TOOL_BAR_ICON_SIZE); gtk_widget_show (image); - search_bar->previous = item = gtk_tool_button_new (image, _("_Previous")); + item = gtk_tool_button_new (image, _("_Previous")); gtk_tool_item_set_is_important (item, TRUE); gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (item), TRUE); gtk_toolbar_insert (GTK_TOOLBAR (search_bar), item, -1); @@ -262,13 +284,36 @@ mousepad_search_bar_init (MousepadSearchBar *search_bar) check = gtk_check_button_new_with_mnemonic (_("Mat_ch Case")); gtk_container_add (GTK_CONTAINER (item), check); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), match_case); gtk_widget_show (check); g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (mousepad_search_bar_match_case_toggled), search_bar); - menuitem = gtk_check_menu_item_new_with_mnemonic (_("Mat_ch Case")); + search_bar->match_case_entry = menuitem = gtk_check_menu_item_new_with_mnemonic (_("Mat_ch Case")); + gtk_tool_item_set_proxy_menu_item (item, "case-sensitive", menuitem); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), match_case); + gtk_widget_show (menuitem); + g_signal_connect (G_OBJECT (menuitem), "toggled", + G_CALLBACK (mousepad_search_bar_menuitem_toggled), check); + + /* check button for wrap around, including the proxy menu item */ + item = gtk_tool_item_new (); + gtk_toolbar_insert (GTK_TOOLBAR (search_bar), item, -1); + gtk_widget_show (GTK_WIDGET (item)); + + check = gtk_check_button_new_with_mnemonic (_("W_rap Around")); + gtk_container_add (GTK_CONTAINER (item), check); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), wrap_around); + gtk_widget_show (check); + g_signal_connect (G_OBJECT (check), "toggled", + G_CALLBACK (mousepad_search_bar_wrap_around_toggled), search_bar); + + search_bar->wrap_around_entry = menuitem = gtk_check_menu_item_new_with_mnemonic (_("W_rap Around")); gtk_tool_item_set_proxy_menu_item (item, "case-sensitive", menuitem); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), wrap_around); gtk_widget_show (menuitem); + g_signal_connect (G_OBJECT (menuitem), "toggled", + G_CALLBACK (mousepad_search_bar_menuitem_toggled), check); } @@ -278,6 +323,9 @@ mousepad_search_bar_finalize (GObject *object) { MousepadSearchBar *search_bar = MOUSEPAD_SEARCH_BAR (object); + /* release the preferences */ + g_object_unref (G_OBJECT (search_bar->preferences)); + /* stop a running highlight timeout */ if (search_bar->highlight_id != 0) g_source_remove (search_bar->highlight_id); @@ -298,6 +346,10 @@ mousepad_search_bar_find_string (MousepadSearchBar *search_bar, if (!search_bar->match_case) flags |= MOUSEPAD_SEARCH_CASE_INSENSITIVE; + /* wrap around flag */ + if (search_bar->wrap_around) + flags |= MOUSEPAD_SEARCH_WRAP_AROUND; + /* get the entry string */ string = gtk_entry_get_text (GTK_ENTRY (search_bar->entry)); @@ -384,8 +436,53 @@ mousepad_search_bar_match_case_toggled (GtkWidget *button, /* get the state of the toggle button */ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + /* set the state of the menu item */ + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (search_bar->match_case_entry), active); + /* save the state */ search_bar->match_case = active; + + /* save the setting */ + g_object_set (G_OBJECT (search_bar->preferences), "last-match-case", active, NULL); + + /* invoke the highlight function to update the buffer */ + search_bar->highlight_id = g_idle_add_full (G_PRIORITY_LOW, mousepad_search_bar_highlight_timeout, + search_bar, mousepad_search_bar_highlight_timeout_destroy); +} + + + +static void +mousepad_search_bar_wrap_around_toggled (GtkWidget *button, + MousepadSearchBar *search_bar) +{ + gboolean active; + + _mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (search_bar)); + + /* get the state of the toggle button */ + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + /* set the state of the menu item */ + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (search_bar->wrap_around_entry), active); + + /* save the state */ + search_bar->wrap_around = active; + + /* save the setting */ + g_object_set (G_OBJECT (search_bar->preferences), "last-wrap-around", active, NULL); +} + + + +static void +mousepad_search_bar_menuitem_toggled (GtkCheckMenuItem *item, + GtkToggleButton *button) +{ + gboolean active; + + active = gtk_check_menu_item_get_active (item); + gtk_toggle_button_set_active (button, active); } diff --git a/mousepad/mousepad-types.h b/mousepad/mousepad-types.h index a1aa178..f819392 100644 --- a/mousepad/mousepad-types.h +++ b/mousepad/mousepad-types.h @@ -25,8 +25,9 @@ G_BEGIN_DECLS typedef enum { MOUSEPAD_SEARCH_CASE_INSENSITIVE = 1 << 1, - MOUSEPAD_SEARCH_FORWARDS = 1 << 2, - MOUSEPAD_SEARCH_BACKWARDS = 1 << 3, + MOUSEPAD_SEARCH_WRAP_AROUND = 1 << 2, + MOUSEPAD_SEARCH_FORWARDS = 1 << 3, + MOUSEPAD_SEARCH_BACKWARDS = 1 << 4, } MousepadSearchFlags; G_END_DECLS diff --git a/mousepad/mousepad-window.c b/mousepad/mousepad-window.c index c09414f..b223468 100644 --- a/mousepad/mousepad-window.c +++ b/mousepad/mousepad-window.c @@ -441,6 +441,7 @@ mousepad_window_init (MousepadWindow *window) accel_group = gtk_ui_manager_get_accel_group (window->ui_manager); gtk_window_add_accel_group (GTK_WINDOW (window), accel_group); + /* create the main table */ window->table = gtk_table_new (6, 1, FALSE); gtk_container_add (GTK_CONTAINER (window), window->table); gtk_widget_show (window->table); _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org https://mail.xfce.org/mailman/listinfo/xfce4-commits