Copyright (c) Hyperion Entertainment and contributors.

Public Screen Type

From AmigaOS Documentation Wiki
Jump to navigation Jump to search

Public Screen Functions

A public screen allows multiple applications to share a single screen thus saving memory. If your application opens a public screen, then other applications will be able to open their windows on your screen. In older versions of the operating system, only the Workbench screen could be shared so applications had to live within its limitations or use up Chip memory creating their own private, custom screens.

Now the system allows any screen to be set up as a public screen so there may be many public screens in memory at once, not just Workbench. This permits the power user to set up different work environments that multiple applications can share in a way that is memory efficient (each one with a display mode appropriate to a particular job).

Workbench is a special case public screen because it is the initial default public screen. The default public screen is the screen applications will get when they ask for a public screen but don't specify a name. Under normal conditions, Workbench is the default public screen and is created by the system at startup time. However, keep in mind that the default public screen can be changed (it's not always guaranteed to be Workbench).

Screens for the Novice
If you're not sure what kind of screen to use, then use the default public screen. You can open a window on the default public screen without doing any screen set-up work. See the Intuition Windows for more details.

Generally, it is much easier to use an existing, public screen than to set up one of your own. Here are the basic functions you use to work with an existing public screen.

Public Screen Functions
LockPubScreen() Find Workbench or any other public screen; prevent it from closing while a window is opened or its attributes copied.
UnlockPubScreen() Release the lock allowing the screen to later be closed.
SetDefaultPubScreen() Establishes a given public screen as the default.
GetDefaultPubScreen() Copies the name of the default screen to a user supplied buffer for use by the screen manager utility (the name is not needed by normal applications, use LockPubScreen(NULL) instead).
PubScreenStatus() Converts a screen to private or public status.
SetPubScreenModes() Controls the public screen global mode bits.

By using an existing public screen, an application is no longer responsible for setting up the display, however, it also loses flexibility and control. It can no longer set the palette or depth, and it cannot write directly into screen memory without cooperation from the owner of the public screen. (If these limitations are too confining, the application can create a new screen instead.)

Accessing a Public Screen by Name

The main calls for accessing an existing public screen are LockPubScreen() and UnlockPubScreen(). To use these functions you need to know the name of the public screen you want to access. If you do not know the name of the public screen or if you are not sure, you can lock the default public screen with LockPubScreen(NULL).

struct Screen *LockPubScreen( UBYTE * );
VOID           UnlockPubScreen( UBYTE * , struct Screen *);

These calls enable the application to determine that a public screen exists, and to ensure its continued existence while opening a window on it. This function also serves as an improvement over the old GetScreenData() function from V34 by returning a pointer to the Screen structure of the locked screen so that its attributes can be examined.

Be sure to unlock the public screen when done with it. Note that once a window is open on the screen the program does not need to hold the screen lock, as the window acts as a lock on the screen. The pointer to the screen structure is valid as long as a lock on the screen is held by the application, or the application has a window open on the screen.

Locks should not be held without reason. Holding unnecessary locks on screens may prevent the user from closing a public screen that has no apparent activity. Keep in mind that as long as you have a window open on a public screen, the window acts as a lock preventing the screen from closing.

Shown here is a simple example of how to find the Workbench public screen using LockPubScreen() and UnlockPubScreen().

/* pubscreenbeep.c
 */
 
#include <exec/types.h>               /* Amiga data types.               */
#include <exec/libraries.h>
#include <intuition/intuition.h>      /* Lots of important Intuition     */
#include <intuition/screens.h>        /* structures we will be using.    */
 
#include <proto/exec.h>
#include <proto/intuition.h>
 
struct IntuitionIFace *IIntuition = NULL;
 
/* Simple example of how to find a public screen to work with.
 */
 
int main(int argc, char **argv)
{
  struct Screen  *my_wbscreen_ptr;     /* Pointer to the Workbench screen */
 
  /* Open the library before you call any functions */
  struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
  IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
 
  if (NULL != IIntuition)
  {
    if(NULL != (my_wbscreen_ptr = IIntuition->LockPubScreen("Workbench")))
    {
      /* OK found the Workbench screen.                      */
      /* Normally the program would be here.  A window could */
      /* be opened or the attributes of the screen copied    */
      IIntuition->DisplayBeep(my_wbscreen_ptr);
 
      IIntuition->UnlockPubScreen(NULL, my_wbscreen_ptr);
     }
  }
 
  IExec->DropInterface((struct Interface*)IIntuition);
  IExec->CloseLibrary(IntuitionBase);
  return 0;
}

