mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-11 05:33:55 -04:00
Merge branch 'synchronized-updates'
This commit is contained in:
commit
21646f0059
4 changed files with 124 additions and 29 deletions
14
dcs.c
14
dcs.c
|
|
@ -8,17 +8,19 @@
|
||||||
static void
|
static void
|
||||||
bsu(struct terminal *term)
|
bsu(struct terminal *term)
|
||||||
{
|
{
|
||||||
LOG_WARN("unimplemented: BSU - Begin Synchronized Update (params: %.*s)",
|
LOG_DBG("BSU - Begin Synchronized Update (params: %.*s)",
|
||||||
(int)term->vt.dcs.idx, term->vt.dcs.data);
|
(int)term->vt.dcs.idx, term->vt.dcs.data);
|
||||||
abort();
|
|
||||||
|
term_enable_application_synchronized_updates(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
esu(struct terminal *term)
|
esu(struct terminal *term)
|
||||||
{
|
{
|
||||||
LOG_WARN("unimplemented: ESU - Begin Synchronized Update (params: %.*s)",
|
LOG_DBG("ESU - Begin Synchronized Update (params: %.*s)",
|
||||||
(int)term->vt.dcs.idx, term->vt.dcs.data);
|
(int)term->vt.dcs.idx, term->vt.dcs.data);
|
||||||
abort();
|
|
||||||
|
term_disable_application_synchronized_updates(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
6
render.c
6
render.c
|
|
@ -1015,6 +1015,9 @@ render_resize(struct terminal *term, int width, int height)
|
||||||
if (width == term->width && height == term->height && scale == term->scale)
|
if (width == term->width && height == term->height && scale == term->scale)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Cancel an application initiated "Synchronized Update" */
|
||||||
|
term_disable_application_synchronized_updates(term);
|
||||||
|
|
||||||
term->width = width;
|
term->width = width;
|
||||||
term->height = height;
|
term->height = height;
|
||||||
term->scale = scale;
|
term->scale = scale;
|
||||||
|
|
@ -1190,6 +1193,9 @@ fdm_hook_refresh_pending_terminals(struct fdm *fdm, void *data)
|
||||||
if (!term->render.refresh_needed)
|
if (!term->render.refresh_needed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (term->render.application_synchronized_updates.enabled)
|
||||||
|
continue;
|
||||||
|
|
||||||
assert(term->window->is_configured);
|
assert(term->window->is_configured);
|
||||||
term->render.refresh_needed = false;
|
term->render.refresh_needed = false;
|
||||||
|
|
||||||
|
|
|
||||||
125
terminal.c
125
terminal.c
|
|
@ -186,36 +186,41 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
|
||||||
* has any effect when the renderer is idle.
|
* has any effect when the renderer is idle.
|
||||||
*/
|
*/
|
||||||
if (term->window->frame_callback == NULL) {
|
if (term->window->frame_callback == NULL) {
|
||||||
/* First timeout - reset each time we receive input. */
|
if (term->render.application_synchronized_updates.enabled)
|
||||||
|
term->render.refresh_needed = true;
|
||||||
|
|
||||||
|
else {
|
||||||
|
/* First timeout - reset each time we receive input. */
|
||||||
|
|
||||||
#if PTMX_TIMING
|
#if PTMX_TIMING
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
clock_gettime(1, &now);
|
clock_gettime(1, &now);
|
||||||
if (last.tv_sec > 0 || last.tv_nsec > 0) {
|
if (last.tv_sec > 0 || last.tv_nsec > 0) {
|
||||||
struct timeval diff;
|
struct timeval diff;
|
||||||
struct timeval l = {last.tv_sec, last.tv_nsec / 1000};
|
struct timeval l = {last.tv_sec, last.tv_nsec / 1000};
|
||||||
struct timeval n = {now.tv_sec, now.tv_nsec / 1000};
|
struct timeval n = {now.tv_sec, now.tv_nsec / 1000};
|
||||||
|
|
||||||
timersub(&n, &l, &diff);
|
timersub(&n, &l, &diff);
|
||||||
LOG_INFO("waited %lu µs for more input", diff.tv_usec);
|
LOG_INFO("waited %lu µs for more input", diff.tv_usec);
|
||||||
}
|
}
|
||||||
last = now;
|
last = now;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
timerfd_settime(
|
|
||||||
term->delayed_render_timer.lower_fd, 0,
|
|
||||||
&(struct itimerspec){.it_value = {.tv_nsec = 500000}},
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* Second timeout - only reset when we render. Set to one
|
|
||||||
* frame (assuming 60Hz) */
|
|
||||||
if (!term->delayed_render_timer.is_armed) {
|
|
||||||
timerfd_settime(
|
timerfd_settime(
|
||||||
term->delayed_render_timer.upper_fd, 0,
|
term->delayed_render_timer.lower_fd, 0,
|
||||||
&(struct itimerspec){.it_value = {.tv_nsec = 16666666 / 2}},
|
&(struct itimerspec){.it_value = {.tv_nsec = 500000}},
|
||||||
NULL);
|
NULL);
|
||||||
term->delayed_render_timer.is_armed = true;
|
|
||||||
|
/* Second timeout - only reset when we render. Set to one
|
||||||
|
* frame (assuming 60Hz) */
|
||||||
|
if (!term->delayed_render_timer.is_armed) {
|
||||||
|
timerfd_settime(
|
||||||
|
term->delayed_render_timer.upper_fd, 0,
|
||||||
|
&(struct itimerspec){.it_value = {.tv_nsec = 16666666 / 2}},
|
||||||
|
NULL);
|
||||||
|
term->delayed_render_timer.is_armed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
term->render.pending = true;
|
term->render.pending = true;
|
||||||
|
|
@ -412,6 +417,29 @@ fdm_delayed_render(struct fdm *fdm, int fd, int events, void *data)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
fdm_application_synchronized_updates_timeout(
|
||||||
|
struct fdm *fdm, int fd, int events, void *data)
|
||||||
|
{
|
||||||
|
if (events & EPOLLHUP)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct terminal *term = data;
|
||||||
|
uint64_t unused;
|
||||||
|
ssize_t ret = read(term->render.application_synchronized_updates.timer_fd,
|
||||||
|
&unused, sizeof(unused));
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return true;
|
||||||
|
LOG_ERRNO("failed to read application synchronized updates timeout timer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
term_disable_application_synchronized_updates(term);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
initialize_color_cube(struct terminal *term)
|
initialize_color_cube(struct terminal *term)
|
||||||
{
|
{
|
||||||
|
|
@ -506,6 +534,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
|
||||||
int cursor_blink_fd = -1;
|
int cursor_blink_fd = -1;
|
||||||
int delay_lower_fd = -1;
|
int delay_lower_fd = -1;
|
||||||
int delay_upper_fd = -1;
|
int delay_upper_fd = -1;
|
||||||
|
int application_synchronized_updates_fd = -1;
|
||||||
|
|
||||||
struct terminal *term = malloc(sizeof(*term));
|
struct terminal *term = malloc(sizeof(*term));
|
||||||
|
|
||||||
|
|
@ -532,6 +561,12 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
|
||||||
goto close_fds;
|
goto close_fds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((application_synchronized_updates_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)) == -1)
|
||||||
|
{
|
||||||
|
LOG_ERRNO("failed to create application synchronized updates timer FD");
|
||||||
|
goto close_fds;
|
||||||
|
}
|
||||||
|
|
||||||
int ptmx_flags;
|
int ptmx_flags;
|
||||||
if ((ptmx_flags = fcntl(ptmx, F_GETFL)) < 0 ||
|
if ((ptmx_flags = fcntl(ptmx, F_GETFL)) < 0 ||
|
||||||
fcntl(ptmx, F_SETFL, ptmx_flags | O_NONBLOCK) < 0)
|
fcntl(ptmx, F_SETFL, ptmx_flags | O_NONBLOCK) < 0)
|
||||||
|
|
@ -545,7 +580,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
|
||||||
!fdm_add(fdm, blink_fd, EPOLLIN, &fdm_blink, term) ||
|
!fdm_add(fdm, blink_fd, EPOLLIN, &fdm_blink, term) ||
|
||||||
!fdm_add(fdm, cursor_blink_fd, EPOLLIN, &fdm_cursor_blink, term) ||
|
!fdm_add(fdm, cursor_blink_fd, EPOLLIN, &fdm_cursor_blink, term) ||
|
||||||
!fdm_add(fdm, delay_lower_fd, EPOLLIN, &fdm_delayed_render, term) ||
|
!fdm_add(fdm, delay_lower_fd, EPOLLIN, &fdm_delayed_render, term) ||
|
||||||
!fdm_add(fdm, delay_upper_fd, EPOLLIN, &fdm_delayed_render, term))
|
!fdm_add(fdm, delay_upper_fd, EPOLLIN, &fdm_delayed_render, term) ||
|
||||||
|
!fdm_add(fdm, application_synchronized_updates_fd, EPOLLIN, &fdm_application_synchronized_updates_timeout, term))
|
||||||
{
|
{
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
@ -620,6 +656,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
|
||||||
.wl = wayl,
|
.wl = wayl,
|
||||||
.render = {
|
.render = {
|
||||||
.scrollback_lines = conf->scrollback_lines,
|
.scrollback_lines = conf->scrollback_lines,
|
||||||
|
.application_synchronized_updates.timer_fd = application_synchronized_updates_fd,
|
||||||
.workers = {
|
.workers = {
|
||||||
.count = conf->render_worker_count,
|
.count = conf->render_worker_count,
|
||||||
.queue = tll_init(),
|
.queue = tll_init(),
|
||||||
|
|
@ -695,6 +732,7 @@ close_fds:
|
||||||
fdm_del(fdm, cursor_blink_fd);
|
fdm_del(fdm, cursor_blink_fd);
|
||||||
fdm_del(fdm, delay_lower_fd);
|
fdm_del(fdm, delay_lower_fd);
|
||||||
fdm_del(fdm, delay_upper_fd);
|
fdm_del(fdm, delay_upper_fd);
|
||||||
|
fdm_del(fdm, application_synchronized_updates_fd);
|
||||||
|
|
||||||
free(term);
|
free(term);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -755,6 +793,7 @@ term_shutdown(struct terminal *term)
|
||||||
|
|
||||||
term_cursor_blink_disable(term);
|
term_cursor_blink_disable(term);
|
||||||
|
|
||||||
|
fdm_del(term->fdm, term->render.application_synchronized_updates.timer_fd);
|
||||||
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
|
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
|
||||||
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
|
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
|
||||||
fdm_del(term->fdm, term->cursor_blink.fd);
|
fdm_del(term->fdm, term->cursor_blink.fd);
|
||||||
|
|
@ -762,6 +801,7 @@ term_shutdown(struct terminal *term)
|
||||||
fdm_del(term->fdm, term->flash.fd);
|
fdm_del(term->fdm, term->flash.fd);
|
||||||
fdm_del(term->fdm, term->ptmx);
|
fdm_del(term->fdm, term->ptmx);
|
||||||
|
|
||||||
|
term->render.application_synchronized_updates.timer_fd = -1;
|
||||||
term->delayed_render_timer.lower_fd = -1;
|
term->delayed_render_timer.lower_fd = -1;
|
||||||
term->delayed_render_timer.upper_fd = -1;
|
term->delayed_render_timer.upper_fd = -1;
|
||||||
term->cursor_blink.fd = -1;
|
term->cursor_blink.fd = -1;
|
||||||
|
|
@ -811,6 +851,7 @@ term_destroy(struct terminal *term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fdm_del(term->fdm, term->render.application_synchronized_updates.timer_fd);
|
||||||
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
|
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
|
||||||
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
|
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
|
||||||
fdm_del(term->fdm, term->cursor_blink.fd);
|
fdm_del(term->fdm, term->cursor_blink.fd);
|
||||||
|
|
@ -1764,3 +1805,41 @@ term_spawn_new(const struct terminal *term)
|
||||||
waitpid(pid, &result, 0);
|
waitpid(pid, &result, 0);
|
||||||
return WIFEXITED(result) && WEXITSTATUS(result) == 0;
|
return WIFEXITED(result) && WEXITSTATUS(result) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_enable_application_synchronized_updates(struct terminal *term)
|
||||||
|
{
|
||||||
|
if (term->render.application_synchronized_updates.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
term->render.application_synchronized_updates.enabled = true;
|
||||||
|
|
||||||
|
if (timerfd_settime(
|
||||||
|
term->render.application_synchronized_updates.timer_fd, 0,
|
||||||
|
&(struct itimerspec){.it_value = {.tv_sec = 1}}, NULL) < 0)
|
||||||
|
{
|
||||||
|
LOG_ERR("failed to arm timer for application synchronized updates");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disarm delayed rendering timers */
|
||||||
|
timerfd_settime(
|
||||||
|
term->delayed_render_timer.lower_fd, 0,
|
||||||
|
&(struct itimerspec){{0}}, NULL);
|
||||||
|
timerfd_settime(
|
||||||
|
term->delayed_render_timer.upper_fd, 0,
|
||||||
|
&(struct itimerspec){{0}}, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_disable_application_synchronized_updates(struct terminal *term)
|
||||||
|
{
|
||||||
|
if (!term->render.application_synchronized_updates.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
term->render.application_synchronized_updates.enabled = false;
|
||||||
|
|
||||||
|
/* Reset timers */
|
||||||
|
timerfd_settime(
|
||||||
|
term->render.application_synchronized_updates.timer_fd, 0,
|
||||||
|
&(struct itimerspec){{0}}, NULL);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,11 @@ struct terminal {
|
||||||
bool refresh_needed; /* Terminal needs to be re-rendered, as soon-as-possible */
|
bool refresh_needed; /* Terminal needs to be re-rendered, as soon-as-possible */
|
||||||
int scrollback_lines; /* Number of scrollback lines, from conf (TODO: move out from render struct?) */
|
int scrollback_lines; /* Number of scrollback lines, from conf (TODO: move out from render struct?) */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool enabled;
|
||||||
|
int timer_fd;
|
||||||
|
} application_synchronized_updates;
|
||||||
|
|
||||||
/* Render threads + synchronization primitives */
|
/* Render threads + synchronization primitives */
|
||||||
struct {
|
struct {
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
@ -405,3 +410,6 @@ void term_xcursor_update(struct terminal *term);
|
||||||
void term_set_window_title(struct terminal *term, const char *title);
|
void term_set_window_title(struct terminal *term, const char *title);
|
||||||
void term_flash(struct terminal *term, unsigned duration_ms);
|
void term_flash(struct terminal *term, unsigned duration_ms);
|
||||||
bool term_spawn_new(const struct terminal *term);
|
bool term_spawn_new(const struct terminal *term);
|
||||||
|
|
||||||
|
void term_enable_application_synchronized_updates(struct terminal *term);
|
||||||
|
void term_disable_application_synchronized_updates(struct terminal *term);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue