Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "Classic Intuition Screens"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
Line 105: Line 105:
   
 
The NewScreen structure used with OpenScreen() has been extended with a tag list in V36 to form an ExtNewScreen. This is done by setting the NS_EXTENDED bit in the Type field of the NewScreen structure and adding a pointer to an array of tags to the end of the structure. The NS_EXTENDED bit is ignored in older versions of the operating system, so the tags can be transparently added to existing applications and the features will appear when executed in a system running V36 or greater. See the OpenScreen() Autodocs and the include file <intuition/screens.h> for more information on NS_EXTENDED and the ExtNewScreen structure.
 
The NewScreen structure used with OpenScreen() has been extended with a tag list in V36 to form an ExtNewScreen. This is done by setting the NS_EXTENDED bit in the Type field of the NewScreen structure and adding a pointer to an array of tags to the end of the structure. The NS_EXTENDED bit is ignored in older versions of the operating system, so the tags can be transparently added to existing applications and the features will appear when executed in a system running V36 or greater. See the OpenScreen() Autodocs and the include file <intuition/screens.h> for more information on NS_EXTENDED and the ExtNewScreen structure.
  +
  +
== Advanced Screen Programming ==
  +
  +
This section discusses how to create a dual-playfield Intuition screen and other advanced topics.
  +
  +
=== Dual-Playfield Screen Example ===
  +
  +
This example shows how to create a dual-playfield display. Note that this technique is only valid for screen modes which support dual-playfield, do not try to convert other modes.
  +
  +
Setting up dual playfield mode in the OpenScreen() call is not the best method of obtaining a dual playfield viewport for a screen. It is better to open a standard screen, passing to Intuition (or letting Intuition create) only one of the playfield bitmaps (the front one). Next allocate and set up a second bitmap, its bitplanes, and a RasInfo structure installing these into the new screen's viewport. Update the viewport modes to include DUALPF and call MakeScreen() and RethinkDisplay(). This method, shown in the example below, keeps Intuition rendering (gadgets, menus, windows) in a single playfield.
  +
  +
<pre>
  +
/* dualplayfield.c
  +
** Shows how to turn on dual-playfield mode in a screen.
  +
**
  +
** SAS/C 5.10a
  +
** lc -b1 -cfist -v -y dualplayfield
  +
** blink FROM LIB:c.o dualplayfield.o TO dualplayfield LIB LIB:lc.lib LIB:amiga.lib
  +
*/
  +
  +
#define INTUI_V36_NAMES_ONLY
  +
  +
#include &lt;exec/types.h&gt;
  +
#include &lt;exec/memory.h&gt;
  +
#include &lt;intuition/intuition.h&gt;
  +
#include &lt;graphics/displayinfo.h&gt;
  +
  +
#include &lt;clib/exec_protos.h&gt;
  +
#include &lt;clib/intuition_protos.h&gt;
  +
#include &lt;clib/graphics_protos.h&gt;
  +
  +
VOID doDualPF ( struct Window * );
  +
BOOL installDualPF( struct Screen *, struct RastInfo * );
  +
VOID drawSomething( struct RastPort * );
  +
VOID handleIDCMP ( struct Window * );
  +
VOID removeDualPF( struct Screen *s );
  +
  +
struct Library *IntuitionBase;
  +
struct Library *GfxBase;
  +
  +
VOID main(int argc, char **argv)
  +
{
  +
struct Window *win;
  +
struct Screen *scr;
  +
  +
IntuitionBase = OpenLibrary(&quot;intuition.library&quot;,37);
  +
if (IntuitionBase != NULL)
  +
{
  +
GfxBase = OpenLibrary(&quot;graphics.library&quot;, 37);
  +
if (GfxBase != NULL)
  +
{
  +
scr = OpenScreenTags(NULL,
  +
SA_Depth, 2,
  +
SA_DisplayID, HIRES_KEY,
  +
SA_Title, &quot;Dual Playfield Test Screen&quot;,
  +
TAG_END);
  +
if ( scr != NULL )
  +
{
  +
win = OpenWindowTags(NULL,
  +
WA_Title, &quot;Dual Playfield Mode&quot;,
  +
WA_IDCMP, IDCMP_CLOSEWINDOW,
  +
WA_Width, 200,
  +
WA_Height, 100,
  +
WA_DragBar, TRUE,
  +
WA_CloseGadget, TRUE,
  +
WA_CustomScreen, scr,
  +
TAG_END);
  +
if ( win != NULL )
  +
{
  +
doDualPF(win);
  +
  +
CloseWindow(win);
  +
}
  +
CloseScreen(scr);
  +
}
  +
CloseLibrary(GfxBase);
  +
}
  +
CloseLibrary(IntuitionBase);
  +
}
  +
}
  +
  +
  +
