mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-12 16:16: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
11 KiB
Markdown
370 lines
11 KiB
Markdown
[← Home](../README.md) · [Intuition](README.md)
|
|
|
|
# Requesters
|
|
|
|
## What Is a Requester?
|
|
|
|
A requester is a **modal dialog** — a focused interaction that temporarily blocks user access to its parent window until the user responds. Amiga requesters come in several flavors:
|
|
|
|
| Type | API | Use Case |
|
|
|---|---|---|
|
|
| **EasyRequest** | `EasyRequest()` / `EasyRequestArgs()` | Simple message dialogs (alerts, confirmations) |
|
|
| **AutoRequest** | `AutoRequest()` | Legacy OS 1.x two-button dialog |
|
|
| **ASL File** | `asl.library` — `ASL_FileRequest` | File open/save dialogs |
|
|
| **ASL Font** | `asl.library` — `ASL_FontRequest` | Font picker |
|
|
| **ASL ScreenMode** | `asl.library` — `ASL_ScreenModeRequest` | Display mode picker |
|
|
| **Custom** | `Request()` / BOOPSI | Application-defined forms |
|
|
|
|
---
|
|
|
|
## EasyRequest (OS 2.0+)
|
|
|
|
The standard way to show message dialogs — supports printf-style formatting and arbitrary button layouts:
|
|
|
|
### Basic Usage
|
|
|
|
```c
|
|
struct EasyStruct es = {
|
|
sizeof(struct EasyStruct),
|
|
0, /* Flags (reserved) */
|
|
"Warning", /* Window title */
|
|
"Delete file '%s'?\n"
|
|
"This action cannot be undone.", /* Body text (printf format) */
|
|
"Delete|Cancel" /* Button labels (| separated) */
|
|
};
|
|
|
|
LONG result = EasyRequest(win, &es, NULL, filename);
|
|
```
|
|
|
|
### Return Value Logic
|
|
|
|
The return value mapping is **not intuitive** — it follows a specific pattern:
|
|
|
|
| Buttons | Click | Return Value |
|
|
|---|---|---|
|
|
| `"OK"` | OK | `1` |
|
|
| `"Yes\|No"` | Yes | `1` |
|
|
| `"Yes\|No"` | No | `0` |
|
|
| `"Save\|Don't Save\|Cancel"` | Save | `1` |
|
|
| `"Save\|Don't Save\|Cancel"` | Don't Save | `2` |
|
|
| `"Save\|Don't Save\|Cancel"` | Cancel | `0` |
|
|
|
|
**Rule**: The **rightmost button always returns 0** (typically "Cancel"). All other buttons return 1, 2, 3... from left to right.
|
|
|
|
### Printf-Style Formatting
|
|
|
|
The body text supports `%s`, `%ld`, `%lx`, etc. Additional arguments are passed after the `IDCMP_Ptr` parameter:
|
|
|
|
```c
|
|
struct EasyStruct es = {
|
|
sizeof(struct EasyStruct), 0,
|
|
"Disk Error",
|
|
"Error %ld occurred while\n"
|
|
"reading '%s' from %s:",
|
|
"Retry|Abort"
|
|
};
|
|
|
|
/* Pass format arguments as varargs */
|
|
LONG result = EasyRequest(win, &es, NULL,
|
|
errorCode, /* %ld */
|
|
fileName, /* %s */
|
|
deviceName /* %s */
|
|
);
|
|
```
|
|
|
|
### Non-Blocking Variant
|
|
|
|
```c
|
|
/* For situations where you can't block (e.g., input handler): */
|
|
struct Window *reqWin = BuildEasyRequest(win, &es, IDCMP_DISKINSERTED, args);
|
|
|
|
/* Poll for response (returns -1 while still open): */
|
|
LONG response;
|
|
while ((response = SysReqHandler(reqWin, NULL, FALSE)) == -1)
|
|
{
|
|
/* Do other work or Wait() */
|
|
Wait(1L << reqWin->UserPort->mp_SigBit);
|
|
}
|
|
FreeSysRequest(reqWin);
|
|
```
|
|
|
|
---
|
|
|
|
## ASL File Requester
|
|
|
|
The standard file open/save dialog provided by `asl.library`:
|
|
|
|
### Opening a File
|
|
|
|
```c
|
|
#include <libraries/asl.h>
|
|
#include <proto/asl.h>
|
|
|
|
struct Library *AslBase = OpenLibrary("asl.library", 39);
|
|
|
|
struct FileRequester *fr = AllocAslRequestTags(ASL_FileRequest,
|
|
ASLFR_TitleText, "Open File",
|
|
ASLFR_InitialDrawer, "SYS:Docs",
|
|
ASLFR_InitialFile, "",
|
|
ASLFR_InitialPattern, "#?.(txt|doc|guide)",
|
|
ASLFR_DoPatterns, TRUE, /* Show pattern gadget */
|
|
ASLFR_DoMultiSelect, FALSE, /* Single file selection */
|
|
ASLFR_RejectIcons, TRUE, /* Hide .info files */
|
|
TAG_DONE);
|
|
|
|
if (AslRequest(fr, NULL))
|
|
{
|
|
/* User clicked "OK" */
|
|
char fullPath[512];
|
|
strcpy(fullPath, fr->fr_Drawer);
|
|
AddPart(fullPath, fr->fr_File, sizeof(fullPath));
|
|
Printf("Selected: %s\n", fullPath);
|
|
}
|
|
else
|
|
{
|
|
/* User clicked "Cancel" */
|
|
}
|
|
|
|
FreeAslRequest(fr);
|
|
CloseLibrary(AslBase);
|
|
```
|
|
|
|
### Save Dialog
|
|
|
|
```c
|
|
struct FileRequester *fr = AllocAslRequestTags(ASL_FileRequest,
|
|
ASLFR_TitleText, "Save As...",
|
|
ASLFR_InitialDrawer, currentDrawer,
|
|
ASLFR_InitialFile, currentFile,
|
|
ASLFR_DoSaveMode, TRUE, /* "Save" button instead of "Open" */
|
|
ASLFR_DoPatterns, TRUE,
|
|
TAG_DONE);
|
|
```
|
|
|
|
### Multi-Select
|
|
|
|
```c
|
|
struct FileRequester *fr = AllocAslRequestTags(ASL_FileRequest,
|
|
ASLFR_TitleText, "Select Files",
|
|
ASLFR_DoMultiSelect, TRUE,
|
|
TAG_DONE);
|
|
|
|
if (AslRequest(fr, NULL))
|
|
{
|
|
if (fr->fr_NumArgs > 0)
|
|
{
|
|
/* Multi-select: iterate the WBArg array */
|
|
for (LONG i = 0; i < fr->fr_NumArgs; i++)
|
|
{
|
|
Printf("File: %s\n", fr->fr_ArgList[i].wa_Name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Single file selected (even in multi-select mode) */
|
|
Printf("File: %s%s\n", fr->fr_Drawer, fr->fr_File);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Common ASL File Tags
|
|
|
|
| Tag | Type | Description |
|
|
|---|---|---|
|
|
| `ASLFR_TitleText` | `STRPTR` | Requester window title |
|
|
| `ASLFR_InitialDrawer` | `STRPTR` | Starting directory |
|
|
| `ASLFR_InitialFile` | `STRPTR` | Pre-selected filename |
|
|
| `ASLFR_InitialPattern` | `STRPTR` | AmigaOS pattern filter (e.g., `#?.txt`) |
|
|
| `ASLFR_DoPatterns` | `BOOL` | Show pattern matching gadget |
|
|
| `ASLFR_DoSaveMode` | `BOOL` | Show "Save" button instead of "Open" |
|
|
| `ASLFR_DoMultiSelect` | `BOOL` | Allow multiple file selection |
|
|
| `ASLFR_RejectIcons` | `BOOL` | Hide `.info` icon files |
|
|
| `ASLFR_DrawersOnly` | `BOOL` | Only show directories (folder picker) |
|
|
| `ASLFR_InitialLeftEdge/TopEdge` | `WORD` | Requester position |
|
|
| `ASLFR_InitialWidth/Height` | `WORD` | Requester size |
|
|
| `ASLFR_Window` | `struct Window *` | Parent window (for positioning) |
|
|
| `ASLFR_Screen` | `struct Screen *` | Screen to open on |
|
|
| `ASLFR_FilterFunc` | `struct Hook *` | Custom filtering function |
|
|
|
|
---
|
|
|
|
## ASL Font Requester
|
|
|
|
```c
|
|
struct FontRequester *fo = AllocAslRequestTags(ASL_FontRequest,
|
|
ASLFO_TitleText, "Select Font",
|
|
ASLFO_InitialName, "topaz.font",
|
|
ASLFO_InitialSize, 8,
|
|
ASLFO_DoFrontPen, TRUE, /* Show color picker */
|
|
ASLFO_DoStyle, TRUE, /* Show Bold/Italic/Underline */
|
|
ASLFO_DoDrawMode, TRUE, /* Show JAM1/JAM2 selector */
|
|
ASLFO_MinHeight, 6, /* Minimum font size */
|
|
ASLFO_MaxHeight, 72, /* Maximum font size */
|
|
TAG_DONE);
|
|
|
|
if (AslRequest(fo, NULL))
|
|
{
|
|
Printf("Font: %s %ld\n", fo->fo_Attr.ta_Name, fo->fo_Attr.ta_YSize);
|
|
Printf("Style: %ld, FrontPen: %ld\n", fo->fo_Attr.ta_Style, fo->fo_FrontPen);
|
|
|
|
/* Open the selected font */
|
|
struct TextFont *font = OpenDiskFont(&fo->fo_Attr);
|
|
if (font)
|
|
{
|
|
SetFont(win->RPort, font);
|
|
/* ... */
|
|
CloseFont(font);
|
|
}
|
|
}
|
|
FreeAslRequest(fo);
|
|
```
|
|
|
|
---
|
|
|
|
## ASL ScreenMode Requester
|
|
|
|
For applications that let users choose their display mode:
|
|
|
|
```c
|
|
struct ScreenModeRequester *smr = AllocAslRequestTags(ASL_ScreenModeRequest,
|
|
ASLSM_TitleText, "Select Screen Mode",
|
|
ASLSM_InitialDisplayID, HIRES_KEY,
|
|
ASLSM_InitialDisplayDepth, 4,
|
|
ASLSM_DoWidth, TRUE, /* Allow width selection */
|
|
ASLSM_DoHeight, TRUE, /* Allow height selection */
|
|
ASLSM_DoDepth, TRUE, /* Allow depth selection */
|
|
ASLSM_DoOverscanType, TRUE, /* Allow overscan selection */
|
|
ASLSM_MinWidth, 320,
|
|
ASLSM_MinHeight, 200,
|
|
ASLSM_MinDepth, 1,
|
|
ASLSM_MaxDepth, 8,
|
|
TAG_DONE);
|
|
|
|
if (AslRequest(smr, NULL))
|
|
{
|
|
Printf("Mode: 0x%08lx, %ldx%ldx%ld\n",
|
|
smr->sm_DisplayID,
|
|
smr->sm_DisplayWidth,
|
|
smr->sm_DisplayHeight,
|
|
smr->sm_DisplayDepth);
|
|
|
|
/* Open screen with selected mode */
|
|
struct Screen *scr = OpenScreenTags(NULL,
|
|
SA_DisplayID, smr->sm_DisplayID,
|
|
SA_Width, smr->sm_DisplayWidth,
|
|
SA_Height, smr->sm_DisplayHeight,
|
|
SA_Depth, smr->sm_DisplayDepth,
|
|
SA_Overscan, smr->sm_OverscanType,
|
|
SA_AutoScroll, TRUE,
|
|
TAG_DONE);
|
|
}
|
|
FreeAslRequest(smr);
|
|
```
|
|
|
|
---
|
|
|
|
## Custom Window Requesters
|
|
|
|
For application-specific forms, use `Request()` with a custom layout:
|
|
|
|
```c
|
|
/* Create a requester with gadgets */
|
|
struct Requester req;
|
|
InitRequester(&req);
|
|
|
|
req.LeftEdge = 20;
|
|
req.TopEdge = 20;
|
|
req.Width = 300;
|
|
req.Height = 100;
|
|
req.ReqGadget = myGadgetList; /* Your gadgets */
|
|
req.ReqText = myIntuiText; /* Labels */
|
|
req.BackFill = 0; /* Background pen */
|
|
req.Flags = 0;
|
|
req.ReqBorder = myBorder; /* Border decoration */
|
|
|
|
/* Activate the requester (blocks the parent window) */
|
|
if (Request(&req, win))
|
|
{
|
|
/* Requester is active — handle IDCMP_GADGETUP events */
|
|
/* When done: */
|
|
EndRequest(&req, win);
|
|
}
|
|
```
|
|
|
|
> Most modern applications use `EasyRequest()` for simple dialogs or build custom windows instead of `Request()`. The `Request()` API is mainly relevant for legacy code.
|
|
|
|
---
|
|
|
|
## Remembering Requester State
|
|
|
|
ASL requesters remember their last position and selections if you reuse the same requester structure:
|
|
|
|
```c
|
|
/* Allocate once at program start */
|
|
struct FileRequester *fr = AllocAslRequestTags(ASL_FileRequest,
|
|
ASLFR_TitleText, "Open", TAG_DONE);
|
|
|
|
/* First use — shows default directory */
|
|
AslRequest(fr, NULL);
|
|
|
|
/* Second use — automatically shows the directory from last use */
|
|
AslRequest(fr, NULL);
|
|
|
|
/* Free at program exit */
|
|
FreeAslRequest(fr);
|
|
```
|
|
|
|
You can override this with explicit tags on each call:
|
|
|
|
```c
|
|
AslRequest(fr, (struct TagItem *)(APTR[]){
|
|
{ ASLFR_InitialDrawer, (ULONG)"RAM:" },
|
|
{ TAG_DONE, 0 }
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Pitfalls
|
|
|
|
### 1. EasyRequest Return Value Confusion
|
|
|
|
The rightmost button always returns 0, not the button count. For `"Yes|No"`, "No" returns 0 — which many developers mistake for FALSE when it's actually the "No" response.
|
|
|
|
### 2. ASL Without a Window Reference
|
|
|
|
If you don't pass `ASLFR_Window`, the requester opens at a default position, potentially on a different screen or off-screen.
|
|
|
|
### 3. Not Checking AslRequest Return
|
|
|
|
`AslRequest()` returns FALSE if the user cancels. Always check — accessing `fr->fr_File` after cancellation returns the previous (stale) selection.
|
|
|
|
### 4. Forgetting FreeAslRequest
|
|
|
|
ASL requesters allocate internal memory for file lists and paths. Failing to call `FreeAslRequest()` leaks memory.
|
|
|
|
### 5. Blocking While Requester Is Open
|
|
|
|
EasyRequest and AslRequest are **synchronous** — your event loop is stopped while the requester is open. If you need to handle background events, use the non-blocking `BuildEasyRequest()`/`SysReqHandler()` pattern.
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Use `EasyRequest()`** for all message dialogs — not `AutoRequest()` (OS 1.x legacy)
|
|
2. **Place "Cancel" as the rightmost button** — it always returns 0, matching the Amiga convention
|
|
3. **Pass the parent window** to requesters — for proper screen placement and depth arrangement
|
|
4. **Reuse ASL requesters** — users expect the dialog to remember their last directory
|
|
5. **Use `ASLFR_DoPatterns, TRUE`** — power users rely on pattern matching
|
|
6. **Use `ASLFR_RejectIcons, TRUE`** — `.info` files clutter the file list
|
|
7. **Use `BuildEasyRequest()`** when you need to handle events during a dialog
|
|
8. **Always check return values** — a canceled requester should not proceed with the operation
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- NDK 3.9: `intuition/intuition.h`, `libraries/asl.h`
|
|
- ADCD 2.1: `EasyRequest()`, `AllocAslRequest()`, `AslRequest()`, `FreeAslRequest()`
|
|
- AmigaOS Reference Manual (RKRM): Libraries, Chapter 9 — Requesters
|
|
- See also: [Windows](windows.md), [Gadgets](gadgets.md), [IDCMP](idcmp.md)
|