Add rudimentary GdkEventKey queue
authorMichael Mackus <michaelmackus@gmail.com>
Tue, 1 Nov 2016 19:34:34 +0000 (12:34 -0700)
committerMichael Mackus <michaelmackus@gmail.com>
Tue, 1 Nov 2016 19:34:34 +0000 (12:34 -0700)
src/events.c [new file with mode: 0644]
src/events.h [new file with mode: 0644]
src/map.c

diff --git a/src/events.c b/src/events.c
new file mode 100644 (file)
index 0000000..a683938
--- /dev/null
@@ -0,0 +1,66 @@
+#include "events.h"
+
+/* this is only to queue GDK key events, in order to later send them if the map didn't match */
+static struct {
+    GdkEventKey **queue;                /* queue holding submitted events */
+    int            qlen;                /* pointer to last char in queue */
+    bool           processing;          /* whether or not events are processing */
+} events;
+
+/**
+ * Append an event into the queue.
+ */
+void queue_event(GdkEventKey* e)
+{
+    if (vb.mode->id != 'i') {
+        /* events are only needed for input mode */
+        return;
+    }
+
+    if (events.queue == NULL) {
+        events.queue = malloc(0);
+    }
+
+    events.queue = realloc(events.queue, (events.qlen + 1) * sizeof *events.queue);
+    events.queue[events.qlen] = e;
+    events.qlen ++;
+}
+
+/**
+ * Process events in the queue, sending the key events to GDK.
+ */
+void process_events()
+{
+    if (vb.mode->id != 'i') {
+        /* events are only needed for input mode */
+        return;
+    }
+
+    events.processing = true; /* signal not to map our events */
+
+    for (int i = 0; i < events.qlen; ++i)
+    {
+        // TODO send to gdk
+    }
+
+    events.qlen = 0;
+    events.processing = false;
+}
+
+/**
+ * Check if the events are currently processing (i.e. being sent to GDK
+ * unhandled).  Provided in order to encapsulate the "events" global struct.
+ */
+bool is_processing_events()
+{
+    return events.processing;
+}
+
+/**
+ * Clear the event queue by resetting the length. Provided in order to
+ * encapsulate the "events" global struct.
+ */
+void clear_events()
+{
+    events.qlen = 0;
+}
diff --git a/src/events.h b/src/events.h
new file mode 100644 (file)
index 0000000..32d5889
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _EVENTS_H
+#define _EVENTS_H
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkkeysyms-compat.h>
+#include "main.h"
+#include "map.h"
+
+void queue_event(GdkEventKey* e);
+void clear_events();
+void process_events();
+bool is_processing_events();
+
+extern VbCore vb;
+
+#endif /* end of include guard: _MAP_H */
index c5253de..ade7e69 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -18,6 +18,7 @@
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkkeysyms-compat.h>
 #include "config.h"
+#include "events.h"
 #include "main.h"
 #include "map.h"
 #include "normal.h"
@@ -131,6 +132,11 @@ void map_cleanup(void)
  */
 gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data)
 {
+    if (is_processing_events()) {
+        // events are processing, pass all keys unmodified
+        return false;
+    }
+
     guint state  = event->state;
     guint keyval = event->keyval;
     guchar string[32];
@@ -169,11 +175,22 @@ gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data)
     vb.state.typed         = true;
     vb.state.processed_key = true;
 
-    map_handle_keys(string, len, true);
+    MapState res = map_handle_keys(string, len, true);
 
     /* reset the typed flag */
     vb.state.typed = false;
 
+    if (res == MAP_NOMATCH) {
+        /* consume any unprocessed events */
+        process_events();
+    } else if (res == MAP_AMBIGUOUS) {
+        /* queue event for later processing */
+        queue_event(event);
+    } else if (res == MAP_DONE) {
+        /* we're done - clear events */
+        clear_events();
+    }
+
     return vb.state.processed_key;
 }
 
@@ -650,7 +667,15 @@ static char *convert_keylabel(const char *in, int inlen, int *len)
 static gboolean do_timeout(gpointer data)
 {
     /* signalize the timeout to the key handler */
-    map_handle_keys((guchar*)"", 0, true);
+    MapState res = map_handle_keys((guchar*)"", 0, true);
+
+    if (res == MAP_DONE) {
+        /* we're done - clear events */
+        clear_events();
+    } else {
+        /* consume any unprocessed events */
+        process_events();
+    }
 
     /* we return true to not automatically remove the resource - this is
      * required to prevent critical error when we remove the source in