/*
  +
** Allocate all of the stuff required to add dual playfield to a screen.
  +
*/
  +
VOID doDualPF(struct Window *win)
  +
{
  +
struct Screen *myscreen;
  +
struct RasInfo *rinfo2;
  +
struct BitMap *bmap2;
  +
struct RastPort *rport2;
  +
  +
myscreen = win-&gt;WScreen; /* Find the window's screen */
  +
  +
/* Allocate the second playfield's rasinfo, bitmap, and bitplane */
  +
rinfo2 = (struct RasInfo *) AllocMem(sizeof(struct RasInfo), MEMF_PUBLIC | MEMF_CLEAR);
  +
if ( rinfo2 != NULL )
  +
{
  +
/* Get a rastport, and set it up for rendering into bmap2 */
  +
rport2 = (struct RastPort *) AllocMem(sizeof(struct RastPort), MEMF_PUBLIC );
  +
if (rport2 != NULL )
  +
{
  +
bmap2 = (struct BitMap *) AllocMem(sizeof(struct BitMap), MEMF_PUBLIC | MEMF_CLEAR);
  +
if (bmap2 != NULL )
  +
{
  +
InitBitMap(bmap2, 1, myscreen-&gt;Width, myscreen-&gt;Height);
  +
  +
/* extra playfield will only use one bitplane here. */
  +
bmap2-&gt;Planes[0] = (PLANEPTR) AllocRaster(myscreen-&gt;Width, myscreen-&gt;Height);
  +
if (bmap2-&gt;Planes[0] != NULL )
  +
{
  +
InitRastPort(rport2);
  +
rport2-&gt;BitMap = rinfo2-&gt;BitMap = bmap2;
  +
  +
SetRast(rport2, 0);
  +
  +
if (installDualPF(myscreen,rinfo2))
  +
{
  +
/* Set foreground color; color 9 is color 1 for
  +
** second playfield of hi-res viewport
  +
*/
  +
SetRGB4(&amp;myscreen-&gt;ViewPort, 9, 0, 0xF, 0);
  +
  +
drawSomething(rport2);
  +
  +
handleIDCMP(win);
  +
  +
removeDualPF(myscreen);
  +
}
  +
FreeRaster(bmap2-&gt;Planes[0], myscreen-&gt;Width, myscreen-&gt;Height);
  +
}
  +
FreeMem(bmap2, sizeof(struct BitMap));
  +
}
  +
FreeMem(rport2, sizeof(struct RastPort));
  +
}
  +
FreeMem(rinfo2, sizeof(struct RasInfo));
  +
}
  +
}
  +
  +
  +
/*
  +
** Manhandle the viewport:
  +
** install second playfield and change modes
  +
*/
  +
BOOL installDualPF(struct Screen *scrn, struct RastInfo *rinfo2)
  +
{
  +
ULONG screen_modeID;
  +
BOOL return_code = FALSE;
  +
  +
screen_modeID = GetVPModeID(&amp;(scrn-&gt;ViewPort));
  +
if( screen_modeID != INVALID_ID )
  +
{
  +
/* you can only play with the bits in the Modes field
  +
** if the upper half of the screen mode ID is zero!!!
  +
*/
  +
if ( (screen_modeID &amp; 0xFFFF0000L) == 0L )
  +
{
  +
return_code = TRUE;
  +
  +
Forbid();
  +
  +
/* Install rinfo for viewport's second playfield */
  +
scrn-&gt;ViewPort.RasInfo-&gt;Next = rinfo2;
  +
scrn-&gt;ViewPort.Modes |= DUALPF;
  +
  +
Permit();
  +
  +
/* Put viewport change into effect */
  +
MakeScreen(scrn);
  +
RethinkDisplay();
  +
}
  +
}
  +
return(return_code);
  +
}
  +
  +
