A ProWesS type is simply an external module, as is supported by syslib. These modules can easily be built by using some lines in your makefile, similar to these (example for the menu type) :
type_menu : type_menu_o core-dll_o ${LD} -ms -otype_menu type_menu_o \ core-dll_o -lpw -lpf -lsms -sxmod mkxmod type_menu \"ProWesS External Type Definition\"
The init bit in the module should be a structure which defines the type and its functionality. This structure is defined in the PWTypeDef.h header file. This header file is always included when you include the PWHandler.h header file. So a generic definition for the init structure would be :
PWTypeDef init={ PW_TYPEDEF_FLAG, PW_TYPE_CANVAS, PW_TYPE_EVENT_REGION, &CanvasCreate, &CanvasChange, &Query, &CanvasRemove, &CanvasEntry, &CanvasExit, &CanvasHandle, NULL, &CanvasDraw, &CanvasDetermineSize, &DoScale };
This mechanism also allows you to define more than one type in one module file. This is for example used to combine the container, separator and direction types in one module. In this particular case, the definition of the types looks like this :
PWTypeDef keep={ PW_TYPEDEF_FLAG, PW_TYPE_DIRECTION, PW_TYPE_EVENT_REGION, &KEEPCreate, NULL, NULL, &Remove, NULL, NULL, NULL, NULL, NULL, GetColour, NULL }; PWTypeDef cont={ (int)&keep, PW_TYPE_CONTAINER, PW_TYPE_EVENT_REGION, &CONTCreate, NULL, NULL, &Remove, NULL, NULL, NULL, NULL, &CONTDraw, GetColour, NULL }; PWTypeDef init={ (int)&cont, PW_TYPE_SEPARATOR, PW_TYPE_EVENT_REGION, &SEPACreate, NULL, NULL, &Remove, NULL, NULL, NULL, &Define, &SEPADraw, &SEPADetermineSize, NULL };
You can see that you can link several types by using the pointer to a different type definition instead of the identifier flag. This example also shows that many of the fields in the type definition can be NULL.
Each type has a name (new names should be registered at PROGS to prevent name clashes). You also have to specify whether the type is used to build region or keypress objects. Apart from that, the type is completely defined by a set of routines which are called when certain events occur.
#define PW_TYPEDEF_MODULE "ProWesS External Type Definition" #define PW_TYPEDEF_FLAG 0x58505753 /* flag for PWXType */ #define PW_TYPE_EVENT_REGION 1 /* region associated with object type */ #define PW_TYPE_EVENT_KEYPRESS 2 /* keypress associated with object type */ typedef struct _PWTypeDef { int flag; /* flag for external object 'XPWS' */ PWType identifier; /* type identifier, e.g. 'OUTL' */ char event_type; /* identifies type of event associated */ /* with object of this type */ /* the routines to handle calls which affect this type of object */ Error (*PWCreate)(PWObject owner, PWObject *ret, PWEvent event, int *taglist); Error (*PWChange)(PWObject object, int *taglist); Error (*PWQuery)(PWObject object, int what, void *ret); Error (*PWRemove)(PWObject object); /* handler routines */ Error (*PWRegionEntry)(PWObject object); Error (*PWRegionExit)(PWObject object); Error (*PWHandle)(PWObject object, PWWait event); /* routine to define the parameters according to the configuration file */ Error (*PWDefine)(char *name, char *value); /* draw routine for object (if it is drawable) */ Error (*PWDraw)(PWObject object); /* routines to handle the size aspects of the object */ Error (*PWDetermineSize)(PWObject object); Error (*PWScale)(PWObject object, pt xinc, pt yinc); };
The use of each of the member functions is explained in detail below. In principle, each function is called to handle a particular event which may occur. The exception to this is the PWHandle function. This function is actually called for all events which don't have a specific function. The event itself is in that case identified in the event parameters.
When defining a type, you can determine which information is contained in each object. Each object automatically contains some information which references (amongst other things) the system in which the object is contained, and a description of the object as positioned inside the system. This last reference differs depending on whether the objects are windowing or keypress objects.
To make sure that ProWesS can use this information, the start of the object is fixed, and should always be PWBaseObject. All the things which have to be known when writing a ProWesS type are defined when you include the PWHandler.h header file.
#include "PWHandler.h" typedef struct _Object { PWBaseObject; some extra variables, specific to each object } Object;
In ProWesS there are three types of events. Some events have a specific handler routine. Those events are described below. All the other events have to be handled by the PWHandle routine which is part of the type. For these events, there are two types. Some events are only generated when you ask to be notified for those events. Some events can always be generated.
Each windowing object has a link to a structure of type PWEvent. This sctructure contains a variable called wait_event. This variable is a mask which indicates which events have to be passed and which don't. You can add events by ORing the event code to the value. You should never mask an event which is always generated in this value !
PWSystem *system=object->event.region->system; pix ptrxpos=system->ptr_xpos-system->win_xpos-reg->hit_xorg+system->xorg; pix ptrypos=system->ptr_ypos-system->win_ypos-reg->hit_yorg+system->yorg;
When this event is generated, you can determine how much the pointer was adjusted by reading the Xdragadjust and Ydragadjust variables in the PWsystem structure.
To allow the objects to function properly, you get access to a part of the ProWesS data structures. These data structures are described here. All these data structures are defined when you include the PWHandler.h file.
Please note that only the fields which have a plus sign at the beginning of the description are allowed to be modified. The other fields should be treated as read only !
typedef struct _PWSystem PWSystem; typedef union { struct _PWRegion *region; /* region */ struct _PWKeyPress *keypress; /* OR keypress */ } PWEvent; /* -- definition of the dummy object (base of the real object) -- */ #define OSTATUS_REDRAW (short)0x0001 /* set when redraw needed */ #define OSTATUS_REMOVE (short)0x0002 /* set when should be removed */ #define OSTATUS_INITIALISED (short)0x0004 /* set when initialised */ #define OSTATUS_POINTER (short)0x4000 /* pointer in object on activate */ #define OSTATUS_AUTOSIZE (short)0x2000 /* increase size to fit contents */ #define PWBaseObject \ PWTypeDef *type; /* type of object */ \ PWEvent event; /* event associated with object */ \ void *auxiliary; /* auxiliary parameter for client */ \ short status /*+object status */ struct _PWDummyObject { PWBaseObject; /* common start for all objects */ };
The status field contains a mask of statusses for the object (OSTATUS_xxx).
typedef unsigned char Scale; /* scale factor */ typedef int pix; /* pixel values */ typedef short PWWait; /* type for events */ struct _PWRegion { PWSystem *system; /* global data structure for window */ PWObject parentObject; /* parent (owner when creating file) */ PWObject owner; /* owner/creator of this region */ struct _PWRegion *parent; /* parent region */ struct _PWRegion *next; /* next region on this level */ struct _PWRegion *prev; /* previous region on this level */ struct _PWRegion *children; /* list on next level of nesting */ short level; /* nesting level (==parent->level+1) /* parameters for region handler */ PWWait wait_event; /*+events to wait for */ TimeOut timeout; /*+timeout for events */ /* total area covered by region */ pt tot_xpos, tot_ypos; /* origin of region in parent */ pt tot_xsiz, tot_ysiz; /*+size of region */ /* hit area, only this area is handled by */ /* the object type handle routine */ pix hit_off_lft, hit_off_rgt; /*+margins of hit area in total area */ pix hit_off_top, hit_off_bot; /*+margins of hit area in total area */ pix hit_xorg, hit_yorg; /* top left coordinate of area on screen */ pix hit_xend, hit_yend; /* bottom right coordinate */ /* scale parameters for object */ /* the size of the margins around the hit */ /* area stays the same */ Scale scale; /* scale factor for size (primary dir.) */ char windowfit; /* secondary direction */ char composite; /*+this is a composite object */ char dragging; /* are we dragging in this region ?? */ }; struct _PWKeyPress { PWSystem *system; /* global data structure for window */ PWObject parentObject; /* parent (owner when creating file */ PWObject owner; /* owner/creator of this keypress */ struct _PWKeyPress *next; /* next keypress in list of keyspresses */ char key; /* key which should be pressed */ char alternative; /* alternative for this action */ }; typedef struct _PWRegion PWRegion; typedef struct _PWKeyPress PWKeyPress;
/* Each type can have a general state, to keep information about it */ /* Normally the base type is followed by extra type specific information */ /* The PWTypeState information is kept in a list with sentinel (type=NULL) */ #define PWBaseTypeState \ PWType type; /* type identifier */ \ struct _PWDummyTypeState *next /* next item */ typedef struct _PWDummyTypeState { PWBaseTypeState; /* common start for all typestates */ } PWDummyTypeState; /* System data structure */ #define PWPublicSystem \ unsigned long status; /*+system status (values SSTATUS_xxx) */ \ \ Gstate gstate; /* PROforma gstate is used (or NULL) */ \ Window window; /* Window identifier */ \ \ PWObject catchkeys; /* object which has to catch keypresses */\ char catch; /* key for which catching is needed */ \ char activated; /* TRUE when system activated */ \ \ short ptr_xpos, ptr_ypos; /* current pointer position */ \ pix win_xpos, win_ypos; /* position of window */ \ pix xorg, yorg; /* origin of area in window */ \ \ Heap heap; /* heap with/for this system */ \ \ int Xdragadjust, Ydragadjust; /* adjustment of pointer while dragging */\ int Xspaceleft, Yspaceleft /* space left for auto increment of obj */ #ifndef _PW_PRIVATE struct _PWSystem { PWPublicSystem; }; #endif _PW_PRIVATE #define SSTATUS_REDRAW 0x00000001 /* set when part of window needs redraw */ #define SSTATUS_WINCHANGE 0x00000004 /* set when window build has changed */ #define SSTATUS_PAGESHOW 0x00000040 /* set when PFPageShow should be done */
To aid in the development of types, some hooks back into ProWesS are provided. These hooks can be used by linking the 'core-dll_o' file into your external module. When you use these functions you should include the line
#include "PWHandler_h"in your source file.
To make it easier to handle definition constants, the PWHandleDefine function is provided. Starting from a table of possible constants and their type, place to store the new value etc. The type for the constant can be either a builtin type, or you can provide a routine to parse this value.
To aid in using the definition constants, you can also provide a post processing routine (e.g. to assure that a certain value is always even), and you can pass the address of a character which is set to TRUE when that constant was defined. This can be used to know whether the value as defined should be used, or whether a default value has to be obtained (probably by querying the ProWesS system).
typedef struct _Defines { char *name; /* name of constant, no prefix */ Error (*Handle)(struct _Defines *possible, char *value); void (*Post)(void *data); /* post processing routine */ void *data; /* place where data should be put */ char *set; /* set to TRUE when data set (if !NULL) */ } Defines; #define PW_DEFINE_COLOUR ((Error (*)(Defines*,char*))1) #define PW_DEFINE_BOOLEAN ((Error (*)(Defines*,char*))2) #define PW_DEFINE_CHARACTER ((Error (*)(Defines*,char*))3) #define PW_DEFINE_SHORT ((Error (*)(Defines*,char*))4) #define PW_DEFINE_INT ((Error (*)(Defines*,char*))5) #define PW_DEFINE_PT ((Error (*)(Defines*,char*))6) #define PW_DEFINE_FONT ((Error (*)(Defines*,char*))7) Error PWHandleDefine(char *prefix, Defines *possible, char *name, char *value);
This function is used in most of the builtin types. For example in the scroll type. A small extract of that code is shown here :
Error SetTRUE(Defines *this, char *value) { *(char *)this->data=TRUE; return ERR_OK; } Error SetFALSE(Defines *this, char *value) { *(char *)this->data=FALSE; return ERR_OK; } void cwidth(void *data) { xwidth=PF2xpix(width); ywidth=PF2ypix(width); } Defines defines[]={ { "ARROWS-LEFT", SetTRUE, NULL, &arrowsleft, NULL }, { "ARROWS-RIGHT", SetFALSE, NULL, &arrowsleft, NULL }, { "BAR-MARGINWIDTH", PW_DEFINE_PT, cwidth, &width, NULL }, { "BAR-COLOUR", PW_DEFINE_COLOUR, NULL, &colour, &Kcolour }, { 0 } }; Error ScrollDefine(char *name, char *value) { return PWHandleDefine("SCROLL-",defines,name,value); }
This command can force ProWesS to handle the current keypress in the window. ProWesS always handles keypresses as window actions. Only when no keypress handler object is created for a keypress, the current object has the chance to react to that key. However, a HIT or DO is an event which can be acted upon by the region handler. In some cases, it may be useful to pass this on to the window (possibly in the form of a <space> or <enter> keypress). Of course, you are free to activate any keypress in the window.
The current keypress in stored in :
PWSystem *system; /* the current system */ ... system->ptr_info.keystroke
Get the type definition of another type in the system. This command is needed when you want to use (part of) another already existing type. It can be compared with inheritance in object oriented programming languages. You can thus use the access routines of another type and possibly extend it, or call the existing routines in some cases, and handle some things differently.
An example where this is useful is the implementation of loose items. The loose item needs to get a border when the pointer enters the region. This is no real problem, but there may also be other types of items, like edit text which also needs such a border. However, I don't want to repeat the method of drawing this border for each type, and I want all these borders to look the same. Therefore the item type is used for the entry and exit routines of the type, and the item routine can also determine the size of the border around the hit area. The size and colour of the border can be configured, and the system background colour is used to remove the border.
These commands allow you to allocate and release some memory for a ProWesS type. It is advised that these routines are used specifically when allocating and releaseing the object itself.
Some of the type handler routines have a taglist as parameter. Some of these tags may have to be processed, and some just have to be skipped. The PWSkipTag routine skips a tag and all the parameters. This is important because there are many kinds of tags (fixed number of parameters, list or taglist as parameter), and because there has to be a correct method of skipping unrecognised tags.
Get the conversion factors to convert points (PROforma coordinates) into pixels (window coordinates), or vice versa.
{ pt Xpt2pix, Ypt2pix; pt Xpix2pt, Ypix2pt; pt pix, x, pf; short Pix, X; PWpixel2point(&Xpix2pt,&Ypix2pt); PWpoint2pixel(&Xpt2pix,&Ypt2pix); /* convert x (PROforma coor), into equivalent in pixels (pt or short) */ pix=fixmul(x,Xpix2pt); Pix=x/Xpt2pix; Pix=pt2short(fixmul(x,Xpix2pt)); /* convert X (pixel coor, short), into PROforma coor (pt) */ pf=X*Xpix2pt; pf=fixmul(short2pt(X),Xpix2pt); }
char test(pt x) { pt Xpt2pix, Ypt2pix; pt Xpix2pt, Ypix2pt; pt y; PWpixel2point(&Xpix2pt,&Ypix2pt); PWpoint2pixel(&Xpt2pix,&Ypt2pix); y=XROUND(x); return XROUND(x)==XROUND(y); }the result would be TRUE if XROUND is defined as
#define XROUND(x) PFxround(x)but it would be false with the following definition
#define XROUND(x) (Xpix2pt*pt2short(fixmul(Xpt2pix,(x))))