Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "Intuition Library"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
Line 146: Line 146:
 
<center>'''Figure 2-5: An Intuition Requester'''</center>
 
<center>'''Figure 2-5: An Intuition Requester'''</center>
   
Requesters are discussed in detail in Chapter 7, "Intuition Requesters and Alerts". Additional information on programming requesters for Release 2 of the system can be found in Chapter 16, "ASL Library".
+
Requesters are discussed in detail in [[Intuition_Requesters_and_Alerts|Intuition Requesters and Alerts]]. Additional information on programming requesters can be found in [[ASL_Library|ASL Library]].
   
 
==== The Intuition Input Event Loop ====
 
==== The Intuition Input Event Loop ====

Revision as of 21:02, 17 April 2012

Intuition and the Amiga Graphical User Interface

Intuition is the collective name for the function libraries, data structures and other elements needed to create a graphical interface for Amiga applications. Programmers use Intuition to perform user interface chores such as opening windows, managing menus, monitoring gadgets, reading the mouse position and so forth.

Newcomers to the Amiga sometimes think of Intuition as the Amiga's operating system but it is not. Intuition is just one component that together with Exec, AmigaDOS, and other subsystems make up the whole operating system. Intuition is the most visible part of the operating system though since it provides the graphical user interface familiar to all Amiga users.

About User Interfaces

What is a user interface? This sweeping phrase covers all aspects of communication between the user and the computer. It includes the innermost mechanisms of the computer and rises to the height of defining a philosophy to guide the interaction between human and machine. Intuition is, above all else, a philosophy turned into software.

Intuition’s user interface philosophy is simple to describe: the interaction between the user and the computer should be consistent, simple and enjoyable; in a word, intuitive. Intuition supplies the tools needed to turn this philosophy into practice.

Implicit in this philosophy is the idea that the user interface should be graphical. A graphical user interface, or GUI, is a visually oriented method of communicating with a computer in which system resources are represented by pictorial symbols that can be manipulated with a pointing device such as a mouse. Other types of user interfaces are possible such as the Amiga’s Shell in which text commands are entered by typing them at the keyboard. For more information about user interfaces, refer to the Amiga User Interface Style Guide.

Elements of the Amiga graphical user interface system

There is more to the Amiga user interface than Intuition. To build a complete user interface, application writers need to understand these other elements of the system software.

Elements of the Amiga Graphical User Interface System

System Element Purpose
Intuition The main toolkit and function library for creating a graphical user interface (GUI) on the Amiga.
Workbench The Amiga file system GUI in which icons represent applications and files.
Preferences A family of editors and configuration files for setting Amiga system options.
BOOPSI Subsystem of Intuition that allows applications to add extensions to Intuition through object-oriented techniques (Release 2 only).
Gadtools Library A support library for creating Intuition gadgets and menus (Release 2 only).
ASL Library A support library for creating Intuition requesters (Release 2 only).
Icon Library Main library for using Workbench icons.
Workbench Library A support library for Workbench icons and menus (Release 2 only).
Console Device An I/O support module which allows windows to be treated as text-based virtual terminals.
Graphics Library The main library of rendering and drawing routines.
Layers Library A support library that manages overlapping, rectangular drawing areas which Intuition uses for windows.

As you read about Intuition in the chapters to follow, you will be introduced to each of these elements of the Amiga user interface in more detail.

Goals of Intuition

Intuition was designed with two major goals in mind. The first is to give users a friendly and consistent environment to control the functions of the Amiga operating system and its applications.

The second goal (the big one) is to give application designers a graphical user interface toolkit that manages all the complexities of sharing the system with other programs that may be running at the same time. Since the Amiga is a multitasking computer, many programs can reside in memory at the same time sharing the system's resources with one another. Programs take turns running so that, from the user's point of view, it appears that many programs are running simultaneously.

On a multitasking computer like the Amiga, the user interface design must allow the user to control many programs with just one monitor, one keyboard, and one mouse. (Imagine driving many cars simultaneously with one steering wheel.) Intuition supplies the tools needed to solve this problem.

