amiga-bootcamp/09_intuition/requesters.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

11 KiB

← Home · Intuition

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.libraryASL_FileRequest File open/save dialogs
ASL Font asl.libraryASL_FontRequest Font picker
ASL ScreenMode asl.libraryASL_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

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:

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

/* 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

#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

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

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

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:

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:

/* 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:

/* 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:

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, Gadgets, IDCMP