Next Previous Contents

4. Library Structures

To simplify usage and optimize passing parameters to functions I have declared several structures which describe most common objects. Some of these structures are bound to static addresses in GEOS data space ($8000-$8fff), so you can use their fields directly in optimized way. Please see gsym.h and find them. All structures are defined in gstruct.h and you may find also some comments there.

4.1 Graphics Structures

pixel

One simple structure describing a point on the screen.

fontdesc

This structure describes a font in one pointsize. There is current font - struct fontdesc bound to curFontDesc. You can also force GEOS to use your own fonts by calling LoadCharSet. You just need to open a VLIR font file and load one record - one pointsize - somewhere. At the start of this area you already have all data for fontdesc so you can pass a pointer to the load address of that pointsize to LoadCharSet. (Note that although it has 'Load' in the name, that function loads only GEOS internal data structures, not data from disk).

window

This widely used structure holds description of a region of the screen. It describes top-left and bottom-right corners of a window.

iconpic

Maybe the name isn't the best - it has nothing with DoIcons but with bitmap functions - BitmapUp for example. This structure holds parameters needed to properly decode and show a bitmap on the screen. Bitmap has to be encoded - if you have some non-GEOS bitmaps simply convert them to Photo Scraps - this is the format used by all GEOS bitmap functions - DoIcons too.

4.2 Icons

These structures describe click boxes (icons) that can be placed on screen or in a dialog box.

icondef

This is the definition of a single click box. Please see gstruct.h for description of its fields.

icontab

This is toplevel description of icons to be placed and enabled on the screen. This structure has following fields:

4.3 File and Disk

tr_se

This simple structure holds track and sector number of something. Do not expect the track to be in range 1-35, as GEOS can support many various and weird devices. For example my C128 256K expansion is utilized as RAMDisk with layout of 4 tracks 128 sectors each. However assuming that track number equal to 0 is illegal might be wise.

f_date

This is placeholder for file datestamp. This structure is also present in struct filehandle. GEOS is not Y2K compliant, so if current file has in filehandle.date.year value less than 86 you can safely assume that it is e.g. 2004 and not 1904.

filehandle

This is main file descriptor. It is either entry in the directory (returned from file functions) or its copy in dirEntryBuf. This is optimized so you can safely get to the file's year e.g. by testing dirEntryBuf.date.year - it will be compiled to simple LDA, STA.

fileheader

This structure holds fileheader description. You can load file's header into fileHeader fixed area using GetFHdrInfo. (note that fileHeader is a place in memory while fileheader is a structure). You will also need own fileheader for SaveFile.

4.4 System Structures

s_date

This structure is defined only for system_date. It is slightly different from f_date so I prepared this one. You can e.g. get or set current time using system_date.s_hour and system_date.s_minute. Accesses to these will be optimized to simple LDA and STA pair.

process

You should declare a table of that type to prepare data for InitProcesses. The maximum number of processes is 20, and the last entry has to be equal to {NULL,NULL}, so this table may hold only 21 entries. The first member of this structure (pointer) holds the pointer to called function (void returning void), you will probably have to cast that pointer into unsigned int. The second field jiffies holds the amount of time between calls to that function. On PAL systems there are 50 jiffies per second, while NTSC have 60 of them.

4.5 Few thing in detail...

GEOSLib uses cc65 non-ANSI extensions to easily initialize data in memory. This is done with a kind of array of unspecified length and unspecified type. Here is how it goes:

void example = {
    (char)3, (unsigned)3, (char)0 };
Which will be compiled to following string of bytes:
_example:
        .byte 3
        .word 3
        .byte 0
As you see this way it is possible to define data of any type in any order. You must remember to cast each member to proper type.

DoMenu structure

DoMenu is responsible for everything concerned with menu processing. Many, many GEOS programs are just initializing screen and menu and exit to MainLoop. In GEOSLib it is the same as returning from main function without using exit(0).

Menu is described by two types of data - menu descriptors and menu items. Descriptor contains information about following menu items, and items are containing names of entries and either pointers to functions to execute or, in case of nested menus, pointers to submenu descriptors. Note that submenu descriptor can be top-level descriptor, there's no difference in structure, just in the content.

Here is how single descriptor looks like:

void myMenu = {
        (char)top, (char)bottom,                // this is the size of the menubox
        (unsigned)left, (unsigned)right,        // counting all items in current descriptor
        (char)number_of_items | type_of_menu,   // number of following items ORed with
                                                // type of this menu, it can be either
        // HORIZONTAL or VERTICAL if you will have also bit 6 set then menu won't be closed
        // after moving mouse pointer outside the menubox. You can have at most 31 items.
This is followed by number_of_items of following item description.
        ...
        "menuitemname", (char)item_type, (unsigned)pointer,
        "nextitemname", (char)item_type, (unsigned)pointer,
        ...
        "lastitemname", (char)item_type, (unsigned)pointer };
        // Note that there isn't ending <tt/NULL/ or something like that.
pointer is a pointer to something, what it points for depends from item_type. This one can have following values:

MENU_ACTION - a function pointed by pointer will be called after clicking on menu item

SUB_MENU - pointer points to next menu descriptor - a submenu

Both of them can be ORed with DYN_SUB_MENU and then the pointer points to a function which will return in r0 needed pointer (to function to execute or a submenu).

