amiga-bootcamp/09_intuition/windows.md
Ilia Sharin 4d136b0672 doc: Intuition bootcamp — comprehensive enrichment of all subsystem articles
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.
2026-04-23 17:29:18 -04:00

12 KiB
Raw Blame History

← Home · Intuition

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

  1. Use WA_InnerWidth/WA_InnerHeight for predictable content dimensions
  2. Use Smart Refresh unless you have a specific reason not to
  3. Always set WA_MinWidth/WA_MinHeight for resizable windows
  4. Handle IDCMP_NEWSIZE — recalculate and redraw layout
  5. Use WA_PubScreen, NULL to open on the default public screen
  6. Drain IDCMP messages before calling CloseWindow()
  7. Show a busy pointer during long operations — it prevents user confusion
  8. Use WA_AutoAdjust, TRUE to handle cases where the window doesn't fit the screen

References

  • NDK 3.9: intuition/intuition.h, intuition/screens.h
  • ADCD 2.1: OpenWindowTagList(), CloseWindow(), ModifyIDCMP()
  • AmigaOS Reference Manual (RKRM): Libraries, Chapter 4 — Intuition Windows
  • See also: IDCMP, Screens, Gadgets