Copyright (c) Hyperion Entertainment and contributors.

Icon Library

From AmigaOS Documentation Wiki
Revision as of 20:34, 17 March 2014 by Steven Solie (talk | contribs)
Jump to navigation Jump to search

The Icon Library

The .info file is the center of interaction between applications and Workbench. To help support the Workbench iconic interface and manage .info files, the Amiga operating system provides the icon library. The icon library allows you to create icons for data files and directories under program control and examine icons to obtain their Tool Types and other characteristics.

Icon Library Data Structures

The preceding sections discussed how icons are used to pass file name arguments to an application run from the Workbench. Workbench allows other types of arguments to be passed in the Tool Types array of an icon. To examine the Tool Types array or find other characteristics of the icon such as its type, applications need to read in the .info file for the icon.

The DiskObject Structure

The actual data present in the .info file is organized as a DiskObject structure which is defined in the include file <workbench/workbench.h>. For a complete listing, see the SDK. The DiskObject structure contains the following elements:

struct DiskObject
    {
    UWORD              do_Magic;       /* magic number at start of file */
    UWORD              do_Version;     /* so we can change structure    */
    struct Gadget      do_Gadget;      /* a copy of in core gadget      */
    UBYTE              do_Type;
    char              *do_DefaultTool;
    char             **do_ToolTypes;
    LONG               do_CurrentX;
    LONG               do_CurrentY;
    struct DrawerData *do_DrawerData;
    char              *do_ToolWindow;  /* only applies to tools */
    LONG               do_StackSize;   /* only applies to tools */
    };
do_Magic
A magic number that the icon library looks for to make sure that the file it is reading really contains an icon. It should be the manifest constant WB_DISKMAGIC. PutDiskObject() will put this value in the structure, and GetDiskObject will not believe that a file is really an icon unless this value is correct.
do_Version
This provides a way to enhance the .info file in an upwardly-compatible way. It should be WB_DISKVERSION. The icon library will set this value for you and will not believe weird values.
do_Gadget
This contains all the imagery for the icon. See the "Gadget Structure" section below for more details.
do_Type
The type of the icon; can be set to any of the following values.
WBDISK The root of a disk
WBDRAWER A directory on the disk
WBTOOL An executable program
WBPROJECT A data file
WBGARBAGE The Trashcan directory
WBKICK A Kickstart disk
WBAPPICON Any object not directly associated with a filing system object, such as a print spooler.
do_DefaultTool
Default tools are used for project and disk icons. For projects (data files), the default tool is the program Workbench runs when the project is activated. Any valid AmigaDOS path may be entered in this field such as "SYS:myprogram", "df0:mypaint", "myeditor" or ":work/mytool".
For disk icons, the default tool is the diskcopy program ("SYS:System/DiskCopy") that will be used when this disk is the source of a copy.
do_ToolTypes
This is an array of free-format strings. Workbench does not enforce any rules on these strings, but they are useful for passing environment information. See the section on "The ToolTypes Array" below for more information.
do_CurrentX, do_CurrentY
Drawers have a virtual coordinate system. The user can scroll around in this system using the scroll gadgets on the window that opens when the drawer is activated. Each icon in the drawer has a position in the coordinate system. CurrentX and CurrentY contain the icon's current position in the drawer. Picking a position for a newly created icon can be tricky. NO_ICON_POSITION is a system constant for do_CurrentX and do_CurrentY that instructs Workbench to pick a reasonable place for the icon. Workbench will place the icon in an unused region of the drawer. If there is no space in the drawers window, the icon will be placed just to the right of the visible region.
do_DrawerData
If the icon is associated with a directory (WBDISK, WBDRAWER, WBGARBAGE), it needs a DrawerData structure to go with it. This structure contains an Intuition NewWindow structure (see the "Intuition Windows" chapter for more information):
  struct DrawerData
     {
     struct NewWindow dd_NewWindow; /* structure to open window       */
     LONG             dd_CurrentX;  /* current x coordinate of origin */
     LONG             dd_CurrentY;  /* current y coordinate of origin */

};

Workbench uses this to hold the current window position and size of the window so it will reopen in the same place.
do_ToolWindow
This field is reserved for future use.
do_StackSize
This is the size of the stack (in bytes) used for running the tool. If this is NULL, then Workbench will use a reasonable default stack size (currently 4K bytes).
Stack Size is Taken from the Project Icon
When a tool is run via the default tool mechanism (i.e., a project was activated, not the tool itself), Workbench uses the stack size specified in the project's .info file and the tool's .info file is ignored.

The Gadget Structure