How the User Sees Intuition

Intuition solves the problem of interacting with multiple programs by dividing the display up into multiple screens and overlapping windows so that each application has its own work area. The user sees the Amiga environment through these windows, each of which can represent a different task or application context.

The user performs operations inside screens and windows with the mouse, a mechanical device that moves a pointer over the Amiga's display. The user moves the mouse to position the pointer on graphic symbols of various objects or actions. Buttons on the mouse are pressed to select or activate the item pointed to.

The user can switch back and forth between different jobs, such as writing a document, drawing an illustration, printing text, or getting help from the system simply by moving from one window to another with the mouse. With the mouse, the user can also change the shape and size of application windows, move them around on the screen, overlap them, bring a window to the foreground, and send a window to the background. By changing the arrangement of the windows, the user selects which information is visible and which application to work with next. (Screens may also be moved up or down in the display, and they can be moved in front of or behind other screens.)

LibFig2-1.png
Figure 2-1: The Workbench Screen With Windows

Workbench and Preferences

Normally, the Workbench screen (shown above) is the first screen the user sees upon booting the Amiga. Workbench is a special program supplied with every Amiga that gives the user a friendly and consistent graphic interface to the file system. It's the default environment the user starts out with.

In Workbench, disks, directories, files and other objects are symbolized by small pictures called icons which can be manipulated with the mouse. For instance, a program file can be executed by pointing to its icon with the mouse and double-clicking the left mouse button. The Workbench screen is automatically set up by Intuition and can be easily shared, so many application programs use it too.

User control of the OS is also supported through Preferences. Preferences is a family of editors and associated configuration files that allow the user to control the basic set up of the operating system. For example Printer Preferences sets up all the printer options.

Workbench, together with Preferences, gives the user an easy way to control the OS and launch applications. These programs are built with the same Intuition tools available to application programmers giving the whole Amiga system an integrated look and feel. Workbench and Preferences are important components of the Amiga graphic user interface system and are discussed in greater detail in later chapters.

How an Application Sees Intuition

Intuition is organized as a library of over 100 functions. Before using an Intuition function you must first open the Intuition library. (In general, you must always open a library before you can call the functions of that library. See Chapter 1, "Introduction to Amiga System Libraries".)

Components of Intuition

The types of data objects that the Intuition library functions create and control fall into six broad categories. These are the main components an application uses to build and operate a graphic user interface on the Amiga.

GUI Components of Intuition

Screens The display environment. Sets the resolution and number of colors.
Windows A graphic rectangle within a screen representing a working context.
Menus A list of choices displayed at the top of a screen that can be selected with the mouse.
Gadgets A control symbolized by a graphic image that can be operated with the mouse or keyboard.
Requesters Sub-windows for confirming actions, accessing files and other special options.
Input events Mouse, keyboard or other input activity.

Screens and Windows

As mentioned earlier, Intuition allows multiple programs to share the display by managing a system of multiple screens and overlapping windows. A screen sets up the display environment and forms the background that application windows operate in. A window is simply a graphic rectangle that represents a work context. Each screen can have many windows on it.

Multiple screens and windows give each application its own separate visual context so that many programs can output graphics and text to the display at the same time without interfering with one another. Intuition (using the layers library) handles all the details of clipping graphics so they stay inside window bounds and remembering graphics that go temporarily out of sight when the user rearranges windows.

The keyboard and mouse are shared among applications through a simpler technique: only one application window at a time can have the input focus. Hence, Intuition ensures that only one window, called the active window gets to know about keyboard, mouse and other types of input activity.

Each application window is like a virtual terminal or console. Your program will seem to have the entire machine and display to itself. It can send text and graphics to its terminal window, and ask for input from any number of sources, ignoring the fact that other programs may be performing these same operations. Intuition handles all the housekeeping. In fact, your program can open several of these virtual terminals and treat each one as if it were the only program running on the machine. Intuition will keep track of all the activity and make sure commands and data are dispatched to the right place.

