summaryrefslogtreecommitdiff
path: root/taro
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2025-06-17 11:22:17 -0400
committerAndrew Opalach <andrew@akon.city> 2025-06-17 11:27:55 -0400
commit110be42a7d267647241905936c414a53ad18ddae (patch)
treef73e28f564a78775ab85656acc1e56d020f89474 /taro
parent5986c8bf61fc980a9a3383a426479a1296d179e7 (diff)
downloadmauri-110be42a7d267647241905936c414a53ad18ddae.tar.gz
mauri-110be42a7d267647241905936c414a53ad18ddae.tar.bz2
mauri-110be42a7d267647241905936c414a53ad18ddae.zip
Test packaging for debian and arch
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'taro')
-rw-r--r--taro/config.h27
-rw-r--r--taro/daemon.c82
-rw-r--r--taro/meson.build5
-rw-r--r--taro/ui.c130
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')
diff --git a/taro/ui.c b/taro/ui.c
index 1162196..2b1de3b 100644
--- a/taro/ui.c
+++ b/taro/ui.c
@@ -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;
}