Transformed 8 stub articles (720 lines total) into full bootcamp-grade references (5,100+ lines) with architecture diagrams, complete code examples, struct field references, pitfalls, and best practices. IDCMP (idcmp.md — 1,060 lines): - IntuiMessage field reference with types, sizes, value ranges - Use-case cookbook: double-click, rubber-band, multi-signal, BOOPSI - When to use IDCMP vs alternatives (decision flowchart) - 5 named antipatterns with WRONG/RIGHT code - Memory safety checklist and defensive event loop template - Cross-platform comparison table (Win32, X11, Cocoa, Qt) Input Events (input_events.md — 850 lines): - Event class routing and QoS analysis (priority-as-QoS hierarchy) - Intuition consumption table (what survives the handler chain) - lowlevel.library bypass for CD32/game input - Latency analysis with pipeline timing budget (68000 vs 68040) - Input strategy comparison (IDCMP vs handler vs direct hardware) - Game input patterns: direct HW polling, CIA keyboard, hybrid handler - Signal pattern for proper handler→application communication Windows (windows.md — 370 lines): - Window anatomy diagram, WA_ tag reference tables - Refresh modes comparison (Simple/Smart/SuperBitMap) - Window types: standard, backdrop, borderless, GimmeZeroZero - Coordinate system, border offsets, struct Window fields - Modification API (move, resize, title, busy pointer) Gadgets (gadgets.md — 403 lines): - Three-generation evolution (raw/GadTools/BOOPSI) - Complete GadTools lifecycle with setup, creation, events, cleanup - Runtime state updates (GadTools vs raw Intuition) - Raw struct Gadget: GFLG_*, GACT_*, GTYP_* flag tables - Proportional and string gadget internals BOOPSI (boopsi.md — 505 lines): - Class hierarchy Mermaid diagram - Method dispatch sequence diagram - ICA interconnection architecture (icclass, modelclass, ICTARGET_IDCMP) - Full custom gadget class tutorial (4 steps with complete code) - Built-in class reference table - C++/Qt analog comparison table Menus (menus.md — 378 lines): - Menu hierarchy diagram (Menu → Item → Sub-Item) - GadTools NewMenu workflow with field reference - Event handling with multi-select chain walking - Checkmark/mutual exclusion, sub-menus, dynamic modification - Keyboard shortcut system (single-char and NM_COMMANDSTRING) Requesters (requesters.md — 370 lines): - EasyRequest return value logic table - ASL file requester with multi-select and full tag reference - ASL font and screenmode requesters - Non-blocking BuildEasyRequest/SysReqHandler pattern - Requester state persistence IntuitionBase (intuition_base.md — 267 lines): - Library version table (OS 1.2 through 3.2.x) - Struct field reference with safety annotations - ViewLord architecture diagram - LockIBase vs Forbid/Permit guidance - Complete library function overview (5 categories) README index updated with enriched article descriptions.
12 KiB
Windows
What Is a Window?
A window is Intuition's fundamental unit of user interaction. Every GUI element — gadgets, menus, text, graphics — lives inside a window. A window belongs to exactly one screen, receives user input through IDCMP, and is managed by the system's layered display architecture.
Unlike modern windowing systems where windows are heavyweight objects backed by compositor surfaces, Amiga windows are lightweight wrappers around Layers — the graphics.library's clipping and damage-tracking mechanism. This is why a 7 MHz 68000 can manage dozens of overlapping windows smoothly.
Window Anatomy
graph TB
subgraph "Window Structure"
TITLE["Title Bar (drag area)"]
CLOSE["×"]
DEPTH["⊡"]
ZOOM["□"]
BORDER_L["Left Border"]
CONTENT["Content Area<br/>(your drawing region)"]
BORDER_R["Right Border"]
SIZE["Size Gadget ◢"]
BOTTOM["Bottom Border"]
end
style TITLE fill:#e8f4fd,stroke:#2196f3,color:#333
style CONTENT fill:#fff,stroke:#bdbdbd,color:#333
style CLOSE fill:#ffebee,stroke:#f44336,color:#333
style DEPTH fill:#e8f5e9,stroke:#4caf50,color:#333
style SIZE fill:#fff3e0,stroke:#ff9800,color:#333
| Element | System Gadget | Purpose |
|---|---|---|
| Close | WFLG_CLOSEGADGET |
Sends IDCMP_CLOSEWINDOW |
| Depth | WFLG_DEPTHGADGET |
Moves window front/back |
| Zoom | WFLG_HASZOOM (OS 2.0+) |
Toggles between two sizes |
| Drag Bar | WFLG_DRAGBAR |
User drags the window |
| Size | WFLG_SIZEGADGET |
Resize handle (bottom-right) |
| Borders | Automatic | Visual frame; width depends on screen resolution |
Opening a Window
Modern Pattern (OS 2.0+ TagList)
struct Window *win = OpenWindowTags(NULL,
WA_Left, 100,
WA_Top, 50,
WA_InnerWidth, 400, /* Content area width */
WA_InnerHeight, 300, /* Content area height */
WA_Title, "My Window",
WA_ScreenTitle, "Status bar text when this window is active",
WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_GADGETUP |
IDCMP_RAWKEY | IDCMP_NEWSIZE,
WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR |
WFLG_DEPTHGADGET | WFLG_SIZEGADGET |
WFLG_ACTIVATE | WFLG_SMART_REFRESH,
WA_MinWidth, 200,
WA_MinHeight, 100,
WA_MaxWidth, -1, /* No maximum (screen width) */
WA_MaxHeight, -1, /* No maximum (screen height) */
WA_PubScreen, NULL, /* Default public screen (Workbench) */
TAG_DONE);
if (!win) { /* Handle failure — screen may be locked or out of memory */ }
Legacy Pattern (struct NewWindow)
/* Pre-OS 2.0 — avoid in new code */
struct NewWindow nw = {
100, 50, 400, 300, /* Left, Top, Width, Height */
0, 1, /* DetailPen, BlockPen */
IDCMP_CLOSEWINDOW, /* IDCMPFlags */
WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_ACTIVATE,
NULL, NULL, /* FirstGadget, CheckMark */
"My Window", /* Title */
NULL, NULL, /* Screen, BitMap */
200, 100, -1, -1, /* Min/Max Width/Height */
WBENCHSCREEN /* Type */
};
struct Window *win = OpenWindow(&nw);
Common WA_ Tags
Position and Size
| Tag | Type | Description |
|---|---|---|
WA_Left, WA_Top |
WORD |
Window position (outer edge) |
WA_Width, WA_Height |
WORD |
Total window size (including borders) |
WA_InnerWidth, WA_InnerHeight |
WORD |
Content area size (excluding borders) — preferred |
WA_MinWidth, WA_MinHeight |
WORD |
Minimum resize dimensions |
WA_MaxWidth, WA_MaxHeight |
WORD |
Maximum resize dimensions; -1 = screen size |
WA_Zoom |
WORD[4] |
Alternate position/size for zoom gadget |
Appearance
| Tag | Type | Description |
|---|---|---|
WA_Title |
STRPTR |
Title bar text |
WA_ScreenTitle |
STRPTR |
Screen title shown when this window is active |
WA_Borderless |
BOOL |
No borders or system gadgets |
WA_GimmeZeroZero |
BOOL |
Inner content area starts at (0,0) — adds extra layer |
WA_NoCareRefresh |
BOOL |
Ignore REFRESHWINDOW — Intuition handles it (may cause glitches) |
Screen Placement
| Tag | Type | Description |
|---|---|---|
WA_PubScreen |
struct Screen * |
Open on a public screen (NULL = default/Workbench) |
WA_CustomScreen |
struct Screen * |
Open on a custom (private) screen |
WA_PubScreenName |
STRPTR |
Open on named public screen; falls back to default |
WA_PubScreenFallBack |
BOOL |
If named screen unavailable, use default |
Behavior
| Tag | Type | Description |
|---|---|---|
WA_Activate |
BOOL |
Window becomes active immediately on open |
WA_Backdrop |
BOOL |
Always stays behind all normal windows |
WA_SmartRefresh |
BOOL |
Intuition saves obscured content automatically |
WA_SimpleRefresh |
BOOL |
Application must redraw on expose (less memory) |
WA_SuperBitMap |
struct BitMap * |
Application provides full off-screen buffer |
WA_AutoAdjust |
BOOL |
Auto-adjust position/size to fit screen |
WA_NewLookMenus |
BOOL |
OS 3.0+ 3D menu appearance |
Refresh Modes
How Intuition handles window content when areas are obscured and then revealed:
| Mode | Flag | Memory Cost | App Responsibility | Best For |
|---|---|---|---|---|
| Simple Refresh | WFLG_SIMPLE_REFRESH |
Lowest | Must handle IDCMP_REFRESHWINDOW — redraw exposed areas |
Text editors, games (redraw every frame anyway) |
| Smart Refresh | WFLG_SMART_REFRESH |
Medium | Intuition saves/restores obscured areas automatically | Most applications — recommended default |
| SuperBitMap | WFLG_SUPER_BITMAP |
Highest | Application provides full-size BitMap; Intuition copies from it |
CAD, paint programs with large canvases |
Simple Refresh Handler
case IDCMP_REFRESHWINDOW:
BeginRefresh(win);
/* Redraw only the damaged region — clipping is set automatically */
RedrawWindowContents(win);
EndRefresh(win, TRUE); /* TRUE = damage fully repaired */
break;
Smart Refresh Memory Cost
Smart Refresh allocates off-screen buffers proportional to the obscured area. If a 640×400 window is 50% covered by other windows, Smart Refresh consumes ~128 KB (at 4 bitplanes). On a 512 KB A500, this is significant.
Window Types
Standard Window
The default — has borders, title bar, and system gadgets:
WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR |
WFLG_DEPTHGADGET | WFLG_SIZEGADGET | WFLG_ACTIVATE,
Backdrop Window
Stays behind all other windows. Commonly used for:
- Desktop manager backgrounds
- Full-screen applications that want to coexist with Workbench windows
WA_Flags, WFLG_BACKDROP | WFLG_BORDERLESS | WFLG_ACTIVATE,
WA_IDCMP, IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY,
Borderless Window
No system gadgets or decorations — the application draws everything:
WA_Borderless, TRUE,
WA_Flags, WFLG_ACTIVATE | WFLG_RMBTRAP, /* Trap right-click too */
GimmeZeroZero Window
Creates a separate layer for window borders. The content area's RastPort starts at (0,0) regardless of border width:
WA_Flags, WFLG_GIMMEZEROZERO | WFLG_CLOSEGADGET | WFLG_DRAGBAR,
Trade-off: Uses an extra layer (memory + blitter operations) but simplifies rendering code since you don't need to account for border offsets.
Sizing Constraints
WA_MinWidth, 200,
WA_MinHeight, 100,
WA_MaxWidth, -1, /* Screen width */
WA_MaxHeight, -1, /* Screen height */
WA_SizeGadget, TRUE,
WA_SizeBRight, TRUE, /* Size gadget on right border */
WA_SizeBBottom, TRUE, /* Size gadget on bottom border */
Window Coordinates
Border Offsets
The content area does NOT start at (0,0) in a normal window. You must account for borders:
WORD contentLeft = win->BorderLeft;
WORD contentTop = win->BorderTop;
WORD contentWidth = win->Width - win->BorderLeft - win->BorderRight;
WORD contentHeight = win->Height - win->BorderTop - win->BorderBottom;
/* Draw at content origin */
Move(win->RPort, contentLeft, contentTop + baseline);
Text(win->RPort, "Hello", 5);
With WFLG_GIMMEZEROZERO, the window provides a separate GZZWidth/GZZHeight and a content RastPort where (0,0) is the content origin.
Closing a Window
Simple Case
CloseWindow(win);
Safe Shutdown (Drain Messages First)
/* Drain any pending IDCMP messages */
struct IntuiMessage *msg;
while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
ReplyMsg((struct Message *)msg);
CloseWindow(win);
With Shared Port
See IDCMP — Multi-Window Shared Port for the full Forbid()/strip/detach protocol.
Modifying a Window
Move and Resize
MoveWindow(win, deltaX, deltaY); /* Relative move */
SizeWindow(win, deltaWidth, deltaHeight); /* Relative resize */
ChangeWindowBox(win, left, top, w, h); /* Absolute reposition + resize */
WindowToFront(win);
WindowToBack(win);
ActivateWindow(win);
Change Title
SetWindowTitles(win, "New Title", "New Screen Title");
/* Pass (UBYTE *)-1 to leave unchanged */
SetWindowTitles(win, "New Title", (UBYTE *)-1);
Busy Pointer
/* OS 3.0+ — show busy pointer */
SetWindowPointer(win, WA_BusyPointer, TRUE, TAG_DONE);
/* Restore normal pointer */
SetWindowPointer(win, WA_Pointer, NULL, TAG_DONE);
struct Window — Key Fields
| Field | Type | Description |
|---|---|---|
LeftEdge, TopEdge |
WORD |
Position on screen |
Width, Height |
WORD |
Total size (including borders) |
BorderLeft/Right/Top/Bottom |
BYTE |
Border thickness (pixels) |
RPort |
struct RastPort * |
Drawing context for this window |
UserPort |
struct MsgPort * |
IDCMP message port |
IDCMPFlags |
ULONG |
Currently active IDCMP flags |
Flags |
ULONG |
Window flags (WFLG_*) |
Title |
UBYTE * |
Title string |
WScreen |
struct Screen * |
Screen this window belongs to |
FirstGadget |
struct Gadget * |
Head of gadget list |
MouseX, MouseY |
WORD |
Current mouse position (relative to window) |
GZZWidth, GZZHeight |
WORD |
Inner dimensions (GimmeZeroZero only) |
MinWidth/Height, MaxWidth/Height |
WORD |
Size constraints |
Pitfalls
1. Using WA_Width Instead of WA_InnerWidth
WA_Width includes borders. On different screen resolutions, border width varies. Always use WA_InnerWidth/WA_InnerHeight for predictable content area sizing.
2. Drawing Outside Content Area
Drawing at (0,0) in a non-GZZ window overwrites the border:
/* WRONG — draws over title bar */
Move(win->RPort, 0, 10);
/* CORRECT — offset by borders */
Move(win->RPort, win->BorderLeft, win->BorderTop + 10);
3. Forgetting MinWidth/MinHeight
Without size constraints, users can resize the window to 1×1 pixel, causing division-by-zero in layout code.
4. Not Handling NEWSIZE
If your window is resizable, you must redraw content when IDCMP_NEWSIZE arrives — the old content is clipped or garbage.
5. Opening on a Closed Screen
If you cache a screen pointer and it becomes invalid, OpenWindowTags() will crash. Always LockPubScreen() → open window → UnlockPubScreen().
Best Practices
- Use
WA_InnerWidth/WA_InnerHeightfor predictable content dimensions - Use Smart Refresh unless you have a specific reason not to
- Always set
WA_MinWidth/WA_MinHeightfor resizable windows - Handle
IDCMP_NEWSIZE— recalculate and redraw layout - Use
WA_PubScreen, NULLto open on the default public screen - Drain IDCMP messages before calling
CloseWindow() - Show a busy pointer during long operations — it prevents user confusion
- Use
WA_AutoAdjust, TRUEto handle cases where the window doesn't fit the screen