Gadgets, Menus and Requesters

Intuition screens and windows provide an orderly way for multiple programs to share the display and input devices. Each application also needs a method for the user to send commands to it and select its options. Intuition supplies gadgets, menus and requesters for this purpose.

Gadgets

A gadget is an application control symbolized by a graphic image that can be operated with the mouse or keyboard. The imagery used for a gadget could look like a switch, a knob, a button, or just about anything. Intuition supplies some prefabricated gadgets, called system gadgets, for controlling window and screen arrangements. Other gadget types allow the user to select colors, enter text or numbers, and perform other simple operations.

LibFig2-3.png
Figure 2-3: An Intuition Window with Gadgets

Most of the user's input for a typical Intuition application will be obtained with gadgets. Gadgets are discussed in detail in Intuition Gadgets. Additional information on programming gadgets can be found in GadTools Library.

Menus

Intuition also supplies a menu system for accepting commands and options from the user. A menu is a list of choices displayed at the top of the screen from which the user can select with the mouse. Each screen has one menu bar that all application windows operating on the screen share. Whichever window is active controls what appears in the menu bar.

LibFig2-4.png
Figure 2-4: An Intuition Menu

The current set of menu choices can always be brought into view by pressing the right mouse button (the menu button) thus providing the user with a familiar landmark even in unfamiliar applications. Menus allow the user to browse through the possible set of actions that can be performed giving an outline-like overview of the functions offered by a program.

Menus are discussed in detail in Intuition Menus. Additional information on programming menus can be found in GadTools Library.

Requesters

Gadgets and menus do much of the work of getting commands and option choices from the user. Sometimes though, an application needs to get further information from a user in response to a command which has already been initiated. In that case, a requester can be used. A requester is a temporary sub-window, usually containing several gadgets, used to confirm actions, access files, or adjust the special options of a command the user has already given.

LibFig2-5.png
Figure 2-5: An Intuition Requester

Requesters are discussed in detail in Intuition Requesters and Alerts. Additional information on programming requesters can be found in ASL Library.

The Intuition Input Event Loop

Once an application has set up the appropriate screen, window, gadgets menus and requesters, it waits for the user to do something. Intuition can notify an application whenever user activity occurs by sending a message. The message is simply a pointer to some memory owned by Intuition that contains an IntuiMessage data structure describing the user activity that occurred.

To wait for user activity or other events, the Exec library provides a special function named Wait(). The Exec Wait() function suspends your task allowing other applications or system tasks to run while your application is waiting for input or events from Intuition and other sources.

Thus, the basic outline for any Intuition program is:

  • Set up the window, screen and any required gadgets, menus or requesters.

  • Wait()

    for a message from Intuition about user activity or other events. Copy needed data from the message and tell Intuition you received it by replying. Look at the data and take the appropriate action.

  • Repeat until the user wants to quit.

These steps, sometimes referred to as the Intuition input event loop are basically the same for any Intuition application.

As you might expect, Intuition can send a message to your application whenever the user presses a key on the keyboard or moves the mouse. Other types of input events Intuition will notify you about include gadget hits, menu item selection, time elapsing, disk insertion, disk removal, and window rearrangement.

Gadgets, menus, requesters are the nuts and bolts of the Intuition GUI toolkit. Much of the code in an application that uses Intuition deals with the set up and operation of these important data objects. No matter how simple, complex, or fanciful your program design, it will fit within the basic Intuition framework of windows and screens, gadgets, menus and requesters. The users of the Amiga understand these basic Intuition elements and trust that the building blocks remain constant. This consistency ensures that a well-designed program will be understandable to the naive user as well as to the sophisticate.

A Simple Intuition Program

