Intuition V47 BOOPSI and Input Extensions

intuition.library V47 (AmigaOS 3.2) adds a set of input and BOOPSI extensions that let applications and gadget classes take part in mouse-wheel scrolling, hover-driven mouse pointers and tooltips, and hidden gadgets without patching the system. This article collects these additions from the 3.2 NDK headers (intuition/intuition.h, gadgetclass.h, imageclass.h, pointerclass.h, screens.h) and the intuition release notes, together with the smaller V45–V47 changes a programmer is likely to meet: hidden windows, built-in pointer types, new frame and system images, and the DrawInfo revision.

Everything here requires intuition.library 47 or later unless a different version is stated. Check IntuitionBase->LibNode.lib_Version (or open the library with version 47) before relying on any of it; on older systems the tags are ignored and the methods are never sent.

At a glance

Addition Kind Value Version
IDCMP_EXTENDEDMOUSE 3.2+ IDCMP class 0x08000000 V47
struct IntuiWheelData message payload INTUIWHEELDATA_VERSION = 2 V47
IMSGCODE_INTUIWHEELDATA IntuiMessage.Code 1<<15 V47
GM_HANDLESCROLL 3.2+ gadget method 14 V47
GM_QUERYHOVERED 3.2+ gadget method 15 V47
GA_Hidden 3.2+ gadgetclass attr GA_Dummy+54 V47
GA_PointerType 3.2+ gadgetclass attr GA_Dummy+61 V47
GA_ParentHidden 3.2+ gadgetclass attr GA_Dummy+62 V47
GMORE_HIDDEN 3.2+ ExtGadget.MoreFlags 0x00000010 V47
GMORE_BOOPSIGADGET 3.2+ ExtGadget.MoreFlags 0x00000400 V47
GMORE_FREEIMAGE 3.2+ ExtGadget.MoreFlags 0x00000800 V47
GMORE_PARENTHIDDEN 3.2+ ExtGadget.MoreFlags 0x01000000 V47
WA_Hidden 3.2+ window tag WA_Dummy+0x3c V47
WA_PointerType 3.2+ window tag WA_Dummy+0x50 V47
WA_IconifyGadget 3.1.4+ window tag WA_Dummy+0x60 V46
ShowWindow() / HideWindow() functions — V46
PGA_KnobImage 3.2+ propgclass attr PGA_Dummy+0x000D V47

Mouse wheel: IDCMP_EXTENDEDMOUSE

Intuition 47.26 introduced "true OS level support for scrollwheel". A window that wants raw wheel events adds IDCMP_EXTENDEDMOUSE to its IDCMP flags. Each event arrives as an IntuiMessage whose Class is IDCMP_EXTENDEDMOUSE and whose IAddress points to:

struct IntuiWheelData
{
    UWORD Version;  /* version of this structure (see below) */
    UWORD Reserved; /* always 0, reserved for future use     */
    WORD  WheelX;   /* horizontal wheel movement delta       */
    WORD  WheelY;   /* vertical wheel movement delta         */
    struct Gadget *HoveredGadget; /* Version 2: pointer to gadget that is hovered */
};

#define INTUIWHEELDATA_VERSION 2 /* current version of the structure above */

enum
{
    IMSGCODE_INTUIWHEELDATA  = (1<<15),
    IMSGCODE_INTUIRAWKEYDATA = (1<<14),
    IMSGCODE_INTUIWHEELDATAREJECT = (1<<13) /* for internal use */
};

Rules from the header comment:

  • Always check Code against IMSGCODE_INTUIWHEELDATA before treating IAddress as an IntuiWheelData. Future versions of Intuition may send other structures with the same class.
  • Check Version before reading fields. HoveredGadget only exists from version 2.
  • IMSGCODE_INTUIWHEELDATAREJECT is reserved for Intuition's internal use. Do not send or interpret it.
  • IAddress belongs to Intuition. Copy what you need before ReplyMsg().

