SkyKit (skykit/): - Shared palette constants, font setup, and Xlib/Xft drawing utilities - sk_fill, sk_rect, sk_line, sk_text, sk_text_clip, sk_textw, sk_baseline - Builds as libskykit.a, consumed by Rigel and future shell components Rigel (rigel/): - Native C/Xlib file manager with SkyKit - Sidebar with 8 bookmarks (Home, Desktop, Documents, Downloads, etc.) - Editable path bar (Ctrl+L or '/' to activate, Enter to navigate) - Sortable columns: Name / Size / Modified (click header to sort/reverse) - Colored type badges: DIR, IMG, SND, VID, ZIP, SRC, PDF, TXT, EXE - Double-click to open dirs or files (xdg-open) - Keyboard: ↑↓ select, Enter open, Backspace back, Ctrl+H toggle hidden - Right-click menu updated: "File Manager" now launches rigel Text centering fix (deskbar + wm): - Root cause: draw_str added glyph-specific ext.height/ext.y offset, and all callers used hardcoded (H-10)/2 magic numbers instead of font metrics - Fix: draw_str now takes y as a direct baseline; str_baseline() computes (strip_y + strip_h + ascent - descent) / 2 for consistent centering - WM titlebar: same fix using font_title->ascent/descent - Affects: "Orion ▾" button, clock, date, app list, flyout menu items, letter icons, and all window titlebars Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
114 lines
4.7 KiB
C
114 lines
4.7 KiB
C
/* skykit.c — OrionOS native UI toolkit implementation */
|
|
#include "skykit.h"
|
|
|
|
void sk_app_init(SKApp *app) {
|
|
app->dpy = XOpenDisplay(NULL);
|
|
if (!app->dpy) { fputs("skykit: cannot open display\n", stderr); exit(1); }
|
|
app->screen = DefaultScreen(app->dpy);
|
|
app->root = RootWindow(app->dpy, app->screen);
|
|
app->cmap = DefaultColormap(app->dpy, app->screen);
|
|
app->vis = DefaultVisual(app->dpy, app->screen);
|
|
app->depth = DefaultDepth(app->dpy, app->screen);
|
|
|
|
app->font_ui = XftFontOpenName(app->dpy, app->screen, SK_FONT_UI);
|
|
app->font_sm = XftFontOpenName(app->dpy, app->screen, SK_FONT_SM);
|
|
app->font_hdr = XftFontOpenName(app->dpy, app->screen, SK_FONT_HDR);
|
|
app->font_mono = XftFontOpenName(app->dpy, app->screen, SK_FONT_MONO);
|
|
if (!app->font_ui) { fputs("skykit: cannot open UI font\n", stderr); exit(1); }
|
|
if (!app->font_sm) app->font_sm = app->font_ui;
|
|
if (!app->font_hdr) app->font_hdr = app->font_ui;
|
|
if (!app->font_mono) app->font_mono = app->font_ui;
|
|
}
|
|
|
|
void sk_app_free(SKApp *app) {
|
|
if (app->font_ui) XftFontClose(app->dpy, app->font_ui);
|
|
if (app->font_sm && app->font_sm != app->font_ui) XftFontClose(app->dpy, app->font_sm);
|
|
if (app->font_hdr && app->font_hdr != app->font_ui) XftFontClose(app->dpy, app->font_hdr);
|
|
if (app->font_mono && app->font_mono != app->font_ui) XftFontClose(app->dpy, app->font_mono);
|
|
XCloseDisplay(app->dpy);
|
|
}
|
|
|
|
unsigned long sk_color(SKApp *app, unsigned long rgb) {
|
|
XColor c = {
|
|
.red = ((rgb >> 16) & 0xFF) * 257,
|
|
.green = ((rgb >> 8) & 0xFF) * 257,
|
|
.blue = ( rgb & 0xFF) * 257,
|
|
.flags = DoRed | DoGreen | DoBlue
|
|
};
|
|
XAllocColor(app->dpy, app->cmap, &c);
|
|
return c.pixel;
|
|
}
|
|
|
|
void sk_xft_color(SKApp *app, unsigned long rgb, XftColor *out) {
|
|
XRenderColor rc = {
|
|
.red = ((rgb >> 16) & 0xFF) * 257,
|
|
.green = ((rgb >> 8) & 0xFF) * 257,
|
|
.blue = ( rgb & 0xFF) * 257,
|
|
.alpha = 0xFFFF
|
|
};
|
|
XftColorAllocValue(app->dpy, app->vis, app->cmap, &rc, out);
|
|
}
|
|
|
|
void sk_fill(SKPainter *p, unsigned long rgb, int x, int y, int w, int h) {
|
|
XSetForeground(p->app->dpy, p->gc, sk_color(p->app, rgb));
|
|
XFillRectangle(p->app->dpy, p->drw, p->gc, x, y, (unsigned)w, (unsigned)h);
|
|
}
|
|
|
|
void sk_rect(SKPainter *p, unsigned long rgb, int x, int y, int w, int h) {
|
|
XSetForeground(p->app->dpy, p->gc, sk_color(p->app, rgb));
|
|
XDrawRectangle(p->app->dpy, p->drw, p->gc, x, y, (unsigned)(w-1), (unsigned)(h-1));
|
|
}
|
|
|
|
void sk_line(SKPainter *p, unsigned long rgb, int x1, int y1, int x2, int y2) {
|
|
XSetForeground(p->app->dpy, p->gc, sk_color(p->app, rgb));
|
|
XDrawLine(p->app->dpy, p->drw, p->gc, x1, y1, x2, y2);
|
|
}
|
|
|
|
void sk_text(SKPainter *p, XftFont *font, unsigned long rgb,
|
|
int x, int y, const char *s) {
|
|
if (!s || !s[0]) return;
|
|
XftDraw *xd = XftDrawCreate(p->app->dpy, p->drw, p->app->vis, p->app->cmap);
|
|
XftColor col; sk_xft_color(p->app, rgb, &col);
|
|
XftDrawStringUtf8(xd, &col, font, x, y, (const FcChar8 *)s, (int)strlen(s));
|
|
XftColorFree(p->app->dpy, p->app->vis, p->app->cmap, &col);
|
|
XftDrawDestroy(xd);
|
|
}
|
|
|
|
void sk_text_clip(SKPainter *p, XftFont *font, unsigned long rgb,
|
|
int x, int y, const char *s,
|
|
int cx, int cy, int cw, int ch) {
|
|
if (!s || !s[0]) return;
|
|
XftDraw *xd = XftDrawCreate(p->app->dpy, p->drw, p->app->vis, p->app->cmap);
|
|
XRectangle clip = { (short)cx, (short)cy, (unsigned short)cw, (unsigned short)ch };
|
|
XftDrawSetClipRectangles(xd, 0, 0, &clip, 1);
|
|
XftColor col; sk_xft_color(p->app, rgb, &col);
|
|
XftDrawStringUtf8(xd, &col, font, x, y, (const FcChar8 *)s, (int)strlen(s));
|
|
XftColorFree(p->app->dpy, p->app->vis, p->app->cmap, &col);
|
|
XftDrawSetClip(xd, None);
|
|
XftDrawDestroy(xd);
|
|
}
|
|
|
|
int sk_textw(SKApp *app, XftFont *font, const char *s) {
|
|
if (!s || !s[0]) return 0;
|
|
XGlyphInfo ext;
|
|
XftTextExtentsUtf8(app->dpy, font, (const FcChar8 *)s, (int)strlen(s), &ext);
|
|
return ext.xOff;
|
|
}
|
|
|
|
int sk_baseline(XftFont *font, int y, int h) {
|
|
return y + (h + font->ascent - font->descent) / 2;
|
|
}
|
|
|
|
int sk_in_rect(int mx, int my, int x, int y, int w, int h) {
|
|
return mx >= x && mx < x + w && my >= y && my < y + h;
|
|
}
|
|
|
|
void sk_draw_btn(SKPainter *p, SKApp *app, XftFont *font, const SKBtn *b,
|
|
int hovered, unsigned long bg, unsigned long bghov) {
|
|
unsigned long bbg = hovered ? bghov : bg;
|
|
sk_fill(p, bbg, b->x, b->y, b->w, b->h);
|
|
sk_rect(p, SK_BORDER, b->x, b->y, b->w, b->h);
|
|
int tx = b->x + (b->w - sk_textw(app, font, b->label)) / 2;
|
|
sk_text(p, font, SK_TEXT_HDR, tx, sk_baseline(font, b->y, b->h), b->label);
|
|
}
|