The Default Public Screen and Workbench

As mentioned earlier, Workbench is a special case public screen because it is the initial default public screen. There are other reasons Workbench has a special status. Normally, it's the first thing the user sees because it is the default user interface on all Amiga computers. Many older applications written for V34 and earlier versions of the OS expect to run in the Workbench screen.

Because of its close ties with the operating system, there are some extra functions available to manipulate the Workbench screen. One function which controls both Workbench and other public screens is SetPubScreenModes(). This function controls the global public screen mode bits, SHANGHAI and POPPUBSCREEN. If the SHANGHAI mode bit is set, older applications which expect to open on the Workbench screen will open instead on the default public screen (which may or may not be the Workbench screen). The POPPUBSCREEN bit controls whether public screens will be popped to the front when a window is opened. These modes are documented in Window Structures and Functions.

Other functions which control the Workbench screen are listed in the table below.

Workbench Public Screen Functions
WBenchToBack() Move the Workbench screen behind all other screens.
WBenchToFront() Move the Workbench screen in front of all other screens.
OpenWorkBench() Open the Workbench screen. If the screen is already open, this call has no effect. This call will re-awaken the Workbench application if it was active when CloseWorkBench() was called.
CloseWorkBench() Attempt to reclaim memory used for the Workbench screen. If successful, this call closes the screen and puts the Workbench application to sleep. This call fails if any application has windows open or locks on the Workbench screen.

Programs can attempt to reclaim memory used by the Workbench screen by calling CloseWorkBench(). Programs that have closed Workbench, should call OpenWorkBench() as they exit or allow the user to re-open the screen through a menu or gadget.

If Workbench is closed, any of the following events can re-open it: calling OpenWorkBench(); opening a window on the Workbench (including EasyRequests() such as the DOS "Insert Disk" requester); calling LockPubScreen("Workbench"); calling LockPubScreen(NULL) when Workbench is the default public screen.

Taking a new Custom Screen Public

Applications that open a new screen should consider taking the screen public. If the screen's characteristics are not very esoteric, making the screen public is useful because it allows other applications to share the working context. This makes an application more powerful and more attractive to the user because it allows the user to add supporting applications and utilities from other vendors to make a customized and integrated work environment.

To make your own custom screen into a public screen that other applications may use, you give the screen a public name and then register the screen with Intuition. The screen must be declared as public in the OpenScreenTagList() call by specifying a public name string with the SA_PubName tag. The application's task ID and a signal bit may also be registered when the screen is opened with the SA_PubTask and SA_PubSig tags. If these tags are given, the system will signal your task when the last window on the screen closes.

When a new public screen is opened, it starts out private so the application can perform any desired initialization (for instance, opening a backdrop window) before the screen is made public. Use the PubScreenStatus() function to make the screen public and available to other applications (or to take the screen private again, later). The screen may not be taken private or closed until all windows on the screen are closed and all locks on the screen are released. However, the screen does not need to be made private before closing it.

CloseScreen() will fail if an attempt is made to close a public screen that still has visitor windows or locks on it. If the user selects close screen, but the screen will not close due to visitor windows, a requester should be displayed informing the user of the condition and instructing them to close any windows before closing the screen.

Searching the Public Screen List

To access an existing public screen the application may take one of three approaches. To get a lock on the default public screen, either LockPubScreen(NULL) or {WA_PubScreenName, NULL} may be used.

If the name of the screen is known, the application may use LockPubScreen(Name) to gain a lock on the screen as shown in the example above (or use OpenWindowTagList() with the WA_PubScreenName tag as described in the "Intuition Windows" chapter). Failure to lock the screen or open the window probably indicates that the screen does not exist.

A third approach is to search the public screen list for a screen that meets the requirements of the application. These requirements may be related to the name or attributes of the screen. Here are the functions to use with the public screen list maintained by Intuition.

Public Screen List Functions
LockPubScreenList() Lock the public screen list maintained by Intuition so that it may be quickly copied
UnlockPubScreenList() Release the lock on the public screen list
NextPubScreen() Find the next screen in the public screen list

The main function used to access the public screen list is LockPubScreenList(). This function, intended for use by the public screen manager utility, locks the list to allow data from it to be quickly copied. The list is stored in an Exec List structure, with each node in the list being a PubScreenNode structure. See <intuition/screens.h> for details.