To hold the icon's image, Workbench uses an Intuition Gadget structure, defined in <intuition/intuition.h>. Workbench restricts some of the values of the gadget. All unused fields should be set to 0 or NULL. The Intuition gadget structure members that Workbench icons use are listed below.

Width
This is the width (in pixels) of the icon's active region. Any mouse button press within this range will be interpreted as having selected this icon.
Height
This is the height (in pixels) of the icon's active region. Any mouse button press within this range will be interpreted as having selected this icon.
Flags
The gadget must be of type GADGIMAGE. Three highlight modes are supported: GADGHCOMP, GADGHIMAGE, and GADGBACKFILL. GADGHCOMP complements everything within the area defined by CurrentX, CurrentY, Width, Height. GADGHIMAGE uses an alternate selection image. GADGBACKFILL is similar to GADGHCOMP, but ensures that there is no "ring" around the selected image. It does this by first complementing the image, and then flooding all color 3 pixels that are on the border of the image to color 0. All other flag bits should be 0.
Activation
The activation should have only RELVERIFY and GADGIMMEDIATE set.
Type
The gadget type should be BOOLGADGET.
GadgetRender
Set this to an appropriate Image structure.
SelectRender
Set this to an appropriate alternate Image structure if and only if the highlight mode is GADGHIMAGE.

The Image structure is typically the same size as the gadget, except that Height is often one pixel less than the gadget height. This allows a blank line between the icon image and the icon name. The image depth must be 2; PlanePick must be 3; and PlaneOnOff should be 0. The NextImage field should be null.

Icon Library Functions

The icon library functions do all the work needed to read, write and examine an icon's .info file and corresponding DiskObject structure:

struct DiskObject *GetDiskObject(UBYTE *name);
struct DiskObject *GetDiskObjectNew(UBYTE *name);
BOOL               PutDiskObject(UBYTE *name, struct DiskObject *diskobj);
void               FreeDiskObject(struct DiskObject *diskobj);
BOOL               DeleteDiskObject(UBYTE *);

UBYTE             *FindToolType(UBYTE **toolTypeArray, UBYTE *typeName);
BOOL               MatchToolValue(UBYTE *typeString, UBYTE *value);

struct DiskObject *GetDefDiskObjectNew(LONG type);
BOOL               PutDefDiskObject(struct DiskObject *diskobj);

UBYTE             *BumpRevision(UBYTE *newbuf, UBYTE *oldname);

The icon library routine GetDiskObject() reads an icon's .info file from disk into a DiskObject structure it creates in memory where it can be examined or altered. PutDiskObject() writes the DiskObject out to disk and FreeDiskObject() frees the memory it used. If you modify any pointers in a DiskObject acquired via GetDiskObject(), replace the old pointers before calling FreeDiskObject() so that the proper memory will be freed.

GetDiskObjectNew() works the same as GetDiskObject() except that if no .info file is found, a default DiskObject will be created for you. DeleteDiskObject() is for removing .info files from disk, and the functions GetDefDiskObject() and PutDefDiskObject() allow the default icons to be copied or replaced with new defaults.

Once an icon's .info file has been read into a DiskObject structure, the functions FindToolType() and MatchToolType() can be used to examine the icon's Tool Types array.

The Tool Types Array

Earlier sections discussed how Workbench passes filenames as arguments to a program that's about to run. Workbench also allows other types of arguments to be passed in the Tool Types array of an icon. The Tool Types array is found in the do_ToolTypes field of the icon's DiskObject structure.

In brief, Tool Types is an array of pointers to strings that contain any information an application wants to store such as the program options that were in effect when the icon was created. These strings can be used to encode information which will be available to all applications that read the icon's .info file. Users can enter and change a selected icon's Tool Types by choosing Information in the Workbench Icons menu.

Workbench does not place many restrictions on the Tool Types array, but there are a few conventions you should follow. A string may be no more than 128 bytes long. The alphabet used is 8-bit ANSI (for example, normal ASCII with foreign-language extensions). This means that users may enter Tool Type strings containing international characters. Avoid special or nonprinting characters. The case of the characters is currently significant, so the string "Window" is not equal to "WINDOW".

The general format for a Tool Types entry is <name>=<value>[|<value>], where <name> is the field name and <value> is the text to associate with that name. Multiple values for one name may be separated by a vertical bar. The values may be the type of the file, programs that can access the data, parameters to be passed to an application, etc. For example, a paint program might set:

FILETYPE = PaintProgram | ILBM

This Tool Type indicates that the file is an ILBM, perhaps with some additional chunks of data specific to PaintProgram.

