IDCMP Event Handling — Section 3.7¶
This article synthesises Section 3.7 ("Checking the IDCMP") of Amiga C for Advanced Programmers by Bleek, Jennrich, Schulz (Abacus / Data Becker, ~1991). It covers the Intuition event loop pattern: configuring which events a window receives (the IDCMPFlags field of NewWindow), reading messages from the window's UserPort, and dispatching based on the event class.
For the modern comprehensive treatment, see intuition/intuition-windows-screens-events.md and library-reference/intuition-library.md. The book covers the pre-OS-2.0 model; OS 2.0+ uses the same patterns but with WindowUserData(), GT_GetIMsg(), and IExec->Wait().
Editorial note: page numbers in this article refer to the PDF page index in the raw OCR source.
What the IDCMP is (page 273)¶
The Intuition Direct-Communication Message Port (IDCMP) is the asynchronous event channel between Intuition and your application. When the user moves the mouse, clicks a gadget, selects a menu, or anything else happens in your window, Intuition posts a message on the window's UserPort. Your event loop pulls messages off, dispatches based on the message class, and replies to free the slot.
"The IDCMP is not constantly on standby, ready for the programmer's call. Intuition must know that a possibility exists for data reception."
The book breaks down IDCMP flags into six conceptual groups (page 274), which map to the event classes in <intuition/intuition.h>:
| Group | Common flags |
|---|---|
| Window lifecycle | IDCMP_REFRESHWINDOW, IDCMP_NEWSIZE, IDCMP_CLOSEWINDOW, IDCMP_ACTIVEWINDOW, IDCMP_INACTIVEWINDOW |
| Mouse | IDCMP_MOUSEBUTTONS, IDCMP_MOUSEMOVE, IDCMP_DELTAMOVE |
| Keyboard | IDCMP_RAWKEY, IDCMP_VANILLAKEY |
| Gadgets | IDCMP_GADGETDOWN, IDCMP_GADGETUP |
| Menus | IDCMP_MENUPICK, IDCMP_MENUVERIFY |
| Requesters | IDCMP_REQSET, IDCMP_REQCLEAR, IDCMP_REQVERIFY |
Each flag is a single bit in the IDCMPFlags field of NewWindow. You set the bits you care about; Intuition only sends you those events.
The IntuiMessage structure (page 280)¶
Each event message has the format:
struct IntuiMessage {
struct Message ExecMessage; /* standard exec message header */
ULONG Class; /* IDCMP_* */
UWORD Code; /* event-specific */
UWORD Qualifier; /* IEQUALIFIER_* */
APTR IAddress; /* gadget, menu item, etc. */
WORD MouseX, MouseY; /* relative to window origin */
ULONG Seconds, Micros; /* timestamp (V36+) */
struct Window *IDCMPWindow;
struct IntuiMessage *SpecialLink; /* V39+ chaining */
};
Most applications only need:
- Class — what happened
- Code — additional info (e.g. for IDCMP_RAWKEY, this is the raw key code)
- Qualifier — shift / alt / ctrl state
- IAddress — gadget pointer or menu pointer
- MouseX, MouseY — pointer position
The event loop (page 281)¶
The book's standard pattern:
BOOL done = FALSE;
while (!done) {
/* Block until at least one event is available */
WaitPort(win->UserPort);
/* Drain all pending events */
while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort))) {
switch (msg->Class) {
case IDCMP_CLOSEWINDOW:
done = TRUE;
break;
case IDCMP_REFRESHWINDOW:
BeginRefresh(win);
/* redraw your content */
EndRefresh(win, TRUE);
break;
case IDCMP_MOUSEBUTTONS:
if (msg->Code == SELECTDOWN) {
/* left mouse press at (msg->MouseX, msg->MouseY) */
}
break;
case IDCMP_RAWKEY:
/* see [intuition-keymap](../intuition/intuition-windows-screens-events.md) */
break;
case IDCMP_GADGETUP:
/* msg->IAddress is the Gadget */
break;
case IDCMP_MENUPICK:
/* msg->Code is the menu number (encode as FullMenuStrip) */
break;
default:
break;
}
/* Return the message to Intuition */
ReplyMsg((struct Message *)msg);
}
}
This is the canonical pattern. Variations:
- Multi-source wait: if you have multiple windows / ports, use
Wait()withwin->UserPort->mp_SigBitinstead ofWaitPort(). - Modern (OS 4 / MorphOS): use
IExec->Wait()instead ofWait().
Reading the message: class-by-class (page 281+)¶
The book's section 3.7 walks through the major message classes.
IDCMP_CLOSEWINDOW and IDCMP_NEWSIZE¶
Simplest messages. Class tells you the type; Code is unused.
case IDCMP_CLOSEWINDOW:
done = TRUE;
break;
case IDCMP_NEWSIZE:
/* window was resized; may need to re-layout content */
RefreshWindowFrame(win);
break;
IDCMP_MOUSEBUTTONS¶
Code holds the mouse code: SELECTDOWN, SELECTUP, MIDDLEDOWN, MIDDLEUP, MENUDOWN, MENUUP. The book uses the IECODE_* constants:
case IDCMP_MOUSEBUTTONS:
if (msg->Code == SELECTDOWN) {
/* left button pressed at msg->MouseX, msg->MouseY */
}
IDCMP_RAWKEY¶
Code is the raw key code; Qualifier has shift / alt / ctrl state.
case IDCMP_RAWKEY:
if (msg->Code == 0x44) { /* left arrow */
/* move cursor left */
}
break;
The book's section 3.10 covers raw-key → ASCII conversion tables (pre-OS-2.0 era; OS 2.0+ has Intuition → Keymap).
IDCMP_GADGETUP¶
IAddress is the struct Gadget * that triggered. Code is unused for classic gadgets:
case IDCMP_GADGETUP:
{
struct Gadget *g = (struct Gadget *)msg->IAddress;
/* use g->GadgetID to identify */
}
break;
IDCMP_MENUPICK¶
Code is the menu number. Use MenuNumber() to decode:
case IDCMP_MENUPICK:
{
UWORD code = msg->Code;
while (code != MENUNULL) {
struct MenuItem *item = ItemAddress(menu_strip, code);
/* process item */
code = item->NextSelect;
}
}
break;
ReplyMsg: freeing the slot (page 290)¶
Every message retrieved with GetMsg() MUST be replied via ReplyMsg(). This signals Intuition that the message structure can be reused.
The book is explicit: if you forget
ReplyMsg(), you'll eventually exhaust Intuition's message pool (typically 32 messages) and the system will lock up.
Modern OS 2.0+ provides GT_GetIMsg() and GT_ReplyIMsg() for gadget messages specifically — these functions do ReplyMsg() automatically when appropriate.
Multi-window applications¶
The book notes that more complex applications have multiple windows with their own ports. The pattern becomes:
/* Wait for any of N ports */
ULONG sigmask = 0;
for (i = 0; i < nports; i++) sigmask |= (1UL << ports[i]->mp_SigBit);
ULONG signals = Wait(sigmask);
/* Service whichever ports have signals */
for (i = 0; i < nports; i++) {
if (signals & (1UL << ports[i]->mp_SigBit)) {
/* process this port */
}
}
The modern replacement is IExec->Wait() (V40+) which is functionally identical but uses an exec.library Cleanup macro.
What's NOT in section 3.7¶
IECLASS_xxxconstants (V39+ class-based events). The book uses the legacyClassfield directly; OS 2.0+ accepts both.IIntuition->GetAttr()/DoGadgetMethod()(V39+) — the BOOPSI way to query gadgets programmatically.- Async / interrupt-driven event handling — events are always handled on the main task.
SetGadgetAttrs()from an interrupt — covered in BOOPSI autodocs, not here.
Modern migration¶
If writing new code today:
| Use this | Instead of this | Why |
|---|---|---|
IExec->Wait() |
Wait() |
Forward-compatible |
GT_GetIMsg() for gadgets |
GetMsg() + manual class check |
Type-safe gadget helpers |
IECLASS_* constants |
IDCMP_* legacy flags |
V39+ class system |
IIntuition->IDoMethod() |
Direct gadget-pointer poke | Method dispatch |
But the fundamentals (port → get → dispatch → reply) carry forward unchanged.
Sources¶
- Bleek, Jennrich, Schulz, Amiga C for Advanced Programmers, Abacus / Data Becker, ~1991, Chapter 3 section 3.7 (pages ~210–225 of the printed book; PDF pages 273–292 of the scanned source).
- Full OCR text:
raw/c-programming/amiga-c-for-advanced-programmers.md. - Cross-references:
intuition/intuition-windows-screens-events.md,library-reference/intuition-library.md,intuition/intuition-layer-locking.md.