From: Thomas Legris Date: Thu, 14 Mar 2019 21:44:15 +0000 (+0000) Subject: Allow incomplete imap sequence to timeout X-Git-Url: https://git.owens.tech///git?a=commitdiff_plain;h=cd0e694f4cd709f2a3d7205199c5fcf91502d41b;p=vimb.git Allow incomplete imap sequence to timeout --- 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 +#include +#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 */