






===========  C - Programmering  Amiga OS 2.xx  ===================
                                              Av Kjell Cederfeldt.
                                              Tel 0302-463 41,42
                                              FidoNet 2:203/319
Del 15. Söndag den 14 Mars 1993.
--------------------------------

I denna del kommer vi att ta upp grunderna ur intuition.library.
Det library som hanterar fönster, skärmar, menyer, gadgets mm.

Det är nu viktigt att man kan och förstår innehållet i de
tidigare kursdelarna.

Från och med version 2.0 (2.04) av operativsystemet, har det blivit
mycket enklare och trevligare att skapa och öppna fönster och
skärmar. Även gadgets och menyer har förenklats, men förenklingen
ligger i ett helt nytt library, Gadtools.library. Gadtools.library
har 18 (tagit ur Rom Kernal Referens manual Inkl & Autodoc Rev 3.)
funktioner. Dessa funktioner är till stor hjälp för skapande och
användning av gadgets (trycknappar) och menyer. Jag kommer att
blanda funktioner ur intuition.library och gadtools.library
efterhand som det behövs.


struct Window
{
  struct Window *NextWindow; /* nästa fönster */
  WORD LeftEdge, TopEdge;    /* Fönstrets position */
  WORD Width, Height;        /* bredd och höjd på fönstret */
  WORD MouseY, MouseX;       /* relative to upper-left of window */
  WORD MinWidth, MinHeight;  /* Minsta tillåtna bredd, höjd */
  UWORD MaxWidth, MaxHeight; /* Största tillåtna bredd, höjd */
  ULONG Flags;               /* Flaggor */
  struct Menu *MenuStrip;    /* Pekare till meny */
  UBYTE *Title;              /* Pekare till fönstertiteln */
  struct Requester *FirstRequest;   /* all active Requesters */
  struct Requester *DMRequest;      /* double-click Requester */
  WORD ReqCount;               /* count of reqs blocking Window */
  struct Screen *WScreen;      /* Skärmen som fönstret tillhör */
  struct RastPort *RPort;      /* fönstrets egna RastPort */
  BYTE BorderLeft, BorderTop, BorderRight, BorderBottom;
  struct RastPort *BorderRPort;
  struct Gadget *FirstGadget;  /* Pekare till gadget-lista */
  struct Window *Parent, *Descendant;
  UWORD *Pointer; /* sprite data */
  BYTE PtrHeight; /* sprite height (not including sprite padding) */
  BYTE PtrWidth;  /* sprite width (must be less than or equal to 16) */
  BYTE XOffset, YOffset;	/* sprite offsets */
  ULONG IDCMPFlags;	        /* Händelse-flaggor */
  struct MsgPort *UserPort, *WindowPort;  /* Meddelande port */
  struct IntuiMessage *MessageKey;
  UBYTE DetailPen, BlockPen;	/* for bar/border/gadget rendering */
  struct Image *CheckMark;
  UBYTE *ScreenTitle;      /* Skärm-titel då fönstret är aktivt */
  WORD GZZMouseX;
  WORD GZZMouseY;
  WORD GZZWidth;
  WORD GZZHeight;
  UBYTE *ExtData;
  BYTE *UserData;	/* general-purpose pointer to User data extension */
  struct Layer *WLayer;
  struct TextFont *IFont;  /* Pekare till fönster-text */
  ULONG	MoreFlags;
};

Mer förklaring av Struct Window finns i Autodocs.

Struct window innehåller uppgifter om ett öppnat fönster. Skall
inte förväxlas med struct NewWindow, som är en struktur som ifylles
då man vill öppna ett nytt fönster.

struct NewWindow
{
    WORD LeftEdge, TopEdge;		/* screen dimensions of window */
    WORD Width, Height;			/* screen dimensions of window */

    UBYTE DetailPen, BlockPen;		/* for bar/border/gadget rendering */

    ULONG IDCMPFlags;			/* User-selected IDCMP flags */

    ULONG Flags;			/* see Window struct for defines */

    /* You supply a linked-list of Gadgets for your Window.
     *	This list DOES NOT include system Gadgets.  You get the standard
     *	system Window Gadgets by setting flag-bits in the variable Flags (see
     *	the bit definitions under the Window structure definition)
     */
    struct Gadget *FirstGadget;

