commit 12b2a89c050b3b79107dde6cadfbd43f00e3c5eb
parent 8876d156020f15a77460eaf698b024ae239faf8e
Author: hhvn <dev@hhvn.uk>
Date: Thu, 25 Aug 2022 22:15:39 +0100
Loading window
Diffstat:
7 files changed, 183 insertions(+), 8 deletions(-)
diff --git a/src/data.c b/src/data.c
@@ -47,15 +47,19 @@ unsigned char settings_png[] = {
};
#define IMAGE_LOAD(name) \
+ loading_update(lscr, "Loading image"); \
raw_image_##name = LoadImageFromMemory(".png", \
name##_png, sizeof(name##_png)); \
image_##name = LoadTextureFromImage(raw_image_##name); \
UnloadImage(raw_image_##name)
void
-data_load(void) {
+data_load(Loader *lscr) {
+ /* update main.h when adding loading steps */
+ loading_update(lscr, "Loading fonts");
font = LoadFontFromMemory(".ttf", DejaVuSansMono_ttf,
sizeof(DejaVuSansMono_ttf), FONT_SIZE, NULL, 0);
+ /* one step per IMAGE_LOAD() */
IMAGE_LOAD(tactical);
IMAGE_LOAD(colonies);
IMAGE_LOAD(bodies);
diff --git a/src/loading.c b/src/loading.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <raylib.h>
+#include "main.h"
+
+#define LOADING_FPS 60
+#define LOADING_W 500
+#define LOADING_H 50
+#define LOADING_FONT 30
+#define LOADING_PAD ((LOADING_H - LOADING_FONT) / 2)
+
+struct shmdata {
+ int step;
+ char str[LOAD_STR_MAX];
+};
+
+static int recv_winch = 0;
+
+static void
+loading_sighandler(int signal) {
+ fflush(stdout);
+ if (signal == SIGWINCH)
+ recv_winch = 1;
+}
+
+Loader *
+loading_open(int steps, char *initstr) {
+ Loader *ret;
+ int fd;
+ struct shmdata *shmdata;
+ /* child only */
+ struct shmdata *data;
+ char curstr[LOAD_STR_MAX];
+ struct sigaction sa;
+ int step = 0;
+
+ ret = malloc(sizeof(Loader));
+ if (!ret) return NULL;
+
+ snprintf(ret->path, sizeof(ret->path), "/%ld-loading", (long)getpid());
+ if ((fd = shm_open(ret->path, O_CREAT|O_RDWR, 0600)) == -1)
+ goto fail;
+
+ if (ftruncate(fd, sizeof(struct shmdata)) == -1)
+ goto fail;
+
+ if ((shmdata = mmap(NULL, sizeof(struct shmdata), PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0)) == MAP_FAILED)
+ goto fail;
+
+ shmdata->step = 0;
+ ret->step = &shmdata->step;
+ ret->data = &shmdata->str;
+
+ if ((ret->pid = fork()) == -1)
+ goto unmap;
+
+ if (ret->pid == 0) {
+ /* we're the child */
+ sa.sa_handler = loading_sighandler;
+ sa.sa_flags = SA_RESTART;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGWINCH, &sa, NULL);
+
+ fd = shm_open(ret->path, O_RDONLY, 0);
+ data = mmap(NULL, sizeof(struct shmdata), PROT_READ,
+ MAP_SHARED, fd, 0);
+ if (fd == -1 || data == MAP_FAILED)
+ data = initstr;
+
+ SetWindowState(FLAG_WINDOW_TOPMOST);
+ SetTargetFPS(LOADING_FPS);
+ SetExitKey(KEY_NULL);
+ InitWindow(LOADING_W, LOADING_H, "Loading...");
+ snprintf(curstr, sizeof(curstr), "%s...", initstr);
+
+ while (!WindowShouldClose()) {
+ if (recv_winch) {
+ recv_winch = 0;
+ memcpy(curstr, data->str, LOAD_STR_MAX);
+ }
+
+ BeginDrawing();
+
+ ClearBackground(col_bg);
+ DrawText(curstr, LOADING_PAD, LOADING_PAD, LOADING_FONT, col_fg);
+
+ BeginScissorMode(0, 0, data->step * LOADING_W / steps, LOADING_H);
+ DrawRectangle(0, 0, data->step * LOADING_W / steps, LOADING_H, col_fg);
+ DrawText(curstr, LOADING_PAD, LOADING_PAD, LOADING_FONT, col_bg);
+ EndScissorMode();
+
+ EndDrawing();
+ }
+ exit(0);
+ }
+
+ return ret;
+
+unmap:
+ munmap(ret->data, sizeof(struct shmdata));
+fail:
+ free(ret);
+ return NULL;
+}
+
+void
+loading_update(Loader *hand, char *str) {
+ (*hand->step)++;
+ snprintf(hand->data, LOAD_STR_MAX, "%s...", str);
+ kill(hand->pid, SIGWINCH);
+}
+
+void
+loading(Loader **hand, int steps, char *str) {
+ if (!*hand)
+ *hand = loading_open(steps, str);
+ else
+ loading_update(*hand, str);
+}
+
+void
+loading_close(Loader *hand) {
+ kill(hand->pid, SIGTERM);
+ shm_unlink(hand->path);
+ munmap(hand->data, sizeof(struct shmdata));
+ free(hand);
+}
diff --git a/src/main.c b/src/main.c
@@ -12,13 +12,25 @@ main(void) {
int draw;
int view_prev = -1;
time_t lastevent;
+ Loader *loader;
+
+
+ loader = loading_open(DATA_LOAD_STEPS + SAVE_READ_STEPS + 3, "Initializing UI");
ui_init();
- data_load();
- save_read(TESTSAVE);
+
+ data_load(loader);
+ save_read(loader, TESTSAVE);
+
+ loading_close(loader);
lastevent = time(NULL);
+ /* The window is hidden so that only the loading bar is shown. Hiding
+ * and unhiding the window also has the added effect of making it
+ * behave like a normal window in window managers, rather than having
+ * it float in the middle of the screen. */
+ ClearWindowState(FLAG_WINDOW_HIDDEN);
ui_update_screen();
while (!WindowShouldClose()) {
diff --git a/src/main.h b/src/main.h
@@ -90,7 +90,8 @@ System *sys_get(char *name);
System *sys_default(void);
/* save.c */
-void save_read(char *dir);
+#define SAVE_READ_STEPS 2
+void save_read(Loader *lscr, char *dir);
void save_write(void);
/* data.c */
@@ -102,7 +103,8 @@ extern Texture image_fleet;
extern Texture image_design;
extern Texture image_sys;
extern Texture image_settings;
-void data_load(void);
+#define DATA_LOAD_STEPS (1 + 7)
+void data_load(Loader *lscr);
void data_unload(void);
/* db.c */
@@ -115,3 +117,8 @@ int vdbgetf(char *dir, char *group, char *key, char *fmt, va_list args);
int dbgetf(char *dir, char *group, char *key, char *fmt, ...);
int dbgetint(char *dir, char *group, char *key);
float dbgetfloat(char *dir, char *group, char *key);
+
+/* loading.c */
+Loader *loading_open(int steps, char *initstr);
+void loading_update(Loader *hand, char *str);
+void loading_close(Loader *hand);
diff --git a/src/save.c b/src/save.c
@@ -2,6 +2,13 @@
#include <string.h>
#include "main.h"
+/* Plan for dealing with multiple saves:
+ * - saves: linked list with all saves that have been loaded (some data pruned)
+ * - save: the current save
+ * - save_get(name): get a save from saves/disk by name and load necessary data
+ * - save_select(name): set save to save_get(name) + housekeeping
+ */
+
static void
save_free(void) {
free(save->db.dir);
@@ -13,7 +20,7 @@ save_free(void) {
}
void
-save_read(char *dir) {
+save_read(Loader *lscr, char *dir) {
char *str;
if (save)
@@ -22,11 +29,13 @@ save_read(char *dir) {
if (!dir || !(save = malloc(sizeof(Save))))
return;
+ loading_update(lscr, "Initializing DB");
dbdeclare(dir);
save->db.dir = nstrdup(dir);
save->db.races = smprintf("%s/Races", dir);
save->db.systems = smprintf("%s/Systems", dir);
save->db.fleets = smprintf("%s/Fleets", dir);
+ loading_update(lscr, "Loading systems");
if ((str = dbget(save->db.dir, "index", "homesystem")))
save->homesys = sys_get(str);
return;
diff --git a/src/struct.h b/src/struct.h
@@ -1,4 +1,5 @@
#include <stddef.h>
+#include <sys/types.h>
/* system.c */
typedef struct {
@@ -152,4 +153,12 @@ typedef struct {
void *elem;
} Clickable;
+#define LOAD_STR_MAX 512
+typedef struct {
+ char path[64];
+ pid_t pid;
+ int *step;
+ char *data;
+} Loader;
+
#include "views.h" /* unique structures */
diff --git a/src/ui.c b/src/ui.c
@@ -134,10 +134,10 @@ View_sys view_sys = {
void
ui_init(void) {
- InitWindow(500, 500, "");
- SetWindowState(FLAG_WINDOW_RESIZABLE);
+ SetWindowState(FLAG_WINDOW_RESIZABLE|FLAG_WINDOW_HIDDEN);
SetTargetFPS(TARGET_FPS);
SetExitKey(KEY_NULL);
+ InitWindow(500, 500, "");
}
void