[← Home](../README.md) · [Intuition](README.md)
# IntuitionBase — Global GUI State
## What Is IntuitionBase?
`IntuitionBase` is the library base structure for `intuition.library` — the heart of the Amiga's graphical user interface. Unlike modern systems where the window manager is a separate process, Intuition is a **shared library** loaded into the system's address space. `IntuitionBase` contains the global state for all screens, windows, and input routing.
Every Amiga GUI program begins by opening this library:
```c
struct IntuitionBase *IntuitionBase;
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39);
if (!IntuitionBase)
{
/* Running on a system older than OS 3.0 — exit gracefully */
return RETURN_FAIL;
}
```
### Version Requirements
| Version | OS Release | Key Features Added |
|---|---|---|
| 33 | 1.2 | Original Intuition |
| 36 | 2.0 | TagList APIs, public screens, BOOPSI, GadTools |
| 37 | 2.04 | Improved memory handling |
| 39 | 3.0 | New-look menus, enhanced DrawInfo, `ChangeWindowBox()` |
| 40 | 3.1 | AppWindow/AppIcon improvements |
| 47 | 3.2 | OS 3.2 additions (enhanced backfill, new screen tags) |
| 50+ | 3.2.x | Continued 3.2 line improvements |
---
## struct IntuitionBase
```c
/* intuition/intuitionbase.h — NDK 3.9 */
struct IntuitionBase {
struct Library LibNode; /* Standard library node */
struct View ViewLord; /* Master graphics View */
struct Window *ActiveWindow; /* Currently active window */
struct Screen *ActiveScreen; /* Currently active screen */
struct Screen *FirstScreen; /* Head of screen linked list */
ULONG Flags; /* Internal state flags */
WORD MouseY, MouseX; /* Current mouse position */
ULONG Seconds, Micros; /* Current timestamp */
/* ... many private/internal fields follow ... */
};
```
### Field Reference
| Field | Type | Description | Safe to Read? |
|---|---|---|---|
| `LibNode` | `struct Library` | Standard Exec library header — version, open count, etc. | Yes |
| `ViewLord` | `struct View` | Master `View` structure — controls the entire display through the Copper | **No** — use graphics.library functions |
| `ActiveWindow` | `struct Window *` | Pointer to the currently active window | Yes (with `Forbid()`/`Permit()`) |
| `ActiveScreen` | `struct Screen *` | Pointer to the currently active screen | Yes (with `Forbid()`/`Permit()`) |
| `FirstScreen` | `struct Screen *` | Head of the screen list (front-to-back order) | Yes (with `Forbid()`/`Permit()`) |
| `Flags` | `ULONG` | Internal state flags | **No** — private |
| `MouseY`, `MouseX` | `WORD` | Absolute mouse position on active screen | Yes |
| `Seconds`, `Micros` | `ULONG` | System timestamp of last input event | Yes |
> **Warning**: Fields beyond those listed above are **private** and change between OS versions. Accessing undocumented fields will break your program on different OS releases.
---
## Using IntuitionBase
### Reading the Active Window
```c
/* Must protect with Forbid/Permit — ActiveWindow can change asynchronously */
Forbid();
struct Window *active = IntuitionBase->ActiveWindow;
if (active)
{
/* Read what you need while protected */
STRPTR title = active->Title;
/* ... */
}
Permit();
```
### Walking the Screen List
```c
Forbid();
struct Screen *scr = IntuitionBase->FirstScreen;
while (scr)
{
Printf("Screen: %s (%ldx%ld)\n",
scr->Title ? scr->Title : "(no title)",
scr->Width, scr->Height);
scr = scr->NextScreen;
}
Permit();
```
### Reading Mouse Position
```c
/* Global mouse position (relative to active screen) */
WORD mx = IntuitionBase->MouseX;
WORD my = IntuitionBase->MouseY;
/* For window-relative position, use Window->MouseX/MouseY instead */
```
---
## The ViewLord
`IntuitionBase->ViewLord` is the master `struct View` — the top-level graphics structure that controls the entire display. Intuition builds a Copper list from this View to render all screens.
```mermaid
graph TB
VL["ViewLord
(struct View)"] --> VP1["ViewPort 1
Workbench Screen"]
VL --> VP2["ViewPort 2
Custom Screen"]
VL --> VP3["ViewPort 3
Game Screen"]
VP1 --> BM1["BitMap 1"]
VP2 --> BM2["BitMap 2"]
VP3 --> BM3["BitMap 3"]
style VL fill:#e8f4fd,stroke:#2196f3,color:#333
```
You should **never** modify the ViewLord directly. Use `MakeScreen()`, `RethinkDisplay()`, or `RemakeDisplay()`:
```c
/* After changing a screen's ViewPort (e.g., palette): */
MakeScreen(scr); /* Rebuild this screen's Copper list */
RethinkDisplay(); /* Rebuild the entire display from ViewLord */
/* Or the combined version: */
RemakeDisplay(); /* MakeScreen + RethinkDisplay for all screens */
```
---
## Library Functions Overview
### Screen Management
| Function | Description |
|---|---|
| `OpenScreenTagList()` | Open a new screen with tag-based configuration |
| `CloseScreen()` | Close a screen (all windows must be closed first) |
| `LockPubScreen()` | Lock a public screen by name (prevents closing) |
| `UnlockPubScreen()` | Release a public screen lock |
| `PubScreenStatus()` | Set public screen state (available / private) |
| `GetScreenDrawInfo()` | Get pen and font information for a screen |
| `FreeScreenDrawInfo()` | Release DrawInfo |
| `ScreenToFront()` / `ScreenToBack()` | Change screen depth order |
| `MoveScreen()` | Move screen vertically |
### Window Management
| Function | Description |
|---|---|
| `OpenWindowTagList()` | Open a new window with tag-based configuration |
| `CloseWindow()` | Close a window |
| `ActivateWindow()` | Make a window active |
| `WindowToFront()` / `WindowToBack()` | Change window depth |
| `MoveWindow()` / `SizeWindow()` | Adjust window position/size |
| `ChangeWindowBox()` | Set absolute position and size |
| `SetWindowTitles()` | Change window and screen titles |
| `SetWindowPointer()` | Set custom or busy pointer |
### Gadget Management
| Function | Description |
|---|---|
| `AddGadget()` / `RemoveGadget()` | Add/remove gadgets from windows |
| `RefreshGList()` | Redraw gadget(s) |
| `SetGadgetAttrs()` | Set BOOPSI gadget attributes |
| `ModifyIDCMP()` | Change IDCMP flags dynamically |
### Menu Management
| Function | Description |
|---|---|
| `SetMenuStrip()` | Attach menu strip to window |
| `ClearMenuStrip()` | Remove menu strip from window |
| `OnMenu()` / `OffMenu()` | Enable/disable menu items |
| `ItemAddress()` | Get MenuItem pointer from packed menu number |
### Requesters and Dialogs
| Function | Description |
|---|---|
| `EasyRequest()` | Show a simple message dialog |
| `BuildEasyRequest()` | Create a non-blocking requester |
| `SysReqHandler()` | Poll a non-blocking requester |
| `FreeSysRequest()` | Free a non-blocking requester |
| `AutoRequest()` | Legacy two-button dialog (OS 1.x) |
### Rendering Support
| Function | Description |
|---|---|
| `DrawBorder()` | Draw a `struct Border` |
| `PrintIText()` | Draw `struct IntuiText` |
| `BeginRefresh()` / `EndRefresh()` | Simple-refresh window support |
| `LockIBase()` / `UnlockIBase()` | Lock IntuitionBase for multi-field reads |
---
## LockIBase — Safe Multi-Field Access
When reading multiple IntuitionBase fields that must be consistent, use `LockIBase()`:
```c
ULONG lock = LockIBase(0);
struct Window *active = IntuitionBase->ActiveWindow;
struct Screen *screen = IntuitionBase->ActiveScreen;
/* Both refer to the same moment in time */
UnlockIBase(lock);
```
Without the lock, `ActiveWindow` could change between reading it and reading `ActiveScreen` — giving you a window on a different screen than expected.
> `LockIBase()` is heavier than `Forbid()`/`Permit()` — use it only when you need atomic multi-field reads. For single field access, `Forbid()`/`Permit()` is sufficient.
---
## Pitfalls
### 1. Not Checking Library Version
Opening `intuition.library` version 0 succeeds on any system, but tag-based functions (`OpenWindowTags`, `OpenScreenTags`) require version 36+. Always specify the minimum version you need.
### 2. Reading Private Fields
Many tools and examples from the late '80s directly access internal IntuitionBase fields (like internal semaphores or the gadget environment). These fields **moved between OS versions** — code that worked on 1.3 crashed on 2.0, and code that worked on 3.1 crashes on 3.2.
### 3. Writing to IntuitionBase
Never write to IntuitionBase fields directly. Use the provided API functions. Direct writes bypass Intuition's internal state management and cause corruption.
### 4. Forgetting Forbid/Permit
`ActiveWindow`, `ActiveScreen`, and `FirstScreen` can change at any time (multitasking). Reading without `Forbid()`/`Permit()` or `LockIBase()` creates a race condition.
---
## Best Practices
1. **Open with the minimum version you need** — e.g., `OpenLibrary("intuition.library", 39)` for OS 3.0 features
2. **Use `LockIBase()`** for atomic multi-field reads from IntuitionBase
3. **Use `Forbid()`/`Permit()`** for quick single-field reads
4. **Never access undocumented fields** — they change between OS versions
5. **Never modify IntuitionBase** — use API functions
6. **Close the library** when done — `CloseLibrary((struct Library *)IntuitionBase)`
7. **Check the library pointer** before using any functions — it may be NULL on pre-2.0 systems
---
## References
- NDK 3.9: `intuition/intuitionbase.h`, `intuition/intuition.h`
- ADCD 2.1: `OpenLibrary()`, `LockIBase()`, `UnlockIBase()`
- AmigaOS Reference Manual (RKRM): Libraries, Chapter 2 — Intuition Overview
- See also: [Screens](screens.md), [Windows](windows.md), [IDCMP](idcmp.md)