The sample Intuition program that follows shows all of the basic requirements for an Intuition application. There are three important points:

  • You must open the Intuition library before you can use the Intuition functions. Certain languages such as C require the pointer to the Intuition library to be assigned to a variable called IntuitionBase (see Chapter 1 for more about this).
  • When you set up a window, you also specify the events that you want to know about. If the user performs some activity that triggers one of the events you specified, Intuition signals you and sends a message. The message is a pointer to an IntuiMessage data structure that describes the event in more detail. Messages about Intuition events are sent to a MsgPort structure which queues up the messages for you in a linked list so that you may respond to them at your convenience.
  • Resources must be returned to the system. In this case, any windows, screens or libraries that were opened are closed before exiting.

Example Intuition event loop

The Intuition event loop used in the example is very simple. The example first sets up a custom screen, opens a window on it, then waits for Intuition to send messages about user input with the following event loop:

    winsignal = 1L << window1->UserPort->mp_SigBit;  /* window signal */
    signalmask = winsignal;   /* example only waits for window events */

    while( !done )  {
        signals = Wait(signalmask);
        if (signals & winsignal)
            done = handleIDCMP(window1);
    }


Intuition sends messages about user activity to a special port known as the IDCMP. Each window can have its own IDCMP (in the code above the IDCMP is window1->UserPort). To wait for event messages to arrive at the IDCMP port, the example code calls the Exec Wait() function. It then processes and replies to any event messages that it gets in a subroutine named handleIDCMP(). For this example, the only event Intuition will report is the close window event. When the example detects this event, it closes the window, closes the screen, closes the Intuition library and exits. Event loops similar to this one are used in Intuition examples throughout this book. For more information about IDCMP and user input, see the chapters on “Intuition Windows” and “Intuition Input and Output”.

Intuition example (V36 and later)

This example shows a simple Intuition program that works with Release 2 (V36) and later versions of the Amiga operating system.


/* easyintuition37.c -- Simple Intuition program for V37   */
/* (Release 2) and later versions of the operating system. */
/* Compiled with Lattice C v5.04: lc -L easyintuition37.c  */

#include <exec/types.h>             /* The Amiga data types file.         */
#include <intuition/intuition.h>    /* Intuition data strucutres, etc.    */
#include <graphics/displayinfo.h>   /* Release 2 Amiga display mode ID's  */
#include <libraries/dos.h>          /* Official return codes defined here */

#include <clib/exec_protos.h>       /* Exec function prototypes           */
#include <clib/intuition_protos.h>  /* Intuition function prototypes      */

/* Force use of new variable names to help prevent errors  */
#define INTUI_V36_NAMES_ONLY

#ifdef LATTICE                      /* Disable Ctrl-C handling in SAS/C   */
int CXBRK(void)  {return(0);}
void chkabort(void) {return;}
#endif

/* Use lowest non-obsolete version that supplies the functions needed. */
#define INTUITION_REV 37

/* Declare the prototypes of our own functions.  Prototypes for system */
/* functions are declared in the header files in the clib directory.   */
VOID cleanExit( struct Screen *, struct Window *, LONG );
BOOL handleIDCMP( struct Window *);

struct Library *IntuitionBase = NULL;

/* Position and sizes for our window */
#define WIN_LEFTEDGE   20
#define WIN_TOPEDGE    20
#define WIN_WIDTH     400
#define WIN_MINWIDTH   80
#define WIN_HEIGHT    150
#define WIN_MINHEIGHT  20


