diff options
Diffstat (limited to 'gtk')
34 files changed, 5482 insertions, 3535 deletions
diff --git a/gtk/.cvsignore b/gtk/.cvsignore index 1a313c90c2..d93b49fe11 100644 --- a/gtk/.cvsignore +++ b/gtk/.cvsignore @@ -19,6 +19,7 @@ testtree gtkcompat.h testthreads libgtk.la +gtkfeatures.h gtkmarshal.h gtktypebuiltins.h gtkmarshal.c @@ -30,3 +31,5 @@ testdnd stamp-gtktypebuiltins.h stamp-gtkmarshal.h stamp-gtk.defs +gtk-query-immodules-2.0 +gtk.immodules diff --git a/gtk/Makefile.am b/gtk/Makefile.am index e05b165c06..060d12154c 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -104,6 +104,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \ gtkiconfactory.h \ gtkimage.h \ gtkimcontext.h \ + gtkimmodule.h \ gtkimmulticontext.h \ gtkinputdialog.h \ gtkinvisible.h \ @@ -124,6 +125,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \ gtkmisc.h \ gtkmodelsimple.h \ gtknotebook.h \ + gtkoldeditable.h \ gtkobject.h \ gtkoptionmenu.h \ gtkpacker.h \ @@ -163,7 +165,6 @@ gtk_public_h_sources = @STRIP_BEGIN@ \ gtktexttagtable.h \ gtktextview.h \ gtktext.h \ - gtkthemes.h \ gtktipsquery.h \ gtktogglebutton.h \ gtktoolbar.h \ @@ -198,6 +199,7 @@ gtk_private_h_sources = @STRIP_BEGIN@ \ gtktextiterprivate.h \ gtktextmarkprivate.h \ gtktexttagprivate.h \ + gtkthemes.h \ gtktreeprivate.h \ @STRIP_END@ # GTK+ C sources to build the library from @@ -257,6 +259,7 @@ gtk_c_sources = @STRIP_BEGIN@ \ gtkimcontext.c \ gtkimcontextsimple.c \ gtkimcontextsimple.h \ + gtkimmodule.c \ gtkimmulticontext.c \ gtkinputdialog.c \ gtkintl.h \ @@ -279,6 +282,7 @@ gtk_c_sources = @STRIP_BEGIN@ \ gtkmodelsimple.c \ gtknotebook.c \ gtkobject.c \ + gtkoldeditable.c \ gtkoptionmenu.c \ gtkpacker.c \ gtkpaned.c \ @@ -543,11 +547,9 @@ install-data-local: uninstall-local: rm -f $(DESTDIR)$(datadir)/themes/Default/gtk-2.0/gtkrc -# -# test programs, not to be installed -# -noinst_PROGRAMS = testgtk testcalendar testinput testselection testrgb testdnd testtext simple treestoretest testtextbuffer # testthreads -DEPS = @gtktargetlib@ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-1.3.la $(top_builddir)/gdk/@gdktargetlib@ +DEPS = @gtktargetlib@ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-1.3.la $(top_builddir)/gdk/@gdktargetlib@ +TEST_DEPS = $(DEPS) gtk.immodules + LDADDS = @STRIP_BEGIN@ \ @gtktargetlib@ \ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-1.3.la \ @@ -561,25 +563,44 @@ LDADDS = @STRIP_BEGIN@ \ -lm \ @STRIP_END@ -testgtk_DEPENDENCIES = $(DEPS) -testcalendar_DEPENDENCIES = $(DEPS) -testinput_DEPENDENCIES = $(DEPS) -testselection_DEPENDENCIES = $(DEPS) -testrgb_DEPENDENCIES = $(DEPS) -testtext_DEPENDENCIES = $(DEPS) -testtextbuffer_DEPENDENCIES = $(DEPS) -treestoretest_DEPENDENCIES = $(DEPS) -testdnd_DEPENDENCIES = $(DEPS) -simple_DEPENDENCIES = $(DEPS) -#testthreads_DEPENDENCIES = $(DEPS) +# +# Installed tools +# +bin_PROGRAMS = gtk-query-immodules-2.0 + +gtk_query_immodules_2_0_DEPENDENCIES = $(DEPS) +gtk_query_immodules_2_0_LDADD = $(LDADDS) + +gtk_query_immodules_2_0_SOURCES = queryimmodules.c + +gtk.immodules: gtk-query-immodules-2.0 + ./gtk-query-immodules-2.0 ../modules/input/.libs/*.so > gtk.immodules + +# +# test programs, not to be installed +# +noinst_PROGRAMS = testgtk testcalendar testinput testselection testrgb testdnd testtext simple treestoretest testtextbuffer # testthreads + +testcalendar_DEPENDENCIES = $(TEST_DEPS) +testgtk_DEPENDENCIES = $(TEST_DEPS) +testinput_DEPENDENCIES = $(TEST_DEPS) +testrgb_DEPENDENCIES = $(TEST_DEPS) +testselection_DEPENDENCIES = $(TEST_DEPS) +testtext_DEPENDENCIES = $(TEST_DEPS) +testtextbuffer_DEPENDENCIES = $(TEST_DEPS) +treestoretest_DEPENDENCIES = $(TEST_DEPS) +testdnd_DEPENDENCIES = $(TEST_DEPS) +simple_DEPENDENCIES = $(TEST_DEPS) +#testthreads_DEPENDENCIES = $(TEST_DEPS) + testcalendar_LDADD = $(LDADDS) testgtk_LDADD = $(LDADDS) testinput_LDADD = $(LDADDS) +testrgb_LDADD = $(LDADDS) testselection_LDADD = $(LDADDS) testtext_LDADD = $(LDADDS) -treestoretest_LDADD = $(LDADDS) testtextbuffer_LDADD = $(LDADDS) -testrgb_LDADD = $(LDADDS) +treestoretest_LDADD = $(LDADDS) testdnd_LDADD = $(LDADDS) simple_LDADD = $(LDADDS) #testthreads_LDADD = $(LDADDS) @@ -104,6 +104,7 @@ #include <gtk/gtkmodelsimple.h> #include <gtk/gtknotebook.h> #include <gtk/gtkobject.h> +#include <gtk/gtkoldeditable.h> #include <gtk/gtkoptionmenu.h> #include <gtk/gtkpacker.h> #include <gtk/gtkpaned.h> @@ -133,7 +134,6 @@ #include <gtk/gtktext.h> #include <gtk/gtktextbuffer.h> #include <gtk/gtktextview.h> -#include <gtk/gtkthemes.h> #include <gtk/gtktipsquery.h> #include <gtk/gtktogglebutton.h> #include <gtk/gtktoolbar.h> diff --git a/gtk/gtkcellrenderertextpixbuf.c b/gtk/gtkcellrenderertextpixbuf.c index d2fe42dac4..694538a2b6 100644 --- a/gtk/gtkcellrenderertextpixbuf.c +++ b/gtk/gtkcellrenderertextpixbuf.c @@ -60,7 +60,7 @@ static void gtk_cell_renderer_text_pixbuf_render (GtkCellRenderer guint flags); -GtkCellRendererTextClass *parent_class = NULL; +static GtkCellRendererTextClass *parent_class = NULL; GtkType diff --git a/gtk/gtkcombo.c b/gtk/gtkcombo.c index 03cb0faab6..dea6d8956c 100644 --- a/gtk/gtkcombo.c +++ b/gtk/gtkcombo.c @@ -132,6 +132,7 @@ gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * com /* completion */ if ((event->keyval == GDK_Tab) && (event->state & GDK_MOD1_MASK)) { + GtkEditable *editable = GTK_EDITABLE (entry); GCompletion * cmpl; gchar* prefix; gchar* nprefix = NULL; @@ -145,16 +146,16 @@ gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * com cmpl = g_completion_new ((GCompletionFunc)gtk_combo_func); g_completion_add_items (cmpl, GTK_LIST (combo->list)->children); - pos = GTK_EDITABLE (entry)->current_pos; - prefix = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, pos); + pos = gtk_editable_get_position (editable); + prefix = gtk_editable_get_chars (editable, 0, pos); g_completion_complete(cmpl, prefix, &nprefix); if (nprefix && strlen (nprefix) > strlen (prefix)) { - gtk_editable_insert_text (GTK_EDITABLE (entry), nprefix + pos, - strlen (nprefix) - strlen (prefix), &pos); - GTK_EDITABLE (entry)->current_pos = pos; + gtk_editable_insert_text (editable, nprefix + pos, + strlen (nprefix) - strlen (prefix), &pos); + gtk_editable_set_position (editable, pos); } if (nprefix) diff --git a/gtk/gtkeditable.c b/gtk/gtkeditable.c index 76ee618fda..b2ea905c33 100644 --- a/gtk/gtkeditable.c +++ b/gtk/gtkeditable.c @@ -24,91 +24,11 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include <ctype.h> #include <string.h> -#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 { - CHANGED, - INSERT_TEXT, - DELETE_TEXT, - /* Binding actions */ - ACTIVATE, - SET_EDITABLE, - MOVE_CURSOR, - MOVE_WORD, - MOVE_PAGE, - MOVE_TO_ROW, - MOVE_TO_COLUMN, - KILL_CHAR, - KILL_WORD, - KILL_LINE, - CUT_CLIPBOARD, - COPY_CLIPBOARD, - PASTE_CLIPBOARD, - LAST_SIGNAL -}; - -enum { - ARG_0, - ARG_TEXT_POSITION, - ARG_EDITABLE -}; - -/* values for selection info */ - -enum { - TARGET_STRING, - TARGET_TEXT, - TARGET_COMPOUND_TEXT -}; - -static void gtk_editable_class_init (GtkEditableClass *klass); -static void gtk_editable_init (GtkEditable *editable); -static void gtk_editable_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_editable_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void *gtk_editable_get_public_chars (GtkEditable *editable, - gint start, - gint end); -static gint gtk_editable_selection_clear (GtkWidget *widget, - GdkEventSelection *event); -static void gtk_editable_selection_get (GtkWidget *widget, - GtkSelectionData *selection_data, - guint info, - guint time); -static void gtk_editable_selection_received (GtkWidget *widget, - GtkSelectionData *selection_data, - guint time); - -static void gtk_editable_set_selection (GtkEditable *editable, - gint start, - gint end); -static guint32 gtk_editable_get_event_time (GtkEditable *editable); - -static void gtk_editable_real_cut_clipboard (GtkEditable *editable); -static void gtk_editable_real_copy_clipboard (GtkEditable *editable); -static void gtk_editable_real_paste_clipboard (GtkEditable *editable); -static void gtk_editable_real_set_editable (GtkEditable *editable, - gboolean is_editable); - -static GtkWidgetClass *parent_class = NULL; -static guint editable_signals[LAST_SIGNAL] = { 0 }; - -static GdkAtom clipboard_atom = GDK_NONE; - GtkType gtk_editable_get_type (void) { @@ -116,331 +36,32 @@ gtk_editable_get_type (void) if (!editable_type) { - static const GtkTypeInfo editable_info = + static const GTypeInfo editable_info = { - "GtkEditable", - sizeof (GtkEditable), - sizeof (GtkEditableClass), - (GtkClassInitFunc) gtk_editable_class_init, - (GtkObjectInitFunc) gtk_editable_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, + sizeof (GtkEditableClass), /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ }; - editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &editable_info); + editable_type = g_type_register_static (G_TYPE_INTERFACE, "GtkEditable", &editable_info, 0); } 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_TYPE_WIDGET); - - editable_signals[CHANGED] = - gtk_signal_new ("changed", - GTK_RUN_LAST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, changed), - gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); - - editable_signals[INSERT_TEXT] = - gtk_signal_new ("insert_text", - GTK_RUN_LAST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, insert_text), - gtk_marshal_VOID__POINTER_INT_POINTER, - 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, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, delete_text), - gtk_marshal_VOID__INT_INT, - GTK_TYPE_NONE, - 2, - GTK_TYPE_INT, - GTK_TYPE_INT); - - editable_signals[ACTIVATE] = - gtk_signal_new ("activate", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, activate), - gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); - widget_class->activate_signal = editable_signals[ACTIVATE]; - - editable_signals[SET_EDITABLE] = - gtk_signal_new ("set-editable", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, set_editable), - gtk_marshal_VOID__BOOLEAN, - GTK_TYPE_NONE, 1, - GTK_TYPE_BOOL); - - editable_signals[MOVE_CURSOR] = - gtk_signal_new ("move_cursor", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, move_cursor), - gtk_marshal_VOID__INT_INT, - GTK_TYPE_NONE, 2, - GTK_TYPE_INT, - GTK_TYPE_INT); - - editable_signals[MOVE_WORD] = - gtk_signal_new ("move_word", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, move_word), - gtk_marshal_VOID__INT, - GTK_TYPE_NONE, 1, - GTK_TYPE_INT); - - editable_signals[MOVE_PAGE] = - gtk_signal_new ("move_page", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, move_page), - gtk_marshal_VOID__INT_INT, - GTK_TYPE_NONE, 2, - GTK_TYPE_INT, - GTK_TYPE_INT); - - editable_signals[MOVE_TO_ROW] = - gtk_signal_new ("move_to_row", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, move_to_row), - gtk_marshal_VOID__INT, - GTK_TYPE_NONE, 1, - GTK_TYPE_INT); - - editable_signals[MOVE_TO_COLUMN] = - gtk_signal_new ("move_to_column", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, move_to_column), - gtk_marshal_VOID__INT, - GTK_TYPE_NONE, 1, - GTK_TYPE_INT); - - editable_signals[KILL_CHAR] = - gtk_signal_new ("kill_char", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, kill_char), - gtk_marshal_VOID__INT, - GTK_TYPE_NONE, 1, - GTK_TYPE_INT); - - editable_signals[KILL_WORD] = - gtk_signal_new ("kill_word", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, kill_word), - gtk_marshal_VOID__INT, - GTK_TYPE_NONE, 1, - GTK_TYPE_INT); - - editable_signals[KILL_LINE] = - gtk_signal_new ("kill_line", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, kill_line), - gtk_marshal_VOID__INT, - GTK_TYPE_NONE, 1, - GTK_TYPE_INT); - - editable_signals[CUT_CLIPBOARD] = - gtk_signal_new ("cut_clipboard", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, cut_clipboard), - gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); - - editable_signals[COPY_CLIPBOARD] = - gtk_signal_new ("copy_clipboard", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, copy_clipboard), - gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); - - editable_signals[PASTE_CLIPBOARD] = - gtk_signal_new ("paste_clipboard", - GTK_RUN_LAST | GTK_RUN_ACTION, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkEditableClass, paste_clipboard), - gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL); - - gtk_object_add_arg_type ("GtkEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION); - gtk_object_add_arg_type ("GtkEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE); - - object_class->set_arg = gtk_editable_set_arg; - object_class->get_arg = gtk_editable_get_arg; - - widget_class->selection_clear_event = gtk_editable_selection_clear; - widget_class->selection_received = gtk_editable_selection_received; - widget_class->selection_get = gtk_editable_selection_get; - - class->insert_text = NULL; - class->delete_text = NULL; - - class->activate = NULL; - class->set_editable = gtk_editable_real_set_editable; - - class->move_cursor = NULL; - class->move_word = NULL; - class->move_page = NULL; - class->move_to_row = NULL; - class->move_to_column = NULL; - - class->kill_char = NULL; - class->kill_word = NULL; - class->kill_line = NULL; - - class->cut_clipboard = gtk_editable_real_cut_clipboard; - class->copy_clipboard = gtk_editable_real_copy_clipboard; - class->paste_clipboard = gtk_editable_real_paste_clipboard; - - class->update_text = NULL; - class->get_chars = NULL; - class->set_selection = NULL; - class->set_position = NULL; -} - -static void -gtk_editable_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) -{ - GtkEditable *editable; - - editable = GTK_EDITABLE (object); - - switch (arg_id) - { - case ARG_TEXT_POSITION: - gtk_editable_set_position (editable, GTK_VALUE_INT (*arg)); - break; - case ARG_EDITABLE: - gtk_editable_set_editable (editable, GTK_VALUE_BOOL (*arg)); - break; - default: - break; - } -} - -static void -gtk_editable_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) -{ - GtkEditable *editable; - - editable = GTK_EDITABLE (object); - - switch (arg_id) - { - case ARG_TEXT_POSITION: - GTK_VALUE_INT (*arg) = editable->current_pos; - break; - case ARG_EDITABLE: - GTK_VALUE_BOOL (*arg) = editable->editable; - break; - default: - arg->type = GTK_TYPE_INVALID; - break; - } -} - -static void -gtk_editable_init (GtkEditable *editable) -{ - static const GtkTargetEntry targets[] = { - { "STRING", 0, TARGET_STRING }, - { "TEXT", 0, TARGET_TEXT }, - { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT } - }; - static const gint n_targets = sizeof(targets) / sizeof(targets[0]); - - 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->visible = 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_targets (GTK_WIDGET (editable), GDK_SELECTION_PRIMARY, - targets, n_targets); - gtk_selection_add_targets (GTK_WIDGET (editable), clipboard_atom, - targets, n_targets); -} - void gtk_editable_insert_text (GtkEditable *editable, const gchar *new_text, gint new_text_length, gint *position) { - GtkEditableClass *klass; - gchar buf[64]; - gchar *text; - - g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - - gtk_widget_ref (GTK_WIDGET (editable)); - - klass = GTK_EDITABLE_GET_CLASS (editable); + g_return_if_fail (position != NULL); if (new_text_length < 0) new_text_length = strlen (new_text); - 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); - - gtk_widget_unref (GTK_WIDGET (editable)); + GTK_EDITABLE_GET_CLASS (editable)->insert_text (editable, new_text, new_text_length, position); } void @@ -448,360 +69,67 @@ gtk_editable_delete_text (GtkEditable *editable, gint start_pos, gint end_pos) { - GtkEditableClass *klass; - - g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - gtk_widget_ref (GTK_WIDGET (editable)); - - klass = GTK_EDITABLE_GET_CLASS (editable); - - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[DELETE_TEXT], start_pos, end_pos); - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]); - - gtk_widget_unref (GTK_WIDGET (editable)); -} - -static void -gtk_editable_update_text (GtkEditable *editable, - gint start_pos, - gint end_pos) -{ - GtkEditableClass *klass; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - - klass = GTK_EDITABLE_GET_CLASS (editable); - - klass->update_text (editable, start_pos, end_pos); + GTK_EDITABLE_GET_CLASS (editable)->delete_text (editable, start_pos, end_pos); } gchar * -gtk_editable_get_chars (GtkEditable *editable, - gint start, - gint end) -{ - GtkEditableClass *klass; - - g_return_val_if_fail (editable != NULL, NULL); - g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL); - - klass = GTK_EDITABLE_GET_CLASS (editable); - - return klass->get_chars (editable, start, end); -} - -/* - * Like gtk_editable_get_chars, but if the editable is not - * visible, return asterisks - */ -static void * -gtk_editable_get_public_chars (GtkEditable *editable, - gint start, - gint end) -{ - if (editable->visible) - return gtk_editable_get_chars (editable, start, end); - else - { - gint i; - gint nchars = end - start; - gchar *str; - - if (nchars < 0) - nchars = -nchars; - - str = g_new (gchar, nchars + 1); - for (i = 0; i<nchars; i++) - str[i] = '*'; - str[i] = '\0'; - - return str; - } -} - -static void -gtk_editable_set_selection (GtkEditable *editable, - gint start_pos, - gint end_pos) +gtk_editable_get_chars (GtkEditable *editable, + gint start, + gint end) { - GtkEditableClass *klass; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); + g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE); - klass = GTK_EDITABLE_GET_CLASS (editable); - - klass->set_selection (editable, start_pos, end_pos); + return GTK_EDITABLE_GET_CLASS (editable)->get_chars (editable, start, end); } void gtk_editable_set_position (GtkEditable *editable, gint position) { - GtkEditableClass *klass; - - g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - klass = GTK_EDITABLE_GET_CLASS (editable); - - klass->set_position (editable, position); + GTK_EDITABLE_GET_CLASS (editable)->set_position (editable, position); } gint gtk_editable_get_position (GtkEditable *editable) { - g_return_val_if_fail (editable != NULL, -1); - g_return_val_if_fail (GTK_IS_EDITABLE (editable), -1); - - return editable->current_pos; -} + g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0); -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 */ - if (!gtk_selection_clear (widget, event)) - return FALSE; - - 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 TRUE; + return GTK_EDITABLE_GET_CLASS (editable)->get_position (editable); } -static void -gtk_editable_selection_get (GtkWidget *widget, - GtkSelectionData *selection_data, - guint info, - guint time) +gboolean +gtk_editable_get_selection_bounds (GtkEditable *editable, + gint *start_pos, + gint *end_pos) { - 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_public_chars(editable, - selection_start_pos, - selection_end_pos); - if (!str) - return; /* Refuse */ - length = strlen (str); - } - else /* CLIPBOARD */ - { - if (!editable->clipboard_text) - return; /* Refuse */ - - str = editable->clipboard_text; - length = strlen (editable->clipboard_text); - } + gint tmp_start, tmp_end; + gboolean result; - if (info == TARGET_STRING) - { - gtk_selection_data_set (selection_data, - GDK_SELECTION_TYPE_STRING, - 8*sizeof(gchar), (guchar *)str, length); - } - else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT)) - { - 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, - guint time) -{ - 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 == gdk_atom_intern ("COMPOUND_TEXT", FALSE)) || - (selection_data->type == gdk_atom_intern ("TEXT", FALSE))) - 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, time); - return; - } - - reselect = FALSE; + g_return_val_if_fail (GTK_IS_EDITABLE (editable), 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); - } + result = GTK_EDITABLE_GET_CLASS (editable)->get_selection_bounds (editable, &tmp_start, &tmp_end); - tmp_pos = old_pos = editable->current_pos; + if (start_pos) + *start_pos = MIN (tmp_start, tmp_end); + if (end_pos) + *end_pos = MAX (tmp_start, tmp_end); - switch (type) - { - case STRING: - selection_data->data[selection_data->length] = 0; - gtk_editable_insert_text (editable, (gchar *)selection_data->data, - strlen ((gchar *)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); + return result; } void gtk_editable_delete_selection (GtkEditable *editable) { - guint start; - guint end; + gint start, end; - g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - if (!editable->editable) - return; - - start = editable->selection_start_pos; - end = editable->selection_end_pos; - - editable->selection_start_pos = 0; - editable->selection_end_pos = 0; - - if (start != end) - gtk_editable_delete_text (editable, MIN (start, end), MAX (start,end)); - - 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 (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - g_return_if_fail (GTK_WIDGET_REALIZED (editable)); - - editable->has_selection = FALSE; - - 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); - } + if (gtk_editable_get_selection_bounds (editable, &start, &end)) + gtk_editable_delete_text (editable, start, end); } void @@ -809,57 +137,9 @@ gtk_editable_select_region (GtkEditable *editable, gint start, gint end) { - g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - if (GTK_WIDGET_REALIZED (editable)) - gtk_editable_claim_selection (editable, start != end, GDK_CURRENT_TIME); - - gtk_editable_set_selection (editable, start, end); -} - -/* Get the timestamp of the current event. Actually, the only thing - * we really care about below is the key event - */ -static guint32 -gtk_editable_get_event_time (GtkEditable *editable) -{ - GdkEvent *event; - guint32 tm = GDK_CURRENT_TIME; - - event = gtk_get_current_event(); - - if (event) - switch (event->type) - { - case GDK_MOTION_NOTIFY: - tm = event->motion.time; break; - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - case GDK_BUTTON_RELEASE: - tm = event->button.time; break; - case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: - tm = event->key.time; break; - case GDK_ENTER_NOTIFY: - case GDK_LEAVE_NOTIFY: - tm = event->crossing.time; break; - case GDK_PROPERTY_NOTIFY: - tm = event->property.time; break; - case GDK_SELECTION_CLEAR: - case GDK_SELECTION_REQUEST: - case GDK_SELECTION_NOTIFY: - tm = event->selection.time; break; - case GDK_PROXIMITY_IN: - case GDK_PROXIMITY_OUT: - tm = event->proximity.time; break; - default: /* use current time */ - break; - } - gdk_event_free(event); - - return tm; + GTK_EDITABLE_GET_CLASS (editable)->set_selection_bounds (editable, start, end); } void @@ -868,7 +148,7 @@ gtk_editable_cut_clipboard (GtkEditable *editable) g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CUT_CLIPBOARD]); + gtk_signal_emit_by_name (GTK_OBJECT (editable), "cut_clipboard"); } void @@ -877,7 +157,7 @@ gtk_editable_copy_clipboard (GtkEditable *editable) g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[COPY_CLIPBOARD]); + gtk_signal_emit_by_name (GTK_OBJECT (editable), "copy_clipboard"); } void @@ -886,85 +166,16 @@ gtk_editable_paste_clipboard (GtkEditable *editable) g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[PASTE_CLIPBOARD]); + gtk_signal_emit_by_name (GTK_OBJECT (editable), "paste_clipboard"); } void gtk_editable_set_editable (GtkEditable *editable, gboolean is_editable) { - g_return_if_fail (editable != NULL); g_return_if_fail (GTK_IS_EDITABLE (editable)); - - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[SET_EDITABLE], is_editable != FALSE); -} -static void -gtk_editable_real_set_editable (GtkEditable *editable, - gboolean is_editable) -{ - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - - editable->editable = is_editable != FALSE; - gtk_widget_queue_draw (GTK_WIDGET (editable)); -} - -static void -gtk_editable_real_cut_clipboard (GtkEditable *editable) -{ - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - - gtk_editable_real_copy_clipboard (editable); - gtk_editable_delete_selection (editable); -} - -static void -gtk_editable_real_copy_clipboard (GtkEditable *editable) -{ - guint32 time; - gint selection_start_pos; - gint selection_end_pos; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - - time = gtk_editable_get_event_time (editable); - 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, - time)) - editable->clipboard_text = gtk_editable_get_public_chars (editable, - selection_start_pos, - selection_end_pos); - } -} - -static void -gtk_editable_real_paste_clipboard (GtkEditable *editable) -{ - guint32 time; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - - time = gtk_editable_get_event_time (editable); - if (editable->editable) - gtk_selection_convert (GTK_WIDGET(editable), - clipboard_atom, - gdk_atom_intern ("COMPOUND_TEXT", FALSE), time); -} - -void -gtk_editable_changed (GtkEditable *editable) -{ - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_EDITABLE (editable)); - - gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]); + gtk_object_set (GTK_OBJECT (editable), + "editable", is_editable != FALSE, + NULL); } diff --git a/gtk/gtkeditable.h b/gtk/gtkeditable.h index 55c1c22e9e..9fb5ba06ad 100644 --- a/gtk/gtkeditable.h +++ b/gtk/gtkeditable.h @@ -31,132 +31,73 @@ #include <gdk/gdk.h> #include <gtk/gtkwidget.h> - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#define GTK_TYPE_EDITABLE (gtk_editable_get_type ()) -#define GTK_EDITABLE(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_EDITABLE, GtkEditable)) -#define GTK_EDITABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_EDITABLE, GtkEditableClass)) -#define GTK_IS_EDITABLE(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_EDITABLE)) -#define GTK_IS_EDITABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_EDITABLE)) -#define GTK_EDITABLE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_EDITABLE, GtkEditableClass)) - +#define GTK_TYPE_EDITABLE (gtk_editable_get_type ()) +#define GTK_EDITABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_EDITABLE, GtkEditable)) +#define GTK_EDITABLE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_EDITABLE, GtkEditableClass)) +#define GTK_IS_EDITABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_EDITABLE)) +#define GTK_IS_EDITABLE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_EDITABLE)) +#define GTK_EDITABLE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_EDITABLE, GtkEditableClass)) -typedef struct _GtkEditable GtkEditable; +typedef struct _GtkEditable GtkEditable; /* Dummy typedef */ typedef struct _GtkEditableClass GtkEditableClass; -typedef void (*GtkTextFunction) (GtkEditable *editable, guint32 time); - -struct _GtkEditable -{ - GtkWidget widget; - - /*< public >*/ - guint current_pos; - - guint selection_start_pos; - guint selection_end_pos; - guint has_selection : 1; - - /*< private >*/ - guint editable : 1; - guint visible : 1; - GdkIC *ic; - GdkICAttr *ic_attr; - - gchar *clipboard_text; -}; - struct _GtkEditableClass { - GtkWidgetClass parent_class; + GTypeInterface base_iface; /* Signals for notification/filtering of changes */ - void (* changed) (GtkEditable *editable); - void (* insert_text) (GtkEditable *editable, - const gchar *text, - gint length, - gint *position); - void (* delete_text) (GtkEditable *editable, - gint start_pos, - gint end_pos); - - /* Bindings actions */ - void (* activate) (GtkEditable *editable); - void (* set_editable) (GtkEditable *editable, - gboolean is_editable); - void (* move_cursor) (GtkEditable *editable, - gint x, - gint y); - void (* move_word) (GtkEditable *editable, - gint n); - void (* move_page) (GtkEditable *editable, - gint x, - gint y); - void (* move_to_row) (GtkEditable *editable, - gint row); - void (* move_to_column) (GtkEditable *editable, - gint row); - void (* kill_char) (GtkEditable *editable, - gint direction); - void (* kill_word) (GtkEditable *editable, - gint direction); - void (* kill_line) (GtkEditable *editable, - gint direction); - void (* cut_clipboard) (GtkEditable *editable); - void (* copy_clipboard) (GtkEditable *editable); - void (* paste_clipboard) (GtkEditable *editable); - - /* Virtual functions. get_chars is in paricular not a signal because - * it returns malloced memory. The others are not signals because - * they would not be particularly useful as such. (All changes to - * selection and position do not go through these functions) - */ - void (* update_text) (GtkEditable *editable, - gint start_pos, - gint end_pos); - gchar* (* get_chars) (GtkEditable *editable, - gint start_pos, - gint end_pos); - void (* set_selection)(GtkEditable *editable, - gint start_pos, - gint end_pos); - void (* set_position) (GtkEditable *editable, - gint position); + void (* insert_text) (GtkEditable *editable, + const gchar *text, + gint length, + gint *position); + void (* delete_text) (GtkEditable *editable, + gint start_pos, + gint end_pos); + gchar* (* get_chars) (GtkEditable *editable, + gint start_pos, + gint end_pos); + void (* set_selection_bounds) (GtkEditable *editable, + gint start_pos, + gint end_pos); + gboolean (* get_selection_bounds) (GtkEditable *editable, + gint *start_pos, + gint *end_pos); + void (* set_position) (GtkEditable *editable, + gint position); + gint (* get_position) (GtkEditable *editable); }; -GtkType gtk_editable_get_type (void) G_GNUC_CONST; -void gtk_editable_select_region (GtkEditable *editable, - gint start, - gint end); -void gtk_editable_insert_text (GtkEditable *editable, - const gchar *new_text, - gint new_text_length, - gint *position); -void gtk_editable_delete_text (GtkEditable *editable, - gint start_pos, - gint end_pos); -gchar* gtk_editable_get_chars (GtkEditable *editable, - gint start_pos, - gint end_pos); -void gtk_editable_cut_clipboard (GtkEditable *editable); -void gtk_editable_copy_clipboard (GtkEditable *editable); -void gtk_editable_paste_clipboard (GtkEditable *editable); -void gtk_editable_claim_selection (GtkEditable *editable, - gboolean claim, - guint32 time); -void gtk_editable_delete_selection (GtkEditable *editable); - -void gtk_editable_changed (GtkEditable *editable); -void gtk_editable_set_position (GtkEditable *editable, - gint position); -gint gtk_editable_get_position (GtkEditable *editable); -void gtk_editable_set_editable (GtkEditable *editable, - gboolean is_editable); - +GtkType gtk_editable_get_type (void) G_GNUC_CONST; +void gtk_editable_select_region (GtkEditable *editable, + gint start, + gint end); +gboolean gtk_editable_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end); +void gtk_editable_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position); +void gtk_editable_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos); +gchar* gtk_editable_get_chars (GtkEditable *editable, + gint start_pos, + gint end_pos); +void gtk_editable_cut_clipboard (GtkEditable *editable); +void gtk_editable_copy_clipboard (GtkEditable *editable); +void gtk_editable_paste_clipboard (GtkEditable *editable); +void gtk_editable_delete_selection (GtkEditable *editable); +void gtk_editable_set_position (GtkEditable *editable, + gint position); +gint gtk_editable_get_position (GtkEditable *editable); +void gtk_editable_set_editable (GtkEditable *editable, + gboolean is_editable); #ifdef __cplusplus } diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 050709181a..fcffeedf4b 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -24,19 +24,21 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include <ctype.h> #include <string.h> + +#include <pango/pango.h> + #include "gdk/gdkkeysyms.h" -#include "gdk/gdki18n.h" +#include "gtkbindings.h" +#include "gtkclipboard.h" #include "gtkentry.h" #include "gtkimmulticontext.h" +#include "gtkintl.h" #include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" #include "gtkselection.h" #include "gtksignal.h" -#include "gtkstyle.h" - -#include <pango/pango.h> -#include <glib-object.h> #define MIN_ENTRY_WIDTH 150 #define DRAW_TIMEOUT 20 @@ -49,13 +51,34 @@ #define MAX_SIZE G_MAXUSHORT enum { + INSERT_TEXT, + DELETE_TEXT, + CHANGED, + ACTIVATE, + MOVE_CURSOR, + INSERT_AT_CURSOR, + DELETE_FROM_CURSOR, + CUT_CLIPBOARD, + COPY_CLIPBOARD, + PASTE_CLIPBOARD, + TOGGLE_OVERWRITE, + LAST_SIGNAL +}; + +enum { ARG_0, + ARG_TEXT_POSITION, + ARG_EDITABLE, ARG_MAX_LENGTH, ARG_VISIBILITY }; +static guint signals[LAST_SIGNAL] = { 0 }; +/* GObject, GtkObject methods + */ static void gtk_entry_class_init (GtkEntryClass *klass); +static void gtk_entry_editable_init (GtkEditableClass *iface); static void gtk_entry_init (GtkEntry *entry); static void gtk_entry_set_arg (GtkObject *object, GtkArg *arg, @@ -64,15 +87,18 @@ static void gtk_entry_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void gtk_entry_finalize (GObject *object); + +/* GtkWidget methods + */ static void gtk_entry_realize (GtkWidget *widget); static void gtk_entry_unrealize (GtkWidget *widget); -static void gtk_entry_draw_focus (GtkWidget *widget); static void gtk_entry_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gtk_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void gtk_entry_draw (GtkWidget *widget, GdkRectangle *area); +static void gtk_entry_draw_focus (GtkWidget *widget); static gint gtk_entry_expose (GtkWidget *widget, GdkEventExpose *event); static gint gtk_entry_button_press (GtkWidget *widget, @@ -87,145 +113,100 @@ static gint gtk_entry_focus_in (GtkWidget *widget, GdkEventFocus *event); static gint gtk_entry_focus_out (GtkWidget *widget, GdkEventFocus *event); -static void gtk_entry_draw_text (GtkEntry *entry); -static void gtk_entry_ensure_layout (GtkEntry *entry); -static void gtk_entry_draw_cursor (GtkEntry *entry); static void gtk_entry_style_set (GtkWidget *widget, GtkStyle *previous_style); static void gtk_entry_direction_changed (GtkWidget *widget, GtkTextDirection previous_dir); static void gtk_entry_state_changed (GtkWidget *widget, GtkStateType previous_state); -static void gtk_entry_queue_draw (GtkEntry *entry); -static gint gtk_entry_find_position (GtkEntry *entry, - gint x); -static void gtk_entry_get_cursor_locations (GtkEntry *entry, - gint *strong_x, - gint *weak_x); -static void entry_adjust_scroll (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 (GtkEditable *editable, - gint start_pos, - gint end_pos); -static void gtk_entry_update_text (GtkEditable *editable, - gint start_pos, - gint end_pos); -static gchar *gtk_entry_get_chars (GtkEditable *editable, - gint start_pos, - gint end_pos); - -/* Binding actions */ -static void gtk_entry_move_cursor (GtkEditable *editable, - gint x, - gint y); -static void gtk_entry_move_word (GtkEditable *editable, - gint n); -static void gtk_entry_move_to_column (GtkEditable *editable, - gint row); -static void gtk_entry_kill_char (GtkEditable *editable, - gint direction); -static void gtk_entry_kill_word (GtkEditable *editable, - gint direction); -static void gtk_entry_kill_line (GtkEditable *editable, - gint direction); - -/* To be removed */ -static void gtk_move_forward_character (GtkEntry *entry); -static void gtk_move_backward_character (GtkEntry *entry); -static void gtk_move_forward_word (GtkEntry *entry); -static void gtk_move_backward_word (GtkEntry *entry); -static void gtk_move_beginning_of_line (GtkEntry *entry); -static void gtk_move_end_of_line (GtkEntry *entry); -static void gtk_delete_forward_character (GtkEntry *entry); -static void gtk_delete_backward_character (GtkEntry *entry); -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_select_word (GtkEntry *entry, - guint32 time); -static void gtk_select_line (GtkEntry *entry, - guint32 time); - - -static void gtk_entry_set_selection (GtkEditable *editable, - gint start, - gint end); - -static void gtk_entry_set_position_from_editable (GtkEditable *editable, - gint position); +/* GtkEditable method implementations + */ +static void gtk_entry_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_entry_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos); +static gchar * gtk_entry_get_chars (GtkEditable *editable, + gint start_pos, + gint end_pos); +static void gtk_entry_real_set_position (GtkEditable *editable, + gint position); +static gint gtk_entry_get_position (GtkEditable *editable); +static void gtk_entry_set_selection_bounds (GtkEditable *editable, + gint start, + gint end); +static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end); + +/* Default signal handlers + */ +static void gtk_entry_real_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_entry_real_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos); +static void gtk_entry_move (GtkEntry *entry, + GtkMovementStep step, + gint count, + gboolean extend_selection); +static void gtk_entry_insert (GtkEntry *entry, + const gchar *str); +static void gtk_entry_delete (GtkEntry *entry, + GtkDeleteType type, + gint count); +static void gtk_entry_cut_clipboard (GtkEntry *entry); +static void gtk_entry_copy_clipboard (GtkEntry *entry); +static void gtk_entry_paste_clipboard (GtkEntry *entry); +static void gtk_entry_toggle_overwrite (GtkEntry *entry); + +/* IM Context Callbacks + */ static void gtk_entry_commit_cb (GtkIMContext *context, const gchar *str, GtkEntry *entry); - +static void gtk_entry_preedit_changed_cb (GtkIMContext *context, + GtkEntry *entry); +/* Internal routines + */ +static void gtk_entry_draw_text (GtkEntry *entry); +static void gtk_entry_draw_cursor (GtkEntry *entry); +static PangoLayout *gtk_entry_get_layout (GtkEntry *entry, + gboolean include_preedit); +static void gtk_entry_queue_draw (GtkEntry *entry); +static void gtk_entry_reset_im_context (GtkEntry *entry); +static void gtk_entry_recompute (GtkEntry *entry); +static gint gtk_entry_find_position (GtkEntry *entry, + gint x); +static void gtk_entry_get_cursor_locations (GtkEntry *entry, + gint *strong_x, + gint *weak_x); +static void gtk_entry_adjust_scroll (GtkEntry *entry); +static gint gtk_entry_move_visually (GtkEntry *editable, + gint start, + gint count); +static gint gtk_entry_move_forward_word (GtkEntry *entry, + gint start); +static gint gtk_entry_move_backward_word (GtkEntry *entry, + gint start); +static void gtk_entry_delete_whitespace (GtkEntry *entry); +static void gtk_entry_select_word (GtkEntry *entry); +static void gtk_entry_select_line (GtkEntry *entry); +static char * gtk_entry_get_public_chars (GtkEntry *entry, + gint start, + gint end); +static void gtk_entry_paste (GtkEntry *entry, + GdkAtom selection); +static void gtk_entry_update_primary_selection (GtkEntry *entry); +static void gtk_entry_popup_menu (GtkEntry *entry, + GdkEventButton *event); static GtkWidgetClass *parent_class = NULL; -static GdkAtom ctext_atom = GDK_NONE; - -static const GtkTextFunction control_keys[26] = -{ - (GtkTextFunction)gtk_move_beginning_of_line, /* a */ - (GtkTextFunction)gtk_move_backward_character, /* b */ - (GtkTextFunction)gtk_editable_copy_clipboard, /* c */ - (GtkTextFunction)gtk_delete_forward_character, /* d */ - (GtkTextFunction)gtk_move_end_of_line, /* e */ - (GtkTextFunction)gtk_move_forward_character, /* f */ - NULL, /* g */ - (GtkTextFunction)gtk_delete_backward_character, /* h */ - NULL, /* i */ - NULL, /* j */ - (GtkTextFunction)gtk_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_delete_line, /* u */ - (GtkTextFunction)gtk_editable_paste_clipboard, /* v */ - (GtkTextFunction)gtk_delete_backward_word, /* w */ - (GtkTextFunction)gtk_editable_cut_clipboard, /* x */ - NULL, /* y */ - NULL, /* z */ -}; - -static const GtkTextFunction alt_keys[26] = -{ - NULL, /* a */ - (GtkTextFunction)gtk_move_backward_word, /* b */ - NULL, /* c */ - (GtkTextFunction)gtk_delete_forward_word, /* d */ - NULL, /* e */ - (GtkTextFunction)gtk_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 */ -}; - GtkType gtk_entry_get_type (void) @@ -245,31 +226,291 @@ gtk_entry_get_type (void) /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; + + static const GInterfaceInfo editable_info = + { + (GInterfaceInitFunc) gtk_entry_editable_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; - entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info); + entry_type = gtk_type_unique (GTK_TYPE_WIDGET, &entry_info); + g_type_add_interface_static (entry_type, + GTK_TYPE_EDITABLE, + &editable_info); } return entry_type; } static void +add_move_binding (GtkBindingSet *binding_set, + guint keyval, + guint modmask, + GtkMovementStep step, + gint count) +{ + g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0); + + gtk_binding_entry_add_signal (binding_set, keyval, modmask, + "move_cursor", 3, + GTK_TYPE_ENUM, step, + G_TYPE_INT, count, + G_TYPE_BOOLEAN, FALSE); + + /* Selection-extending version */ + gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK, + "move_cursor", 3, + GTK_TYPE_ENUM, step, + G_TYPE_INT, count, + G_TYPE_BOOLEAN, TRUE); +} + +static void gtk_entry_class_init (GtkEntryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkObjectClass *object_class; GtkWidgetClass *widget_class; - GtkEditableClass *editable_class; + + GtkBindingSet *binding_set; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; - editable_class = (GtkEditableClass*) class; - parent_class = gtk_type_class (GTK_TYPE_EDITABLE); + parent_class = gtk_type_class (GTK_TYPE_WIDGET); gobject_class->finalize = gtk_entry_finalize; - gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH); - gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY); + gtk_object_add_arg_type ("GtkEntry::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION); + gtk_object_add_arg_type ("GtkEntry::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE); + gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH); + gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY); + + signals[INSERT_TEXT] = + gtk_signal_new ("insert_text", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, insert_text), + gtk_marshal_VOID__STRING_INT_POINTER, + GTK_TYPE_NONE, + 3, + GTK_TYPE_STRING, + GTK_TYPE_INT, + GTK_TYPE_POINTER); + + signals[DELETE_TEXT] = + gtk_signal_new ("delete_text", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, delete_text), + gtk_marshal_VOID__INT_INT, + GTK_TYPE_NONE, + 2, + GTK_TYPE_INT, + GTK_TYPE_INT); + + signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, changed), + gtk_marshal_VOID__VOID, + GTK_TYPE_NONE, 0); + + /* Action signals */ + + signals[ACTIVATE] = + gtk_signal_new ("activate", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, activate), + gtk_marshal_VOID__VOID, + GTK_TYPE_NONE, 0); + + widget_class->activate_signal = signals[ACTIVATE]; + + signals[MOVE_CURSOR] = + gtk_signal_new ("move_cursor", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, move), + gtk_marshal_VOID__ENUM_INT_BOOLEAN, + GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL); + + signals[INSERT_AT_CURSOR] = + gtk_signal_new ("insert_at_cursor", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, insert), + gtk_marshal_VOID__STRING, + GTK_TYPE_NONE, 1, GTK_TYPE_STRING); + + signals[DELETE_FROM_CURSOR] = + gtk_signal_new ("delete_from_cursor", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, delete), + gtk_marshal_VOID__ENUM_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT); + + signals[CUT_CLIPBOARD] = + gtk_signal_new ("cut_clipboard", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, cut_clipboard), + gtk_marshal_VOID__VOID, + GTK_TYPE_NONE, 0); + + signals[COPY_CLIPBOARD] = + gtk_signal_new ("copy_clipboard", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, copy_clipboard), + gtk_marshal_VOID__VOID, + GTK_TYPE_NONE, 0); + + signals[PASTE_CLIPBOARD] = + gtk_signal_new ("paste_clipboard", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, paste_clipboard), + gtk_marshal_VOID__VOID, + GTK_TYPE_NONE, 0); + + signals[TOGGLE_OVERWRITE] = + gtk_signal_new ("toggle_overwrite", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkEntryClass, toggle_overwrite), + gtk_marshal_VOID__VOID, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + + /* + * Key bindings + */ + binding_set = gtk_binding_set_by_class (class); + + /* Moving the insertion point */ + add_move_binding (binding_set, GDK_Right, 0, + GTK_MOVEMENT_POSITIONS, 1); + + add_move_binding (binding_set, GDK_Left, 0, + GTK_MOVEMENT_POSITIONS, -1); + + add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK, + GTK_MOVEMENT_CHARS, 1); + + add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK, + GTK_MOVEMENT_CHARS, -1); + + add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, + GTK_MOVEMENT_WORDS, 1); + + add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, + GTK_MOVEMENT_WORDS, -1); + + add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK, + GTK_MOVEMENT_PARAGRAPH_ENDS, -1); + + add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK, + GTK_MOVEMENT_PARAGRAPH_ENDS, 1); + + add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK, + GTK_MOVEMENT_WORDS, 1); + + add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK, + GTK_MOVEMENT_WORDS, -1); + + add_move_binding (binding_set, GDK_Home, 0, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + + add_move_binding (binding_set, GDK_End, 0, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + + add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK, + GTK_MOVEMENT_BUFFER_ENDS, -1); + + add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK, + GTK_MOVEMENT_BUFFER_ENDS, 1); + + /* Deleting text */ + gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_CHARS, + GTK_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_CHARS, + GTK_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_CHARS, + GTK_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS, + GTK_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS, + GTK_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS, + GTK_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS, + GTK_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS, + GTK_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE, + GTK_TYPE_INT, 1); + gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK, + "insert_at_cursor", 1, + GTK_TYPE_STRING, " "); + + gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK, + "delete_from_cursor", 2, + GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE, + GTK_TYPE_INT, 1); + + /* Cut/copy/paste */ + + gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK, + "cut_clipboard", 0); + + gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK, + "cut_clipboard", 0); + + gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK, + "copy_clipboard", 0); + + gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK, + "paste_clipboard", 0); + + gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK, + "paste_clipboard", 0); + + /* Overwrite */ + gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0, + "toggle_overwrite", 0); + object_class->set_arg = gtk_entry_set_arg; object_class->get_arg = gtk_entry_get_arg; @@ -290,22 +531,27 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->direction_changed = gtk_entry_direction_changed; widget_class->state_changed = gtk_entry_state_changed; - editable_class->insert_text = gtk_entry_insert_text; - editable_class->delete_text = gtk_entry_delete_text; - editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll; - - editable_class->move_cursor = gtk_entry_move_cursor; - editable_class->move_word = gtk_entry_move_word; - editable_class->move_to_column = gtk_entry_move_to_column; - - editable_class->kill_char = gtk_entry_kill_char; - editable_class->kill_word = gtk_entry_kill_word; - editable_class->kill_line = gtk_entry_kill_line; + class->insert_text = gtk_entry_real_insert_text; + class->delete_text = gtk_entry_real_delete_text; + class->move = gtk_entry_move; + class->insert = gtk_entry_insert; + class->delete = gtk_entry_delete; + class->cut_clipboard = gtk_entry_cut_clipboard; + class->copy_clipboard = gtk_entry_copy_clipboard; + class->paste_clipboard = gtk_entry_paste_clipboard; + class->toggle_overwrite = gtk_entry_toggle_overwrite; +} - 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->set_position = gtk_entry_set_position_from_editable; +static void +gtk_entry_editable_init (GtkEditableClass *iface) +{ + iface->insert_text = gtk_entry_insert_text; + iface->delete_text = gtk_entry_delete_text; + iface->get_chars = gtk_entry_get_chars; + iface->set_selection_bounds = gtk_entry_set_selection_bounds; + iface->get_selection_bounds = gtk_entry_get_selection_bounds; + iface->set_position = gtk_entry_real_set_position; + iface->get_position = gtk_entry_get_position; } static void @@ -313,12 +559,23 @@ gtk_entry_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - GtkEntry *entry; - - entry = GTK_ENTRY (object); + GtkEntry *entry = GTK_ENTRY (object); switch (arg_id) { + case ARG_TEXT_POSITION: + gtk_editable_set_position (GTK_EDITABLE (object), GTK_VALUE_INT (*arg)); + break; + case ARG_EDITABLE: + { + gboolean new_value = GTK_VALUE_BOOL (*arg) != 0; + if (new_value != entry->editable) + { + entry->editable = new_value; + gtk_entry_queue_draw (entry); + } + } + break; case ARG_MAX_LENGTH: gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg)); break; @@ -341,11 +598,17 @@ gtk_entry_get_arg (GtkObject *object, switch (arg_id) { + case ARG_TEXT_POSITION: + GTK_VALUE_INT (*arg) = entry->current_pos; + break; + case ARG_EDITABLE: + GTK_VALUE_BOOL (*arg) = entry->editable; + break; case ARG_MAX_LENGTH: GTK_VALUE_UINT (*arg) = entry->text_max_length; break; case ARG_VISIBILITY: - GTK_VALUE_BOOL (*arg) = GTK_EDITABLE (entry)->visible; + GTK_VALUE_BOOL (*arg) = entry->visible; break; default: arg->type = GTK_TYPE_INVALID; @@ -358,20 +621,12 @@ gtk_entry_init (GtkEntry *entry) { GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS); - entry->text_area = NULL; - entry->text_size = MIN_SIZE; entry->text = g_malloc (entry->text_size); entry->text[0] = '\0'; - - entry->text_length = 0; - entry->text_max_length = 0; - entry->n_bytes = 0; - entry->scroll_offset = 0; - entry->timer = 0; - entry->button = 0; - entry->ascent = 0; - entry->descent = 0; + + entry->editable = TRUE; + entry->visible = TRUE; /* This object is completely private. No external entity can gain a reference * to it; so we create it here and destroy it in finalize(). @@ -380,124 +635,8 @@ gtk_entry_init (GtkEntry *entry) gtk_signal_connect (GTK_OBJECT (entry->im_context), "commit", GTK_SIGNAL_FUNC (gtk_entry_commit_cb), entry); -} - -GtkWidget* -gtk_entry_new (void) -{ - return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY)); -} - -GtkWidget* -gtk_entry_new_with_max_length (guint16 max) -{ - GtkEntry *entry; - - entry = gtk_type_new (GTK_TYPE_ENTRY); - entry->text_max_length = max; - - return GTK_WIDGET (entry); -} - -void -gtk_entry_set_text (GtkEntry *entry, - const gchar *text) -{ - 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); - - editable = GTK_EDITABLE (entry); - - gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length); - - tmp_pos = 0; - gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos); - editable->current_pos = tmp_pos; -} - -void -gtk_entry_append_text (GtkEntry *entry, - const gchar *text) -{ - gint tmp_pos; - - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - g_return_if_fail (text != NULL); - - tmp_pos = entry->text_length; - gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos); -} - -void -gtk_entry_prepend_text (GtkEntry *entry, - const gchar *text) -{ - gint tmp_pos; - - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - g_return_if_fail (text != NULL); - - tmp_pos = 0; - gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos); -} - -void -gtk_entry_set_position (GtkEntry *entry, - gint position) -{ - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - if ((position == -1) || (position > entry->text_length)) - GTK_EDITABLE(entry)->current_pos = entry->text_length; - else - GTK_EDITABLE(entry)->current_pos = position; - entry_adjust_scroll (entry); -} - -static void -gtk_entry_set_position_from_editable (GtkEditable *editable, - gint position) -{ - gtk_entry_set_position (GTK_ENTRY (editable), position); -} - -void -gtk_entry_set_visibility (GtkEntry *entry, - gboolean visible) -{ - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - GTK_EDITABLE (entry)->visible = visible ? TRUE : FALSE; - - gtk_entry_queue_draw (entry); -} - -void -gtk_entry_set_editable(GtkEntry *entry, - gboolean editable) -{ - g_return_if_fail (entry != NULL); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - gtk_editable_set_editable (GTK_EDITABLE (entry), editable); -} - -gchar* -gtk_entry_get_text (GtkEntry *entry) -{ - g_return_val_if_fail (entry != NULL, NULL); - g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - - return entry->text; + gtk_signal_connect (GTK_OBJECT (entry->im_context), "preedit_changed", + GTK_SIGNAL_FUNC (gtk_entry_preedit_changed_cb), entry); } static void @@ -509,13 +648,16 @@ gtk_entry_finalize (GObject *object) entry = GTK_ENTRY (object); - if (entry->layout) - g_object_unref (G_OBJECT (entry->layout)); + if (entry->cached_layout) + g_object_unref (G_OBJECT (entry->cached_layout)); gtk_object_unref (GTK_OBJECT (entry->im_context)); if (entry->timer) - gtk_timeout_remove (entry->timer); + g_source_remove (entry->timer); + + if (entry->recompute_idle) + g_source_remove (entry->recompute_idle); entry->text_size = 0; @@ -559,10 +701,7 @@ gtk_entry_realize (GtkWidget *widget) GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_KEY_PRESS_MASK); + GDK_POINTER_MOTION_HINT_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); @@ -572,7 +711,7 @@ gtk_entry_realize (GtkWidget *widget) attributes.y = widget->style->ythickness; attributes.width = widget->allocation.width - attributes.x * 2; attributes.height = requisition.height - attributes.y * 2; - attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM); + attributes.cursor = gdk_cursor_new (GDK_XTERM); attributes_mask |= GDK_WA_CURSOR; entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); @@ -585,12 +724,9 @@ gtk_entry_realize (GtkWidget *widget) gdk_window_show (entry->text_area); - if (editable->selection_start_pos != editable->selection_end_pos) - gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); - gtk_im_context_set_client_window (entry->im_context, entry->text_area); - entry_adjust_scroll (entry); + gtk_entry_adjust_scroll (entry); } static void @@ -610,53 +746,16 @@ gtk_entry_unrealize (GtkWidget *widget) gdk_window_set_user_data (entry->text_area, NULL); gdk_window_destroy (entry->text_area); entry->text_area = NULL; - gdk_cursor_destroy (entry->cursor); - entry->cursor = NULL; } + if (entry->popup_menu) + gtk_widget_destroy (entry->popup_menu); + if (GTK_WIDGET_CLASS (parent_class)->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static void -gtk_entry_draw_focus (GtkWidget *widget) -{ - gint width, height; - gint x, y; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_ENTRY (widget)); - - if (GTK_WIDGET_DRAWABLE (widget)) - { - x = 0; - y = 0; - gdk_window_get_size (widget->window, &width, &height); - - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - x += 1; - y += 1; - width -= 2; - height -= 2; - } - - gtk_paint_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_IN, - NULL, widget, "entry", - x, y, width, height); - - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - gdk_window_get_size (widget->window, &width, &height); - gtk_paint_focus (widget->style, widget->window, - NULL, widget, "entry", - 0, 0, width - 1, height - 1); - } - } -} - -static void gtk_entry_size_request (GtkWidget *widget, GtkRequisition *requisition) { @@ -671,13 +770,11 @@ gtk_entry_size_request (GtkWidget *widget, entry = GTK_ENTRY (widget); - gtk_entry_ensure_layout (entry); - /* hackish for now, get metrics */ - font = pango_context_load_font (pango_layout_get_context (entry->layout), + font = pango_context_load_font (gtk_widget_get_pango_context (widget), widget->style->font_desc); - lang = pango_context_get_lang (pango_layout_get_context (entry->layout)); + lang = pango_context_get_lang (gtk_widget_get_pango_context (widget)); pango_font_get_metrics (font, lang, &metrics); g_free (lang); @@ -725,8 +822,7 @@ gtk_entry_size_allocate (GtkWidget *widget, allocation->width - widget->style->xthickness * 2, requisition.height - widget->style->ythickness * 2); - /* And make sure the cursor is on screen */ - entry_adjust_scroll (entry); + gtk_entry_recompute (entry); } } @@ -757,6 +853,44 @@ gtk_entry_draw (GtkWidget *widget, } } +static void +gtk_entry_draw_focus (GtkWidget *widget) +{ + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + x = 0; + y = 0; + gdk_window_get_size (widget->window, &width, &height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + + gtk_paint_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + NULL, widget, "entry", + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gdk_window_get_size (widget->window, &width, &height); + gtk_paint_focus (widget->style, widget->window, + NULL, widget, "entry", + 0, 0, width - 1, height - 1); + } + } +} + static gint gtk_entry_expose (GtkWidget *widget, GdkEventExpose *event) @@ -784,49 +918,44 @@ static gint gtk_entry_button_press (GtkWidget *widget, GdkEventButton *event) { - GtkEntry *entry; - GtkEditable *editable; + GtkEntry *entry = GTK_ENTRY (widget); + GtkEditable *editable = GTK_EDITABLE (widget); gint tmp_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); - - if (ctext_atom == GDK_NONE) - ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); - entry = GTK_ENTRY (widget); editable = GTK_EDITABLE (widget); - if (entry->button && (event->button != entry->button)) + if (event->window != entry->text_area || + (entry->button && event->button != entry->button)) return FALSE; entry->button = event->button; if (!GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget); - + + tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); + if (event->button == 1) { switch (event->type) { case GDK_BUTTON_PRESS: - gtk_grab_add (widget); - - tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); - /* Set it now, so we display things right. We'll unset it - * later if things don't work out */ - editable->has_selection = TRUE; - gtk_entry_set_selection (editable, tmp_pos, tmp_pos); - editable->current_pos = editable->selection_start_pos; + gtk_entry_reset_im_context (entry); + + entry->current_pos = tmp_pos; + entry->selection_bound = tmp_pos; + + gtk_entry_recompute (entry); + break; case GDK_2BUTTON_PRESS: - gtk_select_word (entry, event->time); + gtk_entry_select_word (entry); break; case GDK_3BUTTON_PRESS: - gtk_select_line (entry, event->time); + gtk_entry_select_line (entry); break; default: @@ -835,28 +964,17 @@ gtk_entry_button_press (GtkWidget *widget, return TRUE; } - else if (event->type == GDK_BUTTON_PRESS) + else if (event->button == 2 && event->type == GDK_BUTTON_PRESS && entry->editable) { - if ((event->button == 2) && editable->editable) - { - if (editable->selection_start_pos == editable->selection_end_pos || - editable->has_selection) - editable->current_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); - gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, - ctext_atom, event->time); - } - else - { - gtk_grab_add (widget); - - tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); - gtk_entry_set_selection (editable, tmp_pos, tmp_pos); - editable->has_selection = FALSE; - editable->current_pos = editable->selection_start_pos; + gtk_editable_select_region (editable, tmp_pos, tmp_pos); + gtk_entry_paste (entry, GDK_SELECTION_PRIMARY); - if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) - gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); - } + return TRUE; + } + else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) + { + gtk_entry_popup_menu (entry, event); + entry->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */ return TRUE; } @@ -868,46 +986,20 @@ static gint 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); - g_return_val_if_fail (event != NULL, FALSE); - - entry = GTK_ENTRY (widget); - editable = GTK_EDITABLE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEditable *editable = GTK_EDITABLE (widget); - if (entry->button != event->button) + if (event->window != entry->text_area || entry->button != event->button) return FALSE; entry->button = 0; if (event->button == 1) { - gtk_grab_remove (widget); + gint tmp_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)) - editable->has_selection = TRUE; - else - 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); - } - - return TRUE; - } - else if (event->button == 3) - { - gtk_grab_remove (widget); + tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); + gtk_editable_select_region (editable, entry->selection_bound, tmp_pos); return TRUE; } @@ -919,27 +1011,23 @@ static gint gtk_entry_motion_notify (GtkWidget *widget, GdkEventMotion *event) { - GtkEntry *entry; - gint x; - - 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); + GtkEntry *entry = GTK_ENTRY (widget); + gint tmp_pos; - if (entry->button == 0) + if (event->window != entry->text_area || entry->button != 1) return FALSE; - x = event->x; if (event->is_hint || (entry->text_area != event->window)) - gdk_window_get_pointer (entry->text_area, &x, NULL, NULL); + gdk_window_get_pointer (entry->text_area, NULL, NULL, NULL); - GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_find_position (entry, x + entry->scroll_offset); - GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos; - entry_adjust_scroll (entry); - gtk_entry_queue_draw (entry); + tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); + if (tmp_pos != entry->current_pos) + { + entry->current_pos = tmp_pos; + gtk_entry_recompute (entry); + } + return TRUE; } @@ -947,230 +1035,644 @@ static gint gtk_entry_key_press (GtkWidget *widget, GdkEventKey *event) { - GtkEntry *entry; - GtkEditable *editable; + GtkEntry *entry = GTK_ENTRY (widget); - gint return_val; - gint key; - guint initial_pos; - gint extend_selection; - gint extend_start; + if (!entry->editable) + return FALSE; + + /* Activate key bindings + */ + if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) + return TRUE; + + /* Not bound, pass to input method + */ + entry->need_im_reset = TRUE; + return gtk_im_context_filter_keypress (entry->im_context, event); +} +static gint +gtk_entry_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ 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); - editable = GTK_EDITABLE (widget); - return_val = FALSE; + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + gtk_entry_queue_draw (GTK_ENTRY (widget)); + + GTK_ENTRY (widget)->need_im_reset = TRUE; + gtk_im_context_focus_in (GTK_ENTRY (widget)->im_context); - if(editable->editable == FALSE) - return FALSE; + return FALSE; +} - initial_pos = editable->current_pos; +static gint +gtk_entry_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + 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); - extend_selection = event->state & GDK_SHIFT_MASK; - extend_start = FALSE; + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + gtk_entry_queue_draw (GTK_ENTRY (widget)); - if (extend_selection) + GTK_ENTRY (widget)->need_im_reset = TRUE; + gtk_im_context_focus_out (GTK_ENTRY (widget)->im_context); + + return FALSE; +} + +static void +gtk_entry_direction_changed (GtkWidget *widget, + GtkTextDirection previous_dir) +{ + GtkEntry *entry = GTK_ENTRY (widget); + + gtk_entry_recompute (entry); + + GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir); +} + +static void +gtk_entry_state_changed (GtkWidget *widget, + GtkStateType previous_state) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + if (GTK_WIDGET_REALIZED (widget)) { - if (editable->selection_start_pos == editable->selection_end_pos) + gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); + gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); + } + + gtk_widget_queue_clear (widget); +} + +/* GtkEditable method implementations + */ +static void +gtk_entry_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + GtkEntry *entry = GTK_ENTRY (editable); + gchar buf[64]; + gchar *text; + + if (*position < 0 || *position > entry->text_length) + *position = entry->text_length; + + g_object_ref (G_OBJECT (editable)); + + if (new_text_length <= 63) + text = buf; + else + text = g_new (gchar, new_text_length + 1); + + text[new_text_length] = '\0'; + strncpy (text, new_text, new_text_length); + + gtk_signal_emit (GTK_OBJECT (editable), signals[INSERT_TEXT], text, new_text_length, position); + gtk_signal_emit (GTK_OBJECT (editable), signals[CHANGED]); + + if (new_text_length > 63) + g_free (text); + + g_object_unref (G_OBJECT (editable)); +} + +static void +gtk_entry_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + GtkEntry *entry = GTK_ENTRY (editable); + + if (end_pos < 0 || end_pos > entry->text_length) + end_pos = entry->text_length; + if (start_pos < 0) + start_pos = 0; + if (start_pos > end_pos) + start_pos = end_pos; + + g_object_ref (G_OBJECT (editable)); + + gtk_signal_emit (GTK_OBJECT (editable), signals[DELETE_TEXT], start_pos, end_pos); + gtk_signal_emit (GTK_OBJECT (editable), signals[CHANGED]); + + g_object_unref (G_OBJECT (editable)); +} + +static gchar * +gtk_entry_get_chars (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + GtkEntry *entry; + gint start_index, end_index; + + g_return_val_if_fail (editable != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL); + + entry = GTK_ENTRY (editable); + + if (end_pos < 0) + end_pos = entry->text_length; + + start_pos = MIN (entry->text_length, start_pos); + end_pos = MIN (entry->text_length, end_pos); + + start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; + end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; + + return g_strndup (entry->text + start_index, end_index - start_index); +} + +static void +gtk_entry_real_set_position (GtkEditable *editable, + gint position) +{ + GtkEntry *entry = GTK_ENTRY (editable); + + if (position < 0 || position > entry->text_length) + position = entry->text_length; + + if (position != entry->current_pos) + { + gtk_entry_reset_im_context (entry); + + entry->current_pos = entry->selection_bound = position; + gtk_entry_recompute (entry); + } +} + +static gint +gtk_entry_get_position (GtkEditable *editable) +{ + return GTK_ENTRY (editable)->current_pos; +} + +static void +gtk_entry_set_selection_bounds (GtkEditable *editable, + gint start, + gint end) +{ + GtkEntry *entry = GTK_ENTRY (editable); + + if (start < 0) + start = entry->text_length; + if (end < 0) + end = entry->text_length; + + gtk_entry_reset_im_context (entry); + + entry->selection_bound = MIN (start, entry->text_length); + entry->current_pos = MIN (end, entry->text_length); + + gtk_entry_update_primary_selection (entry); + + gtk_entry_recompute (entry); +} + +static gboolean +gtk_entry_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end) +{ + GtkEntry *entry = GTK_ENTRY (editable); + + *start = entry->selection_bound; + *end = entry->current_pos; + + return (entry->selection_bound != entry->current_pos); +} + +static void +gtk_entry_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + GtkEntry *entry = GTK_ENTRY (widget); + + if (previous_style && GTK_WIDGET_REALIZED (widget)) + { + gtk_entry_recompute (entry); + + gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); + gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); + } +} + +/* Default signal handlers + */ +static void +gtk_entry_real_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + gint index; + gint n_chars; + + if (new_text_length < 0) + new_text_length = strlen (new_text); + + n_chars = g_utf8_strlen (new_text, new_text_length); + if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length) + { + gdk_beep (); + n_chars = entry->text_max_length - entry->text_length; + } + + if (new_text_length + entry->n_bytes + 1 > entry->text_size) + { + while (new_text_length + entry->n_bytes + 1 > entry->text_size) { - editable->selection_start_pos = editable->current_pos; - editable->selection_end_pos = editable->current_pos; + if (entry->text_size == 0) + entry->text_size = MIN_SIZE; + else + { + if (2 * (guint)entry->text_size < MAX_SIZE && + 2 * (guint)entry->text_size > entry->text_size) + entry->text_size *= 2; + else + { + entry->text_size = MAX_SIZE; + new_text_length = entry->text_size - new_text_length - 1; + break; + } + } } + + entry->text = g_realloc (entry->text, entry->text_size); + } + + index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text; + + g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index); + memcpy (entry->text + index, new_text, new_text_length); + + entry->n_bytes += new_text_length; + entry->text_length += n_chars; + + /* NUL terminate for safety and convenience */ + entry->text[entry->n_bytes] = '\0'; + + if (entry->current_pos > *position) + entry->current_pos += n_chars; + + if (entry->selection_bound > *position) + entry->selection_bound += n_chars; + + *position += n_chars; + + gtk_entry_recompute (entry); +} + +static void +gtk_entry_real_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos) +{ + if (start_pos < 0) + start_pos = 0; + if (end_pos < 0 || end_pos > entry->text_length) + end_pos = entry->text_length; + + if (start_pos < end_pos) + { + gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; + gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; + + g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes - end_index); + entry->text_length -= (end_pos - start_pos); + entry->n_bytes -= (end_index - start_index); - extend_start = (editable->current_pos == editable->selection_start_pos); + if (entry->current_pos > start_pos) + entry->current_pos -= MIN (entry->current_pos, end_pos) - start_pos; + + if (entry->selection_bound > start_pos) + entry->selection_bound -= MIN (entry->selection_bound, end_pos) - start_pos; } - switch (event->keyval) + /* We might have deleted the selection + */ + gtk_entry_update_primary_selection (entry); + + gtk_entry_recompute (entry); +} + + +static void +gtk_entry_move (GtkEntry *entry, + GtkMovementStep step, + gint count, + gboolean extend_selection) +{ + gint new_pos = entry->current_pos; + + gtk_entry_reset_im_context (entry); + + switch (step) { - case GDK_BackSpace: - return_val = TRUE; - if (event->state & GDK_CONTROL_MASK) - gtk_delete_backward_word (entry); - else - gtk_delete_backward_character (entry); + case GTK_MOVEMENT_CHARS: + new_pos = CLAMP (new_pos + count, 0, entry->text_length); break; - case GDK_Clear: - return_val = TRUE; - gtk_delete_line (entry); + case GTK_MOVEMENT_POSITIONS: + new_pos = gtk_entry_move_visually (entry, new_pos, count); break; - case GDK_Insert: - return_val = TRUE; - if (event->state & GDK_SHIFT_MASK) - { - extend_selection = FALSE; - gtk_editable_paste_clipboard (editable); - } - else if (event->state & GDK_CONTROL_MASK) + case GTK_MOVEMENT_WORDS: + while (count > 0) { - gtk_editable_copy_clipboard (editable); + new_pos = gtk_entry_move_forward_word (entry, new_pos); + count--; } - else + while (count < 0) { - /* gtk_toggle_insert(entry) -- IMPLEMENT */ - } - break; - case GDK_Delete: - return_val = TRUE; - if (event->state & GDK_CONTROL_MASK) - gtk_delete_forward_word (entry); - else if (event->state & GDK_SHIFT_MASK) - { - extend_selection = FALSE; - gtk_editable_cut_clipboard (editable); + new_pos = gtk_entry_move_backward_word (entry, new_pos); + count++; } - else - gtk_delete_forward_character (entry); break; - case GDK_Home: - return_val = TRUE; - gtk_move_beginning_of_line (entry); + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_BUFFER_ENDS: + new_pos = count < 0 ? 0 : entry->text_length; break; - case GDK_End: - return_val = TRUE; - gtk_move_end_of_line (entry); + case GTK_MOVEMENT_DISPLAY_LINES: + case GTK_MOVEMENT_PARAGRAPHS: + case GTK_MOVEMENT_PAGES: break; - case GDK_Left: - return_val = TRUE; - if (event->state & GDK_CONTROL_MASK) - gtk_move_backward_word (entry); - else - gtk_move_backward_character (entry); - break; - case GDK_Right: - return_val = TRUE; - if (event->state & GDK_CONTROL_MASK) - gtk_move_forward_word (entry); - else - gtk_move_forward_character (entry); - break; - case GDK_Return: - return_val = TRUE; - gtk_widget_activate (widget); - break; - /* The next two keys should not be inserted literally. Any others ??? */ - case GDK_Tab: - case GDK_Escape: - break; - default: - if ((event->keyval >= 0x20) && (event->keyval <= 0xFF)) - { - key = event->keyval; + } - if (event->state & GDK_CONTROL_MASK) - { - if ((key >= 'A') && (key <= 'Z')) - key -= 'A' - 'a'; + if (extend_selection) + gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos); + else + gtk_editable_set_position (GTK_EDITABLE (entry), new_pos); +} - if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a']) - { - (* control_keys[key - 'a']) (editable, event->time); - return_val = TRUE; - } - break; - } - else if (event->state & GDK_MOD1_MASK) - { - if ((key >= 'A') && (key <= 'Z')) - key -= 'A' - 'a'; +static void +gtk_entry_insert (GtkEntry *entry, + const gchar *str) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + gint pos = entry->current_pos; - if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a']) - { - (* alt_keys[key - 'a']) (editable, event->time); - return_val = TRUE; - } - break; - } - } - gtk_im_context_filter_keypress (entry->im_context, event); - - break; - } + gtk_entry_reset_im_context (entry); - /* since we emit signals from within the above code, - * the widget might already be destroyed or at least - * unrealized. - */ - if (GTK_WIDGET_REALIZED (editable) && - return_val && (editable->current_pos != initial_pos)) + gtk_editable_insert_text (editable, str, -1, &pos); + gtk_editable_set_position (editable, pos); +} + +static void +gtk_entry_delete (GtkEntry *entry, + GtkDeleteType type, + gint count) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + gint start_pos = entry->current_pos; + gint end_pos = entry->current_pos; + + gtk_entry_reset_im_context (entry); + + if (!entry->editable) + return; + + if (entry->selection_bound != entry->current_pos) { - if (extend_selection) + gtk_editable_delete_selection (editable); + return; + } + + switch (type) + { + case GTK_DELETE_CHARS: + end_pos = entry->current_pos + count; + gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos)); + break; + case GTK_DELETE_WORDS: + if (count < 0) { - 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) - editable->selection_start_pos = editable->current_pos; - else - editable->selection_end_pos = editable->current_pos; - } + /* Move to end of current word, or if not on a word, end of previous word */ + end_pos = gtk_entry_move_backward_word (entry, end_pos); + end_pos = gtk_entry_move_forward_word (entry, end_pos); } - else + else if (count > 0) + { + /* Move to beginning of current word, or if not on a word, begining of next word */ + start_pos = gtk_entry_move_forward_word (entry, start_pos); + start_pos = gtk_entry_move_backward_word (entry, start_pos); + } + + /* Fall through */ + case GTK_DELETE_WORD_ENDS: + while (count < 0) { - editable->selection_start_pos = 0; - editable->selection_end_pos = 0; + start_pos = gtk_entry_move_backward_word (entry, start_pos); + count++; } + while (count > 0) + { + end_pos = gtk_entry_move_forward_word (entry, end_pos); + count--; + } + gtk_editable_delete_text (editable, start_pos, end_pos); + break; + case GTK_DELETE_DISPLAY_LINE_ENDS: + case GTK_DELETE_PARAGRAPH_ENDS: + if (count < 0) + gtk_editable_delete_text (editable, 0, entry->current_pos); + else + gtk_editable_delete_text (editable, entry->current_pos, -1); + break; + case GTK_DELETE_DISPLAY_LINES: + case GTK_DELETE_PARAGRAPHS: + gtk_editable_delete_text (editable, 0, -1); + break; + case GTK_DELETE_WHITESPACE: + gtk_entry_delete_whitespace (entry); + break; + } +} - gtk_editable_claim_selection (editable, - editable->selection_start_pos != editable->selection_end_pos, - event->time); - - entry_adjust_scroll (entry); - gtk_entry_queue_draw (entry); +static void +gtk_entry_copy_clipboard (GtkEntry *entry) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + gint start, end; + + if (gtk_editable_get_selection_bounds (editable, &start, &end)) + { + gchar *str = gtk_entry_get_public_chars (entry, start, end); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); + g_free (str); } +} + +static void +gtk_entry_cut_clipboard (GtkEntry *entry) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + gint start, end; - return return_val; + gtk_entry_copy_clipboard (entry); + if (gtk_editable_get_selection_bounds (editable, &start, &end)) + gtk_editable_delete_text (editable, start, end); } -static gint -gtk_entry_focus_in (GtkWidget *widget, - GdkEventFocus *event) +static void +gtk_entry_paste_clipboard (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); + gtk_entry_paste (entry, GDK_NONE); +} - GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); - gtk_widget_draw_focus (widget); - gtk_entry_queue_draw (GTK_ENTRY (widget)); +static void +gtk_entry_toggle_overwrite (GtkEntry *entry) +{ + entry->overwrite_mode = !entry->overwrite_mode; +} + +/* IM Context Callbacks + */ + +static void +gtk_entry_commit_cb (GtkIMContext *context, + const gchar *str, + GtkEntry *entry) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + gint tmp_pos = entry->current_pos; + + gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos); + gtk_editable_set_position (editable, tmp_pos); +} + +static void +gtk_entry_preedit_changed_cb (GtkIMContext *context, + GtkEntry *entry) +{ + gchar *preedit_string; + gint cursor_pos; - gtk_im_context_focus_in (GTK_ENTRY (widget)->im_context); + gtk_im_context_get_preedit_string (entry->im_context, + &preedit_string, NULL, + &cursor_pos); + entry->preedit_length = strlen (preedit_string); + cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); + cursor_pos = g_utf8_offset_to_pointer (preedit_string, cursor_pos) - preedit_string; + g_free (preedit_string); - return FALSE; + gtk_entry_recompute (entry); } -static gint -gtk_entry_focus_out (GtkWidget *widget, - GdkEventFocus *event) +/* Internal functions + */ + +static void +gtk_entry_reset_layout (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); + if (entry->cached_layout) + { + g_object_unref (G_OBJECT (entry->cached_layout)); + entry->cached_layout = NULL; + } +} - GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); - gtk_widget_draw_focus (widget); - gtk_entry_queue_draw (GTK_ENTRY (widget)); +static gboolean +recompute_idle_func (gpointer data) +{ + GtkEntry *entry = GTK_ENTRY (data); - gtk_im_context_focus_out (GTK_ENTRY (widget)->im_context); + gtk_entry_adjust_scroll (entry); + gtk_entry_queue_draw (entry); + entry->recompute_idle = FALSE; + return FALSE; } static void -gtk_entry_ensure_layout (GtkEntry *entry) +gtk_entry_recompute (GtkEntry *entry) { - GtkWidget *widget = GTK_WIDGET (entry); + gtk_entry_reset_layout (entry); + + if (!entry->recompute_idle) + { + entry->recompute_idle = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */ + recompute_idle_func, entry, NULL); + } +} + +static PangoLayout * +gtk_entry_create_layout (GtkEntry *entry, + gboolean include_preedit) +{ + PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (entry), NULL); + PangoAttrList *tmp_attrs = pango_attr_list_new (); - if (!entry->layout) + gchar *preedit_string = NULL; + gint preedit_length = 0; + PangoAttrList *preedit_attrs = NULL; + + if (include_preedit) + { + gtk_im_context_get_preedit_string (entry->im_context, + &preedit_string, &preedit_attrs, NULL); + preedit_length = entry->preedit_length; + } + + if (preedit_length) { - entry->layout = gtk_widget_create_pango_layout (widget, NULL); - pango_layout_set_text (entry->layout, entry->text, entry->n_bytes); + GString *tmp_string = g_string_new (NULL); + + gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text; + + g_string_prepend_len (tmp_string, entry->text, entry->n_bytes); + g_string_insert (tmp_string, cursor_index, preedit_string); + pango_layout_set_text (layout, tmp_string->str, tmp_string->len); + + pango_attr_list_splice (tmp_attrs, preedit_attrs, + cursor_index, entry->preedit_length); + + g_string_free (tmp_string, TRUE); + } + else + pango_layout_set_text (layout, entry->text, entry->n_bytes); + + pango_layout_set_attributes (layout, tmp_attrs); + + if (preedit_string) + g_free (preedit_string); + if (preedit_attrs) + pango_attr_list_unref (preedit_attrs); + + pango_attr_list_unref (tmp_attrs); + + return layout; +} + +static PangoLayout * +gtk_entry_get_layout (GtkEntry *entry, + gboolean include_preedit) +{ + if (entry->preedit_length > 0 && + !include_preedit != !entry->cache_includes_preedit) + gtk_entry_reset_layout (entry); + + if (!entry->cached_layout) + { + entry->cached_layout = gtk_entry_create_layout (entry, include_preedit); + entry->cache_includes_preedit = include_preedit; + } + + g_object_ref (G_OBJECT (entry->cached_layout)); + return entry->cached_layout; } static void @@ -1178,15 +1680,16 @@ gtk_entry_draw_text (GtkEntry *entry) { GtkWidget *widget; PangoLayoutLine *line; - GtkEditable *editable = GTK_EDITABLE (entry); g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ENTRY (entry)); if (GTK_WIDGET_DRAWABLE (entry)) { + PangoLayout *layout = gtk_entry_get_layout (entry, TRUE); PangoRectangle logical_rect; gint area_width, area_height; + gint start_pos, end_pos; gint y_pos; gdk_window_get_size (entry->text_area, &area_width, &area_height); @@ -1199,9 +1702,7 @@ gtk_entry_draw_text (GtkEntry *entry) NULL, widget, "entry_bg", 0, 0, area_width, area_height); - gtk_entry_ensure_layout (entry); - - line = pango_layout_get_lines (entry->layout)->data; + line = pango_layout_get_lines (layout)->data; pango_layout_line_get_extents (line, NULL, &logical_rect); /* Align primarily for locale's ascent/descent */ @@ -1220,17 +1721,14 @@ gtk_entry_draw_text (GtkEntry *entry) gdk_draw_layout (entry->text_area, widget->style->text_gc [widget->state], INNER_BORDER - entry->scroll_offset, y_pos, - entry->layout); + layout); - if (editable->selection_start_pos != editable->selection_end_pos) + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos)) { gint *ranges; gint n_ranges, i; - gint start_index = g_utf8_offset_to_pointer (entry->text, - MIN (editable->selection_start_pos, editable->selection_end_pos)) - entry->text; - gint end_index = g_utf8_offset_to_pointer (entry->text, - MAX (editable->selection_start_pos, editable->selection_end_pos)) - entry->text; - GtkStateType selected_state = editable->has_selection ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE; + gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; + gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; GdkRegion *clip_region = gdk_region_new (); pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges); @@ -1244,21 +1742,23 @@ gtk_entry_draw_text (GtkEntry *entry) rect.width = (ranges[2*i + 1] - ranges[2*i]) / PANGO_SCALE; rect.height = logical_rect.height / PANGO_SCALE; - gdk_draw_rectangle (entry->text_area, widget->style->bg_gc [selected_state], TRUE, + gdk_draw_rectangle (entry->text_area, widget->style->bg_gc [GTK_STATE_SELECTED], TRUE, rect.x, rect.y, rect.width, rect.height); gdk_region_union_with_rect (clip_region, &rect); } - gdk_gc_set_clip_region (widget->style->fg_gc [selected_state], clip_region); - gdk_draw_layout (entry->text_area, widget->style->fg_gc [selected_state], + gdk_gc_set_clip_region (widget->style->fg_gc [GTK_STATE_SELECTED], clip_region); + gdk_draw_layout (entry->text_area, widget->style->fg_gc [GTK_STATE_SELECTED], INNER_BORDER - entry->scroll_offset, y_pos, - entry->layout); - gdk_gc_set_clip_region (widget->style->fg_gc [selected_state], NULL); + layout); + gdk_gc_set_clip_region (widget->style->fg_gc [GTK_STATE_SELECTED], NULL); gdk_region_destroy (clip_region); g_free (ranges); } + + g_object_unref (G_OBJECT (layout)); } } @@ -1271,10 +1771,9 @@ gtk_entry_draw_cursor (GtkEntry *entry) if (GTK_WIDGET_DRAWABLE (entry)) { GtkWidget *widget = GTK_WIDGET (entry); - GtkEditable *editable = GTK_EDITABLE (entry); if (GTK_WIDGET_HAS_FOCUS (widget) && - (editable->selection_start_pos == editable->selection_end_pos)) + (entry->selection_bound == entry->current_pos)) { gint xoffset = INNER_BORDER - entry->scroll_offset; gint strong_x, weak_x; @@ -1308,40 +1807,47 @@ gtk_entry_queue_draw (GtkEntry *entry) GdkRectangle rect = { 0 }; gdk_window_get_size (entry->text_area, &rect.width, &rect.height); - gdk_window_invalidate_rect (entry->text_area, &rect, 0); + gdk_window_invalidate_rect (entry->text_area, &rect, FALSE); } } -#if 0 -static gint -gtk_entry_timer (gpointer data) +static void +gtk_entry_reset_im_context (GtkEntry *entry) { - GtkEntry *entry; - - GDK_THREADS_ENTER (); + if (entry->need_im_reset) + entry->need_im_reset = 0; - entry = GTK_ENTRY (data); - entry->timer = 0; - - GDK_THREADS_LEAVE (); - - return FALSE; + gtk_im_context_reset (entry->im_context); } -#endif static gint gtk_entry_find_position (GtkEntry *entry, gint x) { + PangoLayout *layout; PangoLayoutLine *line; gint index; gint pos; gboolean trailing; + gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text; - gtk_entry_ensure_layout (entry); - - line = pango_layout_get_lines (entry->layout)->data; + layout = gtk_entry_get_layout (entry, TRUE); + + line = pango_layout_get_lines (layout)->data; pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing); + + g_object_unref (G_OBJECT (layout)); + + if (index >= cursor_index && entry->preedit_length) + { + if (index >= cursor_index + entry->preedit_length) + index -= entry->preedit_length; + else + { + index = cursor_index; + trailing = 0; + } + } pos = g_utf8_pointer_to_offset (entry->text, entry->text + index); @@ -1356,15 +1862,14 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, gint *strong_x, gint *weak_x) { - GtkEditable *editable = GTK_EDITABLE (entry); - int index; + PangoLayout *layout = gtk_entry_get_layout (entry, TRUE); + gint index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text; PangoRectangle strong_pos, weak_pos; - gtk_entry_ensure_layout (entry); - - index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text; - pango_layout_get_cursor_pos (entry->layout, index, &strong_pos, &weak_pos); + index += entry->preedit_cursor; + pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos); + g_object_unref (G_OBJECT (layout)); if (strong_x) *strong_x = strong_pos.x / PANGO_SCALE; @@ -1374,13 +1879,14 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, } static void -entry_adjust_scroll (GtkEntry *entry) +gtk_entry_adjust_scroll (GtkEntry *entry) { GtkWidget *widget; gint min_offset, max_offset; gint text_area_width; gint strong_x, weak_x; gint strong_xoffset, weak_xoffset; + PangoLayout *layout; PangoLayoutLine *line; PangoRectangle logical_rect; @@ -1389,17 +1895,19 @@ entry_adjust_scroll (GtkEntry *entry) widget = GTK_WIDGET (entry); - if (!entry->layout || !GTK_WIDGET_REALIZED (entry)) + if (!GTK_WIDGET_REALIZED (entry)) return; gdk_window_get_size (entry->text_area, &text_area_width, NULL); text_area_width -= 2 * INNER_BORDER; - line = pango_layout_get_lines (entry->layout)->data; - - /* Display as much text as we can */ + layout = gtk_entry_get_layout (entry, TRUE); + line = pango_layout_get_lines (layout)->data; pango_layout_line_get_extents (line, NULL, &logical_rect); + g_object_unref (G_OBJECT (layout)); + + /* Display as much text as we can */ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) { @@ -1454,204 +1962,17 @@ entry_adjust_scroll (GtkEntry *entry) { entry->scroll_offset += weak_xoffset - text_area_width; } - - gtk_widget_queue_draw (GTK_WIDGET (entry)); } -static void -gtk_entry_insert_text (GtkEditable *editable, - const gchar *new_text, - gint new_text_length, - gint *position) -{ - gint index; - gint n_chars; - GtkEntry *entry; - GtkWidget *widget; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_ENTRY (editable)); - g_return_if_fail (position != NULL); - g_return_if_fail (*position >= 0 || *position < GTK_ENTRY (editable)->text_size); - - entry = GTK_ENTRY (editable); - widget = GTK_WIDGET (editable); - - if (new_text_length < 0) - new_text_length = strlen (new_text); - - n_chars = g_utf8_strlen (new_text, new_text_length); - if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length) - { - gdk_beep (); - n_chars = entry->text_max_length - entry->text_length; - } - - if (new_text_length + entry->n_bytes + 1 > entry->text_size) - { - while (new_text_length + entry->n_bytes + 1 > entry->text_size) - { - if (entry->text_size == 0) - entry->text_size = MIN_SIZE; - else - { - if (2 * (guint)entry->text_size < MAX_SIZE && - 2 * (guint)entry->text_size > entry->text_size) - entry->text_size *= 2; - else - { - entry->text_size = MAX_SIZE; - new_text_length = entry->text_size - new_text_length - 1; - break; - } - } - } - - entry->text = g_realloc (entry->text, entry->text_size); - } - - index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text; - - g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index); - memcpy (entry->text + index, new_text, new_text_length); - - entry->n_bytes += new_text_length; - entry->text_length += n_chars; - - /* NUL terminate for safety and convenience */ - entry->text[entry->n_bytes] = '\0'; - - if (editable->current_pos > *position) - editable->current_pos += n_chars; - - if (editable->selection_start_pos > *position) - editable->selection_start_pos += n_chars; - - if (editable->selection_end_pos > *position) - editable->selection_end_pos += n_chars; - - *position += n_chars; - - if (entry->layout) - pango_layout_set_text (entry->layout, entry->text, entry->n_bytes); - - gtk_entry_queue_draw (entry); -} - -static void -gtk_entry_delete_text (GtkEditable *editable, - gint start_pos, - gint end_pos) -{ - GtkEntry *entry; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_ENTRY (editable)); - - entry = GTK_ENTRY (editable); - - if (end_pos < 0) - end_pos = entry->text_length; - - if ((start_pos < end_pos) && - (start_pos >= 0) && - (end_pos <= entry->text_length)) - { - gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; - gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; - - g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes - end_index); - entry->text_length -= (end_pos - start_pos); - entry->n_bytes -= (end_index - start_index); - - if (editable->current_pos > start_pos) - editable->current_pos -= MIN (editable->current_pos, end_pos) - start_pos; - - if (editable->selection_start_pos > start_pos) - editable->selection_start_pos -= MIN (editable->selection_start_pos, end_pos) - start_pos; - - if (editable->selection_end_pos > start_pos) - editable->selection_end_pos -= MIN (editable->selection_end_pos, end_pos) - start_pos; - - } - - gtk_entry_queue_draw (entry); - - if (entry->layout) - pango_layout_set_text (entry->layout, entry->text, entry->n_bytes); -} - -static void -gtk_entry_update_text (GtkEditable *editable, - gint start_pos, - gint end_pos) -{ - GtkEntry *entry = GTK_ENTRY (editable); - - gtk_entry_queue_draw (entry); -} - -static gchar * -gtk_entry_get_chars (GtkEditable *editable, - gint start_pos, - gint end_pos) -{ - GtkEntry *entry; - gint start_index, end_index; - - g_return_val_if_fail (editable != NULL, NULL); - g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL); - - entry = GTK_ENTRY (editable); - - if (end_pos < 0) - end_pos = entry->text_length; - - start_pos = MIN (entry->text_length, start_pos); - end_pos = MIN (entry->text_length, end_pos); - - start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; - end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; - - return g_strndup (entry->text + start_index, end_index - start_index); -} - -static void -gtk_entry_move_cursor (GtkEditable *editable, - gint x, - gint y) -{ - GtkEntry *entry; - gint index; - - entry = GTK_ENTRY (editable); - - index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text; - - /* Horizontal motion */ - - if ((gint)editable->current_pos < -x) - editable->current_pos = 0; - else if (editable->current_pos + x > entry->text_length) - editable->current_pos = entry->text_length; - else - editable->current_pos += x; - - /* Ignore vertical motion */ -} - -static void -gtk_entry_move_cursor_visually (GtkEditable *editable, - gint count) +static gint +gtk_entry_move_visually (GtkEntry *entry, + gint start, + gint count) { - GtkEntry *entry; gint index; + PangoLayout *layout = gtk_entry_get_layout (entry, FALSE); - entry = GTK_ENTRY (editable); - - index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text; - - gtk_entry_ensure_layout (entry); + index = g_utf8_offset_to_pointer (entry->text, start) - entry->text; while (count != 0) { @@ -1659,12 +1980,12 @@ gtk_entry_move_cursor_visually (GtkEditable *editable, if (count > 0) { - pango_layout_move_cursor_visually (entry->layout, index, 0, 1, &new_index, &new_trailing); + pango_layout_move_cursor_visually (layout, index, 0, 1, &new_index, &new_trailing); count--; } else { - pango_layout_move_cursor_visually (entry->layout, index, 0, -1, &new_index, &new_trailing); + pango_layout_move_cursor_visually (layout, index, 0, -1, &new_index, &new_trailing); count++; } @@ -1677,289 +1998,341 @@ gtk_entry_move_cursor_visually (GtkEditable *editable, index = new_index; } - editable->current_pos = g_utf8_pointer_to_offset (entry->text, entry->text + index); -} - -static void -gtk_move_forward_character (GtkEntry *entry) -{ - gtk_entry_move_cursor_visually (GTK_EDITABLE (entry), 1); -} - -static void -gtk_move_backward_character (GtkEntry *entry) -{ - gtk_entry_move_cursor_visually (GTK_EDITABLE (entry), -1); -} - -static void -gtk_entry_move_word (GtkEditable *editable, - gint n) -{ - while (n-- > 0) - gtk_move_forward_word (GTK_ENTRY (editable)); - while (n++ < 0) - gtk_move_backward_word (GTK_ENTRY (editable)); + g_object_unref (G_OBJECT (layout)); + + return g_utf8_pointer_to_offset (entry->text, entry->text + index); } -static void -gtk_move_forward_word (GtkEntry *entry) +static gint +gtk_entry_move_forward_word (GtkEntry *entry, + gint start) { - GtkEditable *editable; - gint i; - - editable = GTK_EDITABLE (entry); + gint new_pos = start; /* Prevent any leak of information */ - if (!editable->visible) + if (!entry->visible) { - editable->current_pos = entry->text_length; - return; + new_pos = entry->text_length; } - - if (entry->text && (editable->current_pos < entry->text_length)) + else if (entry->text && (new_pos < entry->text_length)) { + PangoLayout *layout = gtk_entry_get_layout (entry, FALSE); PangoLogAttr *log_attrs; - gint n_attrs, old_pos; - - gtk_entry_ensure_layout (entry); - pango_layout_get_log_attrs (entry->layout, &log_attrs, &n_attrs); + gint n_attrs; - i = old_pos = editable->current_pos; + pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); /* Advance over white space */ - while (i < n_attrs && log_attrs[i].is_white) - i++; + while (new_pos < n_attrs && log_attrs[new_pos].is_white) + new_pos++; /* Find the next word beginning */ - i++; - while (i < n_attrs && !log_attrs[i].is_word_stop) - i++; - - editable->current_pos = MAX (entry->text_length, i); + new_pos++; + while (new_pos < n_attrs && !log_attrs[new_pos].is_word_stop) + new_pos++; /* Back up over white space */ - while (i > 0 && log_attrs[i - 1].is_white) - i--; - - if (i != old_pos) - editable->current_pos = i; + while (new_pos > 0 && log_attrs[new_pos - 1].is_white) + new_pos--; g_free (log_attrs); + g_object_unref (G_OBJECT (layout)); } + + return new_pos; } -static void -gtk_move_backward_word (GtkEntry *entry) -{ - GtkEditable *editable; - gint i; - editable = GTK_EDITABLE (entry); +static gint +gtk_entry_move_backward_word (GtkEntry *entry, + gint start) +{ + gint new_pos = start; /* Prevent any leak of information */ - if (!editable->visible) + if (!entry->visible) { - editable->current_pos = 0; - return; + new_pos = 0; } - - if (entry->text && editable->current_pos > 0) + else if (entry->text && start > 0) { + PangoLayout *layout = gtk_entry_get_layout (entry, FALSE); PangoLogAttr *log_attrs; gint n_attrs; - gtk_entry_ensure_layout (entry); - pango_layout_get_log_attrs (entry->layout, &log_attrs, &n_attrs); + pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); - i = editable->current_pos - 1; + new_pos = start - 1; /* Find the previous word beginning */ - while (i > 0 && !log_attrs[i].is_word_stop) - i--; + while (new_pos > 0 && !log_attrs[new_pos].is_word_stop) + new_pos--; g_free (log_attrs); + g_object_unref (G_OBJECT (layout)); } + + return new_pos; } static void -gtk_entry_move_to_column (GtkEditable *editable, gint column) +gtk_entry_delete_whitespace (GtkEntry *entry) { - GtkEntry *entry; + PangoLayout *layout = gtk_entry_get_layout (entry, FALSE); + PangoLogAttr *log_attrs; + gint n_attrs; + gint start, end; - entry = GTK_ENTRY (editable); + pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); + + start = end = entry->current_pos; - if (column < 0 || column > entry->text_length) - editable->current_pos = entry->text_length; - else - editable->current_pos = column; + while (start > 0 && log_attrs[start-1].is_white) + start--; + + while (end < n_attrs && log_attrs[start-1].is_white) + end++; + + g_free (log_attrs); + g_object_unref (G_OBJECT (layout)); + + if (start != end) + gtk_editable_delete_text (GTK_EDITABLE (entry), start, end); } + static void -gtk_move_beginning_of_line (GtkEntry *entry) +gtk_entry_select_word (GtkEntry *entry) { - gtk_entry_move_to_column (GTK_EDITABLE (entry), 0); + gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos); + gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos); + + gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos); } static void -gtk_move_end_of_line (GtkEntry *entry) +gtk_entry_select_line (GtkEntry *entry) { - gtk_entry_move_to_column (GTK_EDITABLE (entry), -1); + gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1); } -static void -gtk_entry_kill_char (GtkEditable *editable, - gint direction) +/* + * Like gtk_editable_get_chars, but if the editable is not + * visible, return asterisks; also convert result to UTF-8. + */ +static char * +gtk_entry_get_public_chars (GtkEntry *entry, + gint start, + gint end) { - if (editable->selection_start_pos != editable->selection_end_pos) - gtk_editable_delete_selection (editable); + if (end < 0) + end = entry->text_length; + + if (entry->visible) + return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end); else { - gint old_pos = editable->current_pos; - if (direction >= 0) - { - gtk_entry_move_cursor (editable, 1, 0); - gtk_editable_delete_text (editable, old_pos, editable->current_pos); - } - else - { - gtk_entry_move_cursor (editable, -1, 0); - gtk_editable_delete_text (editable, editable->current_pos, old_pos); - } + gchar *str; + gint i; + gint n_chars = end - start; + + str = g_malloc (n_chars + 1); + for (i = 0; i < n_chars; i++) + str[i] = '*'; + str[i] = '\0'; + + return str; } + } static void -gtk_delete_forward_character (GtkEntry *entry) +paste_received (GtkClipboard *clipboard, + const gchar *text, + gpointer data) { - gtk_entry_kill_char (GTK_EDITABLE (entry), 1); + GtkEntry *entry = GTK_ENTRY (data); + GtkEditable *editable = GTK_EDITABLE (entry); + + if (text) + { + gint pos = entry->current_pos; + + gtk_editable_insert_text (editable, text, -1, &pos); + gtk_editable_set_position (editable, pos); + } + + g_object_unref (G_OBJECT (entry)); } static void -gtk_delete_backward_character (GtkEntry *entry) +gtk_entry_paste (GtkEntry *entry, + GdkAtom selection) { - gtk_entry_kill_char (GTK_EDITABLE (entry), -1); + g_object_ref (G_OBJECT (entry)); + gtk_clipboard_request_text (gtk_clipboard_get (selection), + paste_received, entry); } static void -gtk_entry_kill_word (GtkEditable *editable, - gint direction) +primary_get_cb (GtkClipboard *clipboard, + GtkSelectionData *selection_data, + guint info, + gpointer data) { - if (editable->selection_start_pos != editable->selection_end_pos) - gtk_editable_delete_selection (editable); - else + GtkEntry *entry = GTK_ENTRY (data); + gint start, end; + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end)) { - gint old_pos = editable->current_pos; - if (direction >= 0) - { - gtk_entry_move_word (editable, 1); - gtk_editable_delete_text (editable, old_pos, editable->current_pos); - } - else - { - gtk_entry_move_word (editable, -1); - gtk_editable_delete_text (editable, editable->current_pos, old_pos); - } + gchar *str = gtk_entry_get_public_chars (entry, start, end); + gtk_selection_data_set_text (selection_data, str); + g_free (str); } } static void -gtk_delete_forward_word (GtkEntry *entry) +primary_clear_cb (GtkClipboard *clipboard, + gpointer data) { - gtk_entry_kill_word (GTK_EDITABLE (entry), 1); -} + GtkEntry *entry = GTK_ENTRY (data); -static void -gtk_delete_backward_word (GtkEntry *entry) -{ - gtk_entry_kill_word (GTK_EDITABLE (entry), -1); + gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos); } static void -gtk_entry_kill_line (GtkEditable *editable, - gint direction) -{ - gint old_pos = editable->current_pos; - if (direction >= 0) +gtk_entry_update_primary_selection (GtkEntry *entry) +{ + static const GtkTargetEntry targets[] = { + { "UTF8_STRING", 0, 0 }, + { "STRING", 0, 0 }, + { "TEXT", 0, 0 }, + { "COMPOUND_TEXT", 0, 0 } + }; + + GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); + gint start, end; + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end)) { - gtk_entry_move_to_column (editable, -1); - gtk_editable_delete_text (editable, old_pos, editable->current_pos); + if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets), + primary_get_cb, primary_clear_cb, G_OBJECT (entry))) + primary_clear_cb (clipboard, entry); } else { - gtk_entry_move_to_column (editable, 0); - gtk_editable_delete_text (editable, editable->current_pos, old_pos); + if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry)) + gtk_clipboard_clear (clipboard); } } -static void -gtk_delete_line (GtkEntry *entry) +/* Public API + */ + +GtkWidget* +gtk_entry_new (void) { - gtk_entry_move_to_column (GTK_EDITABLE (entry), 0); - gtk_entry_kill_line (GTK_EDITABLE (entry), 1); + return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY)); } -static void -gtk_delete_to_line_end (GtkEntry *entry) +GtkWidget* +gtk_entry_new_with_max_length (guint16 max) { - gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length); + GtkEntry *entry; + + entry = gtk_type_new (GTK_TYPE_ENTRY); + entry->text_max_length = max; + + return GTK_WIDGET (entry); } -static void -gtk_select_word (GtkEntry *entry, - guint32 time) +void +gtk_entry_set_text (GtkEntry *entry, + const gchar *text) { + gint tmp_pos; + GtkEditable *editable; - gint start_pos; - gint end_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (text != NULL); editable = GTK_EDITABLE (entry); + + gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1); + + tmp_pos = 0; + gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos); +} - gtk_move_backward_word (entry); - start_pos = editable->current_pos; +void +gtk_entry_append_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; - gtk_move_forward_word (entry); - end_pos = editable->current_pos; + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (text != NULL); - editable->has_selection = TRUE; - gtk_entry_set_selection (editable, start_pos, end_pos); - gtk_editable_claim_selection (editable, start_pos != end_pos, time); + tmp_pos = entry->text_length; + gtk_editable_insert_text (GTK_EDITABLE(entry), text, -1, &tmp_pos); } -static void -gtk_select_line (GtkEntry *entry, - guint32 time) +void +gtk_entry_prepend_text (GtkEntry *entry, + const gchar *text) { - GtkEditable *editable; + gint tmp_pos; - editable = GTK_EDITABLE (entry); + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (text != NULL); - editable->has_selection = TRUE; - gtk_entry_set_selection (editable, 0, entry->text_length); - gtk_editable_claim_selection (editable, entry->text_length != 0, time); + tmp_pos = 0; + gtk_editable_insert_text (GTK_EDITABLE(entry), text, -1, &tmp_pos); +} - editable->current_pos = editable->selection_end_pos; +void +gtk_entry_set_position (GtkEntry *entry, + gint position) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + gtk_editable_set_position (GTK_EDITABLE (entry), position); } -static void -gtk_entry_set_selection (GtkEditable *editable, - gint start, - gint end) +void +gtk_entry_set_visibility (GtkEntry *entry, + gboolean visible) { - GtkEntry *entry; - - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_ENTRY (editable)); + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); - entry = GTK_ENTRY (editable); + entry->visible = visible ? TRUE : FALSE; - if (end < 0) - end = GTK_ENTRY (editable)->text_length; - - editable->selection_start_pos = start; - editable->selection_end_pos = end; + gtk_entry_recompute (entry); +} + +void +gtk_entry_set_editable(GtkEntry *entry, + gboolean editable) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + gtk_editable_set_editable (GTK_EDITABLE (entry), editable); +} + +gchar* +gtk_entry_get_text (GtkEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - gtk_entry_queue_draw (GTK_ENTRY (editable)); + return entry->text; } void @@ -1983,63 +2356,66 @@ gtk_entry_set_max_length (GtkEntry *entry, entry->text_max_length = max; } - -static void -gtk_entry_style_set (GtkWidget *widget, - GtkStyle *previous_style) +/* Quick hack of a popup menu + */ +static void +activate_cb (GtkWidget *menuitem, + GtkEntry *entry) { - GtkEntry *entry = GTK_ENTRY (widget); - - if (previous_style && GTK_WIDGET_REALIZED (widget)) - { - entry_adjust_scroll (entry); - - gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); - gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); - } - - if (entry->layout) - pango_layout_context_changed (entry->layout); + const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal"); + gtk_signal_emit_by_name (GTK_OBJECT (entry), signal); } -static void -gtk_entry_direction_changed (GtkWidget *widget, - GtkTextDirection previous_dir) +static void +append_action_signal (GtkEntry *entry, + GtkWidget *menu, + const gchar *label, + const gchar *signal) { - GtkEntry *entry = GTK_ENTRY (widget); + GtkWidget *menuitem = gtk_menu_item_new_with_label (label); - if (entry->layout) - pango_layout_context_changed (entry->layout); + gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + activate_cb, entry); - GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); } - + static void -gtk_entry_state_changed (GtkWidget *widget, - GtkStateType previous_state) +popup_menu_detach (GtkWidget *attach_widget, + GtkMenu *menu) { - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_ENTRY (widget)); - - if (GTK_WIDGET_REALIZED (widget)) - { - gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); - gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); - } - - if (GTK_WIDGET_DRAWABLE (widget)) - gtk_widget_queue_clear(widget); + GTK_ENTRY (attach_widget)->popup_menu = NULL; } static void -gtk_entry_commit_cb (GtkIMContext *context, - const gchar *str, - GtkEntry *entry) +gtk_entry_popup_menu (GtkEntry *entry, + GdkEventButton *event) { - GtkEditable *editable = GTK_EDITABLE (entry); - gint tmp_pos = editable->current_pos; + if (!entry->popup_menu) + { + GtkWidget *menuitem; + + entry->popup_menu = gtk_menu_new (); - gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos); - editable->current_pos = tmp_pos; -} + gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu), + GTK_WIDGET (entry), + popup_menu_detach); + + append_action_signal (entry, entry->popup_menu, _("Cut"), "cut_clipboard"); + append_action_signal (entry, entry->popup_menu, _("Copy"), "copy_clipboard"); + append_action_signal (entry, entry->popup_menu, _("Paste"), "paste_clipboard"); + menuitem = gtk_menu_item_new (); /* Separator */ + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); + + gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context), + GTK_MENU_SHELL (entry->popup_menu)); + } + + gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL, + NULL, NULL, + event->button, event->time); +} diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index 9f7f38899e..765da78f03 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -51,57 +51,106 @@ typedef struct _GtkEntryClass GtkEntryClass; struct _GtkEntry { - GtkEditable editable; + GtkWidget widget; - GdkWindow *text_area; - GdkPixmap *backing_pixmap; - GdkCursor *cursor; gchar *text; - guint16 text_size; /* allocated size, in bytes */ + guint editable : 1; + guint visible : 1; + guint overwrite_mode : 1; guint16 text_length; /* length in use, in chars */ guint16 text_max_length; /*< private >*/ + GdkWindow *text_area; + GtkIMContext *im_context; + GtkWidget *popup_menu; + + gint current_pos; + gint selection_bound; + + PangoLayout *cached_layout; + guint cache_includes_preedit : 1; + + guint need_im_reset : 1; + guint button; - guint32 timer; - guint16 n_bytes; /* length in use, in bytes */ - PangoLayout *layout; + guint timer; + guint recompute_idle; gint scroll_offset; gint ascent; /* font ascent, in pango units */ gint descent; /* font descent, in pango units */ - GtkIMContext *im_context; + + guint16 text_size; /* allocated size, in bytes */ + guint16 n_bytes; /* length in use, in bytes */ + + guint16 preedit_length; /* length of preedit string, in bytes */ + guint16 preedit_cursor; /* offset of cursor within preedit string, in bytes */ }; struct _GtkEntryClass { - GtkEditableClass parent_class; + GtkWidgetClass parent_class; + + /* Notification of changes + */ + void (* changed) (GtkEntry *entry); + void (* insert_text) (GtkEntry *entry, + const gchar *text, + gint length, + gint *position); + void (* delete_text) (GtkEntry *entry, + gint start_pos, + gint end_pos); + + /* Action signals + */ + void (* activate) (GtkEntry *entry); + void (* move) (GtkEntry *entry, + GtkMovementStep step, + gint count, + gboolean extend_selection); + void (* insert) (GtkEntry *entry, + const gchar *str); + void (* delete) (GtkEntry *entry, + GtkDeleteType type, + gint count); + void (* cut_clipboard) (GtkEntry *entry); + void (* copy_clipboard) (GtkEntry *entry); + void (* paste_clipboard) (GtkEntry *entry); + void (* toggle_overwrite) (GtkEntry *entry); }; GtkType gtk_entry_get_type (void) G_GNUC_CONST; GtkWidget* gtk_entry_new (void); -GtkWidget* gtk_entry_new_with_max_length (guint16 max); +void gtk_entry_set_visibility (GtkEntry *entry, + gboolean visible); +void gtk_entry_set_editable (GtkEntry *entry, + gboolean editable); +/* text is truncated if needed */ +void gtk_entry_set_max_length (GtkEntry *entry, + guint16 max); + +/* Somewhat more convenient than the GtkEditable generic functions + */ void gtk_entry_set_text (GtkEntry *entry, const gchar *text); +/* returns a reference to the text */ +gchar* gtk_entry_get_text (GtkEntry *entry); + +/* Deprecated compatibility functions + */ +GtkWidget* gtk_entry_new_with_max_length (guint16 max); void gtk_entry_append_text (GtkEntry *entry, const gchar *text); void gtk_entry_prepend_text (GtkEntry *entry, const gchar *text); void gtk_entry_set_position (GtkEntry *entry, gint position); -/* returns a reference to the text */ -gchar* gtk_entry_get_text (GtkEntry *entry); void gtk_entry_select_region (GtkEntry *entry, gint start, gint end); -void gtk_entry_set_visibility (GtkEntry *entry, - gboolean visible); -void gtk_entry_set_editable (GtkEntry *entry, - gboolean editable); -/* text is truncated if needed */ -void gtk_entry_set_max_length (GtkEntry *entry, - guint16 max); #ifdef __cplusplus } diff --git a/gtk/gtkimcontext.c b/gtk/gtkimcontext.c index 753937f11f..3ced6d6036 100644 --- a/gtk/gtkimcontext.c +++ b/gtk/gtkimcontext.c @@ -35,7 +35,8 @@ static void gtk_im_context_init (GtkIMContext *im_context); static void gtk_im_context_real_get_preedit_string (GtkIMContext *context, gchar **str, - PangoAttrList **attrs); + PangoAttrList **attrs, + gint *cursor_pos); static gboolean gtk_im_context_real_filter_keypress (GtkIMContext *context, GdkEventKey *event); @@ -118,12 +119,15 @@ gtk_im_context_init (GtkIMContext *im_context) static void gtk_im_context_real_get_preedit_string (GtkIMContext *context, gchar **str, - PangoAttrList **attrs) + PangoAttrList **attrs, + gint *cursor_pos) { if (str) *str = g_strdup (""); if (attrs) *attrs = pango_attr_list_new (); + if (cursor_pos) + *cursor_pos = 0; } static gboolean @@ -175,7 +179,8 @@ gtk_im_context_set_client_window (GtkIMContext *context, void gtk_im_context_get_preedit_string (GtkIMContext *context, gchar **str, - PangoAttrList **attrs) + PangoAttrList **attrs, + gint *cursor_pos) { GtkIMContextClass *klass; @@ -183,7 +188,7 @@ gtk_im_context_get_preedit_string (GtkIMContext *context, g_return_if_fail (GTK_IS_IM_CONTEXT (context)); klass = GTK_IM_CONTEXT_GET_CLASS (context); - klass->get_preedit_string (context, str, attrs); + klass->get_preedit_string (context, str, attrs, cursor_pos); } /** @@ -235,7 +240,7 @@ gtk_im_context_focus_in (GtkIMContext *context) } /** - * gtk_im_context_focus_in: + * gtk_im_context_focus_out: * @context: a #GtkIMContext * * Notify the input method that the widget to which this @@ -256,4 +261,25 @@ gtk_im_context_focus_out (GtkIMContext *context) klass->focus_out (context); } +/** + * gtk_im_context_reset: + * @context: a #GtkIMContext + * + * Notify the input method that a change such as a change in cursor + * position has been made. This will typically cause the input + * method to clear the preedit state. + **/ +void +gtk_im_context_reset (GtkIMContext *context) +{ + GtkIMContextClass *klass; + + g_return_if_fail (context != NULL); + g_return_if_fail (GTK_IS_IM_CONTEXT (context)); + + klass = GTK_IM_CONTEXT_GET_CLASS (context); + if (klass->reset) + klass->reset (context); +} + diff --git a/gtk/gtkimcontext.h b/gtk/gtkimcontext.h index efc4ab64fe..6435c4eaf8 100644 --- a/gtk/gtkimcontext.h +++ b/gtk/gtkimcontext.h @@ -60,11 +60,13 @@ struct _GtkIMContextClass GdkWindow *window); void (*get_preedit_string) (GtkIMContext *context, gchar **str, - PangoAttrList **attrs); + PangoAttrList **attrs, + gint *cursor_pos); gboolean (*filter_keypress) (GtkIMContext *context, GdkEventKey *event); void (*focus_in) (GtkIMContext *context); void (*focus_out) (GtkIMContext *context); + void (*reset) (GtkIMContext *context); }; GtkType gtk_im_context_get_type (void) G_GNUC_CONST; @@ -72,12 +74,14 @@ GtkType gtk_im_context_get_type (void) G_GNUC_CONST; void gtk_im_context_set_client_window (GtkIMContext *context, GdkWindow *window); void gtk_im_context_get_preedit_string (GtkIMContext *context, - char **str, - PangoAttrList **attrs); + gchar **str, + PangoAttrList **attrs, + gint *cursor_pos); gboolean gtk_im_context_filter_keypress (GtkIMContext *context, GdkEventKey *event); void gtk_im_context_focus_in (GtkIMContext *context); void gtk_im_context_focus_out (GtkIMContext *context); +void gtk_im_context_reset (GtkIMContext *context); #ifdef __cplusplus } diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c index edfdb57296..a01c85c3bd 100644 --- a/gtk/gtkimcontextsimple.c +++ b/gtk/gtkimcontextsimple.c @@ -23,12 +23,13 @@ #include "gtksignal.h" #include "gtkimcontextsimple.h" -typedef struct _GtkComposeSeq GtkComposeSeq; +typedef struct _GtkComposeTable GtkComposeTable; -struct _GtkComposeSeq +struct _GtkComposeTable { - guint16 keysyms[GTK_MAX_COMPOSE_LEN]; - guint16 unicode; + guint16 *data; + gint max_seq_len; + gint n_seqs; }; /* The following table was generated from the X compose tables include with @@ -54,665 +55,671 @@ struct _GtkComposeSeq * that depend on the locale or selected input method. */ -GtkComposeSeq gtk_compose_seqs[] = { - { { GDK_dead_grave, GDK_space, 0, 0 }, 0x0060 }, /* GRAVE_ACCENT */ - { { GDK_dead_grave, GDK_A, 0, 0 }, 0x00C0 }, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ - { { GDK_dead_grave, GDK_E, 0, 0 }, 0x00C8 }, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */ - { { GDK_dead_grave, GDK_I, 0, 0 }, 0x00CC }, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */ - { { GDK_dead_grave, GDK_O, 0, 0 }, 0x00D2 }, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */ - { { GDK_dead_grave, GDK_U, 0, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_dead_grave, GDK_a, 0, 0 }, 0x00E0 }, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */ - { { GDK_dead_grave, GDK_e, 0, 0 }, 0x00E8 }, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */ - { { GDK_dead_grave, GDK_i, 0, 0 }, 0x00EC }, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */ - { { GDK_dead_grave, GDK_o, 0, 0 }, 0x00F2 }, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */ - { { GDK_dead_grave, GDK_u, 0, 0 }, 0x00F9 }, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */ - { { GDK_dead_acute, GDK_space, 0, 0 }, 0x0027 }, /* APOSTROPHE */ - { { GDK_dead_acute, GDK_apostrophe, 0, 0 }, 0x00B4 }, /* ACUTE_ACCENT */ - { { GDK_dead_acute, GDK_A, 0, 0 }, 0x00C1 }, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ - { { GDK_dead_acute, GDK_E, 0, 0 }, 0x00C9 }, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ - { { GDK_dead_acute, GDK_I, 0, 0 }, 0x00CD }, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ - { { GDK_dead_acute, GDK_O, 0, 0 }, 0x00D3 }, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ - { { GDK_dead_acute, GDK_U, 0, 0 }, 0x00DA }, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ - { { GDK_dead_acute, GDK_Y, 0, 0 }, 0x00DD }, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ - { { GDK_dead_acute, GDK_a, 0, 0 }, 0x00E1 }, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ - { { GDK_dead_acute, GDK_e, 0, 0 }, 0x00E9 }, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ - { { GDK_dead_acute, GDK_i, 0, 0 }, 0x00ED }, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ - { { GDK_dead_acute, GDK_o, 0, 0 }, 0x00F3 }, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ - { { GDK_dead_acute, GDK_u, 0, 0 }, 0x00FA }, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ - { { GDK_dead_acute, GDK_y, 0, 0 }, 0x00FD }, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ - { { GDK_dead_acute, GDK_acute, 0, 0 }, 0x00B4 }, /* ACUTE_ACCENT */ - { { GDK_dead_acute, GDK_dead_acute, 0, 0 }, 0x00B4 }, /* ACUTE_ACCENT */ - { { GDK_dead_circumflex, GDK_space, 0, 0 }, 0x005E }, /* CIRCUMFLEX_ACCENT */ - { { GDK_dead_circumflex, GDK_minus, 0, 0 }, 0x00AF }, /* MACRON */ - { { GDK_dead_circumflex, GDK_period, 0, 0 }, 0x00B7 }, /* MIDDLE_DOT */ - { { GDK_dead_circumflex, GDK_slash, 0, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_dead_circumflex, GDK_0, 0, 0 }, 0x00B0 }, /* DEGREE_SIGN */ - { { GDK_dead_circumflex, GDK_1, 0, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_dead_circumflex, GDK_2, 0, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_dead_circumflex, GDK_3, 0, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_dead_circumflex, GDK_A, 0, 0 }, 0x00C2 }, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_E, 0, 0 }, 0x00CA }, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_I, 0, 0 }, 0x00CE }, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_O, 0, 0 }, 0x00D4 }, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_U, 0, 0 }, 0x00DB }, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_underscore, 0, 0 }, 0x00AF }, /* MACRON */ - { { GDK_dead_circumflex, GDK_a, 0, 0 }, 0x00E2 }, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_e, 0, 0 }, 0x00EA }, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_i, 0, 0 }, 0x00EE }, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_o, 0, 0 }, 0x00F4 }, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_dead_circumflex, GDK_u, 0, 0 }, 0x00FB }, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_dead_tilde, GDK_space, 0, 0 }, 0x007E }, /* TILDE */ - { { GDK_dead_tilde, GDK_A, 0, 0 }, 0x00C3 }, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ - { { GDK_dead_tilde, GDK_I, 0, 0 }, 0x0128 }, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */ - { { GDK_dead_tilde, GDK_N, 0, 0 }, 0x00D1 }, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ - { { GDK_dead_tilde, GDK_O, 0, 0 }, 0x00D5 }, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ - { { GDK_dead_tilde, GDK_U, 0, 0 }, 0x0168 }, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */ - { { GDK_dead_tilde, GDK_a, 0, 0 }, 0x00E3 }, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ - { { GDK_dead_tilde, GDK_i, 0, 0 }, 0x0129 }, /* LATIN_SMALL_LETTER_I_WITH_TILDE */ - { { GDK_dead_tilde, GDK_n, 0, 0 }, 0x00F1 }, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ - { { GDK_dead_tilde, GDK_o, 0, 0 }, 0x00F5 }, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ - { { GDK_dead_tilde, GDK_u, 0, 0 }, 0x0169 }, /* LATIN_SMALL_LETTER_U_WITH_TILDE */ - { { GDK_dead_tilde, GDK_asciitilde, 0, 0 }, 0x007E }, /* TILDE */ - { { GDK_dead_tilde, GDK_dead_tilde, 0, 0 }, 0x007E }, /* TILDE */ - { { GDK_dead_macron, GDK_A, 0, 0 }, 0x0100 }, /* LATIN_CAPITAL_LETTER_A_WITH_MACRON */ - { { GDK_dead_macron, GDK_E, 0, 0 }, 0x0112 }, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ - { { GDK_dead_macron, GDK_I, 0, 0 }, 0x012A }, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ - { { GDK_dead_macron, GDK_O, 0, 0 }, 0x014C }, /* LATIN_CAPITAL_LETTER_O_WITH_MACRON */ - { { GDK_dead_macron, GDK_U, 0, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_dead_macron, GDK_a, 0, 0 }, 0x0101 }, /* LATIN_SMALL_LETTER_A_WITH_MACRON */ - { { GDK_dead_macron, GDK_e, 0, 0 }, 0x0113 }, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ - { { GDK_dead_macron, GDK_i, 0, 0 }, 0x012B }, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ - { { GDK_dead_macron, GDK_o, 0, 0 }, 0x014D }, /* LATIN_SMALL_LETTER_O_WITH_MACRON */ - { { GDK_dead_macron, GDK_u, 0, 0 }, 0x016B }, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ - { { GDK_dead_macron, GDK_macron, 0, 0 }, 0x00AF }, /* MACRON */ - { { GDK_dead_macron, GDK_dead_macron, 0, 0 }, 0x00AF }, /* MACRON */ - { { GDK_dead_breve, GDK_G, 0, 0 }, 0x011E }, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ - { { GDK_dead_breve, GDK_g, 0, 0 }, 0x011F }, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ - { { GDK_dead_abovedot, GDK_E, 0, 0 }, 0x0116 }, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */ - { { GDK_dead_abovedot, GDK_I, 0, 0 }, 0x0130 }, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */ - { { GDK_dead_abovedot, GDK_e, 0, 0 }, 0x0117 }, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */ - { { GDK_dead_abovedot, GDK_i, 0, 0 }, 0x0131 }, /* LATIN_SMALL_LETTER_DOTLESS_I */ - { { GDK_dead_abovedot, GDK_abovedot, 0, 0 }, 0x02D9 }, /* DOT_ABOVE */ - { { GDK_dead_abovedot, GDK_dead_abovedot, 0, 0 }, 0x02D9 }, /* DOT_ABOVE */ - { { GDK_dead_diaeresis, GDK_space, 0, 0 }, 0x00A8 }, /* DIAERESIS */ - { { GDK_dead_diaeresis, GDK_quotedbl, 0, 0 }, 0x00A8 }, /* DIAERESIS */ - { { GDK_dead_diaeresis, GDK_A, 0, 0 }, 0x00C4 }, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_E, 0, 0 }, 0x00CB }, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_I, 0, 0 }, 0x00CF }, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_O, 0, 0 }, 0x00D6 }, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_U, 0, 0 }, 0x00DC }, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_Y, 0, 0 }, 0x0178 }, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_a, 0, 0 }, 0x00E4 }, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_e, 0, 0 }, 0x00EB }, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_i, 0, 0 }, 0x00EF }, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_o, 0, 0 }, 0x00F6 }, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_u, 0, 0 }, 0x00FC }, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_y, 0, 0 }, 0x00FF }, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_dead_diaeresis, GDK_diaeresis, 0, 0 }, 0x00A8 }, /* DIAERESIS */ - { { GDK_dead_diaeresis, GDK_dead_diaeresis, 0, 0 }, 0x00A8 }, /* DIAERESIS */ - { { GDK_dead_abovering, GDK_A, 0, 0 }, 0x00C5 }, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_dead_abovering, GDK_a, 0, 0 }, 0x00E5 }, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_dead_abovering, GDK_dead_abovering, 0, 0 }, 0x02DA }, /* RING_ABOVE */ - { { GDK_dead_caron, GDK_C, 0, 0 }, 0x010C }, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */ - { { GDK_dead_caron, GDK_S, 0, 0 }, 0x0160 }, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */ - { { GDK_dead_caron, GDK_Z, 0, 0 }, 0x017D }, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ - { { GDK_dead_caron, GDK_c, 0, 0 }, 0x010D }, /* LATIN_SMALL_LETTER_C_WITH_CARON */ - { { GDK_dead_caron, GDK_s, 0, 0 }, 0x0161 }, /* LATIN_SMALL_LETTER_S_WITH_CARON */ - { { GDK_dead_caron, GDK_z, 0, 0 }, 0x017E }, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ - { { GDK_dead_caron, GDK_caron, 0, 0 }, 0x02C7 }, /* CARON */ - { { GDK_dead_caron, GDK_dead_caron, 0, 0 }, 0x02C7 }, /* CARON */ - { { GDK_dead_cedilla, GDK_comma, 0, 0 }, 0x00B8 }, /* CEDILLA */ - { { GDK_dead_cedilla, GDK_minus, 0, 0 }, 0x00AC }, /* NOT_SIGN */ - { { GDK_dead_cedilla, GDK_C, 0, 0 }, 0x00C7 }, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_G, 0, 0 }, 0x0122 }, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_K, 0, 0 }, 0x0136 }, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_L, 0, 0 }, 0x013B }, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_N, 0, 0 }, 0x0145 }, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_R, 0, 0 }, 0x0156 }, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_S, 0, 0 }, 0x015E }, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_c, 0, 0 }, 0x00E7 }, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_g, 0, 0 }, 0x0123 }, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_k, 0, 0 }, 0x0137 }, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_l, 0, 0 }, 0x013C }, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_n, 0, 0 }, 0x0146 }, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_r, 0, 0 }, 0x0157 }, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_s, 0, 0 }, 0x015F }, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ - { { GDK_dead_cedilla, GDK_cedilla, 0, 0 }, 0x00B8 }, /* CEDILLA */ - { { GDK_dead_cedilla, GDK_dead_cedilla, 0, 0 }, 0x00B8 }, /* CEDILLA */ - { { GDK_dead_ogonek, GDK_A, 0, 0 }, 0x0104 }, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_E, 0, 0 }, 0x0118 }, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_I, 0, 0 }, 0x012E }, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_U, 0, 0 }, 0x0172 }, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_a, 0, 0 }, 0x0105 }, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_e, 0, 0 }, 0x0119 }, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_i, 0, 0 }, 0x012F }, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_u, 0, 0 }, 0x0173 }, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */ - { { GDK_dead_ogonek, GDK_ogonek, 0, 0 }, 0x02DB }, /* OGONEK */ - { { GDK_dead_ogonek, GDK_dead_ogonek, 0, 0 }, 0x02DB }, /* OGONEK */ - { { GDK_Multi_key, GDK_space, GDK_space, 0 }, 0x00A0 }, /* NOxBREAK_SPACE */ - { { GDK_Multi_key, GDK_space, GDK_apostrophe, 0 }, 0x0027 }, /* APOSTROPHE */ - { { GDK_Multi_key, GDK_space, GDK_minus, 0 }, 0x007E }, /* TILDE */ - { { GDK_Multi_key, GDK_space, GDK_greater, 0 }, 0x005E }, /* CIRCUMFLEX_ACCENT */ - { { GDK_Multi_key, GDK_space, GDK_asciicircum, 0 }, 0x005E }, /* CIRCUMFLEX_ACCENT */ - { { GDK_Multi_key, GDK_space, GDK_grave, 0 }, 0x0060 }, /* GRAVE_ACCENT */ - { { GDK_Multi_key, GDK_space, GDK_asciitilde, 0 }, 0x007E }, /* TILDE */ - { { GDK_Multi_key, GDK_exclam, GDK_exclam, 0 }, 0x00A1 }, /* INVERTED_EXCLAMATION_MARK */ - { { GDK_Multi_key, GDK_exclam, GDK_P, 0 }, 0x00B6 }, /* PILCROW_SIGN */ - { { GDK_Multi_key, GDK_exclam, GDK_S, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_exclam, GDK_p, 0 }, 0x00B6 }, /* PILCROW_SIGN */ - { { GDK_Multi_key, GDK_exclam, GDK_s, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_quotedbl, GDK_quotedbl, 0 }, 0x00A8 }, /* DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_A, 0 }, 0x00C4 }, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_E, 0 }, 0x00CB }, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_I, 0 }, 0x00CF }, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_O, 0 }, 0x00D6 }, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_U, 0 }, 0x00DC }, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_Y, 0 }, 0x0178 }, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_a, 0 }, 0x00E4 }, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_e, 0 }, 0x00EB }, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_i, 0 }, 0x00EF }, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_o, 0 }, 0x00F6 }, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_u, 0 }, 0x00FC }, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_quotedbl, GDK_y, 0 }, 0x00FF }, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_apostrophe, GDK_space, 0 }, 0x0027 }, /* APOSTROPHE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_apostrophe, 0 }, 0x00B4 }, /* ACUTE_ACCENT */ - { { GDK_Multi_key, GDK_apostrophe, GDK_A, 0 }, 0x00C1 }, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_E, 0 }, 0x00C9 }, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_I, 0 }, 0x00CD }, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_O, 0 }, 0x00D3 }, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_U, 0 }, 0x00DA }, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_Y, 0 }, 0x00DD }, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_a, 0 }, 0x00E1 }, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_e, 0 }, 0x00E9 }, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_i, 0 }, 0x00ED }, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_o, 0 }, 0x00F3 }, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_u, 0 }, 0x00FA }, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_apostrophe, GDK_y, 0 }, 0x00FD }, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_parenleft, GDK_parenleft, 0 }, 0x005B }, /* LEFT_SQUARE_BRACKET */ - { { GDK_Multi_key, GDK_parenleft, GDK_minus, 0 }, 0x007B }, /* LEFT_CURLY_BRACKET */ - { { GDK_Multi_key, GDK_parenleft, GDK_G, 0 }, 0x011E }, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_parenleft, GDK_c, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_parenleft, GDK_g, 0 }, 0x011F }, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_parenleft, GDK_r, 0 }, 0x00AE }, /* REGISTERED_SIGN */ - { { GDK_Multi_key, GDK_parenright, GDK_parenright, 0 }, 0x005D }, /* RIGHT_SQUARE_BRACKET */ - { { GDK_Multi_key, GDK_parenright, GDK_minus, 0 }, 0x007D }, /* RIGHT_CURLY_BRACKET */ - { { GDK_Multi_key, GDK_asterisk, GDK_0, 0 }, 0x00B0 }, /* DEGREE_SIGN */ - { { GDK_Multi_key, GDK_asterisk, GDK_A, 0 }, 0x00C5 }, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_Multi_key, GDK_asterisk, GDK_a, 0 }, 0x00E5 }, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_Multi_key, GDK_plus, GDK_plus, 0 }, 0x0023 }, /* NUMBER_SIGN */ - { { GDK_Multi_key, GDK_plus, GDK_minus, 0 }, 0x00B1 }, /* PLUSxMINUS_SIGN */ - { { GDK_Multi_key, GDK_comma, GDK_comma, 0 }, 0x00B8 }, /* CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_minus, 0 }, 0x00AC }, /* NOT_SIGN */ - { { GDK_Multi_key, GDK_comma, GDK_A, 0 }, 0x0104 }, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_C, 0 }, 0x00C7 }, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_E, 0 }, 0x0118 }, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_G, 0 }, 0x0122 }, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_I, 0 }, 0x012E }, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_K, 0 }, 0x0136 }, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_L, 0 }, 0x013B }, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_N, 0 }, 0x0145 }, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_R, 0 }, 0x0156 }, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_S, 0 }, 0x015E }, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_U, 0 }, 0x0172 }, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_a, 0 }, 0x0105 }, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_c, 0 }, 0x00E7 }, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_e, 0 }, 0x0119 }, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_g, 0 }, 0x0123 }, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_i, 0 }, 0x012F }, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */ - { { GDK_Multi_key, GDK_comma, GDK_k, 0 }, 0x0137 }, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_l, 0 }, 0x013C }, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_n, 0 }, 0x0146 }, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_r, 0 }, 0x0157 }, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_s, 0 }, 0x015F }, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_comma, GDK_u, 0 }, 0x0173 }, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */ - { { GDK_Multi_key, GDK_minus, GDK_space, 0 }, 0x007E }, /* TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_parenleft, 0 }, 0x007B }, /* LEFT_CURLY_BRACKET */ - { { GDK_Multi_key, GDK_minus, GDK_parenright, 0 }, 0x007D }, /* RIGHT_CURLY_BRACKET */ - { { GDK_Multi_key, GDK_minus, GDK_plus, 0 }, 0x00B1 }, /* PLUSxMINUS_SIGN */ - { { GDK_Multi_key, GDK_minus, GDK_comma, 0 }, 0x00AC }, /* NOT_SIGN */ - { { GDK_Multi_key, GDK_minus, GDK_minus, 0 }, 0x00AD }, /* SOFT_HYPHEN */ - { { GDK_Multi_key, GDK_minus, GDK_colon, 0 }, 0x00F7 }, /* DIVISION_SIGN */ - { { GDK_Multi_key, GDK_minus, GDK_A, 0 }, 0x00C3 }, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_D, 0 }, 0x0110 }, /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */ - { { GDK_Multi_key, GDK_minus, GDK_E, 0 }, 0x0112 }, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_minus, GDK_I, 0 }, 0x012A }, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_minus, GDK_L, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_minus, GDK_N, 0 }, 0x00D1 }, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_O, 0 }, 0x00D5 }, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_U, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_minus, GDK_Y, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_minus, GDK_asciicircum, 0 }, 0x00AF }, /* MACRON */ - { { GDK_Multi_key, GDK_minus, GDK_a, 0 }, 0x00E3 }, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_d, 0 }, 0x0111 }, /* LATIN_SMALL_LETTER_D_WITH_STROKE */ - { { GDK_Multi_key, GDK_minus, GDK_e, 0 }, 0x0113 }, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_minus, GDK_i, 0 }, 0x012B }, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_minus, GDK_l, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_minus, GDK_n, 0 }, 0x00F1 }, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_o, 0 }, 0x00F5 }, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_minus, GDK_u, 0 }, 0x016B }, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ - { { GDK_Multi_key, GDK_minus, GDK_y, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_period, GDK_period, 0 }, 0x02D9 }, /* DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_B, 0 }, 0x1E02 }, /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_C, 0 }, 0x010A }, /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_D, 0 }, 0x1E0A }, /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_E, 0 }, 0x0116 }, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_F, 0 }, 0x1E1E }, /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_G, 0 }, 0x0120 }, /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_I, 0 }, 0x0130 }, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_M, 0 }, 0x1E40 }, /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_P, 0 }, 0x1E56 }, /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_S, 0 }, 0x1E60 }, /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_T, 0 }, 0x1E6A }, /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_asciicircum, 0 }, 0x00B7 }, /* MIDDLE_DOT */ - { { GDK_Multi_key, GDK_period, GDK_b, 0 }, 0x1E03 }, /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_c, 0 }, 0x010B }, /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_d, 0 }, 0x1E0B }, /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_e, 0 }, 0x0117 }, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_f, 0 }, 0x1E1F }, /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_g, 0 }, 0x0121 }, /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_i, 0 }, 0x0131 }, /* LATIN_SMALL_LETTER_DOTLESS_I */ - { { GDK_Multi_key, GDK_period, GDK_m, 0 }, 0x1E41 }, /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_p, 0 }, 0x1E57 }, /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_s, 0 }, 0x1E61 }, /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_period, GDK_t, 0 }, 0x1E6B }, /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_slash, GDK_slash, 0 }, 0x005C }, /* REVERSE_SOLIDUS */ - { { GDK_Multi_key, GDK_slash, GDK_less, 0 }, 0x005C }, /* REVERSE_SOLIDUS */ - { { GDK_Multi_key, GDK_slash, GDK_C, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_slash, GDK_O, 0 }, 0x00D8 }, /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */ - { { GDK_Multi_key, GDK_slash, GDK_T, 0 }, 0x0166 }, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */ - { { GDK_Multi_key, GDK_slash, GDK_U, 0 }, 0x00B5 }, /* MICRO_SIGN */ - { { GDK_Multi_key, GDK_slash, GDK_asciicircum, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_Multi_key, GDK_slash, GDK_c, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_slash, GDK_o, 0 }, 0x00F8 }, /* LATIN_SMALL_LETTER_O_WITH_STROKE */ - { { GDK_Multi_key, GDK_slash, GDK_t, 0 }, 0x0167 }, /* LATIN_SMALL_LETTER_T_WITH_STROKE */ - { { GDK_Multi_key, GDK_slash, GDK_u, 0 }, 0x00B5 }, /* MICRO_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_asterisk, 0 }, 0x00B0 }, /* DEGREE_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_C, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_S, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_X, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_asciicircum, 0 }, 0x00B0 }, /* DEGREE_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_c, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_s, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_0, GDK_x, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_1, GDK_S, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_Multi_key, GDK_1, GDK_asciicircum, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_Multi_key, GDK_1, GDK_s, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_Multi_key, GDK_2, GDK_S, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_Multi_key, GDK_2, GDK_asciicircum, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_Multi_key, GDK_2, GDK_s, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_Multi_key, GDK_3, GDK_S, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_Multi_key, GDK_3, GDK_asciicircum, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_Multi_key, GDK_3, GDK_s, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_Multi_key, GDK_colon, GDK_minus, 0 }, 0x00F7 }, /* DIVISION_SIGN */ - { { GDK_Multi_key, GDK_less, GDK_slash, 0 }, 0x005C }, /* REVERSE_SOLIDUS */ - { { GDK_Multi_key, GDK_less, GDK_less, 0 }, 0x00AB }, /* LEFTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */ - { { GDK_Multi_key, GDK_less, GDK_C, 0 }, 0x010C }, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */ - { { GDK_Multi_key, GDK_less, GDK_S, 0 }, 0x0160 }, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */ - { { GDK_Multi_key, GDK_less, GDK_Z, 0 }, 0x017D }, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ - { { GDK_Multi_key, GDK_less, GDK_c, 0 }, 0x010D }, /* LATIN_SMALL_LETTER_C_WITH_CARON */ - { { GDK_Multi_key, GDK_less, GDK_s, 0 }, 0x0161 }, /* LATIN_SMALL_LETTER_S_WITH_CARON */ - { { GDK_Multi_key, GDK_less, GDK_z, 0 }, 0x017E }, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ - { { GDK_Multi_key, GDK_equal, GDK_C, 0 }, 0x20AC }, /* EURO_SIGN */ - { { GDK_Multi_key, GDK_equal, GDK_L, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_equal, GDK_Y, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_equal, GDK_e, 0 }, 0x20AC }, /* EURO_SIGN */ - { { GDK_Multi_key, GDK_equal, GDK_l, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_equal, GDK_y, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_greater, GDK_space, 0 }, 0x005E }, /* CIRCUMFLEX_ACCENT */ - { { GDK_Multi_key, GDK_greater, GDK_greater, 0 }, 0x00BB }, /* RIGHTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */ - { { GDK_Multi_key, GDK_greater, GDK_A, 0 }, 0x00C2 }, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_E, 0 }, 0x00CA }, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_I, 0 }, 0x00CE }, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_O, 0 }, 0x00D4 }, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_U, 0 }, 0x00DB }, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_a, 0 }, 0x00E2 }, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_e, 0 }, 0x00EA }, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_i, 0 }, 0x00EE }, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_o, 0 }, 0x00F4 }, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_greater, GDK_u, 0 }, 0x00FB }, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_question, GDK_question, 0 }, 0x00BF }, /* INVERTED_QUESTION_MARK */ - { { GDK_Multi_key, GDK_A, GDK_quotedbl, 0 }, 0x00C4 }, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_A, GDK_apostrophe, 0 }, 0x00C1 }, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_A, GDK_asterisk, 0 }, 0x00C5 }, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_Multi_key, GDK_A, GDK_comma, 0 }, 0x0104 }, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */ - { { GDK_Multi_key, GDK_A, GDK_minus, 0 }, 0x00C3 }, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_A, GDK_greater, 0 }, 0x00C2 }, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_A, GDK_A, 0 }, 0x00C5 }, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_Multi_key, GDK_A, GDK_E, 0 }, 0x00C6 }, /* LATIN_CAPITAL_LETTER_AE */ - { { GDK_Multi_key, GDK_A, GDK_asciicircum, 0 }, 0x00C2 }, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_A, GDK_underscore, 0 }, 0x00AA }, /* FEMININE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_A, GDK_grave, 0 }, 0x00C0 }, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ - { { GDK_Multi_key, GDK_A, GDK_asciitilde, 0 }, 0x00C3 }, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_A, GDK_diaeresis, 0 }, 0x00C4 }, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_A, GDK_acute, 0 }, 0x00C1 }, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_B, GDK_period, 0 }, 0x1E02 }, /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_C, GDK_comma, 0 }, 0x00C7 }, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_C, GDK_period, 0 }, 0x010A }, /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_C, GDK_slash, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_C, GDK_0, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_C, GDK_less, 0 }, 0x010C }, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */ - { { GDK_Multi_key, GDK_C, GDK_equal, 0 }, 0x20AC }, /* EURO_SIGN */ - { { GDK_Multi_key, GDK_C, GDK_O, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_C, GDK_o, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_C, GDK_bar, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_D, GDK_minus, 0 }, 0x0110 }, /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */ - { { GDK_Multi_key, GDK_D, GDK_period, 0 }, 0x1E0A }, /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_E, GDK_quotedbl, 0 }, 0x00CB }, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_E, GDK_apostrophe, 0 }, 0x00C9 }, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_E, GDK_comma, 0 }, 0x0118 }, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */ - { { GDK_Multi_key, GDK_E, GDK_minus, 0 }, 0x0112 }, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_E, GDK_period, 0 }, 0x0116 }, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_E, GDK_greater, 0 }, 0x00CA }, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_E, GDK_asciicircum, 0 }, 0x00CA }, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_E, GDK_underscore, 0 }, 0x0112 }, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_E, GDK_grave, 0 }, 0x00C8 }, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */ - { { GDK_Multi_key, GDK_E, GDK_diaeresis, 0 }, 0x00CB }, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_E, GDK_acute, 0 }, 0x00C9 }, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_F, GDK_period, 0 }, 0x1E1E }, /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_G, GDK_parenleft, 0 }, 0x011E }, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_G, GDK_comma, 0 }, 0x0122 }, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_G, GDK_period, 0 }, 0x0120 }, /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_G, GDK_U, 0 }, 0x011E }, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_G, GDK_breve, 0 }, 0x011E }, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_I, GDK_quotedbl, 0 }, 0x00CF }, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_I, GDK_apostrophe, 0 }, 0x00CD }, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_I, GDK_comma, 0 }, 0x012E }, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */ - { { GDK_Multi_key, GDK_I, GDK_minus, 0 }, 0x012A }, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_I, GDK_period, 0 }, 0x0130 }, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_I, GDK_greater, 0 }, 0x00CE }, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_I, GDK_asciicircum, 0 }, 0x00CE }, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_I, GDK_underscore, 0 }, 0x012A }, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_I, GDK_grave, 0 }, 0x00CC }, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */ - { { GDK_Multi_key, GDK_I, GDK_asciitilde, 0 }, 0x0128 }, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */ - { { GDK_Multi_key, GDK_I, GDK_diaeresis, 0 }, 0x00CF }, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_I, GDK_acute, 0 }, 0x00CD }, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_K, GDK_comma, 0 }, 0x0136 }, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_L, GDK_comma, 0 }, 0x013B }, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_L, GDK_minus, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_L, GDK_equal, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_L, GDK_V, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_Multi_key, GDK_M, GDK_period, 0 }, 0x1E40 }, /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_N, GDK_comma, 0 }, 0x0145 }, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_N, GDK_minus, 0 }, 0x00D1 }, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_N, GDK_G, 0 }, 0x014A }, /* LATIN_CAPITAL_LETTER_ENG */ - { { GDK_Multi_key, GDK_N, GDK_asciitilde, 0 }, 0x00D1 }, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_O, GDK_quotedbl, 0 }, 0x00D6 }, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_O, GDK_apostrophe, 0 }, 0x00D3 }, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_O, GDK_minus, 0 }, 0x00D5 }, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_O, GDK_slash, 0 }, 0x00D8 }, /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */ - { { GDK_Multi_key, GDK_O, GDK_greater, 0 }, 0x00D4 }, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_O, GDK_C, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_O, GDK_E, 0 }, 0x0152 }, /* LATIN_CAPITAL_LIGATURE_OE */ - { { GDK_Multi_key, GDK_O, GDK_R, 0 }, 0x00AE }, /* REGISTERED_SIGN */ - { { GDK_Multi_key, GDK_O, GDK_S, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_O, GDK_X, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_O, GDK_asciicircum, 0 }, 0x00D4 }, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_O, GDK_underscore, 0 }, 0x00BA }, /* MASCULINE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_O, GDK_grave, 0 }, 0x00D2 }, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */ - { { GDK_Multi_key, GDK_O, GDK_c, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_O, GDK_x, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_O, GDK_asciitilde, 0 }, 0x00D5 }, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_O, GDK_diaeresis, 0 }, 0x00D6 }, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_O, GDK_acute, 0 }, 0x00D3 }, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_P, GDK_exclam, 0 }, 0x00B6 }, /* PILCROW_SIGN */ - { { GDK_Multi_key, GDK_P, GDK_period, 0 }, 0x1E56 }, /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_R, GDK_comma, 0 }, 0x0156 }, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_R, GDK_O, 0 }, 0x00AE }, /* REGISTERED_SIGN */ - { { GDK_Multi_key, GDK_S, GDK_exclam, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_S, GDK_comma, 0 }, 0x015E }, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_S, GDK_period, 0 }, 0x1E60 }, /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_S, GDK_0, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_S, GDK_1, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_Multi_key, GDK_S, GDK_2, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_Multi_key, GDK_S, GDK_3, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_Multi_key, GDK_S, GDK_less, 0 }, 0x0160 }, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */ - { { GDK_Multi_key, GDK_S, GDK_O, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_S, GDK_cedilla, 0 }, 0x015E }, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_T, GDK_minus, 0 }, 0x0166 }, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */ - { { GDK_Multi_key, GDK_T, GDK_period, 0 }, 0x1E6A }, /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_T, GDK_slash, 0 }, 0x0166 }, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */ - { { GDK_Multi_key, GDK_T, GDK_H, 0 }, 0x00DE }, /* LATIN_CAPITAL_LETTER_THORN */ - { { GDK_Multi_key, GDK_U, GDK_quotedbl, 0 }, 0x00DC }, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_U, GDK_apostrophe, 0 }, 0x00DA }, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_U, GDK_comma, 0 }, 0x0172 }, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */ - { { GDK_Multi_key, GDK_U, GDK_minus, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_U, GDK_slash, 0 }, 0x00B5 }, /* MICRO_SIGN */ - { { GDK_Multi_key, GDK_U, GDK_greater, 0 }, 0x00DB }, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_U, GDK_asciicircum, 0 }, 0x00DB }, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_U, GDK_underscore, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_U, GDK_grave, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_U, GDK_asciitilde, 0 }, 0x0168 }, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */ - { { GDK_Multi_key, GDK_U, GDK_diaeresis, 0 }, 0x00DC }, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_U, GDK_acute, 0 }, 0x00DA }, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_V, GDK_L, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_Multi_key, GDK_W, GDK_asciicircum, 0 }, 0x0174 }, /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_X, GDK_0, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_X, GDK_O, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_X, GDK_o, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_Y, GDK_quotedbl, 0 }, 0x0178 }, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_Y, GDK_apostrophe, 0 }, 0x00DD }, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_Y, GDK_minus, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_Y, GDK_equal, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_Y, GDK_asciicircum, 0 }, 0x0176 }, /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_Y, GDK_diaeresis, 0 }, 0x0178 }, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_Y, GDK_acute, 0 }, 0x00DD }, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_Z, GDK_less, 0 }, 0x017D }, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ - { { GDK_Multi_key, GDK_asciicircum, GDK_space, 0 }, 0x005E }, /* CIRCUMFLEX_ACCENT */ - { { GDK_Multi_key, GDK_asciicircum, GDK_minus, 0 }, 0x00AF }, /* MACRON */ - { { GDK_Multi_key, GDK_asciicircum, GDK_period, 0 }, 0x00B7 }, /* MIDDLE_DOT */ - { { GDK_Multi_key, GDK_asciicircum, GDK_slash, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_Multi_key, GDK_asciicircum, GDK_0, 0 }, 0x00B0 }, /* DEGREE_SIGN */ - { { GDK_Multi_key, GDK_asciicircum, GDK_1, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_Multi_key, GDK_asciicircum, GDK_2, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_Multi_key, GDK_asciicircum, GDK_3, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_Multi_key, GDK_asciicircum, GDK_A, 0 }, 0x00C2 }, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_E, 0 }, 0x00CA }, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_I, 0 }, 0x00CE }, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_O, 0 }, 0x00D4 }, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_U, 0 }, 0x00DB }, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_W, 0 }, 0x0174 }, /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_Y, 0 }, 0x0176 }, /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_underscore, 0 }, 0x00AF }, /* MACRON */ - { { GDK_Multi_key, GDK_asciicircum, GDK_a, 0 }, 0x00E2 }, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_e, 0 }, 0x00EA }, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_i, 0 }, 0x00EE }, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_o, 0 }, 0x00F4 }, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_u, 0 }, 0x00FB }, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_w, 0 }, 0x0175 }, /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_asciicircum, GDK_y, 0 }, 0x0177 }, /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_underscore, GDK_A, 0 }, 0x00AA }, /* FEMININE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_underscore, GDK_E, 0 }, 0x0112 }, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_underscore, GDK_I, 0 }, 0x012A }, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_underscore, GDK_O, 0 }, 0x00BA }, /* MASCULINE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_underscore, GDK_U, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_underscore, GDK_asciicircum, 0 }, 0x00AF }, /* MACRON */ - { { GDK_Multi_key, GDK_underscore, GDK_underscore, 0 }, 0x00AF }, /* MACRON */ - { { GDK_Multi_key, GDK_underscore, GDK_a, 0 }, 0x00AA }, /* FEMININE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_underscore, GDK_e, 0 }, 0x0113 }, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_underscore, GDK_i, 0 }, 0x012B }, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_underscore, GDK_o, 0 }, 0x00BA }, /* MASCULINE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_underscore, GDK_u, 0 }, 0x016B }, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ - { { GDK_Multi_key, GDK_grave, GDK_space, 0 }, 0x0060 }, /* GRAVE_ACCENT */ - { { GDK_Multi_key, GDK_grave, GDK_A, 0 }, 0x00C0 }, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_E, 0 }, 0x00C8 }, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_I, 0 }, 0x00CC }, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_O, 0 }, 0x00D2 }, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_U, 0 }, 0x00D9 }, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_a, 0 }, 0x00E0 }, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_e, 0 }, 0x00E8 }, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_i, 0 }, 0x00EC }, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_o, 0 }, 0x00F2 }, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */ - { { GDK_Multi_key, GDK_grave, GDK_u, 0 }, 0x00F9 }, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_a, GDK_quotedbl, 0 }, 0x00E4 }, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_a, GDK_apostrophe, 0 }, 0x00E1 }, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_a, GDK_asterisk, 0 }, 0x00E5 }, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_Multi_key, GDK_a, GDK_comma, 0 }, 0x0105 }, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */ - { { GDK_Multi_key, GDK_a, GDK_minus, 0 }, 0x00E3 }, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_a, GDK_greater, 0 }, 0x00E2 }, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_a, GDK_asciicircum, 0 }, 0x00E2 }, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_a, GDK_underscore, 0 }, 0x00AA }, /* FEMININE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_a, GDK_grave, 0 }, 0x00E0 }, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */ - { { GDK_Multi_key, GDK_a, GDK_a, 0 }, 0x00E5 }, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ - { { GDK_Multi_key, GDK_a, GDK_e, 0 }, 0x00E6 }, /* LATIN_SMALL_LETTER_AE */ - { { GDK_Multi_key, GDK_a, GDK_asciitilde, 0 }, 0x00E3 }, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_a, GDK_diaeresis, 0 }, 0x00E4 }, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_a, GDK_acute, 0 }, 0x00E1 }, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_b, GDK_period, 0 }, 0x1E03 }, /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_c, GDK_comma, 0 }, 0x00E7 }, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_c, GDK_period, 0 }, 0x010B }, /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_c, GDK_slash, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_c, GDK_0, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_c, GDK_less, 0 }, 0x010D }, /* LATIN_SMALL_LETTER_C_WITH_CARON */ - { { GDK_Multi_key, GDK_c, GDK_O, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_c, GDK_o, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_c, GDK_bar, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_d, GDK_minus, 0 }, 0x0111 }, /* LATIN_SMALL_LETTER_D_WITH_STROKE */ - { { GDK_Multi_key, GDK_d, GDK_period, 0 }, 0x1E0B }, /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_e, GDK_quotedbl, 0 }, 0x00EB }, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_e, GDK_apostrophe, 0 }, 0x00E9 }, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_e, GDK_comma, 0 }, 0x0119 }, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */ - { { GDK_Multi_key, GDK_e, GDK_minus, 0 }, 0x0113 }, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_e, GDK_period, 0 }, 0x0117 }, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_e, GDK_equal, 0 }, 0x20AC }, /* EURO_SIGN */ - { { GDK_Multi_key, GDK_e, GDK_greater, 0 }, 0x00EA }, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_e, GDK_asciicircum, 0 }, 0x00EA }, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_e, GDK_underscore, 0 }, 0x0113 }, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ - { { GDK_Multi_key, GDK_e, GDK_grave, 0 }, 0x00E8 }, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */ - { { GDK_Multi_key, GDK_e, GDK_diaeresis, 0 }, 0x00EB }, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_e, GDK_acute, 0 }, 0x00E9 }, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_f, GDK_period, 0 }, 0x1E1F }, /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_g, GDK_parenleft, 0 }, 0x011F }, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_g, GDK_comma, 0 }, 0x0123 }, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_g, GDK_period, 0 }, 0x0121 }, /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_g, GDK_U, 0 }, 0x011F }, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_g, GDK_breve, 0 }, 0x011F }, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_i, GDK_quotedbl, 0 }, 0x00EF }, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_i, GDK_apostrophe, 0 }, 0x00ED }, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_i, GDK_comma, 0 }, 0x012F }, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */ - { { GDK_Multi_key, GDK_i, GDK_minus, 0 }, 0x012B }, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_i, GDK_period, 0 }, 0x0131 }, /* LATIN_SMALL_LETTER_DOTLESS_I */ - { { GDK_Multi_key, GDK_i, GDK_greater, 0 }, 0x00EE }, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_i, GDK_asciicircum, 0 }, 0x00EE }, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_i, GDK_underscore, 0 }, 0x012B }, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ - { { GDK_Multi_key, GDK_i, GDK_grave, 0 }, 0x00EC }, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */ - { { GDK_Multi_key, GDK_i, GDK_asciitilde, 0 }, 0x0129 }, /* LATIN_SMALL_LETTER_I_WITH_TILDE */ - { { GDK_Multi_key, GDK_i, GDK_diaeresis, 0 }, 0x00EF }, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_i, GDK_acute, 0 }, 0x00ED }, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_k, GDK_comma, 0 }, 0x0137 }, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_k, GDK_k, 0 }, 0x0138 }, /* LATIN_SMALL_LETTER_KRA */ - { { GDK_Multi_key, GDK_l, GDK_comma, 0 }, 0x013C }, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_l, GDK_minus, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_l, GDK_equal, 0 }, 0x00A3 }, /* POUND_SIGN */ - { { GDK_Multi_key, GDK_l, GDK_v, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_Multi_key, GDK_m, GDK_period, 0 }, 0x1E41 }, /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_n, GDK_comma, 0 }, 0x0146 }, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_n, GDK_minus, 0 }, 0x00F1 }, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_n, GDK_g, 0 }, 0x014B }, /* LATIN_SMALL_LETTER_ENG */ - { { GDK_Multi_key, GDK_n, GDK_asciitilde, 0 }, 0x00F1 }, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_o, GDK_quotedbl, 0 }, 0x00F6 }, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_o, GDK_apostrophe, 0 }, 0x00F3 }, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_o, GDK_minus, 0 }, 0x00F5 }, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_o, GDK_slash, 0 }, 0x00F8 }, /* LATIN_SMALL_LETTER_O_WITH_STROKE */ - { { GDK_Multi_key, GDK_o, GDK_greater, 0 }, 0x00F4 }, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_o, GDK_C, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_o, GDK_X, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_o, GDK_asciicircum, 0 }, 0x00F4 }, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_o, GDK_underscore, 0 }, 0x00BA }, /* MASCULINE_ORDINAL_INDICATOR */ - { { GDK_Multi_key, GDK_o, GDK_grave, 0 }, 0x00F2 }, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */ - { { GDK_Multi_key, GDK_o, GDK_c, 0 }, 0x00A9 }, /* COPYRIGHT_SIGN */ - { { GDK_Multi_key, GDK_o, GDK_e, 0 }, 0x0153 }, /* LATIN_SMALL_LIGATURE_OE */ - { { GDK_Multi_key, GDK_o, GDK_s, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_o, GDK_x, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_o, GDK_asciitilde, 0 }, 0x00F5 }, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_o, GDK_diaeresis, 0 }, 0x00F6 }, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_o, GDK_acute, 0 }, 0x00F3 }, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_p, GDK_exclam, 0 }, 0x00B6 }, /* PILCROW_SIGN */ - { { GDK_Multi_key, GDK_p, GDK_period, 0 }, 0x1E57 }, /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_r, GDK_comma, 0 }, 0x0157 }, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_s, GDK_exclam, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_s, GDK_comma, 0 }, 0x015F }, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_s, GDK_period, 0 }, 0x1E61 }, /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_s, GDK_0, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_s, GDK_1, 0 }, 0x00B9 }, /* SUPERSCRIPT_ONE */ - { { GDK_Multi_key, GDK_s, GDK_2, 0 }, 0x00B2 }, /* SUPERSCRIPT_TWO */ - { { GDK_Multi_key, GDK_s, GDK_3, 0 }, 0x00B3 }, /* SUPERSCRIPT_THREE */ - { { GDK_Multi_key, GDK_s, GDK_less, 0 }, 0x0161 }, /* LATIN_SMALL_LETTER_S_WITH_CARON */ - { { GDK_Multi_key, GDK_s, GDK_o, 0 }, 0x00A7 }, /* SECTION_SIGN */ - { { GDK_Multi_key, GDK_s, GDK_s, 0 }, 0x00DF }, /* LATIN_SMALL_LETTER_SHARP_S */ - { { GDK_Multi_key, GDK_s, GDK_cedilla, 0 }, 0x015F }, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_t, GDK_minus, 0 }, 0x0167 }, /* LATIN_SMALL_LETTER_T_WITH_STROKE */ - { { GDK_Multi_key, GDK_t, GDK_period, 0 }, 0x1E6B }, /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */ - { { GDK_Multi_key, GDK_t, GDK_slash, 0 }, 0x0167 }, /* LATIN_SMALL_LETTER_T_WITH_STROKE */ - { { GDK_Multi_key, GDK_t, GDK_h, 0 }, 0x00FE }, /* LATIN_SMALL_LETTER_THORN */ - { { GDK_Multi_key, GDK_u, GDK_quotedbl, 0 }, 0x00FC }, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_u, GDK_apostrophe, 0 }, 0x00FA }, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_u, GDK_comma, 0 }, 0x0173 }, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */ - { { GDK_Multi_key, GDK_u, GDK_minus, 0 }, 0x016B }, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ - { { GDK_Multi_key, GDK_u, GDK_slash, 0 }, 0x00B5 }, /* MICRO_SIGN */ - { { GDK_Multi_key, GDK_u, GDK_greater, 0 }, 0x00FB }, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_u, GDK_asciicircum, 0 }, 0x00FB }, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_u, GDK_underscore, 0 }, 0x016B }, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ - { { GDK_Multi_key, GDK_u, GDK_grave, 0 }, 0x00F9 }, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */ - { { GDK_Multi_key, GDK_u, GDK_asciitilde, 0 }, 0x0169 }, /* LATIN_SMALL_LETTER_U_WITH_TILDE */ - { { GDK_Multi_key, GDK_u, GDK_diaeresis, 0 }, 0x00FC }, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_u, GDK_acute, 0 }, 0x00FA }, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_v, GDK_Z, 0 }, 0x017D }, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ - { { GDK_Multi_key, GDK_v, GDK_l, 0 }, 0x007C }, /* VERTICAL_LINE */ - { { GDK_Multi_key, GDK_v, GDK_z, 0 }, 0x017E }, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ - { { GDK_Multi_key, GDK_w, GDK_asciicircum, 0 }, 0x0175 }, /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_x, GDK_0, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_x, GDK_O, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_x, GDK_o, 0 }, 0x00A4 }, /* CURRENCY_SIGN */ - { { GDK_Multi_key, GDK_x, GDK_x, 0 }, 0x00D7 }, /* MULTIPLICATION_SIGN */ - { { GDK_Multi_key, GDK_y, GDK_quotedbl, 0 }, 0x00FF }, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_y, GDK_apostrophe, 0 }, 0x00FD }, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_y, GDK_minus, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_y, GDK_equal, 0 }, 0x00A5 }, /* YEN_SIGN */ - { { GDK_Multi_key, GDK_y, GDK_asciicircum, 0 }, 0x0177 }, /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */ - { { GDK_Multi_key, GDK_y, GDK_diaeresis, 0 }, 0x00FF }, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_y, GDK_acute, 0 }, 0x00FD }, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_z, GDK_less, 0 }, 0x017E }, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ - { { GDK_Multi_key, GDK_bar, GDK_C, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_bar, GDK_c, 0 }, 0x00A2 }, /* CENT_SIGN */ - { { GDK_Multi_key, GDK_asciitilde, GDK_space, 0 }, 0x007E }, /* TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_A, 0 }, 0x00C3 }, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_I, 0 }, 0x0128 }, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_N, 0 }, 0x00D1 }, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_O, 0 }, 0x00D5 }, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_U, 0 }, 0x0168 }, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_a, 0 }, 0x00E3 }, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_i, 0 }, 0x0129 }, /* LATIN_SMALL_LETTER_I_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_n, 0 }, 0x00F1 }, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_o, 0 }, 0x00F5 }, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ - { { GDK_Multi_key, GDK_asciitilde, GDK_u, 0 }, 0x0169 }, /* LATIN_SMALL_LETTER_U_WITH_TILDE */ - { { GDK_Multi_key, GDK_diaeresis, GDK_A, 0 }, 0x00C4 }, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_E, 0 }, 0x00CB }, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_I, 0 }, 0x00CF }, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_O, 0 }, 0x00D6 }, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_U, 0 }, 0x00DC }, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_Y, 0 }, 0x0178 }, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_a, 0 }, 0x00E4 }, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_e, 0 }, 0x00EB }, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_i, 0 }, 0x00EF }, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_o, 0 }, 0x00F6 }, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_u, 0 }, 0x00FC }, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_diaeresis, GDK_y, 0 }, 0x00FF }, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ - { { GDK_Multi_key, GDK_acute, GDK_A, 0 }, 0x00C1 }, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_E, 0 }, 0x00C9 }, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_I, 0 }, 0x00CD }, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_O, 0 }, 0x00D3 }, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_U, 0 }, 0x00DA }, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_Y, 0 }, 0x00DD }, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_a, 0 }, 0x00E1 }, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_e, 0 }, 0x00E9 }, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_i, 0 }, 0x00ED }, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_o, 0 }, 0x00F3 }, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_u, 0 }, 0x00FA }, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ - { { GDK_Multi_key, GDK_acute, GDK_y, 0 }, 0x00FD }, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ - { { GDK_Multi_key, GDK_cedilla, GDK_S, 0 }, 0x015E }, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_cedilla, GDK_s, 0 }, 0x015F }, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ - { { GDK_Multi_key, GDK_breve, GDK_G, 0 }, 0x011E }, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ - { { GDK_Multi_key, GDK_breve, GDK_g, 0 }, 0x011F }, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ +static guint16 gtk_compose_seqs[] = { + GDK_dead_grave, GDK_space, 0, 0, 0, 0x0060, /* GRAVE_ACCENT */ + GDK_dead_grave, GDK_A, 0, 0, 0, 0x00C0, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ + GDK_dead_grave, GDK_E, 0, 0, 0, 0x00C8, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */ + GDK_dead_grave, GDK_I, 0, 0, 0, 0x00CC, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */ + GDK_dead_grave, GDK_O, 0, 0, 0, 0x00D2, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */ + GDK_dead_grave, GDK_U, 0, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_dead_grave, GDK_a, 0, 0, 0, 0x00E0, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */ + GDK_dead_grave, GDK_e, 0, 0, 0, 0x00E8, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */ + GDK_dead_grave, GDK_i, 0, 0, 0, 0x00EC, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */ + GDK_dead_grave, GDK_o, 0, 0, 0, 0x00F2, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */ + GDK_dead_grave, GDK_u, 0, 0, 0, 0x00F9, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */ + GDK_dead_acute, GDK_space, 0, 0, 0, 0x0027, /* APOSTROPHE */ + GDK_dead_acute, GDK_apostrophe, 0, 0, 0, 0x00B4, /* ACUTE_ACCENT */ + GDK_dead_acute, GDK_A, 0, 0, 0, 0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ + GDK_dead_acute, GDK_E, 0, 0, 0, 0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ + GDK_dead_acute, GDK_I, 0, 0, 0, 0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ + GDK_dead_acute, GDK_O, 0, 0, 0, 0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ + GDK_dead_acute, GDK_U, 0, 0, 0, 0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ + GDK_dead_acute, GDK_Y, 0, 0, 0, 0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ + GDK_dead_acute, GDK_a, 0, 0, 0, 0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ + GDK_dead_acute, GDK_e, 0, 0, 0, 0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ + GDK_dead_acute, GDK_i, 0, 0, 0, 0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ + GDK_dead_acute, GDK_o, 0, 0, 0, 0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ + GDK_dead_acute, GDK_u, 0, 0, 0, 0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ + GDK_dead_acute, GDK_y, 0, 0, 0, 0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ + GDK_dead_acute, GDK_acute, 0, 0, 0, 0x00B4, /* ACUTE_ACCENT */ + GDK_dead_acute, GDK_dead_acute, 0, 0, 0, 0x00B4, /* ACUTE_ACCENT */ + GDK_dead_circumflex, GDK_space, 0, 0, 0, 0x005E, /* CIRCUMFLEX_ACCENT */ + GDK_dead_circumflex, GDK_minus, 0, 0, 0, 0x00AF, /* MACRON */ + GDK_dead_circumflex, GDK_period, 0, 0, 0, 0x00B7, /* MIDDLE_DOT */ + GDK_dead_circumflex, GDK_slash, 0, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_dead_circumflex, GDK_0, 0, 0, 0, 0x00B0, /* DEGREE_SIGN */ + GDK_dead_circumflex, GDK_1, 0, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_dead_circumflex, GDK_2, 0, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_dead_circumflex, GDK_3, 0, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_dead_circumflex, GDK_A, 0, 0, 0, 0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_E, 0, 0, 0, 0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_I, 0, 0, 0, 0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_O, 0, 0, 0, 0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_U, 0, 0, 0, 0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_underscore, 0, 0, 0, 0x00AF, /* MACRON */ + GDK_dead_circumflex, GDK_a, 0, 0, 0, 0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_e, 0, 0, 0, 0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_i, 0, 0, 0, 0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_o, 0, 0, 0, 0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_dead_circumflex, GDK_u, 0, 0, 0, 0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_dead_tilde, GDK_space, 0, 0, 0, 0x007E, /* TILDE */ + GDK_dead_tilde, GDK_A, 0, 0, 0, 0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ + GDK_dead_tilde, GDK_I, 0, 0, 0, 0x0128, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */ + GDK_dead_tilde, GDK_N, 0, 0, 0, 0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ + GDK_dead_tilde, GDK_O, 0, 0, 0, 0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ + GDK_dead_tilde, GDK_U, 0, 0, 0, 0x0168, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */ + GDK_dead_tilde, GDK_a, 0, 0, 0, 0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ + GDK_dead_tilde, GDK_i, 0, 0, 0, 0x0129, /* LATIN_SMALL_LETTER_I_WITH_TILDE */ + GDK_dead_tilde, GDK_n, 0, 0, 0, 0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ + GDK_dead_tilde, GDK_o, 0, 0, 0, 0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ + GDK_dead_tilde, GDK_u, 0, 0, 0, 0x0169, /* LATIN_SMALL_LETTER_U_WITH_TILDE */ + GDK_dead_tilde, GDK_asciitilde, 0, 0, 0, 0x007E, /* TILDE */ + GDK_dead_tilde, GDK_dead_tilde, 0, 0, 0, 0x007E, /* TILDE */ + GDK_dead_macron, GDK_A, 0, 0, 0, 0x0100, /* LATIN_CAPITAL_LETTER_A_WITH_MACRON */ + GDK_dead_macron, GDK_E, 0, 0, 0, 0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ + GDK_dead_macron, GDK_I, 0, 0, 0, 0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ + GDK_dead_macron, GDK_O, 0, 0, 0, 0x014C, /* LATIN_CAPITAL_LETTER_O_WITH_MACRON */ + GDK_dead_macron, GDK_U, 0, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_dead_macron, GDK_a, 0, 0, 0, 0x0101, /* LATIN_SMALL_LETTER_A_WITH_MACRON */ + GDK_dead_macron, GDK_e, 0, 0, 0, 0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ + GDK_dead_macron, GDK_i, 0, 0, 0, 0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ + GDK_dead_macron, GDK_o, 0, 0, 0, 0x014D, /* LATIN_SMALL_LETTER_O_WITH_MACRON */ + GDK_dead_macron, GDK_u, 0, 0, 0, 0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ + GDK_dead_macron, GDK_macron, 0, 0, 0, 0x00AF, /* MACRON */ + GDK_dead_macron, GDK_dead_macron, 0, 0, 0, 0x00AF, /* MACRON */ + GDK_dead_breve, GDK_G, 0, 0, 0, 0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ + GDK_dead_breve, GDK_g, 0, 0, 0, 0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ + GDK_dead_abovedot, GDK_E, 0, 0, 0, 0x0116, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */ + GDK_dead_abovedot, GDK_I, 0, 0, 0, 0x0130, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */ + GDK_dead_abovedot, GDK_e, 0, 0, 0, 0x0117, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */ + GDK_dead_abovedot, GDK_i, 0, 0, 0, 0x0131, /* LATIN_SMALL_LETTER_DOTLESS_I */ + GDK_dead_abovedot, GDK_abovedot, 0, 0, 0, 0x02D9, /* DOT_ABOVE */ + GDK_dead_abovedot, GDK_dead_abovedot, 0, 0, 0, 0x02D9, /* DOT_ABOVE */ + GDK_dead_diaeresis, GDK_space, 0, 0, 0, 0x00A8, /* DIAERESIS */ + GDK_dead_diaeresis, GDK_quotedbl, 0, 0, 0, 0x00A8, /* DIAERESIS */ + GDK_dead_diaeresis, GDK_A, 0, 0, 0, 0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_E, 0, 0, 0, 0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_I, 0, 0, 0, 0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_O, 0, 0, 0, 0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_U, 0, 0, 0, 0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_Y, 0, 0, 0, 0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_a, 0, 0, 0, 0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_e, 0, 0, 0, 0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_i, 0, 0, 0, 0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_o, 0, 0, 0, 0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_u, 0, 0, 0, 0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_y, 0, 0, 0, 0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ + GDK_dead_diaeresis, GDK_diaeresis, 0, 0, 0, 0x00A8, /* DIAERESIS */ + GDK_dead_diaeresis, GDK_dead_diaeresis, 0, 0, 0, 0x00A8, /* DIAERESIS */ + GDK_dead_abovering, GDK_A, 0, 0, 0, 0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ + GDK_dead_abovering, GDK_a, 0, 0, 0, 0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ + GDK_dead_abovering, GDK_dead_abovering, 0, 0, 0, 0x02DA, /* RING_ABOVE */ + GDK_dead_caron, GDK_C, 0, 0, 0, 0x010C, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */ + GDK_dead_caron, GDK_S, 0, 0, 0, 0x0160, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */ + GDK_dead_caron, GDK_Z, 0, 0, 0, 0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ + GDK_dead_caron, GDK_c, 0, 0, 0, 0x010D, /* LATIN_SMALL_LETTER_C_WITH_CARON */ + GDK_dead_caron, GDK_s, 0, 0, 0, 0x0161, /* LATIN_SMALL_LETTER_S_WITH_CARON */ + GDK_dead_caron, GDK_z, 0, 0, 0, 0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ + GDK_dead_caron, GDK_caron, 0, 0, 0, 0x02C7, /* CARON */ + GDK_dead_caron, GDK_dead_caron, 0, 0, 0, 0x02C7, /* CARON */ + GDK_dead_cedilla, GDK_comma, 0, 0, 0, 0x00B8, /* CEDILLA */ + GDK_dead_cedilla, GDK_minus, 0, 0, 0, 0x00AC, /* NOT_SIGN */ + GDK_dead_cedilla, GDK_C, 0, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_G, 0, 0, 0, 0x0122, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_K, 0, 0, 0, 0x0136, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_L, 0, 0, 0, 0x013B, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_N, 0, 0, 0, 0x0145, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_R, 0, 0, 0, 0x0156, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_S, 0, 0, 0, 0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_c, 0, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_g, 0, 0, 0, 0x0123, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_k, 0, 0, 0, 0x0137, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_l, 0, 0, 0, 0x013C, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_n, 0, 0, 0, 0x0146, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_r, 0, 0, 0, 0x0157, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_s, 0, 0, 0, 0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ + GDK_dead_cedilla, GDK_cedilla, 0, 0, 0, 0x00B8, /* CEDILLA */ + GDK_dead_cedilla, GDK_dead_cedilla, 0, 0, 0, 0x00B8, /* CEDILLA */ + GDK_dead_ogonek, GDK_A, 0, 0, 0, 0x0104, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */ + GDK_dead_ogonek, GDK_E, 0, 0, 0, 0x0118, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */ + GDK_dead_ogonek, GDK_I, 0, 0, 0, 0x012E, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */ + GDK_dead_ogonek, GDK_U, 0, 0, 0, 0x0172, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */ + GDK_dead_ogonek, GDK_a, 0, 0, 0, 0x0105, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */ + GDK_dead_ogonek, GDK_e, 0, 0, 0, 0x0119, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */ + GDK_dead_ogonek, GDK_i, 0, 0, 0, 0x012F, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */ + GDK_dead_ogonek, GDK_u, 0, 0, 0, 0x0173, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */ + GDK_dead_ogonek, GDK_ogonek, 0, 0, 0, 0x02DB, /* OGONEK */ + GDK_dead_ogonek, GDK_dead_ogonek, 0, 0, 0, 0x02DB, /* OGONEK */ + GDK_Multi_key, GDK_space, GDK_space, 0, 0, 0x00A0, /* NOxBREAK_SPACE */ + GDK_Multi_key, GDK_space, GDK_apostrophe, 0, 0, 0x0027, /* APOSTROPHE */ + GDK_Multi_key, GDK_space, GDK_minus, 0, 0, 0x007E, /* TILDE */ + GDK_Multi_key, GDK_space, GDK_greater, 0, 0, 0x005E, /* CIRCUMFLEX_ACCENT */ + GDK_Multi_key, GDK_space, GDK_asciicircum, 0, 0, 0x005E, /* CIRCUMFLEX_ACCENT */ + GDK_Multi_key, GDK_space, GDK_grave, 0, 0, 0x0060, /* GRAVE_ACCENT */ + GDK_Multi_key, GDK_space, GDK_asciitilde, 0, 0, 0x007E, /* TILDE */ + GDK_Multi_key, GDK_exclam, GDK_exclam, 0, 0, 0x00A1, /* INVERTED_EXCLAMATION_MARK */ + GDK_Multi_key, GDK_exclam, GDK_P, 0, 0, 0x00B6, /* PILCROW_SIGN */ + GDK_Multi_key, GDK_exclam, GDK_S, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_exclam, GDK_p, 0, 0, 0x00B6, /* PILCROW_SIGN */ + GDK_Multi_key, GDK_exclam, GDK_s, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_quotedbl, GDK_quotedbl, 0, 0, 0x00A8, /* DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_A, 0, 0, 0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_E, 0, 0, 0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_I, 0, 0, 0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_O, 0, 0, 0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_U, 0, 0, 0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_Y, 0, 0, 0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_a, 0, 0, 0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_e, 0, 0, 0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_i, 0, 0, 0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_o, 0, 0, 0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_u, 0, 0, 0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_quotedbl, GDK_y, 0, 0, 0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_apostrophe, GDK_space, 0, 0, 0x0027, /* APOSTROPHE */ + GDK_Multi_key, GDK_apostrophe, GDK_apostrophe, 0, 0, 0x00B4, /* ACUTE_ACCENT */ + GDK_Multi_key, GDK_apostrophe, GDK_A, 0, 0, 0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_E, 0, 0, 0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_I, 0, 0, 0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_O, 0, 0, 0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_U, 0, 0, 0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_Y, 0, 0, 0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_a, 0, 0, 0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_e, 0, 0, 0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_i, 0, 0, 0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_o, 0, 0, 0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_u, 0, 0, 0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_apostrophe, GDK_y, 0, 0, 0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_parenleft, GDK_parenleft, 0, 0, 0x005B, /* LEFT_SQUARE_BRACKET */ + GDK_Multi_key, GDK_parenleft, GDK_minus, 0, 0, 0x007B, /* LEFT_CURLY_BRACKET */ + GDK_Multi_key, GDK_parenleft, GDK_G, 0, 0, 0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_parenleft, GDK_c, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_parenleft, GDK_g, 0, 0, 0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_parenleft, GDK_r, 0, 0, 0x00AE, /* REGISTERED_SIGN */ + GDK_Multi_key, GDK_parenright, GDK_parenright, 0, 0, 0x005D, /* RIGHT_SQUARE_BRACKET */ + GDK_Multi_key, GDK_parenright, GDK_minus, 0, 0, 0x007D, /* RIGHT_CURLY_BRACKET */ + GDK_Multi_key, GDK_asterisk, GDK_0, 0, 0, 0x00B0, /* DEGREE_SIGN */ + GDK_Multi_key, GDK_asterisk, GDK_A, 0, 0, 0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ + GDK_Multi_key, GDK_asterisk, GDK_a, 0, 0, 0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ + GDK_Multi_key, GDK_plus, GDK_plus, 0, 0, 0x0023, /* NUMBER_SIGN */ + GDK_Multi_key, GDK_plus, GDK_minus, 0, 0, 0x00B1, /* PLUSxMINUS_SIGN */ + GDK_Multi_key, GDK_comma, GDK_comma, 0, 0, 0x00B8, /* CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_minus, 0, 0, 0x00AC, /* NOT_SIGN */ + GDK_Multi_key, GDK_comma, GDK_A, 0, 0, 0x0104, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_C, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_E, 0, 0, 0x0118, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_G, 0, 0, 0x0122, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_I, 0, 0, 0x012E, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_K, 0, 0, 0x0136, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_L, 0, 0, 0x013B, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_N, 0, 0, 0x0145, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_R, 0, 0, 0x0156, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_S, 0, 0, 0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_U, 0, 0, 0x0172, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_a, 0, 0, 0x0105, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_c, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_e, 0, 0, 0x0119, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_g, 0, 0, 0x0123, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_i, 0, 0, 0x012F, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */ + GDK_Multi_key, GDK_comma, GDK_k, 0, 0, 0x0137, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_l, 0, 0, 0x013C, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_n, 0, 0, 0x0146, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_r, 0, 0, 0x0157, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_s, 0, 0, 0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_comma, GDK_u, 0, 0, 0x0173, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */ + GDK_Multi_key, GDK_minus, GDK_space, 0, 0, 0x007E, /* TILDE */ + GDK_Multi_key, GDK_minus, GDK_parenleft, 0, 0, 0x007B, /* LEFT_CURLY_BRACKET */ + GDK_Multi_key, GDK_minus, GDK_parenright, 0, 0, 0x007D, /* RIGHT_CURLY_BRACKET */ + GDK_Multi_key, GDK_minus, GDK_plus, 0, 0, 0x00B1, /* PLUSxMINUS_SIGN */ + GDK_Multi_key, GDK_minus, GDK_comma, 0, 0, 0x00AC, /* NOT_SIGN */ + GDK_Multi_key, GDK_minus, GDK_minus, 0, 0, 0x00AD, /* SOFT_HYPHEN */ + GDK_Multi_key, GDK_minus, GDK_colon, 0, 0, 0x00F7, /* DIVISION_SIGN */ + GDK_Multi_key, GDK_minus, GDK_A, 0, 0, 0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_minus, GDK_D, 0, 0, 0x0110, /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */ + GDK_Multi_key, GDK_minus, GDK_E, 0, 0, 0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_minus, GDK_I, 0, 0, 0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_minus, GDK_L, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_minus, GDK_N, 0, 0, 0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_minus, GDK_O, 0, 0, 0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_minus, GDK_U, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_minus, GDK_Y, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_minus, GDK_asciicircum, 0, 0, 0x00AF, /* MACRON */ + GDK_Multi_key, GDK_minus, GDK_a, 0, 0, 0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_minus, GDK_d, 0, 0, 0x0111, /* LATIN_SMALL_LETTER_D_WITH_STROKE */ + GDK_Multi_key, GDK_minus, GDK_e, 0, 0, 0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_minus, GDK_i, 0, 0, 0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_minus, GDK_l, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_minus, GDK_n, 0, 0, 0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_minus, GDK_o, 0, 0, 0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_minus, GDK_u, 0, 0, 0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ + GDK_Multi_key, GDK_minus, GDK_y, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_period, GDK_period, 0, 0, 0x02D9, /* DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_B, 0, 0, 0x1E02, /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_C, 0, 0, 0x010A, /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_D, 0, 0, 0x1E0A, /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_E, 0, 0, 0x0116, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_F, 0, 0, 0x1E1E, /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_G, 0, 0, 0x0120, /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_I, 0, 0, 0x0130, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_M, 0, 0, 0x1E40, /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_P, 0, 0, 0x1E56, /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_S, 0, 0, 0x1E60, /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_T, 0, 0, 0x1E6A, /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_asciicircum, 0, 0, 0x00B7, /* MIDDLE_DOT */ + GDK_Multi_key, GDK_period, GDK_b, 0, 0, 0x1E03, /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_c, 0, 0, 0x010B, /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_d, 0, 0, 0x1E0B, /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_e, 0, 0, 0x0117, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_f, 0, 0, 0x1E1F, /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_g, 0, 0, 0x0121, /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_i, 0, 0, 0x0131, /* LATIN_SMALL_LETTER_DOTLESS_I */ + GDK_Multi_key, GDK_period, GDK_m, 0, 0, 0x1E41, /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_p, 0, 0, 0x1E57, /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_s, 0, 0, 0x1E61, /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_period, GDK_t, 0, 0, 0x1E6B, /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_slash, GDK_slash, 0, 0, 0x005C, /* REVERSE_SOLIDUS */ + GDK_Multi_key, GDK_slash, GDK_less, 0, 0, 0x005C, /* REVERSE_SOLIDUS */ + GDK_Multi_key, GDK_slash, GDK_C, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_slash, GDK_O, 0, 0, 0x00D8, /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */ + GDK_Multi_key, GDK_slash, GDK_T, 0, 0, 0x0166, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */ + GDK_Multi_key, GDK_slash, GDK_U, 0, 0, 0x00B5, /* MICRO_SIGN */ + GDK_Multi_key, GDK_slash, GDK_asciicircum, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_Multi_key, GDK_slash, GDK_c, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_slash, GDK_o, 0, 0, 0x00F8, /* LATIN_SMALL_LETTER_O_WITH_STROKE */ + GDK_Multi_key, GDK_slash, GDK_t, 0, 0, 0x0167, /* LATIN_SMALL_LETTER_T_WITH_STROKE */ + GDK_Multi_key, GDK_slash, GDK_u, 0, 0, 0x00B5, /* MICRO_SIGN */ + GDK_Multi_key, GDK_0, GDK_asterisk, 0, 0, 0x00B0, /* DEGREE_SIGN */ + GDK_Multi_key, GDK_0, GDK_C, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_0, GDK_S, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_0, GDK_X, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_0, GDK_asciicircum, 0, 0, 0x00B0, /* DEGREE_SIGN */ + GDK_Multi_key, GDK_0, GDK_c, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_0, GDK_s, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_0, GDK_x, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_1, GDK_S, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_Multi_key, GDK_1, GDK_asciicircum, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_Multi_key, GDK_1, GDK_s, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_Multi_key, GDK_2, GDK_S, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_Multi_key, GDK_2, GDK_asciicircum, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_Multi_key, GDK_2, GDK_s, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_Multi_key, GDK_3, GDK_S, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_Multi_key, GDK_3, GDK_asciicircum, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_Multi_key, GDK_3, GDK_s, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_Multi_key, GDK_colon, GDK_minus, 0, 0, 0x00F7, /* DIVISION_SIGN */ + GDK_Multi_key, GDK_less, GDK_slash, 0, 0, 0x005C, /* REVERSE_SOLIDUS */ + GDK_Multi_key, GDK_less, GDK_less, 0, 0, 0x00AB, /* LEFTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */ + GDK_Multi_key, GDK_less, GDK_C, 0, 0, 0x010C, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */ + GDK_Multi_key, GDK_less, GDK_S, 0, 0, 0x0160, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */ + GDK_Multi_key, GDK_less, GDK_Z, 0, 0, 0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ + GDK_Multi_key, GDK_less, GDK_c, 0, 0, 0x010D, /* LATIN_SMALL_LETTER_C_WITH_CARON */ + GDK_Multi_key, GDK_less, GDK_s, 0, 0, 0x0161, /* LATIN_SMALL_LETTER_S_WITH_CARON */ + GDK_Multi_key, GDK_less, GDK_z, 0, 0, 0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ + GDK_Multi_key, GDK_equal, GDK_C, 0, 0, 0x20AC, /* EURO_SIGN */ + GDK_Multi_key, GDK_equal, GDK_L, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_equal, GDK_Y, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_equal, GDK_e, 0, 0, 0x20AC, /* EURO_SIGN */ + GDK_Multi_key, GDK_equal, GDK_l, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_equal, GDK_y, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_greater, GDK_space, 0, 0, 0x005E, /* CIRCUMFLEX_ACCENT */ + GDK_Multi_key, GDK_greater, GDK_greater, 0, 0, 0x00BB, /* RIGHTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */ + GDK_Multi_key, GDK_greater, GDK_A, 0, 0, 0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_E, 0, 0, 0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_I, 0, 0, 0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_O, 0, 0, 0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_U, 0, 0, 0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_a, 0, 0, 0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_e, 0, 0, 0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_i, 0, 0, 0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_o, 0, 0, 0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_greater, GDK_u, 0, 0, 0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_question, GDK_question, 0, 0, 0x00BF, /* INVERTED_QUESTION_MARK */ + GDK_Multi_key, GDK_A, GDK_quotedbl, 0, 0, 0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_A, GDK_apostrophe, 0, 0, 0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_A, GDK_asterisk, 0, 0, 0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ + GDK_Multi_key, GDK_A, GDK_comma, 0, 0, 0x0104, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */ + GDK_Multi_key, GDK_A, GDK_minus, 0, 0, 0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_A, GDK_greater, 0, 0, 0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_A, GDK_A, 0, 0, 0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */ + GDK_Multi_key, GDK_A, GDK_E, 0, 0, 0x00C6, /* LATIN_CAPITAL_LETTER_AE */ + GDK_Multi_key, GDK_A, GDK_asciicircum, 0, 0, 0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_A, GDK_underscore, 0, 0, 0x00AA, /* FEMININE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_A, GDK_grave, 0, 0, 0x00C0, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ + GDK_Multi_key, GDK_A, GDK_asciitilde, 0, 0, 0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_A, GDK_diaeresis, 0, 0, 0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_A, GDK_acute, 0, 0, 0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_B, GDK_period, 0, 0, 0x1E02, /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_C, GDK_comma, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ + GDK_Multi_key, GDK_C, GDK_period, 0, 0, 0x010A, /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_C, GDK_slash, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_C, GDK_0, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_C, GDK_less, 0, 0, 0x010C, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */ + GDK_Multi_key, GDK_C, GDK_equal, 0, 0, 0x20AC, /* EURO_SIGN */ + GDK_Multi_key, GDK_C, GDK_O, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_C, GDK_o, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_C, GDK_bar, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_D, GDK_minus, 0, 0, 0x0110, /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */ + GDK_Multi_key, GDK_D, GDK_period, 0, 0, 0x1E0A, /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_E, GDK_quotedbl, 0, 0, 0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_E, GDK_apostrophe, 0, 0, 0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_E, GDK_comma, 0, 0, 0x0118, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */ + GDK_Multi_key, GDK_E, GDK_minus, 0, 0, 0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_E, GDK_period, 0, 0, 0x0116, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_E, GDK_greater, 0, 0, 0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_E, GDK_asciicircum, 0, 0, 0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_E, GDK_underscore, 0, 0, 0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_E, GDK_grave, 0, 0, 0x00C8, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */ + GDK_Multi_key, GDK_E, GDK_diaeresis, 0, 0, 0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_E, GDK_acute, 0, 0, 0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_F, GDK_period, 0, 0, 0x1E1E, /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_G, GDK_parenleft, 0, 0, 0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_G, GDK_comma, 0, 0, 0x0122, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */ + GDK_Multi_key, GDK_G, GDK_period, 0, 0, 0x0120, /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_G, GDK_U, 0, 0, 0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_G, GDK_breve, 0, 0, 0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_I, GDK_quotedbl, 0, 0, 0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_I, GDK_apostrophe, 0, 0, 0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_I, GDK_comma, 0, 0, 0x012E, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */ + GDK_Multi_key, GDK_I, GDK_minus, 0, 0, 0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_I, GDK_period, 0, 0, 0x0130, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_I, GDK_greater, 0, 0, 0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_I, GDK_asciicircum, 0, 0, 0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_I, GDK_underscore, 0, 0, 0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_I, GDK_grave, 0, 0, 0x00CC, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */ + GDK_Multi_key, GDK_I, GDK_asciitilde, 0, 0, 0x0128, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */ + GDK_Multi_key, GDK_I, GDK_diaeresis, 0, 0, 0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_I, GDK_acute, 0, 0, 0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_K, GDK_comma, 0, 0, 0x0136, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */ + GDK_Multi_key, GDK_L, GDK_comma, 0, 0, 0x013B, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */ + GDK_Multi_key, GDK_L, GDK_minus, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_L, GDK_equal, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_L, GDK_V, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_Multi_key, GDK_M, GDK_period, 0, 0, 0x1E40, /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_N, GDK_comma, 0, 0, 0x0145, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */ + GDK_Multi_key, GDK_N, GDK_minus, 0, 0, 0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_N, GDK_G, 0, 0, 0x014A, /* LATIN_CAPITAL_LETTER_ENG */ + GDK_Multi_key, GDK_N, GDK_asciitilde, 0, 0, 0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_O, GDK_quotedbl, 0, 0, 0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_O, GDK_apostrophe, 0, 0, 0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_O, GDK_minus, 0, 0, 0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_O, GDK_slash, 0, 0, 0x00D8, /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */ + GDK_Multi_key, GDK_O, GDK_greater, 0, 0, 0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_O, GDK_C, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_O, GDK_E, 0, 0, 0x0152, /* LATIN_CAPITAL_LIGATURE_OE */ + GDK_Multi_key, GDK_O, GDK_R, 0, 0, 0x00AE, /* REGISTERED_SIGN */ + GDK_Multi_key, GDK_O, GDK_S, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_O, GDK_X, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_O, GDK_asciicircum, 0, 0, 0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_O, GDK_underscore, 0, 0, 0x00BA, /* MASCULINE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_O, GDK_grave, 0, 0, 0x00D2, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */ + GDK_Multi_key, GDK_O, GDK_c, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_O, GDK_x, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_O, GDK_asciitilde, 0, 0, 0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_O, GDK_diaeresis, 0, 0, 0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_O, GDK_acute, 0, 0, 0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_P, GDK_exclam, 0, 0, 0x00B6, /* PILCROW_SIGN */ + GDK_Multi_key, GDK_P, GDK_period, 0, 0, 0x1E56, /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_R, GDK_comma, 0, 0, 0x0156, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */ + GDK_Multi_key, GDK_R, GDK_O, 0, 0, 0x00AE, /* REGISTERED_SIGN */ + GDK_Multi_key, GDK_S, GDK_exclam, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_S, GDK_comma, 0, 0, 0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_S, GDK_period, 0, 0, 0x1E60, /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_S, GDK_0, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_S, GDK_1, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_Multi_key, GDK_S, GDK_2, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_Multi_key, GDK_S, GDK_3, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_Multi_key, GDK_S, GDK_less, 0, 0, 0x0160, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */ + GDK_Multi_key, GDK_S, GDK_O, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_S, GDK_cedilla, 0, 0, 0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_T, GDK_minus, 0, 0, 0x0166, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */ + GDK_Multi_key, GDK_T, GDK_period, 0, 0, 0x1E6A, /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_T, GDK_slash, 0, 0, 0x0166, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */ + GDK_Multi_key, GDK_T, GDK_H, 0, 0, 0x00DE, /* LATIN_CAPITAL_LETTER_THORN */ + GDK_Multi_key, GDK_U, GDK_quotedbl, 0, 0, 0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_U, GDK_apostrophe, 0, 0, 0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_U, GDK_comma, 0, 0, 0x0172, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */ + GDK_Multi_key, GDK_U, GDK_minus, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_U, GDK_slash, 0, 0, 0x00B5, /* MICRO_SIGN */ + GDK_Multi_key, GDK_U, GDK_greater, 0, 0, 0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_U, GDK_asciicircum, 0, 0, 0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_U, GDK_underscore, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_U, GDK_grave, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_U, GDK_asciitilde, 0, 0, 0x0168, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */ + GDK_Multi_key, GDK_U, GDK_diaeresis, 0, 0, 0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_U, GDK_acute, 0, 0, 0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_V, GDK_L, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_Multi_key, GDK_W, GDK_asciicircum, 0, 0, 0x0174, /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_X, GDK_0, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_X, GDK_O, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_X, GDK_o, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_Y, GDK_quotedbl, 0, 0, 0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_Y, GDK_apostrophe, 0, 0, 0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_Y, GDK_minus, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_Y, GDK_equal, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_Y, GDK_asciicircum, 0, 0, 0x0176, /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_Y, GDK_diaeresis, 0, 0, 0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_Y, GDK_acute, 0, 0, 0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_Z, GDK_less, 0, 0, 0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ + GDK_Multi_key, GDK_asciicircum, GDK_space, 0, 0, 0x005E, /* CIRCUMFLEX_ACCENT */ + GDK_Multi_key, GDK_asciicircum, GDK_minus, 0, 0, 0x00AF, /* MACRON */ + GDK_Multi_key, GDK_asciicircum, GDK_period, 0, 0, 0x00B7, /* MIDDLE_DOT */ + GDK_Multi_key, GDK_asciicircum, GDK_slash, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_Multi_key, GDK_asciicircum, GDK_0, 0, 0, 0x00B0, /* DEGREE_SIGN */ + GDK_Multi_key, GDK_asciicircum, GDK_1, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_Multi_key, GDK_asciicircum, GDK_2, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_Multi_key, GDK_asciicircum, GDK_3, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_Multi_key, GDK_asciicircum, GDK_A, 0, 0, 0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_E, 0, 0, 0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_I, 0, 0, 0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_O, 0, 0, 0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_U, 0, 0, 0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_W, 0, 0, 0x0174, /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_Y, 0, 0, 0x0176, /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_underscore, 0, 0, 0x00AF, /* MACRON */ + GDK_Multi_key, GDK_asciicircum, GDK_a, 0, 0, 0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_e, 0, 0, 0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_i, 0, 0, 0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_o, 0, 0, 0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_u, 0, 0, 0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_w, 0, 0, 0x0175, /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_asciicircum, GDK_y, 0, 0, 0x0177, /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_underscore, GDK_A, 0, 0, 0x00AA, /* FEMININE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_underscore, GDK_E, 0, 0, 0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_underscore, GDK_I, 0, 0, 0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_underscore, GDK_O, 0, 0, 0x00BA, /* MASCULINE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_underscore, GDK_U, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_underscore, GDK_asciicircum, 0, 0, 0x00AF, /* MACRON */ + GDK_Multi_key, GDK_underscore, GDK_underscore, 0, 0, 0x00AF, /* MACRON */ + GDK_Multi_key, GDK_underscore, GDK_a, 0, 0, 0x00AA, /* FEMININE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_underscore, GDK_e, 0, 0, 0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_underscore, GDK_i, 0, 0, 0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_underscore, GDK_o, 0, 0, 0x00BA, /* MASCULINE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_underscore, GDK_u, 0, 0, 0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ + GDK_Multi_key, GDK_grave, GDK_space, 0, 0, 0x0060, /* GRAVE_ACCENT */ + GDK_Multi_key, GDK_grave, GDK_A, 0, 0, 0x00C0, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_E, 0, 0, 0x00C8, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_I, 0, 0, 0x00CC, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_O, 0, 0, 0x00D2, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_U, 0, 0, 0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_a, 0, 0, 0x00E0, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_e, 0, 0, 0x00E8, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_i, 0, 0, 0x00EC, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_o, 0, 0, 0x00F2, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */ + GDK_Multi_key, GDK_grave, GDK_u, 0, 0, 0x00F9, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_a, GDK_quotedbl, 0, 0, 0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_a, GDK_apostrophe, 0, 0, 0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_a, GDK_asterisk, 0, 0, 0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ + GDK_Multi_key, GDK_a, GDK_comma, 0, 0, 0x0105, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */ + GDK_Multi_key, GDK_a, GDK_minus, 0, 0, 0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_a, GDK_greater, 0, 0, 0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_a, GDK_asciicircum, 0, 0, 0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_a, GDK_underscore, 0, 0, 0x00AA, /* FEMININE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_a, GDK_grave, 0, 0, 0x00E0, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */ + GDK_Multi_key, GDK_a, GDK_a, 0, 0, 0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */ + GDK_Multi_key, GDK_a, GDK_e, 0, 0, 0x00E6, /* LATIN_SMALL_LETTER_AE */ + GDK_Multi_key, GDK_a, GDK_asciitilde, 0, 0, 0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_a, GDK_diaeresis, 0, 0, 0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_a, GDK_acute, 0, 0, 0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_b, GDK_period, 0, 0, 0x1E03, /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_c, GDK_comma, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ + GDK_Multi_key, GDK_c, GDK_period, 0, 0, 0x010B, /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_c, GDK_slash, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_c, GDK_0, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_c, GDK_less, 0, 0, 0x010D, /* LATIN_SMALL_LETTER_C_WITH_CARON */ + GDK_Multi_key, GDK_c, GDK_O, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_c, GDK_o, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_c, GDK_bar, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_d, GDK_minus, 0, 0, 0x0111, /* LATIN_SMALL_LETTER_D_WITH_STROKE */ + GDK_Multi_key, GDK_d, GDK_period, 0, 0, 0x1E0B, /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_e, GDK_quotedbl, 0, 0, 0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_e, GDK_apostrophe, 0, 0, 0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_e, GDK_comma, 0, 0, 0x0119, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */ + GDK_Multi_key, GDK_e, GDK_minus, 0, 0, 0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_e, GDK_period, 0, 0, 0x0117, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_e, GDK_equal, 0, 0, 0x20AC, /* EURO_SIGN */ + GDK_Multi_key, GDK_e, GDK_greater, 0, 0, 0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_e, GDK_asciicircum, 0, 0, 0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_e, GDK_underscore, 0, 0, 0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */ + GDK_Multi_key, GDK_e, GDK_grave, 0, 0, 0x00E8, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */ + GDK_Multi_key, GDK_e, GDK_diaeresis, 0, 0, 0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_e, GDK_acute, 0, 0, 0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_f, GDK_period, 0, 0, 0x1E1F, /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_g, GDK_parenleft, 0, 0, 0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_g, GDK_comma, 0, 0, 0x0123, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */ + GDK_Multi_key, GDK_g, GDK_period, 0, 0, 0x0121, /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_g, GDK_U, 0, 0, 0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_g, GDK_breve, 0, 0, 0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_i, GDK_quotedbl, 0, 0, 0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_i, GDK_apostrophe, 0, 0, 0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_i, GDK_comma, 0, 0, 0x012F, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */ + GDK_Multi_key, GDK_i, GDK_minus, 0, 0, 0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_i, GDK_period, 0, 0, 0x0131, /* LATIN_SMALL_LETTER_DOTLESS_I */ + GDK_Multi_key, GDK_i, GDK_greater, 0, 0, 0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_i, GDK_asciicircum, 0, 0, 0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_i, GDK_underscore, 0, 0, 0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */ + GDK_Multi_key, GDK_i, GDK_grave, 0, 0, 0x00EC, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */ + GDK_Multi_key, GDK_i, GDK_asciitilde, 0, 0, 0x0129, /* LATIN_SMALL_LETTER_I_WITH_TILDE */ + GDK_Multi_key, GDK_i, GDK_diaeresis, 0, 0, 0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_i, GDK_acute, 0, 0, 0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_k, GDK_comma, 0, 0, 0x0137, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */ + GDK_Multi_key, GDK_k, GDK_k, 0, 0, 0x0138, /* LATIN_SMALL_LETTER_KRA */ + GDK_Multi_key, GDK_l, GDK_comma, 0, 0, 0x013C, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */ + GDK_Multi_key, GDK_l, GDK_minus, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_l, GDK_equal, 0, 0, 0x00A3, /* POUND_SIGN */ + GDK_Multi_key, GDK_l, GDK_v, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_Multi_key, GDK_m, GDK_period, 0, 0, 0x1E41, /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_n, GDK_comma, 0, 0, 0x0146, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */ + GDK_Multi_key, GDK_n, GDK_minus, 0, 0, 0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_n, GDK_g, 0, 0, 0x014B, /* LATIN_SMALL_LETTER_ENG */ + GDK_Multi_key, GDK_n, GDK_asciitilde, 0, 0, 0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_o, GDK_quotedbl, 0, 0, 0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_o, GDK_apostrophe, 0, 0, 0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_o, GDK_minus, 0, 0, 0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_o, GDK_slash, 0, 0, 0x00F8, /* LATIN_SMALL_LETTER_O_WITH_STROKE */ + GDK_Multi_key, GDK_o, GDK_greater, 0, 0, 0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_o, GDK_C, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_o, GDK_X, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_o, GDK_asciicircum, 0, 0, 0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_o, GDK_underscore, 0, 0, 0x00BA, /* MASCULINE_ORDINAL_INDICATOR */ + GDK_Multi_key, GDK_o, GDK_grave, 0, 0, 0x00F2, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */ + GDK_Multi_key, GDK_o, GDK_c, 0, 0, 0x00A9, /* COPYRIGHT_SIGN */ + GDK_Multi_key, GDK_o, GDK_e, 0, 0, 0x0153, /* LATIN_SMALL_LIGATURE_OE */ + GDK_Multi_key, GDK_o, GDK_s, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_o, GDK_x, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_o, GDK_asciitilde, 0, 0, 0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_o, GDK_diaeresis, 0, 0, 0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_o, GDK_acute, 0, 0, 0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_p, GDK_exclam, 0, 0, 0x00B6, /* PILCROW_SIGN */ + GDK_Multi_key, GDK_p, GDK_period, 0, 0, 0x1E57, /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_r, GDK_comma, 0, 0, 0x0157, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */ + GDK_Multi_key, GDK_s, GDK_exclam, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_s, GDK_comma, 0, 0, 0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_s, GDK_period, 0, 0, 0x1E61, /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_s, GDK_0, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_s, GDK_1, 0, 0, 0x00B9, /* SUPERSCRIPT_ONE */ + GDK_Multi_key, GDK_s, GDK_2, 0, 0, 0x00B2, /* SUPERSCRIPT_TWO */ + GDK_Multi_key, GDK_s, GDK_3, 0, 0, 0x00B3, /* SUPERSCRIPT_THREE */ + GDK_Multi_key, GDK_s, GDK_less, 0, 0, 0x0161, /* LATIN_SMALL_LETTER_S_WITH_CARON */ + GDK_Multi_key, GDK_s, GDK_o, 0, 0, 0x00A7, /* SECTION_SIGN */ + GDK_Multi_key, GDK_s, GDK_s, 0, 0, 0x00DF, /* LATIN_SMALL_LETTER_SHARP_S */ + GDK_Multi_key, GDK_s, GDK_cedilla, 0, 0, 0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_t, GDK_minus, 0, 0, 0x0167, /* LATIN_SMALL_LETTER_T_WITH_STROKE */ + GDK_Multi_key, GDK_t, GDK_period, 0, 0, 0x1E6B, /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */ + GDK_Multi_key, GDK_t, GDK_slash, 0, 0, 0x0167, /* LATIN_SMALL_LETTER_T_WITH_STROKE */ + GDK_Multi_key, GDK_t, GDK_h, 0, 0, 0x00FE, /* LATIN_SMALL_LETTER_THORN */ + GDK_Multi_key, GDK_u, GDK_quotedbl, 0, 0, 0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_u, GDK_apostrophe, 0, 0, 0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_u, GDK_comma, 0, 0, 0x0173, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */ + GDK_Multi_key, GDK_u, GDK_minus, 0, 0, 0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ + GDK_Multi_key, GDK_u, GDK_slash, 0, 0, 0x00B5, /* MICRO_SIGN */ + GDK_Multi_key, GDK_u, GDK_greater, 0, 0, 0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_u, GDK_asciicircum, 0, 0, 0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_u, GDK_underscore, 0, 0, 0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */ + GDK_Multi_key, GDK_u, GDK_grave, 0, 0, 0x00F9, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */ + GDK_Multi_key, GDK_u, GDK_asciitilde, 0, 0, 0x0169, /* LATIN_SMALL_LETTER_U_WITH_TILDE */ + GDK_Multi_key, GDK_u, GDK_diaeresis, 0, 0, 0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_u, GDK_acute, 0, 0, 0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_v, GDK_Z, 0, 0, 0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */ + GDK_Multi_key, GDK_v, GDK_l, 0, 0, 0x007C, /* VERTICAL_LINE */ + GDK_Multi_key, GDK_v, GDK_z, 0, 0, 0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ + GDK_Multi_key, GDK_w, GDK_asciicircum, 0, 0, 0x0175, /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_x, GDK_0, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_x, GDK_O, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_x, GDK_o, 0, 0, 0x00A4, /* CURRENCY_SIGN */ + GDK_Multi_key, GDK_x, GDK_x, 0, 0, 0x00D7, /* MULTIPLICATION_SIGN */ + GDK_Multi_key, GDK_y, GDK_quotedbl, 0, 0, 0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_y, GDK_apostrophe, 0, 0, 0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_y, GDK_minus, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_y, GDK_equal, 0, 0, 0x00A5, /* YEN_SIGN */ + GDK_Multi_key, GDK_y, GDK_asciicircum, 0, 0, 0x0177, /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */ + GDK_Multi_key, GDK_y, GDK_diaeresis, 0, 0, 0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_y, GDK_acute, 0, 0, 0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_z, GDK_less, 0, 0, 0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */ + GDK_Multi_key, GDK_bar, GDK_C, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_bar, GDK_c, 0, 0, 0x00A2, /* CENT_SIGN */ + GDK_Multi_key, GDK_asciitilde, GDK_space, 0, 0, 0x007E, /* TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_A, 0, 0, 0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_I, 0, 0, 0x0128, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_N, 0, 0, 0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_O, 0, 0, 0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_U, 0, 0, 0x0168, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_a, 0, 0, 0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_i, 0, 0, 0x0129, /* LATIN_SMALL_LETTER_I_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_n, 0, 0, 0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_o, 0, 0, 0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */ + GDK_Multi_key, GDK_asciitilde, GDK_u, 0, 0, 0x0169, /* LATIN_SMALL_LETTER_U_WITH_TILDE */ + GDK_Multi_key, GDK_diaeresis, GDK_A, 0, 0, 0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_E, 0, 0, 0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_I, 0, 0, 0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_O, 0, 0, 0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_U, 0, 0, 0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_Y, 0, 0, 0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_a, 0, 0, 0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_e, 0, 0, 0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_i, 0, 0, 0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_o, 0, 0, 0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_u, 0, 0, 0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */ + GDK_Multi_key, GDK_diaeresis, GDK_y, 0, 0, 0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */ + GDK_Multi_key, GDK_acute, GDK_A, 0, 0, 0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_E, 0, 0, 0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_I, 0, 0, 0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_O, 0, 0, 0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_U, 0, 0, 0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_Y, 0, 0, 0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_a, 0, 0, 0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_e, 0, 0, 0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_i, 0, 0, 0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_o, 0, 0, 0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_u, 0, 0, 0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */ + GDK_Multi_key, GDK_acute, GDK_y, 0, 0, 0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */ + GDK_Multi_key, GDK_cedilla, GDK_S, 0, 0, 0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_cedilla, GDK_s, 0, 0, 0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */ + GDK_Multi_key, GDK_breve, GDK_G, 0, 0, 0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */ + GDK_Multi_key, GDK_breve, GDK_g, 0, 0, 0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */ +}; + +static const GtkComposeTable gtk_compose_table = { + gtk_compose_seqs, + 4, + G_N_ELEMENTS (gtk_compose_seqs) / 6 }; guint16 gtk_compose_ignore[] = { @@ -732,11 +739,18 @@ guint16 gtk_compose_ignore[] = { GDK_Hyper_R }; -static void gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class); -static void gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple); +static void gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class); +static void gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple); +static void gtk_im_context_simple_finalize (GObject *obj); +static gboolean gtk_im_context_simple_filter_keypress (GtkIMContext *context, + GdkEventKey *key); +static void gtk_im_context_simple_reset (GtkIMContext *context); +static void gtk_im_context_simple_get_preedit_string (GtkIMContext *context, + gchar **str, + PangoAttrList **attrs, + gint *cursor_pos); -static gboolean gtk_im_context_simple_filter_keypress (GtkIMContext *context, - GdkEventKey *key); +static GObjectClass *parent_class; GtkType gtk_im_context_simple_get_type (void) @@ -767,8 +781,14 @@ static void gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class) { GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class); - + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + im_context_class->filter_keypress = gtk_im_context_simple_filter_keypress; + im_context_class->reset = gtk_im_context_simple_reset; + im_context_class->get_preedit_string = gtk_im_context_simple_get_preedit_string; + gobject_class->finalize = gtk_im_context_simple_finalize; } static void @@ -776,6 +796,14 @@ gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple) { } +static void +gtk_im_context_simple_finalize (GObject *obj) +{ + GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (obj); + + g_slist_free (context_simple->tables); +} + GtkIMContext * gtk_im_context_simple_new (void) { @@ -788,10 +816,20 @@ gtk_im_context_simple_commit_char (GtkIMContext *context, { gchar buf[10]; gint len; + + GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context); len = g_unichar_to_utf8 (ch, buf); buf[len] = '\0'; + if (context_simple->tentative_match) + { + context_simple->tentative_match = 0; + context_simple->tentative_match_len = 0; + gtk_signal_emit_by_name (GTK_OBJECT (context_simple), + "preedit-changed"); + } + gtk_signal_emit_by_name (GTK_OBJECT (context), "commit", &buf); } @@ -800,13 +838,13 @@ compare_seq (const void *key, const void *value) { int i = 0; const guint *keysyms = key; - const GtkComposeSeq *seq = value; + const guint16 *seq = value; while (keysyms[i]) { - if (keysyms[i] < seq->keysyms[i]) + if (keysyms[i] < seq[i]) return -1; - else if (keysyms[i] > seq->keysyms[i]) + else if (keysyms[i] > seq[i]) return 1; i++; @@ -816,11 +854,74 @@ compare_seq (const void *key, const void *value) } static gboolean +check_table (GtkIMContextSimple *context_simple, + const GtkComposeTable *table, + gint n_compose) +{ + gint row_stride = table->max_seq_len + 2; + guint16 *seq = bsearch (context_simple->compose_buffer, + table->data, table->n_seqs, + sizeof (guint16) * row_stride, + compare_seq); + + if (seq) + { + guint16 *prev_seq; + + /* Back up to the first sequence that matches to make sure + * we find the exact match if their is one. + */ + while (seq > table->data) + { + prev_seq = seq - row_stride; + if (compare_seq (context_simple->compose_buffer, prev_seq) != 0) + break; + seq = prev_seq; + } + + if (n_compose == table->max_seq_len || + seq[n_compose] == 0) /* complete sequence */ + { + guint16 *next_seq; + gunichar value = + 0x10000 * seq[table->max_seq_len] + seq[table->max_seq_len + 1]; + + + /* We found a tentative match. See if there are any longer + * sequences containing this subsequence + */ + next_seq = seq + row_stride; + if (next_seq < table->data + row_stride * table->n_seqs) + { + if (compare_seq (context_simple->compose_buffer, next_seq) == 0) + { + context_simple->tentative_match = value; + context_simple->tentative_match_len = n_compose; + + gtk_signal_emit_by_name (GTK_OBJECT (context_simple), + "preedit-changed"); + + return TRUE; + } + } + + gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value); + context_simple->compose_buffer[0] = 0; + } + + return TRUE; + } + + return FALSE; +} + + +static gboolean gtk_im_context_simple_filter_keypress (GtkIMContext *context, GdkEventKey *event) { GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context); - GtkComposeSeq *seq; + GSList *tmp_list; gunichar ch; int n_compose = 0; @@ -840,37 +941,138 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context, context_simple->compose_buffer[n_compose++] = event->keyval; context_simple->compose_buffer[n_compose] = 0; - seq = bsearch (context_simple->compose_buffer, - gtk_compose_seqs, G_N_ELEMENTS (gtk_compose_seqs), - sizeof (GtkComposeSeq), compare_seq); + tmp_list = context_simple->tables; + while (tmp_list) + { + if (check_table (context_simple, tmp_list->data, n_compose)) + return TRUE; + tmp_list = tmp_list->next; + } + + if (check_table (context_simple, >k_compose_table, n_compose)) + return TRUE; + + /* No compose sequences found, check first if we have a partial + * match pending. + */ + if (context_simple->tentative_match) + { + gint len = context_simple->tentative_match_len; + int i; + + gtk_im_context_simple_commit_char (context, context_simple->tentative_match); + context_simple->compose_buffer[0] = 0; + + for (i=0; i < n_compose - len - 1; i++) + { + GdkEventKey tmp_event = *event; + tmp_event.keyval = context_simple->compose_buffer[len + i]; + + gtk_im_context_filter_keypress (context, &tmp_event); + } - if (seq) + return gtk_im_context_filter_keypress (context, event); + } + else { - if (n_compose == GTK_MAX_COMPOSE_LEN || - seq->keysyms[n_compose] == 0) /* complete sequence */ + context_simple->compose_buffer[0] = 0; + if (n_compose > 1) /* Invalid sequence */ { - gtk_im_context_simple_commit_char (context, seq->unicode); - context_simple->compose_buffer[0] = 0; + gdk_beep(); + return TRUE; } - - return TRUE; + + ch = gdk_keyval_to_unicode (event->keyval); + if (ch != 0) + { + gtk_im_context_simple_commit_char (context, ch); + return TRUE; + } + else + return FALSE; } +} - /* No compose sequences found, try simple conversion to unicode - */ +static void +gtk_im_context_simple_reset (GtkIMContext *context) +{ + GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context); + context_simple->compose_buffer[0] = 0; - if (n_compose > 1) /* Invalid sequence */ + + if (context_simple->tentative_match) + gtk_im_context_simple_commit_char (context, context_simple->tentative_match); +} + +static void +gtk_im_context_simple_get_preedit_string (GtkIMContext *context, + gchar **str, + PangoAttrList **attrs, + gint *cursor_pos) +{ + char outbuf[7]; + int len = 0; + + GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context); + + if (context_simple->tentative_match) + len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf); + + if (str) + *str = g_strndup (outbuf, len); + + if (attrs) { - gdk_beep(); - return TRUE; + *attrs = pango_attr_list_new(); + + if (len) + { + PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); + attr->start_index = 0; + attr->end_index = len; + pango_attr_list_insert (*attrs, attr); + } } + + if (cursor_pos) + cursor_pos = context_simple->tentative_match ? 1 : 0; +} + +/** + * gtk_im_context_simple_add_table: + * @context_simple: A #GtkIMContextSimple + * @data: the table + * @max_seq_len: Maximum length of a sequence in the table + * (cannot be greater than 7) + * @n_seqs: number of sequences in the table + * + * Add an additional table to search to the input context. + * Each row of the table consists of max_seq_len key symbols + * followed by two guint16 interpreted as the high and low + * words of a gunicode value. Tables are searched starting + * from the last added. + * + * The table must be sorted in dictionary order on the + * by numeric value of the key symbol fields. (Values beyond + * the length of the sequence should be zero.) + **/ +void +gtk_im_context_simple_add_table (GtkIMContextSimple *context_simple, + guint16 *data, + gint max_seq_len, + gint n_seqs) +{ + GtkComposeTable *table; + + g_return_if_fail (GTK_IS_IM_CONTEXT_SIMPLE (context_simple)); + g_return_if_fail (data != NULL); + g_return_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN); - ch = gdk_keyval_to_unicode (event->keyval); - if (ch != 0) - { - gtk_im_context_simple_commit_char (context, ch); - return TRUE; - } - else - return FALSE; + table = g_new (GtkComposeTable, 1); + table->data = data; + table->max_seq_len = max_seq_len; + table->n_seqs = n_seqs; + + context_simple->tables = g_slist_prepend (context_simple->tables, table); } + diff --git a/gtk/gtkimcontextsimple.h b/gtk/gtkimcontextsimple.h index 80e3b2246b..f166d82b47 100644 --- a/gtk/gtkimcontextsimple.h +++ b/gtk/gtkimcontextsimple.h @@ -38,13 +38,17 @@ extern "C" { typedef struct _GtkIMContextSimple GtkIMContextSimple; typedef struct _GtkIMContextSimpleClass GtkIMContextSimpleClass; -#define GTK_MAX_COMPOSE_LEN 4 +#define GTK_MAX_COMPOSE_LEN 7 struct _GtkIMContextSimple { GtkIMContext object; + + GSList *tables; guint compose_buffer[GTK_MAX_COMPOSE_LEN + 1]; + gunichar tentative_match; + gint tentative_match_len; }; struct _GtkIMContextSimpleClass @@ -53,8 +57,12 @@ struct _GtkIMContextSimpleClass }; GtkType gtk_im_context_simple_get_type (void) G_GNUC_CONST; -GtkIMContext *gtk_im_context_simple_new (void); +GtkIMContext *gtk_im_context_simple_new (void); +void gtk_im_context_simple_add_table (GtkIMContextSimple *context_simple, + guint16 *data, + gint max_seq_len, + gint n_seqs); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtkimmodule.c b/gtk/gtkimmodule.c new file mode 100644 index 0000000000..353100720b --- /dev/null +++ b/gtk/gtkimmodule.c @@ -0,0 +1,527 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * Themes added by The Rasterman <raster@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gmodule.h> +#include <pango/pango-utils.h> +#include "gtkimmodule.h" +#include "gtkimcontextsimple.h" +#include "gtkrc.h" +#include "config.h" +#include "gtkintl.h" + +#define SIMPLE_ID "gtk-im-context-simple" + +typedef struct _GtkIMModule GtkIMModule; +typedef struct _GtkIMModuleClass GtkIMModuleClass; + +#define GTK_TYPE_IM_MODULE (gtk_im_module_get_type ()) +#define GTK_IM_MODULE(im_module) (G_TYPE_CHECK_INSTANCE_CAST ((im_module), GTK_TYPE_IM_MODULE, GtkIMModule)) +#define GTK_IS_IM_MODULE(im_module) (G_TYPE_CHECK_INSTANCE_TYPE ((im_module), GTK_TYPE_IM_MODULE)) + +struct _GtkIMModule +{ + GTypeModule parent_instance; + + GModule *library; + + void (*list) (const GtkIMContextInfo ***contexts, + guint *n_contexts); + void (*init) (GTypeModule *module); + void (*exit) (void); + GtkIMContext *(*create) (const gchar *context_id); + + GtkIMContextInfo **contexts; + guint n_contexts; + + gchar *path; +}; + +struct _GtkIMModuleClass +{ + GTypeModuleClass parent_class; +}; + +GType gtk_im_module_get_type (void); + +gint n_loaded_contexts = 0; +static GHashTable *contexts_hash = NULL; +static GSList *modules_list = NULL; + +static GObjectClass *parent_class = NULL; + +static gboolean +gtk_im_module_load (GTypeModule *module) +{ + GtkIMModule *im_module = GTK_IM_MODULE (module); + + im_module->library = g_module_open (im_module->path, 0); + if (!im_module->library) + { + g_warning (g_module_error()); + return FALSE; + } + + /* extract symbols from the lib */ + if (!g_module_symbol (im_module->library, "im_module_init", + (gpointer *)&im_module->init) || + !g_module_symbol (im_module->library, "im_module_exit", + (gpointer *)&im_module->exit) || + !g_module_symbol (im_module->library, "im_module_list", + (gpointer *)&im_module->list) || + !g_module_symbol (im_module->library, "im_module_create", + (gpointer *)&im_module->create)) + { + g_warning (g_module_error()); + g_module_close (im_module->library); + + return FALSE; + } + + /* call the theme's init (theme_init) function to let it */ + /* setup anything it needs to set up. */ + im_module->init (module); + + return TRUE; +} + +static void +gtk_im_module_unload (GTypeModule *module) +{ + GtkIMModule *im_module = GTK_IM_MODULE (module); + + im_module->exit(); + + g_module_close (im_module->library); + im_module->library = NULL; + + im_module->init = NULL; + im_module->exit = NULL; + im_module->list = NULL; + im_module->create = NULL; +} + +/* This only will ever be called if an error occurs during + * initialization + */ +static void +gtk_im_module_finalize (GObject *object) +{ + GtkIMModule *module = GTK_IM_MODULE (object); + + g_free (module->path); + + parent_class->finalize (object); +} + +static void +gtk_im_module_class_init (GtkIMModuleClass *class) +{ + GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class); + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (class)); + + module_class->load = gtk_im_module_load; + module_class->unload = gtk_im_module_unload; + + gobject_class->finalize = gtk_im_module_finalize; +} + +GType +gtk_im_module_get_type (void) +{ + static GType im_module_type = 0; + + if (!im_module_type) + { + static const GTypeInfo im_module_info = { + sizeof (GtkIMModuleClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_im_module_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkIMModule), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + im_module_type = g_type_register_static (G_TYPE_TYPE_MODULE, "GtkIMModule", &im_module_info, 0); + } + + return im_module_type; +} + +static void +free_info (GtkIMContextInfo *info) +{ + g_free ((char *)info->context_id); + g_free ((char *)info->context_name); + g_free ((char *)info->domain); + g_free ((char *)info->domain_dirname); + g_free ((char *)info->default_locales); + g_free (info); +} + +static void +add_module (GtkIMModule *module, GSList *infos) +{ + GSList *tmp_list = infos; + gint i = 0; + gint n = g_slist_length (infos); + module->contexts = g_new (GtkIMContextInfo *, n); + + while (tmp_list) + { + GtkIMContextInfo *info = tmp_list->data; + + if (g_hash_table_lookup (contexts_hash, info->context_id)) + { + free_info (info); /* Duplicate */ + } + else + { + g_hash_table_insert (contexts_hash, (char *)info->context_id, module); + module->contexts[i++] = tmp_list->data; + n_loaded_contexts++; + } + + tmp_list = tmp_list->next; + } + g_slist_free (infos); + module->n_contexts = i; + + modules_list = g_slist_prepend (modules_list, module); +} + +static void +gtk_im_module_init () +{ + GString *line_buf = g_string_new (NULL); + GString *tmp_buf = g_string_new (NULL); + const gchar *filename = gtk_rc_get_im_module_file(); + FILE *file; + gboolean have_error = FALSE; + + GtkIMModule *module = NULL; + GSList *infos = NULL; + + contexts_hash = g_hash_table_new (g_str_hash, g_str_equal); + + file = fopen (filename, "r"); + if (!file) + { + g_warning ("Can not open Input Method module file '%s': %s", + filename, g_strerror (errno)); + return; + } + + while (!have_error && pango_read_line (file, line_buf)) + { + const char *p; + + p = line_buf->str; + + if (!pango_skip_space (&p)) + { + /* Blank line marking the end of a module + */ + if (module && *p != '#') + { + add_module (module, infos); + module = NULL; + infos = NULL; + } + + continue; + } + + if (!module) + { + /* Read a module location + */ + module = g_object_new (GTK_TYPE_IM_MODULE, NULL); + + if (!pango_scan_string (&p, tmp_buf) || + pango_skip_space (&p)) + { + g_warning ("Error parsing context info in '%s'\n %s", + filename, line_buf->str); + have_error = TRUE; + } + + module->path = g_strdup (tmp_buf->str); + g_type_module_set_name (G_TYPE_MODULE (module), module->path); + } + else + { + GtkIMContextInfo *info = g_new0 (GtkIMContextInfo, 1); + + /* Read information about a context type + */ + if (!pango_scan_string (&p, tmp_buf)) + goto context_error; + info->context_id = g_strdup (tmp_buf->str); + + if (!pango_scan_string (&p, tmp_buf)) + goto context_error; + info->context_name = g_strdup (tmp_buf->str); + + if (!pango_scan_string (&p, tmp_buf)) + goto context_error; + info->domain = g_strdup (tmp_buf->str); + + if (!pango_scan_string (&p, tmp_buf)) + goto context_error; + info->domain_dirname = g_strdup (tmp_buf->str); + + if (!pango_scan_string (&p, tmp_buf)) + goto context_error; + info->default_locales = g_strdup (tmp_buf->str); + + if (pango_skip_space (&p)) + goto context_error; + + infos = g_slist_prepend (infos, info); + continue; + + context_error: + g_warning ("Error parsing context info in '%s'\n %s", + filename, line_buf->str); + have_error = TRUE; + } + } + + if (have_error) + { + GSList *tmp_list = infos; + while (tmp_list) + { + free_info (tmp_list->data); + tmp_list = tmp_list->next; + } + g_slist_free (infos); + + g_object_unref (G_OBJECT (module)); + } + else if (module) + add_module (module, infos); + + fclose (file); + g_string_free (line_buf, TRUE); + g_string_free (tmp_buf, TRUE); +} + +/** + * _gtk_im_module_list: + * @contexts: location to store an array of pointers to #GtkIMContextInfo + * this array should be freed with g_free() when you are finished. + * The structures it points are statically allocated and should + * not be modified or freed. + * @n_contexts: the length of the array stored in @contexts + * + * List all available types of input method context + **/ +void +_gtk_im_module_list (const GtkIMContextInfo ***contexts, + guint *n_contexts) +{ + int n = 0; + + static const GtkIMContextInfo simple_context_info = { + SIMPLE_ID, + "Default", + "gtk+", + NULL, + "" + }; + + if (!contexts_hash) + gtk_im_module_init (); + + if (n_contexts) + *n_contexts = (n_loaded_contexts + 1); + + if (contexts) + { + GSList *tmp_list; + int i; + + *contexts = g_new (const GtkIMContextInfo *, n_loaded_contexts + 1); + + (*contexts)[n++] = &simple_context_info; + + tmp_list = modules_list; + while (tmp_list) + { + GtkIMModule *module = tmp_list->data; + + for (i=0; i<module->n_contexts; i++) + (*contexts)[n++] = module->contexts[i]; + + tmp_list = tmp_list->next; + } + } +} + +/** + * _gtk_im_module_create: + * @context_id: the context ID for the context type to create + * + * Create an IM context of a type specified by the string + * ID @context_id. + * + * Return value: a newly created input context of or @context_id, or + * if that could not be created, a newly created GtkIMContextSimple. + **/ +GtkIMContext * +_gtk_im_module_create (const gchar *context_id) +{ + GtkIMModule *im_module; + GtkIMContext *context = NULL; + + if (!contexts_hash) + gtk_im_module_init (); + + if (strcmp (context_id, SIMPLE_ID) != 0) + { + im_module = g_hash_table_lookup (contexts_hash, context_id); + if (!im_module) + { + g_warning ("Attempt to load unknown IM context type '%s'", context_id); + } + else + { + if (g_type_module_use (G_TYPE_MODULE (im_module))) + { + context = im_module->create (context_id); + g_type_module_unuse (G_TYPE_MODULE (im_module)); + } + + if (!context) + g_warning ("Loading IM context type '%s' failed", context_id); + } + } + + if (!context) + return gtk_im_context_simple_new (); + else + return context; +} + +/* Match @locale against @against. + * + * 'en_US' against 'en_US' => 3 + * 'en_US' against 'en' => 2 + * 'en', 'en_UK' against 'en_US' => 1 + */ +static gint +match_locale (const gchar *locale, + const gchar *against, + gint against_len) +{ + if (strcmp (locale, against) == 0) + return 3; + + if (strncmp (locale, against, 2) == 0) + return (against_len == 2) ? 2 : 1; + + return 0; +} + +/** + * _gtk_im_module_get_default_context_id: + * @locale: a locale id in the form 'en_US' + * + * Return the context_id of the best IM context type + * for the given locale ID. + * + * Return value: the context ID (will never be %NULL) + * the value is newly allocated and must be freed + * with g_free(). + **/ +const gchar * +_gtk_im_module_get_default_context_id (const gchar *locale) +{ + GSList *tmp_list; + const gchar *context_id = NULL; + gint best_goodness = 0; + gint i; + gchar *tmp_locale, *tmp; + gchar *envvar; + + if (!contexts_hash) + gtk_im_module_init (); + + envvar = g_getenv ("GTK_IM_MODULE"); + if (envvar && g_hash_table_lookup (contexts_hash, envvar)) + return g_strdup (envvar); + + /* Strip the locale code down to the essentials + */ + tmp_locale = g_strdup (locale); + tmp = strchr (tmp_locale, '.'); + if (tmp) + *tmp = '\0'; + tmp = strchr (tmp_locale, '@'); + if (tmp) + *tmp = '\0'; + + tmp_list = modules_list; + while (tmp_list) + { + GtkIMModule *module = tmp_list->data; + + for (i=0; i<module->n_contexts; i++) + { + const gchar *p = module->contexts[i]->default_locales; + while (p) + { + const gchar *q = strchr (p, ':'); + gint goodness = match_locale (tmp_locale, p, q ? q - p : strlen (p)); + + if (goodness > best_goodness) + { + context_id = module->contexts[i]->context_id; + best_goodness = goodness; + } + + p = q ? q + 1 : NULL; + } + } + + tmp_list = tmp_list->next; + } + + g_free (tmp_locale); + + return g_strdup (context_id ? context_id : SIMPLE_ID); +} diff --git a/gtk/gtkimmodule.h b/gtk/gtkimmodule.h new file mode 100644 index 0000000000..d9ce11b68e --- /dev/null +++ b/gtk/gtkimmodule.h @@ -0,0 +1,62 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2000 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_IM_MODULE_H__ +#define __GTK_IM_MODULE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <gtk/gtkimcontext.h> + +typedef struct _GtkIMContextInfo GtkIMContextInfo; + +struct _GtkIMContextInfo +{ + const gchar *context_id; + const gchar *context_name; + const gchar *domain; + const gchar *domain_dirname; + const gchar *default_locales; +}; + +/* Functions for use within GTK+ + */ +void _gtk_im_module_list (const GtkIMContextInfo ***contexts, + guint *n_contexts); +GtkIMContext *_gtk_im_module_create (const gchar *context_id); +const gchar * _gtk_im_module_get_default_context_id (const gchar *lang); + +/* The following entry points are exported by each input method module + */ + +/* +void im_module_list (const GtkIMContextInfo ***contexts, + guint *n_contexts); +void im_module_init (GtkModule *module); +void im_module_exit (void); +GtkIMContext *im_module_create (const gchar *context_id); +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif __GTK_IM_MODULE_H__ diff --git a/gtk/gtkimmulticontext.c b/gtk/gtkimmulticontext.c index 58b8296a18..2ec808356f 100644 --- a/gtk/gtkimmulticontext.c +++ b/gtk/gtkimmulticontext.c @@ -17,9 +17,18 @@ * Boston, MA 02111-1307, USA. */ +#include <string.h> + +#ifdef GDK_WINDOWING_X11 +#include <X11/Xlocale.h> /* so we get the right setlocale */ +#else +#include <locale.h> +#endif + #include "gtksignal.h" #include "gtkimmulticontext.h" -#include "gtkimcontextsimple.h" +#include "gtkimmodule.h" +#include "gtkmenuitem.h" static void gtk_im_multicontext_class_init (GtkIMMulticontextClass *class); static void gtk_im_multicontext_init (GtkIMMulticontext *im_multicontext); @@ -32,11 +41,13 @@ static void gtk_im_multicontext_set_client_window (GtkIMContext GdkWindow *window); static void gtk_im_multicontext_get_preedit_string (GtkIMContext *context, gchar **str, - PangoAttrList **attrs); + PangoAttrList **attrs, + gint *cursor_pos); static gboolean gtk_im_multicontext_filter_keypress (GtkIMContext *context, GdkEventKey *event); static void gtk_im_multicontext_focus_in (GtkIMContext *context); static void gtk_im_multicontext_focus_out (GtkIMContext *context); +static void gtk_im_multicontext_reset (GtkIMContext *context); void gtk_im_multicontext_preedit_start_cb (GtkIMContext *slave, GtkIMMulticontext *multicontext); @@ -50,6 +61,8 @@ void gtk_im_multicontext_commit_cb (GtkIMContext static GtkIMContextClass *parent_class; +static const gchar *global_context_id = NULL; + GtkType gtk_im_multicontext_get_type (void) { @@ -88,6 +101,7 @@ gtk_im_multicontext_class_init (GtkIMMulticontextClass *class) im_context_class->filter_keypress = gtk_im_multicontext_filter_keypress; im_context_class->focus_in = gtk_im_multicontext_focus_in; im_context_class->focus_out = gtk_im_multicontext_focus_out; + im_context_class->reset = gtk_im_multicontext_reset; gobject_class->finalize = gtk_im_multicontext_finalize; } @@ -141,6 +155,9 @@ gtk_im_multicontext_set_slave (GtkIMMulticontext *multicontext, gtk_signal_connect (GTK_OBJECT (multicontext->slave), "commit", GTK_SIGNAL_FUNC (gtk_im_multicontext_commit_cb), multicontext); + + if (multicontext->client_window) + gtk_im_context_set_client_window (slave, multicontext->client_window); } } @@ -148,7 +165,22 @@ static GtkIMContext * gtk_im_multicontext_get_slave (GtkIMMulticontext *multicontext) { if (!multicontext->slave) - gtk_im_multicontext_set_slave (multicontext, gtk_im_context_simple_new ()); + { + if (!global_context_id) + { + const char *locale; + +#ifdef HAVE_LC_MESSAGES + locale = setlocale (LC_MESSAGES, NULL); +#else + locale = setlocale (LC_CTYPE, NULL); +#endif + global_context_id = _gtk_im_module_get_default_context_id (locale); + } + + gtk_im_multicontext_set_slave (multicontext, _gtk_im_module_create (global_context_id)); + multicontext->context_id = global_context_id; + } return multicontext->slave; } @@ -160,6 +192,8 @@ gtk_im_multicontext_set_client_window (GtkIMContext *context, GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext); + multicontext->client_window = window; + if (slave) gtk_im_context_set_client_window (slave, window); } @@ -167,13 +201,14 @@ gtk_im_multicontext_set_client_window (GtkIMContext *context, static void gtk_im_multicontext_get_preedit_string (GtkIMContext *context, gchar **str, - PangoAttrList **attrs) + PangoAttrList **attrs, + gint *cursor_pos) { GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext); if (slave) - gtk_im_context_get_preedit_string (slave, str, attrs); + gtk_im_context_get_preedit_string (slave, str, attrs, cursor_pos); else { if (str) @@ -200,7 +235,17 @@ static void gtk_im_multicontext_focus_in (GtkIMContext *context) { GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); - GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext); + GtkIMContext *slave; + + /* If the global context type is different from the context we were + * using before, get rid of the old slave and create a new one + * for the new global context type. + */ + if (!multicontext->context_id || + strcmp (global_context_id, multicontext->context_id) != 0) + gtk_im_multicontext_set_slave (multicontext, NULL); + + slave = gtk_im_multicontext_get_slave (multicontext); if (slave) gtk_im_context_focus_in (slave); @@ -216,6 +261,16 @@ gtk_im_multicontext_focus_out (GtkIMContext *context) gtk_im_context_focus_out (slave); } +static void +gtk_im_multicontext_reset (GtkIMContext *context) +{ + GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); + GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext); + + if (slave) + gtk_im_context_reset (slave); +} + void gtk_im_multicontext_preedit_start_cb (GtkIMContext *slave, GtkIMMulticontext *multicontext) @@ -245,3 +300,49 @@ gtk_im_multicontext_commit_cb (GtkIMContext *slave, gtk_signal_emit_by_name (GTK_OBJECT (multicontext), "commit", str);; } +static void +activate_cb (GtkWidget *menuitem, + GtkIMMulticontext *context) +{ + const gchar *id = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-context-id"); + + gtk_im_context_reset (GTK_IM_CONTEXT (context)); + + global_context_id = id; + gtk_im_multicontext_set_slave (context, NULL); +} + +/** + * gtk_im_multicontext_append_menuitems: + * @context: a #GtkIMMultiContext + * @menushell: a #GtkMenuShell + * + * Add menuitems for various available input methods to a menu; + * the menuitems, when selected, will switch the input method + * for the context and the global default input method. + **/ +void +gtk_im_multicontext_append_menuitems (GtkIMMulticontext *context, + GtkMenuShell *menushell) +{ + const GtkIMContextInfo **contexts; + gint n_contexts, i; + + _gtk_im_module_list (&contexts, &n_contexts); + + for (i=0; i < n_contexts; i++) + { + GtkWidget *menuitem; + + menuitem = gtk_menu_item_new_with_label (contexts[i]->context_name); + + gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-context-id", + (char *)contexts[i]->context_id); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + activate_cb, context); + + gtk_widget_show (menuitem); + gtk_menu_shell_append (menushell, menuitem); + } +} + diff --git a/gtk/gtkimmulticontext.h b/gtk/gtkimmulticontext.h index bed52f01d7..faa8b294d5 100644 --- a/gtk/gtkimmulticontext.h +++ b/gtk/gtkimmulticontext.h @@ -21,6 +21,7 @@ #define __GTK_IM_MULTICONTEXT_H__ #include <gtk/gtkimcontext.h> +#include <gtk/gtkmenushell.h> #ifdef __cplusplus extern "C" { @@ -43,6 +44,10 @@ struct _GtkIMMulticontext GtkIMContext object; GtkIMContext *slave; + + GdkWindow *client_window; + + const gchar *context_id; }; struct _GtkIMMulticontextClass @@ -53,6 +58,9 @@ struct _GtkIMMulticontextClass GtkType gtk_im_multicontext_get_type (void) G_GNUC_CONST; GtkIMContext *gtk_im_multicontext_new (void); +void gtk_im_multicontext_append_menuitems (GtkIMMulticontext *context, + GtkMenuShell *menushell); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtkoldeditable.c b/gtk/gtkoldeditable.c new file mode 100644 index 0000000000..a085d0639c --- /dev/null +++ b/gtk/gtkoldeditable.c @@ -0,0 +1,859 @@ +/* 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <ctype.h> +#include <string.h> +#include "gdk/gdkkeysyms.h" +#include "gdk/gdki18n.h" +#include "gtkclipboard.h" +#include "gtkoldeditable.h" +#include "gtkmain.h" +#include "gtkselection.h" +#include "gtksignal.h" + +#define MIN_EDITABLE_WIDTH 150 +#define DRAW_TIMEOUT 20 +#define INNER_BORDER 2 + +enum { + CHANGED, + INSERT_TEXT, + DELETE_TEXT, + /* Binding actions */ + ACTIVATE, + SET_EDITABLE, + MOVE_CURSOR, + MOVE_WORD, + MOVE_PAGE, + MOVE_TO_ROW, + MOVE_TO_COLUMN, + KILL_CHAR, + KILL_WORD, + KILL_LINE, + CUT_CLIPBOARD, + COPY_CLIPBOARD, + PASTE_CLIPBOARD, + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_TEXT_POSITION, + ARG_EDITABLE +}; + +/* values for selection info */ + +enum { + TARGET_STRING, + TARGET_TEXT, + TARGET_COMPOUND_TEXT +}; + +static void gtk_old_editable_class_init (GtkOldEditableClass *klass); +static void gtk_old_editable_editable_init (GtkEditableClass *iface); +static void gtk_old_editable_init (GtkOldEditable *editable); +static void gtk_old_editable_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_old_editable_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void *gtk_old_editable_get_public_chars (GtkOldEditable *old_editable, + gint start, + gint end); + +static gint gtk_old_editable_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +static void gtk_old_editable_selection_get (GtkWidget *widget, + GtkSelectionData *selection_data, + guint info, + guint time); +static void gtk_old_editable_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data, + guint time); + +static void gtk_old_editable_set_selection (GtkOldEditable *old_editable, + gint start, + gint end); + +static void gtk_old_editable_real_set_editable (GtkOldEditable *old_editable, + gboolean is_editable); +static void gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable); +static void gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable); +static void gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable); + +static void gtk_old_editable_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_old_editable_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos); +static gchar * gtk_old_editable_get_chars (GtkEditable *editable, + gint start, + gint end); +static void gtk_old_editable_set_selection_bounds (GtkEditable *editable, + gint start, + gint end); +static gboolean gtk_old_editable_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end); +static void gtk_old_editable_set_position (GtkEditable *editable, + gint position); +static gint gtk_old_editable_get_position (GtkEditable *editable); + +static GtkWidgetClass *parent_class = NULL; +static guint editable_signals[LAST_SIGNAL] = { 0 }; + +GtkType +gtk_old_editable_get_type (void) +{ + static GtkType old_editable_type = 0; + + if (!old_editable_type) + { + static const GtkTypeInfo old_editable_info = + { + "GtkOldEditable", + sizeof (GtkOldEditable), + sizeof (GtkOldEditableClass), + (GtkClassInitFunc) gtk_old_editable_class_init, + (GtkObjectInitFunc) gtk_old_editable_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + static const GInterfaceInfo editable_info = + { + (GInterfaceInitFunc) gtk_old_editable_editable_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + old_editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &old_editable_info); + g_type_add_interface_static (old_editable_type, + GTK_TYPE_EDITABLE, + &editable_info); + } + + return old_editable_type; +} + +static void +gtk_old_editable_class_init (GtkOldEditableClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (GTK_TYPE_WIDGET); + + editable_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + editable_signals[INSERT_TEXT] = + gtk_signal_new ("insert_text", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, insert_text), + gtk_marshal_NONE__POINTER_INT_POINTER, + 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, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, delete_text), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, + 2, + GTK_TYPE_INT, + GTK_TYPE_INT); + + editable_signals[ACTIVATE] = + gtk_signal_new ("activate", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, activate), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + widget_class->activate_signal = editable_signals[ACTIVATE]; + + editable_signals[SET_EDITABLE] = + gtk_signal_new ("set-editable", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, set_editable), + gtk_marshal_NONE__BOOL, + GTK_TYPE_NONE, 1, + GTK_TYPE_BOOL); + + editable_signals[MOVE_CURSOR] = + gtk_signal_new ("move_cursor", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_cursor), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, + GTK_TYPE_INT); + + editable_signals[MOVE_WORD] = + gtk_signal_new ("move_word", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_word), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, + GTK_TYPE_INT); + + editable_signals[MOVE_PAGE] = + gtk_signal_new ("move_page", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_page), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, + GTK_TYPE_INT); + + editable_signals[MOVE_TO_ROW] = + gtk_signal_new ("move_to_row", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_row), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, + GTK_TYPE_INT); + + editable_signals[MOVE_TO_COLUMN] = + gtk_signal_new ("move_to_column", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_column), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, + GTK_TYPE_INT); + + editable_signals[KILL_CHAR] = + gtk_signal_new ("kill_char", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_char), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, + GTK_TYPE_INT); + + editable_signals[KILL_WORD] = + gtk_signal_new ("kill_word", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_word), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, + GTK_TYPE_INT); + + editable_signals[KILL_LINE] = + gtk_signal_new ("kill_line", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_line), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, + GTK_TYPE_INT); + + editable_signals[CUT_CLIPBOARD] = + gtk_signal_new ("cut_clipboard", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, cut_clipboard), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + editable_signals[COPY_CLIPBOARD] = + gtk_signal_new ("copy_clipboard", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, copy_clipboard), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + editable_signals[PASTE_CLIPBOARD] = + gtk_signal_new ("paste_clipboard", + GTK_RUN_LAST | GTK_RUN_ACTION, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkOldEditableClass, paste_clipboard), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL); + + gtk_object_add_arg_type ("GtkOldEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION); + gtk_object_add_arg_type ("GtkOldEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE); + + object_class->set_arg = gtk_old_editable_set_arg; + object_class->get_arg = gtk_old_editable_get_arg; + + widget_class->selection_clear_event = gtk_old_editable_selection_clear; + widget_class->selection_received = gtk_old_editable_selection_received; + widget_class->selection_get = gtk_old_editable_selection_get; + + class->insert_text = NULL; + class->delete_text = NULL; + + class->activate = NULL; + class->set_editable = gtk_old_editable_real_set_editable; + + class->move_cursor = NULL; + class->move_word = NULL; + class->move_page = NULL; + class->move_to_row = NULL; + class->move_to_column = NULL; + + class->kill_char = NULL; + class->kill_word = NULL; + class->kill_line = NULL; + + class->cut_clipboard = gtk_old_editable_real_cut_clipboard; + class->copy_clipboard = gtk_old_editable_real_copy_clipboard; + class->paste_clipboard = gtk_old_editable_real_paste_clipboard; + + class->update_text = NULL; + class->get_chars = NULL; + class->set_selection = NULL; + class->set_position = NULL; +} + +static void +gtk_old_editable_editable_init (GtkEditableClass *iface) +{ + iface->insert_text = gtk_old_editable_insert_text; + iface->delete_text = gtk_old_editable_delete_text; + iface->get_chars = gtk_old_editable_get_chars; + iface->set_selection_bounds = gtk_old_editable_set_selection_bounds; + iface->get_selection_bounds = gtk_old_editable_get_selection_bounds; + iface->set_position = gtk_old_editable_set_position; + iface->get_position = gtk_old_editable_get_position; +} + +static void +gtk_old_editable_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkEditable *editable = GTK_EDITABLE (object); + + switch (arg_id) + { + case ARG_TEXT_POSITION: + gtk_editable_set_position (editable, GTK_VALUE_INT (*arg)); + break; + case ARG_EDITABLE: + gtk_signal_emit (object, editable_signals[SET_EDITABLE], + GTK_VALUE_BOOL (*arg) != FALSE); + break; + default: + break; + } +} + +static void +gtk_old_editable_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkOldEditable *old_editable; + + old_editable = GTK_OLD_EDITABLE (object); + + switch (arg_id) + { + case ARG_TEXT_POSITION: + GTK_VALUE_INT (*arg) = old_editable->current_pos; + break; + case ARG_EDITABLE: + GTK_VALUE_BOOL (*arg) = old_editable->editable; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +gtk_old_editable_init (GtkOldEditable *old_editable) +{ + static const GtkTargetEntry targets[] = { + { "UTF8_STRING", 0, 0 }, + { "STRING", 0, 0 }, + { "TEXT", 0, 0 }, + { "COMPOUND_TEXT", 0, 0 } + }; + + GTK_WIDGET_SET_FLAGS (old_editable, GTK_CAN_FOCUS); + + old_editable->selection_start_pos = 0; + old_editable->selection_end_pos = 0; + old_editable->has_selection = FALSE; + old_editable->editable = 1; + old_editable->visible = 1; + old_editable->clipboard_text = NULL; + +#ifdef USE_XIM + old_editable->ic = NULL; +#endif + + gtk_selection_add_targets (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY, + targets, G_N_ELEMENTS (targets)); +} + +static void +gtk_old_editable_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + gchar buf[64]; + gchar *text; + + gtk_widget_ref (GTK_WIDGET (editable)); + + if (new_text_length <= 63) + text = buf; + else + text = g_new (gchar, new_text_length + 1); + + text[new_text_length] = '\0'; + 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 > 63) + g_free (text); + + gtk_widget_unref (GTK_WIDGET (editable)); +} + +static void +gtk_old_editable_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable); + + gtk_widget_ref (GTK_WIDGET (old_editable)); + + gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[DELETE_TEXT], start_pos, end_pos); + gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[CHANGED]); + + if (old_editable->selection_start_pos == old_editable->selection_end_pos && + old_editable->has_selection) + gtk_old_editable_claim_selection (old_editable, FALSE, GDK_CURRENT_TIME); + + gtk_widget_unref (GTK_WIDGET (old_editable)); +} + +static void +gtk_old_editable_update_text (GtkOldEditable *old_editable, + gint start_pos, + gint end_pos) +{ + GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable); + klass->update_text (GTK_OLD_EDITABLE (old_editable), start_pos, end_pos); +} + +static gchar * +gtk_old_editable_get_chars (GtkEditable *editable, + gint start, + gint end) +{ + GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable); + return klass->get_chars (GTK_OLD_EDITABLE (editable), start, end); +} + +/* + * Like gtk_editable_get_chars, but if the editable is not + * visible, return asterisks; also convert result to UTF-8. + */ +static void * +gtk_old_editable_get_public_chars (GtkOldEditable *old_editable, + gint start, + gint end) +{ + gchar *str = NULL; + gchar *charset; + gboolean need_conversion = !g_get_charset (&charset); + + if (old_editable->visible) + { + GError *error; + gchar *tmp = gtk_editable_get_chars (GTK_EDITABLE (old_editable), start, end); + + if (need_conversion) + { + str = g_convert (tmp, -1, + "UTF-8", charset, + NULL, NULL, &error); + + if (!str) + { + g_warning ("Cannot convert text from charset to UTF-8 %s: %s", charset, error->message); + g_error_free (error); + } + + g_free (tmp); + } + else + str = tmp; + } + else + { + gint i; + gint nchars = end - start; + + if (nchars < 0) + nchars = -nchars; + + str = g_new (gchar, nchars + 1); + for (i = 0; i<nchars; i++) + str[i] = '*'; + str[i] = '\0'; + } + + return str; +} + +static void +gtk_old_editable_set_selection (GtkOldEditable *old_editable, + gint start_pos, + gint end_pos) +{ + GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable); + klass->set_selection (old_editable, start_pos, end_pos); +} + +static void +gtk_old_editable_set_position (GtkEditable *editable, + gint position) +{ + GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable); + + klass->set_position (GTK_OLD_EDITABLE (editable), position); +} + +static gint +gtk_old_editable_get_position (GtkEditable *editable) +{ + return GTK_OLD_EDITABLE (editable)->current_pos; +} + +static gint +gtk_old_editable_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget); + + /* Let the selection handling code know that the selection + * has been changed, since we've overriden the default handler */ + if (!gtk_selection_clear (widget, event)) + return FALSE; + + if (old_editable->has_selection) + { + old_editable->has_selection = FALSE; + gtk_old_editable_update_text (old_editable, old_editable->selection_start_pos, + old_editable->selection_end_pos); + } + + return TRUE; +} + +static void +gtk_old_editable_selection_get (GtkWidget *widget, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget); + gint selection_start_pos; + gint selection_end_pos; + + gchar *str; + + selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos); + selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos); + + str = gtk_old_editable_get_public_chars (old_editable, + selection_start_pos, + selection_end_pos); + + if (str) + { + gtk_selection_data_set_text (selection_data, str); + g_free (str); + } +} + +static void +gtk_old_editable_paste_received (GtkOldEditable *old_editable, + const gchar *text, + gboolean is_clipboard) +{ + const gchar *str = NULL; + gchar *charset; + gboolean need_conversion = FALSE; + + if (text) + { + GError *error; + + need_conversion = !g_get_charset (&charset); + + if (need_conversion) + { + str = g_convert_with_fallback (text, -1, + charset, "UTF-8", NULL, + NULL, NULL, &error); + if (!str) + { + g_warning ("Cannot convert text from UTF-8 to %s: %s", + charset, error->message); + g_error_free (error); + return; + } + } + else + str = text; + } + + if (str) + { + gboolean reselect; + gint old_pos; + gint tmp_pos; + + reselect = FALSE; + + if ((old_editable->selection_start_pos != old_editable->selection_end_pos) && + (!old_editable->has_selection || is_clipboard)) + { + 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 (old_editable->has_selection) + { + gtk_editable_delete_text (GTK_EDITABLE (old_editable), + MIN (old_editable->selection_start_pos, old_editable->selection_end_pos), + MAX (old_editable->selection_start_pos, old_editable->selection_end_pos)); + } + else + gtk_editable_delete_selection (GTK_EDITABLE (old_editable)); + } + + tmp_pos = old_pos = old_editable->current_pos; + + gtk_editable_insert_text (GTK_EDITABLE (old_editable), str, -1, &tmp_pos); + + if (reselect) + gtk_old_editable_set_selection (old_editable, old_pos, old_editable->current_pos); + + if (str && str != text) + g_free ((gchar *) str); + } +} + +static void +gtk_old_editable_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data, + guint time) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget); + + gchar *text = gtk_selection_data_get_text (selection_data); + + if (!text) + { + /* If we asked for UTF8 and didn't get it, try text; if we asked + * for text and didn't get it, try string. If we asked for + * anything else and didn't get it, give up. + */ + if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE)) + { + gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, + gdk_atom_intern ("TEXT", FALSE), + time); + return; + } + else if (selection_data->target == gdk_atom_intern ("TEXT", FALSE)) + { + gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, + time); + return; + } + } + + if (text) + { + gtk_old_editable_paste_received (old_editable, text, FALSE); + g_free (text); + } +} + +static void +old_editable_text_received_cb (GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (data); + + gtk_old_editable_paste_received (old_editable, text, TRUE); + g_object_unref (G_OBJECT (old_editable)); +} + +void +gtk_old_editable_claim_selection (GtkOldEditable *old_editable, + gboolean claim, + guint32 time) +{ + g_return_if_fail (old_editable != NULL); + g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable)); + g_return_if_fail (GTK_WIDGET_REALIZED (old_editable)); + + old_editable->has_selection = FALSE; + + if (claim) + { + if (gtk_selection_owner_set (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY, time)) + old_editable->has_selection = TRUE; + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (old_editable)->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time); + } +} + +static void +gtk_old_editable_set_selection_bounds (GtkEditable *editable, + gint start, + gint end) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable); + + if (GTK_WIDGET_REALIZED (editable)) + gtk_old_editable_claim_selection (old_editable, start != end, GDK_CURRENT_TIME); + + gtk_old_editable_set_selection (old_editable, start, end); +} + +static gboolean +gtk_old_editable_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end) +{ + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable); + + *start = old_editable->selection_start_pos; + *end = old_editable->selection_end_pos; + + return (old_editable->selection_start_pos != old_editable->selection_end_pos); +} + +static void +gtk_old_editable_real_set_editable (GtkOldEditable *old_editable, + gboolean is_editable) +{ + is_editable = is_editable != FALSE; + + if (old_editable->editable != is_editable) + { + old_editable->editable = is_editable; + gtk_widget_queue_draw (GTK_WIDGET (old_editable)); + } +} + +static void +gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable) +{ + gtk_old_editable_real_copy_clipboard (old_editable); + gtk_editable_delete_selection (GTK_EDITABLE (old_editable)); +} + +static void +gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable) +{ + gint selection_start_pos; + gint selection_end_pos; + + selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos); + selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos); + + if (selection_start_pos != selection_end_pos) + { + gchar *text = gtk_old_editable_get_public_chars (old_editable, + selection_start_pos, + selection_end_pos); + + if (text) + { + gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), text, -1); + g_free (text); + } + } +} + +static void +gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable) +{ + g_object_ref (G_OBJECT (old_editable)); + gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE), + old_editable_text_received_cb, old_editable); +} + +void +gtk_old_editable_changed (GtkOldEditable *old_editable) +{ + g_return_if_fail (old_editable != NULL); + g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable)); + + gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[CHANGED]); +} diff --git a/gtk/gtkoldeditable.h b/gtk/gtkoldeditable.h new file mode 100644 index 0000000000..5736539477 --- /dev/null +++ b/gtk/gtkoldeditable.h @@ -0,0 +1,142 @@ +/* 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_OLD_EDITABLE_H__ +#define __GTK_OLD_EDITABLE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkeditable.h> +#include <gtk/gtkwidget.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TYPE_OLD_EDITABLE (gtk_old_editable_get_type ()) +#define GTK_OLD_EDITABLE(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_OLD_EDITABLE, GtkOldEditable)) +#define GTK_OLD_EDITABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_OLD_EDITABLE, GtkOldEditableClass)) +#define GTK_IS_OLD_EDITABLE(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_OLD_EDITABLE)) +#define GTK_IS_OLD_EDITABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OLD_EDITABLE)) +#define GTK_OLD_EDITABLE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_OLD_EDITABLE, GtkOldEditableClass)) + + +typedef struct _GtkOldEditable GtkOldEditable; +typedef struct _GtkOldEditableClass GtkOldEditableClass; + +typedef void (*GtkTextFunction) (GtkOldEditable *editable, guint32 time); + +struct _GtkOldEditable +{ + GtkWidget widget; + + /*< public >*/ + guint current_pos; + + guint selection_start_pos; + guint selection_end_pos; + guint has_selection : 1; + + /*< private >*/ + guint editable : 1; + guint visible : 1; + GdkIC *ic; + GdkICAttr *ic_attr; + + gchar *clipboard_text; +}; + +struct _GtkOldEditableClass +{ + GtkWidgetClass parent_class; + + /* Signals for notification/filtering of changes */ + void (* changed) (GtkOldEditable *editable); + void (* insert_text) (GtkOldEditable *editable, + const gchar *text, + gint length, + gint *position); + void (* delete_text) (GtkOldEditable *editable, + gint start_pos, + gint end_pos); + + /* Bindings actions */ + void (* activate) (GtkOldEditable *editable); + void (* set_editable) (GtkOldEditable *editable, + gboolean is_editable); + void (* move_cursor) (GtkOldEditable *editable, + gint x, + gint y); + void (* move_word) (GtkOldEditable *editable, + gint n); + void (* move_page) (GtkOldEditable *editable, + gint x, + gint y); + void (* move_to_row) (GtkOldEditable *editable, + gint row); + void (* move_to_column) (GtkOldEditable *editable, + gint row); + void (* kill_char) (GtkOldEditable *editable, + gint direction); + void (* kill_word) (GtkOldEditable *editable, + gint direction); + void (* kill_line) (GtkOldEditable *editable, + gint direction); + void (* cut_clipboard) (GtkOldEditable *editable); + void (* copy_clipboard) (GtkOldEditable *editable); + void (* paste_clipboard) (GtkOldEditable *editable); + + /* Virtual functions. get_chars is in paricular not a signal because + * it returns malloced memory. The others are not signals because + * they would not be particularly useful as such. (All changes to + * selection and position do not go through these functions) + */ + void (* update_text) (GtkOldEditable *editable, + gint start_pos, + gint end_pos); + gchar* (* get_chars) (GtkOldEditable *editable, + gint start_pos, + gint end_pos); + void (* set_selection)(GtkOldEditable *editable, + gint start_pos, + gint end_pos); + void (* set_position) (GtkOldEditable *editable, + gint position); +}; + +GtkType gtk_old_editable_get_type (void) G_GNUC_CONST; +void gtk_old_editable_claim_selection (GtkOldEditable *old_editable, + gboolean claim, + guint32 time); +void gtk_old_editable_changed (GtkOldEditable *old_editable); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_OLD_EDITABLE_H__ */ diff --git a/gtk/gtkpreview.c b/gtk/gtkpreview.c index 420bd0aa54..5e4da66dfd 100644 --- a/gtk/gtkpreview.c +++ b/gtk/gtkpreview.c @@ -184,7 +184,6 @@ gtk_preview_init (GtkPreview *preview) void gtk_preview_uninit (void) { - /* unimplemented */ } diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c index 70dfcdf084..06587a2dc9 100644 --- a/gtk/gtkrc.c +++ b/gtk/gtkrc.c @@ -26,9 +26,6 @@ #include "config.h" -#include "glib.h" -#include "gdkconfig.h" - #ifdef GDK_WINDOWING_X11 #include <X11/Xlocale.h> /* so we get the right setlocale */ #else @@ -56,6 +53,9 @@ #include <io.h> #endif +#include <glib.h> +#include "gdkconfig.h" + #include "gtkrc.h" #include "gtkbindings.h" #include "gtkthemes.h" @@ -127,6 +127,8 @@ static guint gtk_rc_parse_pixmap_path (GScanner *scanner); static void gtk_rc_parse_pixmap_path_string (gchar *pix_path); static guint gtk_rc_parse_module_path (GScanner *scanner); static void gtk_rc_parse_module_path_string (gchar *mod_path); +static guint gtk_rc_parse_im_module_path (GScanner *scanner); +static guint gtk_rc_parse_im_module_file (GScanner *scanner); static guint gtk_rc_parse_path_pattern (GScanner *scanner); static guint gtk_rc_parse_stock (GScanner *scanner, GtkRcStyle *rc_style, @@ -225,12 +227,17 @@ static const struct { "engine", GTK_RC_TOKEN_ENGINE }, { "module_path", GTK_RC_TOKEN_MODULE_PATH }, { "stock", GTK_RC_TOKEN_STOCK }, + { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH }, + { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE }, { "LTR", GTK_RC_TOKEN_LTR }, { "RTL", GTK_RC_TOKEN_RTL } }; static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]); +static gchar *im_module_path = NULL; +static gchar *im_module_file = NULL; + static GHashTable *rc_style_ht = NULL; static GHashTable *realized_style_ht = NULL; static GSList *gtk_rc_sets_widget = NULL; @@ -304,42 +311,80 @@ get_themes_directory (void) #endif -gchar * -gtk_rc_get_theme_dir(void) +static gchar * +gtk_rc_make_default_dir (const gchar *type) { gchar *var, *path; #ifndef G_OS_WIN32 - var = getenv("GTK_DATA_PREFIX"); + var = getenv("GTK_EXE_PREFIX"); if (var) - path = g_strdup_printf("%s%s", var, "/share/themes"); + path = g_strdup_printf("%s%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/", type); else - path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes"); + path = g_strdup_printf("%s%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/", type); #else - path = g_strdup (get_themes_directory ()); + path = g_strdup_printf ("%s\\%s", get_themes_directory (), type); #endif return path; } gchar * -gtk_rc_get_module_dir(void) +gtk_rc_get_im_module_path (void) +{ + gchar *result = g_getenv ("GTK_IM_MODULE_PATH"); + + if (!result) + { + if (im_module_path) + result = im_module_path; + else + return gtk_rc_make_default_dir ("immodules"); + } + + return g_strdup (result); +} + +gchar * +gtk_rc_get_im_module_file (void) +{ + gchar *result = g_getenv ("GTK_IM_MODULE_FILE"); + + if (!result) + { + if (im_module_file) + result = im_module_file; + else + result = GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtk.immodules"; + } + + return g_strdup (result); +} + +gchar * +gtk_rc_get_theme_dir(void) { gchar *var, *path; #ifndef G_OS_WIN32 - var = getenv("GTK_EXE_PREFIX"); + var = getenv("GTK_DATA_PREFIX"); if (var) - path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines"); + path = g_strdup_printf("%s%s", var, "/share/themes"); else - path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines"); + path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes"); #else - path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines"); + path = g_strdup (get_themes_directory ()); #endif return path; } +gchar * +gtk_rc_get_module_dir(void) +{ + return gtk_rc_make_default_dir ("engines"); +} + static void gtk_rc_append_default_module_path(void) { @@ -1544,6 +1589,12 @@ gtk_rc_parse_statement (GScanner *scanner) case GTK_RC_TOKEN_MODULE_PATH: return gtk_rc_parse_module_path (scanner); + case GTK_RC_TOKEN_IM_MODULE_PATH: + return gtk_rc_parse_im_module_path (scanner); + + case GTK_RC_TOKEN_IM_MODULE_FILE: + return gtk_rc_parse_im_module_file (scanner); + default: g_scanner_get_next_token (scanner); return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE; @@ -2120,7 +2171,7 @@ gtk_rc_parse_engine (GScanner *scanner, GtkRcStyleClass *new_class; new_style = gtk_theme_engine_create_rc_style (engine); - gtk_theme_engine_unref (engine); + g_type_module_unuse (G_TYPE_MODULE (engine)); new_class = GTK_RC_STYLE_GET_CLASS (new_style); @@ -2460,6 +2511,48 @@ gtk_rc_parse_module_path (GScanner *scanner) return G_TOKEN_NONE; } +static guint +gtk_rc_parse_im_module_path (GScanner *scanner) +{ + guint token; + + token = g_scanner_get_next_token (scanner); + if (token != GTK_RC_TOKEN_IM_MODULE_FILE) + return GTK_RC_TOKEN_IM_MODULE_FILE; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_STRING) + return G_TOKEN_STRING; + + if (im_module_path) + g_free (im_module_path); + + im_module_path = g_strdup (scanner->value.v_string); + + return G_TOKEN_NONE; +} + +static guint +gtk_rc_parse_im_module_file (GScanner *scanner) +{ + guint token; + + token = g_scanner_get_next_token (scanner); + if (token != GTK_RC_TOKEN_IM_MODULE_FILE) + return GTK_RC_TOKEN_IM_MODULE_FILE; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_STRING) + return G_TOKEN_STRING; + + if (im_module_file) + g_free (im_module_file); + + im_module_file = g_strdup (scanner->value.v_string); + + return G_TOKEN_NONE; +} + static void gtk_rc_parse_module_path_string (gchar *mod_path) { diff --git a/gtk/gtkrc.h b/gtk/gtkrc.h index 0b37039311..5f281fc6cc 100644 --- a/gtk/gtkrc.h +++ b/gtk/gtkrc.h @@ -148,6 +148,8 @@ gchar* gtk_rc_find_pixmap_in_path (GScanner *scanner, gchar* gtk_rc_find_module_in_path (const gchar *module_file); gchar* gtk_rc_get_theme_dir (void); gchar* gtk_rc_get_module_dir (void); +gchar* gtk_rc_get_im_module_path (void); +gchar* gtk_rc_get_im_module_file (void); /* private functions/definitions */ typedef enum { @@ -182,6 +184,8 @@ typedef enum { GTK_RC_TOKEN_HIGHEST, GTK_RC_TOKEN_ENGINE, GTK_RC_TOKEN_MODULE_PATH, + GTK_RC_TOKEN_IM_MODULE_PATH, + GTK_RC_TOKEN_IM_MODULE_FILE, GTK_RC_TOKEN_STOCK, GTK_RC_TOKEN_LTR, GTK_RC_TOKEN_RTL, diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c index 4193ba28af..b5a55a8a9a 100644 --- a/gtk/gtkspinbutton.c +++ b/gtk/gtkspinbutton.c @@ -113,10 +113,10 @@ static gint gtk_spin_button_key_release (GtkWidget *widget, GdkEventKey *event); static gint gtk_spin_button_scroll (GtkWidget *widget, GdkEventScroll *event); -static void gtk_spin_button_activate (GtkEditable *editable); +static void gtk_spin_button_activate (GtkEntry *entry); static void gtk_spin_button_snap (GtkSpinButton *spin_button, gfloat val); -static void gtk_spin_button_insert_text (GtkEditable *editable, +static void gtk_spin_button_insert_text (GtkEntry *entry, const gchar *new_text, gint new_text_length, gint *position); @@ -161,11 +161,11 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkObjectClass *object_class; GtkWidgetClass *widget_class; - GtkEditableClass *editable_class; + GtkEntryClass *entry_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; - editable_class = (GtkEditableClass*) class; + entry_class = (GtkEntryClass*) class; parent_class = gtk_type_class (GTK_TYPE_ENTRY); @@ -192,8 +192,8 @@ 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; - editable_class->insert_text = gtk_spin_button_insert_text; - editable_class->activate = gtk_spin_button_activate; + entry_class->insert_text = gtk_spin_button_insert_text; + entry_class->activate = gtk_spin_button_activate; class->input = NULL; class->output = NULL; @@ -756,7 +756,7 @@ gtk_spin_button_focus_out (GtkWidget *widget, g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); - if (GTK_EDITABLE (widget)->editable) + if (GTK_ENTRY (widget)->editable) gtk_spin_button_update (GTK_SPIN_BUTTON (widget)); return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event); @@ -813,7 +813,7 @@ gtk_spin_button_button_press (GtkWidget *widget, gtk_grab_add (widget); spin->button = event->button; - if (GTK_EDITABLE (widget)->editable) + if (GTK_ENTRY (widget)->editable) gtk_spin_button_update (spin); if (event->y <= widget->requisition.height / 2) @@ -1066,7 +1066,7 @@ gtk_spin_button_key_press (GtkWidget *widget, key_repeat = (event->time == spin->ev_time); - if (GTK_EDITABLE (widget)->editable && + if (GTK_ENTRY (widget)->editable && (key == GDK_Up || key == GDK_Down || key == GDK_Page_Up || key == GDK_Page_Down)) gtk_spin_button_update (spin); @@ -1204,30 +1204,21 @@ gtk_spin_button_snap (GtkSpinButton *spin_button, } static void -gtk_spin_button_activate (GtkEditable *editable) +gtk_spin_button_activate (GtkEntry *entry) { - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_SPIN_BUTTON (editable)); - - if (editable->editable) - gtk_spin_button_update (GTK_SPIN_BUTTON (editable)); + if (entry->editable) + gtk_spin_button_update (GTK_SPIN_BUTTON (entry)); } static void -gtk_spin_button_insert_text (GtkEditable *editable, +gtk_spin_button_insert_text (GtkEntry *entry, const gchar *new_text, gint new_text_length, gint *position) { - GtkEntry *entry; - GtkSpinButton *spin; + GtkEditable *editable = GTK_EDITABLE (entry); + GtkSpinButton *spin = GTK_SPIN_BUTTON (editable); - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_SPIN_BUTTON (editable)); - - entry = GTK_ENTRY (editable); - spin = GTK_SPIN_BUTTON (editable); - if (spin->numeric) { struct lconv *lc; @@ -1296,8 +1287,8 @@ gtk_spin_button_insert_text (GtkEditable *editable, } } - GTK_EDITABLE_CLASS (parent_class)->insert_text (editable, new_text, - new_text_length, position); + GTK_ENTRY_CLASS (parent_class)->insert_text (entry, new_text, + new_text_length, position); } static void @@ -1565,7 +1556,7 @@ gtk_spin_button_set_snap_to_ticks (GtkSpinButton *spin_button, if (new_val != spin_button->snap_to_ticks) { spin_button->snap_to_ticks = new_val; - if (new_val && GTK_EDITABLE (spin_button)->editable) + if (new_val && GTK_ENTRY (spin_button)->editable) gtk_spin_button_update (spin_button); } } diff --git a/gtk/gtktext.c b/gtk/gtktext.c index 5994b1949f..cd8bf8dde8 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -219,24 +219,24 @@ 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, - gint new_text_length, - gint *position); -static void gtk_text_delete_text (GtkEditable *editable, - gint start_pos, - gint end_pos); -static void gtk_text_update_text (GtkEditable *editable, - gint start_pos, - gint end_pos); -static gchar *gtk_text_get_chars (GtkEditable *editable, - gint start, - gint end); -static void gtk_text_set_selection (GtkEditable *editable, - gint start, - gint end); -static void gtk_text_real_set_editable (GtkEditable *editable, - gboolean is_editable); +static void gtk_text_insert_text (GtkOldEditable *old_editable, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_text_delete_text (GtkOldEditable *old_editable, + gint start_pos, + gint end_pos); +static void gtk_text_update_text (GtkOldEditable *old_editable, + gint start_pos, + gint end_pos); +static gchar *gtk_text_get_chars (GtkOldEditable *old_editable, + gint start, + gint end); +static void gtk_text_set_selection (GtkOldEditable *old_editable, + gint start, + gint end); +static void gtk_text_real_set_editable (GtkOldEditable *old_editable, + gboolean is_editable); /* Event handlers */ static void gtk_text_draw (GtkWidget *widget, @@ -346,24 +346,24 @@ static void move_cursor_ver (GtkText *text, int count); static void move_cursor_hor (GtkText *text, int count); /* Binding actions */ -static void gtk_text_move_cursor (GtkEditable *editable, - gint x, - gint y); -static void gtk_text_move_word (GtkEditable *editable, - gint n); -static void gtk_text_move_page (GtkEditable *editable, - gint x, - gint y); -static void gtk_text_move_to_row (GtkEditable *editable, - gint row); -static void gtk_text_move_to_column (GtkEditable *editable, - gint row); -static void gtk_text_kill_char (GtkEditable *editable, - gint direction); -static void gtk_text_kill_word (GtkEditable *editable, - gint direction); -static void gtk_text_kill_line (GtkEditable *editable, - gint direction); +static void gtk_text_move_cursor (GtkOldEditable *old_editable, + gint x, + gint y); +static void gtk_text_move_word (GtkOldEditable *old_editable, + gint n); +static void gtk_text_move_page (GtkOldEditable *old_editable, + gint x, + gint y); +static void gtk_text_move_to_row (GtkOldEditable *old_editable, + gint row); +static void gtk_text_move_to_column (GtkOldEditable *old_editable, + gint row); +static void gtk_text_kill_char (GtkOldEditable *old_editable, + gint direction); +static void gtk_text_kill_word (GtkOldEditable *old_editable, + gint direction); +static void gtk_text_kill_line (GtkOldEditable *old_editable, + gint direction); /* To be removed */ static void gtk_text_move_forward_character (GtkText *text); @@ -386,8 +386,8 @@ static void gtk_text_select_word (GtkText *text, static void gtk_text_select_line (GtkText *text, guint32 time); -static void gtk_text_set_position (GtkEditable *editable, - gint position); +static void gtk_text_set_position (GtkOldEditable *old_editable, + gint position); /* #define DEBUG_GTK_TEXT */ @@ -525,7 +525,7 @@ gtk_text_get_type (void) (GtkClassInitFunc) NULL, }; - text_type = gtk_type_unique (GTK_TYPE_EDITABLE, &text_info); + text_type = gtk_type_unique (GTK_TYPE_OLD_EDITABLE, &text_info); } return text_type; @@ -537,12 +537,12 @@ gtk_text_class_init (GtkTextClass *class) GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkObjectClass *object_class; GtkWidgetClass *widget_class; - GtkEditableClass *editable_class; + GtkOldEditableClass *old_editable_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; - editable_class = (GtkEditableClass*) class; - parent_class = gtk_type_class (GTK_TYPE_EDITABLE); + old_editable_class = (GtkOldEditableClass*) class; + parent_class = gtk_type_class (GTK_TYPE_OLD_EDITABLE); gobject_class->finalize = gtk_text_finalize; @@ -566,24 +566,24 @@ gtk_text_class_init (GtkTextClass *class) widget_class->focus_in_event = gtk_text_focus_in; widget_class->focus_out_event = gtk_text_focus_out; - editable_class->set_editable = gtk_text_real_set_editable; - editable_class->insert_text = gtk_text_insert_text; - editable_class->delete_text = gtk_text_delete_text; + old_editable_class->set_editable = gtk_text_real_set_editable; + old_editable_class->insert_text = gtk_text_insert_text; + old_editable_class->delete_text = gtk_text_delete_text; - editable_class->move_cursor = gtk_text_move_cursor; - editable_class->move_word = gtk_text_move_word; - editable_class->move_page = gtk_text_move_page; - editable_class->move_to_row = gtk_text_move_to_row; - editable_class->move_to_column = gtk_text_move_to_column; + old_editable_class->move_cursor = gtk_text_move_cursor; + old_editable_class->move_word = gtk_text_move_word; + old_editable_class->move_page = gtk_text_move_page; + old_editable_class->move_to_row = gtk_text_move_to_row; + old_editable_class->move_to_column = gtk_text_move_to_column; - editable_class->kill_char = gtk_text_kill_char; - editable_class->kill_word = gtk_text_kill_word; - editable_class->kill_line = gtk_text_kill_line; + old_editable_class->kill_char = gtk_text_kill_char; + old_editable_class->kill_word = gtk_text_kill_word; + old_editable_class->kill_line = gtk_text_kill_line; - editable_class->update_text = gtk_text_update_text; - editable_class->get_chars = gtk_text_get_chars; - editable_class->set_selection = gtk_text_set_selection; - editable_class->set_position = gtk_text_set_position; + old_editable_class->update_text = gtk_text_update_text; + old_editable_class->get_chars = gtk_text_get_chars; + old_editable_class->set_selection = gtk_text_set_selection; + old_editable_class->set_position = gtk_text_set_position; class->set_scroll_adjustments = gtk_text_set_adjustments; @@ -721,7 +721,7 @@ gtk_text_init (GtkText *text) init_properties (text); - GTK_EDITABLE (text)->editable = FALSE; + GTK_OLD_EDITABLE (text)->editable = FALSE; gtk_text_set_adjustments (text, NULL, NULL); gtk_editable_set_position (GTK_EDITABLE (text), 0); @@ -789,17 +789,17 @@ gtk_text_set_editable (GtkText *text, } static void -gtk_text_real_set_editable (GtkEditable *editable, - gboolean is_editable) +gtk_text_real_set_editable (GtkOldEditable *old_editable, + gboolean is_editable) { GtkText *text; - g_return_if_fail (editable != NULL); - g_return_if_fail (GTK_IS_TEXT (editable)); + g_return_if_fail (old_editable != NULL); + g_return_if_fail (GTK_IS_TEXT (old_editable)); - text = GTK_TEXT (editable); + text = GTK_TEXT (old_editable); - editable->editable = (is_editable != FALSE); + old_editable->editable = (is_editable != FALSE); if (is_editable) draw_cursor (text, TRUE); @@ -932,7 +932,7 @@ gtk_text_insert (GtkText *text, const char *chars, gint nchars) { - GtkEditable *editable = GTK_EDITABLE (text); + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (text); gboolean frozen = FALSE; gint new_line_count = 1; @@ -1032,10 +1032,10 @@ gtk_text_insert (GtkText *text, if (text->point.index < text->first_line_start_index) text->first_line_start_index += numwcs; - if (text->point.index < editable->selection_start_pos) - editable->selection_start_pos += numwcs; - if (text->point.index < editable->selection_end_pos) - editable->selection_end_pos += numwcs; + if (text->point.index < old_editable->selection_start_pos) + old_editable->selection_start_pos += numwcs; + if (text->point.index < old_editable->selection_end_pos) + old_editable->selection_end_pos += numwcs; /* We'll reset the cursor later anyways if we aren't frozen */ if (text->point.index < text->cursor_mark.index) text->cursor_mark.index += numwcs; @@ -1070,7 +1070,7 @@ gtk_text_forward_delete (GtkText *text, guint nchars) { guint old_lines, old_height; - GtkEditable *editable = GTK_EDITABLE (text); + GtkOldEditable *old_editable = GTK_OLD_EDITABLE (text); gboolean frozen = FALSE; g_return_val_if_fail (text != NULL, 0); @@ -1111,12 +1111,12 @@ gtk_text_forward_delete (GtkText *text, text->first_line_start_index -= nchars; } - if (text->point.index < editable->selection_start_pos) - editable->selection_start_pos -= - MIN(nchars, editable->selection_start_pos - text->point.index); - if (text->point.index < editable->selection_end_pos) - editable->selection_end_pos -= - MIN(nchars, editable->selection_end_pos - text->point.index); + if (text->point.index < old_editable->selection_start_pos) + old_editable->selection_start_pos -= + MIN(nchars, old_editable->selection_start_pos - text->point.index); + if (text->point.index < old_editable->selection_end_pos) + old_editable->selection_end_pos -= + MIN(nchars, old_editable->selection_end_pos - text->point.index); /* We'll reset the cursor later anyways if we aren't frozen */ if (text->point.index < text->cursor_mark.index) move_mark_n (&text->cursor_mark, @@ -1141,30 +1141,30 @@ gtk_text_forward_delete (GtkText *text, } static void -gtk_text_set_position (GtkEditable *editable, - gint position) +gtk_text_set_position (GtkOldEditable *old_editable, + gint position) { - GtkText *text = (GtkText *) editable; + GtkText *text = (GtkText *) old_editable; undraw_cursor (text, FALSE); text->cursor_mark = find_mark (text, position); find_cursor (text, TRUE); draw_cursor (text, FALSE); - gtk_editable_select_region (editable, 0, 0); + gtk_editable_select_region (GTK_EDITABLE (old_editable), 0, 0); } static gchar * -gtk_text_get_chars (GtkEditable *editable, - gint start_pos, - gint end_pos) +gtk_text_get_chars (GtkOldEditable *old_editable, + gint start_pos, + gint end_pos) { GtkText *text; gchar *retval; - g_return_val_if_fail (editable != NULL, NULL); - g_return_val_if_fail (GTK_IS_TEXT (editable), NULL); - text = GTK_TEXT (editable); + g_return_val_if_fail (old_editable != NULL, NULL); + g_return_val_if_fail (GTK_IS_TEXT (old_editable), NULL); + text = GTK_TEXT (old_editable); if (end_pos < 0) end_pos = TEXT_LENGTH (text); @@ -1277,7 +1277,7 @@ static void gtk_text_realize (GtkWidget *widget) { GtkText *text; - GtkEditable *editable; + GtkOldEditable *old_editable; GdkWindowAttr attributes; gint attributes_mask; @@ -1285,7 +1285,7 @@ gtk_text_realize (GtkWidget *widget) g_return_if_fail (GTK_IS_TEXT (widget)); text = GTK_TEXT (widget); - editable = GTK_EDITABLE (widget); + old_editable = GTK_OLD_EDITABLE (widget); GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED); attributes.window_type = GDK_WINDOW_CHILD; @@ -1341,12 +1341,12 @@ gtk_text_realize (GtkWidget *widget) gdk_gc_set_foreground (text->gc, &widget->style->text[GTK_STATE_NORMAL]); #ifdef USE_XIM - if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL) + if (gdk_im_ready () && (old_editable->ic_attr = gdk_ic_attr_new ()) != NULL) { gint width, height; GdkColormap *colormap; GdkEventMask mask; - GdkICAttr *attr = editable->ic_attr; + GdkICAttr *attr = old_editable->ic_attr; GdkICAttributesType attrmask = GDK_IC_ALL_REQ; GdkIMStyle style; GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE | @@ -1389,18 +1389,18 @@ gtk_text_realize (GtkWidget *widget) break; } - editable->ic = gdk_ic_new (attr, attrmask); + old_editable->ic = gdk_ic_new (attr, attrmask); - if (editable->ic == NULL) + if (old_editable->ic == NULL) g_warning ("Can't create input context."); else { mask = gdk_window_get_events (text->text_area); - mask |= gdk_ic_get_events (editable->ic); + mask |= gdk_ic_get_events (old_editable->ic); gdk_window_set_events (text->text_area, mask); if (GTK_WIDGET_HAS_FOCUS (widget)) - gdk_im_begin (editable->ic, text->text_area); + gdk_im_begin (old_editable->ic, text->text_area); } } #endif @@ -1409,8 +1409,8 @@ gtk_text_realize (GtkWidget *widget) gdk_window_show (text->text_area); init_properties (text); - if (editable->selection_start_pos != editable->selection_end_pos) - gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); + if (old_editable->selection_start_pos != old_editable->selection_end_pos) + gtk_old_editable_claim_selection (old_editable, TRUE, GDK_CURRENT_TIME); recompute_geometry (text); } @@ -1467,15 +1467,15 @@ gtk_text_unrealize (GtkWidget *widget) text = GTK_TEXT (widget); #ifdef USE_XIM - if (GTK_EDITABLE (widget)->ic) + if (GTK_OLD_EDITABLE (widget)->ic) { - gdk_ic_destroy (GTK_EDITABLE (widget)->ic); - GTK_EDITABLE (widget)->ic = NULL; + gdk_ic_destroy (GTK_OLD_EDITABLE (widget)->ic); + GTK_OLD_EDITABLE (widget)->ic = NULL; } - if (GTK_EDITABLE (widget)->ic_attr) + if (GTK_OLD_EDITABLE (widget)->ic_attr) { - gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr); - GTK_EDITABLE (widget)->ic_attr = NULL; + gdk_ic_attr_destroy (GTK_OLD_EDITABLE (widget)->ic_attr); + GTK_OLD_EDITABLE (widget)->ic_attr = NULL; } #endif @@ -1628,14 +1628,14 @@ gtk_text_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkText *text; - GtkEditable *editable; + GtkOldEditable *old_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); + old_editable = GTK_OLD_EDITABLE (widget); widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) @@ -1653,16 +1653,16 @@ gtk_text_size_allocate (GtkWidget *widget, (gint)TEXT_BORDER_ROOM) * 2)); #ifdef USE_XIM - if (editable->ic && (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION)) + if (old_editable->ic && (gdk_ic_get_style (old_editable->ic) & GDK_IM_PREEDIT_POSITION)) { gint width, height; gdk_window_get_size (text->text_area, &width, &height); - editable->ic_attr->preedit_area.width = width; - editable->ic_attr->preedit_area.height = height; + old_editable->ic_attr->preedit_area.width = width; + old_editable->ic_attr->preedit_area.height = height; - gdk_ic_set_attr (editable->ic, - editable->ic_attr, GDK_IC_PREEDIT_AREA); + gdk_ic_set_attr (old_editable->ic, + old_editable->ic_attr, GDK_IC_PREEDIT_AREA); } #endif @@ -1742,18 +1742,14 @@ gtk_text_button_press (GtkWidget *widget, GdkEventButton *event) { GtkText *text; - GtkEditable *editable; - static GdkAtom ctext_atom = GDK_NONE; + GtkOldEditable *old_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 (ctext_atom == GDK_NONE) - ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); - text = GTK_TEXT (widget); - editable = GTK_EDITABLE (widget); + old_editable = GTK_OLD_EDITABLE (widget); if (text->button && (event->button != text->button)) return FALSE; @@ -1776,8 +1772,8 @@ gtk_text_button_press (GtkWidget *widget, /* Set it now, so we display things right. We'll unset it * later if things don't work out */ - editable->has_selection = TRUE; - gtk_text_set_selection (GTK_EDITABLE(text), + old_editable->has_selection = TRUE; + gtk_text_set_selection (GTK_OLD_EDITABLE (text), text->cursor_mark.index, text->cursor_mark.index); @@ -1797,10 +1793,10 @@ gtk_text_button_press (GtkWidget *widget, } else if (event->type == GDK_BUTTON_PRESS) { - if ((event->button == 2) && editable->editable) + if ((event->button == 2) && old_editable->editable) { - if (editable->selection_start_pos == editable->selection_end_pos || - editable->has_selection) + if (old_editable->selection_start_pos == old_editable->selection_end_pos || + old_editable->has_selection) { undraw_cursor (text, FALSE); find_mouse_cursor (text, (gint)event->x, (gint)event->y); @@ -1809,7 +1805,8 @@ gtk_text_button_press (GtkWidget *widget, } gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, - ctext_atom, event->time); + gdk_atom_intern ("UTF8_STRING", FALSE), + event->time); } else { @@ -1819,11 +1816,11 @@ gtk_text_button_press (GtkWidget *widget, find_mouse_cursor (text, event->x, event->y); draw_cursor (text, FALSE); - gtk_text_set_selection (GTK_EDITABLE(text), + gtk_text_set_selection (GTK_OLD_EDITABLE (text), text->cursor_mark.index, text->cursor_mark.index); - editable->has_selection = FALSE; + old_editable->has_selection = FALSE; if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); } @@ -1837,7 +1834,7 @@ gtk_text_button_release (GtkWidget *widget, GdkEventButton *event) { GtkText *text; - GtkEditable *editable; + GtkOldEditable *old_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); @@ -1860,20 +1857,20 @@ gtk_text_button_release (GtkWidget *widget, if (event->button == 1) { text = GTK_TEXT (widget); - editable = GTK_EDITABLE (widget); + old_editable = GTK_OLD_EDITABLE (widget); gtk_grab_remove (widget); - editable->has_selection = FALSE; - if (editable->selection_start_pos != editable->selection_end_pos) + old_editable->has_selection = FALSE; + if (old_editable->selection_start_pos != old_editable->selection_end_pos) { if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time)) - editable->has_selection = TRUE; + old_editable->has_selection = TRUE; else - gtk_text_update_text (editable, editable->selection_start_pos, - editable->selection_end_pos); + gtk_text_update_text (old_editable, old_editable->selection_start_pos, + old_editable->selection_end_pos); } else { @@ -1943,20 +1940,20 @@ gtk_text_motion_notify (GtkWidget *widget, find_mouse_cursor (GTK_TEXT (widget), x, y); draw_cursor (GTK_TEXT (widget), FALSE); - gtk_text_set_selection (GTK_EDITABLE(text), - GTK_EDITABLE(text)->selection_start_pos, + gtk_text_set_selection (GTK_OLD_EDITABLE (text), + GTK_OLD_EDITABLE (text)->selection_start_pos, text->cursor_mark.index); return FALSE; } static void -gtk_text_insert_text (GtkEditable *editable, +gtk_text_insert_text (GtkOldEditable *old_editable, const gchar *new_text, gint new_text_length, gint *position) { - GtkText *text = GTK_TEXT (editable); + GtkText *text = GTK_TEXT (old_editable); GdkFont *font; GdkColor *fore, *back; @@ -1975,7 +1972,7 @@ gtk_text_insert_text (GtkEditable *editable, } static void -gtk_text_delete_text (GtkEditable *editable, +gtk_text_delete_text (GtkOldEditable *old_editable, gint start_pos, gint end_pos) { @@ -1983,7 +1980,7 @@ gtk_text_delete_text (GtkEditable *editable, g_return_if_fail (start_pos >= 0); - text = GTK_TEXT (editable); + text = GTK_TEXT (old_editable); gtk_text_set_point (text, start_pos); if (end_pos < 0) @@ -1998,7 +1995,7 @@ gtk_text_key_press (GtkWidget *widget, GdkEventKey *event) { GtkText *text; - GtkEditable *editable; + GtkOldEditable *old_editable; gchar key; gint return_val; gint position; @@ -2010,12 +2007,12 @@ gtk_text_key_press (GtkWidget *widget, return_val = FALSE; text = GTK_TEXT (widget); - editable = GTK_EDITABLE (widget); + old_editable = GTK_OLD_EDITABLE (widget); key = event->keyval; return_val = TRUE; - if ((GTK_EDITABLE(text)->editable == FALSE)) + if ((GTK_OLD_EDITABLE(text)->editable == FALSE)) { switch (event->keyval) { @@ -2050,7 +2047,7 @@ gtk_text_key_press (GtkWidget *widget, { gint extend_selection; gint extend_start; - guint initial_pos = editable->current_pos; + guint initial_pos = old_editable->current_pos; text->point = find_mark (text, text->cursor_mark.index); @@ -2059,15 +2056,15 @@ gtk_text_key_press (GtkWidget *widget, if (extend_selection) { - editable->has_selection = TRUE; + old_editable->has_selection = TRUE; - if (editable->selection_start_pos == editable->selection_end_pos) + if (old_editable->selection_start_pos == old_editable->selection_end_pos) { - editable->selection_start_pos = text->point.index; - editable->selection_end_pos = text->point.index; + old_editable->selection_start_pos = text->point.index; + old_editable->selection_end_pos = text->point.index; } - extend_start = (text->point.index == editable->selection_start_pos); + extend_start = (text->point.index == old_editable->selection_start_pos); } switch (event->keyval) @@ -2115,11 +2112,11 @@ gtk_text_key_press (GtkWidget *widget, if (event->state & GDK_SHIFT_MASK) { extend_selection = FALSE; - gtk_editable_paste_clipboard (editable); + gtk_editable_paste_clipboard (GTK_EDITABLE (old_editable)); } else if (event->state & GDK_CONTROL_MASK) { - gtk_editable_copy_clipboard (editable); + gtk_editable_copy_clipboard (GTK_EDITABLE (old_editable)); } else { @@ -2132,14 +2129,14 @@ gtk_text_key_press (GtkWidget *widget, else if (event->state & GDK_SHIFT_MASK) { extend_selection = FALSE; - gtk_editable_cut_clipboard (editable); + gtk_editable_cut_clipboard (GTK_EDITABLE (old_editable)); } else gtk_text_delete_forward_character (text); break; case GDK_Tab: position = text->point.index; - gtk_editable_insert_text (editable, "\t", 1, &position); + gtk_editable_insert_text (GTK_EDITABLE (old_editable), "\t", 1, &position); break; case GDK_Return: if (event->state & GDK_CONTROL_MASK) @@ -2147,7 +2144,7 @@ gtk_text_key_press (GtkWidget *widget, else { position = text->point.index; - gtk_editable_insert_text (editable, "\n", 1, &position); + gtk_editable_insert_text (GTK_EDITABLE (old_editable), "\n", 1, &position); } break; case GDK_Escape: @@ -2165,7 +2162,7 @@ gtk_text_key_press (GtkWidget *widget, if ((key >= 'a') && (key <= 'z') && control_keys[(int) (key - 'a')]) { - (* control_keys[(int) (key - 'a')]) (editable, event->time); + (* control_keys[(int) (key - 'a')]) (old_editable, event->time); return_val = TRUE; } @@ -2178,7 +2175,7 @@ gtk_text_key_press (GtkWidget *widget, if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')]) { - (* alt_keys[(int) (key - 'a')]) (editable, event->time); + (* alt_keys[(int) (key - 'a')]) (old_editable, event->time); return_val = TRUE; } @@ -2188,9 +2185,9 @@ gtk_text_key_press (GtkWidget *widget, { extend_selection = FALSE; - gtk_editable_delete_selection (editable); + gtk_editable_delete_selection (GTK_EDITABLE (old_editable)); position = text->point.index; - gtk_editable_insert_text (editable, event->string, event->length, &position); + gtk_editable_insert_text (GTK_EDITABLE (old_editable), event->string, event->length, &position); return_val = TRUE; } @@ -2198,32 +2195,32 @@ gtk_text_key_press (GtkWidget *widget, return_val = FALSE; } - if (return_val && (editable->current_pos != initial_pos)) + if (return_val && (old_editable->current_pos != initial_pos)) { 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); + if (old_editable->current_pos < old_editable->selection_start_pos) + gtk_text_set_selection (old_editable, old_editable->current_pos, + old_editable->selection_end_pos); + else if (old_editable->current_pos > old_editable->selection_end_pos) + gtk_text_set_selection (old_editable, old_editable->selection_start_pos, + old_editable->current_pos); else { if (extend_start) - gtk_text_set_selection (editable, editable->current_pos, - editable->selection_end_pos); + gtk_text_set_selection (old_editable, old_editable->current_pos, + old_editable->selection_end_pos); else - gtk_text_set_selection (editable, editable->selection_start_pos, - editable->current_pos); + gtk_text_set_selection (old_editable, old_editable->selection_start_pos, + old_editable->current_pos); } } else - gtk_text_set_selection (editable, 0, 0); + gtk_text_set_selection (old_editable, 0, 0); - gtk_editable_claim_selection (editable, - editable->selection_start_pos != editable->selection_end_pos, - event->time); + gtk_old_editable_claim_selection (old_editable, + old_editable->selection_start_pos != old_editable->selection_end_pos, + event->time); } } @@ -2244,8 +2241,8 @@ gtk_text_focus_in (GtkWidget *widget, gtk_widget_draw_focus (widget); #ifdef USE_XIM - if (GTK_EDITABLE(widget)->ic) - gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_TEXT(widget)->text_area); + if (GTK_OLD_EDITABLE (widget)->ic) + gdk_im_begin (GTK_OLD_EDITABLE (widget)->ic, GTK_TEXT(widget)->text_area); #endif draw_cursor (GTK_TEXT(widget), TRUE); @@ -3734,7 +3731,7 @@ static void find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height) { GdkWChar ch; - GtkEditable *editable = (GtkEditable *)text; + GtkOldEditable *old_editable = (GtkOldEditable *)text; GtkPropertyMark mark = start_line->start; TabStopMark tab_mark = start_line->tab_cont.tab_start; @@ -3762,26 +3759,26 @@ find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_hei text->cursor_char = ch; #ifdef USE_XIM - if (GTK_WIDGET_HAS_FOCUS(text) && gdk_im_ready() && editable->ic && - (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION)) + if (GTK_WIDGET_HAS_FOCUS(text) && gdk_im_ready() && old_editable->ic && + (gdk_ic_get_style (old_editable->ic) & GDK_IM_PREEDIT_POSITION)) { GdkICAttributesType mask = GDK_IC_SPOT_LOCATION | GDK_IC_PREEDIT_FOREGROUND | GDK_IC_PREEDIT_BACKGROUND; - editable->ic_attr->spot_location.x = text->cursor_pos_x; - editable->ic_attr->spot_location.y + old_editable->ic_attr->spot_location.x = text->cursor_pos_x; + old_editable->ic_attr->spot_location.y = text->cursor_pos_y - text->cursor_char_offset; - editable->ic_attr->preedit_foreground = *MARK_CURRENT_FORE (text, &mark); - editable->ic_attr->preedit_background = *MARK_CURRENT_BACK (text, &mark); + old_editable->ic_attr->preedit_foreground = *MARK_CURRENT_FORE (text, &mark); + old_editable->ic_attr->preedit_background = *MARK_CURRENT_BACK (text, &mark); if (MARK_CURRENT_FONT (text, &mark)->type == GDK_FONT_FONTSET) { mask |= GDK_IC_PREEDIT_FONTSET; - editable->ic_attr->preedit_fontset = MARK_CURRENT_FONT (text, &mark); + old_editable->ic_attr->preedit_fontset = MARK_CURRENT_FONT (text, &mark); } - gdk_ic_set_attr (editable->ic, editable->ic_attr, mask); + gdk_ic_set_attr (old_editable->ic, old_editable->ic_attr, mask); } #endif } @@ -3799,7 +3796,7 @@ find_cursor (GtkText* text, gboolean scroll) pixel_height_of(text, text->current_line)); } - GTK_EDITABLE (text)->current_pos = text->cursor_mark.index; + GTK_OLD_EDITABLE (text)->current_pos = text->cursor_mark.index; } static void @@ -4023,30 +4020,30 @@ move_cursor_hor (GtkText *text, int count) } static void -gtk_text_move_cursor (GtkEditable *editable, - gint x, - gint y) +gtk_text_move_cursor (GtkOldEditable *old_editable, + gint x, + gint y) { if (x > 0) { while (x-- != 0) - move_cursor_hor (GTK_TEXT (editable), 1); + move_cursor_hor (GTK_TEXT (old_editable), 1); } else if (x < 0) { while (x++ != 0) - move_cursor_hor (GTK_TEXT (editable), -1); + move_cursor_hor (GTK_TEXT (old_editable), -1); } if (y > 0) { while (y-- != 0) - move_cursor_ver (GTK_TEXT (editable), 1); + move_cursor_ver (GTK_TEXT (old_editable), 1); } else if (y < 0) { while (y++ != 0) - move_cursor_ver (GTK_TEXT (editable), -1); + move_cursor_ver (GTK_TEXT (old_editable), -1); } } @@ -4075,18 +4072,18 @@ gtk_text_move_previous_line (GtkText *text) } static void -gtk_text_move_word (GtkEditable *editable, - gint n) +gtk_text_move_word (GtkOldEditable *old_editable, + gint n) { if (n > 0) { while (n-- != 0) - gtk_text_move_forward_word (GTK_TEXT (editable)); + gtk_text_move_forward_word (GTK_TEXT (old_editable)); } else if (n < 0) { while (n++ != 0) - gtk_text_move_backward_word (GTK_TEXT (editable)); + gtk_text_move_backward_word (GTK_TEXT (old_editable)); } } @@ -4155,28 +4152,28 @@ gtk_text_move_backward_word (GtkText *text) } static void -gtk_text_move_page (GtkEditable *editable, - gint x, - gint y) +gtk_text_move_page (GtkOldEditable *old_editable, + gint x, + gint y) { if (y != 0) - scroll_int (GTK_TEXT (editable), - y * GTK_TEXT(editable)->vadj->page_increment); + scroll_int (GTK_TEXT (old_editable), + y * GTK_TEXT(old_editable)->vadj->page_increment); } static void -gtk_text_move_to_row (GtkEditable *editable, - gint row) +gtk_text_move_to_row (GtkOldEditable *old_editable, + gint row) { } static void -gtk_text_move_to_column (GtkEditable *editable, - gint column) +gtk_text_move_to_column (GtkOldEditable *old_editable, + gint column) { GtkText *text; - text = GTK_TEXT (editable); + text = GTK_TEXT (old_editable); text->cursor_virtual_x = 0; /* FIXME */ @@ -4205,37 +4202,37 @@ gtk_text_move_to_column (GtkEditable *editable, static void gtk_text_move_beginning_of_line (GtkText *text) { - gtk_text_move_to_column (GTK_EDITABLE (text), 0); + gtk_text_move_to_column (GTK_OLD_EDITABLE (text), 0); } static void gtk_text_move_end_of_line (GtkText *text) { - gtk_text_move_to_column (GTK_EDITABLE (text), -1); + gtk_text_move_to_column (GTK_OLD_EDITABLE (text), -1); } static void -gtk_text_kill_char (GtkEditable *editable, - gint direction) +gtk_text_kill_char (GtkOldEditable *old_editable, + gint direction) { GtkText *text; - text = GTK_TEXT (editable); + text = GTK_TEXT (old_editable); - if (editable->selection_start_pos != editable->selection_end_pos) - gtk_editable_delete_selection (editable); + if (old_editable->selection_start_pos != old_editable->selection_end_pos) + gtk_editable_delete_selection (GTK_EDITABLE (old_editable)); else { if (direction >= 0) { if (text->point.index + 1 <= TEXT_LENGTH (text)) - gtk_editable_delete_text (editable, text->point.index, text->point.index + 1); + gtk_editable_delete_text (GTK_EDITABLE (old_editable), text->point.index, text->point.index + 1); } else { if (text->point.index > 0) - gtk_editable_delete_text (editable, text->point.index - 1, text->point.index); + gtk_editable_delete_text (GTK_EDITABLE (old_editable), text->point.index - 1, text->point.index); } } } @@ -4243,33 +4240,33 @@ gtk_text_kill_char (GtkEditable *editable, static void gtk_text_delete_forward_character (GtkText *text) { - gtk_text_kill_char (GTK_EDITABLE (text), 1); + gtk_text_kill_char (GTK_OLD_EDITABLE (text), 1); } static void gtk_text_delete_backward_character (GtkText *text) { - gtk_text_kill_char (GTK_EDITABLE (text), -1); + gtk_text_kill_char (GTK_OLD_EDITABLE (text), -1); } static void -gtk_text_kill_word (GtkEditable *editable, - gint direction) +gtk_text_kill_word (GtkOldEditable *old_editable, + gint direction) { - if (editable->selection_start_pos != editable->selection_end_pos) - gtk_editable_delete_selection (editable); + if (old_editable->selection_start_pos != old_editable->selection_end_pos) + gtk_editable_delete_selection (GTK_EDITABLE (old_editable)); else { - gint old_pos = editable->current_pos; + gint old_pos = old_editable->current_pos; if (direction >= 0) { - gtk_text_move_word (editable, 1); - gtk_editable_delete_text (editable, old_pos, editable->current_pos); + gtk_text_move_word (old_editable, 1); + gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_pos, old_editable->current_pos); } else { - gtk_text_move_word (editable, -1); - gtk_editable_delete_text (editable, editable->current_pos, old_pos); + gtk_text_move_word (old_editable, -1); + gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_editable->current_pos, old_pos); } } } @@ -4277,43 +4274,43 @@ gtk_text_kill_word (GtkEditable *editable, static void gtk_text_delete_forward_word (GtkText *text) { - gtk_text_kill_word (GTK_EDITABLE (text), 1); + gtk_text_kill_word (GTK_OLD_EDITABLE (text), 1); } static void gtk_text_delete_backward_word (GtkText *text) { - gtk_text_kill_word (GTK_EDITABLE (text), -1); + gtk_text_kill_word (GTK_OLD_EDITABLE (text), -1); } static void -gtk_text_kill_line (GtkEditable *editable, - gint direction) +gtk_text_kill_line (GtkOldEditable *old_editable, + gint direction) { - gint old_pos = editable->current_pos; + gint old_pos = old_editable->current_pos; if (direction >= 0) { - gtk_text_move_to_column (editable, -1); - gtk_editable_delete_text (editable, old_pos, editable->current_pos); + gtk_text_move_to_column (old_editable, -1); + gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_pos, old_editable->current_pos); } else { - gtk_text_move_to_column (editable, 0); - gtk_editable_delete_text (editable, editable->current_pos, old_pos); + gtk_text_move_to_column (old_editable, 0); + gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_editable->current_pos, old_pos); } } static void gtk_text_delete_line (GtkText *text) { - gtk_text_move_to_column (GTK_EDITABLE (text), 0); - gtk_text_kill_line (GTK_EDITABLE (text), 1); + gtk_text_move_to_column (GTK_OLD_EDITABLE (text), 0); + gtk_text_kill_line (GTK_OLD_EDITABLE (text), 1); } static void gtk_text_delete_to_line_end (GtkText *text) { - gtk_text_kill_line (GTK_EDITABLE (text), 1); + gtk_text_kill_line (GTK_OLD_EDITABLE (text), 1); } static void @@ -4322,8 +4319,8 @@ gtk_text_select_word (GtkText *text, guint32 time) gint start_pos; gint end_pos; - GtkEditable *editable; - editable = GTK_EDITABLE (text); + GtkOldEditable *old_editable; + old_editable = GTK_OLD_EDITABLE (text); gtk_text_move_backward_word (text); start_pos = text->cursor_mark.index; @@ -4331,9 +4328,9 @@ gtk_text_select_word (GtkText *text, guint32 time) gtk_text_move_forward_word (text); end_pos = text->cursor_mark.index; - editable->has_selection = TRUE; - gtk_text_set_selection (editable, start_pos, end_pos); - gtk_editable_claim_selection (editable, start_pos != end_pos, time); + old_editable->has_selection = TRUE; + gtk_text_set_selection (old_editable, start_pos, end_pos); + gtk_old_editable_claim_selection (old_editable, start_pos != end_pos, time); } static void @@ -4342,8 +4339,8 @@ gtk_text_select_line (GtkText *text, guint32 time) gint start_pos; gint end_pos; - GtkEditable *editable; - editable = GTK_EDITABLE (text); + GtkOldEditable *old_editable; + old_editable = GTK_OLD_EDITABLE (text); gtk_text_move_beginning_of_line (text); start_pos = text->cursor_mark.index; @@ -4352,9 +4349,9 @@ gtk_text_select_line (GtkText *text, guint32 time) gtk_text_move_forward_character (text); end_pos = text->cursor_mark.index; - editable->has_selection = TRUE; - gtk_text_set_selection (editable, start_pos, end_pos); - gtk_editable_claim_selection (editable, start_pos != end_pos, time); + old_editable->has_selection = TRUE; + gtk_text_set_selection (old_editable, start_pos, end_pos); + gtk_old_editable_claim_selection (old_editable, start_pos != end_pos, time); } /**********************************************************************/ @@ -4867,19 +4864,18 @@ expand_scratch_buffer (GtkText* text, guint len) /* Side effect: modifies text->gc */ - static void draw_bg_rect (GtkText* text, GtkPropertyMark *mark, gint x, gint y, gint width, gint height, gboolean already_cleared) { - GtkEditable *editable = GTK_EDITABLE(text); + GtkOldEditable *old_editable = GTK_OLD_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 ((mark->index >= MIN(old_editable->selection_start_pos, old_editable->selection_end_pos) && + mark->index < MAX(old_editable->selection_start_pos, old_editable->selection_end_pos))) { gtk_paint_flat_box(GTK_WIDGET(text)->style, text->text_area, - editable->has_selection ? + old_editable->has_selection ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE, GTK_SHADOW_NONE, NULL, GTK_WIDGET(text), "text", @@ -4921,10 +4917,10 @@ draw_line (GtkText* text, union { GdkWChar *wc; guchar *ch; } buffer; GdkGC *fg_gc; - GtkEditable *editable = GTK_EDITABLE(text); + GtkOldEditable *old_editable = GTK_OLD_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); + guint selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos); + guint selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos); GtkPropertyMark mark = lp->start; TabStopMark tab_mark = lp->tab_cont.tab_start; @@ -5044,7 +5040,7 @@ draw_line (GtkText* text, if ((mark.index >= selection_start_pos) && (mark.index < selection_end_pos)) { - if (editable->has_selection) + if (old_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]; @@ -5159,7 +5155,7 @@ draw_line_wrap (GtkText* text, guint height /* baseline height */) static void undraw_cursor (GtkText* text, gint absolute) { - GtkEditable *editable = (GtkEditable *)text; + GtkOldEditable *old_editable = (GtkOldEditable *) text; TDEBUG (("in undraw_cursor\n")); @@ -5167,7 +5163,7 @@ undraw_cursor (GtkText* text, gint absolute) text->cursor_drawn_level = 0; if ((text->cursor_drawn_level ++ == 0) && - (editable->selection_start_pos == editable->selection_end_pos) && + (old_editable->selection_start_pos == old_editable->selection_end_pos) && GTK_WIDGET_DRAWABLE (text) && text->line_start_cache) { GdkFont* font; @@ -5225,7 +5221,7 @@ drawn_cursor_max (GtkText* text) static void draw_cursor (GtkText* text, gint absolute) { - GtkEditable *editable = (GtkEditable *)text; + GtkOldEditable *old_editable = (GtkOldEditable *)text; TDEBUG (("in draw_cursor\n")); @@ -5233,8 +5229,8 @@ draw_cursor (GtkText* text, gint absolute) text->cursor_drawn_level = 1; if ((--text->cursor_drawn_level == 0) && - editable->editable && - (editable->selection_start_pos == editable->selection_end_pos) && + old_editable->editable && + (old_editable->selection_start_pos == old_editable->selection_end_pos) && GTK_WIDGET_DRAWABLE (text) && text->line_start_cache) { GdkFont* font; @@ -5339,11 +5335,11 @@ expose_text (GtkText* text, GdkRectangle *area, gboolean cursor) } static void -gtk_text_update_text (GtkEditable *editable, - gint start_pos, - gint end_pos) +gtk_text_update_text (GtkOldEditable *old_editable, + gint start_pos, + gint end_pos) { - GtkText *text = GTK_TEXT (editable); + GtkText *text = GTK_TEXT (old_editable); GList *cache = text->line_start_cache; gint pixels = - text->first_cut_pixels; @@ -5454,11 +5450,11 @@ recompute_geometry (GtkText* text) /**********************************************************************/ static void -gtk_text_set_selection (GtkEditable *editable, - gint start, - gint end) +gtk_text_set_selection (GtkOldEditable *old_editable, + gint start, + gint end) { - GtkText *text = GTK_TEXT (editable); + GtkText *text = GTK_TEXT (old_editable); guint start1, end1, start2, end2; @@ -5467,8 +5463,8 @@ gtk_text_set_selection (GtkEditable *editable, start1 = MIN(start,end); end1 = MAX(start,end); - start2 = MIN(editable->selection_start_pos, editable->selection_end_pos); - end2 = MAX(editable->selection_start_pos, editable->selection_end_pos); + start2 = MIN(old_editable->selection_start_pos, old_editable->selection_end_pos); + end2 = MAX(old_editable->selection_start_pos, old_editable->selection_end_pos); if (start2 < start1) { @@ -5479,19 +5475,19 @@ gtk_text_set_selection (GtkEditable *editable, } undraw_cursor (text, FALSE); - editable->selection_start_pos = start; - editable->selection_end_pos = end; + old_editable->selection_start_pos = start; + old_editable->selection_end_pos = end; draw_cursor (text, FALSE); /* Expose only what changed */ if (start1 < start2) - gtk_text_update_text (editable, start1, MIN(end1, start2)); + gtk_text_update_text (old_editable, start1, MIN(end1, start2)); if (end2 > end1) - gtk_text_update_text (editable, MAX(end1, start2), end2); + gtk_text_update_text (old_editable, MAX(end1, start2), end2); else if (end2 < end1) - gtk_text_update_text (editable, end2, end1); + gtk_text_update_text (old_editable, end2, end1); } diff --git a/gtk/gtktext.h b/gtk/gtktext.h index 96eb30f183..b51f7b56e8 100644 --- a/gtk/gtktext.h +++ b/gtk/gtktext.h @@ -30,7 +30,7 @@ #include <gdk/gdk.h> #include <gtk/gtkadjustment.h> -#include <gtk/gtkeditable.h> +#include <gtk/gtkoldeditable.h> #ifdef __cplusplus extern "C" { @@ -64,7 +64,7 @@ struct _GtkPropertyMark struct _GtkText { - GtkEditable editable; + GtkOldEditable old_editable; GdkWindow *text_area; @@ -169,7 +169,7 @@ struct _GtkText struct _GtkTextClass { - GtkEditableClass parent_class; + GtkOldEditableClass parent_class; void (*set_scroll_adjustments) (GtkText *text, GtkAdjustment *hadjustment, diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index cbbd5cebea..7487d3d20c 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -92,11 +92,6 @@ static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout, /* may be NULL */ GtkTextLineData *line_data); -static void gtk_text_layout_real_get_log_attrs (GtkTextLayout *layout, - GtkTextLine *line, - PangoLogAttr **attrs, - gint *n_attrs); - static void gtk_text_layout_invalidated (GtkTextLayout *layout); static void gtk_text_layout_real_invalidate (GtkTextLayout *layout, @@ -207,7 +202,6 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass) gobject_class->finalize = gtk_text_layout_finalize; klass->wrap = gtk_text_layout_real_wrap; - klass->get_log_attrs = gtk_text_layout_real_get_log_attrs; klass->invalidate = gtk_text_layout_real_invalidate; klass->free_line_data = gtk_text_layout_real_free_line_data; } @@ -418,6 +412,69 @@ gtk_text_layout_get_cursor_visible (GtkTextLayout *layout) return layout->cursor_visible; } +/** + * gtk_text_layout_set_preedit_string: + * @layout: a #PangoLayout + * @preedit_string: a string to display at the insertion point + * @preedit_attrs: a #PangoAttrList of attributes that apply to @preedit_string + * @cursor_pos: position of cursor within preedit string in chars + * + * Set the preedit string and attributes. The preedit string is a + * string showing text that is currently being edited and not + * yet committed into the buffer. + **/ +void +gtk_text_layout_set_preedit_string (GtkTextLayout *layout, + const gchar *preedit_string, + PangoAttrList *preedit_attrs, + gint cursor_pos) +{ + GtkTextIter iter; + GtkTextLine *line; + GtkTextLineData *line_data; + + g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); + g_return_if_fail (preedit_attrs != NULL || preedit_string == NULL); + + if (layout->preedit_string) + g_free (layout->preedit_string); + + if (layout->preedit_attrs) + pango_attr_list_unref (layout->preedit_attrs); + + if (preedit_string) + { + layout->preedit_string = g_strdup (preedit_string); + layout->preedit_len = strlen (layout->preedit_string); + pango_attr_list_ref (preedit_attrs); + layout->preedit_attrs = preedit_attrs; + + cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (layout->preedit_string, -1)); + layout->preedit_cursor = g_utf8_offset_to_pointer (layout->preedit_string, cursor_pos) - layout->preedit_string; + } + else + { + layout->preedit_string = NULL; + layout->preedit_len = 0; + layout->preedit_attrs = NULL; + layout->preedit_cursor = 0; + } + + /* Now invalidate the paragraph containing the cursor + */ + gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter, + gtk_text_buffer_get_mark (layout->buffer, "insert")); + + line = gtk_text_iter_get_text_line (&iter); + line_data = gtk_text_line_get_data (line, layout); + if (line_data) + { + gtk_text_layout_invalidate_cache (layout, line); + gtk_text_line_invalidate_wrap (line, line_data); + gtk_text_layout_invalidated (layout); + } +} + void gtk_text_layout_get_size (GtkTextLayout *layout, gint *width, @@ -483,16 +540,6 @@ gtk_text_layout_wrap (GtkTextLayout *layout, return (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->wrap) (layout, line, line_data); } -void -gtk_text_layout_get_log_attrs (GtkTextLayout *layout, - GtkTextLine *line, - PangoLogAttr **attrs, - gint *n_attrs) -{ - (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->get_log_attrs) - (layout, line, attrs, n_attrs); -} - GSList* gtk_text_layout_get_lines (GtkTextLayout *layout, /* [top_y, bottom_y) */ @@ -856,21 +903,6 @@ gtk_text_layout_real_wrap (GtkTextLayout *layout, return line_data; } -static void -gtk_text_layout_real_get_log_attrs (GtkTextLayout *layout, - GtkTextLine *line, - PangoLogAttr **attrs, - gint *n_attrs) -{ - GtkTextLineDisplay *display; - - g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); - - display = gtk_text_layout_get_line_display (layout, line, TRUE); - pango_layout_get_log_attrs (display->layout, attrs, n_attrs); - gtk_text_layout_free_line_display (layout, display); -} - /* * Layout utility functions */ @@ -1285,6 +1317,18 @@ add_child_attrs (GtkTextLayout *layout, return; } + + if (layout->preedit_string) + { + g_free (layout->preedit_string); + layout->preedit_string = NULL; + } + + if (layout->preedit_attrs) + { + pango_attr_list_unref (layout->preedit_attrs); + layout->preedit_attrs = NULL; + } logical_rect.x = 0; logical_rect.y = -height * PANGO_SCALE; @@ -1355,6 +1399,96 @@ allocate_child_widgets (GtkTextLayout *layout, #endif } +static void +convert_color (GdkColor *result, + PangoAttrColor *attr) +{ + result->red = attr->red; + result->blue = attr->blue; + result->green = attr->green; +} + +/* This function is used to convert the preedit string attributes, which are + * standard PangoAttributes, into the custom attributes used by the text + * widget and insert them into a attr list with a given offset. + */ +static void +add_preedit_attrs (GtkTextLayout *layout, + GtkTextAttributes *style, + PangoAttrList *attrs, + gint offset, + gboolean size_only) +{ + PangoAttrIterator *iter = pango_attr_list_get_iterator (layout->preedit_attrs); + + do + { + GtkTextAppearance appearance = style->appearance; + PangoFontDescription font_desc; + PangoAttribute *insert_attr; + GSList *extra_attrs = NULL; + GSList *tmp_list; + gint start, end; + + pango_attr_iterator_range (iter, &start, &end); + + if (end == G_MAXINT) + end = layout->preedit_len; + + pango_attr_iterator_get_font (iter, style->font_desc, + &font_desc, size_only ? NULL : &extra_attrs); + + tmp_list = extra_attrs; + while (tmp_list) + { + PangoAttribute *attr = tmp_list->data; + + switch (attr->klass->type) + { + case PANGO_ATTR_FOREGROUND: + convert_color (&appearance.fg_color, (PangoAttrColor *)attr); + break; + case PANGO_ATTR_BACKGROUND: + convert_color (&appearance.bg_color, (PangoAttrColor *)attr); + appearance.draw_bg = TRUE; + break; + case PANGO_ATTR_UNDERLINE: + appearance.underline = ((PangoAttrInt *)attr)->value; + break; + case PANGO_ATTR_STRIKETHROUGH: + appearance.strikethrough = ((PangoAttrInt *)attr)->value; + break; + default: + break; + } + + pango_attribute_destroy (attr); + tmp_list = tmp_list->next; + } + + g_slist_free (extra_attrs); + + insert_attr = pango_attr_font_desc_new (&font_desc); + insert_attr->start_index = start + offset; + insert_attr->end_index = end + offset; + + pango_attr_list_insert (attrs, insert_attr); + + if (!size_only) + { + insert_attr = gtk_text_attr_appearance_new (&appearance); + + insert_attr->start_index = start + offset; + insert_attr->end_index = end + offset; + + pango_attr_list_insert (attrs, insert_attr); + } + } + while (pango_attr_iterator_next (iter)); + + pango_attr_iterator_destroy (iter); +} + GtkTextLineDisplay * gtk_text_layout_get_line_display (GtkTextLayout *layout, GtkTextLine *line, @@ -1393,6 +1527,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, display->size_only = size_only; display->line = line; + display->insert_index = -1; gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), &iter, line, 0); @@ -1454,8 +1589,9 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, */ gint byte_count = 0; - - while (TRUE) + GtkTextLineSegment *prev_seg = NULL; + + while (seg) { if (seg->type == >k_text_char_type) { @@ -1463,21 +1599,32 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, byte_offset += seg->byte_count; byte_count += seg->byte_count; } - else if (seg->body.mark.visible) + else if (seg->type == >k_text_right_mark_type || + seg->type == >k_text_left_mark_type) { - cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (byte_offset)); - cursor_segs = g_slist_prepend (cursor_segs, seg); + /* If we have preedit string, break out of this loop - we'll almost + * certainly have different attributes on the preedit string + */ + + if (layout->preedit_len > 0 && + gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer), + seg->body.mark.obj)) + break; + + if (seg->body.mark.visible) + { + cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (byte_offset)); + cursor_segs = g_slist_prepend (cursor_segs, seg); + } } + else + break; - if (!seg->next || - (seg->next->type != >k_text_right_mark_type && - seg->next->type != >k_text_left_mark_type && - seg->next->type != >k_text_char_type)) - break; - + prev_seg = seg; seg = seg->next; } + seg = prev_seg; /* Back up one */ add_text_attrs (layout, style, byte_count, attrs, byte_offset - byte_count, size_only); } @@ -1519,12 +1666,38 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, else if (seg->type == >k_text_right_mark_type || seg->type == >k_text_left_mark_type) { + gint cursor_offset = 0; + + /* At the insertion point, add the preedit string, if any */ + + if (gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer), + seg->body.mark.obj)) + { + display->insert_index = byte_offset; + + if (layout->preedit_len > 0) + { + byte_count += layout->preedit_len; + text = g_realloc (text, byte_count); + + style = get_style (layout, &iter); + add_preedit_attrs (layout, style, attrs, byte_offset, size_only); + release_style (layout, style); + + memcpy (text + byte_offset, layout->preedit_string, layout->preedit_len); + byte_offset += layout->preedit_len; + + cursor_offset = layout->preedit_cursor - layout->preedit_len; + } + } + + /* Display visible marks */ if (seg->body.mark.visible) { cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, - GINT_TO_POINTER (byte_offset)); + GINT_TO_POINTER (byte_offset + cursor_offset)); cursor_segs = g_slist_prepend (cursor_segs, seg); } } @@ -1602,6 +1775,46 @@ gtk_text_layout_free_line_display (GtkTextLayout *layout, } } +/* Functions to convert iter <=> index for the line of a GtkTextLineDisplay + * taking into account the preedit string, if necessary. + */ +gint +line_display_iter_to_index (GtkTextLayout *layout, + GtkTextLineDisplay *display, + const GtkTextIter *iter) +{ + gint index; + + g_return_val_if_fail (gtk_text_iter_get_text_line (iter) == display->line, 0); + + index = gtk_text_iter_get_line_index (iter); + + if (index >= display->insert_index) + index += layout->preedit_len; + + return index; +} + +void +line_display_index_to_iter (GtkTextLayout *layout, + GtkTextLineDisplay *display, + GtkTextIter *iter, + gint index, + gint trailing) +{ + if (index >= display->insert_index + layout->preedit_len) + index -= layout->preedit_len; + else if (index > display->insert_index) + { + index = display->insert_index; + trailing = 0; + } + + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + iter, display->line, index); + gtk_text_iter_forward_chars (iter, trailing); +} + /* FIXME: This really doesn't belong in this file ... */ static GtkTextLineData* gtk_text_line_data_new (GtkTextLayout *layout, @@ -1711,12 +1924,7 @@ gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout, trailing = 0; } - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - target_iter, - line, byte_index); - - while (trailing--) - gtk_text_iter_next_char (target_iter); + line_display_index_to_iter (layout, display, target_iter, byte_index, trailing); gtk_text_layout_free_line_display (layout, display); } @@ -1746,6 +1954,7 @@ gtk_text_layout_get_cursor_locations (GtkTextLayout *layout, GtkTextLine *line; GtkTextLineDisplay *display; gint line_top; + gint index; PangoRectangle pango_strong_pos; PangoRectangle pango_weak_pos; @@ -1754,12 +1963,13 @@ gtk_text_layout_get_cursor_locations (GtkTextLayout *layout, g_return_if_fail (iter != NULL); line = gtk_text_iter_get_text_line (iter); + display = gtk_text_layout_get_line_display (layout, line, FALSE); + index = line_display_iter_to_index (layout, display, iter); + line_top = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), line, layout); - - display = gtk_text_layout_get_line_display (layout, line, FALSE); - - pango_layout_get_cursor_pos (display->layout, gtk_text_iter_get_line_index (iter), + + pango_layout_get_cursor_pos (display->layout, index, strong_pos ? &pango_strong_pos : NULL, weak_pos ? &pango_weak_pos : NULL); @@ -1885,7 +2095,7 @@ gtk_text_layout_get_iter_location (GtkTextLayout *layout, } else { - byte_index = gtk_text_iter_get_line_index (iter); + byte_index = line_display_iter_to_index (layout, display, iter); pango_layout_index_to_pos (display->layout, byte_index, &pango_rect); @@ -1898,6 +2108,8 @@ gtk_text_layout_get_iter_location (GtkTextLayout *layout, gtk_text_layout_free_line_display (layout, display); } +/* FFIXX */ + /* Find the iter for the logical beginning of the first display line whose * top y is >= y. If none exists, move the iter to the logical beginning * of the last line in the buffer. @@ -2104,9 +2316,8 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, g_return_if_fail (iter != NULL); line = gtk_text_iter_get_text_line (iter); - line_byte = gtk_text_iter_get_line_index (iter); - display = gtk_text_layout_get_line_display (layout, line, FALSE); + line_byte = line_display_iter_to_index (layout, display, iter); tmp_list = pango_layout_get_lines (display->layout); layout_line = tmp_list->data; @@ -2122,7 +2333,7 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, gtk_text_layout_free_line_display (layout, display); display = gtk_text_layout_get_line_display (layout, prev_line, FALSE); - tmp_list = pango_layout_get_lines (display->layout); + tmp_list = pango_layout_get_lines (display->layout); while (tmp_list->next) { @@ -2132,12 +2343,10 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, byte_offset += layout_line->length; } - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, prev_line, byte_offset); + line_display_index_to_iter (layout, display, iter, byte_offset, 0); } else - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, line, 0); + line_display_index_to_iter (layout, display, iter, 0, 0); } else { @@ -2151,8 +2360,7 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, if (line_byte < byte_offset + layout_line->length || !tmp_list->next) { - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, line, prev_offset); + line_display_index_to_iter (layout, display, iter, prev_offset, 0); break; } @@ -2190,7 +2398,6 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, g_return_if_fail (iter != NULL); line = gtk_text_iter_get_text_line (iter); - line_byte = gtk_text_iter_get_line_index (iter); while (line && !found_after) { @@ -2198,6 +2405,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, GSList *tmp_list; display = gtk_text_layout_get_line_display (layout, line, FALSE); + line_byte = line_display_iter_to_index (layout, display, iter); tmp_list = pango_layout_get_lines (display->layout); while (tmp_list && !found_after) @@ -2206,9 +2414,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, if (found) { - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, line, - byte_offset); + line_display_index_to_iter (layout, display, iter, byte_offset, 0); found_after = TRUE; } else if (line_byte < byte_offset + layout_line->length || !tmp_list->next) @@ -2248,9 +2454,8 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, g_return_if_fail (iter != NULL); line = gtk_text_iter_get_text_line (iter); - line_byte = gtk_text_iter_get_line_index (iter); - display = gtk_text_layout_get_line_display (layout, line, FALSE); + line_byte = line_display_iter_to_index (layout, display, iter); tmp_list = pango_layout_get_lines (display->layout); while (tmp_list) @@ -2259,11 +2464,13 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, if (line_byte < byte_offset + layout_line->length || !tmp_list->next) { - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, line, - direction < 0 ? byte_offset : byte_offset + layout_line->length); + line_display_index_to_iter (layout, display, iter, + direction < 0 ? byte_offset : byte_offset + layout_line->length, + 0); - /* FIXME: Move back one position to avoid going to next line + /* FIXME: As a bad hack, we move back one position to avoid going + * to next line on a forced break not at whitespace. Real fix + * is to keep track of whether marks are at leading or trailing edge? */ if (direction < 0 && layout_line->length > 0) gtk_text_iter_prev_char (iter); @@ -2304,9 +2511,9 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, g_return_if_fail (iter != NULL); line = gtk_text_iter_get_text_line (iter); - line_byte = gtk_text_iter_get_line_index (iter); display = gtk_text_layout_get_line_display (layout, line, FALSE); + line_byte = line_display_iter_to_index (layout, display, iter); tmp_list = pango_layout_get_lines (display->layout); while (tmp_list) @@ -2342,13 +2549,8 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, x * PANGO_SCALE - x_offset, &byte_index, &trailing); - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, - line, byte_index); - - while (trailing--) - gtk_text_iter_next_char (iter); - + line_display_index_to_iter (layout, display, iter, byte_index, trailing); + break; } @@ -2383,20 +2585,27 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, GtkTextIter *iter, gint count) { + GtkTextLineDisplay *display = NULL; + g_return_if_fail (layout != NULL); g_return_if_fail (iter != NULL); while (count != 0) { GtkTextLine *line = gtk_text_iter_get_text_line (iter); - gint line_byte = gtk_text_iter_get_line_index (iter); - GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE); + gint line_byte; + gint extra_back = 0; int byte_count = gtk_text_line_byte_count (line); int new_index; int new_trailing; + + if (!display) + display = gtk_text_layout_get_line_display (layout, line, FALSE); + line_byte = line_display_iter_to_index (layout, display, iter); + if (count > 0) { pango_layout_move_cursor_visually (display->layout, line_byte, 0, 1, &new_index, &new_trailing); @@ -2408,16 +2617,32 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, count++; } - gtk_text_layout_free_line_display (layout, display); - - if (new_index < 0) + /* We need to handle the preedit string specially. Well, we don't really need to + * handle it specially, since hopefully calling gtk_im_context_reset() will + * remove the preedit string; but if we start off in front of the preedit + * string (logically) and end up in or on the back edge of the preedit string, + * we should move the iter one place farther. + */ + if (layout->preedit_len > 0 && display->insert_index >= 0) + { + if (line_byte == display->insert_index + layout->preedit_len && + new_index < display->insert_index + layout->preedit_len) + { + line_byte = display->insert_index; + extra_back = 1; + } + } + + if (new_index < 0 || (new_index == 0 && extra_back)) { line = gtk_text_line_previous (line); + if (!line) return; + gtk_text_layout_free_line_display (layout, display); + display = gtk_text_layout_get_line_display (layout, line, FALSE); new_index = gtk_text_line_byte_count (line); - } else if (new_index > byte_count) { @@ -2425,16 +2650,17 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, if (!line) return; + gtk_text_layout_free_line_display (layout, display); + display = gtk_text_layout_get_line_display (layout, line, FALSE); new_index = 0; } - - gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), - iter, - line, new_index); - while (new_trailing--) - gtk_text_iter_next_char (iter); + + line_display_index_to_iter (layout, display, iter, new_index, new_trailing); + if (extra_back) + gtk_text_iter_prev_char (iter); } + gtk_text_layout_free_line_display (layout, display); } void @@ -2472,5 +2698,3 @@ gtk_text_layout_spew (GtkTextLayout *layout) layout->height, layout->screen_width); #endif } - - diff --git a/gtk/gtktextlayout.h b/gtk/gtktextlayout.h index 04ae9c0c77..dca8e362e5 100644 --- a/gtk/gtktextlayout.h +++ b/gtk/gtktextlayout.h @@ -156,6 +156,13 @@ struct _GtkTextLayout /* Whether to show the insertion cursor */ guint cursor_visible : 1; + + /* The preedit string and attributes, if any */ + + gchar *preedit_string; + PangoAttrList *preedit_attrs; + gint preedit_len; + gint preedit_cursor; }; struct _GtkTextLayoutClass @@ -221,6 +228,7 @@ struct _GtkTextLineDisplay gint right_margin; gint top_margin; gint bottom_margin; + gint insert_index; /* Byte index of insert cursor within para or -1 */ gboolean size_only; GtkTextLine *line; @@ -238,8 +246,14 @@ void gtk_text_layout_set_contexts (GtkTextLayout *layout, PangoContext *ltr_context, PangoContext *rtl_context); void gtk_text_layout_default_style_changed (GtkTextLayout *layout); + void gtk_text_layout_set_screen_width (GtkTextLayout *layout, gint width); +void gtk_text_layout_set_preedit_string (GtkTextLayout *layout, + const gchar *preedit_string, + PangoAttrList *preedit_attrs, + gint cursor_pos); + void gtk_text_layout_set_cursor_visible (GtkTextLayout *layout, gboolean cursor_visible); gboolean gtk_text_layout_get_cursor_visible (GtkTextLayout *layout); @@ -302,10 +316,6 @@ void gtk_text_layout_validate (GtkTextLayout *layout, GtkTextLineData* gtk_text_layout_wrap (GtkTextLayout *layout, GtkTextLine *line, GtkTextLineData *line_data); /* may be NULL */ -void gtk_text_layout_get_log_attrs (GtkTextLayout *layout, - GtkTextLine *line, - PangoLogAttr **attrs, - gint *n_attrs); void gtk_text_layout_changed (GtkTextLayout *layout, gint y, gint old_height, diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index ef21c82fb3..707cc98cd4 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -28,7 +28,10 @@ #include "gtkbindings.h" #include "gtkdnd.h" +#include "gtkintl.h" #include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" #include "gtksignal.h" #include "gtktext.h" #include "gtktextdisplay.h" @@ -176,6 +179,7 @@ static void gtk_text_view_set_attributes_from_style (GtkTextView *tex GtkStyle *style); static void gtk_text_view_ensure_layout (GtkTextView *text_view); static void gtk_text_view_destroy_layout (GtkTextView *text_view); +static void gtk_text_view_reset_im_context (GtkTextView *text_view); static void gtk_text_view_start_selection_drag (GtkTextView *text_view, const GtkTextIter *iter, GdkEventButton *event); @@ -187,11 +191,13 @@ static void gtk_text_view_start_selection_dnd (GtkTextView *text_vi static void gtk_text_view_start_cursor_blink (GtkTextView *text_view); static void gtk_text_view_stop_cursor_blink (GtkTextView *text_view); -static void gtk_text_view_value_changed (GtkAdjustment *adj, - GtkTextView *view); -static void gtk_text_view_commit_handler (GtkIMContext *context, - const gchar *str, - GtkTextView *text_view); +static void gtk_text_view_value_changed (GtkAdjustment *adj, + GtkTextView *view); +static void gtk_text_view_commit_handler (GtkIMContext *context, + const gchar *str, + GtkTextView *text_view); +static void gtk_text_view_preedit_changed_handler (GtkIMContext *context, + GtkTextView *text_view); static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer, const GtkTextIter *location, @@ -207,6 +213,9 @@ static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view, static GtkAdjustment* get_hadjustment (GtkTextView *text_view); static GtkAdjustment* get_vadjustment (GtkTextView *text_view); +static void gtk_text_view_popup_menu (GtkTextView *text_view, + GdkEventButton *event); + /* Container methods */ static void gtk_text_view_add (GtkContainer *container, GtkWidget *child); @@ -682,6 +691,9 @@ gtk_text_view_init (GtkTextView *text_view) gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit", GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view); + gtk_signal_connect (GTK_OBJECT (text_view->im_context), "preedit_changed", + GTK_SIGNAL_FUNC (gtk_text_view_preedit_changed_handler), text_view); + text_view->editable = TRUE; text_view->cursor_visible = TRUE; @@ -1578,7 +1590,6 @@ gtk_text_view_size_allocate (GtkWidget *widget, GdkRectangle right_rect; GdkRectangle top_rect; GdkRectangle bottom_rect; - GSList *tmp_list; text_view = GTK_TEXT_VIEW (widget); @@ -1914,6 +1925,12 @@ gtk_text_view_unrealize (GtkWidget *widget) text_view->incremental_validate_idle = 0; } + if (text_view->popup_menu) + { + gtk_widget_destroy (text_view->popup_menu); + text_view->popup_menu = NULL; + } + text_window_unrealize (text_view->text_window); if (text_view->left_window) @@ -2123,14 +2140,13 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event) get_buffer (text_view) == NULL) return FALSE; - if (GTK_WIDGET_CLASS (parent_class)->key_press_event && - GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) - return TRUE; - - if (event->window != text_view->text_window->bin_window) - return FALSE; - if (gtk_im_context_filter_keypress (text_view->im_context, event)) + { + text_view->need_im_reset = TRUE; + return TRUE; + } + else if (GTK_WIDGET_CLASS (parent_class)->key_press_event && + GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) return TRUE; else if (event->keyval == GDK_Return) { @@ -2179,14 +2195,18 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event) return FALSE; } +#if 0 /* debug hack */ if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0) _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer); else if (event->button == 3) gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout); +#endif if (event->type == GDK_BUTTON_PRESS) { + gtk_text_view_reset_im_context (text_view); + if (event->button == 1) { /* If we're in the selection, start a drag copy/move of the @@ -2230,10 +2250,7 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event) } else if (event->button == 3) { - if (gtk_text_view_end_selection_drag (text_view, event)) - return TRUE; - else - return FALSE; + gtk_text_view_popup_menu (text_view, event); } } @@ -2287,6 +2304,7 @@ gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event) gtk_text_view_start_cursor_blink (text_view); } + text_view->need_im_reset = TRUE; gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context); return FALSE; @@ -2306,6 +2324,7 @@ gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event) gtk_text_view_stop_cursor_blink (text_view); } + text_view->need_im_reset = TRUE; gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context); return FALSE; @@ -2642,6 +2661,8 @@ gtk_text_view_move_cursor (GtkTextView *text_view, gint cursor_x_pos = 0; + gtk_text_view_reset_im_context (text_view); + if (step == GTK_MOVEMENT_PAGES) { gtk_text_view_scroll_pages (text_view, count); @@ -2847,6 +2868,8 @@ gtk_text_view_delete_from_cursor (GtkTextView *text_view, GtkTextIter end; gboolean leave_one = FALSE; + gtk_text_view_reset_im_context (text_view); + if (type == GTK_DELETE_CHARS) { /* Char delete deletes the selection, if one exists */ @@ -3358,6 +3381,14 @@ gtk_text_view_destroy_layout (GtkTextView *text_view) } } +static void +gtk_text_view_reset_im_context (GtkTextView *text_view) +{ + if (text_view->need_im_reset) + text_view->need_im_reset = 0; + + gtk_im_context_reset (text_view->im_context); +} /* * DND feature @@ -3836,6 +3867,21 @@ gtk_text_view_commit_handler (GtkIMContext *context, 0); } +static void +gtk_text_view_preedit_changed_handler (GtkIMContext *context, + GtkTextView *text_view) +{ + gchar *str; + PangoAttrList *attrs; + gint cursor_pos; + + gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos); + gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos); + + pango_attr_list_unref (attrs); + g_free (str); +} + static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer, const GtkTextIter *location, @@ -3843,12 +3889,21 @@ gtk_text_view_mark_set_handler (GtkTextBuffer *buffer, gpointer data) { GtkTextView *text_view = GTK_TEXT_VIEW (data); + gboolean need_reset = FALSE; if (mark == gtk_text_buffer_get_insert (buffer)) { text_view->virtual_cursor_x = -1; text_view->virtual_cursor_y = -1; + need_reset = TRUE; + } + else if (mark == gtk_text_buffer_get_selection_bound (buffer)) + { + need_reset = TRUE; } + + if (need_reset) + gtk_text_view_reset_im_context (text_view); } static void @@ -3903,6 +3958,70 @@ gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view, text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y; } +/* Quick hack of a popup menu + */ +static void +activate_cb (GtkWidget *menuitem, + GtkTextView *text_view) +{ + const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal"); + gtk_signal_emit_by_name (GTK_OBJECT (text_view), signal); +} + +static void +append_action_signal (GtkTextView *text_view, + GtkWidget *menu, + const gchar *label, + const gchar *signal) +{ + GtkWidget *menuitem = gtk_menu_item_new_with_label (label); + + gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + activate_cb, text_view); + + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); +} + +static void +popup_menu_detach (GtkWidget *attach_widget, + GtkMenu *menu) +{ + GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL; +} + +static void +gtk_text_view_popup_menu (GtkTextView *text_view, + GdkEventButton *event) +{ + if (!text_view->popup_menu) + { + GtkWidget *menuitem; + + text_view->popup_menu = gtk_menu_new (); + + gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu), + GTK_WIDGET (text_view), + popup_menu_detach); + + append_action_signal (text_view, text_view->popup_menu, _("Cut"), "cut_clipboard"); + append_action_signal (text_view, text_view->popup_menu, _("Copy"), "copy_clipboard"); + append_action_signal (text_view, text_view->popup_menu, _("Paste"), "paste_clipboard"); + + menuitem = gtk_menu_item_new (); /* Separator */ + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem); + + gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context), + GTK_MENU_SHELL (text_view->popup_menu)); + } + + gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL, + NULL, NULL, + event->button, event->time); +} + /* Child GdkWindows */ diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 5d96ca7be8..5943aceab8 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -70,13 +70,12 @@ struct _GtkTextView guint selection_drag_scan_timeout; gint scrolling_accel_factor; - gboolean overwrite_mode; - GtkWrapMode wrap_mode; /* Default wrap mode */ - gboolean editable; /* default editability */ - - gboolean cursor_visible; + guint editable : 1; /* default editability */ + guint overwrite_mode : 1; + guint cursor_visible : 1; + guint need_im_reset : 1; /* If we have reset the IM since the last character entered */ GtkTextWindow *text_window; GtkTextWindow *left_window; @@ -114,6 +113,7 @@ struct _GtkTextView guint incremental_validate_idle; /* Idle to revalidate offscreen portions, runs after redraw */ GtkIMContext *im_context; + GtkWidget *popup_menu; gint drag_start_x; gint drag_start_y; diff --git a/gtk/gtkthemes.c b/gtk/gtkthemes.c index dc10495400..af3a2cb048 100644 --- a/gtk/gtkthemes.c +++ b/gtk/gtkthemes.c @@ -29,384 +29,166 @@ #include <stdlib.h> #include <gmodule.h> #include "gtkthemes.h" -#include "gtkmain.h" #include "gtkrc.h" -#include "gtkselection.h" -#include "gtksignal.h" -#include "gtkwidget.h" #include "config.h" #include "gtkintl.h" -/***************************** - ***************************** - * temporary compat code, make GtkThemeEnginePlugin a GObject plus GTypePlugin interface - */ -typedef struct _GtkThemeEnginePlugin GtkThemeEnginePlugin; -typedef struct _GObjectClass GtkThemeEnginePluginClass; -static void gtk_theme_engine_plugin_use (GTypePlugin *plugin); -static void gtk_theme_engine_plugin_unuse (GTypePlugin *plugin); -static void gtk_theme_engine_plugin_complete_type_info (GTypePlugin *plugin, - GType g_type, - GTypeInfo *info, - GTypeValueTable *value_table); -GType gtk_theme_engine_plugin_get_type (void); -struct _GtkThemeEnginePlugin -{ - GObject parent_instance; - - GtkThemeEngine *engine; - gchar *engine_name; - GTypeInfo info; - GType type; - GType parent_type; -}; -#define GTK_TYPE_THEME_ENGINE_PLUGIN (gtk_theme_engine_plugin_get_type ()) -#define GTK_THEME_ENGINE_PLUGIN(plugin) (G_TYPE_CHECK_INSTANCE_CAST ((plugin), GTK_TYPE_THEME_ENGINE_PLUGIN, GtkThemeEnginePlugin)) -#define GTK_THEME_ENGINE_PLUGIN_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), GTK_TYPE_THEME_ENGINE_PLUGIN, GtkThemeEnginePluginClass)) -#define GTK_IS_THEME_ENGINE_PLUGIN(plugin) (G_TYPE_CHECK_INSTANCE_TYPE ((plugin), GTK_TYPE_THEME_ENGINE_PLUGIN)) -#define GTK_IS_THEME_ENGINE_PLUGIN_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GTK_TYPE_THEME_ENGINE_PLUGIN)) -#define GTK_THEME_ENGINE_PLUGIN_GET_CLASS(plugin) (G_TYPE_INSTANCE_GET_CLASS ((plugin), GTK_TYPE_THEME_ENGINE_PLUGIN, GtkThemeEnginePluginClass)) -static void -gtk_theme_engine_plugin_shutdown (GObject *object) -{ - GtkThemeEnginePlugin *plugin = GTK_THEME_ENGINE_PLUGIN (object); - - g_warning (G_STRLOC ": shutdown should never happen for static type plugins"); - - g_object_ref (object); - - /* chain parent class handler */ - G_OBJECT_CLASS (g_type_class_peek_parent (GTK_THEME_ENGINE_PLUGIN_GET_CLASS (plugin)))->shutdown (object); -} -static void -gtk_theme_engine_plugin_class_init (GtkThemeEnginePluginClass *class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (class); - - gobject_class->shutdown = gtk_theme_engine_plugin_shutdown; -} -static void -theme_engine_plugin_iface_init (GTypePluginClass *iface) -{ - iface->use_plugin = gtk_theme_engine_plugin_use; - iface->unuse_plugin = gtk_theme_engine_plugin_unuse; - iface->complete_type_info = gtk_theme_engine_plugin_complete_type_info; -} -GType -gtk_theme_engine_plugin_get_type (void) -{ - static GType theme_engine_plugin_type = 0; - - if (!theme_engine_plugin_type) - { - static const GTypeInfo theme_engine_plugin_info = { - sizeof (GtkThemeEnginePluginClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_theme_engine_plugin_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkThemeEnginePlugin), - 0, /* n_preallocs */ - NULL, /* instance_init */ - }; - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) theme_engine_plugin_iface_init, - NULL, /* interface_finalize */ - NULL, /* interface_data */ - }; - - theme_engine_plugin_type = g_type_register_static (G_TYPE_OBJECT, "GtkThemeEnginePlugin", &theme_engine_plugin_info, 0); - - g_type_add_interface_static (theme_engine_plugin_type, G_TYPE_TYPE_PLUGIN, &iface_info); - } - - return theme_engine_plugin_type; -} -/* end of GtkThemeEnginePlugin object implementation stuff - ***************************** - *****************************/ +typedef struct _GtkThemeEngineClass GtkThemeEngineClass; struct _GtkThemeEngine { + GTypeModule parent_instance; + GModule *library; - void (*init) (GtkThemeEngine *); + void (*init) (GTypeModule *); void (*exit) (void); GtkRcStyle *(*create_rc_style) (); gchar *name; +}; - GSList *plugins; /* TypePlugins for this engine */ - - guint refcount; +struct _GtkThemeEngineClass +{ + GTypeModuleClass parent_class; }; static GHashTable *engine_hash = NULL; -#ifdef __EMX__ -static void gen_8_3_dll_name(gchar *name, gchar *fullname) -{ - /* 8.3 dll filename restriction */ - fullname[0] = '_'; - strncpy (fullname + 1, name, 7); - fullname[8] = '\0'; - strcat (fullname, ".dll"); -} -#endif - -GtkThemeEngine* -gtk_theme_engine_get (const gchar *name) +static gboolean +gtk_theme_engine_load (GTypeModule *module) { - GtkThemeEngine *result; + GtkThemeEngine *engine = GTK_THEME_ENGINE (module); - if (!engine_hash) - engine_hash = g_hash_table_new (g_str_hash, g_str_equal); - - /* get the library name for the theme */ + gchar *fullname; + gchar *engine_path; + + fullname = g_module_build_path (NULL, engine->name); + engine_path = gtk_rc_find_module_in_path (fullname); - result = g_hash_table_lookup (engine_hash, name); - - if (!result) + if (!engine_path) { - gchar *fullname; - gchar *engine_path; - GModule *library; + g_warning (_("Unable to locate loadable module in module_path: \"%s\","), + fullname); -#ifndef __EMX__ - fullname = g_module_build_path (NULL, name); -#else - fullname = g_malloc (13); - gen_8_3_dll_name(name, fullname); -#endif - engine_path = gtk_rc_find_module_in_path (fullname); -#ifdef __EMX__ - if (!engine_path) - { - /* try theme name without prefix '_' */ - memmove(fullname, fullname + 1, strlen(fullname)); - engine_path = gtk_rc_find_module_in_path (fullname); - } -#endif - - if (!engine_path) - { - g_warning (_("Unable to locate loadable module in module_path: \"%s\","), - fullname); - - g_free (fullname); - return NULL; - } - g_free (fullname); + g_free (fullname); + return FALSE; + } + + g_free (fullname); - /* load the lib */ - - GTK_NOTE (MISC, g_message ("Loading Theme %s\n", engine_path)); + /* load the lib */ + + GTK_NOTE (MISC, g_message ("Loading Theme %s\n", engine_path)); - library = g_module_open (engine_path, 0); - g_free(engine_path); - if (!library) - { - g_warning (g_module_error()); - return NULL; - } - else - { - result = g_new (GtkThemeEngine, 1); - - result->refcount = 1; - result->name = g_strdup (name); - result->library = library; - result->plugins = NULL; - - /* extract symbols from the lib */ - if (!g_module_symbol (library, "theme_init", - (gpointer *)&result->init) || - !g_module_symbol (library, "theme_exit", - (gpointer *)&result->exit) || - !g_module_symbol (library, "theme_create_rc_style", - (gpointer *)&result->create_rc_style)) - { - g_warning (g_module_error()); - g_free (result); - return NULL; - } - - /* call the theme's init (theme_init) function to let it */ - /* setup anything it needs to set up. */ - result->init((GtkThemeEngine *)result); - - g_hash_table_insert (engine_hash, result->name, result); - } + engine->library = g_module_open (engine_path, 0); + g_free(engine_path); + if (!engine->library) + { + g_warning (g_module_error()); + return FALSE; } - else - result->refcount++; - - return (GtkThemeEngine *)result; -} - -void -gtk_theme_engine_ref (GtkThemeEngine *engine) -{ - g_return_if_fail (engine != NULL); - engine->refcount++; -} - -void -gtk_theme_engine_unref (GtkThemeEngine *engine) -{ - GSList *tmp_list; - - g_return_if_fail (engine != NULL); - g_return_if_fail (engine->refcount > 0); - - engine->refcount--; - - if (engine->refcount == 0) + /* extract symbols from the lib */ + if (!g_module_symbol (engine->library, "theme_init", + (gpointer *)&engine->init) || + !g_module_symbol (engine->library, "theme_exit", + (gpointer *)&engine->exit) || + !g_module_symbol (engine->library, "theme_create_rc_style", + (gpointer *)&engine->create_rc_style)) { - engine->exit(); - - g_hash_table_remove (engine_hash, engine->name); - - tmp_list = engine->plugins; - while (tmp_list) - { - GtkThemeEnginePlugin *plugin = tmp_list->data; - plugin->engine = NULL; - - tmp_list = tmp_list->next; - } - g_slist_free (engine->plugins); - + g_warning (g_module_error()); g_module_close (engine->library); - g_free (engine->name); - g_free (engine); + + return FALSE; } -} + + /* call the theme's init (theme_init) function to let it */ + /* setup anything it needs to set up. */ + engine->init (module); -GtkRcStyle * -gtk_theme_engine_create_rc_style (GtkThemeEngine *engine) -{ - g_return_val_if_fail (engine != NULL, NULL); - - return engine->create_rc_style (); + return TRUE; } static void -gtk_theme_engine_plugin_use (GTypePlugin *plugin) +gtk_theme_engine_unload (GTypeModule *module) { - GtkThemeEnginePlugin *theme_plugin = GTK_THEME_ENGINE_PLUGIN (plugin); + GtkThemeEngine *engine = GTK_THEME_ENGINE (module); - if (theme_plugin->engine == NULL) - { - gtk_theme_engine_get (theme_plugin->engine_name); - if (!theme_plugin->engine) - { - g_warning ("An attempt to create an instance of a type from\n" - "a previously loaded theme engine was made after the engine\n" - "was unloaded, but the engine could not be reloaded or no longer\n" - "implements the type. Bad things will happen.\n"); - } - } - else - gtk_theme_engine_ref (theme_plugin->engine); -} + engine->exit(); -static void -gtk_theme_engine_plugin_unuse (GTypePlugin *plugin) -{ - GtkThemeEnginePlugin *theme_plugin = GTK_THEME_ENGINE_PLUGIN (plugin); + g_module_close (engine->library); + engine->library = NULL; - g_return_if_fail (theme_plugin->engine != NULL); - - gtk_theme_engine_unref (theme_plugin->engine); + engine->init = NULL; + engine->exit = NULL; + engine->create_rc_style = NULL; } - + static void -gtk_theme_engine_plugin_complete_type_info (GTypePlugin *plugin, - GType g_type, - GTypeInfo *info, - GTypeValueTable *value_table) +gtk_theme_engine_class_init (GtkThemeEngineClass *class) { - GtkThemeEnginePlugin *theme_plugin = GTK_THEME_ENGINE_PLUGIN (plugin); + GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class); - *info = theme_plugin->info; + module_class->load = gtk_theme_engine_load; + module_class->unload = gtk_theme_engine_unload; } -/** - * gtk_theme_engine_register_type: - * @engine: a #GtkThemeEngine - * @parent_type: the type for the parent class - * @type_name: name for the type - * @type_info: type information structure - * - * Looks up or registers a type that is implemented with a particular - * theme engine. If a type with name @type_name is already registered, - * the #GType identifier for the type is returned, otherwise the type - * is newly registered, and the resulting #GType identifier returned. - * - * As long as any instances of the type exist, the a reference will be - * held to the theme engine and the theme engine will not be unloaded. - * - * Return value: the type identifier for the class. - **/ GType -gtk_theme_engine_register_type (GtkThemeEngine *engine, - GType parent_type, - const gchar *type_name, - const GTypeInfo *type_info) +gtk_theme_engine_get_type (void) { - GtkThemeEnginePlugin *plugin; - GType type; - - g_return_val_if_fail (engine != NULL, 0); - g_return_val_if_fail (type_name != NULL, 0); - g_return_val_if_fail (type_info != NULL, 0); + static GType theme_engine_type = 0; - type = g_type_from_name (type_name); - if (type) - plugin = GTK_THEME_ENGINE_PLUGIN (g_type_get_plugin (type)); - else + if (!theme_engine_type) { - plugin = g_object_new (GTK_TYPE_THEME_ENGINE_PLUGIN, NULL); + static const GTypeInfo theme_engine_info = { + sizeof (GtkThemeEngineClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_theme_engine_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkThemeEngine), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; - plugin->engine = NULL; - plugin->engine_name = NULL; - plugin->parent_type = parent_type; - plugin->type = g_type_register_dynamic (parent_type, type_name, G_TYPE_PLUGIN (plugin), 0); + theme_engine_type = g_type_register_static (G_TYPE_TYPE_MODULE, "GtkThemeEngine", &theme_engine_info, 0); } - if (plugin->engine) - { - if (plugin->engine != engine) - { - g_warning ("Two different theme engines tried to register '%s'.", type_name); - return 0; - } + return theme_engine_type; +} - if (plugin->parent_type != parent_type) - { - g_warning ("Type '%s' recreated with different parent type.\n" - "(was '%s', now '%s')", type_name, - g_type_name (plugin->parent_type), - g_type_name (parent_type)); - return 0; - } - } - else - { - plugin->engine = engine; - if (plugin->engine_name) - g_free (plugin->engine_name); +GtkThemeEngine* +gtk_theme_engine_get (const gchar *name) +{ + GtkThemeEngine *result; + + if (!engine_hash) + engine_hash = g_hash_table_new (g_str_hash, g_str_equal); - plugin->engine_name = g_strdup (engine->name); - - plugin->info = *type_info; + /* get the library name for the theme + */ + result = g_hash_table_lookup (engine_hash, name); - engine->plugins = g_slist_prepend (engine->plugins, plugin); + if (!result) + { + result = GTK_THEME_ENGINE (g_object_new (GTK_TYPE_THEME_ENGINE, NULL)); + g_type_module_set_name (G_TYPE_MODULE (result), name); + + g_hash_table_insert (engine_hash, result->name, result); } - return plugin->type; + if (!g_type_module_use (G_TYPE_MODULE (result))) + return NULL; + + return result; } +GtkRcStyle * +gtk_theme_engine_create_rc_style (GtkThemeEngine *engine) +{ + g_return_val_if_fail (engine != NULL, NULL); + + return engine->create_rc_style (); +} diff --git a/gtk/gtkthemes.h b/gtk/gtkthemes.h index 713bda7b65..4c8b9a5550 100644 --- a/gtk/gtkthemes.h +++ b/gtk/gtkthemes.h @@ -32,21 +32,17 @@ #include <gtk/gtkstyle.h> #include <gtk/gtkwidget.h> - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -GtkThemeEngine * gtk_theme_engine_get (const gchar *name); -void gtk_theme_engine_ref (GtkThemeEngine *engine); -void gtk_theme_engine_unref (GtkThemeEngine *engine); -GtkRcStyle * gtk_theme_engine_create_rc_style (GtkThemeEngine *engine); - -GType gtk_theme_engine_register_type (GtkThemeEngine *engine, - GType parent_type, - const gchar *type_name, - const GTypeInfo *type_info); +#define GTK_TYPE_THEME_ENGINE (gtk_theme_engine_get_type ()) +#define GTK_THEME_ENGINE(theme_engine) (G_TYPE_CHECK_INSTANCE_CAST ((theme_engine), GTK_TYPE_THEME_ENGINE, GtkThemeEngine)) +#define GTK_IS_THEME_ENGINE(theme_engine) (G_TYPE_CHECK_INSTANCE_TYPE ((theme_engine), GTK_TYPE_THEME_ENGINE)) +GType gtk_theme_engine_get_type (void); +GtkThemeEngine *gtk_theme_engine_get (const gchar *name); +GtkRcStyle *gtk_theme_engine_create_rc_style (GtkThemeEngine *engine); #ifdef __cplusplus } diff --git a/gtk/queryimmodules.c b/gtk/queryimmodules.c new file mode 100644 index 0000000000..ff4987b2ea --- /dev/null +++ b/gtk/queryimmodules.c @@ -0,0 +1,170 @@ +/* GTK+ + * querymodules.c: + * + * Copyright (C) 2000 Red Hat Software + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include <glib.h> +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#endif +#include <gmodule.h> + +#include <errno.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdio.h> + +#ifdef G_OS_WIN32 +#define SOEXT ".dll" +#else +#define SOEXT ".so" +#endif + +#include <pango/pango-utils.h> +#include "gtk/gtkrc.h" +#include "gtk/gtkimmodule.h" + +void +print_escaped (const char *str) +{ + char *tmp = g_strescape (str, NULL); + printf ("\"%s\" ", tmp); + g_free (tmp); +} + +gboolean +query_module (const char *dir, const char *name) +{ + void (*list) (const GtkIMContextInfo ***contexts, + guint *n_contexts); + void (*init) (GTypeModule *type_module); + void (*exit) (void); + GtkIMContext *(*create) (const gchar *context_id); + + GModule *module; + gchar *path; + gboolean error = FALSE; + + if (name[0] == G_DIR_SEPARATOR) + path = g_strdup (name); + else + path = g_strconcat (dir, G_DIR_SEPARATOR_S, name, NULL); + + module = g_module_open (path, 0); + + if (!module) + { + fprintf(stderr, "Cannot load module %s: %s\n", path, g_module_error()); + error = TRUE; + } + + if (module && + g_module_symbol (module, "im_module_list", (gpointer)&list) && + g_module_symbol (module, "im_module_init", (gpointer)&init) && + g_module_symbol (module, "im_module_exit", (gpointer)&exit) && + g_module_symbol (module, "im_module_create", (gpointer)&create)) + { + const GtkIMContextInfo **contexts; + guint n_contexts; + int i; + + print_escaped (path); + fputs ("\n", stdout); + + (*list) (&contexts, &n_contexts); + + for (i=0; i<n_contexts; i++) + { + print_escaped (contexts[i]->context_id); + print_escaped (contexts[i]->context_name); + print_escaped (contexts[i]->domain); + print_escaped (contexts[i]->domain_dirname); + print_escaped (contexts[i]->default_locales); + fputs ("\n", stdout); + } + fputs ("\n", stdout); + } + else + { + fprintf (stderr, "%s does not export GTK+ IM module API: %s\n", path, + g_module_error()); + error = TRUE; + } + + g_free (path); + if (module) + g_module_close (module); + + return error; +} + +int main (int argc, char **argv) +{ + char cwd[PATH_MAX]; + int i; + char *path; + gboolean error = FALSE; + + printf ("# GTK+ Input Method Modules file\n" + "# Automatically generated file, do not edit\n" + "#\n"); + + if (argc == 1) /* No arguments given */ + { + char **dirs; + int i; + + path = gtk_rc_get_im_module_path (); + + printf ("# ModulesPath = %s\n#\n", path); + + dirs = pango_split_file_list (path); + + for (i=0; dirs[i]; i++) + { + DIR *dir = opendir (dirs[i]); + if (dir) + { + struct dirent *dent; + + while ((dent = readdir (dir))) + { + int len = strlen (dent->d_name); + if (len > 3 && strcmp (dent->d_name + len - strlen (SOEXT), SOEXT) == 0) + error |= query_module (dirs[i], dent->d_name); + } + + closedir (dir); + } + } + } + else + { + getcwd (cwd, PATH_MAX); + + for (i=1; i<argc; i++) + error |= query_module (cwd, argv[i]); + } + + return error ? 1 : 0; +} diff --git a/gtk/testgtk.c b/gtk/testgtk.c index cf36663f28..fd1795f2f6 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -9229,11 +9229,14 @@ create_main_window (void) gtk_widget_show_all (window); } -void -pixbuf_init () +static void +test_init () { if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so")) - putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs"); + { + putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs"); + putenv ("GTK_IM_MODULE_FILE=./gtk.immodules"); + } } int @@ -9243,7 +9246,7 @@ main (int argc, char *argv[]) srand (time (NULL)); - pixbuf_init (); + test_init (); gtk_set_locale (); /* Check to see if we are being run from the correct diff --git a/gtk/testtext.c b/gtk/testtext.c index 5424dc0f7f..279535aecd 100644 --- a/gtk/testtext.c +++ b/gtk/testtext.c @@ -1922,13 +1922,32 @@ create_view (Buffer *buffer) return view; } +static gboolean +file_exists (const char *filename) +{ + struct stat statbuf; + + return stat (filename, &statbuf) == 0; +} +void +test_init () +{ + if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so")) + { + putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs"); + putenv ("GTK_IM_MODULE_FILE=./gtk.immodules"); + } +} + int main (int argc, char** argv) { Buffer *buffer; View *view; int i; - + + test_init (); + gtk_set_locale (); gtk_init (&argc, &argv); buffer = create_buffer (); |