/*
  +
** Draw some lines in a rast port...This is used to get some data into
  +
** the second playfield. The windows on the screen will move underneath
  +
** these graphics without disturbing them.
  +
*/
  +
VOID drawSomething(struct RastPort *rp)
  +
{
  +
int width, height;
  +
int r, c;
  +
  +
width = rp-&gt;BitMap-&gt;BytesPerRow * 8;
  +
height = rp-&gt;BitMap-&gt;Rows;
  +
  +
SetAPen(rp, 1);
  +
  +
for (r = 0; r &lt; height; r += 40)
  +
{
  +
for (c = 0; c &lt; width; c += 40)
  +
{
  +
Move(rp, 0L, r);
  +
Draw(rp, c, 0L);
  +
}
  +
}
  +
}
  +
  +
/*
  +
** simple event loop to wait for the user to hit the close gadget
  +
** on the window.
  +
*/
  +
VOID handleIDCMP(struct Window *win)
  +
{
  +
BOOL done = FALSE;
  +
struct IntuiMessage *message = NULL;
  +
ULONG class;
  +
ULONG signals;
  +
  +
while (!done)
  +
{
  +
signals = Wait(1L &lt;&lt; win-&gt;UserPort-&gt;mp_SigBit);
  +
if (signals &amp; (1L &lt;&lt; win-&gt;UserPort-&gt;mp_SigBit))
  +
{
  +
while ((!done) &amp;&amp;
  +
(message = (struct IntuiMessage *)GetMsg(win-&gt;UserPort)))
  +
{
  +
class = message-&gt;Class;
  +
ReplyMsg((struct Message *)message);
  +
  +
switch (class)
  +
{
  +
case IDCMP_CLOSEWINDOW:
  +
done = TRUE;
  +
break;
  +
}
  +
}
  +
}
  +
}
  +
}
  +
  +
/*
  +
** remove the effects of installDualPF().
  +
** only call if installDualPF() succeeded.
  +
*/
  +
VOID removeDualPF(struct Screen *scrn)
  +
{
  +
Forbid();
  +
  +
scrn-&gt;ViewPort.RasInfo-&gt;Next = NULL;
  +
scrn-&gt;ViewPort.Modes &amp;= ~DUALPF;
  +
  +
Permit();
  +
  +
MakeScreen(scrn);
  +
RethinkDisplay();
  +
}
  +
</pre>

Revision as of 16:35, 10 April 2013

Classic Intuition Screens

This sections contains information regarding programming Amiga screens which is no longer in use. See Intuition Screens for the current methods used to manipulate Intuition screens.

Screen Data Structures

The Amiga uses color registers and bitplane organization as its internal representation of display data. Screens require a color table and display raster memory for each bitplane. This is the memory where imagery is rendered and later translated by the hardware into the actual video display. This information is contained in data structures from the Amiga's graphics library.

A ViewPort is the main data structure used by the graphics library to represent a screen. Pointers to each of the screen's bitplanes are stored in the graphics library BitMap structure. Color table information is stored in a graphics structure called a ColorMap. And the screen's drawing and font information is stored in the RastPort structure.

The graphics RastPort structure is a general-purpose handle that the graphics library uses for drawing operations. Many Intuition drawing functions also take a RastPort address as a parameter. This makes sense since the RastPort structure contains drawing variables as well as a pointer to the BitMap telling where to draw. See Graphics Primitives chapter for more information on these structures and how they are used.

The Intuition Screen Data Structure

The structures mentioned above are unified along with other information in Intuition's Screen data structure defined in the include file <intuition/screens.h>. Notice that the Screen structure contains instances of a ViewPort, RastPort and BitMap.

