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
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 ofRequest(). TheRequest()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
- Use
EasyRequest()for all message dialogs โ notAutoRequest()(OS 1.x legacy) - Place "Cancel" as the rightmost button โ it always returns 0, matching the Amiga convention
- Pass the parent window to requesters โ for proper screen placement and depth arrangement
- Reuse ASL requesters โ users expect the dialog to remember their last directory
- Use
ASLFR_DoPatterns, TRUEโ power users rely on pattern matching - Use
ASLFR_RejectIcons, TRUEโ.infofiles clutter the file list - Use
BuildEasyRequest()when you need to handle events during a dialog - Always check return values โ a canceled requester should not proceed with the operation