Do not interpret the list while in a locked state, instead, copy any values required to local variables and release the lock. All required data must be copied, including the name of the screen which is not part of the structure. Pointers that reference the list or structures attached to the list are not valid after releasing the lock. Once the lock is released, the screen pointers in the list (psn_Screen) may be tested for equality against other screen pointers, but referencing any part of the screen structure from this pointer is strictly illegal. After the lock is released with UnlockPubScreenList(), the application may access the data in the screen structure by obtaining a lock on the screen using LockPubScreen() with the name of the screen.

The application should only require accessing three fields in the PubScreenNode, these are ln_Name, psn_Screen and psn_Flags. The name of the public screen is maintained in the ln_Name field of the Node (psn_Node) structure. Access to other information on the screen may be done by getting a lock on this name and reading the data from the Screen structure. The screen pointer (psn_Screen) may only be used for testing against other screen pointers, never reference the screen structure from this value. Finally, the public screen flags are maintained in psn_Flags. Currently, only PSNF_PRIVATE is defined for this field. PSNF_PRIVATE indicates that the screen is not currently public.

Remember that all information in the public screen list is transitory, that is, it may change at any time. Do not rely on the values in the list. The only way to ensure the existence or mode of a screen is to lock it, either directly with LockPubScreen() or by opening a window on the screen. To update the copy of the list, lock it and copy the data again. Don't forget to release the lock when finished.

As an alternative to dealing with the public screen list, NextPubScreen() can be used. This call takes the name of a public screen as its argument and returns the name of the next screen in the public screen list. This helps an application move a window through the entire rotation of public screens. Repeated calls to NextPubScreen() could be used to get the names of all public screens one at a time. Keep in mind though that the list of public screens is subject to sudden change; the task that owns a public screen might close it after you obtain the name, but before you access the screen.

Always use LockPubScreen() to access screen information after scanning the public screen list.

Cloning a Public Screen (Workbench)

User preferences for screen attributes are generally reflected in the Workbench screen or in the default public screen. In some cases it may be useful to create a new screen with the same attributes.

LockPubScreen() returns a pointer to the Screen structure of a specific screen. GetScreenDrawInfo() returns rendering information on the screen, such as the pen array and font used. QueryOverscan() returns the overscan information of a specific display mode (for more information, see the section on "Overscan and the Display Clip").

The example below shows how to use GetScreenDrawInfo() to examine the attributes of the Workbench screen so that a new screen with the same attributes can be created.

struct DrawInfo *GetScreenDrawInfo( struct Screen * );

The attributes required to clone an existing screen are its width, height, depth, pens and mode. The pens and screen depth are available through the DrawInfo structure. The width and height may be obtained from the Screen structure. (The width and height may be larger than the overscan area if the screen is scrollable, and autoscroll may always be enabled as it does not effect displays smaller than or equal to the overscan area.)

The screen's display mode can be obtained using the graphics library call GetVPModeID(). This call returns the display ID of an existing screen which can then be used as the data for the SA_DisplayID tag in OpenScreenTagList(). Note that the example assumes the screen should be open to the user's text overscan preference. If an exact copy of the display clip of the existing screen is required, use the VideoControl() command of the graphics library to access the ViewPortExtra structure.

The colors of the screen may be copied using the graphics library calls GetRGB4(), SetRGB4(), SetRGB4CM() and LoadRGB4(). The example code does not copy the colors.

The example copies the font from the cloned screen. A reasonable alternative would be to use the user's preference font, which may be accessed through the SA_SysFont tag.

/* clonescreen.c
** clone an existing public screen.
*/
 
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
 
#include <string.h>
 
VOID cloneScreen(CONST_STRPTR);
 
struct IntuitionIFace *IIntuition = NULL;
struct GraphicsIFace *IGraphics = NULL;
 
/*
** Open all libraries for the cloneScreen() subroutine.
*/
int main(int argc, char **argv)
{
  CONST_STRPTR pub_screen_name = "Workbench";
 
  struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
  IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
 
  struct Library *GfxBase = IExec->OpenLibrary("graphics.library", 50);
  IGraphics = (struct GraphicsIFace*)IExec->GetInterface(GfxBase, "main", 1, NULL);
 
  if (IIntuition != NULL && IGraphics != NULL)
  {
    cloneScreen(pub_screen_name);
  }
 
  IExec->DropInterface((struct Interface*)IGraphics);
  IExec->CloseLibrary(GfxBase);
  IExec->DropInterface((struct Interface*)IIntuition);
  IExec->CloseLibrary(IntuitionBase);
  return 0;
}
 
