Article # 192, added by Geoworks, historical record
| first | previous | index | next | last |

Why does Swat "time out"?

;
; SaverVector abstraction
;
;==============================================================================

A number of specific savers have needed to bounce things around the screen in
a nice fashion, with different things when the point(s) being bounced
encounter the edge of the drawing area. These actions are encapsulated in the
SaverVector data type provided by the generic saver library. The vector is
one-dimensional, meaning it has only half a coordinate, not the normal ordered
pair, that it maintains. Two vectors will normally make up a point being moved
around the screen.

SaverVectorReflectTypes etype word
    SVRT_BOUNCE		enum	SaverVectorReflectTypes	; Elastic bounce (delta
							;  becomes -delta)
    SVRT_RANDOM		enum	SaverVectorReflectTypes	; Reflect in a random
							; direction opposite the
							; current one.

This enumerated type tells the generic library what action is to be taken when
the point crosses over one of the endpoints of its axis. It can reflect
elasticly simply by negating the initial delta chosen for it, or it can
reflect at a random velocity.

SaverVector	struc
    ; Data for current location
    SV_point	word			; Current point
    SV_min	word			; Minimum value for SV_point
    SV_max	word			; Maximum value for SV_point
    SV_reflect	SaverVectorReflectTypes	; Type of reflection to happen when
					;  SV_point reaches a boundary
    ; Data for delta value
    SV_delta	sword			; Current delta
    SV_deltaBase byte			; Base value for delta.
    SV_deltaMax	byte			; Maximum value for delta (above base)
SaverVector	ends

This is the data structure to be stored in the specific saver's own data
structure for each half of the ordered pair that makes up a single point.


global	SaverVectorInit:far
;
;	Initialize a SaverVector structure
;
;	Pass:	es:di	= SaverVector to initialize
;		ax	= SaverVectorReflectType
;		cx	= minimum value
;		dx	= maximum value
;		bl	= delta max
;		bh	= delta base
;	Return:	nothing
;

global	SaverVectorUpdate:far
;
;	Update a SaverVector according to its delta, etc.
;
;	Pass:	ds:si	= SaverVector to advance one step.
;	Return:	ax	= the new coordinate.
;

;==============================================================================
;
; Document Control
;
;==============================================================================

If a specific saver has documents it wishes to manipulate, it can do so using
the SaverUIDocumentControl and SaverAppDocumentControl classes. As the names
imply, the former is run by the UI thread and the latter by Saver's own
thread, so the two objects must reside in separate blocks that the specific
saver duplicates. The ugly work of supporting document control objects that
can come and go is taken care of by the generic saver library, but a number of
non-obvious actions must be performed by the specific saver. To wit:

	* In the SF_FETCH_UI procedure:
	    * You must call ProcInfo with the handle of the generic library to
	      obtain the handle of the saver's process thread.
	    * Duplicate the application-run block as you duplicate the UI-run
	      block. Note that the application-run block should be marked as
	      ui-object in the .gp file to avoid confusing GeodeLoad. You will
	      need to save this block handle for later.
	    * Call MemModify on the resulting block, passing the saver's
	      process thread in SI and MODIFY_OTHER in AH (NOTE: this is
	      different for 2.0)
	    * Invoke METHOD_APP_DOC_CONTROL_SET_OUTPUT on the app DC to point
	      its output to the saver process.
	    * Duplicate the UI-run block so you can get the OD of the ui DC.
	    * Queue a METHOD_SADC_SET_UI_DC method for the app DC passing it
	      the OD of the ui DC in ^lcx:dx. Note that this *must* be queued
	      so the attaching of the ui DC, and subsequent opening of the
	      default document, etc., will happen after the saver's UI is
	      visibly built.
	    * Invoke METHOD_UI_DOC_CONTROL_SET_PATH on the ui DC if the path
	      wasn't set in the .ui file.
	* In the SF_SAVE_STATE procedure, flag that the application-run block
	  must remain in existence. Message does this by setting the variable
	  holding the block handle to 0.
	* In the library entry routine, when di==LCT_DETACH, if the
	  SF_SAVE_STATE entry wasn't called, invoke METHOD_FREE_DUPLICATE on
	  the app DC in the application-run block.
	* When restoring from state, you will need to call
	  METHOD_SUIDC_GET_APP_DC on the ui DC to locate the application-run
	  block.

You will probably need to use the next mechanism, the specific saver process
class, to properly interact with the document control, as far as updating the
document at the right time, etc., so read on, MacDuff...

For a real-life example of how this is used, consult Saver/Message/message.asm.

;==============================================================================
;
; Specific Saver Process Class
;
;==============================================================================

The generic library allows a specific saver to have a process class via which
it can receive messages from other parts of the system (such as clipboard-
change notification) without a lot of messing around with application-run
object blocks and the like (though this is sometimes necessary, as for using a
document control object).

