osc: add support for osc 176 (app ID)

This adds support for a new OSC escape sequence: OSC 176, that lets
terminal programs tell the terminal the name of the app that is
running. foot then sets the app ID of the toplevel to that ID,
which lets the compositor know which app is running, and typically
sets the appropriate icon, window grouping, ...

See: https://gist.github.com/delthas/d451e2cc1573bb2364839849c7117239
This commit is contained in:
delthas 2023-09-04 14:02:05 +02:00 committed by Daniel Eklöf
parent 4801d3a305
commit 6c56b04b3f
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 101 additions and 2 deletions

View file

@ -627,6 +627,30 @@ fdm_title_update_timeout(struct fdm *fdm, int fd, int events, void *data)
return true;
}
static bool
fdm_app_id_update_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.app_id.timer_fd, &unused, sizeof(unused));
if (ret < 0) {
if (errno == EAGAIN)
return true;
LOG_ERRNO("failed to read app ID update throttle timer");
return false;
}
struct itimerspec reset = {{0}};
timerfd_settime(term->render.app_id.timer_fd, 0, &reset, NULL);
render_refresh_app_id(term);
return true;
}
static bool
initialize_render_workers(struct terminal *term)
{
@ -1050,6 +1074,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
int delay_upper_fd = -1;
int app_sync_updates_fd = -1;
int title_update_fd = -1;
int app_id_update_fd = -1;
struct terminal *term = malloc(sizeof(*term));
if (unlikely(term == NULL)) {
@ -1084,6 +1109,12 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
goto close_fds;
}
if ((app_id_update_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)) < 0)
{
LOG_ERRNO("failed to create app ID update throttle timer FD");
goto close_fds;
}
if (ioctl(ptmx, (unsigned int)TIOCSWINSZ,
&(struct winsize){.ws_row = 24, .ws_col = 80}) < 0)
{
@ -1114,7 +1145,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
!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, app_sync_updates_fd, EPOLLIN, &fdm_app_sync_updates_timeout, term) ||
!fdm_add(fdm, title_update_fd, EPOLLIN, &fdm_title_update_timeout, term))
!fdm_add(fdm, title_update_fd, EPOLLIN, &fdm_title_update_timeout, term) ||
!fdm_add(fdm, app_id_update_fd, EPOLLIN, &fdm_app_id_update_timeout, term))
{
goto err;
}
@ -1210,6 +1242,9 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.title = {
.timer_fd = title_update_fd,
},
.app_id = {
.timer_fd = app_id_update_fd,
},
.workers = {
.count = conf->render_worker_count,
.queue = tll_init(),
@ -1318,6 +1353,7 @@ close_fds:
fdm_del(fdm, delay_upper_fd);
fdm_del(fdm, app_sync_updates_fd);
fdm_del(fdm, title_update_fd);
fdm_del(fdm, app_id_update_fd);
free(term);
return NULL;
@ -1510,6 +1546,7 @@ term_shutdown(struct terminal *term)
fdm_del(term->fdm, term->selection.auto_scroll.fd);
fdm_del(term->fdm, term->render.app_sync_updates.timer_fd);
fdm_del(term->fdm, term->render.app_id.timer_fd);
fdm_del(term->fdm, term->render.title.timer_fd);
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
@ -1548,6 +1585,7 @@ term_shutdown(struct terminal *term)
term->selection.auto_scroll.fd = -1;
term->render.app_sync_updates.timer_fd = -1;
term->render.app_id.timer_fd = -1;
term->render.title.timer_fd = -1;
term->delayed_render_timer.lower_fd = -1;
term->delayed_render_timer.upper_fd = -1;
@ -1601,6 +1639,7 @@ term_destroy(struct terminal *term)
fdm_del(term->fdm, term->selection.auto_scroll.fd);
fdm_del(term->fdm, term->render.app_sync_updates.timer_fd);
fdm_del(term->fdm, term->render.app_id.timer_fd);
fdm_del(term->fdm, term->render.title.timer_fd);
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
@ -1644,6 +1683,7 @@ term_destroy(struct terminal *term)
composed_free(term->composed);
free(term->app_id);
free(term->window_title);
tll_free_and_free(term->window_title_stack, free);
@ -3260,6 +3300,25 @@ term_set_window_title(struct terminal *term, const char *title)
term->window_title_has_been_set = true;
}
void
term_set_app_id(struct terminal *term, const char *app_id)
{
if (app_id != NULL && *app_id == '\0')
app_id = NULL;
if (term->app_id == NULL && app_id == NULL)
return;
if (term->app_id != NULL && app_id != NULL && strcmp(term->app_id, app_id) == 0)
return;
free(term->app_id);
if (app_id != NULL) {
term->app_id = xstrdup(app_id);
} else {
term->app_id = NULL;
}
render_refresh_app_id(term);
}
void
term_flash(struct terminal *term, unsigned duration_ms)
{