struct Screen
    {
    struct Screen *NextScreen;
    struct Window *FirstWindow;
    WORD LeftEdge, TopEdge, Width, Height;
    WORD MouseY, MouseX;
    UWORD Flags;
    UBYTE *Title, *DefaultTitle;
    BYTE BarHeight, BarVBorder, BarHBorder, MenuVBorder, MenuHBorder;
    BYTE WBorTop, WBorLeft, WBorRight, WBorBottom;
    struct TextAttr *Font;
    struct ViewPort ViewPort;
    struct RastPort RastPort;
    struct BitMap BitMap;
    struct Layer_Info LayerInfo;
    struct Gadget *FirstGadget;
    UBYTE DetailPen, BlockPen;
    UWORD SaveColor0;
    struct Layer *BarLayer;
    UBYTE *ExtData, *UserData;
    };

In general, applications don't need to access the fields in the Screen structure directly; they use Intuition functions to manipulate the screen instead. Likewise, applications do not set up the Screen themselves; they use one of the OpenScreen() calls (see below). Here is a description of some of the more interesting members of the Screen structure (it is not meant to be a complete description of all the fields).

LeftEdge, TopEdge
The LeftEdge and TopEdge variables give the position of the screen relative to the upper left corner of the monitor's visible display (as set by the user in the Overscan preferences editor). If it is positioned down or to the right, the values are positive. If the screen is positioned up or to the left, the values are negative. The values are in screen resolution pixels.
The screen position may be set when the screen is opened or later by calling the MoveScreen() function.
Note that the screen's actual display position may not exactly equal the coordinates given in the LeftEdge and TopEdge fields of the Screen structure. This can cause a window which is opened in the visible part of the screen to be incorrectly positioned by a few pixels in each direction. This complication is due to hardware constraints that limit the fineness of screen positioning. For instance, high resolution screens can only be positioned in low resolution pixel coordinates, yet the values in the LeftEdge and TopEdge use high resolution pixel coordinates. So when the screen is displayed, its position is rounded to a position available for the monitor.
MouseX, MouseY
Position of the mouse with respect to the upper left corner of the screen.
ViewPort, RastPort, BitMap, LayerInfo
Actual instances of the graphics library data structures associated with this screen (not pointers to structures). For normal use of custom screens, these structures may be ignored.
BarLayer
A pointer to the Layer structure for the screen's title bar.
WBorTop, WBorLeft, WBorRight, WBorBottom
Window border values, see the Intuition Windows for information on pre-calculating the size of window borders for windows that open in this screen.
Font
The default screen font, this can be used to pre-calculate the size of the window borders for windows that open in this screen.
UserData
Free for application use.

Other Screen structure members provide information on the title bar layer, and attributes of menus and windows opened in the screen. Of particular interest are the values that allow precalculation of window border size. These variables will be discussed in Intuition Windows.

Other Screen Data Structures

In addition to the Screen structure, Intuition uses some other supporting structures defined in the include file <intuition/screens.h> and in <utility/tagitems.h>. (See the SDK for a complete listing.)

Structure Name Description Defined in Include File
Screen Main Intuition structure that defines a screen (see above) <intuition/screens.h>
DrawInfo Holds the screen's pen, font and aspect data for Intuition <intuition/screens.h>
TagItem General purpose parameter structure used to set up screens in V36 <utility/tagitem.h>
NewScreen Parameter structure used to create a screen in V34 <intuition/screens.h>
ExtNewScreen An extension to the NewScreen structure used in V37 for backward compatibility with older systems <intuition/screens.h>

As previously mentioned, there is an Intuition Screen structure (and a corresponding graphics ViewPort) for every screen in memory. Whenever a new screen is created, Intuition also creates an auxiliary data structure called a DrawInfo.

The DrawInfo structure is similar to a RastPort in that it holds drawing information. But where a RastPort is used at the lower graphics level, the DrawInfo structure is used at the higher Intuition level. Specifically, DrawInfo contains data needed to support the New Look of Intuition. (See the section below, "DrawInfo and the 3D Look" for more information.)

With screens, tag items are used to describe the attributes an application wants for a new, custom screen. Tag items replace the NewScreen structure, the set of parameters used in older versions of the OS to set up a screen.

Applications should use tag items to set up a new screen instead of the NewScreen structure since tag items are often more convenient. For the sake of backwards compatibility, the ExtNewScreen structure is available. ExtNewScreen combines the NewScreen method used to define screens in older versions of the OS with the tag item method. The examples listed in the next section show how these various data structures can be used to set up a new screen.

Custom Screen Functions

