mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
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.
370 lines
12 KiB
Markdown
370 lines
12 KiB
Markdown
[← Home](../README.md) · [Intuition](README.md)
|
||
|
||
# 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](screens.md), receives user input through [IDCMP](idcmp.md), 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
|
||
|
||
```mermaid
|
||
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)
|
||
|
||
```c
|
||
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)
|
||
|
||
```c
|
||
/* 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
|
||
|
||
```c
|
||
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:
|
||
|
||
```c
|
||
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
|
||
|
||
```c
|
||
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:
|
||
|
||
```c
|
||
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:
|
||
|
||
```c
|
||
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
|
||
|
||
```c
|
||
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:
|
||
|
||
```c
|
||
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
|
||
|
||
```c
|
||
CloseWindow(win);
|
||
```
|
||
|
||
### Safe Shutdown (Drain Messages First)
|
||
|
||
```c
|
||
/* 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](idcmp.md#multi-window-shared-port) for the full `Forbid()`/strip/detach protocol.
|
||
|
||
---
|
||
|
||
## Modifying a Window
|
||
|
||
### Move and Resize
|
||
|
||
```c
|
||
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
|
||
|
||
```c
|
||
SetWindowTitles(win, "New Title", "New Screen Title");
|
||
/* Pass (UBYTE *)-1 to leave unchanged */
|
||
SetWindowTitles(win, "New Title", (UBYTE *)-1);
|
||
```
|
||
|
||
### Busy Pointer
|
||
|
||
```c
|
||
/* 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:
|
||
```c
|
||
/* 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](idcmp.md), [Screens](screens.md), [Gadgets](gadgets.md)
|