PHASE II · SURFACE / MODULE 04 · · FREE

Windows & a Desktop

Primitives become a system. Build a window manager that stacks, drags, and resizes windows; a global chrome so every titlebar matches; and a dock. This is where a pile of pixels becomes a desktop.

Recommended test path

Build and boot in QEMU first. Follow the exact QEMU, USB and real-PC deployment guide before changing disks or firmware settings.

A window is just a rectangle that remembers its position, size, title, and z-order. A window manager is the code that stacks them, decides which one the mouse is over, and lets you drag and resize. Build it in that order.

Lesson 4.1

4.1 A window struct and the stack

the data behind every window
window.ccopy
typedef struct {
    int  x, y, w, h;
    const char *title;
    int  z;              // stacking order; higher = on top
    int  focused;
    int  minimized;
    void (*draw_content)(struct Window*); // each app fills this
} Window;

static Window windows[MAX_WINDOWS];

// draw back-to-front so higher-z windows land on top
void wm_draw_all(void) {
    sort_by_z(windows);
    for (int i = 0; i < window_count; i++)
        if (!windows[i].minimized) draw_window(&windows[i]);
}
Lesson 4.2

4.2 Global window chrome

one titlebar renderer, every window

The mistake to avoid: letting each app draw its own titlebar. They drift apart instantly. Instead, one chrome function draws the frame — titlebar, border, shadow, close/min/max buttons, active vs inactive treatment — for every window. Apps only fill the content area. Change the look in one place, every window updates.

chrome.c — the shared framecopy
// spec-driven constants: change here, whole OS follows
#define TITLE_H   40
#define RADIUS    10
#define CTRL_SIZE 28

void chrome_draw_frame(Window *win) {
    int focused = win->focused;
    UINT32 body   = focused ? 0x141B27 : 0x0F1622;
    UINT32 title  = focused ? 0xE8EDF4 : 0x64738A;

    draw_shadow(win->x, win->y, win->w, win->h);
    draw_rounded_rect(win->x, win->y, win->w, win->h, RADIUS, body);
    draw_rounded_rect(win->x, win->y, win->w, TITLE_H, RADIUS, 0x101724);
    draw_string(win->x+16, win->y+12, win->title, title);
    draw_window_controls(win, focused);   // close/min/max, right-aligned
}
Active vs inactive is what sells "real"

A focused window gets bright title text, a solid border, and a deeper shadow; an unfocused one goes dim, flatter, and its controls stop reacting to hover. That single contrast is most of what makes a desktop read as a real OS rather than a mockup. Bake it into the chrome from the start.

Lesson 4.3

4.3 Dragging and resizing

make the windows move

Dragging is bookkeeping: on mouse-down in the titlebar, record the offset between the cursor and the window's corner; on every mouse-move while held, move the window to keep that offset constant. Resizing is the same idea on the edges, adjusting width/height instead of position.

drag.ccopy
static int drag_dx, drag_dy;
static Window *dragging;

void on_mouse_down(int mx, int my) {
    Window *w = window_at(mx, my);
    if (w && in_titlebar(w, mx, my)) {
        dragging = w;
        drag_dx = mx - w->x;   // remember grab offset
        drag_dy = my - w->y;
    }
}

void on_mouse_move(int mx, int my) {
    if (dragging) {
        mark_dirty(dragging);           // erase old position
        dragging->x = mx - drag_dx;
        dragging->y = my - drag_dy;
        mark_dirty(dragging);           // draw new position
    }
}
Lesson 4.4

4.4 Hit-testing and focus

which window is the mouse over?

When the mouse clicks, you need the topmost window under it. Walk the stack from highest z to lowest; the first window whose rectangle contains the point wins. Clicking it raises it to the top and gives it focus.

hittest.ccopy
Window *window_at(int mx, int my) {
    // highest z first — topmost window wins
    for (int i = window_count - 1; i >= 0; i--) {
        Window *w = z_order[i];
        if (!w->minimized && point_in_rect(mx, my, w->x, w->y, w->w, w->h))
            return w;
    }
    return 0;   // clicked the desktop
}
Lesson 4.5

4.5 A dock and the desktop

launchers and a place to click

The desktop is the bottom layer: a wallpaper fill, a row of dock icons that open apps, and desktop icons. It's the same primitives — rects, text, hit-testing — assembled into a launcher. Click a dock icon, spawn a window, and the loop is complete: you have a desktop you can actually use.

Module 04 checkpoint
  • A window struct with z-order and a content callback
  • One global chrome renderer — every window matches
  • Draggable titlebars and resizable edges
  • Top-down hit-testing and click-to-focus
  • A dock that launches apps onto a real desktop
next module

Module 05 — USB & a Filesystem

Claim the xHCI controller from the firmware, talk to a USB drive over Bulk-Only Transport, and read & write real FAT32 files — then a working file manager on top.

See pricing — from $9/mo or $149 once →