VOID main(int argc, char *argv[])
{
    /* Declare variables here */
    ULONG signalmask, winsignal, signals;
    BOOL done = FALSE;
    UWORD pens[]={~0};

    struct Screen *screen1 = NULL;
    struct Window *window1 = NULL;

    /* Open the Intuition Library */
    IntuitionBase = OpenLibrary( "intuition.library",INTUITION_REV );
    if (IntuitionBase == NULL)
        cleanExit(screen1, window1, RETURN_WARN);

    /* Open any other required libraries and make */
    /* any assignments that were postponed above  */

    /* Open the screen */
    screen1 = OpenScreenTags(NULL,
                             SA_Pens,  (ULONG)pens,
                             SA_DisplayID, HIRES_KEY,
                             SA_Depth, 2,
                             SA_Title, (ULONG)"Our Screen",
                             TAG_DONE);

    if (screen1 == NULL)
        cleanExit(screen1, window1, RETURN_WARN);

    /* ... and open the window */
    window1 = OpenWindowTags(NULL,
                             /* Specify window dimensions and limits */
                             WA_Left,         WIN_LEFTEDGE,
                             WA_Top,          WIN_TOPEDGE,
                             WA_Width,        WIN_WIDTH,
                             WA_Height,       WIN_HEIGHT,
                             WA_MinWidth,     WIN_MINWIDTH,
                             WA_MinHeight,    WIN_MINHEIGHT,
                             WA_MaxWidth,     ~0,
                             WA_MaxHeight,    ~0,
                             /* Specify the system gadgets we want */
                             WA_CloseGadget,  TRUE,
                             WA_SizeGadget,   TRUE,
                             WA_DepthGadget,  TRUE,
                             WA_DragBar,      TRUE,
                             /* Specify other attributes           */
                             WA_Activate,     TRUE,
                             WA_NoCareRefresh,TRUE,

                             /* Specify the events we want to know about */
                             WA_IDCMP,        IDCMP_CLOSEWINDOW,

                             /* Attach the window to the open screen ...*/
                             WA_CustomScreen, screen1,
                             WA_Title,        "EasyWindow",
                             WA_ScreenTitle,  "Our Screen - EasyWindow is Active",
                             TAG_DONE);
    if (window1 == NULL)
        cleanExit(screen1, window1, RETURN_WARN);

    /* Set up the signals for the events we want to hear about ...   */
    winsignal = 1L << window1->UserPort->mp_SigBit;  /* window IDCMP */
    signalmask = winsignal;   /* we are only waiting on IDCMP events */

    /* Here's the main input event loop where we wait for events.    */
    /* We have asked Intuition to send us CLOSEWINDOW IDCMP events   */
    /* Exec will wake us if any event we are waiting for occurs.     */
    while( !done )
    {
        signals = Wait(signalmask);

        /* An event occurred - now act on the signal(s) we received.*/
        /* We were only waiting on one signal (winsignal) in our    */
        /* signalmask, so we actually know we received winsignal.   */
        if(signals & winsignal)
            done = handleIDCMP(window1);    /* done if close gadget */
    }
    cleanExit(screen1, window1, RETURN_OK); /* Exit the program     */
}

BOOL handleIDCMP( struct Window *win )
{
    BOOL done = FALSE;
    struct IntuiMessage *message = NULL;
    ULONG class;

    /* Examine pending messages */
    while( message = (struct IntuiMessage *)GetMsg(win->UserPort) )
    {
        class = message->Class;  /* get all data we need from message */

        /* When we're through with a message, reply */
        ReplyMsg( (struct Message *)message);

        /* See what events occurred */
        switch( class )
        {
            case IDCMP_CLOSEWINDOW:
                done = TRUE;
                break;
            default:
                break;
        }
    }
    return(done);
}

VOID cleanExit( struct Screen *scrn, struct Window *wind, LONG returnValue )
{
    /* Close things in the reverse order of opening */
    if (wind) CloseWindow( wind );      /* Close window if opened */
    if (scrn) CloseScreen( scrn );      /* Close screen if opened */

    /* Close the library, and then exit */
    if (IntuitionBase) CloseLibrary( IntuitionBase );
    exit(returnValue);
}

Intuition example (all versions)

Here’s the same example as above written for both Release 2 and earlier versions of the operating system. The main difference here is that this example avoids using any new Release 2 functions, but does pass extended structures to the older Intuition functions so that some new Release 2 features may be accessed in a backward-compatible manner.


