
			ETT LITE STRRE EXEMPEL


Som avslutning p det hr ska vi frska dissekera ett riktigt Amigaprogram 
och noga g igenom hur det r tnkt att fungera.


/* hello.c

 * 
 * Programmet ppnar sin egen screen (320x200) och skapar ett window som
 * kan flyttas, storleksndras, flyttas framfr eller bakom och stngas.
 * 
 */

/***************************************************************************
 *
 *       "Hello World"
 *
 **************************************************************************/

#include <exec/types.h>

/* En frprocessorinstruktion som hmtar in en headerfil och tar med dess
   innehll i kllkoden. Denna innehller alla typdefinitioner som Amiga
   anvnder sig av. De finns listade i brjan av den hr artikeln */

#include <intuition/intuition.h>

/* Nsta headerfil. Den innehller frst instruktioner fr att hmta ytter-
   ligare headerfiler, sedan kommer strukturmallar som behvs till Intuition
   och definitioner av alla flaggor och annat smtt och gott. Denna headerfil
   r en av de lngsta i hela systemet s den kar ut omfnget p programmet
   hgst avsevrt. Men den mste finnas med om man ska kunna utnyttja Intui-
   tion och dess funktioner. */

#include <intuition/intuitionbase.h>

/* Sista headerfilen. Den innehller ytterligare strukturdefinitioner och en
   massa varningar som uppmanar dig att inte rra om bland dessa parametrar
   ens om du vet vad du gr. Hr finns ocks en massa definitioner som rr de
   delar av Intuition som r avsedda bara fr Amigas egna systemutvecklare.
   De r frsedda med nnu fler varningar och en garanti fr att ditt program
   kommer att krascha under nsta version av systemet om du frsker anvnda
   ngot av detta fr eget bruk. Men den r nyttig att titta p fr den som 
   r intresserad av systemets djupaste hemligheter. */
 
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

/* Deklaration av pekare till strukturerna IntuitionBase och GfxBase. Dessa 
   mste vara med och ha exakt dessa namn om det ska g att anvnda Intuition
   och grafikfunktioner */

#define INTUITION_REV 28	/* Funkar inte med ldre versioner n s */
#define GRAPHICS_REV 28

/* Frprocessorinstruktion som medfr att det bara gr att ppna intuition-
   biblioteket och grafikbiblioteket om de r av version 28 eller senare.
   Det fungerar s att dessa vrden stts in som argument vid anropet till
   de funktioner som ppnar biblioteken. Se ovan om frdelarna med symbo-
   liska konstanter, det r just sdana det r frga om hr.
   Programmet skulle nda inte fungera med tidigare versioner eftersom det
   innehller funktioner som mste ha senare versioner av biblioteken. 

struct TextAttr MyFont =
   {
   "topaz.font",     /* Fontnamn *
   TOPAZ_SIXTY,      /* Fontstorlek */
   FS_NORMAL,        /* Extra attribut, inget srskilt */
   FPF_ROMFONT       /* Fonten finns i ROM */
   };

/* Det hr var deklarationen och initieringen av den struktur som innehller
   upplysningar om vilken textfont som ska anvndas nr vi senare ppnar vr
   screen. Vi dper strukturvariabeln, fr en sn r det, till MyFont. Om man
   vill anvnda andra fonter till andra screens s r det bara att deklarera 
   fler sdana hr strukturvariabler med andra namn. */

/* Nu deklarerar vi en frdiginitierad NewScreenstruktur. Det r ofta 
 * mindre arbetsamt och tar mindre plats i kllkoden att initiera
 * strukturer p detta stt.
 */

struct NewScreen NewScreen =
   {
   0,                /* Vnsterkant altid noll */
   0,                /* verkanten */
   320,              /* Bredd, lgupplsning */
   200,	             /* Hjd (ingen interlace) */
   4,	             /* Djup (16 frger, 4 bitplan allts) */
   0, 1,             /* DetailPen och BlockPen  */
   NULL,             /* viewmode lgupplsning */
   CUSTOMSCREEN,     /* Screentyp */
   &MyFont,          /* Anvnd denna font */
   "My Own Screen",  /* Titel, kompileras som pekare */
   NULL,             /* inga Gadgets */
   NULL              /* ingen Custom BitMap */
   };

