diff options
Diffstat (limited to 'taro')
| -rw-r--r-- | taro/config.h | 27 | ||||
| -rw-r--r-- | taro/daemon.c | 82 | ||||
| -rw-r--r-- | taro/meson.build | 5 | ||||
| -rw-r--r-- | taro/ui.c | 130 |
4 files changed, 178 insertions, 66 deletions
diff --git a/taro/config.h b/taro/config.h index cca7807..7c8e2a1 100644 --- a/taro/config.h +++ b/taro/config.h @@ -8,12 +8,20 @@ #define CONFIG_PATH "/.config/taro" +enum { + CONFIG_CREATED = 0, + CONFIG_LOADED, + CONFIG_ERRORED +}; + struct config { str config_dir; str config_path; + bool newly_created; str asset_dir; array(str) wallpaper_dirs; bool valid; + bool errored; }; AL_IGNORE_WARNING("-Wunused-function") @@ -96,9 +104,11 @@ out: json_decref(root); } -static bool open_config(struct config *conf, bool create) +static u8 open_config(struct config *conf, bool create) { al_memset(conf, 0, sizeof(struct config)); + al_array_init(conf->wallpaper_dirs); + conf->errored = false; char *envhome = getenv("HOME"); if (!envhome) goto err; @@ -108,6 +118,8 @@ static bool open_config(struct config *conf, bool create) if (!nn_dir_exists(&conf->config_dir)) { if (!create || !nn_dir_create(&conf->config_dir)) { goto err; + } else { + conf->newly_created = true; } } @@ -127,14 +139,17 @@ static bool open_config(struct config *conf, bool create) json_t *root = nn_file_open_as_json(&conf->config_path); if (!root) goto err; - al_array_init(conf->wallpaper_dirs); - - parse_config_json(conf, envhome, root); + if (!conf->newly_created) { + parse_config_json(conf, envhome, root); + } else { + conf->valid = false; + } - return true; + return conf->newly_created ? CONFIG_CREATED : CONFIG_LOADED; err: + conf->errored = true; close_config(conf); - return false; + return CONFIG_ERRORED; } AL_IGNORE_WARNING_END diff --git a/taro/daemon.c b/taro/daemon.c index 6ceba90..895ce53 100644 --- a/taro/daemon.c +++ b/taro/daemon.c @@ -14,6 +14,8 @@ #include "file_ext.h" #include "config.h" +//#define USE_SWAYIPC + struct monitor { struct stl_monitor *os; str config_dir; @@ -26,15 +28,15 @@ struct monitor { struct daemon *dmon; }; -#define SWAY_IPC_HEADER_LENGTH 14 -#define SWAY_IPC_SUBSCRIBE 2 - struct daemon { struct nn_event_loop loop; struct nn_signal quit_signal; s32 context_poll_fd; struct nn_poll context_poll; array(struct monitor *) monitors; +#ifdef USE_SWAYIPC +#define SWAY_IPC_HEADER_LENGTH 14 +#define SWAY_IPC_SUBSCRIBE 2 struct nn_socket ipc_socket; bool ipc_connected; bool ipc_errored; @@ -50,6 +52,7 @@ struct daemon { ssize_t size; ssize_t alloc; } ipc; +#endif struct config conf; struct nn_fs_event conf_event; }; @@ -111,7 +114,7 @@ static pid_t exec_or_exit(char *args[]) // This should return the pid of init if the parent process has already exited. pid_t ppid = getppid(); if (ppid != 1) send_signal_to_pid(ppid, SIGINT); - exit(EXIT_FAILURE); + // Rely on maybe_kill_wallpaper() to kill this fork. } } return pid; @@ -119,28 +122,27 @@ static pid_t exec_or_exit(char *args[]) static void maybe_kill_wallpaper(struct monitor *monitor) { - if (monitor->pid != -1) { - if (monitor->paused) { - signal_monitor(monitor, SIGCONT); - monitor->paused = false; - } - signal_monitor(monitor, SIGTERM); - monitor->pid = -1; + if (monitor->pid == -1) return; + if (monitor->paused) { + signal_monitor(monitor, SIGCONT); + monitor->paused = false; } + signal_monitor(monitor, SIGTERM); + monitor->pid = -1; } static bool search_wallpaper_dirs(struct daemon *dmon, str *id, str *path) { bool found = false; - log_debug("searching for wallpaper of id %.*s", al_str_x(id)); + log_info("searching for wallpaper of id %.*s", al_str_x(id)); str *dir; al_array_foreach_ptr(dmon->conf.wallpaper_dirs, i, dir) { - log_debug("checking dir %.*s", al_str_x(dir)); + log_info("checking dir %.*s", al_str_x(dir)); al_str_clone(path, dir); if (al_str_at(path, 1) != '/') al_str_cat(path, &al_str_c("/")); al_str_cat(path, id); if (nn_dir_exists(path)) { - log_debug("found wallpaper"); + log_info("found wallpaper"); found = true; break; } @@ -155,6 +157,11 @@ static bool run_wallpaper(struct daemon *dmon, struct monitor *monitor) { maybe_kill_wallpaper(monitor); + if (dmon->conf.newly_created) { + al_assert(!dmon->conf.valid); + return false; + } + if (!dmon->conf.valid) { log_error("config invalid, not setting wallpaper on %s", monitor->os->name); return false; @@ -272,6 +279,9 @@ static void output_discovered_callback(void *userdata, struct stl_monitor *os_mo { struct daemon *dmon = (struct daemon *)userdata; + log_info("Output discovered: %s (%ux%u) (vertical: %s).", os_monitor->name, + os_monitor->width, os_monitor->height, BOOLSTR(os_monitor->vertical)); + struct monitor *monitor; al_array_foreach(dmon->monitors, i, monitor) { if (strcmp(monitor->os->name, os_monitor->name) == 0) { @@ -299,10 +309,14 @@ static void conf_fs_event_callback(void *userdata, struct inotify_event *event) { struct daemon *dmon = (struct daemon *)userdata; (void)event; - close_config(&dmon->conf); - if (!open_config(&dmon->conf, false)) { - log_error("config became unavailable, exiting..."); - exit(EXIT_FAILURE); + nn_fs_event_stop(&dmon->conf_event); + nn_fs_event_start(&dmon->conf_event, &dmon->loop); + if (!dmon->conf.errored) close_config(&dmon->conf); + if (open_config(&dmon->conf, false) == CONFIG_LOADED && dmon->conf.valid) { + log_info("config successfully reloaded"); + } else { + log_error("failed to reload config"); + return; } struct monitor *monitor; al_array_foreach(dmon->monitors, i, monitor) { @@ -317,6 +331,7 @@ static void close_monitor(struct monitor *monitor) nn_fs_event_free(&monitor->selection_event); } +#ifdef USE_SWAYIPC static void ipc_handle_subscribe_success(json_t *root) { if (json_boolean_value(root)) { @@ -442,6 +457,7 @@ static void ipc_poll_callback(void *userdata, s32 revents) } } } +#endif static void context_poll_callback(void *userdata, s32 revents) { @@ -458,7 +474,9 @@ static void quit_signal_callback(void *userdata) nn_fs_event_stop(&monitor->selection_event); } nn_fs_event_stop(&dmon->conf_event); +#ifdef USE_SWAYIPC if (!dmon->ipc_errored) nn_poll_stop(&dmon->ipc_poll); +#endif if (dmon->context_poll_fd != -1) nn_poll_stop(&dmon->context_poll); nn_signal_stop(&dmon->quit_signal); } @@ -480,17 +498,27 @@ static void sigint_handler(s32 signum) nn_signal_send(&dmon.quit_signal); } -s32 main(void) +s32 main() { - if (!nn_common_init(NULL) || !open_config(&dmon.conf, true)) { - return EXIT_FAILURE; + s32 exit_status = EXIT_FAILURE; + + if (!nn_common_init(NULL)) return exit_status; + + switch (open_config(&dmon.conf, true)) { + case CONFIG_CREATED: + log_info("config generated in $HOME%s, go fill it out", CONFIG_PATH); + break; + case CONFIG_LOADED: + break; + case CONFIG_ERRORED: + log_error("failed to open config"); + nn_common_close(); + return exit_status; } signal(SIGINT, sigint_handler); signal(SIGCHLD, sigchld_handler); - s32 ret = EXIT_FAILURE; - nn_event_loop_init(&dmon.loop); nn_signal_init(&dmon.quit_signal, &dmon.loop, quit_signal_callback, &dmon); @@ -525,6 +553,7 @@ s32 main(void) al_str_free(&monitors); if (!monitors_exists) goto out; +#ifdef USE_SWAYIPC dmon.ipc.buf = NULL; dmon.ipc.size = 0; dmon.ipc.index = 0; @@ -544,19 +573,22 @@ s32 main(void) dmon.ipc_errored = true; log_warn("couldn't connect to sway ipc socket"); } +#endif nn_fs_event_init(&dmon.conf_event, &dmon.conf.config_path, NNWT_CLOSE_WRITE, conf_fs_event_callback, &dmon); nn_fs_event_start(&dmon.conf_event, &dmon.loop); nn_event_loop_run(&dmon.loop); - ret = EXIT_SUCCESS; + exit_status = EXIT_SUCCESS; nn_fs_event_free(&dmon.conf_event); +#ifdef USE_SWAYIPC al_free(dmon.out.buf); al_free(dmon.ipc.buf); nn_socket_close(&dmon.ipc_socket); +#endif out: al_array_foreach(dmon.monitors, i, monitor) { @@ -573,5 +605,5 @@ out: stl_global_close(); nn_common_close(); - return ret; + return exit_status; } diff --git a/taro/meson.build b/taro/meson.build index ffee872..a5be1e0 100644 --- a/taro/meson.build +++ b/taro/meson.build @@ -3,14 +3,15 @@ notcurses_core = dependency('notcurses-core', required: false, allow_fallback: f if not notcurses.found() or not notcurses_core.found() notcurses_opts = cmake.subproject_options() notcurses_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : 'Release' }) - notcurses_opts.add_cmake_defines({ 'USE_CXX': false }) + use_oiio = false + notcurses_opts.add_cmake_defines({ 'USE_CXX': use_oiio }) notcurses_opts.add_cmake_defines({ 'USE_DOCTEST': false }) notcurses_opts.add_cmake_defines({ 'USE_PANDOC': false }) notcurses_opts.add_cmake_defines({ 'BUILD_EXECUTABLES': false }) notcurses_opts.add_cmake_defines({ 'BUILD_FFI_LIBRARY': false }) notcurses_opts.add_cmake_defines({ 'USE_POC': false }) notcurses_opts.add_cmake_defines({ 'USE_STATIC': false }) - notcurses_opts.add_cmake_defines({ 'USE_MULTIMEDIA': 'ffmpeg' }) + notcurses_opts.add_cmake_defines({ 'USE_MULTIMEDIA': use_oiio ? 'oiio' : 'ffmpeg' }) notcurses_proj = cmake.subproject('notcurses', options: notcurses_opts) notcurses = notcurses_proj.dependency('notcurses') notcurses_core = notcurses_proj.dependency('notcurses-core') @@ -12,8 +12,6 @@ #include "file_ext.h" #include "config.h" -#define PIXEL_BLIT 1 - #define TIMER_UPDATE_BASE 1.f #define TIMER_TICK(delay) MAX(TIMER_UPDATE_BASE * (delay / 1000000.f), 0.001f) @@ -116,6 +114,7 @@ enum { struct ui { struct notcurses *nc; + bool use_pixel_blit; struct nn_event_loop loop; struct nn_poll input_poll; u64 delay; @@ -183,11 +182,12 @@ static void write_selected_entry_to_config(struct ui *u) if (u->g.set_index == -1) { al_str_from(&config, "||"); } else { - al_str_clone(&config, &u->n.e->id); - al_str_cat(&config, u->n.e->has_package ? &al_str_c("_p") : &al_str_c("_d")); + struct entry *e = &al_array_at(u->db.entries, u->g.set_index); + al_str_clone(&config, &e->id); + al_str_cat(&config, e->has_package ? &al_str_c("_p") : &al_str_c("_d")); al_str_cat(&config, &al_str_c("|false,100|")); struct prop *p; - al_array_foreach_ptr(u->n.e->props, i, p) { + al_array_foreach_ptr(e->props, i, p) { switch (p->type) { case PROP_TYPE_BOOL: { bool value = *((bool *)p->value); @@ -272,6 +272,7 @@ static bool init_monitors(struct ui *u, struct monitors *m) } else { u->selected_menu = MENU_MONITORS; } + u->previous_menu = u->selected_menu; return true; } @@ -293,10 +294,17 @@ static bool init_ui(struct ui *u) log_error("failed to initialize notcurses"); return false; } + //al_printf("%u\n", notcurses_palette_size(u->nc)); al_set_print(void_print_callback, NULL); return true; } +static inline void ncplane_maybe_set_styles(struct ui *u, struct ncplane *p, u32 style) +{ + // Setting text to bold messes up colors on some terminals. + if (u->use_pixel_blit) ncplane_set_styles(p, style); +} + struct image *get_image_from_pool(struct image_pool *pool, str *path) { u32 hash = al_str_hash(path); @@ -710,7 +718,7 @@ void draw_monitors(struct ui *u, struct monitors *m) } } - ncplane_set_styles(u->mp, NCSTYLE_BOLD); + ncplane_maybe_set_styles(u, u->mp, NCSTYLE_BOLD); s32 x = ((ncplane_dim_x(u->mp) - 1) - width) / 2; ncplane_cursor_move_yx(u->mp, 0, x); @@ -748,8 +756,10 @@ void draw_info(struct ui *u, struct info *n, bool update_text) ncplane_erase(u->ip); struct ncvisual_options vopts = { 0 }; - vopts.scaling = PIXEL_BLIT ? NCSCALE_SCALE_HIRES : NCSCALE_STRETCH; - vopts.blitter = PIXEL_BLIT ? NCBLIT_PIXEL : NCBLIT_2x1; + vopts.scaling = u->use_pixel_blit ? NCSCALE_SCALE_HIRES : NCSCALE_STRETCH; + vopts.blitter = u->use_pixel_blit ? NCBLIT_PIXEL : NCBLIT_2x1; + vopts.flags = NCVISUAL_OPTION_HORALIGNED; + vopts.x = NCALIGN_CENTER; struct image *img = get_image_from_pool(&u->pool, &n->e->preview_path); if (img && !n->blitted && !img->errored) { ncplane_erase(n->ip); @@ -759,10 +769,8 @@ void draw_info(struct ui *u, struct info *n, bool update_text) ncvisual_blit(u->nc, img->v, &vopts); n->blitted = !img->gif; u->delay = ncvisual_get_duration(img->v); - if (u->delay == 10000) { - // Default 100fps gifs to 10fps, seems like some weird wallpaper engine behavior. - u->delay = 100000; - } + // Default 100fps gifs to 10fps, seems like some weird wallpaper engine behavior. + if (u->delay == 10000) u->delay = 100000; } } else if (!img) { ncplane_erase(n->ip); @@ -813,11 +821,14 @@ static void set_tile_highlight(struct tile *t, s32 findex, s32 bindex) nccell_set_fg_default(&ncl); ncplane_polyfill_yx(t->p, 1, 0, &ncl); nccell_release(t->p, &ncl); + + // Portion of the top row. ncplane_set_bg_default(t->p); ncplane_set_fg_palindex(t->p, bindex); for (s32 i = 0; i < GRID_TILE_WIDTH; i++) { ncplane_putwc_yx(t->p, 0, i, L'▃'); } + (void)findex; //ncplane_set_fg_palindex(t->p, findex); // If we set both fg and bg palindex here, the fg color @@ -825,7 +836,6 @@ static void set_tile_highlight(struct tile *t, s32 findex, s32 bindex) // This might be a notcurses bug, I need to look more carefully. ncplane_set_fg_rgb8(t->p, 0, 0, 0); ncplane_set_bg_palindex(t->p, bindex); - ncplane_set_styles(t->p, NCSTYLE_BOLD); } void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text) @@ -833,8 +843,10 @@ void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text) if (!u->layed_out) return; struct ncvisual_options vopts = { 0 }; - vopts.scaling = PIXEL_BLIT ? NCSCALE_SCALE_HIRES : NCSCALE_STRETCH; - vopts.blitter = PIXEL_BLIT ? NCBLIT_PIXEL : NCBLIT_2x1; + vopts.scaling = u->use_pixel_blit ? NCSCALE_SCALE_HIRES : NCSCALE_STRETCH; + vopts.blitter = u->use_pixel_blit ? NCBLIT_PIXEL : NCBLIT_2x1; + vopts.flags = NCVISUAL_OPTION_HORALIGNED; + vopts.x = NCALIGN_CENTER; struct tile *t; al_array_foreach_ptr(g->tiles, i, t) { @@ -847,19 +859,33 @@ void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text) } } } + s32 index = g->selected_index - (g->selected_index % g->tiles_per_page); al_array_foreach_ptr(g->tiles, i, t) { ncplane_erase(t->p); if (!t->e) continue; - if (index == g->selected_index && g->flash <= 0.f && u->selected_menu == MENU_GRID) { - set_tile_highlight(t, 0, 8); + if (index == g->selected_index && u->selected_menu == MENU_GRID) { + if (g->flash >= 0.f) { + if (index == g->set_index) { + set_tile_highlight(t, 0, 7); + ncplane_maybe_set_styles(u, t->p, NCSTYLE_BOLD); + } else if (g->set_index == -1) { + ncplane_set_fg_default(t->p); + ncplane_set_bg_default(t->p); + ncplane_maybe_set_styles(u, t->p, NCSTYLE_NONE); + } + g->flash -= TIMER_TICK(u->delay); + } else { + set_tile_highlight(t, 0, 8); + ncplane_maybe_set_styles(u, t->p, NCSTYLE_BOLD); + } } else if (index == g->set_index && g->set_index >= 0) { set_tile_highlight(t, 0, 7); - g->flash -= TIMER_TICK(u->delay); + ncplane_maybe_set_styles(u, t->p, NCSTYLE_BOLD); } else { ncplane_set_fg_default(t->p); ncplane_set_bg_default(t->p); - ncplane_set_styles(t->p, NCSTYLE_NONE); + ncplane_maybe_set_styles(u, t->p, NCSTYLE_NONE); } if (t->text.s && !al_wstr_is_empty(t->text.s)) { draw_scrolling_text(t->p, &t->text, update_text); @@ -894,9 +920,11 @@ static bool handle_input_monitors(struct ui *u, struct monitors *m, struct ncinp } case NCKEY_DOWN: case 'j': { - u->selected_menu = MENU_GRID; - should_redraw_monitors = true; - should_redraw_grid = true; + if (u->db.entries.count > 0) { + u->selected_menu = MENU_GRID; + should_redraw_monitors = true; + should_redraw_grid = true; + } break; } case NCKEY_RETURN: @@ -1106,8 +1134,35 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu } break; } + case 'N': + case 'n': { + if (g->selected_index < 0) { + return false; + } + if (input->id == 'N' || input->modifiers & NCKEY_MOD_SHIFT) { + if (g->selected_index == 0) { + return false; + } + g->selected_index -= 1; + } else { + if ((u32)g->selected_index + 1 >= u->db.entries.count) { + return false; + } + g->selected_index += 1; + } + if (g->selected_index > g->max_index || g->selected_index < g->min_index) { + should_update_grid = true; + } + g->set_index = g->selected_index; + g->flash = FLASH_DURATION; + write_selected_entry_to_config(u); + should_redraw_grid = true; + should_redraw_info = true; + break; + } case 'r': { g->set_index = -1; + g->flash = FLASH_DURATION; write_selected_entry_to_config(u); should_redraw_grid = true; should_redraw_info = true; @@ -1126,10 +1181,11 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu } case NCKEY_RETURN: case NCKEY_SPACE: { - if (g->selected_index >= 0) { - g->set_index = g->selected_index; - g->flash = FLASH_DURATION; + if (g->selected_index < 0) { + return false; } + g->set_index = g->selected_index; + g->flash = FLASH_DURATION; write_selected_entry_to_config(u); should_redraw_grid = true; should_redraw_info = true; @@ -1248,14 +1304,15 @@ static struct ui u = { 0 }; s32 main(void) { - if (!nn_common_init(NULL)) return EXIT_FAILURE; + s32 exit_status = EXIT_FAILURE; - if (!open_config(&u.conf, false)) { - log_error("failed to open config, run `tarod` at least once to generate needed config"); - return EXIT_FAILURE; - } + if (!nn_common_init(NULL)) return exit_status; - s32 ret = EXIT_FAILURE; + if (open_config(&u.conf, false) != CONFIG_LOADED) { + log_error("failed to open config, run `tarod` at least once to generate the required config"); + nn_common_close(); + return exit_status; + } db_init(&u.db); @@ -1266,6 +1323,13 @@ s32 main(void) db_sort(&u.db); + const char *term_env = getenv("TERM"); + if (strcmp(term_env, "xterm-kitty") == 0) { + u.use_pixel_blit = true; + } else { + u.use_pixel_blit = false; + } + if (!init_ui(&u)) goto out; notcurses_stddim_yx(u.nc, &u.term_rows, &u.term_cols); @@ -1295,12 +1359,12 @@ s32 main(void) notcurses_stop(u.nc); - ret = EXIT_SUCCESS; + exit_status = EXIT_SUCCESS; out: close_config(&u.conf); nn_common_close(); - return ret; + return exit_status; } |