/* easyintuition.c  Simple backward-compatible V37 Intuition example    */
/*                                                                      */
/* This example uses extended structures with the pre-V37 OpenScreen()  */
/* and OpenWindow() functions to compatibly open an Intuition display.  */
/* Enhanced V37 options specified via tags are ignored on 1.3 systems.  */
/* Compiled with Lattice C v5.10: lc -L easyintuition.c                 */

/* Force use of new variable names to help prevent errors  */
#define INTUI_V36_NAMES_ONLY

#include <exec/types.h>             /* The Amiga data types file.         */
#include <intuition/intuition.h>    /* Intuition data strucutres, etc.    */
#include <libraries/dos.h>          /* Official return codes defined here */

#include <clib/exec_protos.h>       /* Exec function prototypes           */
#include <clib/intuition_protos.h>  /* Intuition function prototypes      */

#ifdef LATTICE                      /* Disable Ctrl-C handling in SAS/C   */
int CXBRK(void)  {return(0);}
void chkabort(void) {return;}
#endif

/* Use lowest non-obsolete version that supplies the functions needed. */
#define INTUITION_REV 33L

/* Declare the prototypes of our own functions. Prototypes for system  */
/* functions are declared in the header files in the clib directory    */
VOID cleanExit( struct Screen *, struct Window *, LONG );
BOOL handleIDCMP( struct Window *);

struct Library *IntuitionBase = NULL;

/* We can specify that we want the V37-compatible 3D look when
 * running under V37 by adding an SA_Pens tag.
 */
WORD pens[] = {~0}; /* empty pen array to get default 3D look */
struct TagItem ourscreentags[] = {
    { SA_Pens, (ULONG)pens },
    { TAG_DONE }};

/* ExtNewScreen is an extended NewScreen structure.
 * NS_EXTENDED flags that there is a tag pointer to additional
 * tag information at the end of this structure.  The tags will
 * be parsed by Release 2 but ignored by earlier OS versions.
 */
struct ExtNewScreen fullHires =
    {
    0,                /* LeftEdge must be zero prior to Release 2 */
    0,                /* TopEdge */
    640,              /* Width (high-resolution) */
    STDSCREENHEIGHT,  /* Height (non-interlace)  */
    2,                /* Depth (4 colors will be available) */
    0,1,              /* Default DetailPen and BlockPen  */
    HIRES,            /* the high-resolution display mode */
    CUSTOMSCREEN | NS_EXTENDED,     /* the screen type */
    NULL,             /* no special font */
    "Our Screen",     /* the screen title */
    NULL,             /* no custom screen gadgets (not supported) */
    NULL,             /* no CustomBitMap */
    ourscreentags     /* tags for additional V37 features */
    };

/* Position and sizes for our window */
#define WIN_LEFTEDGE   20
#define WIN_TOPEDGE    20
#define WIN_WIDTH     400
#define WIN_MINWIDTH   80
#define WIN_HEIGHT    150
#define WIN_MINHEIGHT  20

/* Under V37, we'll get a special screen title when our window is active */
UBYTE activetitle[] = {"Our Screen - EasyWindow is Active"};

struct TagItem ourwindowtags[] = {
    { WA_ScreenTitle, (ULONG)&activetitle[0] },
    { TAG_DONE }};

/* ExtNewWindow is an extended NewWindow structure.
 * NW_EXTENDED indicates that there is a tag pointer to additional tag
 * information at the end of this structure.  The tags will be parsed
 * by Release 2 but ignored by earlier OS versions.
 */
