Citadel Desktop Shell
Desktop shell components: top bar, application dock with frosted glass, theme constants, and Bastion display manager
Citadel Desktop Shell
Citadel is the desktop shell library for Aegis. It provides the top bar, application dock, and theme system that compose the desktop environment rendered by the Lumen compositor. Citadel also encompasses the Bastion display manager, which handles graphical login, session spawning, and screen locking.
v1 note: Citadel and Bastion are v1 software – functional and tested, but still evolving. Contributions are welcome – file issues or propose changes at exec/aegis.
Citadel desktop shell components:
+-------------------------------------------------------+
| Top bar (taskbar.c) clock |
| [*] Aegis HH:MM |
+-------------------------------------------------------+
| |
| Desktop area (wallpaper + windows) |
| |
| |
+-------------------------------------------------------+
| +--[dock.c: frosted glass dock]--+ |
| | [gear] [folder] [>_] [grid] | |
| +-------------------------------+ |
+-------------------------------------------------------+
Architecture
Citadel compiles to libcitadel.a, a static library linked by Lumen. It consists of two source files (dock.c, taskbar.c) and a theme header (theme.h). Citadel depends on libglyph.a for drawing primitives and font rendering.
SRCS = dock.c taskbar.c
OBJS = $(SRCS:.c=.o)
libcitadel.a: $(OBJS)
ar rcs $@ $^
Lumen integrates Citadel via two compositor callbacks:
comp.on_draw_desktop = desktop_draw_cb; /* draws top bar */
comp.on_draw_overlay = overlay_draw_cb; /* draws dock + context menu */
The desktop callback runs after the background fill but before window rendering, placing the top bar beneath all windows. The overlay callback runs after window rendering but before the framebuffer flip, placing the dock and context menu above all windows.
Top Bar (taskbar.c)
The top bar is a frosted glass strip at the top of the screen.
Rendering
void topbar_draw(surface_t *s, int screen_w, const char *clock_str);
The rendering pipeline:
- Box blur the top
TOPBAR_HEIGHT(28px) of the backbuffer at radius 8 - Dark tint via
draw_blend_rectwithTOPBAR_BG(0x001A1A2E) at alpha 128 - Bottom border: 1px white blend at alpha 20 for definition
- Accent dot: 4px filled circle at x=14 in
C_ACCENTblue - “Aegis” text: white, positioned at x=24 (TTF at 14px or bitmap fallback)
- Clock text: right-aligned with 12px margin,
TOPBAR_TEXTcolor (0x00C0C0D0)
The clock string is passed in from Lumen’s main loop, which updates it approximately once per second by checking clock_gettime(CLOCK_REALTIME) every 60 frames.
Hit Testing
int topbar_hit_aegis(int mx, int my, int screen_w);
Returns true if the click is within the “Aegis” clickable area: x < AEGIS_AREA_W (80px) and y < TOPBAR_HEIGHT (28px). Clicking this area opens the system context menu.
Theme Constants
Defined in theme.h:
| Constant | Value | Purpose |
|---|---|---|
TOPBAR_HEIGHT |
28 | Top bar height in pixels |
TOPBAR_BG |
0x001A1A2E |
Top bar tint color |
TOPBAR_TEXT |
0x00C0C0D0 |
Top bar text color (clock, etc.) |
AEGIS_AREA_W |
80 | Width of the clickable “Aegis” text area |
DESKTOP_BG |
0x001A1A2E |
Desktop background (when no wallpaper) |
Application Dock (dock.c)
The dock is a centered, frosted-glass panel at the bottom of the screen containing application launcher icons.
Layout
Dock geometry:
+-------------------------------------------+
| 24px | icon | 12px | icon | ... | 24px |
| pad | 48px | gap | 48px | | pad |
+-------------------------------------------+
^ ^
DOCK_PADDING_X DOCK_PADDING_X
DOCK_HEIGHT = DOCK_ICON_SIZE + 2 * DOCK_PADDING_Y = 48 + 32 = 80
Layout constants:
| Constant | Value |
|---|---|
DOCK_ICON_SIZE |
48 pixels |
DOCK_ICON_GAP |
12 pixels |
DOCK_PADDING_X |
24 pixels |
DOCK_PADDING_Y |
16 pixels |
DOCK_HEIGHT |
80 pixels |
DOCK_CORNER_R |
16 pixels |
DOCK_BOTTOM_MARGIN |
10 pixels |
The dock is horizontally centered: dock_x = (screen_w - dock_w) / 2. Vertically it sits DOCK_BOTTOM_MARGIN above the screen bottom.
Dock Items
Four items are defined:
| Index | Constant | Key | Icon | Action |
|---|---|---|---|---|
| 0 | DOCK_ITEM_SETTINGS |
"settings" |
Gear (circles + rectangles) | Stub (no action) |
| 1 | DOCK_ITEM_FILES |
"files" |
Folder (rounded rects) | Stub (no action) |
| 2 | DOCK_ITEM_TERMINAL |
"terminal" |
Terminal (dark rect + “>_”) | Spawns terminal window |
| 3 | DOCK_ITEM_WIDGETS |
"widgets" |
2x2 colored grid | Opens widget test window |
Frosted Glass Rendering
The dock’s frosted glass is rendered in dock_draw:
Dock frosted glass pipeline:
+--------------------------------------------+
| 1. draw_box_blur(back, x, y, w, h, 10) |
| Blur the dock region in-place |
+--------------------------------------------+
| 2. draw_blend_rect(x, y, w, h, |
| DOCK_GLASS_TINT=0x1A1A2E, alpha=160) |
| Dark translucent tint |
+--------------------------------------------+
| 3. Round corner masking |
| Pixels outside rounded rect restored |
| by sampling 1px above dock |
+--------------------------------------------+
| 4. Subtle border (top: white a=20, |
| bottom: black a=40) |
+--------------------------------------------+
| 5. Draw icons with hover highlight |
| Hover: white blend a=40 on icon area |
+--------------------------------------------+
The corner masking approximation samples the background color from one pixel above the dock. This avoids needing a saved pre-blur copy of the background.
Icon Rendering
Each dock icon is drawn programmatically (no image assets):
- Settings (gear): Filled accent circle (r=18) with 8 rectangular teeth + hollow center
- Files (folder): Two overlapping rounded rectangles in amber/brown
- Terminal: Dark rounded rectangle with “>_” text in terminal foreground color
- Widgets: Four small colored rounded rectangles arranged as a 2x2 grid (blue, green, orange, purple)
Hit Testing
int dock_hit_test(int mx, int my); /* returns item index or -1 */
First checks if the point is within the dock bounds, then iterates items checking DOCK_ICON_SIZE x DOCK_ICON_SIZE bounding boxes.
Hover State
void dock_set_hover(int item); /* -1 for no hover */
The hover item index is tracked as static state. When the hover changes, Lumen marks the dock region as a dirty rect. The hovered icon receives a DOCK_HOVER_BG (white) blend at DOCK_HOVER_ALPHA (40).
Context Menu
The system context menu is drawn by Lumen’s main.c (not Citadel) but uses Citadel’s theme colors. It opens when clicking the “Aegis” text in the top bar.
Menu Items
| Index | Label | Action |
|---|---|---|
| 0 | “About Aegis” | Opens the About window |
| 1 | “Settings…” | Stub (no action) |
| 2 | “Lock Screen” | Freezes input, signals Bastion |
| 3 | ”—” | Separator |
| 4 | “Restart” | syscall(169, 1) – system reboot |
| 5 | “Power Off” | kill(1, SIGTERM) – signal init |
Menu Rendering
The context menu uses the same frosted glass technique as the dock:
- Box blur at radius 10
- Dark tint (
MENU_BG = 0x00222238, alpha 180) - Rounded corner masking (radius 8)
- Subtle border highlights
- Items with hover highlight (
MENU_HOVER_BG = 0x003A3A58, alpha 100) - Separator rendered as a 1px line at alpha 120
Menu geometry: 160px wide, positioned at (4, TOPBAR_HEIGHT), item height 28px, separator height 10px, 8px top/bottom padding.
Bastion Display Manager
Bastion (user/bin/bastion/main.c) is the graphical login manager. It runs as a Vigil service with policy capabilities AUTH, FB, and SETUID granted via /etc/aegis/caps.d/ entries in the security policy engine.
Boot Flow
Bastion lifecycle:
+---------------------------+
| Check /proc/cmdline for |
| "boot=graphical" |
| (or --force flag) |
+---------------------------+
|
v
+---------------------------+
| Map framebuffer (513) |
| Alloc backbuffer |
| Load logo, init fonts |
+---------------------------+
|
v
+---------------------------+
| Show greeter form |
| (username + password + |
| login button) |
+---------------------------+
| (credentials)
v
+---------------------------+
| auth_check() via libauth |
| auth_elevate_session() |
| auth_set_identity(uid,gid)|
| auth_grant_shell_caps() |
+---------------------------+
|
v
+---------------------------+
| fork() + execve() |
| -> /bin/lumen |
+---------------------------+
|
v
+---------------------------+
| waitpid() for Lumen |
| Handle SIGUSR1 (lock) |
+---------------------------+
Login Form
The login form uses a horizontal layout: [username field] [password field] [Login button], centered at 75% screen height. The Aegis logo is displayed centered at the middle of the screen, loaded from /usr/share/logo.raw and rendered at 50% scale.
Network status is displayed in the top-left corner by querying SYS_NETCFG (syscall 500), showing IP address and MAC if available.
Session Spawn
Bastion uses fork+execve rather than sys_spawn to give Lumen an independent file descriptor table. Before execve, the child process:
- Calls
auth_grant_shell_caps()to populate the child’s capability table with the appropriate capability kinds for shell use - Sets environment variables (
PATH,HOME,USER,TERM) - Executes
/bin/lumen
Lock Screen Protocol
- Lumen receives
Ctrl+Alt+Lor the “Lock Screen” menu item - Lumen sets
s_input_frozen = 1, sendsSIGUSR1to Bastion (parent) - Bastion’s SIGUSR1 handler sets
s_locked = 1 - Bastion re-enters its input loop, displaying the lock form (password only, username pre-filled)
- On successful re-authentication, Bastion sends
SIGUSR2to Lumen - Lumen’s SIGUSR2 handler clears
s_input_frozen, resuming normal operation
During lock, Bastion draws over the framebuffer directly. Lumen continues compositing in the background but discards all keyboard input.
Session Restart
When Lumen exits (process terminates), Bastion reopens /dev/kbd and /dev/mouse, restores raw terminal mode, and returns to the greeter loop. This provides automatic session recovery.
Crossfade Transitions
Both Bastion and Lumen implement pixel-by-pixel crossfade transitions:
- Bastion -> Lumen: Lumen captures the framebuffer (Bastion’s login screen), composites the desktop, then fades from the old frame to the new over 15 steps (250ms)
- Text console -> Bastion: Bastion captures whatever was on screen, draws the login form, then fades between them
The crossfade formula for each pixel:
result = (old_pixel * alpha + new_pixel * (255 - alpha)) / 255;
Where alpha decreases from 255 to 0 across the transition steps.
Component Relationship
+-----------------------------------------------+
| Vigil (init) |
| spawns Bastion as a graphical service |
+-----------------------------------------------+
|
v
+-----------------------------------------------+
| Bastion (display manager) |
| user/bin/bastion/main.c |
| Links: libglyph.a (drawing + fonts) |
| Policy capabilities: AUTH, FB, SETUID |
+-----------------------------------------------+
| fork+execve on login
v
+-----------------------------------------------+
| Lumen (compositor) |
| user/bin/lumen/ |
| Links: libglyph.a + libcitadel.a |
| Baseline capabilities (FB inherited) |
+-----------------------------------------------+
| uses
v
+-----------------------------------------------+
| libcitadel.a (desktop shell) |
| user/lib/citadel/ |
| dock.c -- frosted glass dock |
| taskbar.c -- top bar with clock |
| theme.h -- shared visual constants |
+-----------------------------------------------+
| depends on
v
+-----------------------------------------------+
| libglyph.a (widget toolkit) |
| user/lib/glyph/ |
| Drawing primitives, font rendering, |
| widget tree, window management |
+-----------------------------------------------+
Source Files
| File | Path | Purpose |
|---|---|---|
dock.c |
user/lib/citadel/ |
Application dock: layout, frosted glass, icons, hit testing |
dock.h |
user/lib/citadel/ |
Dock API, geometry constants, item definitions |
taskbar.c |
user/lib/citadel/ |
Top bar: frosted glass, “Aegis” text, clock |
taskbar.h |
user/lib/citadel/ |
Top bar API declarations |
theme.h |
user/lib/citadel/ |
Shared theme constants (colors, dimensions) |
Makefile |
user/lib/citadel/ |
Builds libcitadel.a |
main.c |
user/bin/bastion/ |
Display manager: login, session spawn, lock screen |
Makefile |
user/bin/bastion/ |
Builds bastion.elf |