    /* the CheckMark is a pointer to the imagery that will be used when
     * rendering MenuItems of this Window that want to be checkmarked
     * if this is equal to NULL, you'll get the default imagery
     */
    struct Image *CheckMark;

    UBYTE *Title;			  /* the title text for this window */

    /* the Screen pointer is used only if you've defined a CUSTOMSCREEN and
     * want this Window to open in it.	If so, you pass the address of the
     * Custom Screen structure in this variable.  Otherwise, this variable
     * is ignored and doesn't have to be initialized.
     */
    struct Screen *Screen;

    /* WFLG_SUPER_BITMAP Window?  If so, put the address of your BitMap
     * structure in this variable.  If not, this variable is ignored and
     * doesn't have to be initialized
     */
    struct BitMap *BitMap;

    /* the values describe the minimum and maximum sizes of your Windows.
     * these matter only if you've chosen the WFLG_SIZEGADGET option,
     * which means that you want to let the User to change the size of
     * this Window.  You describe the minimum and maximum sizes that the
     * Window can grow by setting these variables.  You can initialize
     * any one these to zero, which will mean that you want to duplicate
     * the setting for that dimension (if MinWidth == 0, MinWidth will be
     * set to the opening Width of the Window).
     * You can change these settings later using SetWindowLimits().
     * If you haven't asked for a SIZING Gadget, you don't have to
     * initialize any of these variables.
     */
    WORD MinWidth, MinHeight;	    /* minimums */
    UWORD MaxWidth, MaxHeight;	     /* maximums */

    /* the type variable describes the Screen in which you want this Window to
     * open.  The type value can either be CUSTOMSCREEN or one of the
     * system standard Screen Types such as WBENCHSCREEN.  See the
     * type definitions under the Screen structure.
     */
    UWORD Type;

};

Tidigare var det lite "jobbigt" att öppna ett fönster eftersom man
var tvungen att fylla i NewWindowstrukturen med uppgifter och öppna
fönstret med OpenWindow(). Från och med OS2.0 slipper man detta.
Man kan istället använda OpenWindowTagList() eller
OpenWindowTags(). Skillnaden är alltså ifyllningen av NewWindow
strukturen. Man slipper fylla i hela strukturen innan man öppnar
ett fönster. OpenWindowTags() eller OpenWindowTagList() anger man
endast det som man vill skall vara unikt med fönstret (jämfört med
förvalda inställningar). Man kan alltså öppna ett fönster med
OpenWindowTags() eller OpenWindowTagList() utan att ange en enda
parameter, men då blir troligtvis inte fönstret som man tänkt sig.

Vi skall göra ett lite exempel som öppnar ett fönster och väntar
tills någon stänger det genom att klicka på close-gadgeten.

/*************************** Window.c ******************/
#include <stdio.h>
#include <stdlib.h>
#include <exec/exec.h>
#include <exec/libraries.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>

extern struct ExecBase  *SysBase;
extern struct Library   *DOSBase;
struct Library          *IntuitionBase;

void OpenLibs(void);
void Cleanup(int, STRPTR);

struct Window           *mywindow = NULL;


/****************************************************************/

void main(void)
{
struct IntuiMessage *message;     /* Meddelande från intuition   */
ULONG class = 0;                  /* Typ av IDCMP                */
struct Gadget *Gad;               /* Pekare till vilken gadget   */
UWORD code = 0;                   /* Specialvärde typ menynr osv */
BOOL terminated = FALSE;


    OpenLibs();

    mywindow = OpenWindowTags(NULL, WA_CloseGadget, TRUE,
                   WA_IDCMP, IDCMP_CLOSEWINDOW, TAG_DONE);

    if (!mywindow)
        Cleanup(10, "Kunde inte öppna fönstret");

    while(!terminated)
    {
        WaitPort(mywindow->UserPort);      /* Vänta på meddelande */

        while((!terminated) && (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)))
        {
            class = message->Class;
            code = message->Code;

            if ((class == IDCMP_GADGETUP) || (class==IDCMP_GADGETDOWN) || (class==IDCMP_MOUSEMOVE))
                Gad = (struct Gadget *) message->IAddress;

            ReplyMsg((struct Message *)message);

            switch(class)
            {
                case CLOSEWINDOW:
                    terminated = TRUE;
                    break;
            }
        }
    }

    if (mywindow)
    {
        CloseWindow(mywindow);
        mywindow = NULL;
    }

    Cleanup(0, NULL);
}


void OpenLibs(void)
{

    if (!(IntuitionBase = OpenLibrary("intuition.library",37L)))
        Cleanup(0, NULL);

}


void Cleanup(return_code, return_text)
int return_code;
STRPTR return_text;
{
    if (return_code)
        printf("%d: %s\n", return_code, return_text);

    if (IntuitionBase)
    {
        CloseLibrary(IntuitionBase);
        IntuitionBase = NULL;
    }

    exit(NULL);
}


Kompilera programmet ovan på följande sätt:

sc Window.c LINK


När vi kör programmet, öppnas ett stort fönster över hela
workbenchskärmen. Fönstret innehåller inget mer än en
closegadget (stängningsknapp).

Allt som behövdes för att öppna fönstret är:

    mywindow = OpenWindowTags(NULL, WA_CloseGadget, TRUE,
                   WA_IDCMP, IDCMP_CLOSEWINDOW, TAG_DONE);

Funktionen OpenWindowTags() lämnar en pekare till fönstret som
öppnats i retur. Första argumentet som OpenWindowTags() vill ha är
en pekare till en initierad NewWindow struktur. Om man utelämnar
NewWindowstrukturen genom att ange noll lägger OpenWindowTags()
in förvalda värden. Nästkommande argument är så kallande tags. Tags
är nytt för OS2.0 och gör livet för oss programmerare mycket
lättare. Tags kan anges i en funktion som en serie data, 
(OpenWindowTags() ) eller i form av en TagLista
( OpenWindowTagsList() ). Man kan alltså ange Tags direkt i
funktionen eller lagras i en taglista och istället skicka med
listan till funktionen. Hur som helst anges alltid Tags som en
serie data. Först kommer ett styrord (styrdata) och därpå själva
datat (värdet). I exemplet angav vi en Tags som hette
WA_CloseGadget. Denna Tags anger alltså om vi skall ha en
Closegadget eller inte. Efter WA_CloseGadget skickade vi med TRUE
för att tala om att vi ville ha en CloseGadget. Man kan inte enbart
ange styrorden. Det måste alltid ange tags parvis , styrord, data.
Undantaget är den sista Tag'en vilket ALLTID måste vara TAG_DONE.
TAG_DONE talar om att det inte kommer fler tags. I OpenWindowTags()
har tags högre prioritet än datat i NewWindowstrukturen. Alltså
om samma data anges i både newwindowstrukturen och i tags så är det
datat ur Tags som väljs.

I vårt exempel var vi två tagsitem (dataelementspost) förutom
TAG_DONE. Dessa var:

WA_CloseGadget, TRUE           Anger att vi vill ha en CloseGadget.
WA_IDCMP, IDCMP_CLOSEWINDOW    Lägger till Closewindow till
                               händelseflaggan.

Om dessa två tags uteblivit, hade fönstret inte fått sin
closegadget och därför inte gått att stänga genom att klicka på
stängningsknappen.

IDCMP är flaggor som man anger för att tala om vilka händelser som
man vill att fönstret skall reagera på. Varje händelse skickas av
intuition till programmet. Om man inte sätter att man vill ha en
händelse för 'CLOSEWINDOW' (stängfönster) så får man inget
meddelande när någon trycker på CloseGadget. Så även om man har en
CloseGadget, är det alltså inte säkert att man får ett meddelande
om det. Det finns flera olika händelseflaggor. Exempel på dessa är
händelser då någon trycker på en gadget, väljer en meny osv.

Varje händelse som man vill bevaka måste anges genom att sätta
motsvarande bit i IDCMPFlags. Som du ser i strukturen för Windows
är IDCMPFlags ett teckenlöst 'LONGWORDS'. 

Funktionen WaitPort(mywindow->UserPort) väntar på att det skall
komma ett meddelande till fönstrets 'UserPort'. Om ingen IDCMP
anges, lär det aldrig komma något. I vårt exempel kan det bara
komma ett då någon trycker på stängningsknappen.

Meddelandet läses med GetMsg(mywindow->UserPort). Inkommande
meddelande från intuition lagras ner i message.

            class = message->Class;
            code = message->Code;

Meddelandets class motsvaras av IDCMP. Här kan man alltså avgöra
vilken händelse som inträffat. Code innehåller olika saker beroende
på vilken händelse som inträffar. Om det är en händelse då någon
valt en meny, finns här uppgifter om vilken meny som valts. Om det
är en händelse då någon tryckt på en CycleGadget (gadget som byter
text då man trycker på den, en slags lista över olika val)
innehåller code uppgift om indexnummret till texten  som visades
osv.

           Gad = (struct Gadget *) message->IAddress;

Gad innehåller adressen till vilken gadget som tryckts. Man bör
bara hämta denna uppgift i fall att det är en gadget som
meddelandet (händelsen) berör. Man bör alltså inte hämta adressen
till en gadget om det är en meny eller liknande som händelsen avser.

Vi har nu tagit reda på de uppgifter vi behöver. Vi gör därför en
ReplyMsg((struct Message *)message);

I detta fallet kanske det är lite onödigt med en switch(), men vi
kommer att bygga på programmet allt eftersom, så vi använder denna
tekniken. I switch-satsen avgörs vilken IDCMP som class
innehåller. I vårt fall kommer alltid case CLOSEWINDOW: att
utföras eftersom det är den enda möjliga händelsen.

Oavsett hur fönstret öppnades, stänger vi det med CloseWindow().
CloseWindow() vill (inte helt oväntat) ha en pekaren till fönstret.

I OpenLibs() funktionen öppnar vi intuition.library och i Cleanup()
stänger vi den.

Här kommer ett nytt exempel. Vi använder nu OpenWindowTagList()
istället för OpenWindowTags().

/*************************** Window.c ******************/
#include <stdio.h>
#include <stdlib.h>
#include <exec/exec.h>
#include <exec/libraries.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>

extern struct ExecBase  *SysBase;
extern struct Library   *DOSBase;
struct Library          *IntuitionBase;

void OpenLibs(void);
void Cleanup(int, STRPTR);

struct Window           *mywindow = NULL;

struct TagItem WindowTags[] =
{
   WA_IDCMP, IDCMP_CLOSEWINDOW,
   WA_Flags, WFLG_CLOSEGADGET,
   TAG_DONE

};

/****************************************************************/

void main(void)
{
struct IntuiMessage *message;     /* Meddelande från intuition   */
ULONG class = 0;                  /* Typ av IDCMP                */
struct Gadget *Gad;               /* Pekare till vilken gadget   */
UWORD code = 0;                   /* Specialvärde typ menynr osv */
BOOL terminated = FALSE;


    OpenLibs();

    mywindow = OpenWindowTagList(NULL, WindowTags);

    if (!mywindow)
        Cleanup(10, "Kunde inte öppna fönstret");

    while(!terminated)
    {
        WaitPort(mywindow->UserPort);      /* Vänta på meddelande */

        while((!terminated) && (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)))
        {
            class = message->Class;
            code = message->Code;

            if ((class == IDCMP_GADGETUP) || (class==IDCMP_GADGETDOWN) || (class==IDCMP_MOUSEMOVE))
                Gad = (struct Gadget *) message->IAddress;

            ReplyMsg((struct Message *)message);

            switch(class)
            {
                case CLOSEWINDOW:
                    terminated = TRUE;
                    break;
            }
        }
    }

    if (mywindow)
    {
        CloseWindow(mywindow);
        mywindow = NULL;
    }

    Cleanup(0, NULL);
}


void OpenLibs(void)
{

    if (!(IntuitionBase = OpenLibrary("intuition.library",37L)))
        Cleanup(0, NULL);

}


void Cleanup(return_code, return_text)
int return_code;
STRPTR return_text;
{
    if (return_code)
        printf("%d: %s\n", return_code, return_text);

    if (IntuitionBase)
    {
        CloseLibrary(IntuitionBase);
        IntuitionBase = NULL;
    }

    exit(NULL);
}

Kompilera programmet ovan på följande sätt:

sc Window.c LINK


Vad som är nytt är att vi har lagt till en struktur med de olika
tags som vi vill ha. Detta utgör en lista som vi skickar med till
funktionen OpenWindowTagList(). I övrigt fungerar
OpenWindowTagList() på samma sätt som OpenWindowTags().

