diff --git a/src/dulcepan.h b/src/dulcepan.h index 63fef98..fd67567 100644 --- a/src/dulcepan.h +++ b/src/dulcepan.h @@ -160,6 +160,8 @@ struct dp_state { struct sfdo_basedir_ctx *basedir_ctx; + char *persistent_path; + struct wl_list outputs; struct wl_list seats; @@ -208,4 +210,7 @@ char *dp_strdup(const char *str); const char *dp_ext_from_path(const char *path); enum dp_file_format dp_ext_to_format(const char *ext); +void dp_persistent_load(struct dp_state *state); +void dp_persistent_save(struct dp_state *state); + #endif diff --git a/src/main.c b/src/main.c index 8a180c4..8a0fcf1 100644 --- a/src/main.c +++ b/src/main.c @@ -108,6 +108,8 @@ static void run(struct dp_state *state) { } } + dp_persistent_load(state); + wl_list_for_each (output, &state->outputs, link) { dp_output_redraw(output); } @@ -126,6 +128,8 @@ static void run(struct dp_state *state) { dp_save(state); } + dp_persistent_save(state); + struct dp_seat *seat, *seat_tmp; wl_list_for_each_safe (seat, seat_tmp, &state->seats, link) { dp_seat_destroy(seat); diff --git a/src/meson.build b/src/meson.build index fc57b5c..f68c36b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,6 +3,7 @@ src = files( 'config.c', 'main.c', 'output.c', + 'persistent.c', 'save.c', 'seat.c', 'select.c', diff --git a/src/persistent.c b/src/persistent.c new file mode 100644 index 0000000..e975522 --- /dev/null +++ b/src/persistent.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include "dulcepan.h" + +#define STATE_SUBPATH "dulcepan" + +// State format: +// +// +// + +void dp_persistent_load(struct dp_state *state) { + size_t dir_len; + const char *dir = sfdo_basedir_get_cache_home(state->basedir_ctx, &dir_len); + state->persistent_path = dp_zalloc(dir_len + sizeof(STATE_SUBPATH)); + memcpy(state->persistent_path, dir, dir_len); + memcpy(state->persistent_path + dir_len, STATE_SUBPATH, sizeof(STATE_SUBPATH)); + + FILE *fp = fopen(state->persistent_path, "r"); + if (fp == NULL) { + if (errno != ENOENT) { + dp_log_error("Failed to open %s: %s", state->persistent_path, strerror(errno)); + } + return; + } + + char name[32]; + int x, y, width, height; + int n_read = 0; + + fgets(name, sizeof(name), fp); + size_t name_len = strlen(name); + if (name[name_len - 1] == '\n') { + name[--name_len] = '\0'; + } + n_read += fscanf(fp, "%d %d %d %d", &x, &y, &width, &height); + + bool ok = ferror(fp) == 0 && n_read == 4; + fclose(fp); + + if (!ok) { + dp_log_error("Persistent state: bad format"); + return; + } + + struct dp_output *selection_output = NULL; + + struct dp_output *output; + wl_list_for_each (output, &state->outputs, link) { + if (strcmp(output->name, name) == 0) { + selection_output = output; + break; + } + } + + if (selection_output == NULL) { + dp_log_error("Persistent state: failed to find cached output %s", name); + return; + } + + if (x < 0 || y < 0 || x + width > selection_output->transformed_width || + y + height >= selection_output->transformed_height) { + dp_log_error("Persistent state: invalid selection geometry", name); + return; + } + + struct dp_selection *selection = &state->selection; + selection->output = selection_output; + selection->x = x; + selection->y = y; + selection->width = width; + selection->height = height; +} + +void dp_persistent_save(struct dp_state *state) { + struct dp_selection *selection = &state->selection; + if (selection->output != NULL) { + FILE *fp = fopen(state->persistent_path, "w"); + if (fp == NULL) { + dp_log_error("Failed to open %s: %s", state->persistent_path, strerror(errno)); + } else { + fprintf(fp, + "%s\n" + "%d %d %d %d\n", + selection->output->name, selection->x, selection->y, selection->width, + selection->height); + fclose(fp); + } + } + + free(state->persistent_path); +}