Who gets the wheel event

The release notes describe several delivery paths, added over 47.26–47.50:

  • BOOPSI gadgets under the pointer can receive GM_HANDLESCROLL (see below). In ReAction, layout.gadget passes it to "the child under the mouse", and scroller.gadget, listbrowser.gadget and texteditor.gadget implement it.
  • GadTools 47.6 added the same OS-level wheel support for its own gadgets.
  • As a fallback (47.46), Intuition sends wheel events to the nearest vertical scrollbar in the window when none of the newer mechanisms handled them.
  • MUI windows are excluded from this treatment (47.46). They receive the event and do their own thing.
  • The new wheel handling filters out legacy NewMouse IDCMP_RAWKEY wheel codes. 47.50 added a private mechanism to let selected programs (AWeb is the example given) keep getting them.

The NewMouse raw key codes are in libraries/keymap.h: RAWKEY_WHEEL_UP (0x7A), RAWKEY_WHEEL_DOWN (0x7B), RAWKEY_WHEEL_LEFT (0x7C) and RAWKEY_WHEEL_RIGHT (0x7D), with the comment "aka NM_WHEEL_*". A program that must also run on intuition.library before V47 handles both: IDCMP_EXTENDEDMOUSE on V47, and IDCMP_RAWKEY with these codes on older systems. Workbench 47.29 does the same thing: it uses IDCMP_EXTENDEDMOUSE and keeps the NewMouse IDCMP_RAWKEY path for intuition before V47.

Example: a wheel-aware window

This minimal program opens a window, counts wheel steps and shows how to switch the pointer with WA_PointerType while the window is "busy". It follows the NDK prototypes (OpenWindowTags(), SetWindowPointer()), and needs intuition.library 47.

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/pointerclass.h>
#include <libraries/keymap.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

struct IntuitionBase *IntuitionBase;

int main(void)
{
    struct Window *win;
    LONG posx = 0, posy = 0;
    BOOL done = FALSE;

    IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 47);
    if (IntuitionBase == NULL)
    {
        PutStr("Needs intuition.library V47\n");
        return 20;
    }

    win = OpenWindowTags(NULL,
        WA_Title,       "Wheel test",
        WA_Width,       320,
        WA_Height,      100,
        WA_DragBar,     TRUE,
        WA_DepthGadget, TRUE,
        WA_CloseGadget, TRUE,
        WA_Activate,    TRUE,
        WA_IDCMP,       IDCMP_CLOSEWINDOW | IDCMP_EXTENDEDMOUSE |
                        IDCMP_RAWKEY,
        WA_PointerType, POINTERTYPE_CROSS,   /* built-in pointer */
        TAG_DONE);

    if (win)
    {
        while (!done)
        {
            struct IntuiMessage *imsg;

            WaitPort(win->UserPort);
            while ((imsg = (struct IntuiMessage *)GetMsg(win->UserPort)))
            {
                ULONG class = imsg->Class;
                UWORD code  = imsg->Code;
                WORD  dx = 0, dy = 0;

                if (class == IDCMP_EXTENDEDMOUSE &&
                    code == IMSGCODE_INTUIWHEELDATA)
                {
                    struct IntuiWheelData *wd = imsg->IAddress;

                    /* copy before replying: IAddress belongs to Intuition */
                    dx = wd->WheelX;
                    dy = wd->WheelY;
                }
                ReplyMsg((struct Message *)imsg);

                switch (class)
                {
                    case IDCMP_CLOSEWINDOW:
                        done = TRUE;
                        break;

                    case IDCMP_EXTENDEDMOUSE:
                        posx += dx;
                        posy += dy;
                        Printf("wheel dx=%ld dy=%ld -> %ld,%ld\n",
                               (LONG)dx, (LONG)dy, posx, posy);
                        break;

                    case IDCMP_RAWKEY:
                        /* legacy NewMouse codes, only seen on pre-V47
                           Intuition or programs exempted from filtering */
                        if (code == RAWKEY_WHEEL_UP)   posy--;
                        if (code == RAWKEY_WHEEL_DOWN) posy++;
                        break;
                }
            }

            /* show the busy pointer while "working", then restore */
            SetWindowPointer(win, WA_PointerType, POINTERTYPE_BUSY, TAG_DONE);
            Delay(5);
            SetWindowPointer(win, WA_PointerType, POINTERTYPE_CROSS, TAG_DONE);
        }
        CloseWindow(win);
    }
    CloseLibrary((struct Library *)IntuitionBase);
    return 0;
}