Tool Type strings have few restrictions but there are some reserved Tool Types that are parsed by Workbench itself when an application is started from an icon. The reserved Tool Types are TOOLPRI=n (sets the Exec task priority at which Workbench will start the application), STARTPRI=n (sets the starting order for icons in the Wbstartup drawer), and DONOTWAIT (tells Workbench not to wait for the return of a program started via an icon in the Wbstartup drawer). In addition to the reserved Tool Types, which applications should not use, there are standard Tool Types, which applications should use only in the standard way. For a list of standard Tool Types refer to the Amiga User Interface Style Guide.

Two routines are provided to help you deal with the Tool Types array. FindToolType() returns the value of a Tool Type element. Using the above example, if you are looking for FILETYPE, the string "PaintProgram|ILBM" will be returned. MatchToolValue() returns nonzero if the specified string is in the reference value string. This routine knows how to parse vertical bars. For example, using the reference value strings of "PaintProgram" or "ILBM", MatchToolValue() will return TRUE for "ILBM" and "PaintProgram" and FALSE for everything else.

Example of Reading Icons and Parsing Tool Types

The following example demonstrates icon creation, icon reading and Tool Type parsing in the Workbench environment. When called from the Shell, the example creates a small data file in RAM: and creates or updates a project icon for the data file. The created project icon points to this example as its default tool. When the new project icon is double-clicked, Workbench will invoke the default tool (this example) as a Workbench process, and pass it a description of the project data file as a Workbench argument (WBArg) in the WBStartup message.

/*
** iconexample.c - Workbench icon startup, creation, and parsing example
*/
 
#include <exec/types.h>
#include <libraries/dos.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/icon.h>
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
/* our functions */
void cleanexit(UBYTE *,LONG);
void cleanup(void);
void message(UBYTE *);
BOOL makeIcon(UBYTE *, char **, char *);
BOOL showToolTypes(struct WBArg *);
 
UBYTE *projname     = "RAM:Example_Project";
UBYTE *conwinname   = "CON:10/10/620/180/iconexample";
 
UBYTE deftoolname[] = {"iconexample"};
 
USHORT IconImageData1[] =  {
/* Plane 0 */
    0x0000,0x0000,0x0000,0x1000,0x0000,0x0000,0x0000,0x3000,
    0x0FFF,0xFFFC,0x0000,0x3000,0x0800,0x0004,0x0000,0x3000,
    0x0800,0x07FF,0xFFC0,0x3000,0x08A8,0xA400,0x00A0,0x3000,
    0x0800,0x0400,0x0090,0x3000,0x08AA,0xA400,0x0088,0x3000,
    0x0800,0x042A,0xA0FC,0x3000,0x082A,0xA400,0x0002,0x3000,
    0x0800,0x0400,0x0002,0x3000,0x0800,0xA42A,0xA0A2,0x3000,
    0x0800,0x0400,0x0002,0x3000,0x0950,0xA42A,0x8AA2,0x3000,
    0x0800,0x0400,0x0002,0x3000,0x082A,0xA400,0x0002,0x3000,
    0x0800,0x042A,0x2AA2,0x3000,0x0FFF,0xFC00,0x0002,0x3000,
    0x0000,0x0400,0x0002,0x3000,0x0000,0x07FF,0xFFFE,0x3000,
    0x0000,0x0000,0x0000,0x3000,0x7FFF,0xFFFF,0xFFFF,0xF000,
/* Plane 1 */
    0xFFFF,0xFFFF,0xFFFF,0xE000,0xD555,0x5555,0x5555,0x4000,
    0xD000,0x0001,0x5555,0x4000,0xD7FF,0xFFF9,0x5555,0x4000,
    0xD7FF,0xF800,0x0015,0x4000,0xD757,0x5BFF,0xFF55,0x4000,
    0xD7FF,0xFBFF,0xFF65,0x4000,0xD755,0x5BFF,0xFF75,0x4000,
    0xD7FF,0xFBD5,0x5F01,0x4000,0xD7D5,0x5BFF,0xFFFD,0x4000,
    0xD7FF,0xFBFF,0xFFFD,0x4000,0xD7FF,0x5BD5,0x5F5D,0x4000,
    0xD7FF,0xFBFF,0xFFFD,0x4000,0xD6AF,0x5BD5,0x755D,0x4000,
    0xD7FF,0xFBFF,0xFFFD,0x4000,0xD7D5,0x5BFF,0xFFFD,0x4000,
    0xD7FF,0xFBD5,0xD55D,0x4000,0xD000,0x03FF,0xFFFD,0x4000,
    0xD555,0x53FF,0xFFFD,0x4000,0xD555,0x5000,0x0001,0x4000,
    0xD555,0x5555,0x5555,0x4000,0x8000,0x0000,0x0000,0x0000,
};
 