/* Fr att riktigt frst vad som hnder hr behver man ha tillgng till den
   strukturmall som finns i headerfilen intuition.h. De frsta sju vrdena i
   strukturen r av typerna SHORT och UBYTE och innehller talvrden. Men 
   fltet viewmode och screentyp fordrar en frklaring. De har typen USHORT
   men det som str i dem r frvisso inga positiva heltal. I headerfilerna 
   finns definitioner av symboliska flaggvrden, s frprocessorn kommer att
   stta in heltal hr i stllet. Nsta flt r en pekare till en TextAttr-
   struktur och den bestmmer vilken font som ska anvndas. Om du stter den
   till NULL s anvnds den font som finns i Preferences. Sedan fljer namnet
   p vr screen, det skall vara en pekare och kompilatorn lgger upp det som
   en strngkonstant och placerar en pekare till den i strukturen. Vi av-
   slutar ett par pekare till strukturer, men eftersom vi inte ska ha ngon
   gadget hr och inte ngon egen bitmap fr grafiken utan anvnder den som
   systemet lgger upp s kan vi stta dessa till NULL. */

main()   /* Hr brjar sjlva programmet med main() som vanligt */

{
   struct Screen *Screen;
   struct NewWindow NewWindow;
   struct Window *Window;

/* Hr deklarerar vi tv pekare och en komplett struktur. De kommer att bli
   av klassen auto och allts lagras p stacken. Eftersom de inte r statiska
   s existerar de bara s lnge funktionen main arbetar. Detta inkluderar 
   frsts ocks funktioner som anropas av main(). Men s snart vi har hamnat
   utanfr main, s frsvinner dessa variabler. */

   /* ppna nu Intuition library. Resultatet av detta anrop anvnds fr
    * att ditt program ska kunna hitta biblioteksfunktionerna i ROM.
    * Om resultatet r noll, s har ngot gtt fel och du kan inte
    * anvnda Intuition utan mste sluta genast.
    */

   IntuitionBase = (struct IntuitionBase *)
      OpenLibrary("intuition.library",INTUITION_REV);
   if(IntuitionBase == NULL)
      exit(FALSE);

/* Det hr sg trassligt ut. Lt oss bena ut det frn brjan. Det r en
   vanlig tilldelningssats dr vi vill att variabeln IntuitionBase ska f ett
   vrde. Variabeln r en av dem som vi nyss deklarerade, och den r en
   pekare till en IntuitionBasestruktur. Men eftersom funktionen OpenLibrary
   returnerar ett vrde av typen int, s mste vi anvnda oss av typkonver-
   tering fr att inte kompilatorn ska protestera. Funktionens argument r 
   frst namnet p det bibliotek vi vill ppna, och sedan numret p den 
   tidigaste godtagbara versionen. Den definierade vi som symbol redan i br-
   jan av programmet till 28. Nvl, sedan funktionen OpenLibrary har anro-
   pats kommer den tillbaka med ett vrde som vi tolkar som den nskade peka-
   ren. Men om det nu inte lyckades d? Utan denna pekare kan vi dra nt gam-
   malt ver oss och lgga av. Det klarar nsta rad av. Vi kollar helt enkelt
   om pekaren r noll, i s fall vet vi att funktionen misslyckades. Obser-
   vera operatorn == som r relationsoperatorn likhet medan = betyder till-
   delning. Om pekaren r noll s medfr ifsatsen att funktionen exit() an-
   ropas med argumentet FALSE och programmet avslutas. KONTROLLERA ALLTID
   EN PEKARE SOM DU SKAFFAT DIG GENOM ETT FUNKTIONSANROP. Se frresten till
   s att du inte sjlv glmmer att initiera dina pekare innan du anvnder dem.
   Att frska anvnda en pekare med vrdet NULL r ett tmligen skert stt 
   att bomba bde ditt program och systemet p en gng. Att anvnda pekare 
   med slaskvrden i kan ge upphov till svrhittade buggar som ger sig till
   knna lngt senare i programkrningen. Pekare r ett mycket kraftfullt
   instrument och det gr att de mste behandlas med tillbrlig respekt. */

   GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",GRAPHICS_REV);
   if(GfxBase == NULL)
      exit(FALSE);

/* Hr gjorde vi precis samma sak med grafikbiblioteket */

   if((Screen = (struct Screen *) OpenScreen(&NewScreen)) == NULL)
      exit(FALSE);

/* S var det d dags att ppna en screen. Funktionsanropet r hr gjort med
   lite annan teknik. Det ingr i ifsatsen och medfr allts ett kompaktare 
   skrivstt, men funktionen r exakt densamma. Som argument till funktionen 
   OpenScreen skickar vi adressen till vr NewScreenstruktur. I retur fr vi
   en pekare till en Screenstruktur som vi behver fr att ppna fnstret. */

   /* Initiera NewWindowstrukturen fr anropet till OpenWindow() */

   NewWindow.LeftEdge = 20;
   NewWindow.TopEdge = 20;
   NewWindow.Width = 300;
   NewWindow.Height = 100;
   NewWindow.DetailPen = 0;
   NewWindow.BlockPen = 1;
   NewWindow.Title = "A Simple Window";
   NewWindow.Flags = WINDOWCLOSE | SMART_REFRESH | ACTIVATE
      | WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH;
   NewWindow.IDCMPFlags = CLOSEWINDOW;	/* Rapportera CLOSEWINDOW */
   NewWindow.Type = CUSTOMSCREEN;
   NewWindow.FirstGadget = NULL;
   NewWindow.CheckMark = NULL;
   NewWindow.Screen = Screen;
   NewWindow.BitMap = NULL;
   NewWindow.MinWidth = 100;
   NewWindow.MinHeight = 25;
   NewWindow.MaxWidth = 32767;
   NewWindow.MaxHeight = 32767;

/* Det hr var ett annat stt att initiera en struktur. Eftersom vi deklare-
   rade strukturen som automatisk men inte statisk kan vi inte initiera den
   vid deklarationen utan mste ta fram varje element fr sig och initiera
   dem. Vi gr inte in i detalj p strukturens delar, den pminner mycket om
   motsvarande i NewScreenstrukturen. Lt oss bara se p ett par saker. I 
   fltet IDCMPFlags str ett vrde som innebr att IDCMP ( Intuition Direct
   Message Communication Port, tur att det finns frkortningar ) rapporterar
   s snart anvndaren klickar med musen i stngningsrutan. Detta meddelande 
   kan vi anvnda fr att veta nr det r dags att anropa den funktion som 
   stnger fnstret t oss. Detta r enda sttet att komma t musklickningar
   fr eget bruk. I fltet Screen stter vi vr gamle bekant variabeln Screen
   som vi tilldelade ett vrde med hjlp av OpenScreen. Flten MaxWidth och 
   MaxHeight tilldelas rtt hftiga vrden med tanke p att skrmen max kan
   ta 320 pixels p bredden, men frfattaren tar inga risker att inte kunna
   f full storlek p fnstret. Ett vrde p 320 p bredden och 200 p hjden
   hade rckt. Lgg mrke till att programmet r gjort innan PALversionen var
   ens ptnkt, s screenen ppnas med hjden 200. Du kan skriva 256 dr i
   stllet s utnyttjar du hela skrmen p hjden. */ 

   /* ppna fnstret nu. Liksom vid anropet till OpenLibrary(), s fr du
    * tillbaka en pekare till din nya struktur om det gr bra. Om ngot
    * gr fel fr du noll tillbaka istllet.
    */

   if(( Window = (struct Window *) OpenWindow(&NewWindow)) == NULL)
      exit(FALSE);


/*Funktionerna Move() och Text() hr hemma i grafikbiblioteket graphics.li-
  brary, och det var fr att kunna anvnda dem som vi mste ppna detta bib-
  liotek nyss. Move() har tre argument. Det frsta r adressen till den Rast-
  portstruktur som styr grafiken i det aktuella fnstret. Den finns som en 
  understruktur i Windowstrukturen. Eftersom vi har en pekare till den Win-
  dowstruktur som vi just fick nr vi ppnade fnstret, s r det bara att 
  peka p dess RastPort med hjlp av den indirekta elementoperatorn ->. Nsta
  tv argument r tv koordinater, x och y, i det raster som RastPort repre-
  senterar. Dessa anger hur mnga pixels frn vre vnstra hrnet som nsta
  grafikoperation ska brja. Observera att det gller frn rastrets hrn som
  inte ndvndigtvis r detsamma som skrmens hrn, det bestms av andra 
  parametrar i RastPorten. Move() utfr ingen ritning utan lyfter helt enkelt
  p pennan och placerar den i ett nytt utgngslge. Funktionen Text() skri-
  ver text med start i den aktuella pennpositionen. Frsta argumentet r ock-
  s hr adressen till en RastPort, sedan fljer en pekare till en textstrng
  som ska skrivas ut. Att skriva ut strngen inom citationstecken r ju som 
  vi vet detsamma som att definiera en pekarkonstant som pekar p frsta ele-
  mentet i strngen. Det tredje argumentet r helt enkelt lngden p strngen
  och d behver man inte ta med det nolltecken som avslutar en strng i C.
  Exakt hur texten ska skrivas, font, frg och annat, bestms av parametrar i
  RastPortstrukturen, och om vi inte anger ngot s sker det med den font 
  som anges i preferences.*/

   Move(Window->RPort,20,20);
   Text(Window->RPort,"Hello World",11);

/* Nu fljer huvudloopen i programmet. Den ser ut som en ondlig slinga. I 
   ett system med multitasking r det ju absolut frbjudet att gna sig t 
   att vnta med hjlp av slingor som bara kr runt runt. Det kallas fr busy
   waiting, allts att vara fullt sysselsatt med ingenting och p s stt 
   hindra andra program att komma till. Men hr r det inte s illa tack vare
   funktionen Wait(). Den hr hemma i Exec och orsakar att den task som den 
   str i kommer att lggas i vilolge tills den vcks av ett meddelande som
   kommer till dess MessagePort. Dess argument r en s kallad mask. En sig-
   nal bestr av en viss bit i ett lngord. Funktionen Wait() undersker om 
   den har ftt rtt signal genom att gra logisk OR mellan sin mask och den
   inkommna signalen. Det gller allts att skaffa sig den rtta masken. Om 
   man sjlv allokerar sin signalbit s r det ltt, fr d vet man ju vilken
   bit man har ftt, men i det hr fallet har systemet allokerat signalbiten. 
   D r vi s listiga att vi hittar masken genom att vnsterskifta en etta
   lika mnga steg som numret p signalbiten, och det numret hittar vi i det
   MessagePortstruktur som pekas p av UserPort, som i sin tur ingr i Win-
   dowstrukturen. Vi bara anvnder den indirekta elementoperatorn tv gnger
   s r vi framme vid signalbiten. Fr att kunna klura ut detta mste man 
   ha tillgng till includefilerna och leta i de aktuella strukturerna. Ett 
   annat stt r frsts att planka ngon annans program. Nvl, vi matar 
   funktionen Wait() med en mask som kommer att knna igen signalen mp_SigBit
   och vr task kommer att vakna om den kommer. Eftersom vi i strukturen New-
   Window bara angav en enda IDCMPFlag, nmligen CLOSEWINDOW, s r det den
   enda signal som kommer att skickas till UserPort, och drmed r den enda
   hndelse som kan vcka programmet att anvndaren klickar med musen i den
   lilla stngningsrutan uppe till vnster. Nr detta sker fortstter vi med 
   raden efter Wait().

   Hr anropar vi funktionen CloseWindow() med argumentet Window, fr det r
   ju adressen till det fnster som vi ppnade. Sedan stnger vi skrmen med
   CloseScreen() matad med en adress till vr screen. Slutligen anropar vi 
   exit() med argumentet TRUE. Denna funktion ingr inte i Amigasystemet som
   sdant utan finns i kompilatorns standardbibliotek. Parametern r ett vr-
   de som kommer att returneras till det program som startade oss, i det hr
   fallet var det CLI. Ett stt att anvnda parametern r att lta den ange 
   en felkod. Funktionen exit() r mycket hjlpsam och ser till att stnga 
   alla filer som programmet har ppnat. Fast hur r det med fnster och
   screen? Det r skrast och snyggast att gra det sjlv innan man kallar p
   exit() med hjlp av en liten avslutningsrutin som undersker om det finns
   ngot som inte r stngt, kanske skriver en liten text, och sedan gr till
   exit(). Det r srskilt viktigt att frst g till en sdan rutin om man
   hoppar ur programmet i frtid p grund av ngot fel. Ifsatsen vid ppnan-
   det av Window och Screen borde gra s till exempel.  
   
   for(;;)
     {
     Wait(1 << Window->UserPort->mp_SigBit); /* vnta p signal, den enda 
                                             /* du fr r CLOSEWINDOW */
     CloseWindow(Window);       /* Stng fnstret igen */
     CloseScreen(Screen);       /* Stng din screen ocks */
     exit(TRUE);                /* Exit */
     }
}

