mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-05 07:15:30 -04:00
flash: implement 'flash'
Use our own escape sequence for the 'flash' terminfo entry. Implemented by arming a timer FD and setting a boolean that indicates we're currently "flashing". The renderer draws a semi-transparent yellowish layer over the entire window when "flashing" is active.
This commit is contained in:
parent
1ff04c5e36
commit
0dd8951cb3
5 changed files with 84 additions and 22 deletions
19
csi.c
19
csi.c
|
|
@ -5,6 +5,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
|
||||||
#if defined(_DEBUG)
|
#if defined(_DEBUG)
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -573,6 +575,23 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 1001: {
|
||||||
|
/* Our own private - flash */
|
||||||
|
unsigned duration_ms = vt_param_get(term, 1, 100);
|
||||||
|
LOG_WARN("FLASH for %ums", duration_ms);
|
||||||
|
|
||||||
|
struct itimerspec alarm = {
|
||||||
|
.it_value = {.tv_sec = 0, .tv_nsec = duration_ms * 1000000},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (timerfd_settime(term->flash_timer_fd, 0, &alarm, NULL) < 0)
|
||||||
|
LOG_ERRNO("failed to arm flash timer");
|
||||||
|
else {
|
||||||
|
term->flash_active = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG_WARN("ignoring %s", csi_as_string(term, final));
|
LOG_WARN("ignoring %s", csi_as_string(term, final));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ foot+base|foot base fragment,
|
||||||
ed=\E[J,
|
ed=\E[J,
|
||||||
el=\E[K,
|
el=\E[K,
|
||||||
el1=\E[1K,
|
el1=\E[1K,
|
||||||
flash=\E[?5h$<100/>\E[?5l,
|
flash=\E[1001;100t,
|
||||||
home=\E[H,
|
home=\E[H,
|
||||||
hpa=\E[%i%p1%dG,
|
hpa=\E[%i%p1%dG,
|
||||||
ht=^I,
|
ht=^I,
|
||||||
|
|
|
||||||
24
main.c
24
main.c
|
|
@ -10,6 +10,8 @@
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
|
||||||
#include <freetype/tttables.h>
|
#include <freetype/tttables.h>
|
||||||
#include <cairo-ft.h>
|
#include <cairo-ft.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
|
@ -325,6 +327,7 @@ main(int argc, char *const *argv)
|
||||||
.keypad_keys_mode = KEYPAD_NUMERICAL,
|
.keypad_keys_mode = KEYPAD_NUMERICAL,
|
||||||
.auto_margin = true,
|
.auto_margin = true,
|
||||||
.window_title_stack = tll_init(),
|
.window_title_stack = tll_init(),
|
||||||
|
.flash_timer_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC),
|
||||||
.vt = {
|
.vt = {
|
||||||
.state = 1, /* STATE_GROUND */
|
.state = 1, /* STATE_GROUND */
|
||||||
.attrs = {
|
.attrs = {
|
||||||
|
|
@ -681,6 +684,7 @@ main(int argc, char *const *argv)
|
||||||
{.fd = wl_display_get_fd(term.wl.display), .events = POLLIN},
|
{.fd = wl_display_get_fd(term.wl.display), .events = POLLIN},
|
||||||
{.fd = term.ptmx, .events = POLLIN},
|
{.fd = term.ptmx, .events = POLLIN},
|
||||||
{.fd = term.kbd.repeat.pipe_read_fd, .events = POLLIN},
|
{.fd = term.kbd.repeat.pipe_read_fd, .events = POLLIN},
|
||||||
|
{.fd = term.flash_timer_fd, .events = POLLIN},
|
||||||
};
|
};
|
||||||
|
|
||||||
wl_display_flush(term.wl.display);
|
wl_display_flush(term.wl.display);
|
||||||
|
|
@ -775,6 +779,23 @@ main(int argc, char *const *argv)
|
||||||
|
|
||||||
if (fds[2].revents & POLLHUP)
|
if (fds[2].revents & POLLHUP)
|
||||||
LOG_ERR("keyboard repeat handling thread died");
|
LOG_ERR("keyboard repeat handling thread died");
|
||||||
|
|
||||||
|
if (fds[3].revents & POLLIN) {
|
||||||
|
uint64_t expiration_count;
|
||||||
|
ssize_t ret = read(
|
||||||
|
term.flash_timer_fd, &expiration_count, sizeof(expiration_count));
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
LOG_ERRNO("failed to read flash timer");
|
||||||
|
else
|
||||||
|
LOG_DBG("flash timer expired %llu times",
|
||||||
|
(unsigned long long)expiration_count);
|
||||||
|
|
||||||
|
term.flash_active = false;
|
||||||
|
term_damage_view(&term);
|
||||||
|
if (term.frame_callback == NULL)
|
||||||
|
grid_render(&term);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
@ -862,6 +883,9 @@ out:
|
||||||
cairo_glyph_free(f->glyph_cache[j].glyphs);
|
cairo_glyph_free(f->glyph_cache[j].glyphs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (term.flash_timer_fd != -1)
|
||||||
|
close(term.flash_timer_fd);
|
||||||
|
|
||||||
if (term.ptmx != -1)
|
if (term.ptmx != -1)
|
||||||
close(term.ptmx);
|
close(term.ptmx);
|
||||||
|
|
||||||
|
|
|
||||||
58
render.c
58
render.c
|
|
@ -296,34 +296,40 @@ grid_render(struct terminal *term)
|
||||||
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height);
|
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height);
|
||||||
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
|
|
||||||
|
if (term->flash_active)
|
||||||
|
term_damage_view(term);
|
||||||
|
|
||||||
static struct buffer *last_buf = NULL;
|
static struct buffer *last_buf = NULL;
|
||||||
if (last_buf != buf || false) {
|
static bool last_flash = false;
|
||||||
if (last_buf != NULL) {
|
|
||||||
LOG_DBG("new buffer");
|
|
||||||
|
|
||||||
/* Fill area outside the cell grid with the default background color */
|
/* If we resized the window, or is flashing, or just stopped flashing */
|
||||||
int rmargin = term->cols * term->cell_width;
|
if (last_buf != buf || term->flash_active || last_flash) {
|
||||||
int bmargin = term->rows * term->cell_height;
|
LOG_DBG("new buffer");
|
||||||
int rmargin_width = term->width - rmargin;
|
|
||||||
int bmargin_height = term->height - bmargin;
|
|
||||||
|
|
||||||
uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg;
|
/* Fill area outside the cell grid with the default background color */
|
||||||
struct rgb bg = color_hex_to_rgb(_bg);
|
int rmargin = term->cols * term->cell_width;
|
||||||
cairo_set_source_rgb(buf->cairo, bg.r, bg.g, bg.b);
|
int bmargin = term->rows * term->cell_height;
|
||||||
|
int rmargin_width = term->width - rmargin;
|
||||||
|
int bmargin_height = term->height - bmargin;
|
||||||
|
|
||||||
cairo_rectangle(buf->cairo, rmargin, 0, rmargin_width, term->height);
|
uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg;
|
||||||
cairo_rectangle(buf->cairo, 0, bmargin, term->width, bmargin_height);
|
struct rgb bg = color_hex_to_rgb(_bg);
|
||||||
cairo_fill(buf->cairo);
|
cairo_set_source_rgb(buf->cairo, bg.r, bg.g, bg.b);
|
||||||
|
|
||||||
wl_surface_damage_buffer(
|
cairo_rectangle(buf->cairo, rmargin, 0, rmargin_width, term->height);
|
||||||
term->wl.surface, rmargin, 0, rmargin_width, term->height);
|
cairo_rectangle(buf->cairo, 0, bmargin, term->width, bmargin_height);
|
||||||
wl_surface_damage_buffer(
|
cairo_fill(buf->cairo);
|
||||||
term->wl.surface, 0, bmargin, term->width, bmargin_height);
|
|
||||||
|
wl_surface_damage_buffer(
|
||||||
|
term->wl.surface, rmargin, 0, rmargin_width, term->height);
|
||||||
|
wl_surface_damage_buffer(
|
||||||
|
term->wl.surface, 0, bmargin, term->width, bmargin_height);
|
||||||
|
|
||||||
|
/* Force a full grid refresh */
|
||||||
|
term_damage_view(term);
|
||||||
|
|
||||||
/* Force a full grid refresh */
|
|
||||||
term_damage_all(term);
|
|
||||||
}
|
|
||||||
last_buf = buf;
|
last_buf = buf;
|
||||||
|
last_flash = term->flash_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
||||||
|
|
@ -419,6 +425,16 @@ grid_render(struct terminal *term)
|
||||||
if (gseq.count > 0)
|
if (gseq.count > 0)
|
||||||
gseq_flush(term, buf);
|
gseq_flush(term, buf);
|
||||||
|
|
||||||
|
if (term->flash_active) {
|
||||||
|
cairo_set_source_rgba(buf->cairo, 1.0, 1.0, 0.0, 0.5);
|
||||||
|
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER);
|
||||||
|
cairo_rectangle(buf->cairo, 0, 0, term->width, term->height);
|
||||||
|
cairo_fill(buf->cairo);
|
||||||
|
|
||||||
|
wl_surface_damage_buffer(
|
||||||
|
term->wl.surface, 0, 0, term->width, term->height);
|
||||||
|
}
|
||||||
|
|
||||||
assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows);
|
assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows);
|
||||||
assert(term->grid->view >= 0 && term->grid->view < term->grid->num_rows);
|
assert(term->grid->view >= 0 && term->grid->view < term->grid->num_rows);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,9 @@ struct terminal {
|
||||||
char *window_title;
|
char *window_title;
|
||||||
tll(char *) window_title_stack;
|
tll(char *) window_title_stack;
|
||||||
|
|
||||||
|
bool flash_active;
|
||||||
|
int flash_timer_fd;
|
||||||
|
|
||||||
struct vt vt;
|
struct vt vt;
|
||||||
struct kbd kbd;
|
struct kbd kbd;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue