Per dubbi, consigli o richieste, potete mandare un'e-mail ad Andrea Carolfi.
Ringraziamo Amiga Transactor Mailing List per questo tangibile contributo!
Dopo aver visto le strutture principali dell'AmigaDOS e di Exec e le
relative procedure e funzioni messe a disposizione per gestirle, oggi
cominceremo a trattare un'altra parte dell'AmigaOS molto importante:
Intuition.
bordi ed immagini li trascuriamo un momento. Intuition / \ schermo schermo / \ \ finestra finestra finestra / \ \ menù bottoni bottoni Come si può vedere, alla base di tutto vi è Intuition, sopra
di essa vi possono stare tutte quelle librerie che servono per facilitare al
programmatore la creazione di una interfaccia grafica, quali gadtools.library,
mui.library, e compagnia. |------------- 16 --------------| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| | submenù | opzione | menù | |--- 5 ---|---- 6 ----|--- 5 ---| Per poter convertire un "codice di menù" nella relativa rappresentazione menù -> opzione -> sotto opzione e viceversa sono definite delle macro apposite nel file intuition/intuition.h. Queste sono: FULLMENUNUM(menu,item,sub), MENUNUM(code), ITEMNUM(code), SUBNUM(code).
Un'altra "limitazione" sono il numero di bottoni che si possono aggiungere ad
una finestra: "solo" 65536. Questo perchè viene utilizzata una
UWORD in alcune chiamate di sistema e nel campo GadgetID della
struttura Gadget che vedremo in seguito. Cominciamo dunque ad analizzare l'albero a partire dalla radice, ovvero dalla struttura Intuition: /* ======================================================================== */ /* === IntuitionBase ====================================================== */ /* ======================================================================== */ /* * Be sure to protect yourself against someone modifying these data as * you look at them. This is done by calling: * * lock = LockIBase(0), which returns a ULONG. When done call * UnlockIBase(lock) where lock is what LockIBase() returned. */ /* This structure is strictly READ ONLY */ struct IntuitionBase { struct Library LibNode; struct View ViewLord; struct Window *ActiveWindow; struct Screen *ActiveScreen; /* the FirstScreen variable points to the frontmost Screen. Screens are * then maintained in a front to back order using Screen.NextScreen */ struct Screen *FirstScreen; /* for linked list of all screens */ ULONG Flags; /* values are all system private */ WORD MouseY, MouseX; /* note "backwards" order of these */ ULONG Seconds; /* timestamp of most current input event */ ULONG Micros; /* timestamp of most current input event */ /* I told you this was private. * The data beyond this point has changed, is changing, and * will continue to change. */ }; può essere utile dover accedere a queste informazioni magari per realizzare qualche patch o altro. La successiva struttura in ordine di importanza è quella che descrive uno schermo: /* ======================================================================== */ /* === Screen ============================================================= */ /* ======================================================================== */ /* VERY IMPORTANT NOTE ABOUT Screen->BitMap. In the future, bitmaps * will need to grow. The embedded instance of a bitmap in the screen * will no longer be large enough to hold the whole description of * the bitmap. * * YOU ARE STRONGLY URGED to use Screen->RastPort.BitMap in place of * &Screen->BitMap whenever and whereever possible. */ struct Screen { struct Screen *NextScreen; /* linked list of screens */ struct Window *FirstWindow; /* linked list Screen's Windows */ WORD LeftEdge, TopEdge; /* parameters of the screen */ WORD Width, Height; /* parameters of the screen */ WORD MouseY, MouseX; /* position relative to upper-left */ UWORD Flags; /* see definitions below */ UBYTE *Title; /* null-terminated Title text */ UBYTE *DefaultTitle; /* for Windows without ScreenTitle */ /* Bar sizes for this Screen and all Window's in this Screen */ /* Note that BarHeight is one less than the actual menu bar * height. We're going to keep this in V36 for compatibility, * although V36 artwork might use that extra pixel * * Also, the title bar height of a window is calculated from the * screen's WBorTop field, plus the font height, plus one. */ BYTE BarHeight, BarVBorder, BarHBorder, MenuVBorder, MenuHBorder; BYTE WBorTop, WBorLeft, WBorRight, WBorBottom; struct TextAttr *Font; /* this screen's default font */ /* the display data structures for this Screen */ struct ViewPort ViewPort; /* describing the Screen's display */ struct RastPort RastPort; /* describing Screen rendering */ struct BitMap BitMap; /* SEE WARNING ABOVE! */ struct Layer_Info LayerInfo; /* each screen gets a LayerInfo */ /* Only system gadgets may be attached to a screen. * You get the standard system Screen Gadgets automatically */ struct Gadget *FirstGadget; UBYTE DetailPen, BlockPen; /* for bar/border/gadget rendering */ /* the following variable(s) are maintained by Intuition to support the * DisplayBeep() color flashing technique */ UWORD SaveColor0; /* This layer is for the Screen and Menu bars */ struct Layer *BarLayer; UBYTE *ExtData; UBYTE *UserData; /* general-purpose pointer to User data extension */ /**** Data below this point are SYSTEM PRIVATE ****/ };
Prima di andare avanti occorre dare una premessa: dato che il sistema
operativo di Amiga è molto complesso e molte parti di esso sono
correlate ed intrecciate tra loro, non si può capire a fondo il
contenuto di questa struttura senza parlare delle librerie graphics.library
e layer.library. Vediamo quindi la procedura che ci mette a disposizione Intuition per
aprire degli schermi: OpenScreenTagList. In realtà questa
procedura poggia sulla sua sorella OpenScreen, ma visto che aprire
schermi con la OpenScreenTagList è di gran lunga molto
più semplice e flessibile, trascurerò volutamente questa
procedura. typedef ULONG Tag; struct TagItem { Tag ti_Tag; /* identifies the type of data */ ULONG ti_Data; /* type-specific data */ }; Ed ora la sintassi della procedura: Screen = OpenScreenTagList(NewScreen,TagItems); D0 A0 A1 struct Screen *OpenScreenTagList(struct NewScreen *,struct TagItem *); Screen = OpenScreenTags(NewScreen, Tag1, ... ); struct Screen *OpenScreenTags(struct NewScreen *,ULONG, ... ); Perchè due versioni della stessa procedura? Perchè come molte altre procedure del sistema operativo, a partire dalla versione 2.0 accettano parametri sottoforma di TagItem in due modi diversi, il primo consente di passare i parametri sui registri (come mostrato dalle lettere poste sotto i parametri) il secondo sullo stack. Per fare un esempio concreto: primo metodo) struct TagItem tags[] = {SA_Width,320,SA_Height,200,TAG_DONE}; struct Screen *scr; [...] if((scr = OpenScreenTagList(NULL,tags))) [...] secondo metodo) struct Screen * scr; [...] if((scr = OpenScreenTags(NULL, SA_Width, 320, SA_Height, 200, TAG_DONE))) [...]
Entrambi i metodi hanno i loro pregi e difetti. Il primo genererà un
codice più compatto quando troverà la chiamata alla
OpenScreenTagList ma obbliga il programmatore a dichiarare una
variabile in più. Il secondo genererà del codice più
lungo (perchè deve mettere diversi parametri sullo stack, invece di
due puntatori nei registri) ma ha il vantaggio di essere più semplice
da gestire. Scrivendo la chiamata come mostrato, per esempio è
possibile abilitare/disabilitare dei tag semplicemente anteponendo un //
(commento C++) o racchiuderlo tra /* */, non solo: è possibile
utilizzare l'operatore ternario per modificare un flag al volo a seconda di
determinate condizioni tipo: struct TagItem tags[] = {SA_ErrorCode,NULL,TAG_DONE}; LONG errcode; [...] tags[0].ti_Data = (ULONG)&errcode;che secondo me è un pò scomodo ma nessuno vieta. :-) Vediamo dunque i tags principali (sono definiti nel file intuition/screens.h e descritti uno per uno nell'autodoc di intuition ovviamente sotto la descrizione della procedura OpenScreen (per i motivi citati prima)): SA_Left, SA_Top,SA_Width,SA_Height SA_Depth SA_Title SA_ErrorCode SA_Font SA_SysFont SA_Type SA_BitMap SA_PubName SA_PubSig SA_PubTask SA_DisplayID Tag booleani:SA_ShowTitle SA_Behind SA_Quiet SA_AutoScroll SA_Draggable SA_Exclusive SA_LikeWorkbench Non curante della lunghezza di questa lezione :-) proseguiamo con la OpenWindowTagList, anche perchè se mi fermassi quì avreste uno schermo aperto senza niente. :-) La sintassi della OpenWindowTagList è la stessa della OpenScreenTagList salvo il tipo della struttura ritornata e della
struttura NewWindow opzionale (al posto della NewScreen). /* ======================================================================== */ /* === Window ============================================================= */ /* ======================================================================== */ struct Window { struct Window *NextWindow; /* for the linked list in a screen */ WORD LeftEdge, TopEdge; /* screen dimensions of window */ WORD Width, Height; /* screen dimensions of window */ WORD MouseY, MouseX; /* relative to upper-left of window */ WORD MinWidth, MinHeight; /* minimum sizes */ UWORD MaxWidth, MaxHeight; /* maximum sizes */ ULONG Flags; /* see below for defines */ struct Menu *MenuStrip; /* the strip of Menu headers */ UBYTE *Title; /* the title text for this window */ struct Requester *FirstRequest; /* all active Requesters */ struct Requester *DMRequest; /* double-click Requester */ WORD ReqCount; /* count of reqs blocking Window */ struct Screen *WScreen; /* this Window's Screen */ struct RastPort *RPort; /* this Window's very own RastPort */ /* the border variables describe the window border. If you specify * WFLG_GIMMEZEROZERO when you open the window, then the upper-left of * the ClipRect for this window will be upper-left of the BitMap (with * correct offsets when in SuperBitMap mode; you MUST select * WFLG_GIMMEZEROZERO when using SuperBitMap). If you don't specify * ZeroZero, then you save memory (no allocation of RastPort, Layer, * ClipRect and associated Bitmaps), but you also must offset all your * writes by BorderTop, BorderLeft and do your own mini-clipping to * prevent writing over the system gadgets */ BYTE BorderLeft, BorderTop, BorderRight, BorderBottom; struct RastPort *BorderRPort; /* You supply a linked-list of Gadgets for your Window. * This list DOES NOT include system gadgets. You get the standard * window system gadgets by setting flag-bits in the variable Flags (see * the bit definitions below) */ struct Gadget *FirstGadget; /* these are for opening/closing the windows */ struct Window *Parent, *Descendant; /* sprite data information for your own Pointer * set these AFTER you Open the Window by calling SetPointer() */ 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 */ /* the IDCMP Flags and User's and Intuition's Message Ports */ ULONG IDCMPFlags; /* User-selected flags */ struct MsgPort *UserPort, *WindowPort; struct IntuiMessage *MessageKey; UBYTE DetailPen, BlockPen; /* for bar/border/gadget rendering */ /* 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 *ScreenTitle; /* if non-null, Screen title when Window is active */ /* These variables have the mouse coordinates relative to the * inner-Window of WFLG_GIMMEZEROZERO Windows. This is compared with the * MouseX and MouseY variables, which contain the mouse coordinates * relative to the upper-left corner of the Window, WFLG_GIMMEZEROZERO * notwithstanding */ WORD GZZMouseX; WORD GZZMouseY; /* these variables contain the width and height of the inner-Window of * WFLG_GIMMEZEROZERO Windows */ WORD GZZWidth; WORD GZZHeight; UBYTE *ExtData; BYTE *UserData; /* general-purpose pointer to User data extension */ /** 11/18/85: this pointer keeps a duplicate of what * Window.RPort->Layer is _supposed_ to be pointing at */ struct Layer *WLayer; /* NEW 1.2: need to keep track of the font that * OpenWindow opened, in case user SetFont's into RastPort */ struct TextFont *IFont; /* (V36) another flag word (the Flags field is used up). * At present, all flag values are system private. * Until further notice, you may not change nor use this field. */ ULONG MoreFlags; /**** Data beyond this point are Intuition Private. DO NOT USE ****/ }; ed i tag più importanti per aprire una finestra: WA_Left, WA_Top, WA_Width, WA_Height Posizione e dimensione della finestra. WA_IDCMP
Vi ricordate la lezione sui messaggi? Ecco dunque dove vanno a finire.
Gli IDCMP (l'acronimo sta per Intuition Direct Communication Message
Port), sono i vari messaggi che Intuition può comunicare al nostro
task a seconda dei determinati eventi che l'utente crea.
Possono essere specificati in congiunzione utilizzando l'or bit a bit | del C. WA_Flags
WA_Title WA_ScreenTitle WA_MinWidth,WA_MinHeight,WA_MaxWidth,WA_MaxHeight WA_PubScreenName WA_PubScreen Per concludere questa lunghissima lezione, un piccolissimo stralcio di codice, che illustri il tutto: struct Screen *scr; struct Window *win; struct IntuiMessage *msg; BOOL finito = FALSE; if((scr = OpenScreenTags(NULL,SA_LikeWorkbench,TRUE,TAG_DONE))) { if((win = OpenWindowTags(NULL, WA_IDCMP, IDCMP_CLOSEWINDOW, WA_Flags, WFLG_CLOSEGADGET, WA_PubScreen, scr, TAG_DONE))) { while(!finito) { WaitPort(win -> UserPort); while((msg = (struct IntuiMessage *)GetMsg(win -> UserPort))) { switch(msg -> Class) { case IDCMP_CLOSEWINDOW: finito = TRUE; break; } ReplyMsg((struct Message *)msg); } } CloseWindow(win); } CloseScreen(scr); } Listato di questa lezione.
|
![]() |
![]() |