For creating nested menus (you can have at most 8 levels of submenus) you need to declare such structure for each submenu and top level menu.

DoDlgBox command string

DoDlgBox is together with DoMenu one of the most powerful routines in GEOS. It is responsible for creating dialog boxes, that is windows which task is to interact with user. Format of the command string is following:

    (window size and position)
    (commands and parameters)
    NULL
There is custom type defined for the command string: dlgBoxStr.

Size and position

The first element can be specified in two ways - by using default size and position or specifying own. The first case results in

const dlgBoxStr example = {
        DB_DEFPOS (pattern_of_shadow),
        ...             // commands
        DB_END };
And the own size and position would be:
const dlgBoxStr example = {
        DB_SETPOS (pattern, top, bottom, left, right)
        ...             // commands
        DB_END };

Commands

The next element of DoDlgBox command string are commands themselves. First six commands are default icons and the number of selected icon will be returned from window processor. The icons are OK, CANCEL, YES, NO, OPEN, and DISK. You can use predefined macros for use them, e.g.:

        ...
        DB_ICON(OK, DBI_X_0, DBI_Y_0),
        ...
Note that the position is counted from top left corner of window, not entire screen and that the 'x' position is counted in cards (8-pixel) and not in pixels. This is true also for all following commands. DBI_X_0 and DBI_Y_0 are predefined (see gdlgbox.h for more), default positions which will make icons to appear on default window exactly where you would expect them.

DB_TXTSTR (x, y, text) will cause to show given text in the window.

DB_VARSTR (x, y, ptr) works as above, but here you are passing a pointer to a zero page location where the address of text is stored. This is useful for information windows where only text content is variable. Consider following:

char text = "foo";
        ...
        r15=(unsigned)text;             // in code just before call to DoDlgBox
        ...
        DB_VARSTR (TXT_LN_X, TXT_LN_1_Y, &r15),
        ...
will cause to appear the word ``foo'' in the window, but you may store the pointer to any text in r15 (in this case) before call to DoDlgBox.

DB_GETSTR(x, y, ptr, length) - will add input from keyboard feature. ptr works as in previous example and points to place where text is to be stored. Note that the contents of this place will be shown upon creating window. length is the maximum number of characters to input.

DB_SYSOPV(ptr) - this sets otherPressVec to given pointer. It is called on every keypress.

DB_GRPHSTR(ptr) - data for this command is the pointer for GraphicsString commands.

DB_GETFILES(x, y) - for standard window you should pass 4 for both x and y. This function draws file selection box and searches current drive for files. Before call to DoDlgBox you must load r7L with GEOS filetype of searched files and r10 with class text. In r5 you have to load pointer to a char[17] where selected filename will be copied. It works like FindFTypes but is limited to first 16 files.

DB_OPVEC(ptr) - this sets the new pointer for button press function, if you pass RstrFrmDialogue here you will cause the window to close after pressing mouse button.

DB_USRICON(x, y, ptr) - places single user icon (click box) on window, ptr points at a struct icondef but fields x and y are not used here. You can have at most 8 click boxes in a window, this is internal limit of GEOS Kernal.

DB_USRROUT(ptr) - this command causes to immediately call user routine pointed by ptr.

GraphicsString command string

GraphicsString is a very powerful routine to initialize whole screen at once. There are predefined macros for all commands, names are self-explanatory, see them in ggraph.h. Last command have to be GSTR_END. There is custom type defined for the command string: graphicStr.

Here is an example for clearing the screen:

const graphicStr example = {
        MOVEPENTO(0,0),
        NEWPATTERN(0),
        RECTANGLETO(319,199)
        GSTR_END };

InitRam table

This type of data is used to initialize one or more bytes in many places at once. The format is as following:

void example = {
    (unsigned)address_to_store_values_at,
    (char)number_of_bytes_that_follow,
    (char)data,(char)data (...)
    // more such definitions
    (unsigned)NULL // address of 0 ends the table
    };

Intercepting system vectors

It is possible to intercept and hook in the GEOS Kernal using vectors. Here is a little example:

void_func oldVector;

void NewVectorHandler(void) {
        // do something and at the end call the old vector routine
        oldVector();
}

void hook_into_system(void) {
        oldVector = mouseVector;
        mouseVector = NewVectorHandler;
}

void remove_hook(void) {
        mouseVector = oldVector;
}

In your main function you should call hook_into_system() but after all calls to GEOS kernal (like DoMenu, DoIcons, etc.) - right before passing control to the MainLoop(). Be warned that vectors are most likely to be changed by GEOS kernal also by other functions (like GotoFirstMenu, DoDlgBox and its derivatives etc.). It depends on what kernal functions you use and which vectors you altered. Unfortunately there is no exact list for GEOS 2.0, a complete list for GEOS 1.x can be found in A. Boyce's Programmers' Reference Guide mentioned before. Most of information contained there should be still valid for GEOS 2.0. When calling a function that restores the vector you should add a hook_into_system() call right after it.

It is critical to restore old vector values before exiting the program. If you have more than one place where you call exit() then it might be worth to register remove_hook function to be called upon exiting with atexit(&remove_hook); call. This way you will ensure that such destructor will be always called.

That little example above intercepts mouseVector. The NewVectorHandler function will be called every time the mouse button changes status. Other important vectors you should know about are:


Next Previous Contents