Add orionpkg (package manager GUI) + installer locale step
orionpkg/orionpkg.c (~500 lines, native Xlib/Xft): - Launches with checkupdates (pacman-contrib) to list pending upgrades - ST_CHECKING: animated spinner while querying - ST_UPDATES: scrollable package list with name / old ver → new ver columns - ST_UPDATING: pkexec pacman -Syu in background, live log output, progress bar estimated from pacman's (N/M) counters - ST_DONE / ST_ERROR: success or failure screen - Refresh (r key), scroll (mouse wheel / arrow keys), Close (Esc/q) - pacman-contrib added to ISO packages Installer: add STEP_LOCALE (timezone + keyboard layout): - Inserted between STEP_DISK and STEP_USER - Timezone pane: searchable filter input + scrollable list of 37 zones - Keyboard pane: 20 common layouts with code + description - Timezone and keyboard passed as args 6/7 to orioninstall - orioninstall: sets /etc/vconsole.conf and X11 xorg.conf.d keyboard config from args; uses selected timezone for localtime symlink Also: - Right-click menu: "Software Updates" → orionpkg - Root Makefile: orionpkg target + install rule - ISO: orionpkg binary installed, permissions map, gitignore Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
53c6199102
commit
0ed61cea4c
8 files changed
+1000
-6
No files matched your search
@@ -84,6 +84,7 @@
|
||||
typedef enum {
|
||||
STEP_WELCOME = 0,
|
||||
STEP_DISK,
|
||||
STEP_LOCALE, /* timezone + keyboard layout */
|
||||
STEP_USER,
|
||||
STEP_REVIEW,
|
||||
STEP_INSTALL,
|
||||
@@ -140,6 +141,15 @@ typedef struct {
|
||||
int ndisks;
|
||||
int sel_disk;
|
||||
|
||||
/* locale selection */
|
||||
int tz_sel; /* index into TZ_LIST */
|
||||
int tz_scroll; /* first visible row in timezone pane */
|
||||
char tz_filter[48]; /* live filter text */
|
||||
int tz_filter_len;
|
||||
int tz_filter_focus;
|
||||
int kb_sel; /* index into KB_LIST */
|
||||
int kb_scroll;
|
||||
|
||||
/* user fields */
|
||||
TF tf_host, tf_user, tf_pass, tf_pass2;
|
||||
TF *focused_tf;
|
||||
@@ -422,7 +432,7 @@ static void draw_footer(Ins *s, XftDraw *xd,
|
||||
draw_line(s, 0, fy, WIN_W, fy, C_BORDER);
|
||||
|
||||
/* step dots */
|
||||
int ndots = 5; /* steps 0-4 shown as dots (5 is done) */
|
||||
int ndots = 6; /* steps 0-5 shown as dots (6 is done) */
|
||||
int dot_step = (int)s->step < ndots ? (int)s->step : ndots-1;
|
||||
for (int i = 0; i < ndots; i++) {
|
||||
int dx = WIN_W/2 - (ndots*14)/2 + i*14 + 7;
|
||||
@@ -494,6 +504,164 @@ static int validate_step(Ins *s) {
|
||||
/* Step rendering */
|
||||
/* ══════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ── locale data ─────────────────────────────────────────────────── */
|
||||
static const char *TZ_LIST[] = {
|
||||
"UTC",
|
||||
"America/New_York",
|
||||
"America/Chicago",
|
||||
"America/Denver",
|
||||
"America/Los_Angeles",
|
||||
"America/Anchorage",
|
||||
"America/Honolulu",
|
||||
"America/Toronto",
|
||||
"America/Vancouver",
|
||||
"America/Mexico_City",
|
||||
"America/Sao_Paulo",
|
||||
"America/Buenos_Aires",
|
||||
"Europe/London",
|
||||
"Europe/Paris",
|
||||
"Europe/Berlin",
|
||||
"Europe/Rome",
|
||||
"Europe/Madrid",
|
||||
"Europe/Amsterdam",
|
||||
"Europe/Stockholm",
|
||||
"Europe/Warsaw",
|
||||
"Europe/Moscow",
|
||||
"Europe/Istanbul",
|
||||
"Asia/Dubai",
|
||||
"Asia/Kolkata",
|
||||
"Asia/Dhaka",
|
||||
"Asia/Bangkok",
|
||||
"Asia/Shanghai",
|
||||
"Asia/Tokyo",
|
||||
"Asia/Seoul",
|
||||
"Asia/Singapore",
|
||||
"Australia/Sydney",
|
||||
"Australia/Perth",
|
||||
"Pacific/Auckland",
|
||||
"Pacific/Honolulu",
|
||||
"Africa/Cairo",
|
||||
"Africa/Johannesburg",
|
||||
"Africa/Lagos",
|
||||
};
|
||||
#define NTZ ((int)(sizeof(TZ_LIST)/sizeof(TZ_LIST[0])))
|
||||
|
||||
typedef struct { const char *code; const char *label; } KBLayout;
|
||||
static const KBLayout KB_LIST[] = {
|
||||
{ "us", "US English" },
|
||||
{ "gb", "UK English" },
|
||||
{ "de", "German" },
|
||||
{ "fr", "French" },
|
||||
{ "es", "Spanish" },
|
||||
{ "it", "Italian" },
|
||||
{ "pt", "Portuguese" },
|
||||
{ "br", "Portuguese (BR)" },
|
||||
{ "ru", "Russian" },
|
||||
{ "pl", "Polish" },
|
||||
{ "nl", "Dutch" },
|
||||
{ "sv", "Swedish" },
|
||||
{ "no", "Norwegian" },
|
||||
{ "da", "Danish" },
|
||||
{ "fi", "Finnish" },
|
||||
{ "tr", "Turkish" },
|
||||
{ "ar", "Arabic" },
|
||||
{ "jp", "Japanese" },
|
||||
{ "kr", "Korean" },
|
||||
{ "cn", "Chinese (Pinyin)" },
|
||||
};
|
||||
#define NKB ((int)(sizeof(KB_LIST)/sizeof(KB_LIST[0])))
|
||||
|
||||
#define LC_LIST_H 220 /* pixel height of each list pane */
|
||||
#define LC_ROW_H 22 /* row height in list */
|
||||
#define LC_ROWS_VIS (LC_LIST_H / LC_ROW_H)
|
||||
#define LC_PANE_W ((WIN_W - 60) / 2 - 6)
|
||||
|
||||
static void draw_locale(Ins *s, XftDraw *xd) {
|
||||
draw_header(s, xd, "Timezone & Keyboard");
|
||||
fill_rect(s, 0, BODY_Y, WIN_W, BODY_H, C_BODY);
|
||||
|
||||
int lx = 30, rx = WIN_W/2 + 4;
|
||||
int ty = BODY_Y + 14;
|
||||
|
||||
/* ── Timezone pane ── */
|
||||
xft_text(s, xd, s->f_head, C_TXT, lx, ty, "Timezone");
|
||||
|
||||
/* filter input */
|
||||
int fy = ty + 22;
|
||||
int factive = s->tz_filter_focus;
|
||||
unsigned long fbd = factive ? C_INPUT_ACT : C_INPUT_BD;
|
||||
fill_rect(s, lx, fy, LC_PANE_W, 26, C_INPUT_BG);
|
||||
XSetForeground(s->dpy, s->gc, mkcolor(s, fbd));
|
||||
XDrawRectangle(s->dpy, s->win, s->gc, lx, fy, LC_PANE_W-1, 25);
|
||||
const char *fdisp = s->tz_filter_len ? s->tz_filter : "";
|
||||
xft_text(s, xd, s->f_body, s->tz_filter_len ? C_TXT_INP : C_TXT_DIM,
|
||||
lx + 6, fy + 17, s->tz_filter_len ? fdisp : "Filter…");
|
||||
if (factive) {
|
||||
int cx = lx + 6 + text_w(s, s->f_body, fdisp);
|
||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_TXT_INP));
|
||||
XDrawLine(s->dpy, s->win, s->gc, cx, fy + 4, cx, fy + 21);
|
||||
}
|
||||
|
||||
/* timezone list */
|
||||
int ly = fy + 32;
|
||||
fill_rect(s, lx, ly, LC_PANE_W, LC_LIST_H, C_PANEL);
|
||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
||||
XDrawRectangle(s->dpy, s->win, s->gc, lx, ly, LC_PANE_W-1, LC_LIST_H-1);
|
||||
|
||||
int vis = 0, row = 0;
|
||||
for (int i = 0; i < NTZ && vis < LC_ROWS_VIS + s->tz_scroll; i++) {
|
||||
if (s->tz_filter_len &&
|
||||
!strstr(TZ_LIST[i], s->tz_filter)) continue;
|
||||
if (row++ < s->tz_scroll) continue;
|
||||
int ry2 = ly + vis * LC_ROW_H;
|
||||
int actual_i = i; /* track real index */
|
||||
if (actual_i == s->tz_sel)
|
||||
fill_rect(s, lx+1, ry2, LC_PANE_W-2, LC_ROW_H, C_RADIO_SEL);
|
||||
else if (vis % 2 == 1)
|
||||
fill_rect(s, lx+1, ry2, LC_PANE_W-2, LC_ROW_H, 0x141C2C);
|
||||
xft_text(s, xd, s->f_small,
|
||||
actual_i == s->tz_sel ? C_TXT_HDR : C_TXT,
|
||||
lx + 8, ry2 + LC_ROW_H - 5, TZ_LIST[i]);
|
||||
vis++;
|
||||
}
|
||||
|
||||
/* ── Keyboard pane ── */
|
||||
xft_text(s, xd, s->f_head, C_TXT, rx, ty, "Keyboard Layout");
|
||||
|
||||
int kly = ty + 22 + 32; /* align with timezone list (below filter) */
|
||||
fill_rect(s, rx, kly, LC_PANE_W, LC_LIST_H + 26, C_PANEL);
|
||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
||||
XDrawRectangle(s->dpy, s->win, s->gc, rx, kly, LC_PANE_W-1, LC_LIST_H+25);
|
||||
|
||||
int kvis = NKB < LC_ROWS_VIS + 1 ? NKB : LC_ROWS_VIS + 1;
|
||||
for (int i = s->kb_scroll; i < NKB && (i - s->kb_scroll) < kvis; i++) {
|
||||
int ky = kly + (i - s->kb_scroll) * LC_ROW_H;
|
||||
if (i == s->kb_sel)
|
||||
fill_rect(s, rx+1, ky, LC_PANE_W-2, LC_ROW_H, C_RADIO_SEL);
|
||||
else if ((i - s->kb_scroll) % 2 == 1)
|
||||
fill_rect(s, rx+1, ky, LC_PANE_W-2, LC_ROW_H, 0x141C2C);
|
||||
char kbuf[48];
|
||||
snprintf(kbuf, sizeof(kbuf), "[%s] %s",
|
||||
KB_LIST[i].code, KB_LIST[i].label);
|
||||
xft_text(s, xd, s->f_small,
|
||||
i == s->kb_sel ? C_TXT_HDR : C_TXT,
|
||||
rx + 8, ky + LC_ROW_H - 5, kbuf);
|
||||
}
|
||||
|
||||
/* selected values footer */
|
||||
int sy2 = BODY_Y + BODY_H - FOOT_H - 4;
|
||||
char sel_tz[80], sel_kb[80];
|
||||
snprintf(sel_tz, sizeof(sel_tz), "Timezone: %s",
|
||||
s->tz_sel >= 0 ? TZ_LIST[s->tz_sel] : "UTC");
|
||||
snprintf(sel_kb, sizeof(sel_kb), " | Layout: %s",
|
||||
KB_LIST[s->kb_sel].code);
|
||||
xft_text(s, xd, s->f_small, C_TXT_DIM, lx, sy2, sel_tz);
|
||||
xft_text(s, xd, s->f_small, C_TXT_DIM,
|
||||
lx + text_w(s, s->f_small, sel_tz), sy2, sel_kb);
|
||||
|
||||
draw_footer(s, xd, "← Back", "Next →", C_BTN_PRI);
|
||||
}
|
||||
|
||||
static void draw_welcome(Ins *s, XftDraw *xd) {
|
||||
draw_header(s, xd, "Welcome");
|
||||
fill_rect(s, 0, BODY_Y, WIN_W, BODY_H, C_BODY);
|
||||
@@ -746,6 +914,7 @@ static void redraw(Ins *s) {
|
||||
switch (s->step) {
|
||||
case STEP_WELCOME: draw_welcome(s, xd); break;
|
||||
case STEP_DISK: draw_disk(s, xd); break;
|
||||
case STEP_LOCALE: draw_locale(s, xd); break;
|
||||
case STEP_USER: draw_user(s, xd); break;
|
||||
case STEP_REVIEW: draw_review(s, xd); break;
|
||||
case STEP_INSTALL: draw_install(s, xd); break;
|
||||
@@ -793,6 +962,8 @@ static void start_install(Ins *s) {
|
||||
s->tf_host.buf,
|
||||
s->tf_user.buf,
|
||||
s->tf_pass.buf,
|
||||
s->tz_sel >= 0 ? TZ_LIST[s->tz_sel] : "UTC",
|
||||
KB_LIST[s->kb_sel].code,
|
||||
NULL);
|
||||
fprintf(stderr, "exec orioninstall failed: %s\n", strerror(errno));
|
||||
_exit(1);
|
||||
@@ -899,7 +1070,8 @@ static void handle_click(Ins *s, int x, int y) {
|
||||
s->step = STEP_DISK;
|
||||
if (s->ndisks == 0) detect_disks(s);
|
||||
break;
|
||||
case STEP_DISK: s->step = STEP_USER; break;
|
||||
case STEP_DISK: s->step = STEP_LOCALE; break;
|
||||
case STEP_LOCALE: s->step = STEP_USER; break;
|
||||
case STEP_USER: s->step = STEP_REVIEW; break;
|
||||
case STEP_REVIEW:
|
||||
s->step = STEP_INSTALL;
|
||||
@@ -942,6 +1114,41 @@ static void handle_click(Ins *s, int x, int y) {
|
||||
}
|
||||
}
|
||||
|
||||
/* locale pane clicks */
|
||||
if (s->step == STEP_LOCALE) {
|
||||
int lx = 30, rx = WIN_W/2 + 4;
|
||||
int ty = BODY_Y + 14;
|
||||
int fy = ty + 22;
|
||||
/* filter input focus */
|
||||
if (in_rect(x, y, lx, fy, LC_PANE_W, 26)) {
|
||||
s->tz_filter_focus = 1;
|
||||
redraw(s); return;
|
||||
} else {
|
||||
s->tz_filter_focus = 0;
|
||||
}
|
||||
/* timezone list */
|
||||
int ly = fy + 32;
|
||||
if (in_rect(x, y, lx, ly, LC_PANE_W, LC_LIST_H)) {
|
||||
int vis = 0, row = 0;
|
||||
int clicked_row = (y - ly) / LC_ROW_H;
|
||||
for (int i = 0; i < NTZ; i++) {
|
||||
if (s->tz_filter_len && !strstr(TZ_LIST[i], s->tz_filter)) continue;
|
||||
if (row++ < s->tz_scroll) continue;
|
||||
if (vis == clicked_row) { s->tz_sel = i; break; }
|
||||
vis++;
|
||||
}
|
||||
redraw(s); return;
|
||||
}
|
||||
/* keyboard list */
|
||||
int kly = ty + 22 + 32;
|
||||
if (in_rect(x, y, rx, kly, LC_PANE_W, LC_LIST_H + 26)) {
|
||||
int row2 = (y - kly) / LC_ROW_H + s->kb_scroll;
|
||||
if (row2 >= 0 && row2 < NKB) { s->kb_sel = row2; }
|
||||
redraw(s); return;
|
||||
}
|
||||
redraw(s); return;
|
||||
}
|
||||
|
||||
/* text fields */
|
||||
if (s->step == STEP_USER) {
|
||||
TF *hit = tf_at(s, x, y);
|
||||
@@ -955,6 +1162,33 @@ static void handle_click(Ins *s, int x, int y) {
|
||||
static void handle_key(Ins *s, XKeyEvent *e) {
|
||||
KeySym sym = XLookupKeysym(e, 0);
|
||||
|
||||
/* Locale step: typing into the timezone filter */
|
||||
if (s->step == STEP_LOCALE && s->tz_filter_focus) {
|
||||
if (sym == XK_BackSpace && s->tz_filter_len > 0) {
|
||||
s->tz_filter[--s->tz_filter_len] = '\0';
|
||||
s->tz_scroll = 0;
|
||||
redraw(s); return;
|
||||
}
|
||||
if (sym == XK_Escape) {
|
||||
s->tz_filter_len = 0; s->tz_filter[0] = '\0';
|
||||
s->tz_scroll = 0;
|
||||
redraw(s); return;
|
||||
}
|
||||
/* scroll list with arrow keys */
|
||||
if (sym == XK_Down) { s->tz_scroll++; redraw(s); return; }
|
||||
if (sym == XK_Up && s->tz_scroll > 0) { s->tz_scroll--; redraw(s); return; }
|
||||
char buf[8]; int len = XLookupString(e, buf, sizeof(buf)-1, NULL, NULL);
|
||||
if (len > 0 && (unsigned char)buf[0] >= 32
|
||||
&& s->tz_filter_len < (int)sizeof(s->tz_filter) - 2) {
|
||||
buf[len] = '\0';
|
||||
strcat(s->tz_filter, buf);
|
||||
s->tz_filter_len += len;
|
||||
s->tz_scroll = 0;
|
||||
redraw(s); return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Tab cycles text fields */
|
||||
if (sym == XK_Tab && s->step == STEP_USER) {
|
||||
TF *order[] = { &s->tf_host, &s->tf_user, &s->tf_pass, &s->tf_pass2 };
|
||||
@@ -1054,6 +1288,8 @@ static void init(Ins *s) {
|
||||
/* defaults */
|
||||
s->step = STEP_WELCOME;
|
||||
s->sel_disk = -1;
|
||||
s->tz_sel = 0; /* UTC */
|
||||
s->kb_sel = 0; /* us */
|
||||
s->install_fd = -1;
|
||||
s->progress = 0;
|
||||
snprintf(s->prog_msg, sizeof(s->prog_msg), "Starting…");
|
||||
|
||||
Reference in new issue
Block a user