struct Image iconImage1 =
    {
    0, 0,                /* Top Corner */
    52, 22, 2,           /* Width, Height, Depth */
    &IconImageData1[0],  /* Image Data */
    0x003, 0x000,        /* PlanePick,PlaneOnOff */
    NULL                 /* Next Image */
    };
 
UBYTE *toolTypes[] =
    {
    "FILETYPE=text",
    "FLAGS=BOLD|ITALICS",
    NULL
    };
 
struct DiskObject projIcon =
    {
    WB_DISKMAGIC,                   /* Magic Number */
    WB_DISKVERSION,                 /* Version */
        {                           /* Embedded Gadget Structure */
        NULL,                       /* Next Gadget Pointer */
        97,12,52,23,                /* Left,Top,Width,Height */
        GADGIMAGE|GADGHBOX,         /* Flags */
        GADGIMMEDIATE|RELVERIFY,    /* Activation Flags */
        BOOLGADGET,                 /* Gadget Type */
        (APTR)&iconImage1,          /* Render Image */
        NULL,                       /* Select Image */
        NULL,                       /* Gadget Text */
        NULL,                       /* Mutual Exclude */
        NULL,                       /* Special Info */
        0,                          /* Gadget ID */
        NULL                        /* User Data */
        },
    WBPROJECT,                      /* Icon Type */
    deftoolname,                    /* Default Tool */
    toolTypes,                      /* Tool Type Array */
    NO_ICON_POSITION,               /* Current X */
    NO_ICON_POSITION,               /* Current Y */
    NULL,                           /* Drawer Structure */
    NULL,                           /* Tool Window */
    4000                            /* Stack Size */
    };
 
/* Opens and allocations we must clean up */
struct Library *IconBase = NULL;
struct IconIFace *IIcon = NULL;
FILE *conwin = NULL;
LONG olddir = -1;
 
BOOL FromWb;
 
int main(int argc, char **argv)
{
    struct WBStartup *WBenchMsg;
    struct WBArg *wbarg;
    FILE  *file;
    LONG  wLen;
    SHORT i;
 
    FromWb = (argc==0) ? TRUE : FALSE;
 
    /* Open icon.library */
    IconBase = IExec->OpenLibrary("icon.library", 50);
    IIcon = (struct IconIFace*)IExec->GetInterface(IconBase, "main", 1, NULL);
    if (IIcon == NULL)
         cleanexit("Can't open icon.library\n",RETURN_FAIL);
 
    /* If started from CLI, this example will create a small text
     * file RAM:Example_Project, and create an icon for the file
     * which points to this program as its default tool.
     */
    if(!FromWb)
        {
        /* Make a sample project (data) file */
        wLen = -1;
        if(file=fopen(projname,"w"))
            {
            wLen = fprintf(file,"Have a nice day\n");
            fclose(file);
            }
        if(wLen < 0) cleanexit("Error writing data file\n",RETURN_FAIL);
 
        /* Now save/update icon for this data file */
        if(makeIcon(projname, toolTypes, deftoolname))
             {
             IDOS->Printf("%s data file and icon saved.\n",projname);
             IDOS->Printf("Use Workbench menu Icon Information to examine the icon.\n");
             IDOS->Printf("Then copy this example (iconexample) to RAM:\n");
             IDOS->Printf("and double-click the %s project icon\n",projname);
             }
        else cleanexit("Error writing icon\n",RETURN_FAIL);
        }
 
    else  /* Else we are FromWb - ie. we were either
           * started by a tool icon, or as in this case,
           * by being the default tool of a project icon.
           */
        {
        if(!(conwin = fopen(conwinname,"r+")))
             cleanexit("Can't open output window\n",RETURN_FAIL);
 
        WBenchMsg = (struct WBStartup *)argv;
 
        /* Note wbarg++ at end of FOR statement steps through wbargs.
         * First arg is our executable (tool).  Any additional args
         * are projects/icons passed to us via either extend select
         * or default tool method.
         */
        for(i=0, wbarg=WBenchMsg->sm_ArgList;
            i < WBenchMsg->sm_NumArgs;
            i++, wbarg++)
            {
            /* if there's a directory lock for this wbarg, CD there */
            olddir = -1;
            if((wbarg->wa_Lock)&&(*wbarg->wa_Name))
                olddir = IDOS->CurrentDir(wbarg->wa_Lock);
 
            showToolTypes(wbarg);
 
            if((i>0)&&(*wbarg->wa_Name))
                fprintf(conwin,"In Main. We could open the %s file here\n",
                                 wbarg->wa_Name);
            if(olddir != -1)  IDOS->CurrentDir(olddir); /* CD back where we were */
            }
        IDOS->Delay(500);
        }
    cleanup();
    return RETURN_OK;
}
 
