diff options
author | Owen Taylor <owt1@cornell.edu> | 1998-03-22 21:31:10 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 1998-03-22 21:31:10 +0000 |
commit | 16aa9c196416f6bbb60e22f06f62cae8ab4b0196 (patch) | |
tree | fa112252cd622b7ca926ae704d7fce65359b76af | |
parent | ac05ab301ddc3590ca55b7dec8c2ac472cedc55d (diff) | |
download | gdk-pixbuf-16aa9c196416f6bbb60e22f06f62cae8ab4b0196.tar.gz |
fixes to locale checks
Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu>
* gtk/gtkmain.c (gtk_init): fixes to locale checks
* gtk/testgtk.c (create_dnd): Create the dnd icons separately
to avoid strange interactions with shapes demo.
* gtk/gtkentry.[ch]:
- Limit the length of the text to 2048 to prevent long delays
- Fix problems with buffer overruns
- Draw only the onscreen portion of the text to prevent wrapping
of shorts in the X drawing code.
- Keep track of character positions and x-offsets to speed
up algorithms.
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 15 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 15 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 15 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 15 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 15 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 15 | ||||
-rw-r--r-- | INSTALL | 29 | ||||
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | gdk/gdk.c | 3 | ||||
-rw-r--r-- | gdk/x11/gdkmain-x11.c | 3 | ||||
-rw-r--r-- | gtk/gtkentry.c | 414 | ||||
-rw-r--r-- | gtk/gtkentry.h | 13 | ||||
-rw-r--r-- | gtk/gtkmain.c | 6 | ||||
-rw-r--r-- | gtk/testgtk.c | 53 | ||||
-rw-r--r-- | tests/testgtk.c | 53 |
16 files changed, 529 insertions, 155 deletions
@@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 07a06f552..2e2d75963 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 07a06f552..2e2d75963 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 07a06f552..2e2d75963 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 07a06f552..2e2d75963 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 07a06f552..2e2d75963 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 07a06f552..2e2d75963 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,18 @@ +Sun Mar 22 16:25:46 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkmain.c (gtk_init): fixes to locale checks + + * gtk/testgtk.c (create_dnd): Create the dnd icons separately + to avoid strange interactions with shapes demo. + + * gtk/gtkentry.[ch]: + - Limit the length of the text to 2048 to prevent long delays + - Fix problems with buffer overruns + - Draw only the onscreen portion of the text to prevent wrapping + of shorts in the X drawing code. + - Keep track of character positions and x-offsets to speed + up algorithms. + Sun Mar 22 11:37:51 CST 1998 Shawn T. Amundson <amundson@gtk.org> * gtk/gtkcolorsel.c: @@ -26,11 +26,34 @@ for which your operating system has the worst support for the --with-locale option. -Note for using XIM support with kinput2 ---------------------------------------- +Notes for using XIM support for Japanese input +---------------------------------------------- -There is a bug in older versions of kinput2 that will cause +* There is a bug in older versions of kinput2 that will cause GTK to hang when destroying a text entry. The latest versions of kinput is available from: ftp://ftp.sra.co.jp/pub/x11/kinput2 + +* The locale information file for the ja_JP EUC locale +distributed with some recent versions of X11 specifies to +use the C library multibyte functions. Unless your C library +has support for Japanese locales, this is incorrect, and +will cause problems for GTK's internationalization. + +(In particular, this occurs with GNU libc 2.0 and 2.1, in which the +multibyte functions always translate to and from UTF-8; but the +problem may occur for other C libraries, and other operating systems +as well.) + +To fix this, change the line: + +use_stdc_env True + +to + +use_stdc_env False + +in the file /usr/X11R6/lib/X11/locale/ja_JP/XLC_LOCALE. + + @@ -2,9 +2,6 @@ TODO BEFORE GTK 1.0 ------------------- Bugs: - * pasting into a GtkEntry that already has a very long string, - causes the app to hang. - * scrolled windows get cought in an endless reallocation loop under certain (rare) circumstances. @@ -51,7 +48,7 @@ Bugs: * Change bitfields to guints from enums for C++ ? - * Force paned window handle to be kept on screen + * Expose events aren't being generated correctly for DND demo Additions: * GScanner: it might be good to ues stdio and getch() instead of 1-character @@ -3842,6 +3842,9 @@ _g_mbtowc (wchar_t *wstr, const char *str, size_t len) wcs[0] = (wchar_t) NULL; mbs[0] = '\0'; + /* The last argument isn't a mistake. The X locale code trims + * the input string to the length of the output string! + */ len = _Xmbstowcs (wcs, str, (len<MB_CUR_MAX)? len:MB_CUR_MAX); if (len < 1) return len; diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index 936787fa0..14ebfa4e9 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -3842,6 +3842,9 @@ _g_mbtowc (wchar_t *wstr, const char *str, size_t len) wcs[0] = (wchar_t) NULL; mbs[0] = '\0'; + /* The last argument isn't a mistake. The X locale code trims + * the input string to the length of the output string! + */ len = _Xmbstowcs (wcs, str, (len<MB_CUR_MAX)? len:MB_CUR_MAX); if (len < 1) return len; diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 8ee04da48..4435075e4 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -85,7 +85,6 @@ static gchar *gtk_entry_get_chars (GtkEditable *editable, gint start_pos, gint end_pos); -static gint move_backward_character (gchar *str, gint index); static void gtk_move_forward_character (GtkEntry *entry); static void gtk_move_backward_character (GtkEntry *entry); static void gtk_move_forward_word (GtkEntry *entry); @@ -108,6 +107,12 @@ static void gtk_entry_set_selection (GtkEditable *editable, gint start, gint end); +static void gtk_entry_recompute_offsets (GtkEntry *entry); +static gint gtk_entry_find_char (GtkEntry *entry, + gint position); +static gint gtk_entry_find_position (GtkEntry *entry, + gint position); + static GtkWidgetClass *parent_class = NULL; static GdkAtom ctext_atom = GDK_NONE; @@ -250,6 +255,10 @@ gtk_entry_init (GtkEntry *entry) entry->button = 0; entry->visible = 1; + entry->nchars = 0; + entry->char_pos = NULL; + entry->char_offset = NULL; + gtk_entry_grow_text (entry); } @@ -393,6 +402,10 @@ gtk_entry_finalize (GtkObject *object) entry->text_size = 0; if (entry->text) g_free (entry->text); + if (entry->char_pos) + g_free (entry->char_pos); + if (entry->char_offset) + g_free (entry->char_offset); entry->text = NULL; if (entry->backing_pixmap) @@ -526,6 +539,8 @@ gtk_entry_realize (GtkWidget *widget) if (editable->selection_start_pos != editable->selection_end_pos) gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); + + gtk_entry_recompute_offsets (entry); } static void @@ -1112,6 +1127,10 @@ gtk_entry_draw_text (GtkEntry *entry) GtkWidget *widget; GtkEditable *editable; GtkStateType selected_state; + gint start_char; + gint start_pos; + gint end_pos; + gint start_xoffset; gint selection_start_pos; gint selection_end_pos; gint selection_start_xoffset; @@ -1177,59 +1196,64 @@ gtk_entry_draw_text (GtkEntry *entry) y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2; y += widget->style->font->ascent; - if (editable->selection_start_pos != editable->selection_end_pos) - { - selected_state = GTK_STATE_SELECTED; - if (!editable->has_selection) - selected_state = GTK_STATE_ACTIVE; - - selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); - selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); - - selection_start_xoffset = gdk_text_width (widget->style->font, - entry->text, - selection_start_pos); - selection_end_xoffset = gdk_text_width (widget->style->font, - entry->text, - selection_end_pos); - - if (selection_start_pos > 0) - gdk_draw_text (drawable, widget->style->font, - widget->style->fg_gc[GTK_STATE_NORMAL], - -entry->scroll_offset, y, - entry->text, selection_start_pos); + start_char = gtk_entry_find_position (entry, entry->scroll_offset); + start_pos = entry->char_pos[start_char]; + start_xoffset = entry->char_offset[start_char] - entry->scroll_offset; + end_pos = gtk_entry_position (entry, entry->scroll_offset + width); + if (end_pos < entry->text_length) + end_pos += 1; + + selected_state = GTK_STATE_SELECTED; + if (!editable->has_selection) + selected_state = GTK_STATE_ACTIVE; + + selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); + selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); + + selection_start_pos = CLAMP (selection_start_pos, start_pos, end_pos); + selection_end_pos = CLAMP (selection_end_pos, start_pos, end_pos); + + selection_start_xoffset = + entry->char_offset[gtk_entry_find_char(entry,selection_start_pos)] - + entry->scroll_offset; + selection_end_xoffset = + entry->char_offset[gtk_entry_find_char(entry,selection_end_pos)] - + entry->scroll_offset; + + if (selection_start_pos > start_pos) + gdk_draw_text (drawable, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + start_xoffset, y, + entry->text + start_pos, + selection_start_pos - start_pos); + + if ((selection_end_pos >= start_pos) && + (selection_start_pos < end_pos) && + (selection_start_pos != selection_end_pos)) + { gdk_draw_rectangle (drawable, widget->style->bg_gc[selected_state], TRUE, - -entry->scroll_offset + selection_start_xoffset, + selection_start_xoffset, 0, selection_end_xoffset - selection_start_xoffset, -1); - + gdk_draw_text (drawable, widget->style->font, widget->style->fg_gc[selected_state], - -entry->scroll_offset + selection_start_xoffset, y, + selection_start_xoffset, y, entry->text + selection_start_pos, selection_end_pos - selection_start_pos); - - if (selection_end_pos < entry->text_length) - gdk_draw_string (drawable, widget->style->font, - widget->style->fg_gc[GTK_STATE_NORMAL], - -entry->scroll_offset + selection_end_xoffset, y, - entry->text + selection_end_pos); - } - else - { - GdkGCValues values; - - gdk_gc_get_values (widget->style->fg_gc[GTK_STATE_NORMAL], &values); - gdk_draw_string (drawable, widget->style->font, - widget->style->fg_gc[GTK_STATE_NORMAL], - -entry->scroll_offset, y, - entry->text); - } - + } + + if (selection_end_pos < end_pos) + gdk_draw_text (drawable, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + selection_end_xoffset, y, + entry->text + selection_end_pos, + end_pos - selection_end_pos); + if (editable->editable) gtk_entry_draw_cursor_on_drawable (entry, drawable); @@ -1267,8 +1291,8 @@ gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable) widget = GTK_WIDGET (entry); editable = GTK_EDITABLE (entry); - if (editable->current_pos > 0 && entry->visible) - xoffset = gdk_text_width (widget->style->font, entry->text, editable->current_pos); + if (entry->visible) + xoffset = entry->char_offset[gtk_entry_find_char (entry, editable->current_pos)]; else xoffset = 0; xoffset -= entry->scroll_offset; @@ -1320,41 +1344,39 @@ gtk_entry_timer (gpointer data) } static gint -gtk_entry_position (GtkEntry *entry, - gint x) +gtk_entry_find_position (GtkEntry *entry, + gint x) { - gint return_val; - gint char_width; - gint sum; - gint i; - gint len; - - g_return_val_if_fail (entry != NULL, 0); - g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); - - i = 0; - sum = 0; + gint start = 0; + gint end = entry->nchars; + gint half; + + if (x >= entry->char_offset[end]) + return end; + if (x < 0) + return 0; + + /* invariant - char_pos[start] <= x < char_pos[end] */ - if (x > sum) + while (start != end) { - for (; i < entry->text_length; i+=len) - { - len = mblen (entry->text+i, MB_CUR_MAX); - /* character not supported in current locale is included */ - if (len < 1) - len = 1; - char_width = gdk_text_width (GTK_WIDGET (entry)->style->font, - entry->text + i, len); - - if (x < (sum + char_width / 2)) - break; - sum += char_width; - } + half = (start+end)/2; + if (half == start) + return half; + else if (entry->char_offset[half] <= x) + start = half; + else + end = half; } - return_val = i; + return start; +} - return return_val; +static gint +gtk_entry_position (GtkEntry *entry, + gint x) +{ + return entry->char_pos[gtk_entry_find_position(entry, x)]; } void @@ -1371,16 +1393,14 @@ gtk_entry_adjust_scroll (GtkEntry *entry) gdk_window_get_size (entry->text_area, &text_area_width, NULL); - if (GTK_EDITABLE(entry)->current_pos > 0) - xoffset = gdk_text_width (GTK_WIDGET (entry)->style->font, entry->text, GTK_EDITABLE(entry)->current_pos); - else - xoffset = 0; + xoffset = entry->char_offset[gtk_entry_find_char (entry, GTK_EDITABLE(entry)->current_pos)]; xoffset -= entry->scroll_offset; if (xoffset < 0) entry->scroll_offset += xoffset; + else if (xoffset > text_area_width) - entry->scroll_offset += (xoffset - text_area_width) + 1; + entry->scroll_offset += xoffset - text_area_width + 1; } static void @@ -1398,6 +1418,16 @@ gtk_entry_grow_text (GtkEntry *entry) else entry->text_size *= 2; entry->text = g_realloc (entry->text, entry->text_size); + entry->char_pos = g_realloc (entry->char_pos, + entry->text_size * sizeof(guint16)); + entry->char_offset = g_realloc (entry->char_offset, + entry->text_size * sizeof(guint)); + + if (entry->text_length == 0) /* initial allocation */ + { + entry->char_pos[0] = 0; + entry->char_offset[0] = 0; + } for (i = previous_size; i < entry->text_size; i++) entry->text[i] = '\0'; @@ -1410,11 +1440,18 @@ gtk_entry_insert_text (GtkEditable *editable, gint *position) { gchar *text; + gint start_char; + gint end_char; gint start_pos; + gint last_char; gint end_pos; gint last_pos; + gint max_length; gint i; + gint insertion_chars; + guint16 *insertion_pos; + GtkEntry *entry; g_return_if_fail (editable != NULL); @@ -1424,17 +1461,51 @@ gtk_entry_insert_text (GtkEditable *editable, if (new_text_length < 0) new_text_length = strlen (new_text); + + /* The algorithms here will work as long as, the text size (a + * multiple of 2), fits into a guint16 but we specify a shorter + * maximum length so that if the user pastes a very long text, there + * is not a long hang from the slow X_LOCALE functions. */ + + if (entry->text_max_length == 0) + max_length = 2047; + else + max_length = MIN (2047, entry->text_max_length); /* Make sure we do not exceed the maximum size of the entry. */ - if (entry->text_max_length != 0 && - new_text_length + entry->text_length > entry->text_max_length) - new_text_length = entry->text_max_length - entry->text_length; + if (new_text_length + entry->text_length > max_length) + new_text_length = max_length - entry->text_length; /* Don't insert anything, if there was nothing to insert. */ if (new_text_length <= 0) return; - start_pos = *position; + /* Find the length of the inserted text in characters, chop off + partial/invalid characters */ + if (gtk_use_mb) + { + gint len = 0; + + insertion_pos = g_new (guint16, new_text_length+1); + insertion_chars = 0; + + for (i=0; i<new_text_length; i+=len) + { + len = mblen (&new_text[i], MIN(MB_CUR_MAX,new_text_length-i)); + if (len < 0) + break; + insertion_pos[insertion_chars] = i; + insertion_chars++; + } + insertion_pos[insertion_chars] = i; + + new_text_length = i; + } + + /* Make sure we are inserting at integral character position */ + start_char = gtk_entry_find_char (entry, *position); + start_pos = entry->char_pos[start_char]; + end_pos = start_pos + new_text_length; last_pos = new_text_length + entry->text_length; @@ -1452,12 +1523,109 @@ gtk_entry_insert_text (GtkEditable *editable, for (i = start_pos; i < end_pos; i++) text[i] = new_text[i - start_pos]; + if (gtk_use_mb) + { + /* Fix up the character positions */ + + end_char = start_char + insertion_chars; + last_char = entry->nchars + insertion_chars; + + for (i = last_char; i >= end_char; i--) + entry->char_pos[i] + = entry->char_pos[i - insertion_chars] + new_text_length; + + for (i = 1; i < insertion_chars ; i++) + entry->char_pos[start_char+i] = + entry->char_pos[start_char] + insertion_pos[i]; + + g_free (insertion_pos); + } + else + { + end_char = end_pos; + last_char = last_pos; + + for (i = end_char ; i <= last_char ; i++) + entry->char_pos[i] = i; + } + + /* Fix up the the character offsets */ + + if (GTK_WIDGET_REALIZED (entry)) + { + gint offset = 0; + + for (i = last_char; i >= end_char; i--) + entry->char_offset[i] + = entry->char_offset[i - insertion_chars]; + + for (i=start_char; i<end_char; i++) + { + entry->char_offset[i] = entry->char_offset[start_char] + offset; + offset += gdk_text_width (GTK_WIDGET (entry)->style->font, + entry->text + entry->char_pos[i], + entry->char_pos[i+1] - entry->char_pos[i]); + } + for (i = end_char ; i <= last_char ; i++) + entry->char_offset[i] += offset; + } + entry->text_length += new_text_length; + entry->nchars += insertion_chars; *position = end_pos; gtk_entry_queue_draw (entry); } +/* Recompute the x offsets of all characters in the buffer */ +static void +gtk_entry_recompute_offsets (GtkEntry *entry) +{ + gint i; + gint offset = 0; + + for (i=0; i<entry->nchars; i++) + { + entry->char_offset[i] = offset; + offset += gdk_text_width (GTK_WIDGET (entry)->style->font, + entry->text + entry->char_pos[i], + entry->char_pos[i+1] - entry->char_pos[i]); + } + + entry->char_offset[i] = offset; +} + +/* Given a position in the entry, find the character index of the + * last character with position <= the given position + */ +static gint +gtk_entry_find_char (GtkEntry *entry, gint position) +{ + gint start = 0; + gint end = entry->nchars; + gint half; + + if (position >= entry->char_pos[end]) + return end; + if (position < 0) + return 0; + + /* invariant - char_pos[start] <= position < char_pos[end] */ + + while (start != end) + { + half = (start+end)/2; + if (half == start) + return half; + else if (entry->char_pos[half] <= position) + start = half; + else + end = half; + } + + return start; +} + static void gtk_entry_delete_text (GtkEditable *editable, gint start_pos, @@ -1465,6 +1633,8 @@ gtk_entry_delete_text (GtkEditable *editable, { gchar *text; gint deletion_length; + gint start_char; + gint end_char; gint i; GtkEntry *entry; @@ -1474,14 +1644,19 @@ gtk_entry_delete_text (GtkEditable *editable, entry = GTK_ENTRY (editable); + if (end_pos < 0) + end_pos = entry->text_length; + + start_char = gtk_entry_find_char (entry, start_pos); + end_char = gtk_entry_find_char (entry, end_pos); + start_pos = entry->char_pos[start_char]; + end_pos = entry->char_pos[end_char]; + if (editable->selection_start_pos > start_pos) editable->selection_start_pos -= MIN(end_pos, editable->selection_start_pos) - start_pos; if (editable->selection_end_pos > start_pos) editable->selection_end_pos -= MIN(end_pos, editable->selection_end_pos) - start_pos; - - if (end_pos < 0) - end_pos = entry->text_length; - + if ((start_pos < end_pos) && (start_pos >= 0) && (end_pos <= entry->text_length)) @@ -1489,12 +1664,27 @@ gtk_entry_delete_text (GtkEditable *editable, text = entry->text; deletion_length = end_pos - start_pos; + /* Fix up the character offsets */ + if (GTK_WIDGET_REALIZED (entry)) + { + gint deletion_width = + entry->char_offset[end_char] - entry->char_offset[start_char]; + + for (i = 0 ; i <= entry->nchars - end_char; i++) + entry->char_offset[start_char+i] = entry->char_offset[end_char+i] - deletion_width; + } + for (i = end_pos; i < entry->text_length; i++) text[i - deletion_length] = text[i]; for (i = entry->text_length - deletion_length; i < entry->text_length; i++) text[i] = '\0'; + for (i = 0 ; i <= entry->nchars - end_char; i++) + entry->char_pos[start_char+i] = entry->char_pos[end_char+i] - deletion_length; + + entry->nchars -= end_char - start_char; + entry->text_length -= deletion_length; editable->current_pos = start_pos; } @@ -1570,23 +1760,6 @@ gtk_move_forward_character (GtkEntry *entry) } } -static gint -move_backward_character (gchar *str, gint index) -{ - gint i; - gint len; - - if (index <= 0) - return -1; - for (i=0,len=0; i<index; i+=len) - { - len = mblen (str+i, MB_CUR_MAX); - if (len<1) - return i; - } - return i-len; -} - static void gtk_move_backward_character (GtkEntry *entry) { @@ -1596,8 +1769,8 @@ gtk_move_backward_character (GtkEntry *entry) if (0 < editable->current_pos) { if (gtk_use_mb) - editable->current_pos = move_backward_character (entry->text, - editable->current_pos); + editable->current_pos = + entry->char_pos[gtk_entry_find_char (entry, editable->current_pos - 1)]; else editable->current_pos--; } @@ -1667,7 +1840,6 @@ gtk_move_backward_word (GtkEntry *entry) gchar *text; gint i; wchar_t c; - gint len; GtkEditable *editable; editable = GTK_EDITABLE (entry); @@ -1678,26 +1850,31 @@ gtk_move_backward_word (GtkEntry *entry) if (gtk_use_mb) { - i=move_backward_character(text, editable->current_pos); + i = gtk_entry_find_char (entry, editable->current_pos - 1); - len = mbtowc (&c, text+i, MB_CUR_MAX); + mbtowc (&c, text+entry->char_pos[i], MB_CUR_MAX); if (!iswalnum(c)) - for (; i >= 0; i=move_backward_character(text, i)) + for (; i >= 0; i--) { - len = mbtowc (&c, text+i, MB_CUR_MAX); + mbtowc (&c, text+entry->char_pos[i], MB_CUR_MAX); if (iswalnum(c)) break; } - for (; i >= 0; i=move_backward_character(text, i)) + for (; i >= 0; i--) { - len = mbtowc (&c, text+i, MB_CUR_MAX); + mbtowc (&c, text+entry->char_pos[i], MB_CUR_MAX); if (!iswalnum(c)) { - i += len; + i++; break; } } + + if (i < 0) + i = 0; + + editable->current_pos = entry->char_pos[i]; } else { @@ -1718,12 +1895,13 @@ gtk_move_backward_word (GtkEntry *entry) break; } } + + if (i < 0) + i = 0; + + editable->current_pos = i; } - if (i < 0) - i = 0; - - editable->current_pos = i; } } diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index e624def9d..43c895138 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -48,10 +48,21 @@ struct _GtkEntry guint16 text_size; guint16 text_length; guint16 text_max_length; - gint16 scroll_offset; + gint scroll_offset; guint visible : 1; guint32 timer; guint button; + + /* The total number of characters (not bytes) in the entry */ + guint nchars; + + /* The byte offset of each character + * (including the last insertion position) */ + guint16 *char_pos; + + /* The x-offset of each character (including the last insertion position) + * only valid when the widget is realized */ + gint *char_offset; }; struct _GtkEntryClass diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 84385a508..a2791ce9b 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -266,18 +266,18 @@ gtk_init (int *argc, */ current_locale = g_strdup(setlocale (LC_CTYPE, NULL)); - setlocale (LC_CTYPE, "C"); #ifdef X_LOCALE - if ((strcmp (current_locale, "C")) && (!strcmp (current_locale, "POSIX"))) + if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX"))) gtk_use_mb = TRUE; else #endif { + setlocale (LC_CTYPE, "C"); gtk_use_mb = (mblen ("\xc0", MB_CUR_MAX) == 1); + setlocale (LC_CTYPE, current_locale); } - setlocale (LC_CTYPE, current_locale); g_free (current_locale); GTK_NOTE(MISC, g_print("%s multi-byte string functions.\n", diff --git a/gtk/testgtk.c b/gtk/testgtk.c index 1caded069..3d6bd8f14 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -23,12 +23,12 @@ #include "circles.xbm" -/* Variables used by the Drag/Drop and Shape Window demos */ -static GtkWidget *modeller = NULL; -static GtkWidget *sheets = NULL; -static GtkWidget *rings = NULL; -void create_shapes(void); - +GtkWidget *shape_create_icon (char *xpm_file, + gint x, + gint y, + gint px, + gint py, + gint window_type); /* macro, structure and variables used by tree window demos */ #define DEFAULT_NUMBER_OF_ITEM 3 @@ -4264,16 +4264,40 @@ create_dnd () char *possible_drag_types[] = {"text/plain"}; char *accepted_drop_types[] = {"text/plain"}; - if(!modeller) - create_shapes(); + static GtkWidget *drag_icon = NULL; + static GtkWidget *drop_icon = NULL; if (!window) { GdkPoint hotspot = {5,5}; - gdk_dnd_set_drag_shape(modeller->window, + if (!drag_icon) + { + drag_icon = shape_create_icon ("Modeller.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &drag_icon); + + gtk_widget_hide (drag_icon); + } + + if (!drop_icon) + { + drop_icon = shape_create_icon ("3DRings.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &drop_icon); + + gtk_widget_hide (drop_icon); + } + + gdk_dnd_set_drag_shape(drag_icon->window, &hotspot, - rings->window, + drop_icon->window, &hotspot); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); @@ -4372,8 +4396,6 @@ create_dnd () gtk_widget_show (button); } - gtk_widget_hide(modeller); gtk_widget_hide(rings); - if (!GTK_WIDGET_VISIBLE (window)) gtk_widget_show (window); else @@ -4494,13 +4516,18 @@ shape_create_icon (char *xpm_file, gtk_widget_set_uposition (window, x, y); gtk_widget_show (window); - + return window; } void create_shapes () { + /* Variables used by the Drag/Drop and Shape Window demos */ + static GtkWidget *modeller = NULL; + static GtkWidget *sheets = NULL; + static GtkWidget *rings = NULL; + root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ()); if (!modeller) diff --git a/tests/testgtk.c b/tests/testgtk.c index 1caded069..3d6bd8f14 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -23,12 +23,12 @@ #include "circles.xbm" -/* Variables used by the Drag/Drop and Shape Window demos */ -static GtkWidget *modeller = NULL; -static GtkWidget *sheets = NULL; -static GtkWidget *rings = NULL; -void create_shapes(void); - +GtkWidget *shape_create_icon (char *xpm_file, + gint x, + gint y, + gint px, + gint py, + gint window_type); /* macro, structure and variables used by tree window demos */ #define DEFAULT_NUMBER_OF_ITEM 3 @@ -4264,16 +4264,40 @@ create_dnd () char *possible_drag_types[] = {"text/plain"}; char *accepted_drop_types[] = {"text/plain"}; - if(!modeller) - create_shapes(); + static GtkWidget *drag_icon = NULL; + static GtkWidget *drop_icon = NULL; if (!window) { GdkPoint hotspot = {5,5}; - gdk_dnd_set_drag_shape(modeller->window, + if (!drag_icon) + { + drag_icon = shape_create_icon ("Modeller.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &drag_icon); + + gtk_widget_hide (drag_icon); + } + + if (!drop_icon) + { + drop_icon = shape_create_icon ("3DRings.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &drop_icon); + + gtk_widget_hide (drop_icon); + } + + gdk_dnd_set_drag_shape(drag_icon->window, &hotspot, - rings->window, + drop_icon->window, &hotspot); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); @@ -4372,8 +4396,6 @@ create_dnd () gtk_widget_show (button); } - gtk_widget_hide(modeller); gtk_widget_hide(rings); - if (!GTK_WIDGET_VISIBLE (window)) gtk_widget_show (window); else @@ -4494,13 +4516,18 @@ shape_create_icon (char *xpm_file, gtk_widget_set_uposition (window, x, y); gtk_widget_show (window); - + return window; } void create_shapes () { + /* Variables used by the Drag/Drop and Shape Window demos */ + static GtkWidget *modeller = NULL; + static GtkWidget *sheets = NULL; + static GtkWidget *rings = NULL; + root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ()); if (!modeller) |