foot/pgo/pgo.c

421 lines
9.9 KiB
C
Raw Normal View History

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "async.h"
#include "config.h"
#include "key-binding.h"
#include "reaper.h"
#include "sixel.h"
#include "user-notification.h"
#include "vt.h"
extern bool fdm_ptmx(struct fdm *fdm, int fd, int events, void *data);
static void
usage(const char *prog_name)
{
printf(
"Usage: %s stimuli-file1 stimuli-file2 ... stimuli-fileN\n",
prog_name);
}
enum async_write_status
async_write(int fd, const void *data, size_t len, size_t *idx)
{
return ASYNC_WRITE_DONE;
}
bool
fdm_add(struct fdm *fdm, int fd, int events, fdm_fd_handler_t handler, void *data)
{
return true;
}
bool
fdm_del(struct fdm *fdm, int fd)
{
return true;
}
bool
fdm_event_add(struct fdm *fdm, int fd, int events)
{
return true;
}
bool
fdm_event_del(struct fdm *fdm, int fd, int events)
{
return true;
}
bool
render_resize(
struct terminal *term, int width, int height, uint8_t resize_options)
{
return true;
}
void render_refresh(struct terminal *term) {}
void render_refresh_csd(struct terminal *term) {}
void render_refresh_title(struct terminal *term) {}
void render_refresh_app_id(struct terminal *term) {}
bool
render_xcursor_is_valid(const struct seat *seat, const char *cursor)
{
return true;
}
bool
render_xcursor_set(struct seat *seat, struct terminal *term, enum cursor_shape shape)
{
return true;
}
enum cursor_shape
xcursor_for_csd_border(struct terminal *term, int x, int y)
{
return CURSOR_SHAPE_LEFT_PTR;
}
struct wl_window *
wayl_win_init(struct terminal *term, const char *token)
{
return NULL;
}
void wayl_win_destroy(struct wl_window *win) {}
void wayl_win_alpha_changed(struct wl_window *win) {}
2021-05-11 07:56:04 +02:00
bool wayl_win_set_urgent(struct wl_window *win) { return true; }
bool wayl_fractional_scaling(const struct wayland *wayl) { return true; }
2024-07-23 07:43:42 +02:00
pid_t
spawn(struct reaper *reaper, const char *cwd, char *const argv[],
int stdin_fd, int stdout_fd, int stderr_fd,
2024-07-23 07:43:42 +02:00
reaper_cb cb, void *cb_data, const char *xdg_activation_token)
{
2024-07-23 07:43:42 +02:00
return 2;
}
pid_t
slave_spawn(
int ptmx, int argc, const char *cwd, char *const *argv, char *const *envp,
const env_var_list_t *extra_env_vars, const char *term_env,
const char *conf_shell, bool login_shell,
const user_notifications_t *notifications)
{
return 0;
}
int
render_worker_thread(void *_ctx)
{
return 0;
}
struct extraction_context *
extract_begin(enum selection_kind kind, bool strip_trailing_empty)
{
return NULL;
}
bool
extract_one(
const struct terminal *term, const struct row *row, const struct cell *cell,
int col, void *context)
{
return true;
}
bool
extract_finish(struct extraction_context *context, char **text, size_t *len)
{
return true;
}
void cmd_scrollback_up(struct terminal *term, int rows) {}
void cmd_scrollback_down(struct terminal *term, int rows) {}
void ime_enable(struct seat *seat) {}
void ime_disable(struct seat *seat) {}
void ime_reset_preedit(struct seat *seat) {}
bool
notify_notify(struct terminal *term, struct notification *notif)
{
return true;
}
void
notify_free(struct terminal *term, struct notification *notif)
{
}
void
notify_icon_add(struct terminal *term, const char *id,
const char *symbolic_name, const uint8_t *data,
size_t data_sz)
{
}
void
notify_icon_del(struct terminal *term, const char *id)
{
}
void
notify_icon_free(struct notification_icon *icon)
{
}
void reaper_add(struct reaper *reaper, pid_t pid, reaper_cb cb, void *cb_data) {}
void reaper_del(struct reaper *reaper, pid_t pid) {}
void urls_reset(struct terminal *term) {}
void shm_unref(struct buffer *buf) {}
void shm_chain_free(struct buffer_chain *chain) {}
struct buffer_chain *
shm_chain_new(struct wl_shm *shm, bool scrollable, size_t pix_instances)
{
return NULL;
}
void search_selection_cancelled(struct terminal *term) {}
2021-12-04 18:29:58 +01:00
void get_current_modifiers(const struct seat *seat,
xkb_mod_mask_t *effective,
xkb_mod_mask_t *consumed, uint32_t key,
bool filter_locked) {}
2021-12-04 18:29:58 +01:00
static struct key_binding_set kbd;
static bool kbd_initialized = false;
struct key_binding_set *
key_binding_for(
struct key_binding_manager *mgr, const struct config *conf,
const struct seat *seat)
{
return &kbd;
}
void
key_binding_new_for_conf(
struct key_binding_manager *mgr, const struct wayland *wayl,
const struct config *conf)
{
if (!kbd_initialized) {
kbd_initialized = true;
kbd = (struct key_binding_set){
.key = tll_init(),
.search = tll_init(),
.url = tll_init(),
.mouse = tll_init(),
.selection_overrides = 0,
};
}
}
void
key_binding_unref(struct key_binding_manager *mgr, const struct config *conf)
{
}
2021-12-04 18:29:58 +01:00
int
main(int argc, const char *const *argv)
{
if (argc < 2) {
usage(argv[0]);
return EXIT_FAILURE;
}
2020-11-14 13:45:39 +01:00
const int row_count = 67;
const int col_count = 135;
const int grid_row_count = 16384;
int lower_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (lower_fd < 0)
return EXIT_FAILURE;
int upper_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (upper_fd < 0) {
close(lower_fd);
return EXIT_FAILURE;
}
struct row **normal_rows = calloc(grid_row_count, sizeof(normal_rows[0]));
struct row **alt_rows = calloc(grid_row_count, sizeof(alt_rows[0]));
for (int i = 0; i < grid_row_count; i++) {
normal_rows[i] = calloc(1, sizeof(*normal_rows[i]));
normal_rows[i]->cells = calloc(col_count, sizeof(normal_rows[i]->cells[0]));
alt_rows[i] = calloc(1, sizeof(*alt_rows[i]));
alt_rows[i]->cells = calloc(col_count, sizeof(alt_rows[i]->cells[0]));
}
struct config conf = {
.tweak = {
.delayed_render_lower_ns = 500000, /* 0.5ms */
.delayed_render_upper_ns = 16666666 / 2, /* half a frame period (60Hz) */
},
};
struct wayland wayl = {
.seats = tll_init(),
.monitors = tll_init(),
.terms = tll_init(),
};
struct terminal term = {
.conf = &conf,
.wl = &wayl,
.grid = &term.normal,
.normal = {
.num_rows = grid_row_count,
.num_cols = col_count,
.rows = normal_rows,
.cur_row = normal_rows[0],
},
.alt = {
.num_rows = grid_row_count,
.num_cols = col_count,
.rows = alt_rows,
.cur_row = alt_rows[0],
},
.scale = 1,
.width = col_count * 8,
.height = row_count * 15,
.cols = col_count,
.rows = row_count,
.cell_width = 8,
.cell_height = 15,
.scroll_region = {
.start = 0,
.end = row_count,
},
2020-11-19 19:12:32 +01:00
.selection = {
.coords = {
.start = {-1, -1},
.end = {-1, -1},
},
2020-11-19 19:12:32 +01:00
},
.delayed_render_timer = {
.lower_fd = lower_fd,
.upper_fd = upper_fd
},
.sixel = {
.palette_size = SIXEL_MAX_COLORS,
.max_width = SIXEL_MAX_WIDTH,
.max_height = SIXEL_MAX_HEIGHT,
},
};
tll_push_back(wayl.terms, &term);
int ret = EXIT_FAILURE;
for (int i = 1; i < argc; i++) {
struct stat st;
if (stat(argv[i], &st) < 0) {
fprintf(stderr, "error: %s: failed to stat: %s\n",
argv[i], strerror(errno));
goto out;
}
uint8_t *data = malloc(st.st_size);
if (data == NULL) {
fprintf(stderr, "error: %s: failed to allocate buffer: %s\n",
argv[i], strerror(errno));
goto out;
}
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
fprintf(stderr, "error: %s: failed to open: %s\n",
argv[i], strerror(errno));
goto out;
}
ssize_t amount = read(fd, data, st.st_size);
if (amount != st.st_size) {
fprintf(stderr, "error: %s: failed to read: %s\n",
argv[i], strerror(errno));
goto out;
}
close(fd);
shm: unbreak build without memfd_create New FreeBSD versions have memfd_create but other BSDs don't. pgo/pgo.c:260:22: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration] int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC); ^ pgo/pgo.c:260:52: error: use of undeclared identifier 'MFD_CLOEXEC' int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC); ^ shm.c:13:10: fatal error: 'linux/mman.h' file not found #include <linux/mman.h> ^~~~~~~~~~~~~~ shm.c:277:15: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration] pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); ^ shm.c:277:60: error: use of undeclared identifier 'MFD_CLOEXEC' pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); ^ shm.c:277:74: error: use of undeclared identifier 'MFD_ALLOW_SEALING' pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); ^ shm.c:339:15: error: use of undeclared identifier 'F_SEAL_GROW' F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) ^ shm.c:339:29: error: use of undeclared identifier 'F_SEAL_SHRINK' F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) ^ shm.c:339:71: error: use of undeclared identifier 'F_SEAL_SEAL' F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) ^ shm.c:338:24: error: use of undeclared identifier 'F_ADD_SEALS' if (fcntl(pool_fd, F_ADD_SEALS, ^
2021-01-19 14:20:55 +00:00
#if defined(MEMFD_CREATE)
int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC);
shm: unbreak build without memfd_create New FreeBSD versions have memfd_create but other BSDs don't. pgo/pgo.c:260:22: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration] int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC); ^ pgo/pgo.c:260:52: error: use of undeclared identifier 'MFD_CLOEXEC' int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC); ^ shm.c:13:10: fatal error: 'linux/mman.h' file not found #include <linux/mman.h> ^~~~~~~~~~~~~~ shm.c:277:15: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration] pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); ^ shm.c:277:60: error: use of undeclared identifier 'MFD_CLOEXEC' pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); ^ shm.c:277:74: error: use of undeclared identifier 'MFD_ALLOW_SEALING' pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); ^ shm.c:339:15: error: use of undeclared identifier 'F_SEAL_GROW' F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) ^ shm.c:339:29: error: use of undeclared identifier 'F_SEAL_SHRINK' F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) ^ shm.c:339:71: error: use of undeclared identifier 'F_SEAL_SEAL' F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) ^ shm.c:338:24: error: use of undeclared identifier 'F_ADD_SEALS' if (fcntl(pool_fd, F_ADD_SEALS, ^
2021-01-19 14:20:55 +00:00
#elif defined(__FreeBSD__)
// memfd_create on FreeBSD 13 is SHM_ANON without sealing support
int mem_fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
#else
char name[] = "/tmp/foot-pgo-ptmx-XXXXXX";
int mem_fd = mkostemp(name, O_CLOEXEC);
unlink(name);
#endif
if (mem_fd < 0) {
fprintf(stderr, "error: failed to create memory FD\n");
goto out;
}
if (write(mem_fd, data, st.st_size) < 0) {
fprintf(stderr, "error: failed to write memory FD\n");
close(mem_fd);
goto out;
}
free(data);
term.ptmx = mem_fd;
lseek(mem_fd, 0, SEEK_SET);
printf("Feeding VT parser with %s (%lld bytes)\n",
argv[i], (long long)st.st_size);
while (lseek(mem_fd, 0, SEEK_CUR) < st.st_size) {
if (!fdm_ptmx(NULL, -1, EPOLLIN, &term)) {
fprintf(stderr, "error: fdm_ptmx() failed\n");
close(mem_fd);
goto out;
}
}
close(mem_fd);
}
ret = EXIT_SUCCESS;
out:
tll_free(wayl.terms);
for (int i = 0; i < grid_row_count; i++) {
if (normal_rows[i] != NULL)
free(normal_rows[i]->cells);
free(normal_rows[i]);
if (alt_rows[i] != NULL)
free(alt_rows[i]->cells);
free(alt_rows[i]);
}
free(normal_rows);
free(alt_rows);
close(lower_fd);
close(upper_fd);
return ret;
}