mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
tui: Refactor for running in another thread
This commit is contained in:
parent
9f9710aab4
commit
eb001a4abd
@ -15,42 +15,46 @@
|
|||||||
# include "tui/input.c.generated.h"
|
# include "tui/input.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TermInput *term_input_new(void)
|
void term_input_init(TermInput *input, Loop *loop)
|
||||||
{
|
{
|
||||||
TermInput *rv = xmalloc(sizeof(TermInput));
|
input->loop = loop;
|
||||||
rv->paste_enabled = false;
|
input->paste_enabled = false;
|
||||||
rv->in_fd = 0;
|
input->in_fd = 0;
|
||||||
|
|
||||||
const char *term = os_getenv("TERM");
|
const char *term = os_getenv("TERM");
|
||||||
if (!term) {
|
if (!term) {
|
||||||
term = ""; // termkey_new_abstract assumes non-null (#2745)
|
term = ""; // termkey_new_abstract assumes non-null (#2745)
|
||||||
}
|
}
|
||||||
rv->tk = termkey_new_abstract(term, 0);
|
input->tk = termkey_new_abstract(term, 0);
|
||||||
int curflags = termkey_get_canonflags(rv->tk);
|
int curflags = termkey_get_canonflags(input->tk);
|
||||||
termkey_set_canonflags(rv->tk, curflags | TERMKEY_CANON_DELBS);
|
termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS);
|
||||||
// setup input handle
|
// setup input handle
|
||||||
rstream_init_fd(&loop, &rv->read_stream, rv->in_fd, 0xfff, rv);
|
rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff, input);
|
||||||
rstream_start(&rv->read_stream, read_cb);
|
|
||||||
// initialize a timer handle for handling ESC with libtermkey
|
// initialize a timer handle for handling ESC with libtermkey
|
||||||
time_watcher_init(&loop, &rv->timer_handle, rv);
|
time_watcher_init(loop, &input->timer_handle, input);
|
||||||
// Set the pastetoggle option to a special key that will be sent when
|
// Set the pastetoggle option to a special key that will be sent when
|
||||||
// \e[20{0,1}~/ are received
|
// \e[20{0,1}~/ are received
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
vim_set_option(cstr_as_string("pastetoggle"),
|
vim_set_option(cstr_as_string("pastetoggle"),
|
||||||
STRING_OBJ(cstr_as_string(PASTETOGGLE_KEY)), &err);
|
STRING_OBJ(cstr_as_string(PASTETOGGLE_KEY)), &err);
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_input_destroy(TermInput *input)
|
void term_input_destroy(TermInput *input)
|
||||||
{
|
{
|
||||||
time_watcher_stop(&input->timer_handle);
|
|
||||||
time_watcher_close(&input->timer_handle, NULL);
|
time_watcher_close(&input->timer_handle, NULL);
|
||||||
rstream_stop(&input->read_stream);
|
|
||||||
stream_close(&input->read_stream, NULL);
|
stream_close(&input->read_stream, NULL);
|
||||||
termkey_destroy(input->tk);
|
termkey_destroy(input->tk);
|
||||||
// Run once to remove references to input/timer handles
|
}
|
||||||
loop_poll_events(&loop, 0);
|
|
||||||
xfree(input);
|
void term_input_start(TermInput *input)
|
||||||
|
{
|
||||||
|
rstream_start(&input->read_stream, read_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_input_stop(TermInput *input)
|
||||||
|
{
|
||||||
|
rstream_stop(&input->read_stream);
|
||||||
|
time_watcher_stop(&input->timer_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_input_set_encoding(TermInput *input, char* enc)
|
void term_input_set_encoding(TermInput *input, char* enc)
|
||||||
@ -60,6 +64,24 @@ void term_input_set_encoding(TermInput *input, char* enc)
|
|||||||
termkey_set_flags(input->tk, enc_flag);
|
termkey_set_flags(input->tk, enc_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void input_enqueue_event(void **argv)
|
||||||
|
{
|
||||||
|
char *buf = argv[0];
|
||||||
|
input_enqueue(cstr_as_string(buf));
|
||||||
|
xfree(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_done_event(void **argv)
|
||||||
|
{
|
||||||
|
input_done();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enqueue_input(char *buf, size_t size)
|
||||||
|
{
|
||||||
|
loop_schedule(&loop, event_create(1, input_enqueue_event, 1,
|
||||||
|
xstrndup(buf, size)));
|
||||||
|
}
|
||||||
|
|
||||||
static void forward_simple_utf8(TermKeyKey *key)
|
static void forward_simple_utf8(TermKeyKey *key)
|
||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
@ -76,7 +98,7 @@ static void forward_simple_utf8(TermKeyKey *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
input_enqueue((String){.data = buf, .size = len});
|
enqueue_input(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void forward_modified_utf8(TermKey *tk, TermKeyKey *key)
|
static void forward_modified_utf8(TermKey *tk, TermKeyKey *key)
|
||||||
@ -91,7 +113,7 @@ static void forward_modified_utf8(TermKey *tk, TermKeyKey *key)
|
|||||||
len = termkey_strfkey(tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
|
len = termkey_strfkey(tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_enqueue((String){.data = buf, .size = len});
|
enqueue_input(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void forward_mouse_event(TermKey *tk, TermKeyKey *key)
|
static void forward_mouse_event(TermKey *tk, TermKeyKey *key)
|
||||||
@ -142,7 +164,7 @@ static void forward_mouse_event(TermKey *tk, TermKeyKey *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
|
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
|
||||||
input_enqueue((String){.data = buf, .size = len});
|
enqueue_input(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force)
|
static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force)
|
||||||
@ -218,16 +240,16 @@ static bool handle_bracketed_paste(TermInput *input)
|
|||||||
int state = get_real_state();
|
int state = get_real_state();
|
||||||
if (state & NORMAL) {
|
if (state & NORMAL) {
|
||||||
// Enter insert mode
|
// Enter insert mode
|
||||||
input_enqueue(cstr_as_string("i"));
|
enqueue_input("i", 1);
|
||||||
} else if (state & VISUAL) {
|
} else if (state & VISUAL) {
|
||||||
// Remove the selected text and enter insert mode
|
// Remove the selected text and enter insert mode
|
||||||
input_enqueue(cstr_as_string("c"));
|
enqueue_input("c", 1);
|
||||||
} else if (!(state & INSERT)) {
|
} else if (!(state & INSERT)) {
|
||||||
// Don't mess with the paste option
|
// Don't mess with the paste option
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input_enqueue(cstr_as_string(PASTETOGGLE_KEY));
|
enqueue_input(PASTETOGGLE_KEY, sizeof(PASTETOGGLE_KEY) - 1);
|
||||||
input->paste_enabled = enable;
|
input->paste_enabled = enable;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -270,9 +292,9 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
|
|||||||
// ls *.md | xargs nvim
|
// ls *.md | xargs nvim
|
||||||
input->in_fd = 2;
|
input->in_fd = 2;
|
||||||
stream_close(&input->read_stream, NULL);
|
stream_close(&input->read_stream, NULL);
|
||||||
queue_put(loop.fast_events, restart_reading, 1, input);
|
queue_put(input->loop->fast_events, restart_reading, 1, input);
|
||||||
} else {
|
} else {
|
||||||
input_done();
|
loop_schedule(&loop, event_create(1, input_done_event, 0));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -318,6 +340,6 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
|
|||||||
static void restart_reading(void **argv)
|
static void restart_reading(void **argv)
|
||||||
{
|
{
|
||||||
TermInput *input = argv[0];
|
TermInput *input = argv[0];
|
||||||
rstream_init_fd(&loop, &input->read_stream, input->in_fd, 0xfff, input);
|
rstream_init_fd(input->loop, &input->read_stream, input->in_fd, 0xfff, input);
|
||||||
rstream_start(&input->read_stream, read_cb);
|
rstream_start(&input->read_stream, read_cb);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ typedef struct term_input {
|
|||||||
bool paste_enabled;
|
bool paste_enabled;
|
||||||
TermKey *tk;
|
TermKey *tk;
|
||||||
TimeWatcher timer_handle;
|
TimeWatcher timer_handle;
|
||||||
|
Loop *loop;
|
||||||
Stream read_stream;
|
Stream read_stream;
|
||||||
} TermInput;
|
} TermInput;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
#include "nvim/ugrid.h"
|
#include "nvim/ugrid.h"
|
||||||
|
#include "nvim/ui_bridge.h"
|
||||||
|
|
||||||
// Space reserved in the output buffer to restore the cursor to normal when
|
// Space reserved in the output buffer to restore the cursor to normal when
|
||||||
// flushing. No existing terminal will require 32 bytes to do that.
|
// flushing. No existing terminal will require 32 bytes to do that.
|
||||||
@ -33,14 +34,21 @@ typedef struct {
|
|||||||
} Rect;
|
} Rect;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
UIBridgeData *bridge;
|
||||||
|
Loop *loop;
|
||||||
|
bool stop;
|
||||||
unibi_var_t params[9];
|
unibi_var_t params[9];
|
||||||
char buf[OUTBUF_SIZE];
|
char buf[OUTBUF_SIZE];
|
||||||
size_t bufpos, bufsize;
|
size_t bufpos, bufsize;
|
||||||
TermInput *input;
|
TermInput input;
|
||||||
uv_loop_t *write_loop;
|
uv_loop_t write_loop;
|
||||||
unibi_term *ut;
|
unibi_term *ut;
|
||||||
uv_tty_t output_handle;
|
uv_tty_t output_handle;
|
||||||
SignalWatcher winch_handle;
|
SignalWatcher winch_handle, cont_handle;
|
||||||
|
bool cont_received;
|
||||||
|
// Event scheduled by the ui bridge. Since the main thread suspends until
|
||||||
|
// the event is handled, it is fine to use a single field instead of a queue
|
||||||
|
Event scheduled_event;
|
||||||
UGrid grid;
|
UGrid grid;
|
||||||
kvec_t(Rect) invalid_regions;
|
kvec_t(Rect) invalid_regions;
|
||||||
int out_fd;
|
int out_fd;
|
||||||
@ -66,59 +74,9 @@ static bool volatile got_winch = false;
|
|||||||
|
|
||||||
UI *tui_start(void)
|
UI *tui_start(void)
|
||||||
{
|
{
|
||||||
TUIData *data = xcalloc(1, sizeof(TUIData));
|
|
||||||
UI *ui = xcalloc(1, sizeof(UI));
|
UI *ui = xcalloc(1, sizeof(UI));
|
||||||
ui->data = data;
|
|
||||||
data->print_attrs = EMPTY_ATTRS;
|
|
||||||
ugrid_init(&data->grid);
|
|
||||||
data->can_use_terminal_scroll = true;
|
|
||||||
data->bufpos = 0;
|
|
||||||
data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE;
|
|
||||||
data->showing_mode = 0;
|
|
||||||
data->unibi_ext.enable_mouse = -1;
|
|
||||||
data->unibi_ext.disable_mouse = -1;
|
|
||||||
data->unibi_ext.enable_bracketed_paste = -1;
|
|
||||||
data->unibi_ext.disable_bracketed_paste = -1;
|
|
||||||
data->unibi_ext.enter_insert_mode = -1;
|
|
||||||
data->unibi_ext.enter_replace_mode = -1;
|
|
||||||
data->unibi_ext.exit_insert_mode = -1;
|
|
||||||
|
|
||||||
// write output to stderr if stdout is not a tty
|
|
||||||
data->out_fd = os_isatty(1) ? 1 : (os_isatty(2) ? 2 : 1);
|
|
||||||
kv_init(data->invalid_regions);
|
|
||||||
// setup term input
|
|
||||||
data->input = term_input_new();
|
|
||||||
// setup unibilium
|
|
||||||
data->ut = unibi_from_env();
|
|
||||||
if (!data->ut) {
|
|
||||||
// For some reason could not read terminfo file, use a dummy entry that
|
|
||||||
// will be populated with common values by fix_terminfo below
|
|
||||||
data->ut = unibi_dummy();
|
|
||||||
}
|
|
||||||
fix_terminfo(data);
|
|
||||||
// Enter alternate screen and clear
|
|
||||||
unibi_out(ui, unibi_enter_ca_mode);
|
|
||||||
unibi_out(ui, unibi_clear_screen);
|
|
||||||
// Enable bracketed paste
|
|
||||||
unibi_out(ui, data->unibi_ext.enable_bracketed_paste);
|
|
||||||
// setup output handle in a separate event loop(we wanna do synchronous
|
|
||||||
// write to the tty)
|
|
||||||
data->write_loop = xmalloc(sizeof(uv_loop_t));
|
|
||||||
uv_loop_init(data->write_loop);
|
|
||||||
uv_tty_init(data->write_loop, &data->output_handle, data->out_fd, 0);
|
|
||||||
uv_tty_set_mode(&data->output_handle, UV_TTY_MODE_RAW);
|
|
||||||
|
|
||||||
// Obtain screen dimensions
|
|
||||||
update_size(ui);
|
|
||||||
|
|
||||||
// listen for SIGWINCH
|
|
||||||
signal_watcher_init(&loop, &data->winch_handle, ui);
|
|
||||||
data->winch_handle.events = queue_new_child(loop.events);
|
|
||||||
signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
|
|
||||||
|
|
||||||
ui->stop = tui_stop;
|
ui->stop = tui_stop;
|
||||||
ui->rgb = os_getenv("NVIM_TUI_ENABLE_TRUE_COLOR") != NULL;
|
ui->rgb = os_getenv("NVIM_TUI_ENABLE_TRUE_COLOR") != NULL;
|
||||||
ui->data = data;
|
|
||||||
ui->resize = tui_resize;
|
ui->resize = tui_resize;
|
||||||
ui->clear = tui_clear;
|
ui->clear = tui_clear;
|
||||||
ui->eol_clear = tui_eol_clear;
|
ui->eol_clear = tui_eol_clear;
|
||||||
@ -142,21 +100,46 @@ UI *tui_start(void)
|
|||||||
ui->set_title = tui_set_title;
|
ui->set_title = tui_set_title;
|
||||||
ui->set_icon = tui_set_icon;
|
ui->set_icon = tui_set_icon;
|
||||||
ui->set_encoding = tui_set_encoding;
|
ui->set_encoding = tui_set_encoding;
|
||||||
// Attach
|
return ui_bridge_attach(ui, tui_main, tui_scheduler);
|
||||||
ui_attach(ui);
|
|
||||||
return ui;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tui_stop(UI *ui)
|
static void terminfo_start(UI *ui)
|
||||||
|
{
|
||||||
|
TUIData *data = ui->data;
|
||||||
|
data->can_use_terminal_scroll = true;
|
||||||
|
data->bufpos = 0;
|
||||||
|
data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE;
|
||||||
|
data->showing_mode = 0;
|
||||||
|
data->unibi_ext.enable_mouse = -1;
|
||||||
|
data->unibi_ext.disable_mouse = -1;
|
||||||
|
data->unibi_ext.enable_bracketed_paste = -1;
|
||||||
|
data->unibi_ext.disable_bracketed_paste = -1;
|
||||||
|
data->unibi_ext.enter_insert_mode = -1;
|
||||||
|
data->unibi_ext.enter_replace_mode = -1;
|
||||||
|
data->unibi_ext.exit_insert_mode = -1;
|
||||||
|
// write output to stderr if stdout is not a tty
|
||||||
|
data->out_fd = os_isatty(1) ? 1 : (os_isatty(2) ? 2 : 1);
|
||||||
|
// setup unibilium
|
||||||
|
data->ut = unibi_from_env();
|
||||||
|
if (!data->ut) {
|
||||||
|
// For some reason could not read terminfo file, use a dummy entry that
|
||||||
|
// will be populated with common values by fix_terminfo below
|
||||||
|
data->ut = unibi_dummy();
|
||||||
|
}
|
||||||
|
fix_terminfo(data);
|
||||||
|
// Enter alternate screen and clear
|
||||||
|
unibi_out(ui, unibi_enter_ca_mode);
|
||||||
|
unibi_out(ui, unibi_clear_screen);
|
||||||
|
// Enable bracketed paste
|
||||||
|
unibi_out(ui, data->unibi_ext.enable_bracketed_paste);
|
||||||
|
uv_loop_init(&data->write_loop);
|
||||||
|
uv_tty_init(&data->write_loop, &data->output_handle, data->out_fd, 0);
|
||||||
|
uv_tty_set_mode(&data->output_handle, UV_TTY_MODE_RAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void terminfo_stop(UI *ui)
|
||||||
{
|
{
|
||||||
TUIData *data = ui->data;
|
TUIData *data = ui->data;
|
||||||
// Destroy common stuff
|
|
||||||
kv_destroy(data->invalid_regions);
|
|
||||||
signal_watcher_stop(&data->winch_handle);
|
|
||||||
queue_free(data->winch_handle.events);
|
|
||||||
signal_watcher_close(&data->winch_handle, NULL);
|
|
||||||
// Destroy input stuff
|
|
||||||
term_input_destroy(data->input);
|
|
||||||
// Destroy output stuff
|
// Destroy output stuff
|
||||||
tui_mode_change(ui, NORMAL);
|
tui_mode_change(ui, NORMAL);
|
||||||
tui_mouse_off(ui);
|
tui_mouse_off(ui);
|
||||||
@ -169,24 +152,99 @@ static void tui_stop(UI *ui)
|
|||||||
flush_buf(ui);
|
flush_buf(ui);
|
||||||
uv_tty_reset_mode();
|
uv_tty_reset_mode();
|
||||||
uv_close((uv_handle_t *)&data->output_handle, NULL);
|
uv_close((uv_handle_t *)&data->output_handle, NULL);
|
||||||
uv_run(data->write_loop, UV_RUN_DEFAULT);
|
uv_run(&data->write_loop, UV_RUN_DEFAULT);
|
||||||
if (uv_loop_close(data->write_loop)) {
|
if (uv_loop_close(&data->write_loop)) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
xfree(data->write_loop);
|
|
||||||
unibi_destroy(data->ut);
|
unibi_destroy(data->ut);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tui_terminal_start(UI *ui)
|
||||||
|
{
|
||||||
|
TUIData *data = ui->data;
|
||||||
|
data->print_attrs = EMPTY_ATTRS;
|
||||||
|
ugrid_init(&data->grid);
|
||||||
|
terminfo_start(ui);
|
||||||
|
update_size(ui);
|
||||||
|
signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
|
||||||
|
term_input_start(&data->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tui_terminal_stop(UI *ui)
|
||||||
|
{
|
||||||
|
TUIData *data = ui->data;
|
||||||
|
term_input_stop(&data->input);
|
||||||
|
signal_watcher_stop(&data->winch_handle);
|
||||||
|
terminfo_stop(ui);
|
||||||
ugrid_free(&data->grid);
|
ugrid_free(&data->grid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tui_stop(UI *ui)
|
||||||
|
{
|
||||||
|
tui_terminal_stop(ui);
|
||||||
|
TUIData *data = ui->data;
|
||||||
|
data->stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function of the TUI thread
|
||||||
|
static void tui_main(UIBridgeData *bridge, UI *ui)
|
||||||
|
{
|
||||||
|
Loop tui_loop;
|
||||||
|
loop_init(&tui_loop, NULL);
|
||||||
|
TUIData *data = xcalloc(1, sizeof(TUIData));
|
||||||
|
ui->data = data;
|
||||||
|
data->bridge = bridge;
|
||||||
|
data->loop = &tui_loop;
|
||||||
|
kv_init(data->invalid_regions);
|
||||||
|
signal_watcher_init(data->loop, &data->winch_handle, ui);
|
||||||
|
signal_watcher_init(data->loop, &data->cont_handle, data);
|
||||||
|
signal_watcher_start(&data->cont_handle, sigcont_cb, SIGCONT);
|
||||||
|
// initialize input reading structures
|
||||||
|
term_input_init(&data->input, &tui_loop);
|
||||||
|
tui_terminal_start(ui);
|
||||||
|
data->stop = false;
|
||||||
|
// allow the main thread to continue, we are ready to start handling UI
|
||||||
|
// callbacks
|
||||||
|
CONTINUE(bridge);
|
||||||
|
|
||||||
|
while (!data->stop) {
|
||||||
|
loop_poll_events(&tui_loop, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
term_input_destroy(&data->input);
|
||||||
|
signal_watcher_stop(&data->cont_handle);
|
||||||
|
signal_watcher_close(&data->cont_handle, NULL);
|
||||||
|
signal_watcher_close(&data->winch_handle, NULL);
|
||||||
|
loop_close(&tui_loop);
|
||||||
|
kv_destroy(data->invalid_regions);
|
||||||
xfree(data);
|
xfree(data);
|
||||||
ui_detach(ui);
|
|
||||||
xfree(ui);
|
xfree(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tui_scheduler(Event event, void *d)
|
||||||
|
{
|
||||||
|
UI *ui = d;
|
||||||
|
TUIData *data = ui->data;
|
||||||
|
loop_schedule(data->loop, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refresh_event(void **argv)
|
||||||
|
{
|
||||||
|
ui_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sigcont_cb(SignalWatcher *watcher, int signum, void *data)
|
||||||
|
{
|
||||||
|
((TUIData *)data)->cont_received = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
|
static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
|
||||||
{
|
{
|
||||||
got_winch = true;
|
got_winch = true;
|
||||||
UI *ui = data;
|
UI *ui = data;
|
||||||
update_size(ui);
|
update_size(ui);
|
||||||
ui_refresh();
|
// run refresh_event in nvim main loop
|
||||||
|
loop_schedule(&loop, event_create(1, refresh_event, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool attrs_differ(HlAttrs a1, HlAttrs a2)
|
static bool attrs_differ(HlAttrs a1, HlAttrs a2)
|
||||||
@ -521,16 +579,34 @@ static void tui_flush(UI *ui)
|
|||||||
flush_buf(ui);
|
flush_buf(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tui_suspend(UI *ui)
|
static void suspend_event(void **argv)
|
||||||
{
|
{
|
||||||
|
UI *ui = argv[0];
|
||||||
TUIData *data = ui->data;
|
TUIData *data = ui->data;
|
||||||
bool enable_mouse = data->mouse_enabled;
|
bool enable_mouse = data->mouse_enabled;
|
||||||
tui_stop(ui);
|
tui_terminal_stop(ui);
|
||||||
|
data->cont_received = false;
|
||||||
kill(0, SIGTSTP);
|
kill(0, SIGTSTP);
|
||||||
ui = tui_start();
|
while (!data->cont_received) {
|
||||||
|
// poll the event loop until SIGCONT is received
|
||||||
|
loop_poll_events(data->loop, -1);
|
||||||
|
}
|
||||||
|
tui_terminal_start(ui);
|
||||||
if (enable_mouse) {
|
if (enable_mouse) {
|
||||||
tui_mouse_on(ui);
|
tui_mouse_on(ui);
|
||||||
}
|
}
|
||||||
|
// resume the main thread
|
||||||
|
CONTINUE(data->bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tui_suspend(UI *ui)
|
||||||
|
{
|
||||||
|
TUIData *data = ui->data;
|
||||||
|
// kill(0, SIGTSTP) won't stop the UI thread, so we must poll for SIGCONT
|
||||||
|
// before continuing. This is done in another callback to avoid
|
||||||
|
// loop_poll_events recursion
|
||||||
|
queue_put_event(data->loop->fast_events,
|
||||||
|
event_create(1, suspend_event, 1, ui));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tui_set_title(UI *ui, char *title)
|
static void tui_set_title(UI *ui, char *title)
|
||||||
@ -552,7 +628,7 @@ static void tui_set_icon(UI *ui, char *icon)
|
|||||||
static void tui_set_encoding(UI *ui, char* enc)
|
static void tui_set_encoding(UI *ui, char* enc)
|
||||||
{
|
{
|
||||||
TUIData *data = ui->data;
|
TUIData *data = ui->data;
|
||||||
term_input_set_encoding(data->input, enc);
|
term_input_set_encoding(&data->input, enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invalidate(UI *ui, int top, int bot, int left, int right)
|
static void invalidate(UI *ui, int top, int bot, int left, int right)
|
||||||
@ -633,8 +709,8 @@ end:
|
|||||||
height = DFLT_ROWS;
|
height = DFLT_ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->width = width;
|
data->bridge->bridge.width = ui->width = width;
|
||||||
ui->height = height;
|
data->bridge->bridge.height = ui->height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unibi_goto(UI *ui, int row, int col)
|
static void unibi_goto(UI *ui, int row, int col)
|
||||||
@ -817,7 +893,7 @@ static void flush_buf(UI *ui)
|
|||||||
buf.base = data->buf;
|
buf.base = data->buf;
|
||||||
buf.len = data->bufpos;
|
buf.len = data->bufpos;
|
||||||
uv_write(&req, (uv_stream_t *)&data->output_handle, &buf, 1, NULL);
|
uv_write(&req, (uv_stream_t *)&data->output_handle, &buf, 1, NULL);
|
||||||
uv_run(data->write_loop, UV_RUN_DEFAULT);
|
uv_run(&data->write_loop, UV_RUN_DEFAULT);
|
||||||
data->bufpos = 0;
|
data->bufpos = 0;
|
||||||
|
|
||||||
if (!data->busy) {
|
if (!data->busy) {
|
||||||
|
Loading…
Reference in New Issue
Block a user