summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <owt1@cornell.edu>1998-03-22 21:31:10 +0000
committerOwen Taylor <otaylor@src.gnome.org>1998-03-22 21:31:10 +0000
commit16aa9c196416f6bbb60e22f06f62cae8ab4b0196 (patch)
treefa112252cd622b7ca926ae704d7fce65359b76af
parentac05ab301ddc3590ca55b7dec8c2ac472cedc55d (diff)
downloadgdk-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--ChangeLog15
-rw-r--r--ChangeLog.pre-2-015
-rw-r--r--ChangeLog.pre-2-1015
-rw-r--r--ChangeLog.pre-2-215
-rw-r--r--ChangeLog.pre-2-415
-rw-r--r--ChangeLog.pre-2-615
-rw-r--r--ChangeLog.pre-2-815
-rw-r--r--INSTALL29
-rw-r--r--TODO5
-rw-r--r--gdk/gdk.c3
-rw-r--r--gdk/x11/gdkmain-x11.c3
-rw-r--r--gtk/gtkentry.c414
-rw-r--r--gtk/gtkentry.h13
-rw-r--r--gtk/gtkmain.c6
-rw-r--r--gtk/testgtk.c53
-rw-r--r--tests/testgtk.c53
16 files changed, 529 insertions, 155 deletions
diff --git a/ChangeLog b/ChangeLog
index 07a06f552..2e2d75963 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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:
diff --git a/INSTALL b/INSTALL
index 4fecd0a21..cfacfc08f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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.
+
+
diff --git a/TODO b/TODO
index d960dbd6c..1e84fd4ee 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/gdk/gdk.c b/gdk/gdk.c
index 936787fa0..14ebfa4e9 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.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/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)