struct TagItem WindowTags[] =
{
   WA_IDCMP, IDCMP_CLOSEWINDOW,
   WA_Flags, WFLG_CLOSEGADGET,
   TAG_DONE

};

Vi har nu valt att använda Tag'en WA_Flags istället för
WA_CloseGadget. Detta medför att vi kan koppla på fler
IDCMP-flaggor. Detta görs genom att 'or:a' ihop dem med ett
|-tecken. Vi skall nu lägga till ett par nya tags för att utforma
fönstret.

Ändra i programmet så att strukturen får följande utseende.

struct TagItem WindowTags[] =
{
    WA_Left,     0,
    WA_Top,      40,
    WA_Width,    640,
    WA_Height,   110,
    WA_IDCMP,    IDCMP_CLOSEWINDOW,
    WA_Flags,    WFLG_CLOSEGADGET | WFLG_DRAGBAR,
    TAG_DONE

};

Vi talar med dessa tags om att vi vill öppna fönstret i vänstra
kanten 40 positioner ned. Vi sätter bredden till 640 och höjden
till 110 pixels. Den nya flaggan WFLG_DRAGBAR talar om att man kan
flytta runt fönstret genom att dra i fönstrets titelrad (dragbar).
(Testa att dra utan WFLG_DRAGBAR).

Kompilera och testa.


Vi fortsätter att göra följande ändringar:

struct TagItem WindowTags[] =
{
    WA_Left,     0,
    WA_Top,      40,
    WA_Width,    640,
    WA_Height,   110,
    WA_IDCMP,    IDCMP_CLOSEWINDOW,
    WA_Flags,    WFLG_SMART_REFRESH | WFLG_CLOSEGADGET |
                 WFLG_DRAGBAR | WFLG_SIZEGADGET,
    WA_Title,    (ULONG)"Testfönster",
    TAG_DONE

};

WFLG_SMART_REFRESH               Låter systemet ta hand om
                                 uppdatering (refresh) av fönstret

WFLG_SIZEGADGET                  Placerar ut en SizeGadget på
                                 fönstret

WA_Title, (ULONG)"Testfönster"   Ger fönstret en titel.

Fönstret har nu fått en titeltext och sizegadget (nere i högra
hörnet). Men inget händer då vi försöker att ändra storleken på
fönstret. Detta beror på att max och min storleken är den samma som
den nuvarande fönsterstorleken. Vi kan därför lägga in följande två
rader för att se om det påverkar.

    WA_MinWidth, 50,
    WA_MinHeight,50,

Vi lägger också till flaggan WFLG_DEPTHGADGET för att få fram
Depthgadgeten, vilket gör det möjligt att "bläddra" fram/bak
fönstret. Hela strukturen ser ut som följer.

struct TagItem WindowTags[] =
{
    WA_Left,     0,
    WA_Top,      40,
    WA_Width,    640,
    WA_Height,   110,
    WA_MinWidth, 50,
    WA_MinHeight,50,
    WA_IDCMP,    IDCMP_CLOSEWINDOW,
    WA_Flags,    WFLG_SMART_REFRESH | WFLG_CLOSEGADGET |
                 WFLG_DRAGBAR | WFLG_SIZEGADGET | WFLG_DEPTHGADGET,
    WA_Title,    (ULONG)"Testfönster",
    TAG_DONE

};

Kompilera och provkör. Notera att Zoomgadgeten också kommer med
till vänster om DepthGadgeten. Fönstret byter storlek mellan
nuvarande storlek och minstorleken då man trycker på Zoomgadgeten.


Vi öppnar en skärm som vi vill att fönstret skall öppnas på.

Precis som vid öppning av fönster finns det ett enklare sätt att
öppna skärmar än det tidigare OpenScreen() som man då var tvungen
att fylla i en NewScreen struktur innan man öppnade.

Här kommer exemplet:

/*************************** Window.c ******************/
#include <stdio.h>
#include <stdlib.h>
#include <exec/exec.h>
#include <exec/libraries.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>

extern struct ExecBase  *SysBase;
extern struct Library   *DOSBase;
struct Library          *IntuitionBase;

void OpenLibs(void);
void Cleanup(int, STRPTR);

struct Window           *mywindow = NULL;
struct Screen           *myscreen = NULL;