Printf() here is the dos.library function, so %ld arguments must be LONG.

GM_HANDLESCROLL — wheel input for gadgets

#define GM_HANDLESCROLL  (14)
    /* Handle a mouse wheel event. msg is struct gpInput *
     * return GMR_REUSE or GMR_NOREUSE  */

The message is the ordinary struct gpInput used by GM_GOACTIVE/GM_HANDLEINPUT, and the method returns one of the GMR_REUSE / GMR_NOREUSE codes (1<<2 / 1<<1). A class that does not know the method must pass it to its superclass, as with every unknown method, so that the default behaviour is kept.

Composite gadgets should forward the method to the child under the pointer, as layout.gadget does. The ReAction scroller (47.13) implements it and since 47.16 scrolls "3 times delta but no more than quarter page, and no less than 1 delta" per event, which is a reasonable policy for custom scrollable classes as well.

GM_QUERYHOVERED — hover queries, pointers and tooltips

#define GM_QUERYHOVERED  (15)
    /* query the (sub) gadget that was last hovered (aka responded to HELPTEST)
     * apart from propagating to sub gadgets it is basically an OM_GET
     */

Intuition 47.32 added this method and uses it "to figure out what mousepointer to show". window.class 47.15 uses it to implement ReAction tooltips, which removed its old dangling pointers to gadgets and strings. layout.gadget (47.24) and clicktab.gadget implement it. clicktab only propagates it to its page when the page is hovered.

So GM_QUERYHOVERED works like an attribute query that is routed to the sub-gadget which last answered GM_HELPTEST. A leaf gadget answers it like OM_GET; a composite gadget passes it down to the hovered child. A sketch of the composite case:

case GM_QUERYHOVERED:
    /* data->hovered was remembered in our GM_HELPTEST handler */
    if (data->hovered)
        return DoMethodA(data->hovered, msg);
    return DoSuperMethodA(cl, obj, msg);

Remember the hovered child in GM_HELPTEST, because that is the test the comment refers to. Intuition only calls this method on real BOOPSI gadgets. Several 47.x fixes dealt with crashes when non-BOOPSI or GadTools gadgets were hovered, and since 47.41 Intuition uses GMORE_BOOPSIGADGET to tell them apart.

GA_PointerType and WA_PointerType

GA_PointerType (GA_Dummy+61, V47) selects a built-in pointer to show while the gadget is hovered. WA_PointerType (WA_Dummy+0x50, added in 47.34) does the same for a whole window. It is accepted by OpenWindowTagList() and SetWindowPointerA(); zero is the default pointer. The constants live in intuition/pointerclass.h. Pointer preferences support "40 different standard pointertypes":

