feat(gui): Add SUB-WT widget toolkit, icon set, modal dialogs, six apps and a reworked window manager

Turns the desktop from a fixed set of hand-drawn panels into a real
environment applications can be written against.

SUB-WT immediate-mode toolkit (gui/gui_widgets.c):
  Buttons, labels, checkboxes, radios, sliders, list boxes, text fields, tab
  bars, scrollbars, progress bars, sparklines and badges. An app feeds the WM
  event into the toolkit and then calls widgets from its paint routine, so
  each call both draws the control and reports what the user did with it --
  no retained widget tree to keep in sync with window state.

Icons and dialogs:
  gui_icons.c holds 14 16x16 palette-indexed glyphs stored as hex text, so the
  art stays hand-editable and picks up theme changes for free; they scale by
  integer factors and can be drawn as tint stencils. gui_dialog.c adds modal
  info/warning/error/confirm dialogs that dim the desktop, take exclusive
  input, word-wrap on spaces and report results through a callback.

Applications (gui/gui_apps_ext.c):
  Settings (tabbed appearance/input/power), Task Manager (live process table
  over task_find_by_pid with memory and heap gauges), Kernel Log viewer (reads
  the dmesg ring, strips ANSI, colours by severity, scrolls), KTest Runner
  (drives the in-kernel suites and reports 21/21 with timing), Clock & Calendar
  (Zeller's congruence month grid) and a Text Editor.

Window manager (gui/gui_wm.c):
  Minimize/maximize/restore buttons, a corner resize grip, edge snapping, tile
  and cascade layouts, F5-F9 shortcuts, title truncation, and index-based
  enumeration so the taskbar no longer assumes window ids stay dense.

Desktop shell (gui/gui_desktop.c):
  Launcher icon grid, richer start menu, right-click context menu, taskbar
  buttons that minimize and restore, and a live CPU trace in the tray.

Two interaction bugs fixed along the way:
  - keyboard_get_key() blocks until a key arrives, so calling it every frame
    froze the compositor; it is now gated on keyboard_has_key(), and stale
    console input is drained before the first frame.
  - When the desktop consumed a click, the WM's press-edge detector kept the
    pre-press state and read the still-held button as a fresh press on the
    next frame, stealing focus from whatever the click had just opened.
    gui_wm_sync_button_state() keeps the two layers in step.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
This commit is contained in:
subhobhai943andClaude Opus 5 committed 2026-08-25 00:18:55 +05:30
1 parent ed8922c498
commit 1aee7c7a0d
16 files changed
+3248 -335

No files matched your search

+4
View File
@@ -7,6 +7,10 @@
#include <gui/gui_wm.h>
#include <gui/gui_desktop.h>
#include <gui/gui_apps.h>
#include <gui/gui_apps_ext.h>
#include <gui/gui_widgets.h>
#include <gui/gui_icons.h>
#include <gui/gui_dialog.h>
void gui_init(void);
int gui_start_desktop(void);
+16
View File
@@ -0,0 +1,16 @@
#ifndef _GUI_APPS_EXT_H
#define _GUI_APPS_EXT_H
#include <gui/gui_wm.h>
// Second-generation desktop applications, built on the SUB-WT widget toolkit
// rather than raw framebuffer calls.
void gui_app_settings_launch(int x, int y, int w, int h);
void gui_app_taskmgr_launch(int x, int y, int w, int h);
void gui_app_logviewer_launch(int x, int y, int w, int h);
void gui_app_ktest_launch(int x, int y, int w, int h);
void gui_app_clock_launch(int x, int y, int w, int h);
void gui_app_editor_launch(int x, int y, int w, int h);
#endif // _GUI_APPS_EXT_H
+18 -3
View File
@@ -4,16 +4,31 @@
#include <stdint.h>
#include <stdbool.h>
#define GUI_TASKBAR_HEIGHT 32
#define GUI_TASKBAR_HEIGHT 32
#define GUI_DESKTOP_ICON_W 72
#define GUI_DESKTOP_ICON_H 64
void gui_desktop_init(void);
void gui_desktop_render_background(void);
void gui_desktop_render_icons(void);
void gui_desktop_render_taskbar(void);
void gui_desktop_render_start_menu(void);
void gui_desktop_render_context_menu(void);
void gui_desktop_toggle_start_menu(void);
bool gui_desktop_is_start_menu_open(void);
void gui_desktop_handle_taskbar_click(int mx, int my);
void gui_desktop_open_context_menu(int mx, int my);
void gui_desktop_close_menus(void);
int gui_desktop_run(void);
// Returns true if the click was consumed by desktop chrome (taskbar, menus,
// icons) rather than falling through to the window manager.
bool gui_desktop_handle_click(int mx, int my);
// Height of the area windows may occupy (screen minus taskbar).
int gui_desktop_workarea_height(void);
void gui_desktop_request_exit(void);
int gui_desktop_run(void);
#endif // _GUI_DESKTOP_H
+42
View File
@@ -0,0 +1,42 @@
#ifndef _GUI_DIALOG_H
#define _GUI_DIALOG_H
#include <stdint.h>
#include <stdbool.h>
#include <gui/gui_icons.h>
// Modal dialogs. Only one is on screen at a time; while it is up the desktop
// dims behind it and the compositor routes every click to the dialog, so no
// window underneath can be interacted with.
typedef enum {
GUI_DIALOG_INFO,
GUI_DIALOG_WARNING,
GUI_DIALOG_CONFIRM,
GUI_DIALOG_ERROR
} gui_dialog_kind_t;
typedef enum {
GUI_DIALOG_RESULT_NONE = 0,
GUI_DIALOG_RESULT_OK,
GUI_DIALOG_RESULT_CANCEL
} gui_dialog_result_t;
typedef void (*gui_dialog_cb_t)(gui_dialog_result_t result, void* ctx);
void gui_dialog_init(void);
void gui_dialog_show(gui_dialog_kind_t kind, const char* title, const char* message);
void gui_dialog_confirm(const char* title, const char* message,
gui_dialog_cb_t on_result, void* ctx);
void gui_dialog_dismiss(void);
bool gui_dialog_is_open(void);
// Returns true when the dialog consumed the input.
bool gui_dialog_handle_mouse(int mx, int my, bool clicked);
bool gui_dialog_handle_key(uint16_t key);
void gui_dialog_render(void);
#endif // _GUI_DIALOG_H
+40
View File
@@ -0,0 +1,40 @@
#ifndef _GUI_ICONS_H
#define _GUI_ICONS_H
#include <stdint.h>
#include <stdbool.h>
// 16x16 palette-indexed icon set. Each glyph stores one nibble per pixel
// indexing a 16-entry ARGB palette, so the whole set costs 128 bytes an icon
// and can be recoloured per theme without touching the bitmaps.
#define GUI_ICON_SIZE 16
typedef enum {
GUI_ICON_TERMINAL = 0,
GUI_ICON_MONITOR,
GUI_ICON_FOLDER,
GUI_ICON_CALC,
GUI_ICON_PAINT,
GUI_ICON_INFO,
GUI_ICON_SETTINGS,
GUI_ICON_TASKS,
GUI_ICON_LOG,
GUI_ICON_FLASK,
GUI_ICON_CLOCK,
GUI_ICON_FILE,
GUI_ICON_POWER,
GUI_ICON_WARNING,
GUI_ICON_COUNT
} gui_icon_id_t;
void gui_icons_init(void);
// Draw at native 16x16, or scaled by an integer factor (2 = 32x32).
void gui_icon_draw(gui_icon_id_t id, int x, int y);
void gui_icon_draw_scaled(gui_icon_id_t id, int x, int y, int scale);
void gui_icon_draw_tinted(gui_icon_id_t id, int x, int y, int scale, uint32_t tint);
const char* gui_icon_name(gui_icon_id_t id);
#endif // _GUI_ICONS_H
+86
View File
@@ -0,0 +1,86 @@
#ifndef _GUI_WIDGETS_H
#define _GUI_WIDGETS_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <gui/gui_wm.h>
#include <gui/gui_gfx.h>
#include <gui/gui_theme.h>
// SUB-WT: immediate-mode widget toolkit for SUB-OS desktop applications.
//
// An app feeds the toolkit whatever event the window manager delivered
// (gui_widget_feed_event) and then simply calls widget functions from inside
// its paint routine. Each call both draws the control and reports what the
// user did with it, so no retained widget tree has to be kept in sync with
// the window's state.
//
// static void my_paint(gui_window_t* win) {
// gui_widget_begin(win);
// if (gui_button(1, 10, 10, 90, 24, "Refresh")) do_refresh();
// gui_checkbox(2, 10, 44, "Verbose", &verbose);
// gui_widget_end();
// }
#define GUI_FONT_W 8
#define GUI_FONT_H 8
#define GUI_FONT16_H 16
#define GUI_WIDGET_ROW_H 22
typedef enum {
GUI_ALIGN_LEFT,
GUI_ALIGN_CENTER,
GUI_ALIGN_RIGHT
} gui_align_t;
// Per-frame input snapshot the widgets consult.
typedef struct {
int mouse_x; // Window-relative, client area origin
int mouse_y;
bool mouse_down; // Button currently held
bool mouse_clicked; // Press edge, consumed by the first widget hit
bool mouse_released;
uint16_t key; // Pending keystroke, consumed by the focused field
int hot_id; // Widget under the cursor this frame
int active_id; // Widget holding the press
int focus_id; // Widget receiving keystrokes
} gui_widget_input_t;
// Called from an app's handle_event to record what the WM delivered.
void gui_widget_feed_event(gui_window_t* win, const gui_event_t* ev);
// Frame scope. Everything between these two is drawn in client-area
// coordinates: (0,0) is the top-left pixel below the title bar.
void gui_widget_begin(gui_window_t* win);
void gui_widget_end(void);
const gui_widget_input_t* gui_widget_get_input(void);
void gui_widget_set_focus(int id);
int gui_widget_client_width(void);
int gui_widget_client_height(void);
// --- Static content ---------------------------------------------------------
void gui_label(int x, int y, const char* text, uint32_t color);
void gui_label_bold(int x, int y, const char* text, uint32_t color);
void gui_label_aligned(int x, int y, int w, const char* text, uint32_t color, gui_align_t align);
void gui_panel(int x, int y, int w, int h, const char* title);
void gui_separator(int x, int y, int w);
void gui_progress_bar(int x, int y, int w, int h, int percent, uint32_t fill);
void gui_sparkline(int x, int y, int w, int h, const uint8_t* samples, int count, uint32_t color);
void gui_badge(int x, int y, const char* text, uint32_t bg, uint32_t fg);
// --- Interactive controls ---------------------------------------------------
// Every control takes a caller-assigned id that must be unique and stable
// within one window.
bool gui_button(int id, int x, int y, int w, int h, const char* label);
bool gui_button_colored(int id, int x, int y, int w, int h, const char* label, uint32_t accent);
bool gui_checkbox(int id, int x, int y, const char* label, bool* value);
bool gui_radio(int id, int x, int y, const char* label, int* selected, int this_value);
bool gui_slider(int id, int x, int y, int w, int* value, int min_val, int max_val);
bool gui_listbox(int id, int x, int y, int w, int h, const char* const* items, int count, int* selected);
bool gui_textfield(int id, int x, int y, int w, char* buffer, size_t capacity);
int gui_tabbar(int id, int x, int y, int w, const char* const* labels, int count, int* active);
bool gui_scrollbar(int id, int x, int y, int h, int* offset, int total, int visible);
#endif // _GUI_WIDGETS_H
+59 -12
View File
@@ -7,8 +7,11 @@
#include <gui/gui_gfx.h>
#include <gui/gui_theme.h>
#define GUI_MAX_WINDOWS 16
#define GUI_TITLEBAR_HEIGHT 24
#define GUI_MAX_WINDOWS 16
#define GUI_TITLEBAR_HEIGHT 24
#define GUI_RESIZE_GRIP 12
#define GUI_MIN_WINDOW_W 160
#define GUI_MIN_WINDOW_H 100
typedef enum {
GUI_EVENT_MOUSE_MOVE,
@@ -16,6 +19,7 @@ typedef enum {
GUI_EVENT_MOUSE_UP,
GUI_EVENT_KEY_DOWN,
GUI_EVENT_FOCUS,
GUI_EVENT_RESIZE,
GUI_EVENT_CLOSE
} gui_event_type_t;
@@ -30,19 +34,40 @@ typedef struct {
uint16_t key;
} gui_event_t;
// Where a window sits relative to the screen edges.
typedef enum {
GUI_SNAP_NONE = 0,
GUI_SNAP_LEFT,
GUI_SNAP_RIGHT,
GUI_SNAP_MAXIMIZED
} gui_snap_t;
typedef struct gui_window {
int id;
int id;
char title[64];
int x;
int y;
int width;
int height;
int x;
int y;
int width;
int height;
bool active;
bool minimized;
bool visible;
bool resizable;
// Drag / resize interaction state
bool is_dragging;
int drag_off_x;
int drag_off_y;
bool is_resizing;
int drag_off_x;
int drag_off_y;
// Geometry remembered across maximize / snap so restore is exact
gui_snap_t snap;
int saved_x;
int saved_y;
int saved_width;
int saved_height;
void* user_data;
void (*paint)(struct gui_window* win);
@@ -50,12 +75,34 @@ typedef struct gui_window {
} gui_window_t;
void gui_wm_init(void);
// The work area excludes the taskbar; windows maximize and snap inside it.
void gui_wm_set_workarea(int width, int height);
gui_window_t* gui_wm_create_window(const char* title, int x, int y, int w, int h);
void gui_wm_destroy_window(int win_id);
void gui_wm_focus_window(int win_id);
void gui_wm_destroy_window(int win_id);
void gui_wm_focus_window(int win_id);
gui_window_t* gui_wm_get_window(int win_id);
gui_window_t* gui_wm_get_active_window(void);
int gui_wm_get_window_count(void);
int gui_wm_get_window_count(void);
// Enumerate in z-order, bottom-most first. Returns NULL past the end.
gui_window_t* gui_wm_get_window_at_index(int index);
void gui_wm_minimize_window(int win_id);
void gui_wm_restore_window(int win_id);
void gui_wm_toggle_maximize(int win_id);
void gui_wm_snap_window(int win_id, gui_snap_t snap);
void gui_wm_close_active(void);
void gui_wm_cycle_focus(void);
void gui_wm_cascade_windows(void);
void gui_wm_tile_windows(void);
// Keep the WM's press-edge detector in step when another layer (a menu, a
// modal dialog) consumed the click instead. Without this the WM still holds
// the pre-press state and reads the still-held button as a fresh press on the
// following frame, stealing focus from whatever the click just opened.
void gui_wm_sync_button_state(bool btn_left);
void gui_wm_handle_mouse(int x, int y, bool btn_left, bool btn_right);
void gui_wm_handle_key(uint16_t key);