struct TagItem WindowTags[] =
{
    WA_Left,     0,
    WA_Top,      40,
    WA_Width,    640,
    WA_Height,   110,
    WA_MinWidth, 50,
    WA_MinHeight,50,
    WA_IDCMP,    IDCMP_CLOSEWINDOW,
    WA_Flags,    WFLG_SMART_REFRESH | WFLG_CLOSEGADGET |
                 WFLG_DRAGBAR | WFLG_SIZEGADGET | WFLG_DEPTHGADGET,
    WA_Title,    (ULONG)"Testfönster",
    WA_CustomScreen, NULL,
    TAG_DONE

};

/****************************************************************/

void main(void)

{
struct IntuiMessage *message;     /* Meddelande från intuition   */
ULONG class = 0;                  /* Typ av IDCMP                */
struct Gadget *Gad;               /* Pekare till vilken gadget   */
UWORD code = 0;                   /* Specialvärde typ menynr osv */
BOOL terminated = FALSE;


    OpenLibs();

    myscreen = OpenScreenTags(NULL, SA_Depth, 2,
       SA_Type, CUSTOMSCREEN,
       SA_Title, (ULONG)"Min Skärm",
       SA_DisplayID, DEFAULT_MONITOR_ID|HIRES_KEY, TAG_DONE);

    if (!myscreen)
        Cleanup(10, "Kunde inte öppna skärmen");

    WindowTags[9].ti_Data = (ULONG)myscreen;

    mywindow = OpenWindowTagList(NULL, WindowTags);

    if (!mywindow)
        Cleanup(10, "Kunde inte öppna fönstret");

    while(!terminated)
    {
        WaitPort(mywindow->UserPort);      /* Vänta på meddelande */

        while((!terminated) && (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)))
        {
            class = message->Class;
            code = message->Code;

            if ((class == IDCMP_GADGETUP) || (class==IDCMP_GADGETDOWN) || (class==IDCMP_MOUSEMOVE))
                Gad = (struct Gadget *) message->IAddress;

            ReplyMsg((struct Message *)message);

            switch(class)
            {
                case CLOSEWINDOW:
                    terminated = TRUE;
                    break;
            }
        }
    }

    Cleanup(0, NULL);
}


void OpenLibs(void)
{

    if (!(IntuitionBase = OpenLibrary("intuition.library",37L)))
        Cleanup(0, NULL);

}


void Cleanup(return_code, return_text)
int return_code;
STRPTR return_text;
{
    if (return_code)
        printf("%d: %s\n", return_code, return_text);

    if (mywindow)
    {
        CloseWindow(mywindow);
        mywindow = NULL;
    }

    if (myscreen)
    {
        CloseScreen(myscreen);
        myscreen = NULL;
    }

    if (IntuitionBase)
    {
        CloseLibrary(IntuitionBase);
        IntuitionBase = NULL;
    }

    exit(NULL);
}

Kompilera programmet ovan på följande sätt:

sc Window.c LINK

Programmet öppnar en skärm och ett fönster på skärmen. Anledningen
till att fönstret öppnades just på den skärmen, är att vi kopplade
ihop fönstret och skärmen med:

	WA_CustomScreen, NULL

och

    WindowTags[9].ti_Data = (ULONG)myscreen;

WA_CustomScreen är den tag som talar om vilken skärm som fönstret
skall öppnas på. Genom att ange adressen till skärmen vet intuition
vilken skärm fönstret skall öppnas på.

WindowTags[9].ti_Data är den tionde raden i strukturen WinowTags,
den rad som innehåller WA_CustomScreen.

Jag flyttar stängningsfunktionen av fönster från main() till
Cleanup().


Uppgift till nästa gång! Ändra programmet så att de öppnar minst
ett fönster till på skärmen. Alla fönster skall ha en closegadget.
Man skall kunna avsluta programmet genom att kicka på closegadgeten
i något av fönstren. (Programmet skall alltså läsa meddelanden ur
alla fönster och känna av när Closegadget tryckts och då avsluta
programmet oavsett vilket fönster det är).
Programmet skall stänga alla fönster och skärmen samt avslutas
snyggt och säkert. Full felkontroll.

@BEGIN_FILE_ID.DIZVery good C Guide in swedish.
@END_FILE_ID.DIZ
