[gtksourceview/wip/chergert/vim] add some plumbing to observe keys
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/vim] add some plumbing to observe keys
- Date: Thu, 28 Oct 2021 16:31:40 +0000 (UTC)
commit 67cb8e0fb0453a5ff4150278f7cdb6763bfda620
Author: Christian Hergert <chergert redhat com>
Date: Thu Oct 28 09:31:34 2021 -0700
add some plumbing to observe keys
probably want to find a way to make this private eventually
gtksourceview/gtksourcevimimcontext.c | 94 +++++++++++++++++++++++++++++++
gtksourceview/vim/gtk-source-vim-normal.c | 22 ++++++++
gtksourceview/vim/gtk-source-vim.c | 18 ++++++
gtksourceview/vim/gtk-source-vim.h | 1 +
tests/test-vim.c | 56 +++++++++++++++++-
5 files changed, 188 insertions(+), 3 deletions(-)
---
diff --git a/gtksourceview/gtksourcevimimcontext.c b/gtksourceview/gtksourcevimimcontext.c
index 7be52fcf..f19fae22 100644
--- a/gtksourceview/gtksourcevimimcontext.c
+++ b/gtksourceview/gtksourcevimimcontext.c
@@ -31,6 +31,7 @@ struct _GtkSourceVimIMContext
{
GtkIMContext parent_instance;
GtkSourceVim *vim;
+ guint reset_observer : 1;
};
G_DEFINE_TYPE (GtkSourceVimIMContext, gtk_source_vim_im_context, GTK_TYPE_IM_CONTEXT)
@@ -44,12 +45,62 @@ enum {
enum {
EXECUTE_COMMAND,
+ OBSERVE_KEY,
N_SIGNALS
};
static GParamSpec *properties[N_PROPS];
static guint signals[N_SIGNALS];
+static inline void
+keyval_to_string (guint keyval,
+ GdkModifierType mods,
+ char str[16])
+{
+ int pos = 0;
+
+ if (keyval && (mods & GDK_CONTROL_MASK) != 0)
+ {
+ str[pos++] = '^';
+ }
+
+ switch (keyval)
+ {
+ case GDK_KEY_Escape:
+ str[pos++] = '^';
+ str[pos++] = '[';
+ break;
+
+ case GDK_KEY_ISO_Left_Tab:
+ case GDK_KEY_Tab:
+ str[pos++] = '\t';
+ break;
+
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_ISO_Enter:
+ str[pos++] = '\n';
+ break;
+
+ default:
+ {
+ gunichar ch;
+
+ /* ctrl things like ^M ^L are all uppercase */
+ if ((mods & GDK_CONTROL_MASK) != 0)
+ ch = gdk_keyval_to_unicode (gdk_keyval_to_upper (keyval));
+ else
+ ch = gdk_keyval_to_unicode (keyval);
+
+ pos += g_unichar_to_utf8 (ch, &str[pos]);
+
+ break;
+ }
+ }
+
+ str[pos] = 0;
+}
+
GtkIMContext *
gtk_source_vim_im_context_new (void)
{
@@ -89,6 +140,16 @@ on_vim_execute_command_cb (GtkSourceVimIMContext *self,
return ret;
}
+static void
+on_vim_ready_cb (GtkSourceVimIMContext *self,
+ GtkSourceVim *vim)
+{
+ g_assert (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
+ g_assert (GTK_SOURCE_IS_VIM (vim));
+
+ self->reset_observer = TRUE;
+}
+
static void
gtk_source_vim_im_context_set_client_widget (GtkIMContext *context,
GtkWidget *widget)
@@ -117,6 +178,12 @@ gtk_source_vim_im_context_set_client_widget (GtkIMContext *context,
self,
G_CONNECT_SWAPPED);
+ g_signal_connect_object (self->vim,
+ "ready",
+ G_CALLBACK (on_vim_ready_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMMAND_TEXT]);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMMAND_BAR_TEXT]);
}
@@ -159,6 +226,21 @@ gtk_source_vim_im_context_filter_keypress (GtkIMContext *context,
return FALSE;
}
+ if (gdk_event_get_event_type (event) == GDK_KEY_PRESS)
+ {
+ GdkModifierType mods;
+ guint keyval;
+ char str[16];
+
+ mods = gdk_event_get_modifier_state (event);
+ keyval = gdk_key_event_get_keyval (event);
+ keyval_to_string (keyval, mods, str);
+
+ g_signal_emit (self, signals[OBSERVE_KEY], 0, str, self->reset_observer);
+
+ self->reset_observer = FALSE;
+ }
+
return gtk_source_vim_state_handle_event (GTK_SOURCE_VIM_STATE (self->vim), event);
}
@@ -251,6 +333,18 @@ gtk_source_vim_im_context_class_init (GtkSourceVimIMContextClass *klass)
G_TYPE_BOOLEAN,
1,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ signals[OBSERVE_KEY] =
+ g_signal_new ("observe-key",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_BOOLEAN);
}
static void
diff --git a/gtksourceview/vim/gtk-source-vim-normal.c b/gtksourceview/vim/gtk-source-vim-normal.c
index bea3909b..71b6dd6e 100644
--- a/gtksourceview/vim/gtk-source-vim-normal.c
+++ b/gtksourceview/vim/gtk-source-vim-normal.c
@@ -21,6 +21,7 @@
#include "config.h"
+#include "gtk-source-vim.h"
#include "gtk-source-vim-command-bar.h"
#include "gtk-source-vim-delete.h"
#include "gtk-source-vim-insert.h"
@@ -57,6 +58,21 @@ static gboolean key_handler_initial (GtkSourceVimNormal *self,
G_DEFINE_TYPE (GtkSourceVimNormal, gtk_source_vim_normal, GTK_SOURCE_TYPE_VIM_STATE)
+static void
+gtk_source_vim_normal_emit_ready (GtkSourceVimNormal *self)
+{
+ GtkSourceVimState *parent;
+
+ g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
+
+ parent = gtk_source_vim_state_get_parent (GTK_SOURCE_VIM_STATE (self));
+
+ if (GTK_SOURCE_IS_VIM (parent))
+ {
+ gtk_source_vim_emit_ready (GTK_SOURCE_VIM (parent));
+ }
+}
+
static gboolean
gtk_source_vim_normal_bail (GtkSourceVimNormal *self)
{
@@ -998,4 +1014,10 @@ gtk_source_vim_normal_clear (GtkSourceVimNormal *self)
self->has_count = FALSE;
g_string_truncate (self->command_text, 0);
+
+ /* Let the toplevel know we're back at steady state. This is
+ * basically just so observers can watch keys which makes it
+ * much easier to debug issues.
+ */
+ gtk_source_vim_normal_emit_ready (self);
}
diff --git a/gtksourceview/vim/gtk-source-vim.c b/gtksourceview/vim/gtk-source-vim.c
index 9ba1d0d6..20eaaa8d 100644
--- a/gtksourceview/vim/gtk-source-vim.c
+++ b/gtksourceview/vim/gtk-source-vim.c
@@ -44,6 +44,7 @@ enum {
enum {
EXECUTE_COMMAND,
+ READY,
SPLIT,
N_SIGNALS
};
@@ -193,6 +194,15 @@ gtk_source_vim_class_init (GtkSourceVimClass *klass)
1,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
+ signals[READY] =
+ g_signal_new ("ready",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
/**
* GtkSourceVim::split:
* @self: a #GtkSourceVim
@@ -307,3 +317,11 @@ gtk_source_vim_emit_execute_command (GtkSourceVim *self,
return ret;
}
+
+void
+gtk_source_vim_emit_ready (GtkSourceVim *self)
+{
+ g_return_if_fail (GTK_SOURCE_IS_VIM (self));
+
+ g_signal_emit (self, signals[READY], 0);
+}
diff --git a/gtksourceview/vim/gtk-source-vim.h b/gtksourceview/vim/gtk-source-vim.h
index 3e8efad5..ff8a7e3d 100644
--- a/gtksourceview/vim/gtk-source-vim.h
+++ b/gtksourceview/vim/gtk-source-vim.h
@@ -35,6 +35,7 @@ const char *gtk_source_vim_get_command_text (GtkSourceVim *self);
const char *gtk_source_vim_get_command_bar_text (GtkSourceVim *self);
gboolean gtk_source_vim_emit_execute_command (GtkSourceVim *self,
const char *command);
+void gtk_source_vim_emit_ready (GtkSourceVim *self);
void gtk_source_vim_emit_split (GtkSourceVim *self,
GtkOrientation orientation,
gboolean new_document,
diff --git a/tests/test-vim.c b/tests/test-vim.c
index e5d86715..f3479e47 100644
--- a/tests/test-vim.c
+++ b/tests/test-vim.c
@@ -24,6 +24,21 @@
#include <gtksourceview/gtksource.h>
static GMainLoop *main_loop;
+static GString *sequence;
+
+#define OBSERVER_CSS \
+ "label.observer {" \
+ " color: white;" \
+ " font-size: 32pt;" \
+ " font-weight: bold;" \
+ " background: #2e3436;" \
+ " border-radius: 15px;" \
+ " min-width: 72px;" \
+ " min-height: 72px;" \
+ " box-shadow: 0 3px 10px 10px rgba(0,0,0,.09);" \
+ " outline: 1px solid alpha(white, 0.125);" \
+ " outline-offset: -2px;" \
+ "}"
static gboolean
execute_command (GtkSourceVimIMContext *context,
@@ -77,6 +92,18 @@ on_close_request (GtkWindow *window)
return FALSE;
}
+static void
+observe_key (GtkSourceVimIMContext *self,
+ const char *str,
+ gboolean reset_observer,
+ GtkLabel *label)
+{
+ if (reset_observer)
+ g_string_truncate (sequence, 0);
+ g_string_append (sequence, str);
+ gtk_label_set_label (label, sequence->str);
+}
+
int
main (int argc,
char *argv[])
@@ -84,6 +111,7 @@ main (int argc,
GtkWindow *window;
GtkSourceStyleSchemeManager *schemes;
GtkSourceLanguageManager *languages;
+ GtkCssProvider *css;
GtkScrolledWindow *scroller;
GtkSourceView *view;
GtkIMContext *im_context;
@@ -91,12 +119,21 @@ main (int argc,
GtkSourceBuffer *buffer;
GtkLabel *command_bar;
GtkLabel *command;
+ GtkLabel *observe;
+ GtkOverlay *overlay;
GtkBox *box;
GFile *file;
gtk_init ();
gtk_source_init ();
+ css = gtk_css_provider_new ();
+ gtk_css_provider_load_from_data (css, OBSERVER_CSS, -1);
+ gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+ GTK_STYLE_PROVIDER (css),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ sequence = g_string_new (NULL);
schemes = gtk_source_style_scheme_manager_get_default ();
languages = gtk_source_language_manager_get_default ();
@@ -105,6 +142,7 @@ main (int argc,
"default-width", 800,
"default-height", 600,
NULL);
+ overlay = g_object_new (GTK_TYPE_OVERLAY, NULL);
scroller = g_object_new (GTK_TYPE_SCROLLED_WINDOW, NULL);
buffer = gtk_source_buffer_new (NULL);
gtk_source_buffer_set_language (buffer, gtk_source_language_manager_get_language (languages, "c"));
@@ -134,17 +172,29 @@ main (int argc,
"margin-bottom", 6,
"margin-end", 12,
NULL);
- gtk_box_append (box, GTK_WIDGET (command_bar));
- gtk_box_append (box, GTK_WIDGET (command));
+ observe = g_object_new (GTK_TYPE_LABEL,
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_START,
+ "margin-top", 24,
+ "margin-bottom", 24,
+ "margin-end", 24,
+ "margin-start", 24,
+ NULL);
+ gtk_widget_add_css_class (GTK_WIDGET (observe), "observer");
- gtk_window_set_child (window, GTK_WIDGET (scroller));
+ gtk_window_set_child (window, GTK_WIDGET (overlay));
gtk_scrolled_window_set_child (scroller, GTK_WIDGET (view));
gtk_text_view_set_gutter (GTK_TEXT_VIEW (view), GTK_TEXT_WINDOW_BOTTOM, GTK_WIDGET (box));
+ gtk_box_append (box, GTK_WIDGET (command_bar));
+ gtk_box_append (box, GTK_WIDGET (command));
+ gtk_overlay_set_child (overlay, GTK_WIDGET (scroller));
+ gtk_overlay_add_overlay (overlay, GTK_WIDGET (observe));
im_context = gtk_source_vim_im_context_new ();
g_object_bind_property (im_context, "command-bar-text", command_bar, "label", G_BINDING_SYNC_CREATE);
g_object_bind_property (im_context, "command-text", command, "label", G_BINDING_SYNC_CREATE);
g_signal_connect (im_context, "execute-command", G_CALLBACK (execute_command), NULL);
+ g_signal_connect (im_context, "observe-key", G_CALLBACK (observe_key), observe);
gtk_im_context_set_client_widget (im_context, GTK_WIDGET (view));
key = gtk_event_controller_key_new ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]