/* Clone a public screen whose name is passed to the routine.
**    Width, Height, Depth, Pens, Font and DisplayID attributes are
** all copied from the screen.
**    Overscan is assumed to be OSCAN_TEXT, as there is no easy way to
** find the overscan type of an existing screen.
**    AutoScroll is turned on, as it does not hurt.  Screens that are
** smaller than the display clip will not scroll.
*/
 
VOID cloneScreen(CONST_STRPTR pub_screen_name)
{
struct Screen *my_screen;
ULONG  screen_modeID;
UBYTE *pub_scr_font_name;
UBYTE *font_name;
ULONG  font_name_size;
struct TextAttr pub_screen_font;
struct TextFont *opened_font;
 
struct Screen   *pub_screen = NULL;
struct DrawInfo *screen_drawinfo = NULL;
 
/* name is a pointer to the name of the public screen to clone */
pub_screen = IIntuitino->LockPubScreen(pub_screen_name);
if (pub_screen != NULL)
    {
    /* Get the DrawInfo structure from the locked screen
    ** This returns pen, depth and font info.
    */
    screen_drawinfo = IIntuition->GetScreenDrawInfo(pub_screen);
    if (screen_drawinfo != NULL)
        {
        screen_modeID = IGraphics->GetVPModeID(&(pub_screen->ViewPort));
        if( screen_modeID != INVALID_ID )
            {
            /* Get a copy of the font
            ** The name of the font must be copied as the public screen may
            ** go away at any time after we unlock it.
            ** Allocate enough memory to copy the font name, create a
            ** TextAttr that matches the font, and open the font.
            */
            pub_scr_font_name = screen_drawinfo->dri_Font->tf_Message.mn_Node.ln_Name;
            font_name_size = 1 + strlen(pub_scr_font_name);
            font_name = IExec->AllocVecTags(font_name_size, AVT_ClearWithValue, 0, TAG_END);
            if (font_name != NULL)
                {
                strcpy(font_name, pub_scr_font_name);
                pub_screen_font.ta_Name  = font_name;
                pub_screen_font.ta_YSize = screen_drawinfo->dri_Font->tf_YSize;
                pub_screen_font.ta_Style = screen_drawinfo->dri_Font->tf_Style;
                pub_screen_font.ta_Flags = screen_drawinfo->dri_Font->tf_Flags;
 
                opened_font = IGraphics->OpenFont(&pub_screen_font);
                if (opened_font != NULL)
                    {
                    /* screen_modeID may now be used in a call to
                    ** OpenScreenTagList() with the tag SA_DisplayID.
                    */
                    my_screen = IIntuition->OpenScreenTags(NULL,
                        SA_Width,      pub_screen->Width,
                        SA_Height,     pub_screen->Height,
                        SA_Depth,      screen_drawinfo->dri_Depth,
                        SA_Overscan,   OSCAN_TEXT,
                        SA_AutoScroll, TRUE,
                        SA_Pens,       screen_drawinfo->dri_Pens,
                        SA_Font,       &pub_screen_font,
                        SA_DisplayID,  screen_modeID,
                        SA_Title,      "Cloned Screen",
                        TAG_END);
                    if (my_screen != NULL)
                        {
                        /* Free the drawinfo and public screen as we don't
                        ** need them any more.  We now have our own screen.
                        */
                        IIntuition->FreeScreenDrawInfo(pub_screen,screen_drawinfo);
                        screen_drawinfo = NULL;
                        IIntuition->UnlockPubScreen(pub_screen_name,pub_screen);
                        pub_screen = NULL;
 
                        IDOS->Delay(300);   /* should be rest_of_program */
 
                        IIntuition->CloseScreen(my_screen);
                        }
                    IGraphics->CloseFont(opened_font);
                    }
                IExec->FreeVec(font_name);
                }
            }
        }
    }
 
/* These are freed in the main loop if OpenScreenTagList() does
** not fail.  If something goes wrong, free them here.
*/
if (screen_drawinfo != NULL )
    IIntuition->FreeScreenDrawInfo(pub_screen,screen_drawinfo);
if (pub_screen != NULL )
    IIntuition->UnlockPubScreen(pub_screen_name,pub_screen);
}