BOOL makeIcon(UBYTE *name, char **newtooltypes, char *newdeftool)
{
    struct DiskObject *dobj;
    char *olddeftool;
    char **oldtooltypes;
    BOOL success = FALSE;
 
    if(dobj = IIcon->GetDiskObject(name))
        {
        /* If file already has an icon, we will save off any fields we
         * need to update, update those fields, put the object, restore
         * the old field pointers and then free the object.  This will
         * preserve any custom imagery the user has, and the user's
         * current placement of the icon.  If your application does
         * not know where the user currently keeps your application,
         * you should not update his dobj->do_DefaultTool.
         */
         oldtooltypes = dobj->do_ToolTypes;
         olddeftool = dobj->do_DefaultTool;
 
         dobj->do_ToolTypes = newtooltypes;
         dobj->do_DefaultTool = newdeftool;
 
         success = IIcon->PutDiskObject(name,dobj);
 
         /* we must restore the original pointers before freeing */
         dobj->do_ToolTypes = oldtooltypes;
         dobj->do_DefaultTool = olddeftool;
         IIcon->FreeDiskObject(dobj);
         }
    /* Else, put our default icon */
    if(!success)  success = IIcon->PutDiskObject(name,&projIcon);
    return(success);
}
 
BOOL showToolTypes(struct WBArg *wbarg)
{
    struct DiskObject *dobj;
    char **toolarray;
    char *s;
    BOOL success = FALSE;
 
    fprintf(conwin,"\nWBArg Lock=0x%lx, Name=%s\n",
                           wbarg->wa_Lock,wbarg->wa_Name);
 
    if((*wbarg->wa_Name) && (dobj = IIcon->GetDiskObject(wbarg->wa_Name)))
        {
        fprintf(conwin,"  We have read the DiskObject (icon) for this arg\n");
        toolarray = (char **)dobj->do_ToolTypes;
 
        if(s=(char *)IIcon->FindToolType(toolarray,"FILETYPE"))
            {
            fprintf(conwin,"    Found tooltype FILETYPE with value %s\n",s);
            }
        if(s=(char *)IIcon->FindToolType(toolarray,"FLAGS"))
            {
            fprintf(conwin,"    Found tooltype FLAGS with value %s\n",s);
            if(IIcon->MatchToolValue(s,"BOLD"))
                fprintf(conwin,"      BOLD flag requested\n");
            if(IIcon->MatchToolValue(s,"ITALICS"))
                fprintf(conwin,"      ITALICS flag requested\n");
            }
        /* Free the diskobject we got */
        IIcon->FreeDiskObject(dobj);
        success = TRUE;
        }
    else if(!(*wbarg->wa_Name))
        fprintf(conwin,"  Must be a disk or drawer icon\n");
    else
        fprintf(conwin,"  Can't find any DiskObject (icon) for this WBArg\n");
    return(success);
}
 
 
/* Workbench-started programs with no output window may want to display
 * messages in a different manner (requester, window title, etc)
 */
void message(UBYTE *s)
{
    if(FromWb && conwin)  fprintf(conwin,s,strlen(s));
    else if (!FromWb) printf(s);
}
 
void cleanexit(UBYTE *s, LONG n)
{
    if(*s)  message(s);
    cleanup();
    exit(n);
}
 
void cleanup()
{
   if(conwin)    fclose(conwin);
   IExec->DropInterface((struct Interface*)IIcon);
   IExec->CloseLibrary(IconBase);
}

Function Reference

The following are brief descriptions of the functions in icon.library. See SDK for details on each function call.

Icon Library Functions
Function Description
GetDiskObject() Read the .info file of an icon into a DiskObject structure
GetDiskObjectNew() Same as GetDiskObject() but returns a default icon if none exists
PutDiskObject() Write a DiskObject structure to disk as a .info file
FreeDiskObject() Free the DiskObject structure created by GetDiskObject()
DeleteDiskObject() Deletes a given .info file from disk
FindToolType() Return the value of an entry in the icon's Tool Type array
MatchToolValue() Check a Tool Type entry against a given value
GetDefDiskObject() Read the default icon for a given icon type
PutDefDiskObject() Replace the default icon for a given icon type
AddFreeList() Add memory you have allocated to a FreeList
FreeFreeList() Free all the memory for entries in the FreeList
BumpRevision() Create a new name for a second copy of a Workbench object