Add a self-updater that installs new releases.

Bake the release tag into the binary so the app knows what it is running;
plain builds keep the "dev" default and never offer an update. The CI
workflow already exported the tag on Linux and macOS, so only the Windows
job needed it.

Read the newest version from the redirect GitHub serves for
/releases/latest, which avoids the REST API and its unauthenticated rate
limit and needs no JSON parser. Networking goes through the curl command
rather than a linked library: curl handles TLS, redirects and proxies, it
ships on all three platforms, and it keeps the bundling scripts free of
another shared library.

An application cannot reliably replace its own files while running, so
every platform follows one shape: unpack beside the current install,
write a script that waits for this process to exit before swapping, then
launch it detached and quit. Staging beside the install keeps the move on
one filesystem and fails early when the location is read-only. The
Windows script copies without mirroring so the progress files kept inside
the install directory survive.

Check quietly a few seconds after startup and offer the result in a
banner above the pages, with a manual check in the settings popover.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-17 15:04:55 +02:00
commit 91a848b408
10 changed files with 1084 additions and 4 deletions

View file

@ -21,6 +21,13 @@
#define CZ_SUBJ 3 /* index of "Český jazyk a literatura" */
#define CSS_FILE "style.css"
#define APP_ID "org.maturita.Maturita"
/* Release builds bake the git tag in (see VERSION in the Makefile), so the
* updater can tell what it is running. Plain builds stay at "dev" and never
* report an update as available. */
#ifndef APP_VERSION
#define APP_VERSION "dev"
#endif
#define UPDATE_REPO "pepaskopec-blip/maturita.c"
#define ICON_NAME "maturita"
#define ICON_FILE "assets/app-icon.png"
#define ICON_THEME_DIR "assets/icons" /* cwd when run from source tree */
@ -883,6 +890,15 @@ gboolean on_window_key_pressed(GtkEventControllerKey *controller,
GdkModifierType state,
gpointer user_data);
GtkWidget *build_welcome_page(void);
/* util.c */
char *app_executable_path(void);
/* update.c */
void update_init(void);
void update_check_async(gboolean interactive);
void update_clear_staging(void);
void update_apply_lang(void);
GtkWidget *build_update_banner(void);
GtkWidget *build_update_box(void);
void draw_finish_cell(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer data);
void road_point(double t, double *ox, double *oy);