From 0302dc7b630f5a043a8a1f7808f8a72f137e594d Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Sun, 9 Jul 2017 19:57:35 -0400 Subject: [PATCH] switched to using poll() for event handling. Uniform interface for pty and x11 handling. Should extend to generic command execution handling as well --- Makefile | 3 ++- inc/edit.h | 9 ++++++++ inc/x11.h | 1 + lib/event.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/win.c | 18 +++++++++------- lib/x11.c | 4 ++++ tide.c | 40 ++++++++++++++++------------------ 7 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 lib/event.c diff --git a/Makefile b/Makefile index e8bc34c..dc65aab 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,8 @@ LIBEDIT_OBJS = \ lib/x11.o \ lib/win.o \ lib/colors.o \ - lib/config.o + lib/config.o \ + lib/event.o TEST_BINS = \ tests/tide \ diff --git a/inc/edit.h b/inc/edit.h index 54e3860..c01c765 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -21,6 +21,15 @@ char* strconcat(char* dest, ...); bool file_exists(char* path); char* strmcat(char* first, ...); + +enum { INPUT, OUTPUT, NOTIFY }; + +typedef void (*event_cbfn_t)(int fd, void* data); + +bool event_poll(int ms); +void event_watchfd(int fd, int iodir, event_cbfn_t fn, void* data); + + /* Buffer management functions *****************************************************************************/ /* undo/redo list item */ diff --git a/inc/x11.h b/inc/x11.h index a78e000..fdda96b 100644 --- a/inc/x11.h +++ b/inc/x11.h @@ -115,6 +115,7 @@ enum { void x11_init(XConfig* cfg); void x11_deinit(void); +int x11_connfd(void); char* x11_cfg_get(char* opt); int x11_keybtnstate(void); bool x11_keymodsset(int mask); diff --git a/lib/event.c b/lib/event.c new file mode 100644 index 0000000..6c2bf3d --- /dev/null +++ b/lib/event.c @@ -0,0 +1,62 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include + +struct event_data { + int iodir; + void* data; + event_cbfn_t fn; +}; + +static size_t NumDescriptors = 0; +static struct pollfd* Descriptors = NULL; +static struct event_data* EventData = NULL; + +bool event_poll(int ms) { + /* poll for new events */ + long n = poll(Descriptors, NumDescriptors, ms); + if (n < 0) die("poll() :"); + + /* Handle any events that occurred */ + for (int i = 0; i < NumDescriptors; i++) { + /* skip any eventless entries */ + if (!Descriptors[i].revents) continue; + + /* if a requested event occurred, handle it */ + if (Descriptors[i].revents & Descriptors[i].events) { + EventData[i].fn(Descriptors[i].fd, EventData[i].data); + Descriptors[i].revents = 0; + } + + /* if the desriptor is done or errored, throw it out */ + if (Descriptors[i].revents & (POLLERR|POLLHUP)) { + close(Descriptors[i].fd); + for (int x = i+1; x < NumDescriptors; x++) { + Descriptors[x-1] = Descriptors[x]; + EventData[x-1] = EventData[x]; + } + NumDescriptors--; + } + } + + return (n > 0); +} + +void event_watchfd(int fd, int iodir, event_cbfn_t fn, void* data) { + int idx = NumDescriptors++; + Descriptors = realloc(Descriptors, NumDescriptors * sizeof(struct pollfd)); + EventData = realloc(EventData, NumDescriptors * sizeof(struct event_data)); + if (!Descriptors || !EventData) + die("event_Watchfd() : out of memory\n"); + Descriptors[idx].fd = fd; + EventData[idx].data = data; + EventData[idx].fn = fn; + switch (iodir) { + case INPUT: Descriptors[idx].events = POLLIN; break; + case OUTPUT: Descriptors[idx].events = POLLOUT; break; + case NOTIFY: Descriptors[idx].events = (POLLIN|POLLOUT); break; + } +} diff --git a/lib/win.c b/lib/win.c index 59a2df6..22a587a 100644 --- a/lib/win.c +++ b/lib/win.c @@ -60,18 +60,20 @@ void win_dialog(char* name, void (*errfn)(char*)) { x11_dialog(name, config_get_int(WinWidth), config_get_int(WinHeight)); } +static void win_update(int xfd, void* data) { + if (x11_events_queued()) + x11_events_take(); + x11_flush(); +} + void win_loop(void) { x11_show(); x11_flip(); + int ms = config_get_int(EventTimeout); + event_watchfd(x11_connfd(), INPUT, win_update, NULL); while (x11_running()) { - bool pending = x11_events_await(config_get_int(EventTimeout)); - int nevents = x11_events_queued(); - if (update_focus() || pending || nevents || update_needed()) { - x11_events_take(); - if (x11_running()) - x11_flip(); - } - x11_flush(); + if (event_poll(ms) || update_focus() || x11_running()) + x11_flip(); } x11_finish(); } diff --git a/lib/x11.c b/lib/x11.c index 3e091c2..3df97cb 100644 --- a/lib/x11.c +++ b/lib/x11.c @@ -103,6 +103,10 @@ void x11_init(XConfig* cfg) { config_init(X.display); } +int x11_connfd(void) { + return ConnectionNumber(X.display); +} + int x11_keybtnstate(void) { return KeyBtnState; } diff --git a/tide.c b/tide.c index d7430e0..f794f90 100644 --- a/tide.c +++ b/tide.c @@ -8,8 +8,6 @@ #include #include #include -//#include -//#include #ifdef __MACH__ #include #else @@ -539,20 +537,6 @@ void onupdate(void) { strncat(status, path, remlen); win_settext(STATUS, status_bytes); win_view(STATUS)->selection = (Sel){0,0,0}; - - /* Read from command if we have one */ - long n = 0, r = 0, i = 0; - static char cmdbuf[8192]; - if (!update_needed()) return; - if ((n = read(CmdFD, cmdbuf, sizeof(cmdbuf))) < 0) - CmdFD = -1; - while (i < n) { - Rune rune = 0; - size_t length = 0; - while (!utf8decode(&rune, &length, cmdbuf[i++])); - view_insert(win_view(EDIT), false, rune); - } - win_buf(EDIT)->outpoint = win_view(EDIT)->selection.end; } void onlayout(void) { @@ -573,12 +557,7 @@ void onshutdown(void) { } bool update_needed(void) { - if (CmdFD < 0) return false; - fd_set fds; - FD_ZERO(&fds); - FD_SET(CmdFD, &fds); - struct timeval tv = { .tv_usec = 0 }; - return (select(CmdFD+1, &fds, NULL, NULL, &tv) > 0); + return false; } static void oninput(Rune rune) { @@ -623,6 +602,21 @@ int pty_spawn(char** argv) { return fd; } +void pty_update(int fd, void* data) { + /* Read from command if we have one */ + long n = 0, r = 0, i = 0; + static char cmdbuf[8192]; + if ((n = read(CmdFD, cmdbuf, sizeof(cmdbuf))) < 0) + CmdFD = -1; + while (i < n) { + Rune rune = 0; + size_t length = 0; + while (!utf8decode(&rune, &length, cmdbuf[i++])); + view_insert(win_view(EDIT), false, rune); + } + win_buf(EDIT)->outpoint = win_view(EDIT)->selection.end; +} + void edit_relative(char* path) { char *currdir = NULL, *currpath = NULL, *relpath = NULL; char* origdir = getcurrdir(); @@ -679,6 +673,8 @@ void edit_command(char** cmd) { win_setlinenums(false); win_setruler(0); CmdFD = pty_spawn(*cmd ? cmd : shellcmd); + event_watchfd(CmdFD, INPUT, pty_update, NULL); + } #ifndef TEST -- 2.49.0