Value Name Use
0 POINTERTYPE_NORMAL normal pointer
1 POINTERTYPE_BUSY busy
2 POINTERTYPE_ALIAS dragging to create a reference/virtual copy
3 POINTERTYPE_CELL over a table cell
4 POINTERTYPE_COLUMNRESIZE column can be / is being resized
5 POINTERTYPE_CONTEXTMENU a context menu can be opened here
6 POINTERTYPE_COPY drag & drop will copy
7 POINTERTYPE_CROSS precise selection / drawing
8 POINTERTYPE_DRAGANDDROP item being dragged
9 POINTERTYPE_EASTRESIZE resizable on the right border
10 POINTERTYPE_EASTWESTRESIZE being resized left/right
11 POINTERTYPE_HAND item is draggable/movable
12 POINTERTYPE_HELP help available
13 POINTERTYPE_LINK hyperlink / tab
14 POINTERTYPE_MENU a menu is active
15 POINTERTYPE_NODROP cannot drop here
16 POINTERTYPE_NONE pointer deactivated
17–22 POINTERTYPE_NORTHEASTRESIZE, …NORTHEASTSOUTHWESTRESIZE, …NORTHRESIZE, …NORTHSOUTHRESIZE, …NORTHWESTRESIZE, …NORTHWESTSOUTHEASTRESIZE resize directions
23 POINTERTYPE_NOTALLOWED operation not allowed
24 POINTERTYPE_PROGRESS working, but input still accepted
25 POINTERTYPE_ROWRESIZE row resize
26 POINTERTYPE_SCROLLALL item can be / is being moved
27–29 POINTERTYPE_SOUTHEASTRESIZE, …SOUTHRESIZE, …SOUTHWESTRESIZE resize directions
30 POINTERTYPE_TEXT horizontal text selectable
31 POINTERTYPE_VERTICALTEXT vertical text selectable
32 POINTERTYPE_WESTRESIZE resizable on the left border
33 POINTERTYPE_ZOOMIN click zooms in
34 POINTERTYPE_ZOOMOUT click zooms out
35 POINTERTYPE_PEN drawing action
36 POINTERTYPE_ROTATE rotate
37 POINTERTYPE_RUBBER erasing action
38 POINTERTYPE_SELECT select
39 POINTERTYPE_SMUDGE smudge
40 POINTERTYPE_COUNT number of types

GA_PointerType and WA_PointerType sit next to the V39 tags WA_BusyPointer and WA_PointerDelay, which are still the right way to show a deferred busy pointer. Intuition 47.24 also stopped choking on pointer types with a negative id coming from IPrefs.

Hidden gadgets: GA_Hidden and GA_ParentHidden

Attribute Meaning
GA_Hidden (BOOL) On set, maps to GMORE_HIDDEN. On get, returns GMORE_HIDDEN | GMORE_PARENTHIDDEN, so it is TRUE when the gadget is hidden for either reason.
GA_ParentHidden (BOOL) Sets GMORE_PARENTHIDDEN on the gadget and, recursively, on all children.

Both arrived in intuition 47.29. Composite gadgets must implement the recursion themselves; the header notes that "V47 page, layout and clicktab gadgets all recurse". Hiding is cooperative. The layout gadget release note (47.22) says hidden gadgets now "have the chance to not render themselves (it requires cooperation from every single gadget)". scroller.gadget 47.15 checks both flags before painting. A custom class should test GMORE_HIDDEN | GMORE_PARENTHIDDEN in its GM_RENDER and draw nothing when either is set.

Up to 47.45, GA_ParentHidden could be set but not read, and GA_ReadOnly read but not set. Both are fixed in 47.45, so do not rely on reading GA_ParentHidden from older 47.x builds.

New ExtGadget MoreFlags

Flag Value Meaning
GMORE_HIDDEN 3.2+ 0x00000010 gadget is explicitly hidden and cannot be drawn
GMORE_BOOPSIGADGET 3.2+ 0x00000400 gadget was (sub-)instantiated from gadgetclass
GMORE_FREEIMAGE 3.2+ 0x00000800 gadgetclass frees the gadget's GA_Image on OM_DISPOSE
GMORE_PARENTHIDDEN 3.2+ 0x01000000 a parent is hidden, so this gadget is implicitly hidden

GMORE_BOOPSIGADGET (47.39) is set on every instance of gadgetclass or its subclasses. Both real BOOPSI gadgets and old-style custom gadgets have type GTYP_CUSTOMGADGET, so this flag is now the safe way to tell whether you may send BOOPSI methods to a gadget found in a window's list:

struct ExtGadget *eg = (struct ExtGadget *)gad;

if ((eg->Flags & GFLG_EXTENDED) && (eg->MoreFlags & GMORE_BOOPSIGADGET))
{
    /* safe to DoGadgetMethod() / GetAttr() on it */
}

GMORE_FREEIMAGE (47.39) asks gadgetclass to dispose of the gadget's render image automatically. The release note warns: "Do not use this flag with gadget classes that already free their images themselves!"

Windows: WA_Hidden, ShowWindow, HideWindow, iconify

  • WA_Hidden (BOOL, 47.50): open the window already hidden.
  • HideWindow(win) / ShowWindow(win, other) (V46): the SFD prototypes are BOOL ShowWindow(struct Window *window, struct Window *other) and BOOL HideWindow(struct Window *window). For other, pass another window to place this one in front of it, NULL (WINDOW_BACKMOST) to place it behind all windows of the same type, or WINDOW_FRONTMOST ((struct Window *)1). Neither call takes effect immediately. Intuition applies the change the next time it handles an input event, at 10 to 60 times a second.
  • IDCMP_CHANGEWINDOW reports CWCODE_HIDE (0x0002) and CWCODE_SHOW (0x0003) for these state changes (V46).
  • WA_IconifyGadget (V46): adds an iconify gadget (GTYP_ICONIFY = 0x0090, image ICONIFYIMAGE). Pressing it sends IDCMP_CLOSEWINDOW with Code = 1 instead of 0. WFLG_HASICONIFY (0x40000000) marks such windows.
  • Automatic placement (V47): if a window gives neither WA_Left nor WA_Top and sets WA_AutoAdjust, Intuition centres its title bar under the mouse pointer.

Images and frames

sysiclass

New SYSIA_Which values in imageclass.h:

Constant Value Image
ICONIFYIMAGE 3.2+ 0x16 window iconify gadget
MENUMX 3.2+ 0x1B menu mutual-exclude ("radio") mark
MENUSUB 3.2+ 0x1C sub-menu indicator
SHIFTKEYIMAGE 3.2+ 0x2A Shift-key symbol in menus

Leaving out SYSIA_DrawInfo no longer crashes (47.39); you get a monochrome image instead, which is a hint that something is missing. IA_EraseBackground (BOOL, IA_Dummy+0x2D, OM_SET only on sysiclass) set to FALSE blits irregular images through a mask instead of clearing their whole rectangle. For now only MXIMAGE honours it.

The release notes say several of these constants were renumbered in 47.28, before 3.2 went public, to avoid clashes (FRAME_CONTEXT, MXMENUIMAGE (renamed MENUMX), SHIFTKEYIMAGE, MIF_SHIFTCOMMSEQ, MIF_COMMSEQEXTPARSE). Always build against the final 3.2 NDK headers.

frameiclass

IA_FrameType 3.0+ Value Look
FRAME_DEFAULT 3.1+ 0 thin V37 frame
FRAME_BUTTON 3.1+ 1 button frame
FRAME_RIDGE 3.1+ 2 string-gadget ridge
FRAME_ICONDROPBOX 3.1+ 3 AppWindow drop area
FRAME_PROPBORDER 3.2+ 4 proportional gadget container (V47)
FRAME_PROPKNOB 3.2+ 5 proportional gadget knob (V47)
FRAME_DISPLAY 3.2+ 6 recessed read-only display (V47)
FRAME_CONTEXT 3.2+ 7 context frame with headline (V47)

New image attributes for V47:

Attribute Value Type Notes
IA_Orientation 3.2+ IA_Dummy+0x23 UBYTE 0 horizontal, 1 vertical; for FRAME_PROPKNOB and subclasses
IA_Label 3.2+ IA_Dummy+0x28 STRPTR headline text of a FRAME_CONTEXT frame
IA_EraseBackground 3.2+ IA_Dummy+0x2D BOOL see sysiclass above
IA_LabelPen 3.2+ IA_Dummy+0x38 UWORD colour of the label

In 47.47 the FRAME_CONTEXT headline moved from IA_Data/IA_FGPen to IA_Label/IA_LabelPen, because existing software (gadtools among them) already used the old attributes for other things. gadtools.library 47.13 or later is needed for headlines in GadTools bevel boxes. IA_FrameType is now gettable. The new IM_FRAMEBOX flag FRAMEF_MINIMAL (1<<1) returns only the edge sizes without padding.

Proportional gadgets with BOOPSI knobs

The new PropInfo flag SMARTKNOBIMAGE (0x0020) tells Intuition that a custom knob is a BOOPSI image supporting IM_DRAWFRAME, so it can be resized automatically (47.44). For propgclass, PGA_KnobImage sets the image and the flag at once. PGA_Top, PGA_Total and PGA_Visible accept full 32-bit values since 47.39.

Screens and DrawInfo

  • DRI_VERSION 3 (V47) adds dri_Screen, a back pointer to the screen, and pen BARCONTOURPEN (0x000C), raising NUMDRIPENS to 13. BARCONTOURPEN draws the left/top edges of the screen bar and menus, and BARTRIMPEN then draws right/bottom, for an embossed look. Setting BARCONTOURPEN equal to BARBLOCKPEN gives the V39 look. Check dri_Version >= 3 before reading either.
  • SA_OffScreenDragging (SA_Dummy+0x2a, V45): windows may be dragged partly off the screen. It defaults to TRUE for Workbench (subject to IControl prefs) and FALSE elsewhere.
  • OSERR_NORTGBITMAP (10): the RTG software could not allocate the screen bitmap.
  • OpenScreenTagList() limits the requested depth to 8 for hicolor and truecolor screens as well (47.36).
  • SUBMENU (0x0200, MenuItem flag): draw the standard sub-menu mark (the MENUSUB image). GadTools 47.8 sets it instead of using the » character.
  • MIF_SHIFTCOMMSEQ (0x0800): the shortcut needs Shift. It is drawn with a Shift symbol and takes precedence, so Shift+Amiga+S and Amiga+S can be different items. From 47.49 it also applies to non-COMMSEQ strings.
  • Mutually exclusive items are drawn as radio buttons on new-look screens (47.11).

IntuitionControlA

ULONG IntuitionControlA(APTR object, CONST struct TagItem *taglist) was added in 47.28 as a multi-purpose control call. Its tag base is ICTRL_Dummy (TAG_USER + 0x1C000), and the header states "No public tags defined so far". IPrefs uses it to install GUI support hooks such as border-gadget rearrangement and the GUI exception list. Applications have no public use for it.

Writing classes that degrade on V40

  • Unknown methods (14, 15) and unknown attributes fall through to the superclass. On older Intuition they are never sent, so supporting them costs nothing.
  • Test GMORE_HIDDEN | GMORE_PARENTHIDDEN only through GFLG_EXTENDED gadgets, since MoreFlags exists only in struct ExtGadget.
  • Read IntuiWheelData.HoveredGadget only when Version >= 2.
  • Ask for both IDCMP_EXTENDEDMOUSE and IDCMP_RAWKEY if you must handle wheels on old and new systems alike.

See Also


Sources: NDK 3.2 R4 Include_H/intuition/{intuition.h,gadgetclass.h,imageclass.h,pointerclass.h,screens.h}, Include_H/libraries/keymap.h, SFD/intuition_lib.sfd, Autodocs/intuition.doc, Autodocs/layout_gc.doc, ReleaseNotes/{intuition,layout,window,scroller,clicktab,gadtools,wb,Pointer}-RelNotes Updated: 2026-11-13