Phase 4-6: Quill editor, Lens viewer, Rigel context menu, CI, website
Phase 4 — native apps: - quill/: text editor (monospace, double-buffered, find bar, undo, open/save) - lens/: image viewer using imlib2 (zoom, pan, rotate, directory nav) - wm/src/menu.c: launch quill instead of mousepad - iso/docker/entrypoint.sh: add imlib2 package; install quill + lens binaries - skykit/template/: developer app template demonstrating the SkyKit API Phase 5 — file system and search: - rigel/rigel.c: right-click context menu (open, open in quill, copy path, rename, trash, properties); Ctrl+F search/filter bar with name highlighting; F2 rename-in-place overlay; Delete key moves to trash Phase 6 — distribution: - .github/workflows/build-iso.yml: GitHub Actions CI that compiles all components and builds a bootable ISO on every tag push; creates a GitHub release with sha256 checksums Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
d19aca2333
commit
a9efede702
12 files changed
+2186
-92
No files matched your search
@@ -0,0 +1,14 @@
|
||||
CC = gcc
|
||||
CFLAGS = -O2 -Wall -I.. $(shell pkg-config --cflags x11 xft fontconfig)
|
||||
LIBS = -L.. -lskykit $(shell pkg-config --libs x11 xft fontconfig)
|
||||
|
||||
hello: hello.c ../libskykit.a
|
||||
$(CC) $(CFLAGS) -o hello hello.c $(LIBS)
|
||||
|
||||
../libskykit.a:
|
||||
$(MAKE) -C ..
|
||||
|
||||
clean:
|
||||
rm -f hello
|
||||
|
||||
.PHONY: clean
|
||||
@@ -0,0 +1,146 @@
|
||||
/* hello.c — minimal SkyKit application template
|
||||
*
|
||||
* Build:
|
||||
* cd skykit && make (builds libskykit.a)
|
||||
* cd template
|
||||
* gcc -O2 hello.c -I.. -L.. -lskykit \
|
||||
* $(pkg-config --libs --cflags x11 xft fontconfig) -o hello
|
||||
*
|
||||
* This template shows the minimum boilerplate for a native OrionOS app:
|
||||
* - sk_app_init() opens the display and loads fonts
|
||||
* - Create a window and a Pixmap back-buffer
|
||||
* - Wrap them in an SKPainter
|
||||
* - Draw to the Pixmap, then XCopyArea to the window
|
||||
* - Respond to Expose, KeyPress, ButtonPress, ClientMessage
|
||||
*/
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "skykit.h"
|
||||
|
||||
#define WIN_W 640
|
||||
#define WIN_H 400
|
||||
|
||||
int main(void) {
|
||||
SKApp app;
|
||||
sk_app_init(&app);
|
||||
|
||||
/* ── Window ──────────────────────────────────────────── */
|
||||
XSetWindowAttributes swa = {
|
||||
.background_pixel = sk_color(&app, SK_BG),
|
||||
.event_mask = ExposureMask | KeyPressMask
|
||||
| ButtonPressMask | StructureNotifyMask,
|
||||
};
|
||||
Window win = XCreateWindow(
|
||||
app.dpy, app.root,
|
||||
200, 100, WIN_W, WIN_H, 0,
|
||||
app.depth, InputOutput, app.vis,
|
||||
CWBackPixel | CWEventMask, &swa);
|
||||
|
||||
/* Back-buffer for flicker-free rendering */
|
||||
GC gc = XCreateGC(app.dpy, win, 0, NULL);
|
||||
Pixmap buf = XCreatePixmap(app.dpy, win, WIN_W, WIN_H, app.depth);
|
||||
|
||||
/* SKPainter wraps the back-buffer */
|
||||
SKPainter p = { .app = &app, .drw = buf, .gc = gc };
|
||||
|
||||
/* WM_DELETE_WINDOW protocol */
|
||||
Atom wm_del = XInternAtom(app.dpy, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(app.dpy, win, &wm_del, 1);
|
||||
|
||||
XStoreName(app.dpy, win, "Hello OrionOS");
|
||||
XClassHint *ch = XAllocClassHint();
|
||||
if (ch) { ch->res_name = (char*)"hello"; ch->res_class = (char*)"Hello"; XSetClassHint(app.dpy, win, ch); XFree(ch); }
|
||||
|
||||
XMapWindow(app.dpy, win);
|
||||
XFlush(app.dpy);
|
||||
|
||||
/* Click counter for demo */
|
||||
int clicks = 0;
|
||||
|
||||
/* ── Draw function ───────────────────────────────────── */
|
||||
/* We define a lambda-style local redraw — in a real app this would be
|
||||
* a proper function taking your app struct. */
|
||||
#define REDRAW() do { \
|
||||
sk_fill(&p, SK_BG, 0, 0, WIN_W, WIN_H); \
|
||||
\
|
||||
/* Accent bar at top */ \
|
||||
sk_fill(&p, SK_ACCENT, 0, 0, WIN_W, 3); \
|
||||
\
|
||||
/* Centred heading */ \
|
||||
const char *title = "Hello, OrionOS"; \
|
||||
int tw = sk_textw(&app, app.font_hdr, title); \
|
||||
sk_text(&p, app.font_hdr, SK_TEXT_HDR, \
|
||||
(WIN_W - tw) / 2, sk_baseline(app.font_hdr, 60, 32), title); \
|
||||
\
|
||||
/* Subtitle */ \
|
||||
const char *sub = "A SkyKit native application"; \
|
||||
int sw = sk_textw(&app, app.font_ui, sub); \
|
||||
sk_text(&p, app.font_ui, SK_TEXT_DIM, \
|
||||
(WIN_W - sw) / 2, sk_baseline(app.font_ui, 100, 24), sub); \
|
||||
\
|
||||
/* Click counter button */ \
|
||||
SKBtn btn = { (WIN_W - 160) / 2, 160, 160, 36, "Click me", 1 }; \
|
||||
sk_draw_btn(&p, &btn, 0); \
|
||||
\
|
||||
/* Counter label */ \
|
||||
char cnt[64]; snprintf(cnt, sizeof(cnt), "Clicked %d time%s", clicks, clicks==1?"":"s"); \
|
||||
int cw = sk_textw(&app, app.font_ui, cnt); \
|
||||
sk_text(&p, app.font_ui, SK_TEXT, (WIN_W - cw) / 2, \
|
||||
sk_baseline(app.font_ui, 215, 24), cnt); \
|
||||
\
|
||||
/* Hint */ \
|
||||
const char *hint = "Press Q or Esc to quit"; \
|
||||
int hw = sk_textw(&app, app.font_sm, hint); \
|
||||
sk_text(&p, app.font_sm, SK_TEXT_DIM, (WIN_W - hw) / 2, \
|
||||
sk_baseline(app.font_sm, WIN_H - 36, 24), hint); \
|
||||
\
|
||||
/* Blit to window */ \
|
||||
XCopyArea(app.dpy, buf, win, gc, 0, 0, WIN_W, WIN_H, 0, 0); \
|
||||
XFlush(app.dpy); \
|
||||
} while (0)
|
||||
|
||||
REDRAW();
|
||||
|
||||
/* ── Event loop ──────────────────────────────────────── */
|
||||
int running = 1;
|
||||
while (running) {
|
||||
XEvent ev;
|
||||
XNextEvent(app.dpy, &ev);
|
||||
switch (ev.type) {
|
||||
case Expose:
|
||||
if (ev.xexpose.count == 0) REDRAW();
|
||||
break;
|
||||
case KeyPress: {
|
||||
KeySym ks = XLookupKeysym(&ev.xkey, 0);
|
||||
if (ks == XK_q || ks == XK_Q || ks == XK_Escape) running = 0;
|
||||
break;
|
||||
}
|
||||
case ButtonPress:
|
||||
if (ev.xbutton.button == Button1) {
|
||||
/* check if inside the button */
|
||||
int bx = (WIN_W - 160) / 2, by = 160;
|
||||
if (sk_in_rect(ev.xbutton.x, ev.xbutton.y, bx, by, 160, 36)) {
|
||||
clicks++;
|
||||
REDRAW();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ClientMessage:
|
||||
if ((Atom)ev.xclient.data.l[0] == wm_del) running = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef REDRAW
|
||||
|
||||
sk_app_free(&app);
|
||||
XFreePixmap(app.dpy, buf);
|
||||
XFreeGC(app.dpy, gc);
|
||||
XDestroyWindow(app.dpy, win);
|
||||
XCloseDisplay(app.dpy);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user