All applications require a screen to work in. This can be an existing, public screen or a new, custom screen created by the application itself. To create a new, custom screen to work with, you call OpenScreen().

Creating a new Custom Screen

The old OpenScreen() call relied on a fixed size data structure (NewScreen) which made little allowance for extensions and growth. The new calls are tag based, allowing for the addition of new features without modification of existing structures and applications. The "Screen Attributes" section below contains a complete list of all the tag options available for setting up an Intuition screen. For a general description of tag items, see Utility Library.

The NewScreen structure used with OpenScreen() has been extended with a tag list in V36 to form an ExtNewScreen. This is done by setting the NS_EXTENDED bit in the Type field of the NewScreen structure and adding a pointer to an array of tags to the end of the structure. The NS_EXTENDED bit is ignored in older versions of the operating system, so the tags can be transparently added to existing applications and the features will appear when executed in a system running V36 or greater. See the OpenScreen() Autodocs and the include file <intuition/screens.h> for more information on NS_EXTENDED and the ExtNewScreen structure.

Advanced Screen Programming

This section discusses how to create a dual-playfield Intuition screen and other advanced topics.

Dual-Playfield Screen Example

This example shows how to create a dual-playfield display. Note that this technique is only valid for screen modes which support dual-playfield, do not try to convert other modes.

Setting up dual playfield mode in the OpenScreen() call is not the best method of obtaining a dual playfield viewport for a screen. It is better to open a standard screen, passing to Intuition (or letting Intuition create) only one of the playfield bitmaps (the front one). Next allocate and set up a second bitmap, its bitplanes, and a RasInfo structure installing these into the new screen's viewport. Update the viewport modes to include DUALPF and call MakeScreen() and RethinkDisplay(). This method, shown in the example below, keeps Intuition rendering (gadgets, menus, windows) in a single playfield.

/* dualplayfield.c
** Shows how to turn on dual-playfield mode in a screen.
**
** SAS/C 5.10a
** lc -b1 -cfist -v -y dualplayfield
** blink FROM LIB:c.o dualplayfield.o TO dualplayfield LIB LIB:lc.lib LIB:amiga.lib
*/

#define INTUI_V36_NAMES_ONLY

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/displayinfo.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>

VOID doDualPF ( struct Window * );
BOOL installDualPF( struct Screen *, struct RastInfo * );
VOID drawSomething( struct RastPort * );
VOID handleIDCMP ( struct Window * );
VOID removeDualPF( struct Screen *s );

struct Library *IntuitionBase;
struct Library *GfxBase;

VOID main(int argc, char **argv)
{
struct Window *win;
struct Screen *scr;

IntuitionBase = OpenLibrary("intuition.library",37);
if (IntuitionBase != NULL)
    {
    GfxBase = OpenLibrary("graphics.library", 37);
    if (GfxBase != NULL)
        {
        scr = OpenScreenTags(NULL,
                             SA_Depth,     2,
                             SA_DisplayID, HIRES_KEY,
                             SA_Title,     "Dual Playfield Test Screen",
                             TAG_END);
        if ( scr != NULL )
            {
            win = OpenWindowTags(NULL,
                                 WA_Title,        "Dual Playfield Mode",
                                 WA_IDCMP,        IDCMP_CLOSEWINDOW,
                                 WA_Width,        200,
                                 WA_Height,       100,
                                 WA_DragBar,      TRUE,
                                 WA_CloseGadget,  TRUE,
                                 WA_CustomScreen, scr,
                                 TAG_END);
            if ( win != NULL )
                {
                doDualPF(win);

                CloseWindow(win);
                }
            CloseScreen(scr);
            }
        CloseLibrary(GfxBase);
        }
    CloseLibrary(IntuitionBase);
    }
}


