aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/interface-gtk/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interface-gtk/interface.c')
-rw-r--r--src/interface-gtk/interface.c88
1 files changed, 63 insertions, 25 deletions
diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c
index 32f0011..8ccfd30 100644
--- a/src/interface-gtk/interface.c
+++ b/src/interface-gtk/interface.c
@@ -62,6 +62,8 @@
static void teco_interface_cmdline_size_allocate_cb(GtkWidget *widget,
GdkRectangle *allocation,
gpointer user_data);
+static void teco_interface_cmdline_commit_cb(GtkIMContext *context, gchar *str,
+ gpointer user_data);
static gboolean teco_interface_key_pressed_cb(GtkWidget *widget, GdkEventKey *event,
gpointer user_data);
static gboolean teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event,
@@ -183,6 +185,7 @@ static struct {
GtkWidget *message_widget;
teco_view_t *cmdline_view;
+ GtkIMContext *input_method;
GtkWidget *popup_widget;
@@ -326,9 +329,12 @@ teco_interface_init(void)
teco_view_ssm(teco_interface.cmdline_view, SCI_SETMARGINWIDTHN, 1,
teco_view_ssm(teco_interface.cmdline_view, SCI_TEXTWIDTH, STYLE_ASTERISK, (sptr_t)"*"));
teco_view_ssm(teco_interface.cmdline_view, SCI_MARGINSETTEXT, 0, (sptr_t)"*");
+ /* only required as long as we avoid ordinary character representations */
teco_view_ssm(teco_interface.cmdline_view, SCI_INDICSETSTYLE, INDIC_CONTROLCHAR, INDIC_ROUNDBOX);
teco_view_ssm(teco_interface.cmdline_view, SCI_INDICSETALPHA, INDIC_CONTROLCHAR, 128);
teco_view_ssm(teco_interface.cmdline_view, SCI_INDICSETSTYLE, INDIC_RUBBEDOUT, INDIC_STRIKE);
+ /* we will forward key events, so the view should only react to text insertion */
+ teco_view_ssm(teco_interface.cmdline_view, SCI_CLEARALLCMDKEYS, 0, 0);
GtkWidget *cmdline_widget = teco_view_get_widget(teco_interface.cmdline_view);
gtk_widget_set_name(cmdline_widget, "sciteco-cmdline");
@@ -338,6 +344,14 @@ teco_interface_init(void)
gtk_container_add(GTK_CONTAINER(teco_interface.window), vbox);
+ teco_interface.input_method = gtk_im_context_simple_new();
+ gtk_im_context_set_client_window(teco_interface.input_method,
+ gtk_widget_get_window(cmdline_widget));
+ gtk_im_context_focus_in(teco_interface.input_method);
+ gtk_im_context_set_use_preedit(teco_interface.input_method, FALSE);
+ g_signal_connect(teco_interface.input_method, "commit",
+ G_CALLBACK(teco_interface_cmdline_commit_cb), NULL);
+
/*
* Popup widget will be shown in the bottom
* of the overlay widget (i.e. the Scintilla views),
@@ -712,7 +726,8 @@ teco_interface_popup_clear(void)
* event loop (e.g. using libX11 or Win32 APIs).
* There already is a keyboard hook for Win32 in interface-curses.
* On the downside, such solutions will probably freeze the window
- * while SciTECO is busy.
+ * while SciTECO is busy. However we currently freeze the window
+ * anyway while being busy to avoid flickering.
*/
gboolean
teco_interface_is_interrupted(void)
@@ -799,12 +814,30 @@ teco_interface_set_css_variables(teco_view_t *view)
gtk_widget_set_size_request(teco_view_get_widget(teco_interface.cmdline_view), -1, text_height);
}
+static void
+teco_interface_cmdline_commit_cb(GtkIMContext *context, gchar *str, gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+
+ /*
+ * FIXME: This is only for consistency as long as we
+ * do not support Unicode.
+ */
+ for (char *p = str; *p != '\0'; p = g_utf8_next_char(p))
+ if (g_utf8_get_char(p) >= 0x80)
+ return;
+
+ if (!teco_cmdline_keypress(str, strlen(str), &error) &&
+ g_error_matches(error, TECO_ERROR, TECO_ERROR_QUIT))
+ gtk_main_quit();
+}
+
static gboolean
-teco_interface_handle_key_press(guint keyval, guint state, GError **error)
+teco_interface_handle_key_press(GdkEventKey *event, GError **error)
{
- teco_view_t *last_view = teco_interface_current_view;
+ const teco_view_t *last_view = teco_interface_current_view;
- switch (keyval) {
+ switch (event->keyval) {
case GDK_KEY_Escape:
if (!teco_cmdline_keypress_c('\e', error))
return FALSE;
@@ -832,7 +865,7 @@ teco_interface_handle_key_press(guint keyval, guint state, GError **error)
break
#define FNS(KEY, MACRO) \
case GDK_KEY_##KEY: \
- if (!teco_cmdline_fnmacro(state & GDK_SHIFT_MASK ? "S" #MACRO : #MACRO, error)) \
+ if (!teco_cmdline_fnmacro(event->state & GDK_SHIFT_MASK ? "S" #MACRO : #MACRO, error)) \
return FALSE; \
break
FN(Down, DOWN); FN(Up, UP);
@@ -844,7 +877,7 @@ teco_interface_handle_key_press(guint keyval, guint state, GError **error)
gchar macro_name[3+1];
g_snprintf(macro_name, sizeof(macro_name),
- "F%d", keyval - GDK_KEY_F1 + 1);
+ "F%d", event->keyval - GDK_KEY_F1 + 1);
if (!teco_cmdline_fnmacro(macro_name, error))
return FALSE;
break;
@@ -866,25 +899,27 @@ teco_interface_handle_key_press(guint keyval, guint state, GError **error)
* Control keys and keys with printable representation
*/
default: {
- gunichar u = gdk_keyval_to_unicode(keyval);
-
- if (!u || g_unichar_to_utf8(u, NULL) != 1)
- break;
+ gunichar u = gdk_keyval_to_unicode(event->keyval);
- gchar key;
-
- g_unichar_to_utf8(u, &key);
- if (key > 0x7F)
- break;
- /*
- * NOTE: Alt-Gr key-combinations are sometimes reported as
- * Ctrl+Alt, so we filter those out.
- */
- if ((state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) == GDK_CONTROL_MASK)
- key = TECO_CTL_KEY(g_ascii_toupper(key));
-
- if (!teco_cmdline_keypress_c(key, error))
- return FALSE;
+ if (u && u < 0x80 && (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) == GDK_CONTROL_MASK) {
+ /*
+ * NOTE: Alt-Gr key-combinations are sometimes reported as
+ * Ctrl+Alt, so we filter those out.
+ */
+ if (!teco_cmdline_keypress_c(TECO_CTL_KEY(g_ascii_toupper(u)), error))
+ return FALSE;
+ } else {
+ /*
+ * This is necessary to handle dead keys and in the future
+ * for inputting Asian languages.
+ *
+ * FIXME: We do not yet support preediting.
+ * It would be easier to forward the event to the Scintilla
+ * widget and use its existing IM support.
+ * But this breaks the event freezing and results in flickering.
+ */
+ gtk_im_context_filter_keypress(teco_interface.input_method, event);
+ }
}
}
@@ -1079,6 +1114,9 @@ teco_interface_cleanup(void)
{
teco_string_clear(&teco_interface.info_current);
+ if (teco_interface.input_method)
+ g_object_unref(teco_interface.input_method);
+
if (teco_interface.window)
gtk_widget_destroy(teco_interface.window);
@@ -1177,7 +1215,7 @@ teco_interface_key_pressed_cb(GtkWidget *widget, GdkEventKey *event, gpointer us
gdk_window_freeze_updates(top_window);
teco_sigint_occurred = FALSE;
- teco_interface_handle_key_press(event->key.keyval, event->key.state, &error);
+ teco_interface_handle_key_press(&event->key, &error);
teco_sigint_occurred = FALSE;
gdk_window_thaw_updates(top_window);