static void linkify_cb (GtkTextBuffer *buf, GRegex *regex) { gchar *text; GtkTextIter start, end; GMatchInfo *match; gtk_text_buffer_get_bounds (buf, &start, &end); text = gtk_text_buffer_get_text (buf, &start, &end, FALSE); gtk_text_buffer_remove_all_tags (buf, &start, &end); if (g_regex_match (regex, text, G_REGEX_MATCH_NOTEMPTY, &match)) { do { gint sp, ep, spos, epos; g_match_info_fetch_pos (match, 0, &sp, &ep); /* positions are in bytes, not character, so here we must normalize it*/ spos = g_utf8_pointer_to_offset (text, text + sp); epos = g_utf8_pointer_to_offset (text, text + ep); gtk_text_buffer_get_iter_at_offset (buf, &start, spos); gtk_text_buffer_get_iter_at_offset (buf, &end, epos); gtk_text_buffer_apply_tag (buf, tag, &start, &end); } while (g_match_info_next (match, NULL)); } g_match_info_free (match); g_free(text); }
static gboolean complete_suggest(GntEntry *entry, const char *text) { int offstart = 0, offend = 0; if (entry->word) { char *s = get_beginning_of_word(entry); const char *iter = text; offstart = g_utf8_pointer_to_offset(entry->start, s); while (*iter && toupper(*s) == toupper(*iter)) { *s++ = *iter++; } if (*iter) { gnt_entry_key_pressed(GNT_WIDGET(entry), iter); } offend = g_utf8_pointer_to_offset(entry->start, entry->cursor); } else { offstart = 0; gnt_entry_set_text_internal(entry, text); offend = g_utf8_strlen(text, -1); } g_signal_emit(G_OBJECT(entry), signals[SIG_COMPLETION], 0, entry->start + offstart, entry->start + offend); update_kill_ring(entry, ENTRY_JAIL, NULL, 0); return TRUE; }
void _gtk_source_regex_fetch_named_pos (GtkSourceRegex *regex, const gchar *text, const gchar *name, gint *start_pos, /* character offsets */ gint *end_pos) /* character offsets */ { gint byte_start_pos, byte_end_pos; g_assert (regex->resolved); if (!g_match_info_fetch_named_pos (regex->u.regex.match, name, &byte_start_pos, &byte_end_pos)) { if (start_pos != NULL) *start_pos = -1; if (end_pos != NULL) *end_pos = -1; } else { if (start_pos != NULL) *start_pos = g_utf8_pointer_to_offset (text, text + byte_start_pos); if (end_pos != NULL) *end_pos = g_utf8_pointer_to_offset (text, text + byte_end_pos); } }
/* searching */ static void do_search (GtkWidget *e, GtkWidget *w) { static gchar *text = NULL; static guint offset; static GRegex *regex = NULL; GMatchInfo *match = NULL; GtkTextIter begin, end; g_free (pattern); pattern = g_strdup (gtk_entry_get_text (GTK_ENTRY (e))); gtk_widget_destroy (w); gtk_widget_queue_draw (text_view); if (new_search || gtk_text_buffer_get_modified (text_buffer)) { /* get the text */ g_free (text); gtk_text_buffer_get_bounds (text_buffer, &begin, &end); text = gtk_text_buffer_get_text (text_buffer, &begin, &end, FALSE); offset = 0; /* compile new regex */ if (regex) g_regex_unref (regex); regex = g_regex_new (pattern, G_REGEX_EXTENDED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL); new_search = FALSE; } /* search and select if found */ if (g_regex_match (regex, text + offset, G_REGEX_MATCH_NOTEMPTY, &match)) { gint sp, ep, spos, epos; g_match_info_fetch_pos (match, 0, &sp, &ep); /* positions are in bytes, not character, so here we must normalize it*/ spos = g_utf8_pointer_to_offset (text, text + sp + offset); epos = g_utf8_pointer_to_offset (text, text + ep + offset); gtk_text_buffer_get_iter_at_offset (text_buffer, &begin, spos); gtk_text_buffer_get_iter_at_offset (text_buffer, &end, epos); gtk_text_buffer_select_range (text_buffer, &begin, &end); gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (text_view), &begin, 0, FALSE, 0, 0); offset += epos; g_match_info_free (match); match = NULL; } else new_search = TRUE; }
/* Splits a line into a set of (word,word_position) tuples. */ static GSList * tokenize_line (GString * line) { GSList * tokens = NULL; char *utf = (char *) line->str; GString * word; gunichar uc; size_t cur_pos = 0; size_t start_pos = 0; word = g_string_new (NULL); while (cur_pos < line->len && *utf) { int i; /* Skip non-word characters. */ cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); uc = g_utf8_get_char (utf); while (cur_pos < line->len && *utf && !is_word_char(uc,0)) { utf = g_utf8_next_char (utf); uc = g_utf8_get_char (utf); cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); } start_pos = cur_pos; /* Skip over word. */ while (cur_pos < line->len && *utf && is_word_char(uc,1)) { g_string_append_unichar (word, uc); utf = g_utf8_next_char (utf); uc = g_utf8_get_char (utf); cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); } /* Do not accept one or more ' at the end of the word. */ i = word->len-1; while ((i >= 0) && (word->str[i] == '\'')) { g_string_truncate (word, i); i--; } /* Save (word, position) tuple. */ if (word->len) { tokens = g_slist_append (tokens, g_string_new_len (word->str, word->len)); tokens = g_slist_append (tokens, GINT_TO_POINTER(start_pos)); g_string_truncate (word, 0); } } g_string_free (word, TRUE); return tokens; }
/** * utf8_byteoffset_to_charsoffset_cached: * @string: the gchar * you want to count * @byteoffset: glong with the byteoffset you want the charoffset for * * this function calculates the UTF-8 character offset in a string for * a given byte offset * It uses caching to speedup multiple calls for the same buffer, the cache * is emptied if you change to another buffer. If you use the same buffer but * change it inbetween calls, you have to reset it yourself using * the utf8_offset_cache_reset() function * **** the result is undefined if the provided byteoffset is in the middle of a UTF8 character *** * * Return value: guint with character offset **/ guint utf8_byteoffset_to_charsoffset_cached(gchar *string, glong byteoffset) { guint retval; gint i = UTF8_OFFSET_CACHE_SIZE-1; if (byteoffset ==0) return 0; if (string != utf8_offset_cache.last_buf) { utf8_offset_cache_reset(); utf8_offset_cache.last_buf = string; } #ifdef DEBUG DEBUG_MSG("utf8_byteoffset_to_charsoffset_cached, string %p has strlen %d, looking for byteoffset %ld, starting in cache at i=%d\n", string, strlen(string),byteoffset,i); #endif while (i > 0 && utf8_offset_cache.last_byteoffset[i] > byteoffset) { i--; } if (i > 0) { if (utf8_offset_cache.last_byteoffset[i] == byteoffset) { #ifdef DEBUG DEBUG_MSG("byteoffset %ld is in the cache at i=%d, returning %d\n",byteoffset,i,utf8_offset_cache.last_charoffset[i]); #endif return utf8_offset_cache.last_charoffset[i]; } /* if the byteoffset is in the middle of a multibyte character, this line will fail (but we are not supposed to get called in the middle of a character)*/ retval = g_utf8_pointer_to_offset(string+utf8_offset_cache.last_byteoffset[i], string+byteoffset)+utf8_offset_cache.last_charoffset[i]; #ifdef UTF8_BYTECHARDEBUG utf8_offset_cache.numbytes_parsed += (byteoffset - utf8_offset_cache.last_byteoffset[i]); utf8_offset_cache.numbytes_cached_parsed += (byteoffset - utf8_offset_cache.last_byteoffset[i]); utf8_offset_cache.numcalls_cached_since_reset++; #endif } else { retval = g_utf8_pointer_to_offset(string, string+byteoffset); #ifdef UTF8_BYTECHARDEBUG utf8_offset_cache.numbytes_parsed += byteoffset; #endif } DEBUG_MSG(" and byteoffset %ld has charoffset %d\n",byteoffset,retval); if (i == (UTF8_OFFSET_CACHE_SIZE-1)) { /* add this new calculation to the cache */ /* this is a nasty trick to move all guint entries one back in the array, so we can add the new one */ memmove(&utf8_offset_cache.last_byteoffset[0], &utf8_offset_cache.last_byteoffset[1], (UTF8_OFFSET_CACHE_SIZE+UTF8_OFFSET_CACHE_SIZE-1)*sizeof(guint)); utf8_offset_cache.last_byteoffset[UTF8_OFFSET_CACHE_SIZE-1] = byteoffset; utf8_offset_cache.last_charoffset[UTF8_OFFSET_CACHE_SIZE-1] = retval; } #ifdef UTF8_BYTECHARDEBUG utf8_offset_cache.numcalls_since_reset++; #endif return retval; }
static void gnt_entry_draw(GntWidget *widget) { GntEntry *entry = GNT_ENTRY(widget); int stop; gboolean focus; int curpos; if ((focus = gnt_widget_has_focus(widget))) wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_TEXT_NORMAL)); else wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D)); if (entry->masked) { mvwhline(widget->window, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET, g_utf8_pointer_to_offset(entry->scroll, entry->end)); } else mvwprintw(widget->window, 0, 0, "%s", C_(entry->scroll)); stop = gnt_util_onscreen_width(entry->scroll, entry->end); if (stop < widget->priv.width) mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop); curpos = gnt_util_onscreen_width(entry->scroll, entry->cursor); if (focus) mvwchgat(widget->window, 0, curpos, 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); wmove(widget->window, 0, curpos); GNTDEBUG; }
// move word left static void textbox_cursor_dec_word ( textbox *tb ) { // Find word boundaries, with pango_Break? gchar *n; gchar *c = g_utf8_offset_to_pointer ( tb->text, tb->cursor ); while ( ( c = g_utf8_prev_char ( c ) ) && c != tb->text ) { gunichar uc = g_utf8_get_char ( c ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( ( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } } if ( c != tb->text ) { while ( ( n = g_utf8_prev_char ( c ) ) ) { gunichar uc = g_utf8_get_char ( n ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( !( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } c = n; if ( n == tb->text ) { break; } } } int index = g_utf8_pointer_to_offset ( tb->text, c ); textbox_cursor ( tb, index ); }
// Move word right static void textbox_cursor_inc_word ( textbox *tb ) { if ( tb->text == NULL ) { return; } // Find word boundaries, with pango_Break? gchar *c = g_utf8_offset_to_pointer ( tb->text, tb->cursor ); while ( ( c = g_utf8_next_char ( c ) ) ) { gunichar uc = g_utf8_get_char ( c ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( ( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } } if ( c == NULL || *c == '\0' ) { return; } while ( ( c = g_utf8_next_char ( c ) ) ) { gunichar uc = g_utf8_get_char ( c ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( !( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } } int index = g_utf8_pointer_to_offset ( tb->text, c ); textbox_cursor ( tb, index ); }
int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const { #if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) return offsetForPositionForSimpleText(run, xFloat, includePartialGlyphs); #endif // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. int x = static_cast<int>(xFloat); PangoLayout* layout = getDefaultPangoLayout(run); setPangoAttributes(this, run, layout); gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); pango_layout_set_text(layout, utf8, -1); int index, trailing; pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing); glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index); if (includePartialGlyphs) offset += trailing; g_free(utf8); g_object_unref(layout); return offset; }
static void test_utf8 (gconstpointer d) { gint num_chars; const gchar **p; gint i, j; const gchar *string = d; g_assert (g_utf8_validate (string, -1, NULL)); num_chars = g_utf8_strlen (string, -1); p = (const gchar **) g_malloc (num_chars * sizeof (gchar *)); p[0] = string; for (i = 1; i < num_chars; i++) p[i] = g_utf8_next_char (p[i-1]); for (i = 0; i < num_chars; i++) for (j = 0; j < num_chars; j++) { g_assert (g_utf8_offset_to_pointer (p[i], j - i) == p[j]); g_assert (g_utf8_pointer_to_offset (p[i], p[j]) == j - i); } g_free (p); }
/** * g_utf8_offset_to_pointer: * @str: a UTF-8 encoded string * @offset: a character offset within @str * * Converts from an integer character offset to a pointer to a position * within the string. * * Since 2.10, this function allows to pass a negative @offset to * step backwards. It is usually worth stepping backwards from the end * instead of forwards if @offset is in the last fourth of the string, * since moving forward is about 3 times faster than moving backward. * * <note><para> * This function doesn't abort when reaching the end of @str. Therefore * you should be sure that @offset is within string boundaries before * calling that function. Call g_utf8_strlen() when unsure. * * This limitation exists as this function is called frequently during * text rendering and therefore has to be as fast as possible. * </para></note> * * Return value: the resulting pointer **/ gchar * g_utf8_offset_to_pointer (const gchar *str, glong offset) { const gchar *s = str; if (offset > 0) while (offset--) s = g_utf8_next_char (s); else { const char *s1; /* This nice technique for fast backwards stepping * through a UTF-8 string was dubbed "stutter stepping" * by its inventor, Larry Ewing. */ while (offset) { s1 = s; s += offset; while ((*s & 0xc0) == 0x80) s--; offset += g_utf8_pointer_to_offset (s, s1); } } return (gchar *)s; }
static gint gail_label_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords) { GtkWidget *widget; GtkLabel *label; const gchar *label_text; gint index, x_layout, y_layout; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return -1; label = GTK_LABEL (widget); gtk_label_get_layout_offsets (label, &x_layout, &y_layout); index = gail_misc_get_index_at_point_in_layout (widget, gtk_label_get_layout (label), x_layout, y_layout, x, y, coords); label_text = gtk_label_get_text (label); if (index == -1) { if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN) return g_utf8_strlen (label_text, -1); return index; } else return g_utf8_pointer_to_offset (label_text, label_text + index); }
static gint go_load_pango_byte_to_char (gchar const *str, gint byte) { if (byte >= (gint)strlen (str)) return g_utf8_strlen (str, -1); return g_utf8_pointer_to_offset (str, g_utf8_prev_char (str + byte + 1)); }
static gint gail_notebook_page_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords) { GtkWidget *label; GailNotebookPage *notebook_page; gint index, x_layout, y_layout; const gchar *label_text; notebook_page = GAIL_NOTEBOOK_PAGE (text); label = get_label_from_notebook_page (notebook_page); if (!GTK_IS_LABEL(label)) return -1; gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout); index = gail_misc_get_index_at_point_in_layout (label, gtk_label_get_layout (GTK_LABEL (label)), x_layout, y_layout, x, y, coords); label_text = gtk_label_get_text (GTK_LABEL (label)); if (index == -1) { if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN) return g_utf8_strlen (label_text, -1); return index; } else return g_utf8_pointer_to_offset (label_text, label_text + index); }
static void buddy_status_changed(PurpleBuddy *buddy, PurpleStatus *old_status, PurpleStatus *status) { PurplePlugin *prpl; PurplePluginProtocolInfo *prpl_info = NULL; char *sip_from = find_sip_user(buddy->name); int d = hashtable_get_counter(buddy->name); PurpleStatusPrimitive primitive; enum purple_publish_basic basic; enum purple_publish_activity activity; char *statustext = NULL, *tmp = NULL, *new; const char *end; LM_DBG("buddy <%s> has changed status\n", buddy->name); if ((sip_from) && (d>0)) { primitive = purple_status_type_get_primitive(purple_status_get_type(status)); primitive_parse(primitive, &basic, &activity); // char *note = purple_status_get_attr_string(status, "message"); prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account)); if (prpl != NULL) prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); if (prpl_info && prpl_info->status_text && buddy->account->gc) { tmp = prpl_info->status_text(buddy); if(tmp && !g_utf8_validate(tmp, -1, &end)) { new = g_strndup(tmp, g_utf8_pointer_to_offset(tmp, end)); g_free(tmp); tmp = new; }
static void thunar_text_renderer_grab_focus (GtkWidget *entry, ThunarTextRenderer *text_renderer) { const gchar *text; const gchar *dot; glong offset; /* determine the text from the entry widget */ text = gtk_entry_get_text (GTK_ENTRY (entry)); /* lookup the last dot in the text */ dot = strrchr (text, '.'); if (G_LIKELY (dot != NULL)) { /* determine the UTF-8 char offset */ offset = g_utf8_pointer_to_offset (text, dot); /* select the text prior to the dot */ if (G_LIKELY (offset > 0)) gtk_entry_select_region (GTK_ENTRY (entry), 0, offset); } /* disconnect the grab-focus handler, so we change the selection only once */ g_signal_handlers_disconnect_by_func (G_OBJECT (entry), thunar_text_renderer_grab_focus, text_renderer); }
/* Search regular expression in text, return TRUE and matching part as start and * end integer position */ static gboolean search_regex_in_text (const gchar* search_entry, const gchar* editor_text, gboolean search_forward, gint * start_pos, gint * end_pos) { GRegex * regex; GMatchInfo *match_info; gboolean found; GError * err = NULL; regex = g_regex_new (search_entry, 0, 0, &err); if (err) { g_message ("%s",err->message); g_error_free (err); g_regex_unref(regex); return FALSE; } found = g_regex_match (regex, editor_text, 0, &match_info); if (found) { if (search_forward) g_match_info_fetch_pos(match_info, 0, start_pos, end_pos); else { do { g_match_info_fetch_pos(match_info, 0, start_pos, end_pos); } while (g_match_info_next(match_info, NULL)); } *start_pos = g_utf8_pointer_to_offset(editor_text, &editor_text[*start_pos]); *end_pos = g_utf8_pointer_to_offset(editor_text, &editor_text[*end_pos]); } if (regex) g_regex_unref(regex); if (match_info) g_match_info_free (match_info); return found; }
static gint gtk_label_accessible_get_offset_at_point (AtkText *atk_text, gint x, gint y, AtkCoordType coords) { GtkWidget *widget; GtkLabel *label; const gchar *text; gint index, x_layout, y_layout; gint x_window, y_window; gint x_local, y_local; GdkWindow *window; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text)); if (widget == NULL) return -1; label = GTK_LABEL (widget); gtk_label_get_layout_offsets (label, &x_layout, &y_layout); window = gtk_widget_get_window (widget); gdk_window_get_origin (window, &x_window, &y_window); x_local = x - x_layout - x_window; y_local = y - y_layout - y_window; if (coords == ATK_XY_WINDOW) { window = gdk_window_get_toplevel (window); gdk_window_get_origin (window, &x_window, &y_window); x_local += x_window; y_local += y_window; } if (!pango_layout_xy_to_index (gtk_label_get_layout (label), x_local * PANGO_SCALE, y_local * PANGO_SCALE, &index, NULL)) { if (x_local < 0 || y_local < 0) index = 0; else index = -1; } if (index != -1) { text = gtk_label_get_text (label); return g_utf8_pointer_to_offset (text, text + index); } return -1; }
static int string_rindex(struct objlist *obj,N_VALUE *inst,N_VALUE *rval,int argc,char **argv) { int pos, size, len; char *str, *pattern, *ptr, *find; rval->i = -1; pattern = (char *) argv[2]; pos = * (int *) argv[3]; if (pattern == NULL || pattern[0] == '\0') { return 1; } if (_getobj(obj, "length", inst, &size)) { return 2; } if (! g_utf8_validate(pattern, -1, NULL)) { error(obj, ERR_INVALID_UTF8); return 2; } if (pos < 0) { pos += size; } if (pos < 0 || pos >= size) { return 1; } if (_getobj(obj, "@", inst, &str)) { return 1; } if(str == NULL || str[0] == '\0') { return 1; } ptr = g_utf8_offset_to_pointer(str, pos); len = ptr - str + 1; if (len < 1) { return 1; } find = g_strrstr_len(str, len, pattern); if (find == NULL) { return 1; } rval->i = g_utf8_pointer_to_offset(str, find); return 0; }
static gint gail_text_cell_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords) { AtkObject *parent; GailRendererCell *gail_renderer; GtkCellRendererText *gtk_renderer; GtkWidget *widget; GdkRectangle rendered_rect; PangoLayout *layout; gint x_offset, y_offset, index; if (!GAIL_TEXT_CELL (text)->cell_text) return -1; gail_renderer = GAIL_RENDERER_CELL (text); gtk_renderer = GTK_CELL_RENDERER_TEXT (gail_renderer->renderer); parent = atk_object_get_parent (ATK_OBJECT (text)); g_return_val_if_fail (gtk_renderer->text, -1); if (GAIL_IS_CONTAINER_CELL (parent)) parent = atk_object_get_parent (parent); widget = GTK_ACCESSIBLE (parent)->widget; g_return_val_if_fail (GAIL_IS_CELL_PARENT (parent), -1); gail_cell_parent_get_cell_area (GAIL_CELL_PARENT (parent), GAIL_CELL (text), &rendered_rect); gtk_cell_renderer_get_size (GTK_CELL_RENDERER (gtk_renderer), widget, &rendered_rect, &x_offset, &y_offset, NULL, NULL); layout = create_pango_layout (gtk_renderer, widget); index = gail_misc_get_index_at_point_in_layout (widget, layout, x_offset + rendered_rect.x + gail_renderer->renderer->xpad, y_offset + rendered_rect.y + gail_renderer->renderer->ypad, x, y, coords); g_object_unref (layout); if (index == -1) { if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN) return g_utf8_strlen (gtk_renderer->text, -1); return index; } else return g_utf8_pointer_to_offset (gtk_renderer->text, gtk_renderer->text + index); }
/** * Retrieve a possible address (or a part) from an entry box. To make life * easier, we only look at the last valid address component; address * completion only works at the last string component in the entry box. * * \param entry Address entry field. * \param start_pos Address of start position of address. * \return Possible address. */ static gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos) { const gchar *edit_text, *p; gint cur_pos; gboolean in_quote = FALSE; gboolean in_bracket = FALSE; gchar *str; edit_text = gtk_entry_get_text(entry); if (edit_text == NULL) return NULL; cur_pos = gtk_editable_get_position(GTK_EDITABLE(entry)); /* scan for a separator. doesn't matter if walk points at null byte. */ for (p = g_utf8_offset_to_pointer(edit_text, cur_pos); p > edit_text; p = g_utf8_prev_char(p)) { if (*p == '"') { in_quote = TRUE; } else if (!in_quote) { if (!in_bracket && *p == ',') { break; } else if (*p == '<') in_bracket = TRUE; else if (*p == '>') in_bracket = FALSE; } } /* have something valid */ if (g_utf8_strlen(p, -1) == 0) return NULL; #define IS_VALID_CHAR(x) \ (g_ascii_isalnum(x) || (x) == '"' || (x) == '<' || (((unsigned char)(x)) > 0x7f)) /* now scan back until we hit a valid character */ for (; *p && !IS_VALID_CHAR(*p); p = g_utf8_next_char(p)) ; #undef IS_VALID_CHAR if (g_utf8_strlen(p, -1) == 0) return NULL; if (start_pos) *start_pos = g_utf8_pointer_to_offset(edit_text, p); str = g_strdup(p); return str; }
static gint gtk_icon_view_item_accessible_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coord_type) { GtkIconViewItemAccessible *item; gint offset = 0; #if 0 GtkIconView *icon_view; const gchar *item_text; gint index; gint l_x, l_y; #endif item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text); if (!GTK_IS_ICON_VIEW (item->widget)) return -1; if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT)) return -1; #if 0 icon_view = GTK_ICON_VIEW (item->widget); /* FIXME we probably have to use GailTextCell to salvage this */ gtk_icon_view_update_item_text (icon_view, item->item); atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type); x -= l_x + item->item->layout_x - item->item->x; x += ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2, y -= l_y + item->item->layout_y - item->item->y; item_text = pango_layout_get_text (icon_view->priv->layout); if (!pango_layout_xy_to_index (icon_view->priv->layout, x * PANGO_SCALE, y * PANGO_SCALE, &index, NULL)) { if (x < 0 || y < 0) index = 0; else index = -1; } if (index == -1) offset = g_utf8_strlen (item_text, -1); else offset = g_utf8_pointer_to_offset (item_text, item_text + index); #endif return offset; }
/* Search string in text, return TRUE and matching part as start and * end integer position */ static gboolean search_str_in_text (const gchar* search_entry, const gchar* editor_text, gboolean case_sensitive, gint * start_pos, gint * end_pos) { gboolean found; if (strlen (editor_text) >= strlen (search_entry)) { gchar* selected_text_case; gchar* search_text_case; if (case_sensitive) { selected_text_case = g_strdup (editor_text); search_text_case = g_strdup (search_entry); } else { selected_text_case = g_utf8_casefold (editor_text, strlen (editor_text)); search_text_case = g_utf8_casefold (search_entry, strlen (search_entry)); } gchar* strstr = g_strstr_len (selected_text_case, -1, search_text_case); if (strstr) { *start_pos = g_utf8_pointer_to_offset(selected_text_case, strstr); *end_pos = g_utf8_pointer_to_offset(selected_text_case, strstr + strlen (search_entry)); found = TRUE; } g_free (selected_text_case); g_free (search_text_case); } return found; }
static gboolean midorator_entry_key_press_event_cb (MidoratorEntry* e, GdkEventKey* event) { if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_a) { gtk_editable_set_position(GTK_EDITABLE(e), 0); } else if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_e) { gtk_editable_set_position(GTK_EDITABLE(e), -1); } else if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_f) { gtk_editable_set_position(GTK_EDITABLE(e), gtk_editable_get_position(GTK_EDITABLE(e)) + 1); } else if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_b) { gtk_editable_set_position(GTK_EDITABLE(e), gtk_editable_get_position(GTK_EDITABLE(e)) - 1); } else if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_p) { gtk_editable_set_position(GTK_EDITABLE(e), 0); midorator_entry_history_up(e); } else if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_n) { gtk_editable_set_position(GTK_EDITABLE(e), 0); midorator_entry_history_down(e); } else if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_w) { const char *t = gtk_entry_get_text(GTK_ENTRY(e)); int pos = gtk_editable_get_position(GTK_EDITABLE(e)); char *i; for (i = g_utf8_offset_to_pointer(t, pos) - 1; i >= t && *i == ' '; i--); for (; i >= t && *i != ' '; i--); i++; int newpos = g_utf8_pointer_to_offset(t, i); gtk_editable_delete_text(GTK_EDITABLE(e), newpos, pos); gtk_editable_set_position(GTK_EDITABLE(e), newpos); } else if (event->keyval == GDK_Escape) { g_signal_emit(e, signals[SIG_CANCEL], 0); } else if (event->keyval == GDK_Tab) { midorator_entry_perform_completion(e); } else if (event->keyval == GDK_Up) { midorator_entry_history_up(e); } else if (event->keyval == GDK_Down) { midorator_entry_history_down(e); } else if (event->keyval == GDK_Page_Up) { gtk_editable_set_position(GTK_EDITABLE(e), 0); midorator_entry_history_up(e); } else if (event->keyval == GDK_Page_Down) { gtk_editable_set_position(GTK_EDITABLE(e), 0); midorator_entry_history_down(e); } else if (event->keyval == GDK_Return) { char *t = g_strdup(gtk_entry_get_text(GTK_ENTRY(e))); g_signal_emit(e, signals[SIG_EXECUTE], 0, t); midorator_entry_history_add(e, t); g_free(t); } else return false; return true; }
/* stolen from gtkfilechooserentry.c */ static gboolean entry_select_filename_in_focus_cb (GtkWidget * entry, GdkEventFocus * event) { const gchar *str, *ext; glong len = -1; str = gtk_entry_get_text (GTK_ENTRY (entry)); ext = g_strrstr (str, "."); if (ext) len = g_utf8_pointer_to_offset (str, ext); gtk_editable_select_region (GTK_EDITABLE (entry), 0, (gint) len); (void) event; return TRUE; }
int Font::offsetForPositionForComplexText(const TextRun& run, const TextStyle& style, int x, bool includePartialGlyphs) const { PangoLayout* layout = getDefaultPangoLayout(run); setPangoAttributes(this, run, layout, style.rtl()); gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); pango_layout_set_text(layout, utf8, -1); int index, trailing; pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing); glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index); g_object_unref(layout); g_free(utf8); return offset; }
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str) { unichar chr; int i, len; const char *ptr; g_return_if_fail(entry != NULL); g_return_if_fail(str != NULL); gui_entry_redraw_from(entry, entry->pos); if (entry->utf8) { g_utf8_validate(str, -1, &ptr); len = g_utf8_pointer_to_offset(str, ptr); } else if (term_type == TERM_TYPE_BIG5) len = strlen_big5((const unsigned char *)str); else len = strlen(str); entry_text_grow(entry, len); /* make space for the string */ g_memmove(entry->text + entry->pos + len, entry->text + entry->pos, (entry->text_len-entry->pos + 1) * sizeof(unichar)); if (!entry->utf8) { if (term_type == TERM_TYPE_BIG5) { chr = entry->text[entry->pos + len]; big5_to_unichars(str, entry->text + entry->pos); entry->text[entry->pos + len] = chr; } else { for (i = 0; i < len; i++) entry->text[entry->pos + i] = str[i]; } } else { ptr = str; for (i = 0; i < len; i++) { entry->text[entry->pos + i] = g_utf8_get_char(ptr); ptr = g_utf8_next_char(ptr); } } entry->text_len += len; entry->pos += len; gui_entry_fix_cursor(entry); gui_entry_draw(entry); }
/** * g_utf8_pointer_to_offset: * @str: a UTF-8 encoded string * @pos: a pointer to a position within @str * * Converts from a pointer to position within a string to a integer * character offset. * * Since 2.10, this function allows @pos to be before @str, and returns * a negative offset in this case. * * Return value: the resulting character offset **/ glong g_utf8_pointer_to_offset (const gchar *str, const gchar *pos) { const gchar *s = str; glong offset = 0; if (pos < str) offset = - g_utf8_pointer_to_offset (pos, str); else while (s < pos) { s = g_utf8_next_char (s); offset++; } return offset; }
static void FcitxThaiGetPrevCell(FcitxThai* thai, struct thcell_t* res) { th_init_cell(res); if (is_client_support_surrounding(IBUS_ENGINE(libthai_engine))) { IBusText* surrounding; guint cursor_pos; guint anchor_pos; const gchar* s; gchar* tis_text = NULL; ibus_engine_get_surrounding_text(IBUS_ENGINE(libthai_engine), &surrounding, &cursor_pos, &anchor_pos); s = ibus_text_get_text(surrounding); cursor_pos = g_utf8_offset_to_pointer(s, cursor_pos) - s; while (*s) { const gchar* t; tis_text = g_convert(s, cursor_pos, "TIS-620", "UTF-8", NULL, NULL, NULL); if (tis_text) break; t = g_utf8_next_char(s); cursor_pos -= (t - s); s = t; } if (tis_text) { gint char_index; char_index = g_utf8_pointer_to_offset(s, s + cursor_pos); th_prev_cell((thchar_t*) tis_text, char_index, res, TRUE); g_free(tis_text); } } else { /* retrieve from the fallback buffer */ th_prev_cell(libthai_engine->char_buff, libthai_engine->buff_tail, res, TRUE); } }