/*
** Allocate all of the stuff required to add dual playfield to a screen.
*/
VOID doDualPF(struct Window *win)
{
struct Screen   *myscreen;
struct RasInfo  *rinfo2;
struct BitMap   *bmap2;
struct RastPort *rport2;

myscreen = win->WScreen;   /* Find the window's screen */

/* Allocate the second playfield's rasinfo, bitmap, and bitplane */
rinfo2 = (struct RasInfo *) AllocMem(sizeof(struct RasInfo), MEMF_PUBLIC | MEMF_CLEAR);
if ( rinfo2 != NULL )
    {
    /* Get a rastport, and set it up for rendering into bmap2 */
    rport2 = (struct RastPort *) AllocMem(sizeof(struct RastPort), MEMF_PUBLIC );
    if (rport2 != NULL )
        {
        bmap2 = (struct BitMap *) AllocMem(sizeof(struct BitMap), MEMF_PUBLIC | MEMF_CLEAR);
        if (bmap2 != NULL )
            {
            InitBitMap(bmap2, 1, myscreen->Width, myscreen->Height);

            /* extra playfield will only use one bitplane here. */
            bmap2->Planes[0] = (PLANEPTR) AllocRaster(myscreen->Width, myscreen->Height);
            if (bmap2->Planes[0] != NULL )
                {
                InitRastPort(rport2);
                rport2->BitMap = rinfo2->BitMap = bmap2;

                SetRast(rport2, 0);

                if (installDualPF(myscreen,rinfo2))
                    {
                    /* Set foreground color; color 9 is color 1 for
                    ** second playfield of hi-res viewport
                    */
                    SetRGB4(&myscreen->ViewPort, 9, 0, 0xF, 0);

                    drawSomething(rport2);

                    handleIDCMP(win);

                    removeDualPF(myscreen);
                    }
                FreeRaster(bmap2->Planes[0], myscreen->Width, myscreen->Height);
                }
            FreeMem(bmap2, sizeof(struct BitMap));
            }
        FreeMem(rport2, sizeof(struct RastPort));
        }
    FreeMem(rinfo2, sizeof(struct RasInfo));
    }
}


/*
** Manhandle the viewport:
** install second playfield and change modes
*/
BOOL installDualPF(struct Screen *scrn, struct RastInfo *rinfo2)
{
ULONG screen_modeID;
BOOL return_code = FALSE;

screen_modeID = GetVPModeID(&(scrn->ViewPort));
if( screen_modeID != INVALID_ID )
    {
    /* you can only play with the bits in the Modes field
    ** if the upper half of the screen mode ID is zero!!!
    */
    if ( (screen_modeID & 0xFFFF0000L) == 0L )
        {
        return_code = TRUE;

        Forbid();

        /* Install rinfo for viewport's second playfield */
        scrn->ViewPort.RasInfo->Next = rinfo2;
        scrn->ViewPort.Modes |= DUALPF;

        Permit();

        /* Put viewport change into effect */
        MakeScreen(scrn);
        RethinkDisplay();
        }
    }
return(return_code);
}

/*
** Draw some lines in a rast port...This is used to get some data into
** the second playfield.  The windows on the screen will move underneath
** these graphics without disturbing them.
*/
VOID drawSomething(struct RastPort *rp)
{
int width, height;
int r, c;

width = rp->BitMap->BytesPerRow * 8;
height = rp->BitMap->Rows;

SetAPen(rp, 1);

for (r = 0; r < height; r += 40)
    {
    for (c = 0; c < width; c += 40)
        {
        Move(rp, 0L, r);
        Draw(rp, c, 0L);
        }
    }
}

/*
** simple event loop to wait for the user to hit the close gadget
** on the window.
*/
VOID handleIDCMP(struct Window *win)
{
BOOL done = FALSE;
struct IntuiMessage *message = NULL;
ULONG class;
ULONG signals;

while (!done)
    {
    signals = Wait(1L << win->UserPort->mp_SigBit);
    if (signals & (1L << win->UserPort->mp_SigBit))
        {
        while ((!done) &&
               (message = (struct IntuiMessage *)GetMsg(win->UserPort)))
            {
            class = message->Class;
            ReplyMsg((struct Message *)message);

            switch (class)
                {
                case IDCMP_CLOSEWINDOW:
                    done = TRUE;
                    break;
                }
            }
        }
    }
}

/*
** remove the effects of installDualPF().
** only call if installDualPF() succeeded.
*/
VOID removeDualPF(struct Screen *scrn)
{
Forbid();

scrn->ViewPort.RasInfo->Next = NULL;
scrn->ViewPort.Modes &= ~DUALPF;

Permit();

MakeScreen(scrn);
RethinkDisplay();
}