summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Legris <legris.thomas@gmail.com>2019-03-14 21:44:15 +0000
committerDaniel Carl <danielcarl@gmx.de>2019-03-14 23:00:14 +0100
commitcd0e694f4cd709f2a3d7205199c5fcf91502d41b (patch)
tree7d217c2b79543d2849b34c2106a79a4c0ad4f01e
parente316a77b994e2b59c3e468b71c531bb68ba4d637 (diff)
Allow incomplete imap sequence to timeout
-rw-r--r--src/events.c83
-rw-r--r--src/events.h15
-rw-r--r--src/map.c28
3 files changed, 123 insertions, 3 deletions
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 0000000..41a9975
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,83 @@
+/* Copyright (C) 2016-2019 Michael Mackus */
+#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 = {0};
+
+/**
+ * Append an event into the queue.
+ */
+void queue_event(GdkEventKey *e)
+{
+ GdkEventKey **newqueue = realloc(events.queue, (events.qlen + 1) * sizeof **newqueue);
+
+ if (newqueue == NULL) {
+ // error allocating memory
+ return;
+ }
+
+ events.queue = newqueue;
+
+ /* copy memory (otherwise event gets cleared by gdk) */
+ GdkEventKey *tmp = malloc(sizeof *tmp);
+ memcpy(tmp, e, sizeof *e);
+
+ if (tmp == NULL) {
+ // error allocating memory
+ return;
+ }
+
+ events.queue[events.qlen] = tmp;
+ events.qlen ++;
+}
+
+void process_event(GdkEventKey* event)
+{
+ if (event == NULL) {
+ return;
+ }
+
+ events.processing = true; /* signal not to queue other events */
+ gtk_main_do_event ((GdkEvent *) event);
+ events.processing = false;
+ free(event);
+}
+
+/**
+ * Process events in the queue, sending the key events to GDK.
+ */
+void process_events()
+{
+ for (int i = 0; i < events.qlen; ++i) {
+ process_event(events.queue[i]); /* process & free the event */
+ /* TODO take into account qk mapped key? */
+ }
+
+ events.qlen = 0;
+}
+
+/**
+ * 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 free_events()
+{
+ for (int i = 0; i < events.qlen; ++i) {
+ free(events.queue[i]);
+ }
+
+ events.qlen = 0;
+}
diff --git a/src/events.h b/src/events.h
new file mode 100644
index 0000000..565de6b
--- /dev/null
+++ b/src/events.h
@@ -0,0 +1,15 @@
+/* Copyright (C) 2016-2019 Michael Mackus */
+#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 process_events();
+bool is_processing_events();
+void free_events();
+
+#endif /* end of include guard: _MAP_H */
diff --git a/src/map.c b/src/map.c
index b854207..bb35808 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1,7 +1,7 @@
/**
* vimb - a webkit based vim like browser.
*
- * Copyright (C) 2012-2018 Daniel Carl
+ * Copyright (C) 2012-2019 Daniel Carl
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "ascii.h"
#include "config.h"
+#include "events.h"
#include "main.h"
#include "map.h"
#include "util.h"
@@ -324,6 +325,11 @@ gboolean map_delete(Client *c, const char *in, char mode)
*/
gboolean on_map_keypress(GtkWidget *widget, GdkEventKey* event, Client *c)
{
+ if (is_processing_events()) {
+ /* events are processing, pass all keys unmodified */
+ return false;
+ }
+
guint state = event->state;
guint keyval = event->keyval;
guchar string[32];
@@ -362,12 +368,25 @@ gboolean on_map_keypress(GtkWidget *widget, GdkEventKey* event, Client *c)
c->state.typed = TRUE;
c->state.processed_key = TRUE;
- map_handle_keys(c, string, len, TRUE);
+ queue_event(event);
+
+ MapState res = map_handle_keys(c, string, len, true);
+
+ if (res != MAP_AMBIGUOUS) {
+ if (!c->state.processed_key) {
+ /* events ready to be consumed */
+ process_events();
+ } else {
+ /* no ambiguous - key processed elsewhere */
+ free_events();
+ }
+ }
/* reset the typed flag */
c->state.typed = FALSE;
- return c->state.processed_key;
+ /* prevent input from going to GDK - input is sent via process_events(); */
+ return TRUE;
}
/**
@@ -476,6 +495,9 @@ static gboolean do_timeout(Client *c)
/* signalize the timeout to the key handler */
map_handle_keys(c, (guchar*)"", 0, TRUE);
+ /* 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
* map_handle_keys where we don't know if the timeout was called or not */