diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 22 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 22 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 22 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 22 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 22 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 22 | ||||
-rw-r--r-- | TODO | 31 | ||||
-rw-r--r-- | gtk/Makefile.am | 5 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkeditable.c | 664 | ||||
-rw-r--r-- | gtk/gtkeditable.h | 112 | ||||
-rw-r--r-- | gtk/gtkentry.c | 904 | ||||
-rw-r--r-- | gtk/gtkentry.h | 29 | ||||
-rw-r--r-- | gtk/gtkfilesel.c | 4 | ||||
-rw-r--r-- | gtk/gtkspinbutton.c | 24 | ||||
-rw-r--r-- | gtk/gtktext.c | 920 | ||||
-rw-r--r-- | gtk/gtktext.h | 34 |
18 files changed, 1971 insertions, 911 deletions
@@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 45c6e743a..a750a31ca 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 45c6e743a..a750a31ca 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 45c6e743a..a750a31ca 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 45c6e743a..a750a31ca 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 45c6e743a..a750a31ca 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 45c6e743a..a750a31ca 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,25 @@ +Sat Feb 28 23:58:54 1998 Owen Taylor <owt1@cornell.edu> + + * gtk/gtkentry.[ch] gtktext.c gtkeditable.[ch] + + Created a new base widget type Editable for the entry and + text widgets, which encapsulates most of the selection and + clipboard handling stuff, plus some common signals. + + Changed the Entry widget extensively to support this, + but the interface and appearance should be the same. + + Changed the Text widget moderately to support this. + + It now supports: + + - Selection style cut and paste + - Clipboard style cut and paste + - Emacs style key bindings (~same as Entry) + - Word motion + + There are definitely still some bugs in the new stuff. + Sat Feb 28 19:29:09 1998 Tim Janik <timj@gimp.org> * gtk/gtkclist.c (gtk_clist_new_with_titles): retrive the clist widget @@ -57,6 +57,8 @@ Bugs: segfault in malloc -timj + * Change bitfields to guints from enums for C++ ? + Additions: * it might be good to ues stdio and getch() instead of 1-character reads. so one can take advantage of buffering. Currently each read() takes a separate @@ -111,3 +113,32 @@ TODO AFTER GTK 1.0 This will be covered by upcoming themability, raster is working on it. * More work on Documentation + + * Check return values on all calls to XIC[Get/Set]Values + + * Rewrite the interface to the i18n stuff so GTK widgets don't need to + retrieve X values, and so they don't have to know the value of the + XNxxx character constants. + + * The "-geometry" option should be supported + + - Having gdk_init() parse the geometry option. (putting it into + GDK means you can use XParseGeometry() without wrapping it) + + - Add a call gdk_get_geometry() that retrieves the results + in a form like that returned by XParseGeometry() + + - The application then can modify the results (as would gemvt) + then call a routine gtk_window_set_geometry() on whatever + it considers to be its main window. + + - Then in some manner GtkWindow takes that into account when + setting its hints. (Probably it uses the size and position + as the current uposition and usize, and modulates that + be the equivalents of the X flags + + XValue, YValue, WidthValue, HeightValue, XNegative, or YNegative + + ( You'd have to extend gdk_window_set_hints to accept the + window gravity option to get it right. ) + diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 6e26be2a7..c311c0240 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -24,6 +24,7 @@ libgtk_la_SOURCES = \ gtkdata.c \ gtkdialog.c \ gtkdrawingarea.c \ + gtkeditable.c \ gtkentry.c \ gtkeventbox.c \ gtkfilesel.c \ @@ -117,6 +118,7 @@ gtkinclude_HEADERS = \ gtkdebug.h \ gtkdialog.h \ gtkdrawingarea.h \ + gtkeditable.h \ gtkentry.h \ gtkenums.h \ gtkeventbox.h \ @@ -213,7 +215,8 @@ EXTRA_DIST = \ tree_plus.xpm \ tree_minus.xpm \ tree_plus.xbm \ - tree_minus.xbm + tree_minus.xbm \ + circles.xbm INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ @@ -39,6 +39,7 @@ #include <gtk/gtkdata.h> #include <gtk/gtkdialog.h> #include <gtk/gtkdrawingarea.h> +#include <gtk/gtkeditable.h> #include <gtk/gtkentry.h> #include <gtk/gtkenums.h> #include <gtk/gtkeventbox.h> diff --git a/gtk/gtkeditable.c b/gtk/gtkeditable.c new file mode 100644 index 000000000..93ec740ad --- /dev/null +++ b/gtk/gtkeditable.c @@ -0,0 +1,664 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <ctype.h> +#include <string.h> +#ifdef USE_XIM +#include "gdk/gdkx.h" +#endif +#include "gdk/gdkkeysyms.h" +#include "gdk/gdki18n.h" +#include "gtkeditable.h" +#include "gtkmain.h" +#include "gtkselection.h" +#include "gtksignal.h" + +#define MIN_EDITABLE_WIDTH 150 +#define DRAW_TIMEOUT 20 +#define INNER_BORDER 2 + +enum { + INSERT_TEXT, + DELETE_TEXT, + UPDATE_TEXT, + GET_CHARS, + SET_SELECTION, + CHANGED, + LAST_SIGNAL +}; + + +typedef void (*GtkEditableSignal1) (GtkObject *object, + gpointer arg1, + gint arg2, + gpointer arg3, + gpointer data); +typedef void (*GtkEditableSignal2) (GtkObject *object, + gint arg1, + gint arg2, + gpointer data); + +typedef gpointer (*GtkEditableSignal3) (GtkObject *object, + gint arg1, + gint arg2, + gpointer data); + + +static void gtk_editable_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_editable_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_editable_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_editable_class_init (GtkEditableClass *klass); +static void gtk_editable_init (GtkEditable *editable); +static void gtk_editable_finalize (GtkObject *object); +static gint gtk_editable_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +static void gtk_editable_selection_handler (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data); +static void gtk_editable_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data); + +static void gtk_editable_set_selection (GtkEditable *editable, + gint start, + gint end); + +static GtkWidgetClass *parent_class = NULL; +static gint editable_signals[LAST_SIGNAL] = { 0 }; +static GdkAtom ctext_atom = GDK_NONE; +static GdkAtom text_atom = GDK_NONE; +static GdkAtom clipboard_atom = GDK_NONE; + +guint +gtk_editable_get_type () +{ + static guint editable_type = 0; + + if (!editable_type) + { + GtkTypeInfo editable_info = + { + "GtkEditable", + sizeof (GtkEditable), + sizeof (GtkEditableClass), + (GtkClassInitFunc) gtk_editable_class_init, + (GtkObjectInitFunc) gtk_editable_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL, + }; + + editable_type = gtk_type_unique (gtk_widget_get_type (), &editable_info); + } + + return editable_type; +} + +static void +gtk_editable_class_init (GtkEditableClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + editable_signals[INSERT_TEXT] = + gtk_signal_new ("insert_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEditableClass, insert_text), + gtk_editable_marshal_signal_1, + GTK_TYPE_NONE, 3, + GTK_TYPE_STRING, GTK_TYPE_INT, + GTK_TYPE_POINTER); + editable_signals[DELETE_TEXT] = + gtk_signal_new ("delete_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEditableClass, delete_text), + gtk_editable_marshal_signal_2, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, GTK_TYPE_INT); + editable_signals[UPDATE_TEXT] = + gtk_signal_new ("update_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEditableClass, update_text), + gtk_editable_marshal_signal_2, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, GTK_TYPE_INT); + editable_signals[GET_CHARS] = + gtk_signal_new ("get_chars", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEditableClass, get_chars), + gtk_editable_marshal_signal_3, + GTK_TYPE_POINTER, 2, + GTK_TYPE_INT, GTK_TYPE_INT); + editable_signals[SET_SELECTION] = + gtk_signal_new ("set_selection", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEditableClass, set_selection), + gtk_editable_marshal_signal_2, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, GTK_TYPE_INT); + editable_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEditableClass, changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL); + + object_class->finalize = gtk_editable_finalize; + + widget_class->selection_clear_event = gtk_editable_selection_clear; + widget_class->selection_received = gtk_editable_selection_received; + + class->insert_text = NULL; + class->delete_text = NULL; + class->update_text = NULL; + class->get_chars = NULL; + class->set_selection = NULL; + class->changed = NULL; +} + +static void +gtk_editable_init (GtkEditable *editable) +{ + GTK_WIDGET_SET_FLAGS (editable, GTK_CAN_FOCUS); + + editable->selection_start_pos = 0; + editable->selection_end_pos = 0; + editable->has_selection = FALSE; + editable->editable = 1; + editable->clipboard_text = NULL; + +#ifdef USE_XIM + editable->ic = NULL; +#endif + + if (!clipboard_atom) + clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); + + gtk_selection_add_handler (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, gtk_editable_selection_handler, + NULL); + gtk_selection_add_handler (GTK_WIDGET(editable), clipboard_atom, + GDK_TARGET_STRING, gtk_editable_selection_handler, + NULL); + + if (!text_atom) + text_atom = gdk_atom_intern ("TEXT", FALSE); + + gtk_selection_add_handler (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, + text_atom, + gtk_editable_selection_handler, + NULL); + gtk_selection_add_handler (GTK_WIDGET(editable), clipboard_atom, + text_atom, + gtk_editable_selection_handler, + NULL); + + if (!ctext_atom) + ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); + + gtk_selection_add_handler (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, + ctext_atom, + gtk_editable_selection_handler, + NULL); + gtk_selection_add_handler (GTK_WIDGET(editable), clipboard_atom, + ctext_atom, + gtk_editable_selection_handler, + NULL); +} + +static void +gtk_editable_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEditableSignal1 rfunc; + + rfunc = (GtkEditableSignal1) func; + + (* rfunc) (object, GTK_VALUE_STRING (args[0]), GTK_VALUE_INT (args[1]), + GTK_VALUE_POINTER (args[2]), func_data); +} + +static void +gtk_editable_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEditableSignal2 rfunc; + + rfunc = (GtkEditableSignal2) func; + + (* rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]), + func_data); +} + +static void +gtk_editable_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEditableSignal3 rfunc; + gpointer *return_val; + + rfunc = (GtkEditableSignal3) func; + + return_val = GTK_RETLOC_POINTER (args[2]); + + *return_val = (* rfunc) (object, + GTK_VALUE_INT (args[0]), + GTK_VALUE_INT (args[1]), + func_data); +} + +static void +gtk_editable_finalize (GtkObject *object) +{ + GtkEditable *editable; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_EDITABLE (object)); + + editable = GTK_EDITABLE (object); + +#ifdef USE_XIM + if (editable->ic) + { + gdk_ic_destroy (editable->ic); + editable->ic = NULL; + } +#endif + + (* GTK_OBJECT_CLASS (parent_class)->finalize) (object); +} + +void +gtk_editable_insert_text (GtkEditable *editable, + const gchar *new_text, + guint new_text_length, + guint *position) +{ + gchar buf[64]; + gchar *text; + + g_return_if_fail (editable != NULL); + g_return_if_fail (GTK_IS_EDITABLE (editable)); + + if (new_text_length <= 64) + text = buf; + else + text = g_new (gchar, new_text_length); + + strncpy (text, new_text, new_text_length); + + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT], + text, new_text_length, position); + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]); + + if (new_text_length > 64) + g_free (text); +} + +void +gtk_editable_delete_text (GtkEditable *editable, + guint start_pos, + guint end_pos) +{ + g_return_if_fail (editable != NULL); + g_return_if_fail (GTK_IS_EDITABLE (editable)); + + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[DELETE_TEXT], + start_pos, end_pos); + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]); +} + +static void +gtk_editable_update_text (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + g_return_if_fail (editable != NULL); + g_return_if_fail (GTK_IS_EDITABLE (editable)); + + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[UPDATE_TEXT], + start_pos, end_pos); +} + +gchar * +gtk_editable_get_chars (GtkEditable *editable, + guint start, + guint end) +{ + gchar *retval = NULL; + + g_return_val_if_fail (editable != NULL, NULL); + g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL); + + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[GET_CHARS], + start, end, &retval); + + return retval; +} + +static void +gtk_editable_set_selection (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + g_return_if_fail (editable != NULL); + g_return_if_fail (GTK_IS_EDITABLE (editable)); + + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[SET_SELECTION], + start_pos, end_pos); +} + +static gint +gtk_editable_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ + GtkEditable *editable; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_EDITABLE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + /* Let the selection handling code know that the selection + * has been changed, since we've overriden the default handler */ + gtk_selection_clear (widget, event); + + editable = GTK_EDITABLE (widget); + + if (event->selection == GDK_SELECTION_PRIMARY) + { + if (editable->has_selection) + { + editable->has_selection = FALSE; + gtk_editable_update_text (editable, editable->selection_start_pos, + editable->selection_end_pos); + } + } + else if (event->selection == clipboard_atom) + { + g_free (editable->clipboard_text); + editable->clipboard_text = NULL; + } + + return FALSE; +} + +static void +gtk_editable_selection_handler (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data) +{ + GtkEditable *editable; + gint selection_start_pos; + gint selection_end_pos; + + gchar *str; + gint length; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDITABLE (widget)); + + editable = GTK_EDITABLE (widget); + + if (selection_data->selection == GDK_SELECTION_PRIMARY) + { + selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); + selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); + str = gtk_editable_get_chars(editable, selection_start_pos, + selection_end_pos); + length = selection_end_pos - selection_start_pos; + } + else /* CLIPBOARD */ + { + if (!editable->clipboard_text) + return; /* Refuse */ + + str = editable->clipboard_text; + length = strlen (editable->clipboard_text); + } + + if (selection_data->target == GDK_SELECTION_TYPE_STRING) + { + gtk_selection_data_set (selection_data, + GDK_SELECTION_TYPE_STRING, + 8*sizeof(gchar), str, length); + } + else if (selection_data->target == text_atom || + selection_data->target == ctext_atom) + { + guchar *text; + gchar c; + GdkAtom encoding; + gint format; + gint new_length; + + c = str[length]; + str[length] = '\0'; + gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length); + gtk_selection_data_set (selection_data, encoding, format, text, new_length); + gdk_free_compound_text (text); + str[length] = c; + } + + if (str != editable->clipboard_text) + g_free (str); +} + +static void +gtk_editable_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data) +{ + GtkEditable *editable; + gint reselect; + gint old_pos; + gint tmp_pos; + enum {INVALID, STRING, CTEXT} type; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDITABLE (widget)); + + editable = GTK_EDITABLE (widget); + + if (selection_data->type == GDK_TARGET_STRING) + type = STRING; + else if (selection_data->type == ctext_atom) + type = CTEXT; + else + type = INVALID; + + if (type == INVALID || selection_data->length < 0) + { + /* avoid infinite loop */ + if (selection_data->target != GDK_TARGET_STRING) + gtk_selection_convert (widget, selection_data->selection, + GDK_TARGET_STRING, GDK_CURRENT_TIME); + return; + } + + reselect = FALSE; + + if ((editable->selection_start_pos != editable->selection_end_pos) && + (!editable->has_selection || + (selection_data->selection == clipboard_atom))) + { + reselect = TRUE; + + /* Don't want to call gtk_editable_delete_selection here if we are going + * to reclaim the selection to avoid extra server traffic */ + if (editable->has_selection) + { + gtk_editable_delete_text (editable, + MIN (editable->selection_start_pos, editable->selection_end_pos), + MAX (editable->selection_start_pos, editable->selection_end_pos)); + } + else + gtk_editable_delete_selection (editable); + } + + tmp_pos = old_pos = editable->current_pos; + + switch (type) + { + case STRING: + selection_data->data[selection_data->length] = 0; + gtk_editable_insert_text (editable, selection_data->data, + strlen (selection_data->data), &tmp_pos); + editable->current_pos = tmp_pos; + break; + case CTEXT: + { + gchar **list; + gint count; + gint i; + + count = gdk_text_property_to_text_list (selection_data->type, + selection_data->format, + selection_data->data, + selection_data->length, + &list); + for (i=0; i<count; i++) + { + gtk_editable_insert_text (editable, list[i], strlen (list[i]), &tmp_pos); + editable->current_pos = tmp_pos; + } + if (count > 0) + gdk_free_text_list (list); + } + break; + case INVALID: /* quiet compiler */ + break; + } + + if (reselect) + gtk_editable_set_selection (editable, old_pos, editable->current_pos); +} + +void +gtk_editable_delete_selection (GtkEditable *editable) +{ + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_text (editable, + MIN (editable->selection_start_pos, editable->selection_end_pos), + MAX (editable->selection_start_pos, editable->selection_end_pos)); + + editable->selection_start_pos = 0; + editable->selection_end_pos = 0; + + if (editable->has_selection) + { + editable->has_selection = FALSE; + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (editable)->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); + } +} + +void +gtk_editable_claim_selection (GtkEditable *editable, + gboolean claim, + guint32 time) +{ + g_return_if_fail (GTK_WIDGET_REALIZED (editable)); + + if (claim) + { + if (gtk_selection_owner_set (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, time)) + editable->has_selection = TRUE; + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == + GTK_WIDGET(editable)->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time); + } +} + +void +gtk_editable_select_region (GtkEditable *editable, + guint start, + guint end) +{ + if (GTK_WIDGET_REALIZED (editable)) + gtk_editable_claim_selection (editable, start != end, GDK_CURRENT_TIME); + + gtk_editable_set_selection (editable, start, end); +} + +void +gtk_editable_cut_clipboard (GtkEditable *editable, GdkEventKey *event) +{ + gtk_editable_copy_clipboard (editable, event); + gtk_editable_delete_selection (editable); +} + +void +gtk_editable_copy_clipboard (GtkEditable *editable, GdkEventKey *event) +{ + gint selection_start_pos; + gint selection_end_pos; + + selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); + selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); + + if (selection_start_pos != selection_end_pos) + { + if (gtk_selection_owner_set (GTK_WIDGET (editable), + clipboard_atom, + event->time)) + editable->clipboard_text = gtk_editable_get_chars (editable, + editable->selection_start_pos, + editable->selection_end_pos); + } +} + +void +gtk_editable_paste_clipboard (GtkEditable *editable, GdkEventKey *event) +{ + gtk_selection_convert (GTK_WIDGET(editable), + clipboard_atom, ctext_atom, event->time); +} + +void +gtk_editable_changed (GtkEditable *editable) +{ + gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]); +} diff --git a/gtk/gtkeditable.h b/gtk/gtkeditable.h new file mode 100644 index 000000000..253206338 --- /dev/null +++ b/gtk/gtkeditable.h @@ -0,0 +1,112 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_EDITABLE_H__ +#define __GTK_EDITABLE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_EDITABLE(obj) GTK_CHECK_CAST (obj, gtk_editable_get_type (), GtkEditable) +#define GTK_EDITABLE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_editable_get_type (), GtkEditableClass) +#define GTK_IS_EDITABLE(obj) GTK_CHECK_TYPE (obj, gtk_editable_get_type ()) + + +typedef struct _GtkEditable GtkEditable; +typedef struct _GtkEditableClass GtkEditableClass; + +typedef void (*GtkTextFunction) (GtkEditable *editable, GdkEventKey *event); + +struct _GtkEditable +{ + GtkWidget widget; + + guint current_pos; + + guint selection_start_pos; + guint selection_end_pos; + guint has_selection : 1; + guint editable : 1; + GdkIC ic; + + gchar *clipboard_text; +}; + +struct _GtkEditableClass +{ + GtkWidgetClass parent_class; + + void (* insert_text) (GtkEditable *editable, + const gchar *text, + guint length, + guint *position); + void (* delete_text) (GtkEditable *editable, + guint start_pos, + guint end_pos); + void (* update_text) (GtkEditable *editable, + guint start_pos, + guint end_pos); + gchar* (* get_chars) (GtkEditable *editable, + guint start_pos, + guint end_pos); + void (* set_selection)(GtkEditable *editable, + guint start_pos, + guint end_pos); + void (* changed) (GtkEditable *editable); +}; + +guint gtk_editable_get_type (void); +void gtk_editable_select_region (GtkEditable *editable, + guint start, + guint end); +void gtk_editable_insert_text (GtkEditable *editable, + const gchar *new_text, + guint new_text_length, + guint *position); +void gtk_editable_delete_text (GtkEditable *editable, + guint start_pos, + guint end_pos); +gchar * gtk_editable_get_chars (GtkEditable *editable, + guint start, + guint end); +void gtk_editable_cut_clipboard (GtkEditable *editable, + GdkEventKey *event); +void gtk_editable_copy_clipboard (GtkEditable *editable, + GdkEventKey *event); +void gtk_editable_paste_clipboard (GtkEditable *editable, + GdkEventKey *event); +void gtk_editable_claim_selection (GtkEditable *editable, + gboolean claim, + guint32 time); +void gtk_editable_delete_selection (GtkEditable *editable); + +void gtk_editable_changed (GtkEditable *editable); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_EDITABLE_H__ */ diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index a4fdd9731..738410b95 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -32,36 +32,10 @@ #define INNER_BORDER 2 enum { - INSERT_TEXT, - DELETE_TEXT, - CHANGED, - SET_TEXT, ACTIVATE, LAST_SIGNAL }; - -typedef void (*GtkTextFunction) (GtkEntry *entry, GdkEventKey *event); -typedef void (*GtkEntrySignal1) (GtkObject *object, - gpointer arg1, - gint arg2, - gpointer arg3, - gpointer data); -typedef void (*GtkEntrySignal2) (GtkObject *object, - gint arg1, - gint arg2, - gpointer data); - - -static void gtk_entry_marshal_signal_1 (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -static void gtk_entry_marshal_signal_2 (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); - static void gtk_entry_class_init (GtkEntryClass *klass); static void gtk_entry_init (GtkEntry *entry); static void gtk_entry_finalize (GtkObject *object); @@ -90,13 +64,6 @@ static gint gtk_entry_focus_in (GtkWidget *widget, GdkEventFocus *event); static gint gtk_entry_focus_out (GtkWidget *widget, GdkEventFocus *event); -static gint gtk_entry_selection_clear (GtkWidget *widget, - GdkEventSelection *event); -static void gtk_entry_selection_handler (GtkWidget *widget, - GtkSelectionData *selection_data, - gpointer data); -static void gtk_entry_selection_received (GtkWidget *widget, - GtkSelectionData *selection_data); static void gtk_entry_draw_text (GtkEntry *entry); static void gtk_entry_draw_cursor (GtkEntry *entry); static void gtk_entry_draw_cursor_on_drawable @@ -108,20 +75,19 @@ static gint gtk_entry_position (GtkEntry *entry, gint x); void gtk_entry_adjust_scroll (GtkEntry *entry); static void gtk_entry_grow_text (GtkEntry *entry); -static void gtk_entry_insert_text (GtkEntry *entry, +static void gtk_entry_insert_text (GtkEditable *editable, const gchar *new_text, - gint new_text_length, - gint *position); -static void gtk_entry_delete_text (GtkEntry *entry, - gint start_pos, - gint end_pos); -static void gtk_real_entry_insert_text (GtkEntry *entry, - const gchar *new_text, - gint new_text_length, - gint *position); -static void gtk_real_entry_delete_text (GtkEntry *entry, - gint start_pos, - gint end_pos); + guint new_text_length, + guint *position); +static void gtk_entry_delete_text (GtkEditable *editable, + guint start_pos, + guint end_pos); +static void gtk_entry_update_text (GtkEditable *editable, + guint start_pos, + guint end_pos); +static gchar *gtk_entry_get_chars (GtkEditable *editable, + guint start, + guint end); static gint move_backward_character (gchar *str, gint index); static void gtk_move_forward_character (GtkEntry *entry); @@ -136,27 +102,23 @@ static void gtk_delete_forward_word (GtkEntry *entry); static void gtk_delete_backward_word (GtkEntry *entry); static void gtk_delete_line (GtkEntry *entry); static void gtk_delete_to_line_end (GtkEntry *entry); -static void gtk_delete_selection (GtkEntry *entry); static void gtk_select_word (GtkEntry *entry); static void gtk_select_line (GtkEntry *entry); -static void gtk_entry_cut_clipboard (GtkEntry *entry, - GdkEventKey *event); -static void gtk_entry_copy_clipboard (GtkEntry *entry, - GdkEventKey *event); -static void gtk_entry_paste_clipboard (GtkEntry *entry, - GdkEventKey *event); + + +static void gtk_entry_set_selection (GtkEditable *editable, + guint start, + guint end); static GtkWidgetClass *parent_class = NULL; static gint entry_signals[LAST_SIGNAL] = { 0 }; static GdkAtom ctext_atom = GDK_NONE; -static GdkAtom text_atom = GDK_NONE; -static GdkAtom clipboard_atom = GDK_NONE; static GtkTextFunction control_keys[26] = { (GtkTextFunction)gtk_move_beginning_of_line, /* a */ (GtkTextFunction)gtk_move_backward_character, /* b */ - gtk_entry_copy_clipboard, /* c */ + gtk_editable_copy_clipboard, /* c */ (GtkTextFunction)gtk_delete_forward_character, /* d */ (GtkTextFunction)gtk_move_end_of_line, /* e */ (GtkTextFunction)gtk_move_forward_character, /* f */ @@ -175,9 +137,9 @@ static GtkTextFunction control_keys[26] = NULL, /* s */ NULL, /* t */ (GtkTextFunction)gtk_delete_line, /* u */ - gtk_entry_paste_clipboard, /* v */ + gtk_editable_paste_clipboard, /* v */ (GtkTextFunction)gtk_delete_backward_word, /* w */ - gtk_entry_cut_clipboard, /* x */ + gtk_editable_cut_clipboard, /* x */ NULL, /* y */ NULL, /* z */ }; @@ -231,7 +193,7 @@ gtk_entry_get_type () (GtkArgGetFunc) NULL, }; - entry_type = gtk_type_unique (gtk_widget_get_type (), &entry_info); + entry_type = gtk_type_unique (gtk_editable_get_type (), &entry_info); } return entry_type; @@ -242,43 +204,14 @@ gtk_entry_class_init (GtkEntryClass *class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; + GtkEditableClass *editable_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; + editable_class = (GtkEditableClass*) class; parent_class = gtk_type_class (gtk_widget_get_type ()); - entry_signals[INSERT_TEXT] = - gtk_signal_new ("insert_text", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (GtkEntryClass, insert_text), - gtk_entry_marshal_signal_1, - GTK_TYPE_NONE, 3, - GTK_TYPE_STRING, GTK_TYPE_INT, - GTK_TYPE_POINTER); - entry_signals[DELETE_TEXT] = - gtk_signal_new ("delete_text", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (GtkEntryClass, delete_text), - gtk_entry_marshal_signal_2, - GTK_TYPE_NONE, 2, - GTK_TYPE_INT, GTK_TYPE_INT); - entry_signals[CHANGED] = - gtk_signal_new ("changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (GtkEntryClass, changed), - gtk_signal_default_marshaller, - GTK_TYPE_NONE, 0); - entry_signals[SET_TEXT] = - gtk_signal_new ("set_text", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (GtkEntryClass, set_text), - gtk_signal_default_marshaller, - GTK_TYPE_NONE, 0); entry_signals[ACTIVATE] = gtk_signal_new ("activate", GTK_RUN_LAST, @@ -304,14 +237,14 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->key_press_event = gtk_entry_key_press; widget_class->focus_in_event = gtk_entry_focus_in; widget_class->focus_out_event = gtk_entry_focus_out; - widget_class->selection_clear_event = gtk_entry_selection_clear; - widget_class->selection_received = gtk_entry_selection_received; - - class->insert_text = gtk_real_entry_insert_text; - class->delete_text = gtk_real_entry_delete_text; - class->changed = gtk_entry_adjust_scroll; - class->set_text = NULL; /* user defined handling */ - class->activate = NULL; /* user defined handling */ + + editable_class->insert_text = gtk_entry_insert_text; + editable_class->delete_text = gtk_entry_delete_text; + editable_class->update_text = gtk_entry_update_text; + editable_class->get_chars = gtk_entry_get_chars; + editable_class->set_selection = gtk_entry_set_selection; + editable_class->changed = (void (*)(GtkEditable *)) gtk_entry_adjust_scroll; + class->activate = NULL; } static void @@ -325,53 +258,9 @@ gtk_entry_init (GtkEntry *entry) entry->text_size = 0; entry->text_length = 0; entry->text_max_length = 0; - entry->current_pos = 0; - entry->selection_start_pos = 0; - entry->selection_end_pos = 0; entry->scroll_offset = 0; - entry->have_selection = FALSE; entry->timer = 0; entry->visible = 1; - entry->editable = 1; - entry->clipboard_text = NULL; - -#ifdef USE_XIM - entry->ic = NULL; -#endif - - if (!clipboard_atom) - clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); - - gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, - GDK_TARGET_STRING, gtk_entry_selection_handler, - NULL); - gtk_selection_add_handler (GTK_WIDGET(entry), clipboard_atom, - GDK_TARGET_STRING, gtk_entry_selection_handler, - NULL); - - if (!text_atom) - text_atom = gdk_atom_intern ("TEXT", FALSE); - - gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, - text_atom, - gtk_entry_selection_handler, - NULL); - gtk_selection_add_handler (GTK_WIDGET(entry), clipboard_atom, - text_atom, - gtk_entry_selection_handler, - NULL); - - if (!ctext_atom) - ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); - - gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, - ctext_atom, - gtk_entry_selection_handler, - NULL); - gtk_selection_add_handler (GTK_WIDGET(entry), clipboard_atom, - ctext_atom, - gtk_entry_selection_handler, - NULL); gtk_entry_grow_text (entry); } @@ -397,23 +286,25 @@ gtk_entry_set_text (GtkEntry *entry, { gint tmp_pos; + GtkEditable *editable; + g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (text != NULL); - gtk_real_entry_delete_text (entry, 0, entry->text_length); + editable = GTK_EDITABLE (entry); + + gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length); tmp_pos = 0; - gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); - entry->current_pos = tmp_pos; + gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos); + editable->current_pos = tmp_pos; - entry->selection_start_pos = 0; - entry->selection_end_pos = 0; + editable->selection_start_pos = 0; + editable->selection_end_pos = 0; if (GTK_WIDGET_DRAWABLE (entry)) gtk_entry_draw_text (entry); - - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); } void @@ -426,10 +317,8 @@ gtk_entry_append_text (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); tmp_pos = entry->text_length; - gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); - entry->current_pos = tmp_pos; - - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); + gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos); + GTK_EDITABLE(entry)->current_pos = tmp_pos; } void @@ -442,10 +331,8 @@ gtk_entry_prepend_text (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); tmp_pos = 0; - gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); - entry->current_pos = tmp_pos; - - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); + gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos); + GTK_EDITABLE(entry)->current_pos = tmp_pos; } void @@ -456,9 +343,9 @@ gtk_entry_set_position (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); if ((position == -1) || (position > entry->text_length)) - entry->current_pos = entry->text_length; + GTK_EDITABLE(entry)->current_pos = entry->text_length; else - entry->current_pos = position; + GTK_EDITABLE(entry)->current_pos = position; } void @@ -477,7 +364,7 @@ gtk_entry_set_editable(GtkEntry *entry, { g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ENTRY (entry)); - entry->editable = editable; + GTK_EDITABLE(entry)->editable = editable; gtk_entry_queue_draw(entry); } @@ -494,35 +381,6 @@ gtk_entry_get_text (GtkEntry *entry) return entry->text; } - -static void -gtk_entry_marshal_signal_1 (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args) -{ - GtkEntrySignal1 rfunc; - - rfunc = (GtkEntrySignal1) func; - - (* rfunc) (object, GTK_VALUE_STRING (args[0]), GTK_VALUE_INT (args[1]), - GTK_VALUE_POINTER (args[2]), func_data); -} - -static void -gtk_entry_marshal_signal_2 (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args) -{ - GtkEntrySignal2 rfunc; - - rfunc = (GtkEntrySignal2) func; - - (* rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]), - func_data); -} - static void gtk_entry_finalize (GtkObject *object) { @@ -534,10 +392,10 @@ gtk_entry_finalize (GtkObject *object) entry = GTK_ENTRY (object); #ifdef USE_XIM - if (entry->ic) + if (GTK_EDITABLE(entry)->ic) { - gdk_ic_destroy (entry->ic); - entry->ic = NULL; + gdk_ic_destroy (GTK_EDITABLE(entry)->ic); + GTK_EDITABLE(entry)->ic = NULL; } #endif @@ -559,6 +417,7 @@ static void gtk_entry_realize (GtkWidget *widget) { GtkEntry *entry; + GtkEditable *editable; GdkWindowAttr attributes; gint attributes_mask; @@ -567,6 +426,7 @@ gtk_entry_realize (GtkWidget *widget) GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); entry = GTK_ENTRY (widget); + editable = GTK_EDITABLE (widget); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; @@ -637,7 +497,7 @@ gtk_entry_realize (GtkWidget *widget) rect.height = height; spot.x = 0; spot.y = height; - entry->ic = gdk_ic_new (entry->text_area, entry->text_area, + editable->ic = gdk_ic_new (entry->text_area, entry->text_area, style, "spotLocation", &spot, "area", &rect, @@ -645,28 +505,28 @@ gtk_entry_realize (GtkWidget *widget) NULL); break; default: - entry->ic = gdk_ic_new (entry->text_area, entry->text_area, + editable->ic = gdk_ic_new (entry->text_area, entry->text_area, style, NULL); } - if (entry->ic == NULL) + if (editable->ic == NULL) g_warning ("Can't create input context."); else { GdkColormap *colormap; mask = gdk_window_get_events (entry->text_area); - mask |= gdk_ic_get_events (entry->ic); + mask |= gdk_ic_get_events (editable->ic); gdk_window_set_events (entry->text_area, mask); if ((colormap = gtk_widget_get_colormap (widget)) != gtk_widget_get_default_colormap ()) { - gdk_ic_set_attr (entry->ic, "preeditAttributes", + gdk_ic_set_attr (editable->ic, "preeditAttributes", "colorMap", GDK_COLORMAP_XCOLORMAP (colormap), NULL); } - gdk_ic_set_attr (entry->ic,"preeditAttributes", + gdk_ic_set_attr (editable->ic,"preeditAttributes", "foreground", widget->style->fg[GTK_STATE_NORMAL].pixel, "background", widget->style->base[GTK_STATE_NORMAL].pixel, NULL); @@ -675,6 +535,9 @@ gtk_entry_realize (GtkWidget *widget) #endif gdk_window_show (entry->text_area); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); } static void @@ -763,6 +626,7 @@ gtk_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkEntry *entry; + GtkEditable *editable; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_ENTRY (widget)); @@ -770,6 +634,7 @@ gtk_entry_size_allocate (GtkWidget *widget, widget->allocation = *allocation; entry = GTK_ENTRY (widget); + editable = GTK_EDITABLE (widget); if (GTK_WIDGET_REALIZED (widget)) { @@ -786,7 +651,7 @@ gtk_entry_size_allocate (GtkWidget *widget, entry->scroll_offset = 0; gtk_entry_adjust_scroll (entry); #ifdef USE_XIM - if (entry->ic && (gdk_ic_get_style (entry->ic) & GdkIMPreeditPosition)) + if (editable->ic && (gdk_ic_get_style (editable->ic) & GdkIMPreeditPosition)) { gint width, height; GdkRectangle rect; @@ -796,7 +661,7 @@ gtk_entry_size_allocate (GtkWidget *widget, rect.y = 0; rect.width = width; rect.height = height; - gdk_ic_set_attr (entry->ic, "preeditAttributes", "area", &rect, NULL); + gdk_ic_set_attr (editable->ic, "preeditAttributes", "area", &rect, NULL); } #endif } @@ -842,6 +707,7 @@ gtk_entry_button_press (GtkWidget *widget, GdkEventButton *event) { GtkEntry *entry; + GtkEditable *editable; gint tmp_pos; g_return_val_if_fail (widget != NULL, FALSE); @@ -852,6 +718,8 @@ gtk_entry_button_press (GtkWidget *widget, ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); entry = GTK_ENTRY (widget); + editable = GTK_EDITABLE (widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget); @@ -863,8 +731,8 @@ gtk_entry_button_press (GtkWidget *widget, gtk_grab_add (widget); tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); - gtk_entry_select_region (entry, tmp_pos, tmp_pos); - entry->current_pos = entry->selection_start_pos; + gtk_entry_set_selection (editable, tmp_pos, tmp_pos); + editable->current_pos = editable->selection_start_pos; break; case GDK_2BUTTON_PRESS: @@ -883,9 +751,9 @@ gtk_entry_button_press (GtkWidget *widget, { if (event->button == 2) { - if (entry->selection_start_pos == entry->selection_end_pos || - entry->have_selection) - entry->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + if (editable->selection_start_pos == editable->selection_end_pos || + editable->has_selection) + editable->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, ctext_atom, event->time); } @@ -894,9 +762,9 @@ gtk_entry_button_press (GtkWidget *widget, gtk_grab_add (widget); tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); - gtk_entry_select_region (entry, tmp_pos, tmp_pos); - entry->have_selection = FALSE; - entry->current_pos = entry->selection_start_pos; + gtk_entry_set_selection (editable, tmp_pos, tmp_pos); + editable->has_selection = FALSE; + editable->current_pos = editable->selection_start_pos; } } @@ -908,6 +776,7 @@ gtk_entry_button_release (GtkWidget *widget, GdkEventButton *event) { GtkEntry *entry; + GtkEditable *editable; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); @@ -916,16 +785,18 @@ gtk_entry_button_release (GtkWidget *widget, if (event->button == 1) { entry = GTK_ENTRY (widget); + editable = GTK_EDITABLE (widget); + gtk_grab_remove (widget); - entry->have_selection = FALSE; - if (entry->selection_start_pos != entry->selection_end_pos) + editable->has_selection = FALSE; + if (editable->selection_start_pos != editable->selection_end_pos) { if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time)) { - entry->have_selection = TRUE; + editable->has_selection = TRUE; gtk_entry_queue_draw (entry); } } @@ -962,8 +833,8 @@ gtk_entry_motion_notify (GtkWidget *widget, if (event->is_hint || (entry->text_area != event->window)) gdk_window_get_pointer (entry->text_area, &x, NULL, NULL); - entry->selection_end_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); - entry->current_pos = entry->selection_end_pos; + GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos; gtk_entry_adjust_scroll (entry); gtk_entry_queue_draw (entry); @@ -975,6 +846,8 @@ gtk_entry_key_press (GtkWidget *widget, GdkEventKey *event) { GtkEntry *entry; + GtkEditable *editable; + gint return_val; gint key; gint tmp_pos; @@ -986,9 +859,10 @@ gtk_entry_key_press (GtkWidget *widget, g_return_val_if_fail (event != NULL, FALSE); entry = GTK_ENTRY (widget); + editable = GTK_EDITABLE (widget); return_val = FALSE; - if(entry->editable == FALSE) + if(editable->editable == FALSE) return FALSE; extend_selection = event->state & GDK_SHIFT_MASK; @@ -996,21 +870,21 @@ gtk_entry_key_press (GtkWidget *widget, if (extend_selection) { - if (entry->selection_start_pos == entry->selection_end_pos) + if (editable->selection_start_pos == editable->selection_end_pos) { - entry->selection_start_pos = entry->current_pos; - entry->selection_end_pos = entry->current_pos; + editable->selection_start_pos = editable->current_pos; + editable->selection_end_pos = editable->current_pos; } - extend_start = (entry->current_pos == entry->selection_start_pos); + extend_start = (editable->current_pos == editable->selection_start_pos); } switch (event->keyval) { case GDK_BackSpace: return_val = TRUE; - if (entry->selection_start_pos != entry->selection_end_pos) - gtk_delete_selection (entry); + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); else if (event->state & GDK_CONTROL_MASK) gtk_delete_backward_word (entry); else @@ -1025,11 +899,11 @@ gtk_entry_key_press (GtkWidget *widget, if (event->state & GDK_SHIFT_MASK) { extend_selection = FALSE; - gtk_entry_paste_clipboard (entry, event); + gtk_editable_paste_clipboard (editable, event); } else if (event->state & GDK_CONTROL_MASK) { - gtk_entry_copy_clipboard (entry, event); + gtk_editable_copy_clipboard (editable, event); } else { @@ -1041,7 +915,7 @@ gtk_entry_key_press (GtkWidget *widget, if (event->state & GDK_CONTROL_MASK) gtk_delete_line (entry); else if (event->state & GDK_SHIFT_MASK) - gtk_entry_cut_clipboard (entry, event); + gtk_editable_cut_clipboard (editable, event); else gtk_delete_forward_character (entry); break; @@ -1081,7 +955,7 @@ gtk_entry_key_press (GtkWidget *widget, if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a']) { - (* control_keys[key - 'a']) (entry, event); + (* control_keys[key - 'a']) (editable, event); return_val = TRUE; } break; @@ -1093,7 +967,7 @@ gtk_entry_key_press (GtkWidget *widget, if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a']) { - (* alt_keys[key - 'a']) (entry, event); + (* alt_keys[key - 'a']) (editable, event); return_val = TRUE; } break; @@ -1102,11 +976,11 @@ gtk_entry_key_press (GtkWidget *widget, if (event->length > 0) { extend_selection = FALSE; - gtk_delete_selection (entry); + gtk_editable_delete_selection (editable); - tmp_pos = entry->current_pos; - gtk_entry_insert_text (entry, event->string, event->length, &tmp_pos); - entry->current_pos = tmp_pos; + tmp_pos = editable->current_pos; + gtk_editable_insert_text (editable, event->string, event->length, &tmp_pos); + editable->current_pos = tmp_pos; return_val = TRUE; } @@ -1117,39 +991,27 @@ gtk_entry_key_press (GtkWidget *widget, { if (extend_selection) { - if (entry->current_pos < entry->selection_start_pos) - entry->selection_start_pos = entry->current_pos; - else if (entry->current_pos > entry->selection_end_pos) - entry->selection_end_pos = entry->current_pos; + if (editable->current_pos < editable->selection_start_pos) + editable->selection_start_pos = editable->current_pos; + else if (editable->current_pos > editable->selection_end_pos) + editable->selection_end_pos = editable->current_pos; else { if (extend_start) - entry->selection_start_pos = entry->current_pos; + editable->selection_start_pos = editable->current_pos; else - entry->selection_end_pos = entry->current_pos; + editable->selection_end_pos = editable->current_pos; } } else { - entry->selection_start_pos = 0; - entry->selection_end_pos = 0; + editable->selection_start_pos = 0; + editable->selection_end_pos = 0; } - /* alex stuff */ - if (entry->selection_start_pos != entry->selection_end_pos) - { - if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time)) - { - entry->have_selection = TRUE; - gtk_entry_queue_draw (entry); - } - } - else - { - if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) - gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); - } - /* end of alex stuff */ + gtk_editable_claim_selection (editable, + editable->selection_start_pos != editable->selection_end_pos, + event->time); gtk_entry_adjust_scroll (entry); gtk_entry_queue_draw (entry); @@ -1170,8 +1032,8 @@ gtk_entry_focus_in (GtkWidget *widget, gtk_widget_draw_focus (widget); #ifdef USE_XIM - if (GTK_ENTRY(widget)->ic) - gdk_im_begin (GTK_ENTRY(widget)->ic, GTK_ENTRY(widget)->text_area); + if (GTK_EDITABLE(widget)->ic) + gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_ENTRY(widget)->text_area); #endif return FALSE; @@ -1195,187 +1057,6 @@ gtk_entry_focus_out (GtkWidget *widget, return FALSE; } -static gint -gtk_entry_selection_clear (GtkWidget *widget, - GdkEventSelection *event) -{ - GtkEntry *entry; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - /* Let the selection handling code know that the selection - * has been changed, since we've overriden the default handler */ - gtk_selection_clear (widget, event); - - entry = GTK_ENTRY (widget); - - if (event->selection == GDK_SELECTION_PRIMARY) - { - if (entry->have_selection) - { - entry->have_selection = FALSE; - gtk_entry_queue_draw (entry); - } - } - else if (event->selection == clipboard_atom) - { - g_free (entry->clipboard_text); - entry->clipboard_text = NULL; - } - - return FALSE; -} - -static void -gtk_entry_selection_handler (GtkWidget *widget, - GtkSelectionData *selection_data, - gpointer data) -{ - GtkEntry *entry; - gint selection_start_pos; - gint selection_end_pos; - - guchar *str; - gint length; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_ENTRY (widget)); - - entry = GTK_ENTRY (widget); - - if (selection_data->selection == GDK_SELECTION_PRIMARY) - { - selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); - selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); - str = &entry->text[selection_start_pos]; - length = selection_end_pos - selection_start_pos; - } - else /* CLIPBOARD */ - { - if (!entry->clipboard_text) - return; /* Refuse */ - - str = entry->clipboard_text; - length = strlen (entry->clipboard_text); - } - - if (selection_data->target == GDK_SELECTION_TYPE_STRING) - { - gtk_selection_data_set (selection_data, - GDK_SELECTION_TYPE_STRING, - 8*sizeof(gchar), str, length); - } - else if (selection_data->target == text_atom || - selection_data->target == ctext_atom) - { - guchar *text; - gchar c; - GdkAtom encoding; - gint format; - gint new_length; - - c = str[length]; - str[length] = '\0'; - gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length); - gtk_selection_data_set (selection_data, encoding, format, text, new_length); - gdk_free_compound_text (text); - str[length] = c; - } -} - -static void -gtk_entry_selection_received (GtkWidget *widget, - GtkSelectionData *selection_data) -{ - GtkEntry *entry; - gint reselect; - gint old_pos; - gint tmp_pos; - enum {INVALID, STRING, CTEXT} type; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_ENTRY (widget)); - - entry = GTK_ENTRY (widget); - - if (selection_data->type == GDK_TARGET_STRING) - type = STRING; - else if (selection_data->type == ctext_atom) - type = CTEXT; - else - type = INVALID; - - if (type == INVALID || selection_data->length < 0) - { - /* avoid infinite loop */ - if (selection_data->target != GDK_TARGET_STRING) - gtk_selection_convert (widget, selection_data->selection, - GDK_TARGET_STRING, GDK_CURRENT_TIME); - return; - } - - reselect = FALSE; - - if ((entry->selection_start_pos != entry->selection_end_pos) && - (!entry->have_selection || - (selection_data->selection == clipboard_atom))) - { - reselect = TRUE; - - /* Don't want to call gtk_delete_selection here if we are going - * to reclaim the selection to avoid extra server traffic */ - if (entry->have_selection) - { - gtk_entry_delete_text (entry, - MIN (entry->selection_start_pos, entry->selection_end_pos), - MAX (entry->selection_start_pos, entry->selection_end_pos)); - } - else - gtk_delete_selection (entry); - } - - tmp_pos = old_pos = entry->current_pos; - - switch (type) - { - case STRING: - selection_data->data[selection_data->length] = 0; - gtk_entry_insert_text (entry, selection_data->data, - strlen (selection_data->data), &tmp_pos); - entry->current_pos = tmp_pos; - break; - case CTEXT: - { - gchar **list; - gint count; - gint i; - - count = gdk_text_property_to_text_list (selection_data->type, - selection_data->format, - selection_data->data, - selection_data->length, - &list); - for (i=0; i<count; i++) - { - gtk_entry_insert_text (entry, list[i], strlen (list[i]), &tmp_pos); - entry->current_pos = tmp_pos; - } - if (count > 0) - gdk_free_text_list (list); - } - break; - case INVALID: /* quiet compiler */ - break; - } - - if (reselect) - gtk_entry_select_region (entry, old_pos, entry->current_pos); - - gtk_entry_queue_draw (entry); -} - static void gtk_entry_make_backing_pixmap (GtkEntry *entry, gint width, gint height) { @@ -1407,6 +1088,7 @@ static void gtk_entry_draw_text (GtkEntry *entry) { GtkWidget *widget; + GtkEditable *editable; GtkStateType selected_state; gint selection_start_pos; gint selection_end_pos; @@ -1435,11 +1117,12 @@ gtk_entry_draw_text (GtkEntry *entry) if (GTK_WIDGET_DRAWABLE (entry)) { widget = GTK_WIDGET (entry); + editable = GTK_EDITABLE (entry); if (!entry->text) { gdk_window_clear (entry->text_area); - if (entry->editable) + if (editable->editable) gtk_entry_draw_cursor (entry); return; } @@ -1472,14 +1155,14 @@ gtk_entry_draw_text (GtkEntry *entry) y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2; y += widget->style->font->ascent; - if (entry->selection_start_pos != entry->selection_end_pos) + if (editable->selection_start_pos != editable->selection_end_pos) { selected_state = GTK_STATE_SELECTED; - if (!entry->have_selection) + if (!editable->has_selection) selected_state = GTK_STATE_ACTIVE; - selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); - selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + 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, @@ -1525,7 +1208,7 @@ gtk_entry_draw_text (GtkEntry *entry) entry->text); } - if (entry->editable) + if (editable->editable) gtk_entry_draw_cursor_on_drawable (entry, drawable); if (use_backing_pixmap) @@ -1549,6 +1232,7 @@ static void gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable) { GtkWidget *widget; + GtkEditable *editable; GdkGC *gc; gint xoffset; gint text_area_height; @@ -1559,15 +1243,16 @@ gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable) if (GTK_WIDGET_DRAWABLE (entry)) { widget = GTK_WIDGET (entry); + editable = GTK_EDITABLE (entry); - if (entry->current_pos > 0 && entry->visible) - xoffset = gdk_text_width (widget->style->font, entry->text, entry->current_pos); + if (editable->current_pos > 0 && entry->visible) + xoffset = gdk_text_width (widget->style->font, entry->text, editable->current_pos); else xoffset = 0; xoffset -= entry->scroll_offset; if (GTK_WIDGET_HAS_FOCUS (widget) && - (entry->selection_start_pos == entry->selection_end_pos)) + (editable->selection_start_pos == editable->selection_end_pos)) gc = widget->style->fg_gc[GTK_STATE_NORMAL]; else gc = widget->style->base_gc[GTK_WIDGET_STATE(widget)]; @@ -1575,14 +1260,14 @@ gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable) gdk_window_get_size (entry->text_area, NULL, &text_area_height); gdk_draw_line (drawable, gc, xoffset, 0, xoffset, text_area_height); #ifdef USE_XIM - if (gdk_im_ready() && entry->ic && - gdk_ic_get_style (entry->ic) & GdkIMPreeditPosition) + if (gdk_im_ready() && editable->ic && + gdk_ic_get_style (editable->ic) & GdkIMPreeditPosition) { GdkPoint spot; spot.x = xoffset; spot.y = (text_area_height + (widget->style->font->ascent - widget->style->font->descent) + 1) / 2; - gdk_ic_set_attr (entry->ic, "preeditAttributes", "spotLocation", &spot, NULL); + gdk_ic_set_attr (editable->ic, "preeditAttributes", "spotLocation", &spot, NULL); } #endif } @@ -1664,8 +1349,8 @@ gtk_entry_adjust_scroll (GtkEntry *entry) gdk_window_get_size (entry->text_area, &text_area_width, NULL); - if (entry->current_pos > 0) - xoffset = gdk_text_width (GTK_WIDGET (entry)->style->font, entry->text, entry->current_pos); + 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->scroll_offset; @@ -1697,50 +1382,10 @@ gtk_entry_grow_text (GtkEntry *entry) } static void -gtk_entry_insert_text (GtkEntry *entry, - const gchar *new_text, - gint new_text_length, - gint *position) -{ - gchar buf[64]; - gchar *text; - - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - if (new_text_length <= 64) - text = buf; - else - text = g_new (gchar, new_text_length); - - strncpy (text, new_text, new_text_length); - - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[INSERT_TEXT], - text, new_text_length, position); - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[CHANGED]); - - if (new_text_length > 64) - g_free (text); -} - -static void -gtk_entry_delete_text (GtkEntry *entry, - gint start_pos, - gint end_pos) -{ - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[DELETE_TEXT], - start_pos, end_pos); - gtk_signal_emit (GTK_OBJECT (entry), entry_signals[CHANGED]); -} - -static void -gtk_real_entry_insert_text (GtkEntry *entry, +gtk_entry_insert_text (GtkEditable *editable, const gchar *new_text, - gint new_text_length, - gint *position) + guint new_text_length, + guint *position) { gchar *text; gint start_pos; @@ -1748,8 +1393,12 @@ gtk_real_entry_insert_text (GtkEntry *entry, gint last_pos; gint i; + GtkEntry *entry; + g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (GTK_IS_ENTRY (editable)); + + entry = GTK_ENTRY (editable); /* Make sure we do not exceed the maximum size of the entry. */ if (entry->text_max_length != 0 && @@ -1764,10 +1413,10 @@ gtk_real_entry_insert_text (GtkEntry *entry, end_pos = start_pos + new_text_length; last_pos = new_text_length + entry->text_length; - if (entry->selection_start_pos >= *position) - entry->selection_start_pos += new_text_length; - if (entry->selection_end_pos >= *position) - entry->selection_end_pos += new_text_length; + if (editable->selection_start_pos >= *position) + editable->selection_start_pos += new_text_length; + if (editable->selection_end_pos >= *position) + editable->selection_end_pos += new_text_length; while (last_pos >= entry->text_size) gtk_entry_grow_text (entry); @@ -1780,24 +1429,30 @@ gtk_real_entry_insert_text (GtkEntry *entry, entry->text_length += new_text_length; *position = end_pos; + + gtk_entry_queue_draw (entry); } static void -gtk_real_entry_delete_text (GtkEntry *entry, - gint start_pos, - gint end_pos) +gtk_entry_delete_text (GtkEditable *editable, + guint start_pos, + guint end_pos) { gchar *text; gint deletion_length; gint i; + GtkEntry *entry; + g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (GTK_IS_ENTRY (editable)); + + entry = GTK_ENTRY (editable); - if (entry->selection_start_pos > start_pos) - entry->selection_start_pos -= MIN(end_pos, entry->selection_start_pos) - start_pos; - if (entry->selection_end_pos > start_pos) - entry->selection_end_pos -= MIN(end_pos, entry->selection_end_pos) - start_pos; + 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 ((start_pos < end_pos) && (start_pos >= 0) && @@ -1813,23 +1468,62 @@ gtk_real_entry_delete_text (GtkEntry *entry, text[i] = '\0'; entry->text_length -= deletion_length; - entry->current_pos = start_pos; + editable->current_pos = start_pos; } + + gtk_entry_queue_draw (entry); } +static void +gtk_entry_update_text (GtkEditable *editable, + guint start_pos, + guint end_pos) +{ + gtk_entry_queue_draw (GTK_ENTRY(editable)); +} + +gchar * +gtk_entry_get_chars (GtkEditable *editable, + guint start, + guint end) +{ + gchar *retval; + GtkEntry *entry; + gchar c; + + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL); + + entry = GTK_ENTRY (editable); + + start = MIN(entry->text_length, start); + end = MIN(entry->text_length, end); + + c = entry->text[end]; + entry->text[end] = '\0'; + + retval = g_strdup (&entry->text[start]); + + entry->text[end] = c; + + return retval; +} static void gtk_move_forward_character (GtkEntry *entry) { gint len; - if (entry->current_pos < entry->text_length) + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + + if (editable->current_pos < entry->text_length) { - len = mblen (entry->text+entry->current_pos, MB_CUR_MAX); - entry->current_pos += (len>0)? len:1; + len = mblen (entry->text+editable->current_pos, MB_CUR_MAX); + editable->current_pos += (len>0)? len:1; } - if (entry->current_pos > entry->text_length) - entry->current_pos = entry->text_length; + if (editable->current_pos > entry->text_length) + editable->current_pos = entry->text_length; } static gint @@ -1852,14 +1546,17 @@ move_backward_character (gchar *str, gint index) static void gtk_move_backward_character (GtkEntry *entry) { + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + /* this routine is correct only if string is state-independent-encoded */ - if (0 < entry->current_pos) + if (0 < editable->current_pos) { - entry->current_pos = move_backward_character (entry->text, - entry->current_pos); - if (entry->current_pos < 0) - entry->current_pos = 0; + editable->current_pos = move_backward_character (entry->text, + editable->current_pos); + if (editable->current_pos < 0) + editable->current_pos = 0; } } @@ -1871,10 +1568,13 @@ gtk_move_forward_word (GtkEntry *entry) wchar_t c; gint len; + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + if (entry->text) { text = entry->text; - i = entry->current_pos; + i = editable->current_pos; len = mbtowc (&c, text+i, MB_CUR_MAX); if (!iswalnum(c)) @@ -1892,9 +1592,9 @@ gtk_move_forward_word (GtkEntry *entry) break; } - entry->current_pos = i; - if (entry->current_pos > entry->text_length) - entry->current_pos = entry->text_length; + editable->current_pos = i; + if (editable->current_pos > entry->text_length) + editable->current_pos = entry->text_length; } } @@ -1906,14 +1606,17 @@ gtk_move_backward_word (GtkEntry *entry) wchar_t c; gint len; + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + if (entry->text) { text = entry->text; - i=move_backward_character(text, entry->current_pos); + i=move_backward_character(text, editable->current_pos); if (i < 0) /* Per */ { - entry->selection_start_pos = 0; - entry->selection_end_pos = 0; + editable->selection_start_pos = 0; + editable->selection_end_pos = 0; return; } @@ -1939,20 +1642,20 @@ gtk_move_backward_word (GtkEntry *entry) if (i < 0) i = 0; - entry->current_pos = i; + editable->current_pos = i; } } static void gtk_move_beginning_of_line (GtkEntry *entry) { - entry->current_pos = 0; + GTK_EDITABLE(entry)->current_pos = 0; } static void gtk_move_end_of_line (GtkEntry *entry) { - entry->current_pos = entry->text_length; + GTK_EDITABLE(entry)->current_pos = entry->text_length; } static void @@ -1960,13 +1663,16 @@ gtk_delete_forward_character (GtkEntry *entry) { gint old_pos; - if (entry->selection_start_pos != entry->selection_end_pos) - gtk_delete_selection (entry); + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); else { - old_pos = entry->current_pos; + old_pos = editable->current_pos; gtk_move_forward_character (entry); - gtk_entry_delete_text (entry, old_pos, entry->current_pos); + gtk_editable_delete_text (editable, old_pos, editable->current_pos); } } @@ -1975,13 +1681,16 @@ gtk_delete_backward_character (GtkEntry *entry) { gint old_pos; - if (entry->selection_start_pos != entry->selection_end_pos) - gtk_delete_selection (entry); + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); else { - old_pos = entry->current_pos; + old_pos = editable->current_pos; gtk_move_backward_character (entry); - gtk_entry_delete_text (entry, entry->current_pos, old_pos); + gtk_editable_delete_text (editable, editable->current_pos, old_pos); } } @@ -1990,13 +1699,16 @@ gtk_delete_forward_word (GtkEntry *entry) { gint old_pos; - if (entry->selection_start_pos != entry->selection_end_pos) - gtk_delete_selection (entry); + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); else { - old_pos = entry->current_pos; + old_pos = editable->current_pos; gtk_move_forward_word (entry); - gtk_entry_delete_text (entry, old_pos, entry->current_pos); + gtk_editable_delete_text (editable, old_pos, editable->current_pos); } } @@ -2005,45 +1717,29 @@ gtk_delete_backward_word (GtkEntry *entry) { gint old_pos; - if (entry->selection_start_pos != entry->selection_end_pos) - gtk_delete_selection (entry); + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); else { - old_pos = entry->current_pos; + old_pos = editable->current_pos; gtk_move_backward_word (entry); - gtk_entry_delete_text (entry, entry->current_pos, old_pos); + gtk_editable_delete_text (editable, editable->current_pos, old_pos); } } static void gtk_delete_line (GtkEntry *entry) { - gtk_entry_delete_text (entry, 0, entry->text_length); + gtk_editable_delete_text (GTK_EDITABLE(entry), 0, entry->text_length); } static void gtk_delete_to_line_end (GtkEntry *entry) { - gtk_entry_delete_text (entry, entry->current_pos, entry->text_length); -} - -static void -gtk_delete_selection (GtkEntry *entry) -{ - if (entry->selection_start_pos != entry->selection_end_pos) - gtk_entry_delete_text (entry, - MIN (entry->selection_start_pos, entry->selection_end_pos), - MAX (entry->selection_start_pos, entry->selection_end_pos)); - - entry->selection_start_pos = 0; - entry->selection_end_pos = 0; - - if (entry->have_selection) - { - entry->have_selection = FALSE; - if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (entry)->window) - gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); - } + gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length); } static void @@ -2052,82 +1748,46 @@ gtk_select_word (GtkEntry *entry) gint start_pos; gint end_pos; + GtkEditable *editable; + editable = GTK_EDITABLE (entry); + gtk_move_backward_word (entry); - start_pos = entry->current_pos; - end_pos = entry->current_pos; + start_pos = editable->current_pos; gtk_move_forward_word (entry); - end_pos = entry->current_pos; + end_pos = editable->current_pos; - gtk_entry_select_region (entry, start_pos, end_pos); + gtk_entry_set_selection (editable, start_pos, end_pos); } static void gtk_select_line (GtkEntry *entry) { - gtk_entry_select_region (entry, 0, entry->text_length); - entry->current_pos = entry->selection_end_pos; -} - -void -gtk_entry_select_region (GtkEntry *entry, - gint start, - gint end) -{ - entry->have_selection = TRUE; - - entry->selection_start_pos = start; - entry->selection_end_pos = end; - - gtk_widget_queue_draw (GTK_WIDGET (entry)); -} - -static void -gtk_entry_cut_clipboard (GtkEntry *entry, GdkEventKey *event) -{ - gtk_entry_copy_clipboard (entry, event); - gtk_delete_selection (entry); + GtkEditable *editable; + editable = GTK_EDITABLE (entry); - gtk_entry_queue_draw (entry); + gtk_entry_set_selection (editable, 0, entry->text_length); + editable->current_pos = editable->selection_end_pos; } -static void -gtk_entry_copy_clipboard (GtkEntry *entry, GdkEventKey *event) +static void +gtk_entry_set_selection (GtkEditable *editable, + guint start, + guint end) { - gint selection_start_pos; - gint selection_end_pos; + g_return_if_fail (GTK_IS_ENTRY (editable)); - selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); - selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); - - if (selection_start_pos != selection_end_pos) - { - if (gtk_selection_owner_set (GTK_WIDGET (entry), - clipboard_atom, - event->time)) - { - char c; + editable->selection_start_pos = start; + editable->selection_end_pos = end; - c = entry->text[selection_end_pos]; - entry->text[selection_end_pos] = 0; - entry->clipboard_text = g_strdup (entry->text + selection_start_pos); - entry->text[selection_end_pos] = c; - } - } + gtk_entry_queue_draw (GTK_ENTRY (editable)); } -static void -gtk_entry_paste_clipboard (GtkEntry *entry, GdkEventKey *event) +void +gtk_entry_select_region (GtkEntry *entry, + guint start, + guint end) { - gtk_selection_convert (GTK_WIDGET(entry), - clipboard_atom, ctext_atom, event->time); + gtk_editable_select_region (GTK_EDITABLE(entry), start, end); } -void -gtk_entry_set_max_length (GtkEntry *entry, guint16 max) -{ - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - entry->text_max_length = max; -} diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index e977e5761..137818136 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -20,7 +20,7 @@ #include <gdk/gdk.h> -#include <gtk/gtkwidget.h> +#include <gtk/gtkeditable.h> #ifdef __cplusplus @@ -38,7 +38,7 @@ typedef struct _GtkEntryClass GtkEntryClass; struct _GtkEntry { - GtkWidget widget; + GtkEditable editable; GdkWindow *text_area; GdkPixmap *backing_pixmap; @@ -48,32 +48,15 @@ struct _GtkEntry guint16 text_size; guint16 text_length; guint16 text_max_length; - gint16 current_pos; - gint16 selection_start_pos; - gint16 selection_end_pos; gint16 scroll_offset; - guint have_selection : 1; guint visible : 1; - guint editable : 1; guint32 timer; - GdkIC ic; - - gchar *clipboard_text; }; struct _GtkEntryClass { - GtkWidgetClass parent_class; - - void (* insert_text) (GtkEntry *entry, - const gchar *text, - gint length, - gint *position); - void (* delete_text) (GtkEntry *entry, - gint start_pos, - gint end_pos); - void (* changed) (GtkEntry *entry); - void (* set_text) (GtkEntry *entry); + GtkEditableClass parent_class; + void (* activate) (GtkEntry *entry); }; @@ -90,8 +73,8 @@ void gtk_entry_set_position (GtkEntry *entry, gint position); gchar* gtk_entry_get_text (GtkEntry *entry); void gtk_entry_select_region (GtkEntry *entry, - gint start, - gint end); + guint start, + guint end); void gtk_entry_set_visibility (GtkEntry *entry, gboolean visible); void gtk_entry_set_editable (GtkEntry *entry, diff --git a/gtk/gtkfilesel.c b/gtk/gtkfilesel.c index 6ac032659..56013eec1 100644 --- a/gtk/gtkfilesel.c +++ b/gtk/gtkfilesel.c @@ -936,8 +936,8 @@ gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) gtk_widget_show (fs->fileop_entry); gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file); - gtk_entry_select_region (GTK_ENTRY (fs->fileop_entry), - 0, strlen (fs->fileop_file)); + gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry), + 0, strlen (fs->fileop_file)); /* buttons */ button = gtk_button_new_with_label ("Rename"); diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c index 8de901e5a..552e20ef3 100644 --- a/gtk/gtkspinbutton.c +++ b/gtk/gtkspinbutton.c @@ -73,7 +73,7 @@ static void gtk_spin_button_value_changed (GtkWidget *widget, static gint gtk_spin_button_key_press (GtkWidget *widget, GdkEventKey *event); static void gtk_spin_button_update (GtkSpinButton *spin_button); -static void gtk_spin_button_changed (GtkEntry *entry); +static void gtk_spin_button_changed (GtkEditable *editable); static void gtk_spin_button_activate (GtkEntry *entry); @@ -109,11 +109,13 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; + GtkEditableClass *editable_class; GtkEntryClass *entry_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; entry_class = (GtkEntryClass*) class; + editable_class = (GtkEditableClass*) class; parent_class = gtk_type_class (gtk_entry_get_type ()); @@ -135,7 +137,7 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) widget_class->leave_notify_event = gtk_spin_button_leave_notify; widget_class->focus_out_event = gtk_spin_button_focus_out; - entry_class->changed = gtk_spin_button_changed; + editable_class->changed = gtk_spin_button_changed; entry_class->activate = gtk_spin_button_activate; } @@ -900,22 +902,22 @@ gtk_spin_button_update (GtkSpinButton *spin_button) } static void -gtk_spin_button_changed (GtkEntry *entry) +gtk_spin_button_changed (GtkEditable *editable) { - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (editable != NULL); + g_return_if_fail (GTK_IS_SPIN_BUTTON (editable)); - GTK_ENTRY_CLASS (parent_class)->changed (entry); - if (GTK_WIDGET_VISIBLE (GTK_WIDGET (entry))) + GTK_EDITABLE_CLASS (parent_class)->changed (editable); + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (editable))) { GtkSpinButton *spin; gfloat val; gchar *error = NULL; - spin = GTK_SPIN_BUTTON (entry); + spin = GTK_SPIN_BUTTON (editable); spin->snapped = 0; - val = strtod (entry->text, &error); + val = strtod (GTK_ENTRY (editable)->text, &error); if (val < spin->adjustment->lower) val = spin->adjustment->lower; else if (val > spin->adjustment->upper) @@ -928,9 +930,9 @@ static void gtk_spin_button_activate (GtkEntry *entry) { g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (GTK_IS_SPIN_BUTTON (entry)); - if (entry->editable) + if (GTK_EDITABLE(entry)->editable) gtk_spin_button_update (GTK_SPIN_BUTTON (entry)); } diff --git a/gtk/gtktext.c b/gtk/gtktext.c index bf803ea86..a8c8df434 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -22,6 +22,7 @@ #include "gdk/gdkx.h" #endif #include "gtkmain.h" +#include "gtkselection.h" #include "gtksignal.h" #include "gtktext.h" #include "line-wrap.xbm" @@ -57,6 +58,7 @@ #define MARK_CURRENT_FONT(mark) (((TextProperty*)(mark)->property->data)->font->gdk_font) #define MARK_CURRENT_FORE(mark) (&((TextProperty*)(mark)->property->data)->fore_color) #define MARK_CURRENT_BACK(mark) (&((TextProperty*)(mark)->property->data)->back_color) + #define MARK_CURRENT_TEXT_FONT(m) (((TextProperty*)(m)->property->data)->font) #define TEXT_LENGTH(t) ((t)->text_end - (t)->gap_size) #define FONT_HEIGHT(f) ((f)->ascent + (f)->descent) @@ -165,6 +167,23 @@ static void gtk_text_adjustment (GtkAdjustment *adjustment, static void gtk_text_disconnect (GtkAdjustment *adjustment, GtkText *text); +static void gtk_text_insert_text (GtkEditable *editable, + const gchar *new_text, + guint new_text_length, + guint *position); +static void gtk_text_delete_text (GtkEditable *editable, + guint start_pos, + guint end_pos); +static void gtk_text_update_text (GtkEditable *editable, + guint start_pos, + guint end_pos); +static gchar *gtk_text_get_chars (GtkEditable *editable, + guint start, + guint end); +static void gtk_text_set_selection (GtkEditable *editable, + guint start, + guint end); + /* Event handlers */ static void gtk_text_draw (GtkWidget *widget, GdkRectangle *area); @@ -182,12 +201,6 @@ static gint gtk_text_focus_in (GtkWidget *widget, GdkEventFocus *event); static gint gtk_text_focus_out (GtkWidget *widget, GdkEventFocus *event); -static gint gtk_text_selection_clear (GtkWidget *widget, - GdkEventSelection *event); -static gint gtk_text_selection_request (GtkWidget *widget, - GdkEventSelection *event); -static gint gtk_text_selection_notify (GtkWidget *widget, - GdkEventSelection *event); static void move_gap_to_point (GtkText* text); static void make_forward_space (GtkText* text, guint len); @@ -242,7 +255,7 @@ static void find_cursor (GtkText* text); static void find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height); -static void mouse_click_1 (GtkText* text, GdkEventButton *event); +static void find_mouse_cursor (GtkText* text, gint x, gint y); /* Scrolling. */ static void adjust_adj (GtkText* text, GtkAdjustment* adj); @@ -261,6 +274,21 @@ static void move_cursor_page_ver (GtkText *text, int dir); static void move_cursor_ver (GtkText *text, int count); static void move_cursor_hor (GtkText *text, int count); +static void gtk_text_move_forward_character (GtkText *text); +static void gtk_text_move_backward_character (GtkText *text); +static void gtk_text_move_forward_word (GtkText *text); +static void gtk_text_move_backward_word (GtkText *text); +static void gtk_text_move_beginning_of_line (GtkText *text); +static void gtk_text_move_end_of_line (GtkText *text); +static void gtk_text_delete_forward_character (GtkText *text); +static void gtk_text_delete_backward_character (GtkText *text); +static void gtk_text_delete_forward_word (GtkText *text); +static void gtk_text_delete_backward_word (GtkText *text); +static void gtk_text_delete_line (GtkText *text); +static void gtk_text_delete_to_line_end (GtkText *text); +static void gtk_text_select_word (GtkText *text); +static void gtk_text_select_line (GtkText *text); + #define DEBUG_GTK_TEXT #if defined(DEBUG_GTK_TEXT) && defined(__GNUC__) @@ -313,6 +341,67 @@ static GMemChunk *text_property_chunk = NULL; static GtkWidgetClass *parent_class = NULL; +static GtkTextFunction control_keys[26] = +{ + (GtkTextFunction)gtk_text_move_beginning_of_line, /* a */ + (GtkTextFunction)gtk_text_move_backward_character, /* b */ + gtk_editable_copy_clipboard, /* c */ + (GtkTextFunction)gtk_text_delete_forward_character, /* d */ + (GtkTextFunction)gtk_text_move_end_of_line, /* e */ + (GtkTextFunction)gtk_text_move_forward_character, /* f */ + NULL, /* g */ + (GtkTextFunction)gtk_text_delete_backward_character, /* h */ + NULL, /* i */ + NULL, /* j */ + (GtkTextFunction)gtk_text_delete_to_line_end, /* k */ + NULL, /* l */ + NULL, /* m */ + NULL, /* n */ + NULL, /* o */ + NULL, /* p */ + NULL, /* q */ + NULL, /* r */ + NULL, /* s */ + NULL, /* t */ + (GtkTextFunction)gtk_text_delete_line, /* u */ + gtk_editable_paste_clipboard, /* v */ + (GtkTextFunction)gtk_text_delete_backward_word, /* w */ + gtk_editable_cut_clipboard, /* x */ + NULL, /* y */ + NULL, /* z */ +}; + +static GtkTextFunction alt_keys[26] = +{ + NULL, /* a */ + (GtkTextFunction)gtk_text_move_backward_word, /* b */ + NULL, /* c */ + (GtkTextFunction)gtk_text_delete_forward_word, /* d */ + NULL, /* e */ + (GtkTextFunction)gtk_text_move_forward_word, /* f */ + NULL, /* g */ + NULL, /* h */ + NULL, /* i */ + NULL, /* j */ + NULL, /* k */ + NULL, /* l */ + NULL, /* m */ + NULL, /* n */ + NULL, /* o */ + NULL, /* p */ + NULL, /* q */ + NULL, /* r */ + NULL, /* s */ + NULL, /* t */ + NULL, /* u */ + NULL, /* v */ + NULL, /* w */ + NULL, /* x */ + NULL, /* y */ + NULL, /* z */ +}; + + /**********************************************************************/ /* Widget Crap */ /**********************************************************************/ @@ -335,7 +424,7 @@ gtk_text_get_type () (GtkArgGetFunc) NULL, }; - text_type = gtk_type_unique (gtk_widget_get_type (), &text_info); + text_type = gtk_type_unique (gtk_editable_get_type (), &text_info); } return text_type; @@ -346,9 +435,11 @@ gtk_text_class_init (GtkTextClass *class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; + GtkEditableClass *editable_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; + editable_class = (GtkEditableClass*) class; parent_class = gtk_type_class (gtk_widget_get_type ()); @@ -367,9 +458,12 @@ gtk_text_class_init (GtkTextClass *class) widget_class->key_press_event = gtk_text_key_press; widget_class->focus_in_event = gtk_text_focus_in; widget_class->focus_out_event = gtk_text_focus_out; - widget_class->selection_clear_event = gtk_text_selection_clear; - widget_class->selection_request_event = gtk_text_selection_request; - widget_class->selection_notify_event = gtk_text_selection_notify; + + editable_class->insert_text = gtk_text_insert_text; + editable_class->delete_text = gtk_text_delete_text; + editable_class->update_text = gtk_text_update_text; + editable_class->get_chars = gtk_text_get_chars; + editable_class->set_selection = gtk_text_set_selection; } static void @@ -393,7 +487,7 @@ gtk_text_init (GtkText *text) text->tab_stops = g_list_prepend (text->tab_stops, (void*)8); text->line_wrap = TRUE; - text->is_editable = FALSE; + GTK_EDITABLE(text)->editable = FALSE; } GtkWidget* @@ -416,7 +510,7 @@ gtk_text_set_editable (GtkText *text, g_return_if_fail (text != NULL); g_return_if_fail (GTK_IS_TEXT (text)); - text->is_editable = (editable != FALSE); + GTK_EDITABLE(text)->editable = (editable != FALSE); } void @@ -552,9 +646,9 @@ gtk_text_insert (GtkText *text, g_assert (GTK_WIDGET_REALIZED (text)); if (fore == NULL) - fore = &text->widget.style->fg[GTK_STATE_NORMAL]; + fore = >K_WIDGET (text)->style->text[GTK_STATE_NORMAL]; if (back == NULL) - back = &text->widget.style->bg[GTK_STATE_NORMAL]; + back = >K_WIDGET (text)->style->base[GTK_STATE_NORMAL]; /* This must be because we need to have the style set up. */ g_assert (GTK_WIDGET_REALIZED(text)); @@ -631,9 +725,18 @@ gtk_text_forward_delete (GtkText *text, } if (text->point.index < text->first_line_start_index) - text->first_line_start_index -= MIN(nchars, - text->first_line_start_index - - text->point.index); + { + if (text->point.index >= text->first_line_start_index - nchars) + { + text->first_line_start_index = text->point.index; + while ((text->first_line_start_index > 0) && + (GTK_TEXT_INDEX (text, text->first_line_start_index - 1) != LINE_DELIM)) + text->first_line_start_index -= 1; + + } + else + text->first_line_start_index -= nchars; + } move_gap_to_point (text); @@ -647,14 +750,20 @@ gtk_text_forward_delete (GtkText *text, return TRUE; } -gchar * -gtk_text_get_chars (GtkText *text, +static gchar * +gtk_text_get_chars (GtkEditable *editable, guint index, guint nchars) { + GtkText *text; + gchar *retval; gchar *p; guint n; + + g_return_val_if_fail (editable != NULL, NULL); + g_return_val_if_fail (GTK_IS_TEXT (editable), NULL); + text = GTK_TEXT (editable); if (index+nchars > TEXT_LENGTH (text)) return NULL; @@ -668,7 +777,7 @@ gtk_text_get_chars (GtkText *text, if (index < text->gap_position) { n = MIN (text->gap_position - index, nchars); - memcpy (p, text->text + GTK_TEXT_INDEX(text, index), n); + memcpy (p, &text->text[index], n); p += n; index += n; nchars -= n; @@ -680,9 +789,10 @@ gtk_text_get_chars (GtkText *text, text->text + MAX (text->gap_position + text->gap_size, index + text->gap_size), nchars); + p += nchars; } - retval[nchars+1] = 0; + *p = 0; return retval; } @@ -703,10 +813,10 @@ gtk_text_finalize (GtkObject *object) gtk_object_unref (GTK_OBJECT (text->vadj)); #ifdef USE_XIM - if (text->ic) + if (GTK_EDITABLE(text)->ic) { - gdk_ic_destroy (text->ic); - text->ic = NULL; + gdk_ic_destroy (GTK_EDITABLE(text)->ic); + GTK_EDITABLE(text)->ic = NULL; } #endif @@ -717,13 +827,15 @@ static void gtk_text_realize (GtkWidget *widget) { GtkText *text; + GtkEditable *editable; GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_TEXT (widget)); - text = (GtkText*) widget; + text = GTK_TEXT (widget); + editable = GTK_EDITABLE (widget); GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED); attributes.window_type = GDK_WINDOW_CHILD; @@ -758,11 +870,11 @@ gtk_text_realize (GtkWidget *widget) widget->style = gtk_style_attach (widget->style, widget->window); /* Can't call gtk_style_set_background here because its handled specially */ - if (!text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) - gdk_window_set_background (text->widget.window, &text->widget.style->bg[GTK_STATE_NORMAL]); + if (!widget->style->bg_pixmap[GTK_STATE_NORMAL]) + gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]); - if (!text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) - gdk_window_set_background (text->text_area, &text->widget.style->bg[GTK_STATE_NORMAL]); + if (!widget->style->bg_pixmap[GTK_STATE_NORMAL]) + gdk_window_set_background (text->text_area, &widget->style->base[GTK_STATE_NORMAL]); text->line_wrap_bitmap = gdk_bitmap_create_from_data (text->text_area, (gchar*) line_wrap_bits, @@ -776,7 +888,7 @@ gtk_text_realize (GtkWidget *widget) text->gc = gdk_gc_new (text->text_area); gdk_gc_set_exposures (text->gc, TRUE); - gdk_gc_set_foreground (text->gc, &widget->style->fg[GTK_STATE_NORMAL]); + gdk_gc_set_foreground (text->gc, &widget->style->text[GTK_STATE_NORMAL]); #ifdef USE_XIM if (gdk_im_ready ()) @@ -810,7 +922,7 @@ gtk_text_realize (GtkWidget *widget) spot.x = 0; spot.y = height; - text->ic = gdk_ic_new (text->text_area, text->text_area, + editable->ic = gdk_ic_new (text->text_area, text->text_area, style, "spotLocation", &spot, "area", &rect, @@ -818,24 +930,24 @@ gtk_text_realize (GtkWidget *widget) NULL); break; default: - text->ic = gdk_ic_new (text->text_area, text->text_area, + editable->ic = gdk_ic_new (text->text_area, text->text_area, style, NULL); } - if (text->ic == NULL) + if (editable->ic == NULL) g_warning ("Can't create input context."); else { GdkColormap *colormap; mask = gdk_window_get_events (text->text_area); - mask |= gdk_ic_get_events (text->ic); + mask |= gdk_ic_get_events (editable->ic); gdk_window_set_events (text->text_area, mask); if ((colormap = gtk_widget_get_colormap (widget)) != gtk_widget_get_default_colormap ()) { - gdk_ic_set_attr (text->ic, "preeditAttributes", + gdk_ic_set_attr (editable->ic, "preeditAttributes", "colorMap", GDK_COLORMAP_XCOLORMAP (colormap), NULL); } @@ -846,6 +958,9 @@ gtk_text_realize (GtkWidget *widget) init_properties (text); gdk_window_show (text->text_area); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); } static void @@ -872,14 +987,16 @@ gtk_text_unrealize (GtkWidget *widget) static void clear_focus_area (GtkText *text, gint area_x, gint area_y, gint area_width, gint area_height) { - gint ythick = TEXT_BORDER_ROOM + text->widget.style->klass->ythickness; - gint xthick = TEXT_BORDER_ROOM + text->widget.style->klass->xthickness; + GtkWidget *widget = GTK_WIDGET (text); + + gint ythick = TEXT_BORDER_ROOM + widget->style->klass->ythickness; + gint xthick = TEXT_BORDER_ROOM + widget->style->klass->xthickness; gint width, height; gint xorig, yorig; gint x, y; - gdk_window_get_size (text->widget.style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); + gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); yorig = - text->first_onscreen_ver_pixel + ythick; xorig = - text->first_onscreen_hor_pixel + xthick; @@ -900,9 +1017,9 @@ clear_focus_area (GtkText *text, gint area_x, gint area_y, gint area_width, gint gint xoff = (x - xorig) % width; gint xw = MIN(width - xoff, (area_x + area_width) - x); - gdk_draw_pixmap (text->widget.window, + gdk_draw_pixmap (widget->window, text->gc, - text->widget.style->bg_pixmap[GTK_STATE_NORMAL], + widget->style->bg_pixmap[GTK_STATE_NORMAL], xoff, yoff, x, @@ -1018,12 +1135,14 @@ gtk_text_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkText *text; + GtkEditable *editable; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_TEXT (widget)); g_return_if_fail (allocation != NULL); text = GTK_TEXT (widget); + editable = GTK_EDITABLE (widget); widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) @@ -1041,7 +1160,7 @@ gtk_text_size_allocate (GtkWidget *widget, TEXT_BORDER_ROOM) * 2); #ifdef USE_XIM - if (text->ic && (gdk_ic_get_style (text->ic) & GdkIMPreeditPosition)) + if (editable->ic && (gdk_ic_get_style (editable->ic) & GdkIMPreeditPosition)) { gint width, height; GdkRectangle rect; @@ -1051,7 +1170,7 @@ gtk_text_size_allocate (GtkWidget *widget, rect.y = 0; rect.width = width; rect.height = height; - gdk_ic_set_attr (text->ic, "preeditAttributes", "area", &rect, NULL); + gdk_ic_set_attr (editable->ic, "preeditAttributes", "area", &rect, NULL); } #endif @@ -1101,12 +1220,19 @@ gtk_text_button_press (GtkWidget *widget, GdkEventButton *event) { GtkText *text; + GtkEditable *editable; + static GdkAtom ctext_atom = GDK_NONE; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); - text = GTK_TEXT(widget); + if (ctext_atom == GDK_NONE) + ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); + + text = GTK_TEXT (widget); + editable = GTK_EDITABLE (widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget); @@ -1118,18 +1244,21 @@ gtk_text_button_press (GtkWidget *widget, switch (event->type) { case GDK_BUTTON_PRESS: - undraw_cursor (GTK_TEXT (widget), FALSE); - mouse_click_1 (GTK_TEXT (widget), event); - draw_cursor (GTK_TEXT (widget), FALSE); - /* start selection */ + undraw_cursor (text, FALSE); + find_mouse_cursor (text, event->x, event->y); + draw_cursor (text, FALSE); + + gtk_text_set_selection (GTK_EDITABLE(text), + text->cursor_mark.index, + text->cursor_mark.index); break; case GDK_2BUTTON_PRESS: - /* select word */ + gtk_text_select_word (text); break; case GDK_3BUTTON_PRESS: - /* select line */ + gtk_text_select_line (text); break; default: @@ -1140,11 +1269,28 @@ gtk_text_button_press (GtkWidget *widget, { if (event->button == 2) { - /* insert selection. */ + if (editable->selection_start_pos == editable->selection_end_pos || + editable->has_selection) + { + undraw_cursor (text, FALSE); + find_mouse_cursor (text, event->x, event->y); + draw_cursor (text, FALSE); + + editable->current_pos = text->cursor_mark.index; + } + + gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, + ctext_atom, event->time); } else { - /* start selection */ + undraw_cursor (text, FALSE); + find_mouse_cursor (text, event->x, event->y); + draw_cursor (text, FALSE); + + gtk_text_set_selection (GTK_EDITABLE(text), + text->cursor_mark.index, + text->cursor_mark.index); } } @@ -1156,17 +1302,43 @@ gtk_text_button_release (GtkWidget *widget, GdkEventButton *event) { GtkText *text; + GtkEditable *editable; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); - if (event->button != 2) + text = GTK_TEXT (widget); + + if (event->button == 1) { - gtk_grab_remove (widget); - text = GTK_TEXT (widget); + editable = GTK_EDITABLE (widget); - /* stop selecting. */ + gtk_grab_remove (widget); + + editable->has_selection = FALSE; + if (editable->selection_start_pos != editable->selection_end_pos) + { + if (gtk_selection_owner_set (widget, + GDK_SELECTION_PRIMARY, + event->time)) + { + editable->has_selection = TRUE; + gtk_text_update_text (editable, editable->selection_start_pos, + editable->selection_end_pos); + } + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + } + else if (event->button == 3) + { + gtk_grab_remove (widget); + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); } return FALSE; @@ -1189,7 +1361,13 @@ gtk_text_motion_notify (GtkWidget *widget, if (event->is_hint || (text->text_area != event->window)) gdk_window_get_pointer (text->text_area, &x, NULL, NULL); - /* update selection */ + undraw_cursor (GTK_TEXT (widget), FALSE); + find_mouse_cursor (GTK_TEXT (widget), event->x, event->y); + draw_cursor (GTK_TEXT (widget), FALSE); + + gtk_text_set_selection (GTK_EDITABLE(text), + GTK_EDITABLE(text)->selection_start_pos, + text->cursor_mark.index); return FALSE; } @@ -1204,16 +1382,29 @@ gtk_text_insert_1_at_point (GtkText* text, gchar key) &key, 1); } -static void -gtk_text_backward_delete_1_at_point (GtkText* text) +static void +gtk_text_insert_text (GtkEditable *editable, + const gchar *new_text, + guint new_text_length, + guint *position) { - gtk_text_backward_delete (text, 1); + GtkText *text = GTK_TEXT (editable); + + gtk_text_set_point (text, *position); + gtk_text_insert (text, NULL, NULL, NULL, new_text, new_text_length); + + *position = text->point.index; } -static void -gtk_text_forward_delete_1_at_point (GtkText* text) +static void +gtk_text_delete_text (GtkEditable *editable, + guint start_pos, + guint end_pos) { - gtk_text_forward_delete (text, 1); + GtkText *text = GTK_TEXT (editable); + + gtk_text_set_point (text, start_pos); + gtk_text_forward_delete (text, end_pos - start_pos); } static gint @@ -1221,6 +1412,7 @@ gtk_text_key_press (GtkWidget *widget, GdkEventKey *event) { GtkText *text; + GtkEditable *editable; gchar key; gint return_val; @@ -1231,11 +1423,12 @@ gtk_text_key_press (GtkWidget *widget, return_val = FALSE; text = GTK_TEXT (widget); + editable = GTK_EDITABLE (widget); key = event->keyval; return_val = TRUE; - if (text->is_editable == FALSE) + if (GTK_EDITABLE(text)->editable == FALSE) { switch (event->keyval) { @@ -1252,8 +1445,25 @@ gtk_text_key_press (GtkWidget *widget, } else { + gint extend_selection; + gint extend_start; + text->point = find_mark (text, text->cursor_mark.index); + extend_selection = event->state & GDK_SHIFT_MASK; + extend_start = FALSE; + + if (extend_selection) + { + if (editable->selection_start_pos == editable->selection_end_pos) + { + editable->selection_start_pos = text->point.index; + editable->selection_end_pos = text->point.index; + } + + extend_start = (text->point.index == editable->selection_start_pos); + } + switch (event->keyval) { case GDK_Home: move_cursor_buffer_ver (text, -1); break; @@ -1266,16 +1476,32 @@ gtk_text_key_press (GtkWidget *widget, case GDK_Right: move_cursor_hor (text, +1); break; case GDK_BackSpace: - if (!text->has_cursor || text->cursor_mark.index == 0) - break; - - gtk_text_backward_delete_1_at_point (text); + if (editable->selection_start_pos != editable->selection_end_pos) + { + gtk_editable_delete_selection (editable); + break; + } + if (text->has_cursor && text->cursor_mark.index != 0) + { + if (event->state & GDK_CONTROL_MASK) + gtk_text_delete_backward_word (text); + else + gtk_text_backward_delete (text, 1); + } break; case GDK_Delete: - if (!text->has_cursor || LAST_INDEX (text, text->cursor_mark)) - break; - - gtk_text_forward_delete_1_at_point (text); + if (editable->selection_start_pos != editable->selection_end_pos) + { + gtk_editable_delete_selection (editable); + break; + } + if (text->has_cursor && !LAST_INDEX(text, text->cursor_mark)) + { + if (event->state & GDK_CONTROL_MASK) + gtk_text_delete_forward_word (text); + else + gtk_text_forward_delete (text, 1); + } break; case GDK_Tab: if (!text->has_cursor) @@ -1305,9 +1531,9 @@ gtk_text_key_press (GtkWidget *widget, if ((key >= 'A') && (key <= 'Z')) key -= 'A' - 'a'; - if ((key >= 'a') && (key <= 'z') && text->control_keys[(int) (key - 'a')]) + if ((key >= 'a') && (key <= 'z') && control_keys[(int) (key - 'a')]) { - (* text->control_keys[(int) (key - 'a')]) (text); + (* control_keys[(int) (key - 'a')]) (editable, event); return_val = TRUE; } @@ -1318,9 +1544,9 @@ gtk_text_key_press (GtkWidget *widget, if ((key >= 'A') && (key <= 'Z')) key -= 'A' - 'a'; - if ((key >= 'a') && (key <= 'z') && text->alt_keys[(int) (key - 'a')]) + if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')]) { - (* text->alt_keys[(int) (key - 'a')]) (text); + (* alt_keys[(int) (key - 'a')]) (editable, event); return_val = TRUE; } @@ -1335,6 +1561,35 @@ gtk_text_key_press (GtkWidget *widget, else return_val = FALSE; } + editable->current_pos = text->cursor_mark.index; + + if (return_val) + { + if (extend_selection) + { + if (editable->current_pos < editable->selection_start_pos) + gtk_text_set_selection (editable, editable->current_pos, + editable->selection_end_pos); + else if (editable->current_pos > editable->selection_end_pos) + gtk_text_set_selection (editable, editable->selection_start_pos, + editable->current_pos); + else + { + if (extend_start) + gtk_text_set_selection (editable, editable->current_pos, + editable->selection_end_pos); + else + gtk_text_set_selection (editable, editable->selection_start_pos, + editable->current_pos); + } + } + else + gtk_text_set_selection (editable, 0, 0); + + gtk_editable_claim_selection (editable, + editable->selection_start_pos != editable->selection_end_pos, + event->time); + } } return return_val; @@ -1354,8 +1609,8 @@ gtk_text_focus_in (GtkWidget *widget, gtk_widget_draw_focus (widget); #ifdef USE_XIM - if (GTK_TEXT(widget)->ic) - gdk_im_begin (GTK_TEXT(widget)->ic, GTK_TEXT(widget)->text_area); + if (GTK_EDITABLE(widget)->ic) + gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_TEXT(widget)->text_area); #endif draw_cursor (GTK_TEXT(widget), TRUE); @@ -2175,14 +2430,16 @@ delete_text_property (GtkText* text, guint nchars) static void init_properties (GtkText *text) { + GtkWidget *widget = (GtkWidget *)text; + if (!text->text_properties) { text->text_properties = g_list_alloc(); text->text_properties->next = NULL; text->text_properties->prev = NULL; - text->text_properties->data = new_text_property (text->widget.style->font, - &text->widget.style->fg[GTK_STATE_NORMAL], - &text->widget.style->bg[GTK_STATE_NORMAL], + text->text_properties->data = new_text_property (widget->style->font, + &widget->style->text[GTK_STATE_NORMAL], + &widget->style->base[GTK_STATE_NORMAL], 1); text->text_properties_end = text->text_properties; @@ -2440,6 +2697,7 @@ static void find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height) { gchar ch; + GtkEditable *editable = (GtkEditable *)text; GtkPropertyMark mark = start_line->start; TabStopMark tab_mark = start_line->tab_cont.tab_start; @@ -2466,19 +2724,19 @@ find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_hei text->cursor_char = 0; #ifdef USE_XIM - if (gdk_im_ready() && text->ic && - gdk_ic_get_style (text->ic) & GdkIMPreeditPosition) + if (gdk_im_ready() && editable->ic && + gdk_ic_get_style (editable->ic) & GdkIMPreeditPosition) { GdkPoint spot; spot.x = text->cursor_pos_x; spot.y = text->cursor_pos_y - text->cursor_char_offset; if (MARK_CURRENT_FONT (&mark)->type == GDK_FONT_FONTSET) - gdk_ic_set_attr (text->ic, "preeditAttributes", + gdk_ic_set_attr (editable->ic, "preeditAttributes", "fontSet", GDK_FONT_XFONT (MARK_CURRENT_FONT (&mark)), NULL); - gdk_ic_set_attr (text->ic, "preeditAttributes", + gdk_ic_set_attr (editable->ic, "preeditAttributes", "spotLocation", &spot, "lineSpace", LINE_HEIGHT (*start_line), "foreground", MARK_CURRENT_FORE (&mark)->pixel, @@ -2506,7 +2764,7 @@ find_cursor (GtkText* text) } static void -mouse_click_1_at_line (GtkText *text, const LineParams* lp, +find_mouse_cursor_at_line (GtkText *text, const LineParams* lp, guint line_pixel_height, gint button_x) { @@ -2548,9 +2806,9 @@ mouse_click_1_at_line (GtkText *text, const LineParams* lp, } static void -mouse_click_1 (GtkText* text, GdkEventButton *event) +find_mouse_cursor (GtkText* text, gint x, gint y) { - if (text->is_editable) + if (GTK_EDITABLE(text)->editable) { gint pixel_height; GList* cache = text->line_start_cache; @@ -2565,9 +2823,9 @@ mouse_click_1 (GtkText* text, GdkEventButton *event) { pixel_height += LINE_HEIGHT(CACHE_DATA(cache)); - if (event->y < pixel_height || !cache->next) + if (y < pixel_height || !cache->next) { - mouse_click_1_at_line (text, &CACHE_DATA(cache), pixel_height, event->x); + find_mouse_cursor_at_line (text, &CACHE_DATA(cache), pixel_height, x); find_cursor (text); @@ -2714,6 +2972,185 @@ move_cursor_hor (GtkText *text, int count) draw_cursor (text, FALSE); } +static void +gtk_text_move_forward_character (GtkText *text) +{ + move_cursor_hor (text, 1); +} + +static void +gtk_text_move_backward_character (GtkText *text) +{ + move_cursor_hor (text, -1); +} + +static void +gtk_text_move_forward_word (GtkText *text) +{ + undraw_cursor (text, FALSE); + + while (!LAST_INDEX (text, text->cursor_mark) && + !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index))) + advance_mark (&text->cursor_mark); + + while (!LAST_INDEX (text, text->cursor_mark) && + isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index))) + advance_mark (&text->cursor_mark); + + find_cursor (text); + draw_cursor (text, FALSE); +} + +static void +gtk_text_move_backward_word (GtkText *text) +{ + undraw_cursor (text, FALSE); + + while ((text->cursor_mark.index > 0) && + !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index))) + decrement_mark (&text->cursor_mark); + + while ((text->cursor_mark.index > 0) && + isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index))) + decrement_mark (&text->cursor_mark); + + find_cursor (text); + draw_cursor (text, FALSE); +} + +static void +gtk_text_move_beginning_of_line (GtkText *text) +{ + undraw_cursor (text, FALSE); + text->cursor_mark = CACHE_DATA(text->current_line).start; + find_cursor (text); + draw_cursor (text, FALSE); +} + +static void +gtk_text_move_end_of_line (GtkText *text) +{ + undraw_cursor (text, FALSE); + text->cursor_mark = CACHE_DATA(text->current_line).end; + find_cursor (text); + draw_cursor (text, FALSE); +} + +static void +gtk_text_delete_forward_character (GtkText *text) +{ + GtkEditable *editable; + editable = GTK_EDITABLE (text); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); + else + { + gtk_text_forward_delete (text, 1); + gtk_editable_changed (editable); + } +} + +static void +gtk_text_delete_backward_character (GtkText *text) +{ + GtkEditable *editable; + editable = GTK_EDITABLE (text); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); + else + { + gtk_text_backward_delete (text, 1); + gtk_editable_changed (editable); + } +} + +static void +gtk_text_delete_forward_word (GtkText *text) +{ + guint old_pos; + + GtkEditable *editable; + editable = GTK_EDITABLE (text); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); + else + { + old_pos = text->cursor_mark.index; + gtk_text_move_forward_word (text); + gtk_text_backward_delete (text, old_pos - text->cursor_mark.index); + gtk_editable_changed (editable); + } +} + +static void +gtk_text_delete_backward_word (GtkText *text) +{ + gint old_pos; + + GtkEditable *editable; + editable = GTK_EDITABLE (text); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_delete_selection (editable); + else + { + old_pos = text->point.index; + gtk_text_move_backward_word (text); + gtk_text_forward_delete (text, text->point.index - old_pos); + gtk_editable_changed (editable); + } +} + +static void +gtk_text_delete_line (GtkText *text) +{ + gtk_text_set_point (text, CACHE_DATA(text->current_line).start.index); + gtk_text_forward_delete (text, + CACHE_DATA(text->current_line).end.index - + CACHE_DATA(text->current_line).start.index + 1); + + gtk_editable_changed (GTK_EDITABLE (text)); +} + +static void +gtk_text_delete_to_line_end (GtkText *text) +{ + gtk_text_forward_delete (text, + MAX(CACHE_DATA(text->current_line).end.index - + text->point.index, 1)); + + gtk_editable_changed (GTK_EDITABLE (text)); +} + +static void +gtk_text_select_word (GtkText *text) +{ + gint start_pos; + gint end_pos; + + GtkEditable *editable; + editable = GTK_EDITABLE (text); + + gtk_text_move_backward_word (text); + start_pos = text->cursor_mark.index; + + gtk_text_move_forward_word (text); + end_pos = text->cursor_mark.index; + + gtk_text_set_selection (editable, start_pos, end_pos); +} + +static void +gtk_text_select_line (GtkText *text) +{ + gtk_text_set_selection (GTK_EDITABLE (text), + CACHE_DATA(text->current_line).end.index, + CACHE_DATA(text->current_line).start.index); +} + /**********************************************************************/ /* Scrolling */ /**********************************************************************/ @@ -2948,14 +3385,8 @@ scroll_down (GtkText* text, gint diff0) cursor_min = drawn_cursor_min(text); if (cursor_min < 0) - { - GdkEventButton button; - - button.x = text->cursor_pos_x; - button.y = first_visible_line_height (text); - - mouse_click_1 (text, &button); - } + find_mouse_cursor (text, text->cursor_pos_x, + first_visible_line_height (text)); } if (height > real_diff) @@ -3025,14 +3456,8 @@ scroll_up (GtkText* text, gint diff0) gdk_window_get_size (text->text_area, NULL, &height); if (cursor_max >= height) - { - GdkEventButton button; - - button.x = text->cursor_pos_x; - button.y = last_visible_line_height(text); - - mouse_click_1 (text, &button); - } + find_mouse_cursor (text, text->cursor_pos_x, + last_visible_line_height (text)); } if (height > real_diff) @@ -3184,6 +3609,32 @@ expand_scratch_buffer (GtkText* text, guint len) } } +/* Returns a GC to draw a background for the text at a mark, + * or NULL, if the mark's background is NULL + * + * Side effect: modifies text->gc + */ +static GdkGC * +mark_bg_gc (GtkText* text, const GtkPropertyMark *mark) +{ + GtkEditable *editable = GTK_EDITABLE(text); + + if ((mark->index >= MIN(editable->selection_start_pos, editable->selection_end_pos) && + mark->index < MAX(editable->selection_start_pos, editable->selection_end_pos))) + { + if (editable->has_selection) + return GTK_WIDGET(text)->style->bg_gc[GTK_STATE_SELECTED]; + else + return GTK_WIDGET(text)->style->bg_gc[GTK_STATE_ACTIVE]; + } + else if (MARK_CURRENT_BACK (mark)) + { + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (mark)); + return text->gc; + } + return NULL; +} + static void draw_line (GtkText* text, gint pixel_start_height, @@ -3194,6 +3645,12 @@ draw_line (GtkText* text, gint len = 0; guint running_offset = lp->tab_cont.pixel_offset; guchar* buffer; + GdkGC *fg_gc, *bg_gc; + + GtkEditable *editable = GTK_EDITABLE(text); + + guint selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); + guint selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); GtkPropertyMark mark = lp->start; TabStopMark tab_mark = lp->tab_cont.tab_start; @@ -3221,17 +3678,19 @@ draw_line (GtkText* text, buffer = text->text + mark.index; } - if (running_offset > 0 && MARK_CURRENT_BACK (&mark)) + + if (running_offset > 0) { - gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); - - gdk_draw_rectangle (text->text_area, - text->gc, - TRUE, - 0, - pixel_start_height, - running_offset, - LINE_HEIGHT (*lp)); + bg_gc = mark_bg_gc (text, &mark); + + if (bg_gc) + gdk_draw_rectangle (text->text_area, + bg_gc, + TRUE, + 0, + pixel_start_height, + running_offset, + LINE_HEIGHT (*lp)); } for (; chars > 0; chars -= len, buffer += len, len = 0) @@ -3247,6 +3706,11 @@ draw_line (GtkText* text, if (next_tab) len = MIN (len, next_tab - buffer); + if (mark.index < selection_start_pos) + len = MIN (len, selection_start_pos - mark.index); + else if (mark.index < selection_end_pos) + len = MIN (len, selection_end_pos - mark.index); + font = MARK_CURRENT_PROPERTY (&mark)->font->gdk_font; if (font->type == GDK_FONT_FONT) { @@ -3257,24 +3721,33 @@ draw_line (GtkText* text, } else pixel_width = gdk_text_width (font, (gchar*) buffer, len); - - if (MARK_CURRENT_BACK (&mark)) + + bg_gc = mark_bg_gc (text, &mark); + if (bg_gc) + gdk_draw_rectangle (text->text_area, + bg_gc, + TRUE, + running_offset, + pixel_start_height, + pixel_width, + LINE_HEIGHT(*lp)); + + if ((mark.index >= selection_start_pos) && + (mark.index < selection_end_pos)) { - gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); - - gdk_draw_rectangle (text->text_area, - text->gc, - TRUE, - running_offset, - pixel_start_height, - pixel_width, - LINE_HEIGHT(*lp)); + if (editable->has_selection) + fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_SELECTED]; + else + fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_ACTIVE]; + } + else + { + gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (&mark)); + fg_gc = text->gc; } - - gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (&mark)); gdk_draw_text (text->text_area, MARK_CURRENT_FONT (&mark), - text->gc, + fg_gc, running_offset, pixel_height, (gchar*) buffer, @@ -3288,7 +3761,8 @@ draw_line (GtkText* text, { len = 1; - if (MARK_CURRENT_BACK (&mark)) + bg_gc = mark_bg_gc (text, &mark); + if (bg_gc) { gint pixels_remaining; gint space_width; @@ -3302,10 +3776,8 @@ draw_line (GtkText* text, spaces_avail = pixels_remaining / space_width; spaces_avail = MIN (spaces_avail, tab_mark.to_next_tab); - gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); - gdk_draw_rectangle (text->text_area, - text->gc, + bg_gc, TRUE, running_offset, pixel_start_height, @@ -3352,7 +3824,7 @@ draw_line_wrap (GtkText* text, guint height /* baseline height */) gdk_gc_set_fill (text->gc, GDK_STIPPLED); - gdk_gc_set_foreground (text->gc, &text->widget.style->fg[GTK_STATE_NORMAL]); + gdk_gc_set_foreground (text->gc, >K_WIDGET (text)->style->text[GTK_STATE_NORMAL]); gdk_gc_set_ts_origin (text->gc, width + 1, @@ -3379,7 +3851,8 @@ undraw_cursor (GtkText* text, gint absolute) if (absolute) text->cursor_drawn_level = 0; - if (text->has_cursor && (text->cursor_drawn_level ++ == 0)) + if (text->has_cursor && (text->cursor_drawn_level ++ == 0) && + (GTK_EDITABLE(text)->selection_start_pos == GTK_EDITABLE(text)->selection_end_pos)) { GdkFont* font; @@ -3387,7 +3860,7 @@ undraw_cursor (GtkText* text, gint absolute) font = MARK_CURRENT_FONT(&text->cursor_mark); - if (text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + if (GTK_WIDGET (text)->style->bg_pixmap[GTK_STATE_NORMAL]) { GdkRectangle rect; @@ -3403,7 +3876,7 @@ undraw_cursor (GtkText* text, gint absolute) if (MARK_CURRENT_BACK (&text->cursor_mark)) gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&text->cursor_mark)); else - gdk_gc_set_foreground (text->gc, &text->widget.style->bg[GTK_STATE_NORMAL]); + gdk_gc_set_foreground (text->gc, >K_WIDGET (text)->style->base[GTK_STATE_NORMAL]); gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x, text->cursor_pos_y - text->cursor_char_offset, text->cursor_pos_x, @@ -3469,7 +3942,8 @@ draw_cursor (GtkText* text, gint absolute) if (absolute) text->cursor_drawn_level = 1; - if (text->has_cursor && (--text->cursor_drawn_level == 0)) + if (text->has_cursor && (--text->cursor_drawn_level == 0) && + (GTK_EDITABLE(text)->selection_start_pos == GTK_EDITABLE(text)->selection_end_pos)) { GdkFont* font; @@ -3477,7 +3951,7 @@ draw_cursor (GtkText* text, gint absolute) font = MARK_CURRENT_FONT (&text->cursor_mark); - gdk_gc_set_foreground (text->gc, &text->widget.style->fg[GTK_STATE_NORMAL]); + gdk_gc_set_foreground (text->gc, >K_WIDGET (text)->style->text[GTK_STATE_NORMAL]); gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x, text->cursor_pos_y - text->cursor_char_offset, @@ -3489,13 +3963,15 @@ draw_cursor (GtkText* text, gint absolute) static void clear_area (GtkText *text, GdkRectangle *area) { - if (text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + GtkWidget *widget = GTK_WIDGET (text); + + if (widget->style->bg_pixmap[GTK_STATE_NORMAL]) { gint width, height; gint x = area->x, y = area->y; gint xorig, yorig; - gdk_window_get_size (text->widget.style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); + gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); yorig = - text->first_onscreen_ver_pixel; xorig = - text->first_onscreen_hor_pixel; @@ -3512,7 +3988,7 @@ clear_area (GtkText *text, GdkRectangle *area) gdk_draw_pixmap (text->text_area, text->gc, - text->widget.style->bg_pixmap[GTK_STATE_NORMAL], + widget->style->bg_pixmap[GTK_STATE_NORMAL], xoff, yoff, x, @@ -3555,7 +4031,7 @@ expose_text (GtkText* text, GdkRectangle *area, gboolean cursor) draw_line_wrap (text, pixels + CACHE_DATA(cache).font_ascent); } - if (cursor && text->has_cursor && GTK_WIDGET_HAS_FOCUS (&text->widget)) + if (cursor && text->has_cursor && GTK_WIDGET_HAS_FOCUS (text)) { if (CACHE_DATA(cache).start.index <= text->cursor_mark.index && CACHE_DATA(cache).end.index >= text->cursor_mark.index) @@ -3574,6 +4050,56 @@ expose_text (GtkText* text, GdkRectangle *area, gboolean cursor) } } +static void +gtk_text_update_text (GtkEditable *editable, + guint start_pos, + guint end_pos) +{ + GtkText *text = GTK_TEXT (editable); + + GList *cache = text->line_start_cache; + gint pixels = - text->first_cut_pixels; + GdkRectangle area; + gint width; + gint height; + + gdk_window_get_size (text->text_area, &width, &height); + area.x = 0; + area.y = -1; + area.width = width; + area.height = 0; + + TDEBUG (("in expose span start=%d stop=%d\n", start_pos, end_pos)); + + for (; pixels < height; cache = cache->next) + { + if (CACHE_DATA(cache).start.index < end_pos) + { + if (CACHE_DATA(cache).end.index >= start_pos) + { + if (area.y < 0) + area.y = pixels; + area.height = pixels + LINE_HEIGHT(CACHE_DATA(cache)) - area.y; + } + } + else + break; + + pixels += LINE_HEIGHT(CACHE_DATA(cache)); + + if (!cache->next) + { + fetch_lines_forward (text, 1); + + if (!cache->next) + break; + } + } + + if (area.y >= 0) + expose_text (text, &area, TRUE); +} + static void recompute_geometry (GtkText* text) { @@ -3600,99 +4126,43 @@ recompute_geometry (GtkText* text) /* Selection */ /**********************************************************************/ -static gint -gtk_text_selection_clear (GtkWidget *widget, - GdkEventSelection *event) +void +gtk_text_set_selection (GtkEditable *editable, + guint start, + guint end) { -#if 0 - GtkEntry *entry; + GtkText *text = GTK_TEXT (editable); - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); + guint start1 = MIN(start,end); + guint end1 = MAX(start,end); + guint start2 = MIN(editable->selection_start_pos, editable->selection_end_pos); + guint end2 = MAX(editable->selection_start_pos, editable->selection_end_pos); - entry = GTK_ENTRY (widget); - - if (entry->have_selection) + if (start2 < start1) { - entry->have_selection = FALSE; - gtk_entry_queue_draw (entry); - } -#endif - return FALSE; -} - -static gint -gtk_text_selection_request (GtkWidget *widget, - GdkEventSelection *event) -{ -#if 0 - - GtkEntry *entry; - gint selection_start_pos; - gint selection_end_pos; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - entry = GTK_ENTRY (widget); - if (entry->selection_start_pos != entry->selection_end_pos) - { - selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); - selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); - - gdk_selection_set (event->requestor, event->selection, - event->property, event->time, - (guchar*) &entry->text[selection_start_pos], - selection_end_pos - selection_start_pos); - } -#endif - return FALSE; -} - -static gint -gtk_text_selection_notify (GtkWidget *widget, - GdkEventSelection *event) -{ -#if 0 - GtkEntry *entry; - gchar *data; - gint tmp_pos; - gint reselect; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - entry = GTK_ENTRY (widget); + guint tmp; - gdk_selection_get (widget->window, (guchar**) &data); - - reselect = FALSE; - if (entry->selection_start_pos != entry->selection_end_pos) - { - reselect = TRUE; - gtk_delete_selection (entry); + tmp = start1; start1 = start2; start2 = tmp; + tmp = end1; end1 = end2; end2 = tmp; } - tmp_pos = entry->current_pos; - gtk_entry_insert_text (entry, data, strlen (data), &tmp_pos); + undraw_cursor (text, FALSE); + editable->selection_start_pos = start; + editable->selection_end_pos = end; + draw_cursor (text, FALSE); - if (reselect) - { - reselect = entry->have_selection; - gtk_select_region (entry, entry->current_pos, tmp_pos); - entry->have_selection = reselect; - } + /* Expose only what changed */ - entry->current_pos = tmp_pos; + if (start1 < start2) + gtk_text_update_text (editable, start1, MIN(end1, start2)); - gtk_entry_queue_draw (entry); -#endif - return FALSE; + if (end2 > end1) + gtk_text_update_text (editable, MAX(end1, start2), end2); + else if (end2 < end1) + gtk_text_update_text (editable, end2, end1); } + /**********************************************************************/ /* Debug */ /**********************************************************************/ diff --git a/gtk/gtktext.h b/gtk/gtktext.h index 7ae0cd12f..d10c63a20 100644 --- a/gtk/gtktext.h +++ b/gtk/gtktext.h @@ -21,7 +21,7 @@ #include <gdk/gdk.h> #include <gtk/gtkadjustment.h> -#include <gtk/gtkwidget.h> +#include <gtk/gtkeditable.h> #ifdef __cplusplus @@ -38,8 +38,6 @@ typedef struct _GtkPropertyMark GtkPropertyMark; typedef struct _GtkText GtkText; typedef struct _GtkTextClass GtkTextClass; -typedef void (*GtkTextFunction) (GtkText *text); - struct _GtkPropertyMark { /* Position in list. */ @@ -54,7 +52,7 @@ struct _GtkPropertyMark struct _GtkText { - GtkWidget widget; + GtkEditable editable; GdkWindow *text_area; @@ -66,8 +64,6 @@ struct _GtkText GdkPixmap* line_wrap_bitmap; GdkPixmap* line_arrow_bitmap; - GdkIC ic; - /* GAPPED TEXT SEGMENT */ /* The text, a single segment of text a'la emacs, with a gap @@ -96,24 +92,17 @@ struct _GtkText /* First visible horizontal pixel. */ guint first_onscreen_hor_pixel; /* First visible vertical pixel. */ - guint first_onscreen_ver_pixel; + guint first_onscreen_ver_pixel; /* FLAGS */ /* True iff the cursor has been placed yet. */ guint has_cursor : 1; - /* True iff this buffer is editable. (Allowing a cursor to be placed). */ - guint is_editable : 1; /* True iff this buffer is wrapping lines, otherwise it is using a * horizontal scrollbar. */ guint line_wrap : 1; /* Frozen, don't do updates. @@@ fixme */ guint freeze : 1; - /* Whether a selection. */ - guint has_selection : 1; - /* Whether the selection is in the clipboard. */ - guint own_selection : 1; - /* Whether it has been realized yet. */ /* TEXT PROPERTIES */ @@ -155,20 +144,11 @@ struct _GtkText GList *tab_stops; gint default_tab_width; - /* Key bindings */ - - GtkTextFunction control_keys[26]; - GtkTextFunction alt_keys[26]; - - /* Selection nonsense. */ - - guint selection_start; - guint selection_stop; }; struct _GtkTextClass { - GtkWidgetClass parent_class; + GtkEditableClass parent_class; }; @@ -197,9 +177,9 @@ gint gtk_text_backward_delete (GtkText *text, gint gtk_text_forward_delete (GtkText *text, guint nchars); -gchar * gtk_text_get_chars (GtkText *text, - guint index, - guint nchars); +void gtk_text_select_region (GtkText *entry, + guint start, + guint end); #define GTK_TEXT_INDEX(t, index) \ ((index) < (t)->gap_position ? (t)->text[index] : \ |