diff options
-rw-r--r-- | libempathy-gtk/empathy-ui-utils.c | 687 | ||||
-rw-r--r-- | libempathy-gtk/empathy-ui-utils.h | 19 |
2 files changed, 7 insertions, 699 deletions
diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index 798817ef1..8d4689ae1 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -501,7 +501,7 @@ avatar_pixbuf_from_loader (GdkPixbufLoader *loader) return pixbuf; } -GdkPixbuf * +static GdkPixbuf * empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, gint width, gint height) @@ -832,6 +832,11 @@ empathy_pixbuf_contact_status_icon (EmpathyContact *contact, icon_name, show_protocol); } +static GdkPixbuf * empathy_pixbuf_protocol_from_contact_scaled ( + EmpathyContact *contact, + gint width, + gint height); + GdkPixbuf * empathy_pixbuf_contact_status_icon_with_icon_name (EmpathyContact *contact, const gchar *icon_name, @@ -895,7 +900,7 @@ empathy_pixbuf_contact_status_icon_with_icon_name (EmpathyContact *contact, return pix_status; } -GdkPixbuf * +static GdkPixbuf * empathy_pixbuf_protocol_from_contact_scaled (EmpathyContact *contact, gint width, gint height) @@ -1007,684 +1012,6 @@ empathy_filename_from_icon_name (const gchar *icon_name, return ret; } -/* Stolen from GtkSourceView, hence the weird intendation. Please keep it like - * that to make it easier to apply changes from the original code. - */ -#define GTK_TEXT_UNKNOWN_CHAR 0xFFFC - -/* this function acts like g_utf8_offset_to_pointer() except that if it finds a - * decomposable character it consumes the decomposition length from the given - * offset. So it's useful when the offset was calculated for the normalized - * version of str, but we need a pointer to str itself. */ -static const gchar * -pointer_from_offset_skipping_decomp (const gchar *str, - gint offset) -{ - gchar *casefold, *normal; - const gchar *p, *q; - - p = str; - while (offset > 0) - { - q = g_utf8_next_char (p); - casefold = g_utf8_casefold (p, q - p); - normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - offset -= g_utf8_strlen (normal, -1); - g_free (casefold); - g_free (normal); - p = q; - } - - return p; -} - -static const gchar * -g_utf8_strcasestr (const gchar *haystack, - const gchar *needle) -{ - gsize needle_len; - gsize haystack_len; - const gchar *ret = NULL; - gchar *p; - gchar *casefold; - gchar *caseless_haystack; - gint i; - - g_return_val_if_fail (haystack != NULL, NULL); - g_return_val_if_fail (needle != NULL, NULL); - - casefold = g_utf8_casefold (haystack, -1); - caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - needle_len = g_utf8_strlen (needle, -1); - haystack_len = g_utf8_strlen (caseless_haystack, -1); - - if (needle_len == 0) - { - ret = (gchar *) haystack; - goto finally_1; - } - - if (haystack_len < needle_len) - { - ret = NULL; - goto finally_1; - } - - p = (gchar *) caseless_haystack; - needle_len = strlen (needle); - i = 0; - - while (*p) - { - if ((strncmp (p, needle, needle_len) == 0)) - { - ret = pointer_from_offset_skipping_decomp (haystack, i); - goto finally_1; - } - - p = g_utf8_next_char (p); - i++; - } - -finally_1: - g_free (caseless_haystack); - - return ret; -} - -static gboolean -g_utf8_caselessnmatch (const char *s1, - const char *s2, - gssize n1, - gssize n2) -{ - gchar *casefold; - gchar *normalized_s1; - gchar *normalized_s2; - gint len_s1; - gint len_s2; - gboolean ret = FALSE; - - g_return_val_if_fail (s1 != NULL, FALSE); - g_return_val_if_fail (s2 != NULL, FALSE); - g_return_val_if_fail (n1 > 0, FALSE); - g_return_val_if_fail (n2 > 0, FALSE); - - casefold = g_utf8_casefold (s1, n1); - normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - casefold = g_utf8_casefold (s2, n2); - normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - len_s1 = strlen (normalized_s1); - len_s2 = strlen (normalized_s2); - - if (len_s1 < len_s2) - goto finally_2; - - ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0); - -finally_2: - g_free (normalized_s1); - g_free (normalized_s2); - - return ret; -} - -static void -forward_chars_with_skipping (GtkTextIter *iter, - gint count, - gboolean skip_invisible, - gboolean skip_nontext, - gboolean skip_decomp) -{ - gint i; - - g_return_if_fail (count >= 0); - - i = count; - - while (i > 0) - { - gboolean ignored = FALSE; - - /* minimal workaround to avoid the infinite loop of bug #168247. - * It doesn't fix the problemjust the symptom... - */ - if (gtk_text_iter_is_end (iter)) - return; - - if (skip_nontext && - gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR) - ignored = TRUE; - - if (!ignored && skip_invisible && - /* _gtk_text_btree_char_is_invisible (iter)*/ FALSE) - ignored = TRUE; - - if (!ignored && skip_decomp) - { - /* being UTF8 correct sucks; this accounts for extra - offsets coming from canonical decompositions of - UTF8 characters (e.g. accented characters) which - g_utf8_normalize () performs */ - gchar *normal; - gchar buffer[6]; - gint buffer_len; - - buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), - buffer); - - normal = g_utf8_normalize (buffer, buffer_len, G_NORMALIZE_NFD); - i -= (g_utf8_strlen (normal, -1) - 1); - g_free (normal); - } - - gtk_text_iter_forward_char (iter); - - if (!ignored) - --i; - } -} - -static gboolean -lines_match (const GtkTextIter *start, - const gchar **lines, - gboolean visible_only, - gboolean slice, - GtkTextIter *match_start, - GtkTextIter *match_end) -{ - GtkTextIter next; - gchar *line_text; - const gchar *found; - gint offset; - - if (*lines == NULL || **lines == '\0') - { - if (match_start) - *match_start = *start; - if (match_end) - *match_end = *start; - return TRUE; - } - - next = *start; - gtk_text_iter_forward_line (&next); - - /* No more text in buffer, but *lines is nonempty */ - if (gtk_text_iter_equal (start, &next)) - return FALSE; - - if (slice) - { - if (visible_only) - line_text = gtk_text_iter_get_visible_slice (start, &next); - else - line_text = gtk_text_iter_get_slice (start, &next); - } - else - { - if (visible_only) - line_text = gtk_text_iter_get_visible_text (start, &next); - else - line_text = gtk_text_iter_get_text (start, &next); - } - - if (match_start) /* if this is the first line we're matching */ - { - found = g_utf8_strcasestr (line_text, *lines); - } - else - { - /* If it's not the first line, we have to match from the - * start of the line. - */ - if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), - strlen (*lines))) - found = line_text; - else - found = NULL; - } - - if (found == NULL) - { - g_free (line_text); - return FALSE; - } - - /* Get offset to start of search string */ - offset = g_utf8_strlen (line_text, found - line_text); - - next = *start; - - /* If match start needs to be returned, set it to the - * start of the search string. - */ - forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); - if (match_start) - { - *match_start = next; - } - - /* Go to end of search string */ - forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, - !slice, TRUE); - - g_free (line_text); - - ++lines; - - if (match_end) - *match_end = next; - - /* pass NULL for match_start, since we don't need to find the - * start again. - */ - return lines_match (&next, lines, visible_only, slice, NULL, match_end); -} - -/* strsplit () that retains the delimiter as part of the string. */ -static gchar ** -strbreakup (const char *string, - const char *delimiter, - gint max_tokens) -{ - GSList *string_list = NULL, *slist; - gchar **str_array, *s, *casefold, *new_string; - guint i, n = 1; - - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (delimiter != NULL, NULL); - - if (max_tokens < 1) - max_tokens = G_MAXINT; - - s = strstr (string, delimiter); - if (s) - { - guint delimiter_len = strlen (delimiter); - - do - { - guint len; - - len = s - string + delimiter_len; - new_string = g_new (gchar, len + 1); - strncpy (new_string, string, len); - new_string[len] = 0; - casefold = g_utf8_casefold (new_string, -1); - g_free (new_string); - new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - string_list = g_slist_prepend (string_list, new_string); - n++; - string = s + delimiter_len; - s = strstr (string, delimiter); - } while (--max_tokens && s); - } - - if (*string) - { - n++; - casefold = g_utf8_casefold (string, -1); - new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - string_list = g_slist_prepend (string_list, new_string); - } - - str_array = g_new (gchar*, n); - - i = n - 1; - - str_array[i--] = NULL; - for (slist = string_list; slist; slist = slist->next) - str_array[i--] = slist->data; - - g_slist_free (string_list); - - return str_array; -} - -gboolean -empathy_text_iter_forward_search (const GtkTextIter *iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit) -{ - gchar **lines = NULL; - GtkTextIter match; - gboolean retval = FALSE; - GtkTextIter search; - gboolean visible_only; - gboolean slice; - - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (str != NULL, FALSE); - - if (limit && gtk_text_iter_compare (iter, limit) >= 0) - return FALSE; - - if (*str == '\0') - { - /* If we can move one char, return the empty string there */ - match = *iter; - - if (gtk_text_iter_forward_char (&match)) - { - if (limit && gtk_text_iter_equal (&match, limit)) - return FALSE; - - if (match_start) - *match_start = match; - - if (match_end) - *match_end = match; - - return TRUE; - } - else - { - return FALSE; - } - } - - visible_only = TRUE; - slice = FALSE; - - /* locate all lines */ - lines = strbreakup (str, "\n", -1); - - search = *iter; - - do - { - /* This loop has an inefficient worst-case, where - * gtk_text_iter_get_text () is called repeatedly on - * a single line. - */ - GtkTextIter end; - - if (limit && gtk_text_iter_compare (&search, limit) >= 0) - break; - - if (lines_match (&search, (const gchar**)lines, - visible_only, slice, &match, &end)) - { - if (limit == NULL || - (limit && gtk_text_iter_compare (&end, limit) <= 0)) - { - retval = TRUE; - - if (match_start) - *match_start = match; - - if (match_end) - *match_end = end; - } - break; - } - } while (gtk_text_iter_forward_line (&search)); - - g_strfreev ((gchar **) lines); - - return retval; -} - -static const gchar * -g_utf8_strrcasestr (const gchar *haystack, - const gchar *needle) -{ - gsize needle_len; - gsize haystack_len; - const gchar *ret = NULL; - gchar *p; - gchar *casefold; - gchar *caseless_haystack; - gint i; - - g_return_val_if_fail (haystack != NULL, NULL); - g_return_val_if_fail (needle != NULL, NULL); - - casefold = g_utf8_casefold (haystack, -1); - caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - needle_len = g_utf8_strlen (needle, -1); - haystack_len = g_utf8_strlen (caseless_haystack, -1); - - if (needle_len == 0) - { - ret = (gchar *) haystack; - goto finally_1; - } - - if (haystack_len < needle_len) - { - ret = NULL; - goto finally_1; - } - - i = haystack_len - needle_len; - p = g_utf8_offset_to_pointer (caseless_haystack, i); - needle_len = strlen (needle); - - while (p >= caseless_haystack) - { - if (strncmp (p, needle, needle_len) == 0) - { - ret = pointer_from_offset_skipping_decomp (haystack, i); - goto finally_1; - } - - p = g_utf8_prev_char (p); - i--; - } - -finally_1: - g_free (caseless_haystack); - - return ret; -} - -static gboolean -backward_lines_match (const GtkTextIter *start, - const gchar **lines, - gboolean visible_only, - gboolean slice, - GtkTextIter *match_start, - GtkTextIter *match_end) -{ - GtkTextIter line, next; - gchar *line_text; - const gchar *found; - gint offset; - - if (*lines == NULL || **lines == '\0') - { - if (match_start) - *match_start = *start; - if (match_end) - *match_end = *start; - return TRUE; - } - - line = next = *start; - if (gtk_text_iter_get_line_offset (&next) == 0) - { - if (!gtk_text_iter_backward_line (&next)) - return FALSE; - } - else - { - gtk_text_iter_set_line_offset (&next, 0); - } - - if (slice) - { - if (visible_only) - line_text = gtk_text_iter_get_visible_slice (&next, &line); - else - line_text = gtk_text_iter_get_slice (&next, &line); - } - else - { - if (visible_only) - line_text = gtk_text_iter_get_visible_text (&next, &line); - else - line_text = gtk_text_iter_get_text (&next, &line); - } - - if (match_start) /* if this is the first line we're matching */ - { - found = g_utf8_strrcasestr (line_text, *lines); - } - else - { - /* If it's not the first line, we have to match from the - * start of the line. - */ - if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), - strlen (*lines))) - found = line_text; - else - found = NULL; - } - - if (found == NULL) - { - g_free (line_text); - return FALSE; - } - - /* Get offset to start of search string */ - offset = g_utf8_strlen (line_text, found - line_text); - - forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); - - /* If match start needs to be returned, set it to the - * start of the search string. - */ - if (match_start) - { - *match_start = next; - } - - /* Go to end of search string */ - forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, - !slice, TRUE); - - g_free (line_text); - - ++lines; - - if (match_end) - *match_end = next; - - /* try to match the rest of the lines forward, passing NULL - * for match_start so lines_match will try to match the entire - * line */ - return lines_match (&next, lines, visible_only, slice, NULL, match_end); -} - -gboolean -empathy_text_iter_backward_search (const GtkTextIter *iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit) -{ - gchar **lines = NULL; - GtkTextIter match; - gboolean retval = FALSE; - GtkTextIter search; - gboolean visible_only; - gboolean slice; - - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (str != NULL, FALSE); - - if (limit && gtk_text_iter_compare (iter, limit) <= 0) - return FALSE; - - if (*str == '\0') - { - /* If we can move one char, return the empty string there */ - match = *iter; - - if (gtk_text_iter_backward_char (&match)) - { - if (limit && gtk_text_iter_equal (&match, limit)) - return FALSE; - - if (match_start) - *match_start = match; - if (match_end) - *match_end = match; - return TRUE; - } - else - { - return FALSE; - } - } - - visible_only = TRUE; - slice = TRUE; - - /* locate all lines */ - lines = strbreakup (str, "\n", -1); - - search = *iter; - - while (TRUE) - { - /* This loop has an inefficient worst-case, where - * gtk_text_iter_get_text () is called repeatedly on - * a single line. - */ - GtkTextIter end; - - if (limit && gtk_text_iter_compare (&search, limit) <= 0) - break; - - if (backward_lines_match (&search, (const gchar**)lines, - visible_only, slice, &match, &end)) - { - if (limit == NULL || (limit && - gtk_text_iter_compare (&end, limit) > 0)) - { - retval = TRUE; - - if (match_start) - *match_start = match; - if (match_end) - *match_end = end; - } - break; - } - - if (gtk_text_iter_get_line_offset (&search) == 0) - { - if (!gtk_text_iter_backward_line (&search)) - break; - } - else - { - gtk_text_iter_set_line_offset (&search, 0); - } - } - - g_strfreev ((gchar **) lines); - - return retval; -} - /* Takes care of moving the window to the current workspace. */ void empathy_window_present_with_time (GtkWindow *window, diff --git a/libempathy-gtk/empathy-ui-utils.h b/libempathy-gtk/empathy-ui-utils.h index e690f11ab..fdf69df06 100644 --- a/libempathy-gtk/empathy-ui-utils.h +++ b/libempathy-gtk/empathy-ui-utils.h @@ -86,16 +86,9 @@ GdkPixbuf * empathy_pixbuf_avatar_from_individual_scaled_finish ( FolksIndividual *individual, GAsyncResult *result, GError **error); -GdkPixbuf * empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, - gint width, - gint height); GdkPixbuf * empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact, gint width, gint height); -GdkPixbuf * empathy_pixbuf_protocol_from_contact_scaled ( - EmpathyContact *contact, - gint width, - gint height); GdkPixbuf * empathy_pixbuf_contact_status_icon (EmpathyContact *contact, gboolean show_protocol); GdkPixbuf * empathy_pixbuf_contact_status_icon_with_icon_name ( @@ -111,18 +104,6 @@ GdkPixbuf * empathy_pixbuf_from_icon_name_sized (const gchar *icon_name, gchar * empathy_filename_from_icon_name (const gchar *icon_name, GtkIconSize icon_size); -/* Text view */ -gboolean empathy_text_iter_forward_search (const GtkTextIter*iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter*limit); -gboolean empathy_text_iter_backward_search (const GtkTextIter*iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit); - /* Windows */ void empathy_window_present (GtkWindow *window); void empathy_window_present_with_time (GtkWindow *window, |