To do this, declare your specific process class as a subclass of SaverClass,
like so:

    MessageClass    class   SaverClass
    ;
    ; The state we save to our parent's state file on shutdown.
    ;
	MCI_fontID	FontIDs FONT_URW_ROMAN	; Font to use
	MCI_size	word	24*8		; Pointsize of same
	MCI_angle	sword	0		; Angle at which to draw it.
						; -1 => random
	MCI_color	Colors	-1		; Color in which to draw it.
						; -1 => random
	MCI_motion	MessageMotionType MMT_BOUNCE
	MCI_speed	word	MESSAGE_MEDIUM_SPEED
	MCI_format	MessageFormatType MFT_TEXT
    MessageClass    endc

Then call the function SaverSetSpecProcClass, passing the segment and offset
of the class in cx:dx. That's all there is to it. You can then subclass any
method available to SaverClass in your specific saver, including
METHOD_SAVER_START and METHOD_SAVER_STOP. Message uses it to implement such
document-control methods as METHOD_DC_FILE_OPEN, METHOD_DC_FILE_ATTACH_FAILED
and others.

;==============================================================================
;
; Saver fades and other fun stuff
;
;==============================================================================

SaverInitBlank() is provided to simplify things slightly for savers that
wish to simply blank the screen to start with.  The parameters match
those of SF_START, so this routine can be called at the startof that.

global	SaverInitBlank:far
;
;	Clear the window for initial blank.  Designed to be called
;	from SF_START for savers that want to start with a blank screen.
;
;	Pass:	di - GState handle
;		si - window width
;		dx - window height
;	Return:	none
;

There are some utility routines provided for certain special effects.
There a variety of fades and wipes (the Fades & Wipes saver uses
these), as well as a routine to draw a background bitmap (Slide Show
uses this).

;
; The different speeds supported for fades
;
SaverFadeSpeeds		etype	word
SAVER_FADE_SLOW_SPEED		enum SaverFadeSpeeds
SAVER_FADE_MEDIUM_SPEED		enum SaverFadeSpeeds
SAVER_FADE_FAST_SPEED		enum SaverFadeSpeeds

SaverWipeTypes	record
    :12
    SWT_LEFT:1			;TRUE: wipe from left
    SWT_TOP:1			;TRUE: wipe from top
    SWT_RIGHT:1			;TRUE: wipe from right
    SWT_BOTTOM:1		;TRUE: wipe from bottom
SaverWipeTypes	end

global	SaverFadePatternFade:far
;
;	Fade a rectangle to a color, 0% -> 100% patterns
;
;	Pass:	(ax,bx,cx,dx) - rectangle to fade
;		di - handle of GState
;		si - SaverFadeSpeeds (very slow, slow, medium, fast)
;	Return:	none
;

global	SaverFadeWipe:far
;
;	Fade a rectangle to a color by wiping from one or more directions
;
;	Pass:	(ax,bx,cx,dx) - rectangle to fade
;		di - handle of GState
;		si - SaverFadeSpeeds (very slow, slow, medium, fast)
;		bp - SaverWipeTypes for sides to use
;	Return:	none
;

SaverBitmapMode		etype word
SAVER_BITMAP_CENTER		enum SaverBitmapMode
SAVER_BITMAP_TILE		enum SaverBitmapMode
SAVER_BITMAP_UPPER_LEFT		enum SaverBitmapMode
SAVER_BITMAP_APPROPRIATE	enum SaverBitmapMode

global	SaverDrawBGBitmap:far
;
;	Draw a background bitmap to the window
;
;	Pass:	di - handle of GState
;		(cx,dx) - width, height of window
;		ax - SaverBitmapMode
;		ds:si - ptr to NULL-terminated filename
;	Return:	carry - set if error
;

******************************************************************************
				 RANDOM NOTES
******************************************************************************

It is a good idea to save some sort of magic/protocol number before the state
block you write out in SF_SAVE_STATE that you can check in SF_RESTORE_STATE,
especially during development. Since you cannot use the normal geode protocol
method of detecting old state files, this is the only way to safely change the
format/size of the state block without wreaking havoc on unsuspecting people
who are using your screen saver.

Remember that a screen saver is intended to save the screen from wear, not
just to be cool. This means the majority of the screen should be dark or
should rapidly become so.


======================================================================



To get rid of the "timed out" error in Swat, do the following:

1. Make sure cable is correctly wired. See article "How the null
   modem lines should be connected."

2. Make sure any DOS windows that are/were running PCCOM are closed.
   Windows '95 DOS windows will keep a serial port open even after
   you exit PCCOM.

3. Make sure you're in the correct directory on the target machine.
   You'll see three strange characters (shaped like a house) followed
   by a "c" on the target machine if you are running in the wrong
   directory.

   The correct directory is the "root" directory where the geos.ini 
   or geosec.ini file is located.