Rewrite to use libuv

Also instead of resize_term() we use resizeterm() because the former
seems to cause massive glitches.  Not flicker-free in urxvt anymore
though.
This commit is contained in:
Přemysl Eric Janouch 2014-10-24 22:59:24 +02:00
parent 4e1c52d798
commit ee5f1b4cf2
3 changed files with 100 additions and 66 deletions

View File

@ -43,7 +43,7 @@ include_directories (${dependencies_INCLUDE_DIRS} ${Termo_INCLUDE_DIRS})
# Configuration
include (CheckFunctionExists)
set (CMAKE_REQUIRED_LIBRARIES ${dependencies_LIBRARIES})
CHECK_FUNCTION_EXISTS ("resize_term" HAVE_RESIZE_TERM)
CHECK_FUNCTION_EXISTS ("resizeterm" HAVE_RESIZETERM)
# Project source files
set (project_sources ${PROJECT_NAME}.c)

View File

@ -17,8 +17,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// <poll.h> might need this for sigset_t
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <unistd.h>
@ -27,9 +25,9 @@
#include <stdbool.h>
#include <string.h>
#include <poll.h>
#include <signal.h>
#include <uv.h>
#include <curses.h>
#include "termo.h"
@ -45,6 +43,11 @@ struct app_context
{
termo_t *tk; ///< Termo instance
uv_tty_t tty; ///< TTY
uv_poll_t tty_watcher; ///< TTY input watcher
uv_timer_t tty_timer; ///< TTY timeout timer
uv_signal_t winch_watcher; ///< SIGWINCH watcher
chtype palette[2 * 9]; ///< Attribute palette
uint8_t *bitmap; ///< Canvas data for drawing
@ -74,7 +77,14 @@ app_init (app_context_t *self)
memset (self, 0, sizeof *self);
}
static int g_winch_pipe[2];
static void
app_free (app_context_t *self)
{
if (self->tk)
termo_destroy (self->tk);
free (self->bitmap);
}
static void
display (const char *format, ...)
@ -526,11 +536,74 @@ on_key (app_context_t *app, termo_key_t *key)
return true;
}
static void
winch_handler (int signum)
static bool
xstrtoul (unsigned long *out, const char *s, int base)
{
char *end;
errno = 0;
*out = strtoul (s, &end, base);
return errno == 0 && !*end && end != s;
}
static void
on_winch (uv_signal_t *handle, int signum)
{
app_context_t *app = handle->loop->data;
(void) signum;
write (g_winch_pipe[1], "x", 1);
#ifdef HAVE_RESIZETERM
int w, h;
if (!uv_tty_get_winsize (&app->tty, &w, &h))
{
char *row = getenv ("LINES");
char *col = getenv ("COLUMNS");
unsigned long tmp;
resizeterm (
(row && xstrtoul (&tmp, row, 10)) ? (int) tmp : h,
(col && xstrtoul (&tmp, col, 10)) ? (int) tmp : w);
}
#else // ! HAVE_RESIZETERM
endwin ();
refresh ();
#endif // ! HAVE_RESIZETERM
update_canvas_for_screen (app);
redraw (app);
redraw_canvas (app);
}
static void
on_key_timer (uv_timer_t *handle)
{
app_context_t *app = handle->loop->data;
termo_key_t key;
if (termo_getkey_force (app->tk, &key) == TERMO_RES_KEY)
if (!on_key (app, &key))
uv_stop (handle->loop);
}
static void
on_tty_readable (uv_poll_t *handle, int status, int events)
{
// Ignoring and hoping for the best
(void) status;
(void) events;
app_context_t *app = handle->loop->data;
uv_timer_stop (&app->tty_timer);
termo_advisereadable (app->tk);
termo_key_t key;
termo_result_t ret;
while ((ret = termo_getkey (app->tk, &key)) == TERMO_RES_KEY)
if (!on_key (app, &key))
uv_stop (handle->loop);
if (ret == TERMO_RES_AGAIN)
uv_timer_start (&app->tty_timer,
on_key_timer, termo_get_waittime (app->tk), 0);
}
int
@ -542,18 +615,6 @@ main (int argc, char *argv[])
TERMO_CHECK_VERSION;
setlocale (LC_CTYPE, "");
struct sigaction act;
act.sa_handler = winch_handler;
act.sa_flags = SA_RESTART;
sigemptyset (&act.sa_mask);
// Set up a self-pipe so that we can actually poll on SIGWINCH
if (sigaction (SIGWINCH, &act, NULL) || pipe (g_winch_pipe))
{
fprintf (stderr, "Cannot set up signal handler\n");
exit (EXIT_FAILURE);
}
termo_t *tk = termo_new (STDIN_FILENO, NULL, 0);
if (!tk)
{
@ -575,56 +636,29 @@ main (int argc, char *argv[])
app_init (&app);
app.tk = tk;
uv_loop_t *loop = uv_default_loop ();
loop->data = &app;
uv_signal_init (loop, &app.winch_watcher);
uv_signal_start (&app.winch_watcher, on_winch, SIGWINCH);
uv_tty_init (loop, &app.tty, STDOUT_FILENO, false);
uv_poll_init (loop, &app.tty_watcher, STDIN_FILENO);
uv_poll_start (&app.tty_watcher, UV_READABLE, on_tty_readable);
uv_timer_init (loop, &app.tty_timer);
init_palette (&app);
update_canvas_for_screen (&app);
redraw (&app);
redraw_canvas (&app);
termo_result_t ret;
termo_key_t key;
// We listen for mouse/key input and terminal resize events
struct pollfd fds[2] =
{
{ .fd = STDIN_FILENO, .events = POLLIN },
{ .fd = g_winch_pipe[0], .events = POLLIN },
};
// Run a simple event loop with poll()
int nextwait = -1;
bool running = true;
while (running)
{
if (!poll (fds, 2, nextwait))
if (termo_getkey_force (tk, &key) == TERMO_RES_KEY)
running &= on_key (&app, &key);
if (fds[1].revents & (POLLIN | POLLHUP | POLLERR))
{
char x;
read (fds[1].fd, &x, 1);
// The "official" simple and flicker-prone method of resizing
// the internal buffers of curses
endwin ();
refresh ();
update_canvas_for_screen (&app);
redraw (&app);
redraw_canvas (&app);
}
if (fds[0].revents & (POLLIN | POLLHUP | POLLERR))
termo_advisereadable (tk);
while ((ret = termo_getkey (tk, &key)) == TERMO_RES_KEY)
running &= on_key (&app, &key);
nextwait = -1;
if (ret == TERMO_RES_AGAIN)
nextwait = termo_get_waittime (tk);
}
uv_run (loop, UV_RUN_DEFAULT);
endwin ();
termo_destroy (tk);
uv_loop_close (loop);
app_free (&app);
return 0;
}

View File

@ -5,7 +5,7 @@
#define PROJECT_VERSION "${project_VERSION}"
#define PROJECT_URL "${project_URL}"
#cmakedefine HAVE_RESIZE_TERM
#cmakedefine HAVE_RESIZETERM
#endif // ! CONFIG_H