struct ExtNewWindow easyWindow =
    {
    WIN_LEFTEDGE,
    WIN_TOPEDGE,
    WIN_WIDTH,
    WIN_HEIGHT,
    -1,-1,             /* Means use the screen's Detail and Block pens   */

    IDCMP_CLOSEWINDOW, /* This field specifies the events we want to get */

    /* These flags specify system gadgets and other window attributes    */
    /* including the EXTENDED flag which flags this as an ExtNewWindow   */
    WFLG_CLOSEGADGET | WFLG_SMART_REFRESH | WFLG_ACTIVATE | WFLG_DRAGBAR |
    WFLG_DEPTHGADGET | WFLG_SIZEGADGET  | WFLG_NOCAREREFRESH |
    WFLG_NW_EXTENDED,

    NULL,             /* Pointer to the first gadget  */
    NULL,             /* No checkmark.                */
    "EasyWindow",     /* Window title.                */
    NULL,             /* Attach a screen later.       */
    NULL,             /* Let Intuition set up BitMap  */
    WIN_MINWIDTH,     /* Minimum width.       */
    WIN_MINHEIGHT,    /* Minimum height.      */
    -1,               /* Maximum width (screen size)  */
    -1,               /* Maximum height (screen size) */
    CUSTOMSCREEN,     /* A screen of our own. */
    ourwindowtags     /* tags for additional V37 features */
    };


VOID main(int argc, char *argv[])
{
    /* Declare variables here */
    ULONG signalmask, winsignal, signals;
    BOOL done = FALSE;
    struct Screen *screen1 = NULL;
    struct Window *window1 = NULL;

    /* Open Intuition Library.  NOTE - We are accepting version 33 (1.2)
     * or higher because we are opening our display in a compatible manner.
     * However - If you add to this example, do NOT use any NEW V37
     * functions unless IntuitionBase->lib_Version is >= 37
     */
    IntuitionBase = OpenLibrary( "intuition.library",INTUITION_REV );
    if (IntuitionBase == NULL)
        cleanExit(screen1, window1, RETURN_WARN);

    /* Open any other required libraries and make */
    /* any assignments that were postponed above  */

    /* Open the screen */
    screen1 = OpenScreen(&fullHires);
    if (screen1 == NULL)
        cleanExit(screen1, window1, RETURN_WARN);

    /* Attach the window to the open screen ... */
    easyWindow.Screen = screen1;

    /* ... and open the window */
    window1 = OpenWindow(&easyWindow);
    if (window1 == NULL)
        cleanExit(screen1, window1, RETURN_WARN);

    /* Set up the signals for the events we want to hear about ...   */
    winsignal = 1L << window1->UserPort->mp_SigBit;  /* window IDCMP */
    signalmask = winsignal;     /* we will only wait on IDCMP events */

    /* Here's the main input event loop where we wait for events.    */
    /* We have asked Intuition to send us CLOSEWINDOW IDCMP events   */
    /* Exec will wake us if any event we are waiting for occurs.     */
    while( !done )
    {
        signals = Wait(signalmask);

        /* An event occurred - now act on the signal(s) we received.*/
        /* We were only waiting on one signal (winsignal) in our    */
        /* signalmask, so we actually know we received winsignal.   */
        if(signals & winsignal)
            done = handleIDCMP(window1);    /* done if close gadget */
    }
    cleanExit(screen1, window1, RETURN_OK); /* Exit the program     */
}


BOOL handleIDCMP( struct Window *win )
{
    BOOL done = FALSE;
    struct IntuiMessage *message;
    ULONG class;

    /* Examine pending messages */
    while( message = (struct IntuiMessage *)GetMsg(win->UserPort) )
    {
        class = message->Class;   /* get all data we need from message */

        /* When we're through with a message, reply */
        ReplyMsg( (struct Message *)message);

        /* See what events occurred */
        switch( class )
        {
            case IDCMP_CLOSEWINDOW:
                done = TRUE;
                break;
            default:
                break;
        }
    }
    return(done);
}


VOID cleanExit( struct Screen *scrn, struct Window *wind, LONG returnValue )
{
    /* Close things in the reverse order of opening */
    if (wind) CloseWindow( wind );      /* Close window if opened */
    if (scrn) CloseScreen( scrn );      /* Close screen if opened */

    /* Close the library, and then exit */
    if (IntuitionBase) CloseLibrary( IntuitionBase );
    exit(returnValue);
}