MAJOR REDESIGN, TURNED FROM A GERMAN LEARNING APP TO EVERYTHING IN HIGH SCHOOL BUT STILL LOCKED THE OTHER SUBJECTS SINCE THEYRE NOT FINISHED YET

This commit is contained in:
dvorakmortonxd 2026-09-07 16:18:07 +02:00
commit 6ed5c5876b
4 changed files with 412 additions and 32 deletions

3
.gitignore vendored
View file

@ -1,9 +1,10 @@
# ---> C
# Prerequisites
*.d
#.d
# binary
sprechen
maturita
error.txt
error.log
CLAUDE.md

View file

@ -16,8 +16,8 @@ GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk4)
CFLAGS = -Wall -Wextra -Wno-deprecated-declarations $(GTK_CFLAGS)
LIBS = $(GTK_LIBS) -lm
TARGET = sprechen
SRC = sprechen.c
TARGET = maturita
SRC = maturita.c
all: $(TARGET)

View file

@ -1,18 +1,24 @@
# Sprechen.c
# maturita.c
A German learning application written in C using GTK 4.
An educational application written in C using GTK 4.
## Description
Sprechen.c is an educational program designed for practicing German language
skills, aimed at high school and gymnasium students. The UI is available in
Czech and English and is built as a single C file (`sprechen.c`) that renders a
modern, CSS-styled GTK 4 interface.
maturita.c is an educational program for high-school and gymnasium students
preparing for their maturita exam. The UI is available in Czech and English and
is built as a single C file (`maturita.c`) that renders a modern, CSS-styled
GTK 4 interface.
## Features
- **Welcome screen** – branded greeting with a description of the program and a
continue button to get started
- **Subjects ("Předměty")** – adaptive serpentine subject map with 13 subjects
- only **Deutsch** is open (round bubble with the German flag); picking it
opens the German learning path
- the other subjects are dimmed/locked placeholders until their content is
added
- layout folds into multiple rows when the window is narrow
- **Learning roadmap** – adaptive serpentine learning path with 10 units
- each unit numbered and labeled with its topic (e.g. "Neue Freunde")
- units 1 and 2 are open; completed units shown in green with a checkmark
@ -115,7 +121,7 @@ make
Or manually:
```bash
gcc -o sprechen sprechen.c `pkg-config --cflags --libs gtk4` -lm
gcc -o maturita maturita.c `pkg-config --cflags --libs gtk4` -lm
```
### Running the Application
@ -127,22 +133,24 @@ make run
or
```bash
./sprechen
./maturita
```
## Usage
When launched, the application shows the welcome screen. From there:
1. Click **"Pokračuj" / "Continue"** to open the learning roadmap.
2. Browse the units along the path; the roadmap reflows into rows and scrolls
1. Click **"Pokračuj" / "Continue"** to open the **Předměty / Subjects** map.
2. Click the **Deutsch** bubble (German flag) to open the German learning
roadmap. The other subjects are locked for now.
3. Browse the units along the path; the roadmap reflows into rows and scrolls
if the window is too narrow.
3. Click the **"Neue Freunde"** node to open unit 1 or **"Aus aller Welt"** to
4. Click the **"Neue Freunde"** node to open unit 1 or **"Aus aller Welt"** to
open unit 2, then pick any bubble to start an exercise. Unit 2 is available
even if unit 1 is not finished yet.
4. Use the **back button** in the top-left corner to return to the previous
5. Use the **back button** in the top-left corner to return to the previous
screen.
5. Open **Nastavení / Settings** (gear icon, top-right) to switch dark/light
6. Open **Nastavení / Settings** (gear icon, top-right) to switch dark/light
mode, pick a color theme, or change the interface language.
Units 1 and 2 are currently implemented. Locked units do nothing – they are
@ -160,7 +168,7 @@ to the app on first finish).
## Project structure
```
sprechen.c entire application (UI, navigation, themes, exercises)
maturita.c entire application (UI, navigation, themes, exercises)
Makefile build & run targets
README.md this file
LICENSE MIT license
@ -174,18 +182,18 @@ progress/ created at runtime
The app ships with ten palettes – Catppuccin, Nord, Dracula, Rose Pine, Ocean,
Gruvbox, Solarized, Everforest, Monokai and One Dark – each available in dark
and light mode. Colors are defined as theme palettes in `sprechen.c` and
and light mode. Colors are defined as theme palettes in `maturita.c` and
applied through a generated CSS stylesheet (plus matching Cairo colors for the
roadmap rails and icons).
Change the look from the in-app settings panel, or edit the palette tables /
`build_theme_css()` in `sprechen.c` and rebuild.
`build_theme_css()` in `maturita.c` and rebuild.
## Languages
The interface can be switched between Czech and English from the settings
panel; the choice takes effect immediately and is remembered between runs.
Translations live in two tables in `sprechen.c`: `tr_ui` holds interface
Translations live in two tables in `maturita.c`: `tr_ui` holds interface
strings under short keys, while `tr_content` translates the Czech meanings
shown next to the German exercise items and uses the Czech text itself as the
key. Widgets are registered with `i18n_bind()` so `apply_language()` can
@ -196,7 +204,7 @@ German in both languages.
## To-Do Plans
Future enhancements planned for Sprechen.c:
Future enhancements planned for maturita.c:
- [ ] Wire unit nodes to actual German vocabulary/grammar exercises
- [x] Unit 1 ("Neue Freunde") – 13 interactive exercises with progress saving

View file

@ -358,11 +358,11 @@ static const TrEntry tr_ui[] = {
{"theme", "TÉMA", "THEME"},
{"language", "JAZYK", "LANGUAGE"},
{"welcome_body",
"Sprechen.C je vzdělávací program na procvičování Němčiny, určený "
"pro studenty středních škol a gymnázií.\n\n"
"maturita.C je vzdělávací program pro studenty středních škol a "
"gymnázií na přípravu k maturitě.\n\n"
"Program je napsaný v Céčku studentama ze SSŠVT!",
"Sprechen.C is an educational app for practicing German, made for "
"high-school and gymnasium students.\n\n"
"maturita.C is an educational app for high-school and gymnasium "
"students to prepare for their maturita exam.\n\n"
"The program is written in C by students from SSŠVT!"},
{"continue", "Pokračuj", "Continue"},
{"roadmap_title", "Učební plán", "Learning path"},
@ -458,6 +458,25 @@ static const TrEntry tr_ui[] = {
{"hm_done", "Výborně! Uhodli jste všechna povolání.",
"Great! You guessed all the jobs."},
{"hm_guess", "Hádejte písmeno", "Guess a letter"},
{"subjects_title", "Předměty", "Subjects"},
{"subjects_sub", "Zatím je dostupný předmět Deutsch.",
"Only Deutsch is available so far."},
{"Český jazyk a literatura", "Český jazyk a literatura",
"Czech Language and Literature"},
{"Občanská nauka", "Občanská nauka", "Civics"},
{"English", "English", "English"},
{"Deutsch", "Deutsch", "Deutsch"},
{"Matematika", "Matematika", "Mathematics"},
{"Fyzika", "Fyzika", "Physics"},
{"Základy Přírodopisných věd", "Základy Přírodopisných věd",
"Fundamentals of Natural Sciences"},
{"Technická grafika", "Technická grafika", "Technical Drawing"},
{"Prezentační grafika", "Prezentační grafika", "Presentation Graphics"},
{"Správa počítačových sítí", "Správa počítačových sítí",
"Computer Network Administration"},
{"Programování", "Programování", "Programming"},
{"Technické vybavení", "Technické vybavení", "Computer Hardware"},
{"Programové vybavení", "Programové vybavení", "Software"},
{NULL, NULL, NULL}
};
@ -753,11 +772,11 @@ static void refresh_welcome_heading(void) {
return;
if (app_lang == LANG_EN)
markup = g_strdup_printf(
"Welcome to <span color=\"#%06x\">Sprechen.C</span>!",
"Welcome to <span color=\"#%06x\">maturita.C</span>!",
app_theme.accent);
else
markup = g_strdup_printf(
"Vítejte ve <span color=\"#%06x\">Sprechen.C</span>!",
"Vítejte ve <span color=\"#%06x\">maturita.C</span>!",
app_theme.accent);
gtk_label_set_markup(GTK_LABEL(welcome_heading), markup);
g_free(markup);
@ -1829,7 +1848,7 @@ static void on_nav_clicked(GtkButton *button, gpointer user_data) {
static void on_continue_clicked(GtkButton *button, gpointer user_data) {
(void)button;
(void)user_data;
gtk_stack_set_visible_child_name(main_stack, "roadmap");
gtk_stack_set_visible_child_name(main_stack, "subjects");
}
static GtkWidget *make_back_button(const char *target) {
@ -2347,7 +2366,7 @@ static GtkWidget *build_roadmap_page(void) {
gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page),
top_bar("welcome", "roadmap_title", "roadmap_sub"));
top_bar("subjects", "roadmap_title", "roadmap_sub"));
scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
@ -2391,6 +2410,357 @@ static GtkWidget *build_roadmap_page(void) {
}
/* ------------------------------------------------------------------ */
/* Subjects page ("Předměty") - serpentine subject map */
/* ------------------------------------------------------------------ */
#define NUM_SUBJECTS 13
#define SUB_BUBBLE NODE_SIZE /* round node, matches .unit-node */
#define SUB_MX 110.0
#define SUB_MY 150.0
#define SUB_SPAC 220.0
#define SUB_GAP 210.0
#define SUB_WAVE 34.0
/* Index 0 is Deutsch and is the only unlocked subject for now. */
static const char *sub_keys[NUM_SUBJECTS] = {
"Deutsch",
"Český jazyk a literatura",
"Občanská nauka",
"English",
"Matematika",
"Fyzika",
"Základy Přírodopisných věd",
"Technická grafika",
"Prezentační grafika",
"Správa počítačových sítí",
"Programování",
"Technické vybavení",
"Programové vybavení",
};
static GtkWidget *sub_scroll;
static GtkWidget *sub_fixed;
static GtkWidget *sub_rail;
static GtkWidget *sub_cells[NUM_SUBJECTS];
static GtkWidget *sub_labels[NUM_SUBJECTS];
static double sub_cx[NUM_SUBJECTS];
static double sub_cy[NUM_SUBJECTS];
static int sub_rows = 1;
static int sub_cols = NUM_SUBJECTS;
static int sub_cw = (int)(2.0 * SUB_MX + (NUM_SUBJECTS - 1) * SUB_SPAC);
static int sub_ch = (int)(2.0 * SUB_MY);
static guint sub_idle;
static void sub_layout_geometry(double avail) {
const double phase = 2.0 * G_PI * 1.7 / (double)(NUM_SUBJECTS - 1);
int rows;
int r, c, i;
for (rows = 1; rows <= NUM_SUBJECTS; rows++) {
int cols = (NUM_SUBJECTS + rows - 1) / rows;
if (2.0 * SUB_MX + (cols - 1) * SUB_SPAC <= avail + 1.0)
break;
}
if (rows > NUM_SUBJECTS)
rows = NUM_SUBJECTS;
sub_rows = rows;
sub_cols = (NUM_SUBJECTS + rows - 1) / rows;
if (sub_cols < 1)
sub_cols = 1;
sub_cw = (int)(2.0 * SUB_MX + (sub_cols - 1) * SUB_SPAC);
sub_ch = (int)(2.0 * SUB_MY + (rows - 1) * SUB_GAP);
for (r = 0; r < rows; r++) {
int base = r * sub_cols;
int len = MIN(sub_cols, NUM_SUBJECTS - base);
int fwd = (r % 2) == 0;
for (c = 0; c < len; c++) {
i = base + c;
int cc = fwd ? c : (sub_cols - 1 - c);
sub_cx[i] = SUB_MX + cc * SUB_SPAC;
sub_cy[i] = SUB_MY + r * SUB_GAP
+ SUB_WAVE * sin((double)i * phase);
}
}
}
static void sub_point(double t, double *ox, double *oy) {
int k = (int)t;
double u = t - (double)k;
double u2, u3;
double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y;
if (k < 0) { k = 0; u = 0.0; }
if (k >= NUM_SUBJECTS - 1) { k = NUM_SUBJECTS - 2; u = 1.0; }
p1x = sub_cx[k]; p1y = sub_cy[k];
p2x = sub_cx[k + 1]; p2y = sub_cy[k + 1];
if (k - 1 >= 0) { p0x = sub_cx[k - 1]; p0y = sub_cy[k - 1]; }
else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); }
if (k + 2 < NUM_SUBJECTS) { p3x = sub_cx[k + 2]; p3y = sub_cy[k + 2]; }
else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); }
u2 = u * u;
u3 = u2 * u;
*ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u
+ (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2
+ (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3);
*oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u
+ (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2
+ (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3);
}
static void sub_path(cairo_t *cr, double t0, double t1) {
const double steps_per_unit = 48.0;
int n = (int)((t1 - t0) * steps_per_unit);
double x, y;
int s;
if (n < 1)
n = 1;
sub_point(t0, &x, &y);
cairo_move_to(cr, x, y);
for (s = 1; s <= n; s++) {
sub_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y);
cairo_line_to(cr, x, y);
}
}
static void draw_sub_rail(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer user_data) {
const double t_end = (double)(NUM_SUBJECTS - 1);
const Rgb rail = color_from_hex(app_theme.rail);
const Rgb mauve = color_from_hex(app_theme.accent);
double hx, hy;
(void)area;
(void)width;
(void)height;
(void)user_data;
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
sub_point(0.0, &hx, &hy);
draw_node_halo(cr, hx, hy, SUB_BUBBLE * 1.05,
mauve.r, mauve.g, mauve.b, 0.18);
cairo_new_path(cr);
sub_path(cr, 0.0, t_end);
cairo_set_line_width(cr, 14);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
}
static void sub_apply_layout(void) {
int i;
if (!sub_fixed)
return;
for (i = 0; i < NUM_SUBJECTS; i++) {
if (sub_cells[i])
gtk_fixed_move(GTK_FIXED(sub_fixed), sub_cells[i],
(int)(sub_cx[i] - SUB_BUBBLE / 2.0),
(int)(sub_cy[i] - SUB_BUBBLE / 2.0));
if (sub_labels[i])
gtk_fixed_move(GTK_FIXED(sub_fixed), sub_labels[i],
(int)(sub_cx[i] - (SUB_SPAC - 24.0) / 2.0),
(int)(sub_cy[i] + SUB_BUBBLE / 2.0 + 10.0));
}
gtk_widget_set_size_request(sub_fixed, sub_cw, sub_ch);
gtk_widget_set_size_request(sub_rail, sub_cw, sub_ch);
gtk_fixed_move(GTK_FIXED(sub_fixed), sub_rail, 0, 0);
gtk_widget_queue_draw(sub_rail);
}
static void sub_relayout(void) {
GtkAdjustment *hadj;
double avail;
if (!sub_scroll)
return;
hadj = gtk_scrolled_window_get_hadjustment(
GTK_SCROLLED_WINDOW(sub_scroll));
avail = gtk_adjustment_get_page_size(hadj);
if (avail < 1.0)
return;
sub_layout_geometry(avail);
sub_apply_layout();
}
static gboolean sub_relayout_idle(gpointer data) {
(void)data;
sub_idle = 0;
sub_relayout();
return G_SOURCE_REMOVE;
}
static void sub_relayout_later(void) {
if (sub_idle == 0)
sub_idle = g_idle_add(sub_relayout_idle, NULL);
}
static void sub_adjust_notify(GtkAdjustment *adj, GParamSpec *ps,
gpointer data) {
(void)adj;
(void)ps;
(void)data;
sub_relayout_later();
}
/* German flag (black / red / gold) drawn in a clipped circle. */
static void draw_german_flag(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer data) {
double cx = width / 2.0;
double cy = height / 2.0;
double r = MIN(width, height) / 2.0 - 2.0;
double band = (double)height / 3.0;
(void)area;
(void)data;
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_save(cr);
cairo_new_path(cr);
cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI);
cairo_clip(cr);
cairo_new_path(cr);
cairo_rectangle(cr, 0.0, 0.0, (double)width, band);
cairo_set_source_rgb(cr, 0.18, 0.18, 0.19);
cairo_fill(cr);
cairo_new_path(cr);
cairo_rectangle(cr, 0.0, band, (double)width, band);
cairo_set_source_rgb(cr, 0.72, 0.27, 0.24);
cairo_fill(cr);
cairo_new_path(cr);
cairo_rectangle(cr, 0.0, 2.0 * band, (double)width, band);
cairo_set_source_rgb(cr, 0.84, 0.70, 0.32);
cairo_fill(cr);
cairo_restore(cr);
}
static GtkWidget *build_subjects_page(void) {
GtkWidget *page;
GtkWidget *scroll;
GtkWidget *wrap;
GtkWidget *fixed;
GtkWidget *rail;
GtkAdjustment *ha;
GtkAdjustment *va;
int i;
sub_layout_geometry(1000.0);
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_hexpand(page, TRUE);
gtk_widget_set_vexpand(page, TRUE);
gtk_widget_set_margin_start(page, 32);
gtk_widget_set_margin_end(page, 32);
gtk_widget_set_margin_top(page, 24);
gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page),
top_bar("welcome", "subjects_title", "subjects_sub"));
scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_widget_set_vexpand(scroll, TRUE);
gtk_widget_set_margin_top(scroll, 14);
gtk_box_append(GTK_BOX(page), scroll);
sub_scroll = scroll;
wrap = gtk_center_box_new();
gtk_widget_set_vexpand(wrap, TRUE);
gtk_widget_set_hexpand(wrap, TRUE);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap);
fixed = gtk_fixed_new();
gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER);
gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER);
gtk_widget_set_size_request(fixed, sub_cw, sub_ch);
gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed);
sub_fixed = fixed;
rail = gtk_drawing_area_new();
gtk_widget_set_size_request(rail, sub_cw, sub_ch);
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_sub_rail,
NULL, NULL);
gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0);
sub_rail = rail;
for (i = 0; i < NUM_SUBJECTS; i++) {
GtkWidget *card;
GtkWidget *lbl;
card = gtk_button_new();
gtk_widget_add_css_class(card, "unit-node");
gtk_widget_set_can_focus(card, FALSE);
gtk_widget_set_size_request(card, (int)SUB_BUBBLE, (int)SUB_BUBBLE);
if (i == 0) {
GtkWidget *flag = gtk_drawing_area_new();
gtk_widget_add_css_class(card, "current");
gtk_widget_set_size_request(flag, (int)SUB_BUBBLE,
(int)SUB_BUBBLE);
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(flag),
draw_german_flag, NULL, NULL);
gtk_button_set_child(GTK_BUTTON(card), flag);
g_object_set_data_full(G_OBJECT(card), "target",
g_strdup("roadmap"), g_free);
g_signal_connect(card, "clicked", G_CALLBACK(on_nav_clicked), NULL);
} else {
GtkWidget *lock;
gtk_widget_add_css_class(card, "locked");
gtk_widget_set_sensitive(card, FALSE);
lock = icon_area_new(draw_lock_icon,
0.3451, 0.3569, 0.4392, 26);
gtk_button_set_child(GTK_BUTTON(card), lock);
}
sub_cells[i] = card;
gtk_fixed_put(GTK_FIXED(fixed), card, 0, 0);
lbl = gtk_label_new(NULL);
i18n_bind(lbl, sub_keys[i], 0);
gtk_widget_set_size_request(lbl, (int)(SUB_SPAC - 24.0), -1);
gtk_widget_set_halign(lbl, GTK_ALIGN_CENTER);
gtk_label_set_justify(GTK_LABEL(lbl), GTK_JUSTIFY_CENTER);
gtk_label_set_wrap(GTK_LABEL(lbl), TRUE);
gtk_widget_add_css_class(lbl, "unit-name");
if (i != 0)
gtk_widget_add_css_class(lbl, "unit-name-locked");
sub_labels[i] = lbl;
gtk_fixed_put(GTK_FIXED(fixed), lbl, 0, 0);
}
ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll));
va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll));
g_signal_connect(ha, "notify::page-size",
G_CALLBACK(sub_adjust_notify), NULL);
g_signal_connect(va, "notify::page-size",
G_CALLBACK(sub_adjust_notify), NULL);
sub_apply_layout();
sub_relayout_later();
return page;
}
/* ------------------------------------------------------------------ */
/* Unit 1 exercise path (roadmap-style serpentine) */
/* ------------------------------------------------------------------ */
@ -6063,12 +6433,12 @@ static void activate(GtkApplication *app, gpointer user_data) {
window = GTK_WINDOW(gtk_application_window_new(app));
main_window = window;
gtk_window_set_title(window, "Sprechen.c");
gtk_window_set_title(window, "maturita.c");
gtk_window_set_default_size(window, 760, 560);
headerbar = gtk_header_bar_new();
gtk_widget_add_css_class(headerbar, "titlebar");
title_label = gtk_label_new("Sprechen.c");
title_label = gtk_label_new("maturita.c");
gtk_widget_add_css_class(title_label, "app-title");
gtk_header_bar_set_title_widget(GTK_HEADER_BAR(headerbar), title_label);
gtk_window_set_titlebar(window, headerbar);
@ -6083,6 +6453,7 @@ static void activate(GtkApplication *app, gpointer user_data) {
welcome_page = build_welcome_page();
roadmap_page = build_roadmap_page();
gtk_stack_add_named(main_stack, welcome_page, "welcome");
gtk_stack_add_named(main_stack, build_subjects_page(), "subjects");
gtk_stack_add_named(main_stack, roadmap_page, "roadmap");
for (int i = 0; i < NUM_UNLOCKED; i++) {
@ -6123,7 +6494,7 @@ int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("org.example.Sprechen", G_APPLICATION_DEFAULT_FLAGS);
app = gtk_application_new("org.example.maturita", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);