The "big" GEOS knowlage base

This version has been compiled and restructured from the knowlagebase file (public version from Geoworks). It contains all of the public Knowledge Base articles as of Thu Jul 2 15:26:56 1998.

This version is searchable and also contains an index with all of the keywords.

More information about me can be found at my webpage:
http://members.tripod.com/kajsi/

You can also mail me via:
niklas.sjogren@usa.net


Swat 'Death due to' and 'Warning' message explanations

SDK: ALL_GEOS:PUBLIC
DS_SI_NOT_POINTING_TO_SPREADSHEET - ???

CANNOT_REMOTE_CALL_FROM_UI - cannot record a message from the system's
   UI thread.

ILLEGAL_SEGMENT - One of the segment registers references a block
   that is no longer valid.  Most likely, you have a pointer to a
   block that is no longer locked.  Commonly this occurs when a
   message with a pointer parameter is sent with @send and the
   block that the pointer references is unlocked/freed before the
   sent message is handled.  (Thus the pointer is invalid.)

CANNOT_CALL_MEM_LOCK_ON_AN_OBJECT_BLOCK - This warning is caused by
   calling MemLock on an object resource (which is a specialized
   type of memory block).  Note that this is a warning: it is up to
   you to decide whether the data being locked should be moved.

   This warning commonly occurs when one of your object's visMonikers
   is a gstring that references data via an optr (GR_DRAW_BITMAP_OPTR,
   GrDrawTextOptr, etc.) and that data is in the object resource rather
   than a data resource (which is read-only, lmem).  The memory manager
   can more efficiently access the data if it is in a data resource
   rather than the (writeable) object resource.

CANNOT_USE_DOUBLE_BYTE_CHARS_IN_THIS_VERSION - This error means an
   invalid character (something over FF hex) was passed to the routine
   (e.g., LocalUpcaseChar), but this verion of Geos doesn't support
   double byte characters.  The problem may be that the character is
   being sign extended because the high bit of the byte is set.

OBJ_DUPLICATE_BLOCK_NOT_DISCARDED - the resource to be duplicated is
   in memory.  To fix this, add "discard-only" to the resource
   declaration in the .gp file.

GRAPHICS_NO_FONT_FILES - occurs on startup if you don't have any
   files in your USERDATA/FONT directory.

VIS_TEXT_RANGE_END_BEFORE_START - the value for the end parameter is
   smaller than the start parameter.  For GEOS SDK 2.0, this is because
   the C header file has the parameters listed backwards.  To fix this,
   simply swap the start and end parameters in the message call.

TEXT_STRING_CONTAINS_NULL
   The string length in MSG_VIS_TEXT_REPLACE_ALL_PTR includes the null-
   terminator in the string or the string data is corrupted.  If the
   string is null-terminated you may wish to pass zero as the string
   length.

TEXT_PARA_ATTR_RUN_NOT_AT_PARAGRAPH_BOUNDARY - the death error occurs
   when a paragraph run element is not at a paragraph boundary.  That
   is, the element's position is at a character other than a paragraph
   boundary. But I'm unsure why backspacing over a paragraph boundary
   would cause problems. The error-checking code should only be executed
   during editing operations or some other operation that causes the runs
   to be updated.

   If you have not already done so, do "ec text high" to get more error
   checking help.  Also, use ptext just before you hit the backspace to
   see what the paragraph runs look like.

LINE_DOES_NOT_EXIST - This error occurs when a message tries to get line
   information (VTI_lines) from a text object that hasn't been built out
   yet (the text object isn't visible on the screen).  Make sure not to
   send messages like MSG_VIS_TEXT_CONVERT_OFFSET_TO_COORDINATE to a
   newly created text object until it is build out.

VIS_TEXT_REACHED_LAST_REGION_WITHOUT_FINDING_NEEDED_COUNTS
   This is caused when the text object's internal data structures are
   getting is messed up and is not rippling data correctly.  The ISV
   is somehow messing up the text object's internal data structures.

TS_LOCK_TEXT_PTR_INVALID_RETURN_VALUE
   Your text object has gotten larger than 20K.   It may be that the system
   only checks to see if a text object has gotten too large when the user is
   entering characters, that it doesn't in general do something graceful,
   leaving it up to the calling app.

BAD_RELOCATION_CANNOT_FIND_VM_HANDLE - This can be cause by a library
   ldf or goh file being out of synch with the current library geode.
   Get new ldf and goh files.

VM_GAP_EXISTS_IN_FILE - It could be caused by an improperly-created VM file
   created by something external to GEOS.  Often, this is caused by a bug
   in the VM code itself.

FSIR_NOT_LOCKED_SHARED_BY_THIS_THREAD - trashing your stack, or attempting to
   call FSDUnlockInfoShared when you've not called FSDLockInfoShared...

CORRUPT_LINKAGE	- the handle (or chunk handle) of an object is zero.  The
   composite link is (therefore) corrupt.

EVAL_ILLEGAL_PARSER_TOKEN - the parsed token is not one of ParserTokenType.

ILLEGAL_RESOURCE - commonly caused by calling GeodeGetOptrNS in a single
   launchable app.

MUST_SET_CONTEXT_BEFORE_SENDING_UNDO_MESSAGES
   ISV must set the context with MSG_GEN_PROCESS_UNDO_SET_CONTEXT

VM_COMPRESS_HOSED
    we came to the last used block and found out that there are
    more blocks on the assigned list.

LMEM_HEAP_SIZES_DONT_ADD_UP
    the size of all the chunks (as determined by
    LMValidateSizes) does not add up to LMBH_blockSize
    (size of memory block containing chunks).

BAD_HEAP_SIZES
    The various heap/chunk sizes don't add up
    correctly. The offset to the heap start added
    to the sum of the chunk sizes doesn't match
    the value of blockSize (the stored size of the
    block).

UNFREE_CHUNK_ON_LIST
    Somehow a non-free chunk is part of the free
    list.

FREE_SPACE_WRONG
    The sum of the free-chunk sizes doesn't match
    the totalFree variable stored in the info.

HANDLES_MATCH
    Two handles refer to the same chunk.

HANDLE_OUT_OF_BOUNDS
    A reference to a handle which is outside the
    handle table has been made.

ADDR_OUT_OF_BOUNDS
    A reference to a chunk which is outside the
    heap has been made.

TAGS_DONT_MATCH
    The size/flags words at either end of a chunk
    do not match.

CHUNK_WITHOUT_HANDLE
    A non-free chunk has been found which doesn't
    have a handle associated with it.

HANDLE_TO_FREE
    A free chunk has been found that has a handle
    pointing at it.

ADJACENT_FREE_CHUNKS
    Two adjacent chunks are marked as free. This is
    a no-no. They should have been coalesced.

NOT_LMEM_HANDLE
    ECCheckLMemHandle* was called on a handle

GRAPHICS_BAD_FONT_PATH
  Either there are no fonts in USERDATA\FONT, the standard path set
  for fonts is pointing off to oblivion, or the right file system
  driver isn't downloaded. This last will only happen in the non-EC,
  as error checking code in the EC will catch the case otherwise.

NO_ONE_TO_SEND_SHUTDOWN_ACK_TO_ALAS
  Someone called SysShutdown(SST_CLEAN/SST_SUSPEND), passing cx==0, after the
  UI has exited, or before it started up.

Memory errors:

TOO_MANY_LOCKS
  A memory block may only have at most 254 locks placed on it, and you're
  on your 255th, or you're attempting to lock a fixed block. If the former,
  you're probably missing a MemUnlock for one of your MemLocks. If the
  latter, remember the tale of the person who told the doctor, "it hurts
  when I do this."

BAD_UNLOCK
  You are attempting to unlock an unlocked block.

CANNOT_CHANGE_OWNER
  You are attempting to change the owner of a non-sharable handle you do not
  own. Most likely, the handle whose ownership you think you're changing has
  long since been freed and re-used.

HANDLE_SHARING_ERROR
  You are attempting to lock down a memory block owned by another geode that
  isn't marked HF_SHARABLE. Either you've got the wrong handle (e.g. you're
  using a handle for a block you freed, which was recycled by the system),
  or you need to mark this block HF_SHARABLE.

ALLOC_ZERO
  You are not allowed to allocate a zero-sized block of memory. Allocate
  something HF_DISCARDED with a non-zero size if you just wish to reserve
  a memory handle for later use.

MEM_FREE_BLOCK_DATA_NOT_CC
  This error is trigged when ec +heapFree is enabled and indicates that
  something has written outside the bounds of one of its blocks into
  unallocated memory. The system fills free blocks with 0xcc bytes and
  regularly checks all free memory to make certain all the bytes remain
  0xcc. es:di-2 or es:di-1 is the first non-cc byte in the free block (the
  system checks for 0xcccc words, you see). What next? You should look at
  the data to see if they look like anything you might be creating (e.g. a
  recognizable text string), then look at blocks that fall just before the
  free block to see who allocated them and for what purpose, then take a
  look at the code that would be manipulating those blocks and see if they
  might scribble like this.

ECF_UNLOCK_MOVE_FAILED_SORRY
  This indicates that the memory being moved because of ECF_UNLOCK_MOVE being
  set was swapped out and could not be swapped back in again, due to an
  error declared by the swap driver.

MEM_REFERENCE_COUNT_NEVER_INITIALIZED

  MemIncRefCount was called on a block with a refCount of 0 - MemInitRefCount
  was never called on the block

FAKE_BLOCK_DOESNT_COVER_ENTIRE_NEW_HEAP_SEGMENT
  A swap driver is attempting to extend the heap with a segment that must
  already part of the heap, as the block that intersects the start of segment
  being added doesn't cover the entire extent of the segment being added.

OBJ_BAD_DEREF
  You called ObjDerefGen, ObjDeref1 or one of their friends but
  the master offset you are derefing does not have the master offset
  you are derefing.
  i.e. You are using the wrong deref routine.

SOMETHING_LEFT_ON_STACK_BEFORE_STACK_SPACE_RETURN
  You called ThreadRestoreStackSpace with something left on the stack that
  you pushed after calling ThreadBorrowStackSpace. This is a bozo no no.

THREAD_STACK_NOT_IN_LIST
  The list of thread stack blocks has been corrupted, possibly by someone
  calling HandleP on a geode's dgroup handle.

TIMER_BAD_YEAR
  TimerSetDateAndTime() was passed a year outside the range (1980-2099)

TIMER_BAD_MONTH
  TimerSetDateAndTime() was passed a month outside the range (1-12)

TIMER_BAD_DAY
  TimerSetDateAndTime() was passed a day outside the range (1-31)

TIMER_BAD_HOUR
  TimerSetDateAndTime() was passed an hour outside the range (0-23)

TIMER_BAD_MINUTE
  TimerSetDateAndTime() was passed a minute outside the range (0-59)

TIMER_BAD_SECOND
  TimerSetDateAndTime() was passed a second outside the range (0-59)

TIMER_MISSED
  There's a bug in the timer code such that a timer with a time-remaining
  of 0 was placed on the timer list. This should not happen. It's not
  your fault :)

LIBRARY_ENTRY_NUMBER_TOO_LARGE
  Calling ProcGetLibraryEntry with an exported-entry number larger than the
  number of entry points exported by the library (si holds requested number).

UNKNOWN_HANDLE_TYPE_IN_HANDLE_TABLE
  FreeGeodeBlocks is running through the handle table and has hit a handle
  that is not one of the known non-memory handles. The handle table has
  been scribbled on.

GRAPHICS_CANT_CREATE_ZERO_SIZED_BITMAP
  You can't pass zero width or height to GrCreateBitmap

GRAPHICS_PATTERN_CUSTOM_PATTERN_TOO_BIG
  The custom pattern (either a HatchPattern or Bitmap) is too large to be
  used. A 16K limit is enforced for custom patterns, as these are stored in
  the GState segment.

GRAPHICS_HATCH_PATTERN_DELTA_Y_CANT_BE_ZERO
  The HL_deltaY is defined to be in the rotated coordinate space of the hatch
  line (although the rotation may be zero), so it never makes sense to
  have a line that continually draws on top of itself.

GRAPHICS_MUST_PASS_OD_TO_CREATE_BITMAP
  You must pass a non-zero exposure OD to GrCreateBitmap as the object
  that will handle any MSG_META_EXPOSED messages caused by bitblts and the
  like within the bitmap.

GRAPHICS_BITMAP_ALREADY_COMPACTED
  GrCompactBitmap must be passed an uncompacted bitmap

GRAPHICS_BITMAP_MUST_BE_PACKBITS
  GrUncompactBitmap must be passed a compacted bitmap in the PackBits format

GRAPHICS_CANT_DO_THIS_WITH_COMPACTED_BITMAP
  Can't call GrClearBitmap or GrEditBitmap with a compacted bitmap.

GRAPHICS_BITMAP_SHOULDNT_BE_LOCKED
GRAPHICS_DEFINING_PATH_CANT_SET_DEFAULT_STATE
  You shouldn't be calling GrSetDefaultState while defining a path

GRAPHICS_UNBALANCED_SAVE_RESTORE_STATE
  There is an unbalanced GrSaveState/RestoreState pair.  Perhaps you are
  calling GrNewPage with saved states.

GRAPHICS_ILLEGAL_PAGE_END_COMMAND

GRAPHICS_ILLEGAL_PATH_TYPE
GRAPHICS_BITMAP_RESOLUTION_CANT_BE_ZERO
  The bitmap resolution stored in the complex bitmap structure is zero,
  an invalid value.  This may mean that the BMT_COMPLEX bit was set
  in the B_type field of the bitmap header when it shouldn't be.

GRAPHICS_SENTINEL_FOR_BITMAP_COMPRESSION_CORRUPTED
  The sentinel word stored at the end of the buffer used to compress
  a bitmap has been corrupted, indicating an internal error in
  GrCompactBitmap

GRAPHICS_BITMAP_COMPACTION_INTERNAL_ERROR
GRAPHICS_BITMAP_INTERNAL_ERROR
GRAPHICS_SENTINEL_FOR_BITMAP_BUFFER_CORRUPTED
  The sentinel word stored at the end of the buffer used for drawing
  complex bitmaps has been corrupted, indicating an internal error in
  either how the size of the buffer was calculated, or how someone is
  writing into the buffer.

GRAPHICS_POLYLINE_SPECIAL_SHOULDNT_HAVE_FAILED
  A call to CheckThinLine() indicated a fat line would be drawn, but
  PolylineSpecial returned that a thin line would actually suffice. The
  logic to determine a thin line must be the same in each of these routines.

    Font Manager errors

FONTMAN_FIND_OUTLINE_DATA_CALLED_WITH_BITMAP_FONT
  FontDrFindOutlineData() was called with a bitmap font.  It is
  intended for use by font drivers, and therefore should only
  be called for fonts that have outline font data available.

FONTMAN_BAD_ENUM_FLAG_PASSED_TO_IS_FONT_AVAIL
  GrCheckFontAvail() cannot alphabetize fonts.

FONTMAN_BAD_FONT_INFO_FOR_ADD_FONT
  GrAddFont() was called with a bogus FontInfo() entry.

FONTMAN_FONT_FILE_DELETED
  The font file was deleted between the time it was first used and
  the time the font manager attempted to reload a font from it.
  This probably indicates a bug in the font manager.

FONTMAN_COULDNT_OPEN_FONT_FILE
  The font file couldn't be opened to reload a font from it.
  This probably indicates a bug in the font manager.

FONTMAN_BAD_FONT_FILE_READ
  The file read of the font file failed.
  This probably indicates a trashed font file.

FONTMAN_FONT_DRIVER_NOT_FOUND
  The font driver for this font couldn't be found.
  Is the driver specified in the geos.ini file?
  Is the (correct version of) the driver in the SYSTEM\FONT directory?

FONTMAN_NEED_FEF_OUTLINES_OR_FEF_BITMAPS
  GrCheckFontAvail() and GrEnumFonts() need at least one of
  FEF_OUTLINES or FEF_BITMAPS set in the FontEnumFlags, otherwise no
  fonts will ever match.

FONT_INIT_NO_POINTSIZE_FOUND
  No pointsize could be found for the default font.  Something may
  be wrong with the file of the default font, such as a bad header.

FONT_INIT_IN_USE_CHUNK_NOT_EMPTY
  The FontsInUse chunk was not empty during initialization.  Something
  is probably wrong in GrInitDefaultFont() or GrInitFonts().

FONT_BAD_WEIGHT
  You should not use FontWeights in the range FW_ULTRA_LIGHT to FW_BLACK.
  These are provided for backwards compatibility only.

FONTMAN_FILE_CACHE_CORRUPTED
  The font file cache was somehow corrupted (eg. a font in the cache
  didn't exist, was listed in the cache twice, etc.)

WIN_INPUT_OBJ_MUST_BE_RUN_BY_SAME_THREAD_AS_GEODE_INPUT_OBJ
  This is an error that WinOpen generates if the passed "InputOD" & "owner"
  for geode are not compatible.  Any non-NULL InputOD passed must be run by
  the same thread as runs the owner-to-be's geode's input object, by default
  the geode's GenApplication object.  This is necessary not because of a
  kernel requirement, but because GenApplication expects to be able to call
  any InputOD of a window that it has received input for.

WIN_ERROR_MOVING_WINDOW_ALREADY_IN_BACK_TO_BACK
  A window or window layer, after being moved to the back, was found to have
  no siblings to its/their right before beingmoved.  Code earlier in the
  routine is supposed to have bailed out in this case with nothing to do.

WIN_BAD_ASSUMPTION
  Bad assumption internal to window system code

OBJ_FLUSH_INPUT_QUEUE_BAD_NEXT_STOP
  Result of default MetaClass handler for MSG_META_OBJ_FLUSH_INPUT_QUEUE being
  called with bogus ObjFlushInputQueueNextStop value

OBJ_ILLEGAL_REFERENCE_TO_DYING_OBJECT_BLOCK
  Object block being tested has had MSG_META_BLOCK_FREE or ObjFreeObjBlock
  called on, is no longer marked as "in use", & will be nuked from memory the
  moment the queues have finished being flushed.  The current operation being
  performed requires this NOT to be the case.  One example is "WinClose", which
  requires that the exposureObj & inputObj's not already be dying.  This can
  be corrected by first closing the window, or changing its inputObj or
  exposureObj to NULL, & THEN destroying the object, or object block.

  More in-depth info:  This error checking routine
  is called by the system when it is about to start another queue-flushing
  sequence to an object, to make sure that it's going to be around to be able
  to receive the message -- if the block's about to be freed within one
  queue flush, then the new flush doesn't stand any chance of being able to
  finish without crashing.

OWNER_CORE_BLOCK_NOT_LOCKED
  The kernel is unrelocating a handle and has found that the core block for
  the owner of the block being unrelocated is not, in fact, locked.

VM_FILE_MUST_BE_CLOSED_WITH_VM_CLOSE
  A geode tried to close a VM file by calling FileClose instead of VMClose.
  This often happens if a geode has a VM file open, and exits without closing
  it.

ATTEMPTED_TO_PERFORM_UNSUPPORTED_FUNCTION_BEFORE_APPROPRIATE_IFS_DRIVER_WAS_LOADED
  The proper file system driver for one of your PC's drives didn't get
  loaded.  Since the system::fs key in the INI file was not set, Geos
  polled the system to determine what drives are present and didn't
  recognize the response it received.

  To fix this problem:

  If you're using MS-DOS 7 (Windows 95) or PC-DOS 7, add the following
  line to the [system] category of the GEOS.INI file.
    fs = ms4.geo
  This will force the appropriate file system driver to be loaded.
  (For EC emulator, add "fs = ms4ec.geo" to the GEOSEC.INI file.)

  If you plan on reinstalling the target software and don't want to
  always have to update the INI file, you can do the following as a
  more permanent solution:

  For MS-DOS 7, you'll need to enter these three lines at the DOS
  prompt, then reboot the machine:
      CD\WINDOWS
      SETVER LOADER.EXE 6.3
      SETVER LOADEREC.EXE 6.3

  If you're using PC DOS 7, you'll need to make sure that this line
  is in your config.sys file:
      DEVICE=C:\DOS\SETVER.EXE
  then reboot your machine and enter this line at the DOS prompt:
      SETVER LOADER.EXE 6.3
      SETVER LOADEREC.EXE 6.3
  then reboot your machine again.

INVALID_FSDRIVER_OFFSET
  Called FSDUnregister with an offset that's not a registered FS driver, as
  returned by FSDRegister.

FSIR_MAY_NOT_BE_LOCKED
  FileGetDestinationDisk has been called with the FSInfoResource locked in
  some way. This can lead to deadlock, however, when the disk for a drive
  specifier is registered.

FSHOF_SET_FILE_NAME_PASSED_TO_SKELETON_DRIVER
  The skeleton filesystem driver has been told the name of a file opened
  before the other drivers were loaded. This means the file in question
  was opened on a drive for which the driver was not loaded. Likely you will
  die soon of some other error.

VM_READ_FILE_WORD_ERROR
  A call to VMFileReadWord() returned an error.  Given that this is simply
  doing a file pos, and then reading from a portion of the VM header which
  is assumed to exist, an error is a bad thing.  See Tony.

VM_ATTACH_BLOCK_CANNOT_BE_DETACHABLE
  A block that is passed to VMAttach must be NOT_DETACHABLE, so as to avoid
  confusing the application state file mechanism, which will expect to be
  able to save the block to the state file when the application is detached.

  The NOT_DETACHABLE attribute can be set in a .ui file with
  "start Resource, notDetachable" or in a .goc file with
  "@start Resource, notDetachable;"

VMEM_GENERIC_OBJECTS_CANNOT_BE_UPDATED_ASYNCHRONOUSLY
  The file whose handle is in BX has VMA_COMPACT_OBJ_BLOCK set without
  having VMA_SYNC_UPDATE set. This is illegal, as it implies that whenever
  a block containing generic objects is off-screen, it can be compacted,
  thereby losing all non-save-to-state vardata and other things that could
  well be vital to bringing the objects back on-screen.

CANNOT_TRUNCATE_MULTI_REFERENCED_VM_FILE
  Someone has called VMTruncateAndClose for a VM file that has been opened
  by more than one application. Since VMTruncateAndClose is an extremely
  destructive operation, rendering the VM file invalid, the kernel refuses
  to perform it unless it knows only one process is using the file.

DB_UNGROUP_NOT_LOCKED
  VMMarkUngroupAvail has been called passing the handle of a group block
  that's not locked. This is illegal, as the handle for the block could go
  away at any time... this is an internal error in the kernel DB code.

UNGROUPED_GROUP_MAY_NOT_BE_PASSED_AS_AN_EXPLICIT_GROUP
  DBAlloc was called passing a group in AX that is a member of the set of
  groups used to satisfy requests for DB_UNGROUPED allocations. For various
  reasons, this is against the rules. Use DB_UNGROUPED instead, or create
  your own group (if you need to have items end up in the same group, for
  some reason).

  ***** OBJECT ERRORS *****

BAD_REMOVE_CHILD
BAD_CLASS
  This error happens frequently when an object or object block is freed
  before a message in the queue destined for it is delivered.  Always use
  as high a level of object/block destruction mechanism as you can -- The
  highest object-level routine in the UI is MSG_GEN_DETROY, in vis,
  MSG_VIS_DESTROY.  Lower is MSG_META_OBJ_FREE, which first flushes queues
  after which a MSG_META_FINAL_OBJ_FREE is sent to the object.  The handlers
  for this last message are allowed to use ObjFreeChunk & LMemFree.  On the
  block side, once all objects within the block have been taken out of any
  tree they resided in, MSG_META_BLOCK_FREE & ObjFreeObjBlock are the high-
  level message/routine to use.  MSG_META_FINAL_BLOCK_FREE ends up being
  called only after the queues have been flushed out, which in turn is
  allowed to actually nuke the block.

LMEM_BAD_INSERT_OFFSET
  LMemInsertAt() was passed a bad offset.  The offset passed should
  be the offset from the start of the chunk you are inserting in.

LMEM_BAD_DELETE_OFFSET
  LMemDeleteAt() was passed a bad offset.  The offset passed should
  be the offset from the start of the chunk you are deleting in.

LMEM_BAD_DELETE_SIZE
  LMemDeleteAt() was passed a bad size.  The passed size to delete was
  larger than the existing chunk.

LMEM_BAD_DELETE_COMBINATION
  LMemDeleteAt() was passed a bad offset/size comibination.  The offset
  plus the size extends beyond the end of the chunk.

OBJ_BLOCK_BAD_IN_USE_COUNT
  Each object block contains an "in-use" count, which is stored in the
  ObjLMemBlockHeader (The field is OLMBH_inUseCount).   The count starts
  out as 0, indicating objects are not active, climbs during usage, & must
  return to 0 before the block may be destroyed.  If you've gotten this
  error, it is because the count went negative, or became far to large to
  be a reasonable value.  The most common cause of this is intercepting &
  not passing on to the superclass a method which inc/decs this count.

  So, which methods might these be?  The count is incremented each time
  an object becomes active in some new way in the system, & is decremented
  each time an object is no longer active in that way.  Currently, there
  are the following pairs:

    1) Incremented whenever a window is created for visible objects
       having the VTF_IS_WINDOW bit, & decremented in the default
       handler for MSG_META_WIN_DEAD.

    2) Inc in MSG_META_OBJ_FREE (sent when objects are being destroyed)/
       Dec in MSG_META_FINAL_OBJ_FREE (sent out after queues interacting
       with object have been cleared)

    3) New object classes are free to inc/dec this count as well, using
       ObjIncInUseCount & ObjDecInUseCount, but must do so in pairs, or
       this fatal error may be the result.

  Also -- note that if a decrement does not occur for each increment, then
  the count never reaches zero, resulting in the block never getting free/
  application never exiting.

OBJ_BAD_IN_USE_COUNT
  Indicates if in-use count has gone negative for this particular object (The
  EC code only keeps track of the in-use count on a per-object basis).  See
  above OBJ_BLOCK_BAD_IN_USE_COUNT for more info.

OBJ_BLOCK_BAD_INTERACTIBLE_COUNT
  Each object block contains an "interactible" count, which is stored in the
  ObjLMemBlockHeader (The field is OLMBH_interactibleCount).   The count
  starts out as 0, & becomes non-zero as objects in the block become visible,
  or need to have current status information reflected in their state.
  GenControl objects are not updated unless this value is non-zero.  This
  error occurs only if the value goes negative, which should never happen,
  as the count should only be changed by in/dec pairs.

  So, which methods might these be? Currently, there are the following pairs:

    1) Incremented whenever a window is created for visible objects having
       the VTF_IS_WINDOW bit, & decremented in the default handler for
       MSG_META_WIN_DEAD.

OBJ_BAD_INTERACTIBLE_COUNT
  Indicates if interactible count has gone negative for this particular
  object (The EC code only keeps track of the interactible count on a
  per-object basis).  See above OBJ_BLOCK_BAD_INTERACTIBLE_COUNT for
  more info.

OBJ_RELOCATION_TO_INVALID_LIBRARY_NUMBER
  The application is probably restoring from state and one of its libraries,
  or its libraries' libraries exports an object class an instance of which
  was saved to state, but now one of the libraries or libraries' libraries
  has changed what libraries it imports without having increased the
  protocol number, so the state file is invalid.

RELOCATION_TO_INVALID_LIBRARY_ROUTINE_NUMBER
  This can happen if you're using a library whose entry points in the .gp do
  not match the one your geode was compiled with (because it's too old, etc).

BAD_TABLE_SIZE_PASSED_TO_OBJ_VAR_SCAN_DATA
  The # of VarDataHandlers passed to ObjVarScanData is unreasonable (0, or
  very large)

BAD_SIZE_PASSED_TO_OBJ_VAR_ADD_DATA
  Size of extra data passed to ObjVarAddData is unreasonably large

CLASS_AT_DS_SI_MARKED_NEVER_SAVED_SO_WHY_AM_I_RELOCATING_OR_UNRELOCATING_IT_BUB?
  This death occurs if a class has been @classdecl'ed with the "neverSaved"
  flag but an object of that class is being saved to state.  To fix the
  problem, either mark the object "ignoreDirty" (so it doesn't save to state)
  or remove the "neverSaved" flag from the class declaration.

  Note that GenProcessClass subclasses should be marked neverSaved because
  process objects don't have any instance data thus they are never saved
  to state.

OBJ_SHUTDOWN_OR_DETACH_WHILE_OTHER_STILL_ACTIVE
  ObjInitDetach was called for an object while a previous MSG_META_DETACH
  or MSG_META_APP_SHUTDOWN was still active for the object, and the message
  passed to ObjInitDetach is different from when ObjInitDetach was first
  called for the object (e.g. a MSG_META_APP_SHUTDOWN was received before
  the object sent MSG_META_ACK back to the object that sent it a
  MSG_META_DETACH). You might also have trashed AX before calling
  ObjInitDetach, so it didn't receive the message number your object
  actually received.

FSD_LOADED_BUT_NOT_REGISTERED
  When restoring a disk handle, was able to find the core block for
  the IFS driver, but not its  FSDriver record. Likely the FSDriver
  chain has been corrupted.

SAVED_DISK_HAS_NO_DRIVE_SPECIFIER_FOR_DRIVE_NAME
  When trying to locate the drive for a saved disk handle, we
  were told the saved drive name, which should always be a name followed
  by a colon (aka a drive specifier), had no drive specifier. Either
  DiskSave screwed up or, more likely, the saved data have been corrupted
  by the application.

DRIVE_NOT_LOCKED_EXCLUSIVE
  You are attempting to release exclusive access on a drive that is
  marked as being locked for shared access.

INK_ENUM_EXCEEDED_END_OF_BUFFER
  We tried to terminate a line segment, but there were no points in the
  point buffer.

NUM_INK_POINTS_IS_ZERO
  We are sending ink off, and the # points is 0. This shouldn't happen.

INK_Y_COORD_IS_NEGATIVE
  Somehow, an ink point had a negative Y coord

CANNOT_DELETE_MORE_POINTS_THAN_EXIST
  For some strange reason, the code tried to delete more points from the
  input manager ink buffer than actually existed.

TOO_MANY_INK_POINTS
INK_DATA_EXCEEDED_BOUNDS_OF_BUFFER
  More ink points have been stored in the ink buffer than should be able
  to fit.

NO_INK_GSTATE
  MSG_IM_INK_REPLY was received but there was no inkGState for some reason

  One of the handlers for the ink collection finite state machine
  trashed AL...

  Indicates that the MSG_IM_INK_REPLY (with AX=TRUE) was received before
  any pointer window was set

IM_ERROR_BAD_PTR_IMAGE_VALUE
  Indicates that ImSetPtrImage was called with cx = 0, but dx was not set
  to a legal PtrImageValue.

IM_MEMLOCK_FAILURE
  Internal IM problem

IM_BAD_SETPTR_PARAMS
  Internal IM problem

IM_MONITOR_ALREADY_IN_MONITOR_CHAIN
  You have attempted to call ImAddMonitor passing a Monitor structure that
  is already in the monitor chain. You need to have called ImRemoveMonitor
  on the Monitor before you can add it back in again

GCN_BAD_USAGE_COUNT
  Result of NDBH_usageCount within a NotificationDataBlock having an
  abnormally large number in it.

  You passed both GCNLSF_RETURN_COUNT and GCNLSF_SET_STATUS to GCNListSend
  or GCNListSendToBlock, but the two are mutually exclusive, as the
  undisturbed status message handle is expected to be returned in cx.

GCN_UNRELOCATING_GCN_LIST_WITH_UNOWNED_OPTR
  Cannot unrelocate a GCN list with optrs that are owned by someone other
  than the owner of the GCN list itself.

FSD_ES_ISNT_SHARED_FSIR
  A routine was expecting FSInfoResource to have been locked shared and
  its segment loaded into ES.

OVS_BAD_HANDLER_TABLE
  The pointer passed to ObjVarScanData does not point to a valid
  VarDataHandlerTable or VarDataCHandlerTable.

OVS_SIZE_OF_VAR_DATA_ENTRIES_GREATER_THAN_VAR_DATA_AREA
  The variable data storage area of the object has been corrupted -- the
  sum of the sizes of the individual entries exceeds the total size of the
  variable data storage area.

  One common cause of this is that a class definition in a library
  uih/goh file at the time the app was compiled no longer matches the
  structure of the class in the library found at runtime.  This can
  happen if instance data was added to a library class, but the major
  protocol of the library wasn't increased (e.g., you're using an new
  SDK, but an old application).

OVS_CORRUPTED_VAR_DATA_ENTRY
  The VDE_entrySize field was 0, which is illegal.  This field must
  be at least (size VDE_entrySize + size VDE_dataType).

OVS_VAR_DATA_HANDLER_CHANGED_DATA_ENTRY
  A VarDataHandler or VarDataCHandler has changed the data entry it is
  handling.  This is illegal.  A VarDataHandler or VarDataCHandler is not
  allowed to change the data entry or add or remove data entries.

  A data entry size of 0 or 2 was passed to ObjVarAddDataEntry.
  ObjVarAddDataEntry is only used to add a data type with extra data.  If a
  data type with no extra data is to be added, use ObjVarAddDataType.

OVS_BAD_MSG_META_INITIALIZE_VAR_DATA_HANDLER
  MSG_META_INITIALIZE_VAR_DATA has been called on an object to get a
  particular variable data type created & initialized, and ds:ax has NOT
  been returned, as is required, pointing to the extra data of the new
  data entry (Should match return value of ObjVarFindData for the given
  data type)

OVS_VAR_DATA_HANDLER_ADDED_OR_REMOVED_DATA_ENTRY
  After calling a VarDataHandler or VarDataCHandler, the size of the vardata
  area for the object has changed.  It is not allowed for a handler to do
  anything which can cause this to happen, such as add or remove vardata
  entries to/from the current object.  For this reason, it is also not
  advisable to make any message calls from within a handler, unless it is
  known that no current or future handlers for that message would be adding/
  removing vardata entries to/from this object.

BAD_DETACH_MSG
  ObjInitDetach was called with AX != MSG_META_DETACH or
  MSG_META_APP_SHUTDOWN

TIMER_NOT_STOPPED_BEFORE_GEODE_EXITED
  A timer for the currently-exiting geode (ds:bx.HM_owner is the handle
  of the geode) remains on the timer list. All timers belonging to a geode

Back to index


Borland compiler error: Multiple declaration for 'optr'

SDK: ALL_GEOS:PUBLIC
ERROR:
Must take address of a memory location
Multiple declaration for 'optr'

SOLUTION:
Make sure any TO_APP_TARGET or similar destination in the object definition
of a controller is surrounded by parentheses. For example:

    GCI_output = (TO_APP_TARGET);


Using #define and @define correctly in GOC.

SDK: ALL_GEOS:PUBLIC
Q. I get a warning in the Borland compiler about the variable not
   being used in the following code:

    @define DEBUG
    ..
    Boolean error;

    error = FileWrite( .... );
    #ifdef DEBUG
    if ( error ) {
        ...
    }
    #endif

A. The problem is that the @define does not necessarily mean that
   DEBUG is #define'd. You need to do both an @define DEBUG and a
   #define DEBUG for the code to be compiled properly.

   Note:
   @define (and its ilk) are constructs of the Goc preprocessor
   #define (and its ilk) are constructs of the C compiler

   Generally you shouldn't try to mix and match these as was done
   in the example above.


Using the correct DOS code page for the demos.

SDK: ALL_GEOS:PUBLIC
Q. I'm trying to connect Swat to the demo and I get this output:

     WARNING(os2::OS2Init): NOT_MONITORING_JFT
     Death due to ILLEGAL_HANDLE
     CheckHandleLegal+32: MOV     AX, 26 (001ah)
     Execution died in patient geos:
     CheckHandleLegal+32: MOV     AX, 26 (001ah)
     *** No explanation available ***
     Interrupt 3: Breakpoint trap
     Stopped in FatalError, address 152eh:01bch
     CheckHandleLegal+32: MOV     AX, 26 (001ah)
     (geos:0) 2 =>

A. See the answer below.

Q. I'm using a European version of NT and using the Nokia 9000 NT SDK.
   When the demos are started they crash in the DOSInitUseCodePage()
   routine. I've narrowed down the problem to the different DOS code
   page (i.e. GEOS can't find the code page it wants). Is there an easy
   work-around for this?

A. You might have a command called "us" which switches the command
   prompt to the U.S. code page. If not, you can also try using the
   "mode con cp select=437" command. Using this command you will
   switch that command prompt to use the U.S. code page. There might
   be other code pages on your machine, which you can select to in
   a similar manner.


Borland compiler error: 'realloc: Illegal address (0x0)'

SDK: ALL_GEOS:PUBLIC
ERROR:
realloc: Illegal address (0x0)

SOLUTION:
This is a problem with the memory system. The only known solution
is to exit all applications and reset the system. You can also try
installing more memory in your computer.


Where are bitmap tool header files stored?

SDK: BETA:PUBLIC, 2.0:PUBLIC
Question:
I want to use the bitmap tools in my paint program. Where are they in the
header files?

Answer:
The bitmap tool controller is defined in /PCGEOS/INCLUDE/OBJECTS/BITMAPC.GOH.
The controller class is VisBitmapToolControlClass and this is used just like
GrObjToolControlClass.

You will have to edit the BITMAPC.GOH file before you
can use it. There is a struct defined in it that is also defined in
GROBJ.GOH, and if you're using both (which is highly likely), then you
should comment out the struct in BITMAPC.GOH called RectDWFixed. It is not
used in BITMAPC.GOH, so you won't affect anything (that I'm aware of).


Using Clipboard

SDK: ALL_GEOS:PUBLIC
Question:
I am trying to implement drag and drop into my program and I want to get
the name of the transfer item. However, when I use this code to do it, I get
a VM_HANDLE_NOT_IN_USE error:

    TransferBlockID       transferID; /* File/Block of item header. */
    MemHandle             itemMem;    /* Mem block for item header. */
    ClipboardItemHeader * itemPtr;    /* Pointer to item header.    */

    ClipboardEndQuickTransfer( PasteCommon( CIF_QUICK, textOD,
                               pself->GDI_fileHandle, &itemBlock ) );
    transferID = ClipboardGetQuickItemInfo();
    itemPtr = VMLock( FileFromTransferBlockID( transferID ),
                      BlockFromTransferBlockID( transferID ),
                      &itemMem );
       /*
        * Add the new item to the map block.
        */
    @call self::MSG_SB_DOCUMENT_ADD_ITEM( itemBlock, itemPtr );
    VMUnlock( itemMem );

Answer:
Here is how to do it.
(Note: PasteCommon comes from the CLIPSAMP sample app.)

    ClipboardQuickNotifyFlags retFlags; /* Returned from PasteCommon. */

    retFlags = PasteCommon( CIF_QUICK, textOD,
                            pself->GDI_fileHandle, &itemBlock );
    transferID = ClipboardGetQuickItemInfo();
    itemPtr = VMLock( FileFromTransferBlockID( transferID ),
                      BlockFromTransferBlockID( transferID ),
                      &itemMem );
       /*
        * Add the new item to the map block.
        */
    @call self::MSG_SB_DOCUMENT_ADD_ITEM( itemBlock, itemPtr );
    VMUnlock( itemMem );
    ClipboardEndQuickTransfer( retFlags );

This code fragment works because it is getting the information
from the item header BEFORE calling ClipboardEndQuickTransfer, which
destroys that header. In the "bad" fragment, we were calling for
a VM block that was just freed, and thus we got the error message.


Using SpellControlClass

SDK: ALL_GEOS:PUBLIC
Question:
I am trying to use the SpellChecker in my program, but when I test it I just
get a little box with a disabled button. Am I doing something wrong?

Answer:
The spell checker is disabled in the GEOS EC and NC versions because Geoworks
did not license the checker for the SDK versions of GEOS. It is only
available in the full GEOS version that is not part of the GEOS SDK. Also,
the SpellControl is one of those that is not to be put in a GenInteraction.
It should be a direct child of your Edit menu:

    @object GenInteractionClass MyEditMenu = {
        GI_comp = @MySpellControl;
        ...
    } /* MyEditMenu */

    @object SpellControlClass MySpellControl = {
        GI_visMoniker = "Check Spelling";
        GI_states = @default | GS_ENABLED; /* Must enable. */
        GCI_output = ( TO_APP_TARGET ); /* Go to text object. */
    } /* MySpellControl */


Find/Replace disabled problem

SDK: ALL_GEOS:PUBLIC
Question:
Why aren't the triggers in the Find/Replace controller enabled, even after I
type some text in the Find field?

Answer:
In the SearchReplaceControl you need to have the following attribute:

    ATTR_SEARCH_CONTROL_INTERACT_ONLY_WITH_TARGETED_TEXT_OBJECTS;

This will make the triggers become enabled at the appropriate time. Here is
a sample SearchReplaceControl object:

    @object GenInteractionClass MyEditMenu = {
        GI_comp = @MySearchReplaceControl;
        ...
    } /* MyEditMenu */

    @object SearchReplaceControlClass MySearchReplaceControl = {
        GI_visMoniker = "Find and Replace";
        GI_states = @default & ~GS_ENABLED;
        GII_visibility = GIV_DIALOG;
        ATTR_SEARCH_CONTROL_INTERACT_ONLY_WITH_TARGETED_TEXT_OBJECTS;
        ATTR_GEN_DESTINATION_CLASS = { (ClassStruct*)&MyTextClass };
    } /* MySearchReplaceControl */

This example is for text objects, which is generally what Find/Replace
is used for. You should only need to make minor modifications to make this
work with other kinds of objects.


@send dangers with pointer or temporary memory blocks

SDK: ALL_GEOS:PUBLIC
Question:
I get a BAD_DS error in Swat, and I think it's related to this code:

    {
        ...
        textOD = GeodeGetOptrNS( @FMVolumePathText );
        @send textOD::MSG_VIS_TEXT_REPLACE_ALL_PTR( pathBuffer,
                          LocalStringLength( pathBuffer ));
        MemFree( pathBufferHandle );
    }

Answer:
The problem is that the block you're using to send the string is
being freed before the text object sees it. If you change
@send to @call, the routine will work, since the caller will be
blocked until the text object is done with the memory block. After the text
object is done, then your routine will continue with the next line of code,
namely the MemFree.


Name of document on primary's title bar

SDK: ALL_GEOS:PUBLIC
Q: In my text editor, if I have two documents opened and I use the Window
menu to switch between them, the document display will draw twice, and the
name in the primary's title bar will be "No Document" instead of the
file's name.

A: Remove the GDCF_NAME_ON_PRIMARY flag in the GenDocumentControl's
GDCI_features instance. To do this, simply add the following line to your
GenDocumentControlClass object:

       GDCI_features = @default & ~GDCF_NAME_ON_PRIMARY;

The document name will still be on the primary's title bar, but it won't
do the "No Document" thing and the display will stop drawing twice after
the first time you switch to that document.

This is true only when you are using a DisplayControl object. If you are
not using a DisplayControl then leave the GDCF_NAME_ON_PRIMARY flag set.


Single-document-interface and GenDocumentGroup

SDK: ALL_GEOS:PUBLIC
Question:
I am setting up my application using the single-document interface and
I get this error in Swat:

     OBJ_BLOCK_DUPLICATE_NOT_DISCARDED

when I try to open a file.

Answer:
In the procedural model you must take out the GDGI_genDisplay instance
from the GenDocumentGroup object definition. If this field is non-null the
GenDocumentGroup will automatically try to duplicate the display object
resource. You don't want this to happen under the SDI model. You'll
generally just keep one copy of the object around that will interface with
the one document you have opened. Thus, making duplicates of resources is
not necessary, and in this case causes an error.

By the way, you won't need a GenDocumentGroup when using the procedural
document model. It is convenient to keep around if you're going to be
compiling both a MDI and SDI version of your app, but not necessary if
you're only doing SDI.


Error opening GEOS.INI file in GEOS.

SDK: ALL_GEOS:PUBLIC
Question:
When I try to open the GEOS.INI file in my text editor, an error dialog
appears saying I can't open the file. This I understand, but later on the
program crashes when I try to exit.

Answer:
The problem is in the GenDocument object that is created for the GEOS.INI
file. Even though a message appears saying you can't open the file, a
GenDocument object was created for it and, unfortunately, it remains in
memory, uninitialized, waiting to cause an error later on. To solve this, in
your MSG_GEN_DOCUMENT_OPEN handler, check for an error returned by the
superclass, then remove the GenDocument object. Here is a sample:

    @method ZTEDocumentClass, MSG_GEN_DOCUMENT_OPEN {
        word * error;   /* Error value from ReadDataFromFile. */
        optr   ourText; /* Pointer to current text object. */

           /*
            * Check if error occurred during open.
            * If so, cancel the open. Return error status.
            * (Don't try to do MSG_GEN_DESTROY, that gives an error.)
            */
        if ( @callsuper() ) {
            @send self::MSG_GEN_REMOVE( VUM_NOW, 0 );
            return( TRUE );
        }
        else {
               /*
                * Read in text file by calling read data function.
                * Prepare necessary parameters first.
                */
            pself = ObjDerefGen( oself );
            ourText = ConstructOptr( pself->ZTEDI_textHandle,
                                     OptrToChunk( @ZTEText) );
            if ( ReadDataFromFile( pself->GDI_fileHandle, ourText, error ) ) {
                *fileOrError = *error;
                return( TRUE );
            }
            else {
                return( FALSE );
            }
        }
    } /* MSG_GEN_DOCUMENT_OPEN */


Screen size with PT9000 emulator

SDK: BETA:PUBLIC, 2.0:PUBLIC
Question:
I tried using the PT9000 emulator software and the screen looks
garbled. How do I fix this?

Answer:
The PT9000 needs a 640x440 display. Thus, you need to use a VGA or
better display to run the PT9000 demo. So Hercules is out, but VGA and
SVGA will work fine.


Bullet demo Preferences crash

SDK: BETA:PUBLIC, 2.0:PUBLIC
Question:
When I run the Bullet (PT9000) demo, if I make any changes in the
Preferences, it locks up, saying the GEOS.INI file is corrupt.

Answer:
The problem is that the GEOS.INI file has garbage in it. To fix this,
use the MS-DOS editor, scroll down to the end of the file. There should be
some strange characters there. Delete those and save the file. The PT9000
emulator should run fine then.


Is there an @else?

SDK: ALL_GEOS:PUBLIC
Question:
The Concepts book mentions the @if and @endif directives, but no @else.
Is there one?

Answer:
Yes. For whatever reason, the @else didn't make it into the
documentation. It is available and works just like #else only it's used
with code that contains @ symbols (just as the @if directive is used with
code containing @ symbols).


Keyboard shortcuts in menus

SDK: ALL_GEOS:PUBLIC
Question:
The keyboard shortcuts in my program don't work. For instance, if I try
Ctrl-P, I get a beep instead of the Print panel.

Answer:
To fix this just add GA_KBD_SEARCH_PATH to the GI_attrs of the menus
containing shortcuts and all their parents, and their parent's parents,
and so on up to GenApplication. This allows GEOS to search those branches
of the object tree for the keyboard accelerators. It's generally a good
idea to add this attribute to as many objects as will ever need to receive a
shortcut, as well as all the parents of those objects. Here are classes
that have the attribute set automatically:

  GenDisplayClass
  GenDocumentClass
  GenDocumentControlClass
  GenEditControlClass
  GenViewControlClass
  JustificationControlClass
  PointSizeControlClass
  TextStyleControlClass


Multi-launchable apps and GeodeGetOptrNS

SDK: ALL_GEOS:PUBLIC
Question:
I get this error in my program:

  ILLEGAL_HANDLE

and it seems to be associated with this line:

  @send MyPrimary::MSG_META_DO_STUFF( @MyObject );

Answer:
The problem is that with multiple source-file programs that are compiled
is multi-launchable applications, you can't refer to objects in another
source file just by their name. You have to use the function
GeodeGetOptrNS to get a valid optr. Here is how to fix that line:

    optr primary;
    primary = GeodeGetOptrNS( @MyPrimary );
    @send primary::MSG_META_DO_STUFF( GeodeGetOptrNS( @MyObject ) );

You won't have to do this if you are compiling the program as a
single-launchable app. Also, you can't use GeodeGetOptrNS if the app is
single-launchable.


Mysterious object links

SDK: ALL_GEOS:PUBLIC
Q:
I added a couple of entries to a menu and now the contents of the menu
don't appear when I click on it. I looked that the source code, but I just
can't see what's wrong.

A:
Sometimes when you add items to a menu (or any other object tree) you
forget to change all the links. Here's a rough example:

    @object class object1 = {
        GI_comp = @object2,
                  @object3;
    }
    @object class object2 = {
    }
    @object class object3 = {
    }

Now say I want to add an object4 and group it with object3:
    @object class object1 = {
        GI_comp = @object2,
                  @object3;
    }
    @object class object2 = {
    }
    @object class objectgroup = {
        GI_comp = @object3,
                  @object4;
    }
    @object class object3 = {
    }
    @object class object4 = {
    }

Now I'm sure you can see something was forgotten, as this is a simple
example. I forgot to change the GI_comp field in object1, so it's pointing
to the wrong object. It should be like this:

    @object class object1 = {
        GI_comp = @object2,
                  @objectgroup;
    }

In a more complex object tree, spotting this error is difficult.


How to pass pointers to instance data to functions.

SDK: ALL_GEOS:PUBLIC
Q: I'm writing a method for a class and I want to call a function that
   will operate on the instance data of an object of that class. How can
   I pass pself to this function so it can modify the instance data of
   the object?

A: Although this kind of thing is discouraged because it violates most
   OOP paradigms, here is how you would do that:

    @method GenDocumentClass, MSG_GEN_DOCUMENT_MESSAGE {
        BadOOPFunc( pself );
    }
    void BadOOPFunc( GenDocumentInstance * objData ) {
        objData->GDI_fileHandle = NullHandle;
    }

   This is a weak example of why you might want to do this, but you can
   see that to pass pself to a function, simply make the function
   parameter a type of <ClassName>Instance. So for a class called
   "InvListClass", I would make the function parameter type
   "InvListInstance". Be sure to include the * and -> since you are
   passing a struct by reference.


Can't mix Vis and Gen objects

SDK: ALL_GEOS:PUBLIC
ERROR:
CORRUPT_LINKAGE (This happens when I start my program.)

SOLUTION:
What's wrong is you probably have a VisClass object as a child
of a GenClass object. VisClass objects don't have GI_comp fields, thus the
generic tree has a "hole" in it where the VisClass object is. To remedy
the problem, make sure the VisClass is the on ly child of the GenClass
object. Usually you will not have Vis objects under Gen objects, since
technically it can't be done.


Borland compiler error

SDK: ALL_GEOS:PUBLIC
Q:
I have the following code fragment in my global.goh and I get a Goc
error saying "Open conditional...".

    @extern object @SomeObject;
    @ifdef ZOOMER
    @extern object @AnotherObject;
    @endif
    @extern object @MyOtherObject;

A:
The problem there is Goc doesn't like it when the @ifdef and @endif are
not against the left margin. Fix it be bringing the @ifdef and @endif to
the very left side of the document. For example:

    @extern object @SomeObject;
@ifdef ZOOMER
    @extern object @AnotherObject;
@endif
    @extern object @MyOtherObject;


GOC error

SDK: ALL_GEOS:PUBLIC
ERROR:
End of file in resource declaration...

SOLUTION:
Put a semicolon (;) at the end of the @chunk declarations. Strange, but
that fixes the error.


Using the FilterListClass on the Nokia 9000.

SDK: N9000C:PUBLIC
Q. I need to set up a search box.  I found two classes in foam.goh
   that I thought I can use.  I created a search box using
   FilterTextClass and I changed my GenDynamicList to FilterList.
   Does the procedure begin like this?:

     I have to create a filter function that selects those business
     cards that match when user types in search box.

A. Correct. The function should retrieve the current text from
   the FilterText object, and perform the search.

Q. Continued...
   Then I have to send a message MSG_FILTER_LIST_INITIALIZE to my list in
   order to get update. Is the parameter "filter" a chunk array of items
   I want to display?

A. The "filter" is a simple (C-style) array of item ID's. For example:

    word searchResult[10];
    word searchResultLength;

    ... perform search, putting results in searchResult

    @call ListObj::MSG_FILTER_LIST_INITIALIZE(
        searchResultLength,
        searchResult );

Q. Continued...
   This causes my query message to be called. Here comes the problem:
   How can I find out the actual item number the list is going to show.

A. The item number passed to your method handler in the query message
   is the actual item number.

   If the filter has not been set, or has been removed (by passing NULL
   to MSG_FILTER_LIST_INITIALIZE), then the ID's passed & returned by
   filter list API are the physical item numbers, exactly like
   a normal GenDynamicList.

Q. Let's say I have five cards in the folder. Number two matches. My
   query message gives me parameters: item and list. Do I have to call
   MSG_FILTER_LIST_MAP_APP_TO_PHYSICAL?

A. You do not need to do this. The translation between the physical
   item number and the application's item number is automatic. If your
   application's ID for number two were '345', then the item number
   that the query message passes to your method handler will be '345'.

   This also applies to any of the other MSG_FILTER_LIST_* messages
   that have item ID parameters or return values - If
   MSG_FILTER_LIST_INITIALZE has been used to set a "filter", then the
   Item ID's that the application specified in that filter are used.

   The list's status and apply messages also do this automatically.

   It should never be necessary to use the MSG_FILTER_LIST_MAP_*
   messages to manually perform translations between physical and app
   ID's.

   Some other "tricks" you can employ when using FilterListClass:

   If an item matches more than once and you want to display
   it multiple times (once for each match), but be able to
   distinguish between instances of the item, when you build
   the filter array, store the actual item number in the lower bits
   of the ID word, and the character position of the match in the upper bits.
   Example:

    Search for 'Gr'
    Item #3: greg gray
    Match #0: GReg gray (position 0)
    Match #1: greg GRay (position 5)

    the filter list would contain:
       0 << 8 | 3,
       5 << 8 | 3

   The moniker query method could then fetch the actual item by looking
   at only the lower byte of the ID, and know which portion of the
   string to underline by looking at the upper byte (the length of the
   match would be stored in some global variable or instance data, and
   set at the time the search was performed).


How to enable help editor in GeoWrite, and contexts not mentioned that need to be supported.

SDK: ALL_GEOS:PUBLIC
The best editor I've found for making help files for geodes is GeoWrite,
especially after it's been updated by the Bindery upgrade. Once GeoWrite
has been updated by Bindery, it has the "Clear All Hyperlinks" and "Clear
All Contexts" which are very useful features. But even so, if you only
have GeoWrite you will be able to create and maintain help files. I
recommend against using Bindery itself, since the help files that in
generates cause crashes on the OmniGo when you use text styles.

Once you've got GeoWrite as an editor, you'll have to turn on the "Help
Editor" feature, if you haven't done so already. To do this, look in the
GEOS.INI file and find the [configure] section. If there isn't one, create
it by typing "[configure]" on a lin e by itself. Then add the line
"helpEditor=true" right below "[configure]". Now boot GEOS and start
GeoWrite. Click on the Options menu and select "Change User Level", then
click on the Fine Tune button. At the end of the list of options you
should see "H elp Editor". Turn this feature on, if it isn't already.
Click on Ok, then click on the Ok in the "Change User Level" dialog, and
now you should see a "Help Editor" menu in GeoWrite. Don't forget to
select "Save Configuration" in the Options menu.

Now you can begin writing the help file. The Help Object Library chapter
in the Objects Reference will guide you through creating a help file. Now
on to more complex issues.

You should know that there are many contexts in GEOS that are not
mentioned anywhere. For instance, if you create a geode that has a
PrintControl object in it, you will have a "dbPrint" context in that
PrintControl. That means when the user of your progra m brings up the
Print box, they can click on the ? button and get help on printing.
However, GEOS does not provide the dbPrint help context, you have to. That
means you have to define a context somewhere in your help file with the
name "dbPrint".

There's more of these secret contexts. Most I've found are related to
using the GenDocumentControl. Here is a list of them, with a brief
description:

dbDCBig - The main GenDocumentControl dialog, with the New, Open, Template, Exit.
dbDCOpen - The dialog for opening a file.
dbDCSaveAs - The dialog for saving a file under a new name.
dbDCCopy - Dialog for copying the document to another directory.
dbDCGetPass - The dialog for getting a password on a locked document.
dbDCSetPass - The dialog for setting the password to lock a document.
dbDCRename - Dialog for renaming the document.
dbDCSetType - The dialog for setting the document type.


How to connect to the Internet with the N9000 emulator.

SDK: N9000C:PUBLIC
Setting up internet service (access points)
-------------------------------------------
If you need to use Internet apps (except Terminal), you need to configure
access points. Access points are the configuration information when
dialing up your internet service provider (ISP).

The very basic things you need to know about your ISP are:

- Phone number. Make sure this is the PPP phone number, not just a
  regular terminal phone number. GEOS does not support manual PPP login
  nor dial-back service.

- Username to login

- Password. You can put it in when defining access point. It will be saved
  to .INI file. If you do not want it to be saved, select "Prompt password"
  to "Yes" and you will be prompted for password every time you login to PPP.

- Modem initialisation (optional). Some special modem settings in order to
  connect to particular internet service providers. This field is usuually
  left blank.

- IP address, Default gateway and Network mask (optional). They are not
  really used. You can leave them blank.

- Primary nameserver. If you want to resolve address like "geoworks.com",
  you have to put this in. Bascially, this is the address of the DNS server
  that looks up your unresolved address.

- Secondary nameserver (optional). This is used when primary nameserver
  fails to resolve the address.

These access points are what you would choose from when prompted for
"Internet Access" from the individual internet application settings.

Running Internet applications on PC Demo
----------------------------------------
Equipment:
- Modem. If you want to fax, you need a Class 1 compatible fax/modem
  (Class 2 is not good enough).

- Serial cable to connect modem and PC (if external modem).

Notes:
1. The port used by PC is determined by

       [faxout]
       comPort = 0

   in .ini file. In the above example, it is using COM port 1. To use com
   port 2, substitute 0 with 2. The values are actually SerialPortNum enum.
   Be advised that COM3 is usually used by IR, although you can tweak
   IR to use another port.

2. You may also need to set this in .INI file to pass Security library's
   check:

       [security]
       override = true

   If you add this setting after demo is booted up, please restart the
   demo so that this INI setting is re-read in Security library.

3. If your modem lights blink or if it gives dial sounds when you try to
   connect, that means you have successfully opened the port.

Frequently Asked Questions (FAQ)
--------------------------------
Q. When I connect using the emulator, I get an error message "Phone
   turned off or not ready. Check phone and try again."

A. Add this to the .INI file:

   [security]
   override = true

   This tells Security library to skip the check with CMT. If you
   add or change this line while running the demo, please restart
   the demo.

Q. How can I use a particular COM port on PC demo?

A. Add/Change this in the .INI file:

   [faxout]
   comPort = 0

   Put 0 for COM1, 2 for COM2, 4 for COM3, and 6 for COM4.

Q. When I set Internet->Settings->Modem Initialisation to Autobauding or
   Fixed 9600 b/s, it does not connect.

A. Some modems like Macronix do not support the strings for these modem
   strings, "ATS35=6" and "ATS35=7". There is no way out but to make your
   own custom init string.

Q. Why do I get a note, "Internet connectivity problem: Data/Fax calls
   can't be originated during other active calls."?

A. This is because you cannot open the COM port successfully. You should
   make sure:
     1. Your modem is connected at the correct COM port.

     2. COM3 in Responder is generally used for IR. There may be conflicts.

     3. You have the right settings in [faxout] and [security] in .INI
        described above.

     4. You have a Class 1 compatible fax modem if you want to fax (Class 2
        is not good enough.)

     5. Your machine has good COM ports. It has been reported that some HP
        Vectra's have bad physical COM ports. You can test yours by using
        other software like Windows Terminal or Netscape.


Control key and mouse press

SDK: ALL_GEOS:PUBLIC
Q:
How do I detect when the user is holding the Control key and clicking the
mouse button at the same time? Also, what about the Shift keys?

A:
When you receive a MSG_META_START_SELECT, you will get a parameter called
inputState. The high byte of this word parameter contains data indicating
the special mode of the mouse click. For a normal mouse click, the
following bits are set:

    UIFA_SELECT | UIFA_IN

For a Control-click (holding Control key while clicking mouse):
    UIFA_SELECT | UIFA_PREF_A | UIFA_IN

For a Shift-click (holding Shift key while clicking mouse):
    UIFA_SELECT | UIFA_CONSTRAIN | UIFA_PREF_B | UIFA_IN

So, to detect when the user is holding down the Control key and clicking
the mouse at the same time, do this in your MSG_META_START_SELECT method:

    if ( GET_UI_FUNCTIONS_ACTIVE( inputState ) & UIFA_PREF_A ) {
        /* User clicking while pressing Control */
    }

For detecting when the user is pressing the Shift key and clicking:
    if ( GET_UI_FUNCTIONS_ACTIVE( inputState ) & UIFA_PREF_B ) {
        /* User clicking while holding Shift key. */
    }


Libraries included on Zoomer

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q:
I'm developing an application for the Zoomer platform. I was testing it on
the GEOS EC version and it worked fine. But, when I try to run the program
from the Zoomer version of GEOS it says "Missing library or component."
What's wrong?

A:
The problem is there are libraries missing from the Zoomer. Here is a list
of all the missing libraries on the Zoomer:
  Bitmap  Chart   Convert
  DIB     FFile   FileStream
  Game    GrObj   MSMFile
  Saver   Spell   Spline
  SSheet  SSMeta


Content as a child of another content

SDK: ALL_GEOS:PUBLIC
Q:
I've got a VisContent object as a child of a GenDocument. The GenDocument
is acting as the content of a GenView. For some weird reason, the
MSG_VIS_DRAW is not reaching the VisContent. Can you tell me why?

A:
You can't have a VisContent under a GenDocument. This is because
GenDocuments are subclasses of GenContent, and GenContent resolves into a
VisContent at run-time. And, you can't have a VisContent under another
VisContent and expect things to work. Change the VisContent to a VisComp
and everything will work fine.


Ordering static object instance data

SDK: ALL_GEOS:PUBLIC
When declaring static objects in a GOC program, it is a good idea to set
the values of the instance data in order of the class hierarchy. For
example, if you're declaring an object of GenControlClass, you would set
the GenClass instance fields first, then set the GenInteractionClass
fields you want, then finally set the GenControlclass fields.
Here is an example:

    @object GenControlClass Controller = {
        GI_visMoniker = "My Controller";
        GI_comp = @AddButton,
                  @CancelButton;  /* Not defined in this sample. */
        GII_visibility = GIV_DIALOG;
        GII_type = GIT_PROPERTIES;
        GCI_output = process;
    }

One reason for setting the instance data in this order is to force you to
look at each superclass and its instance data. By doing this, you are
less likely to forget to set a value in one of the instance fields.


How to un/relocate objects and their class pointers.

SDK: ALL_GEOS:PUBLIC
If you're storing objects in a VM file and want to perform the object
relocation manually (not something I recommend, since VM manager can do
this for you), this article will give you a summary of what steps to take.
It is assumed you've read the article titled "Using
ObjDoRelocation and ObjDoUnRelocation."

To save objects to a VM file and do the unrelocation yourself, first you
must unrelocate the class pointer of the object. This is done by
dereferencing the optr to the object chunk. Unrelocate the first dword of
the object data, the class pointer, using ObjDoUnRelocation with the
relocation type RELOC_RELOC_ENTRY_POINT. Save the relocated class pointer
somewhere (not where it is now, somewhere else; the object needs a valid
class pointer for just a little bit longer). Then unrelocate the optr to
the object, so you can save it to the file.

Later when you read in the object from file, perform the relocation on the
optr of the object, then using that optr dereference a pointer to the
object chunk and relocate the class pointer, using the "unrelocated" class
pointer saved earlier.


How to use the ObjDoRelocation() and ObjDoUnRelocation() functions to relocate and unrelocate resources.

SDK: ALL_GEOS:PUBLIC
Quoting from the description for the ObjDoUnRelocation function in the
Routines book: "This routine unrelocates a given word or dword. It
translates a handle, a segment address, or an entry point back into a
resource ID. The translation done is the exact reverse of that done by
ObjDoRelocation(). See that routine (above) for more information."

So what exactly does that mean? I think of this as taking a handle or optr
to a resource and turning it into a special kind of identifier. This
identifier is simply a resource "type" combined with an index. This
information is used later for recreating a handle or optr by calling
ObjDoRelocation. The handle or optr created may not be the same value it
was before, but it will refer to the same resource as before.

This mechanism is used whenever the system is saving objects or blocks to
a file. The system will take the optr or handle of the resource,
unrelocate it, and save it. Later when the system wants to load the
resource from the file it will "relocate" the resource ID back into an
optr or handle.

If we didn't unrelocate the optr or handle, we'd have a problem later on
when the resource is read into memory from the file. The handle that we
saved earlier may now be in use by another program, and thus we cannot use
it. So rather than cause conflicts between resources, we unrelocate the
optr or handle, save it, then later relocate it into a new optr or handle.
This new optr or handle is pointing to our resource we're reading in from
disk, and can be used without worry of conflict.

For an example of where you might use these two functions, consider you
have an object. This object is saved to a VM file. Within this object you
have instance data, say an optr to a chunk array, which is also saved in
the VM file. This optr is valid when you first use the object and chunk
array. However, when you later reopen the VM file and read the object and
chunk array back into memory, the optr stored in the object may not be
valid anymore. You will have to first unrelocate the optr before saving
the object to file. Then when you open the file later, relocate the "optr"
(which is really a resource ID) back into a valid optr. Here is an
example:

    MemHandle mh;

    mh = OptrToHandle( pself->MOI_chunk );
    ObjDoUnRelocation( RELOC_RELOC_HANDLE,
                       OptrToHandle( oself ),
                       (Handle*)&mh,
                       (word*)&mh );
    pself->MOI_chunk = ConstructOptr( mh, OptrToChunk( MOI_chunk ) );
    Mark object dirty, so it will be saved by VM manager.
    Save object to file.

    ... (program exits, later relaunches)...

    Object is read from file.
    mh = OptrToHandle( pself->MOI_chunk );
    ObjDoRelocation( RELOC_RELOC_HANDLE,
                     OptrToHandle( oself ),
                     (word*)&mh,
                     (Handle*)&mh );
    pself->MOI_chunk = ConstructOptr( mh, OptrToChunk( MOI_chunk ) );

We use OptrToHandle( oself ) for the second parameter because that is the
handle of the block containing the relocation. In other words, the object
block. ObjDo[Un]Relocation uses this for optimization purposes when
relocating something within the same block as the object.

For relocating optrs to objects, see the article "Relocating Objects".


Pmake needs more memory.

SDK: ALL_GEOS:PUBLIC
Q. When I run pmake, it starts to compile my code, and in a minute or
   so it stops and gives me an error, but it doesn't say what error,
   just "Error".

A. You might want to increase the memory available to the compiler.
   It needs a lot of memory, probably 6Mb or more. Your machine must
   have 8Mb to use pmake, and if you're running it with a SmartDrv disk
   cache, you'll probably need even more memory. Under Windows you can
   create a permanent swap file to help provide memory for pmake.

   Windows 95 handles memory correctly with DOS apps, so this does not
   seem to be a problem if you're running the SDK from '95.

   Not all DOS's are created equal. Even on a system with 32+MB of
   RAM and running DR-DOS 6 you could get this error. The same system
   running Novell DOS 7 works fine. This appears to be a problem with
   the way XMS is handled by the DOS.


Loading saved point size from GEOS.INI

SDK: ALL_GEOS:PUBLIC
Question:
I have a PointSizeControl object that works to set the size of a VisText
object. I am trying to have the point size saved when the program exits
and then load that point size when the program starts. I have the size
information saved to the GEOS.INI file, and that seems to be working fine.
However, when the program starts, it does all the message sending, but the
point size control is set to 8 point, instead of whatever it's supposed to
be.

Answer:
The problem here is that the PointSizeControl has this field:

    GCI_output = ( TO_APP_TARGET );

If your text object does not have the target when the
MSG_PSC_SET_POINT_SIZE is sent then that size change will be sent to the
wrong place. To remedy this, set the GCI_output to the text object, like
this:

    GCI_output = @MyTextObject;

If you can't do this (eg., because the text object is duplicated by the
document control) then make sure the text object receives the
MSG_META_GRAB_TARGET_EXCL message before you send the
MSG_PSC_SET_POINT_SIZE message.


Breakpoints in Swat and detaching.

SDK: ALL_GEOS:PUBLIC
Question:
Sometimes when I detach in Swat, then reattach, I get the 'Geos exited'
message and a prompt, but I can't type anything. I then have to end the
task in Windows, or reset the machine if I'm running Swat from the DOS
prompt.

Answer:
The problem here is most likely that you are using software breaks. To
solve this, don't do anything with the breaks while you are detached from
the target computer. Here's what you shouldn't do:

     det
     brk delete 5-
     att

This will cause Swat to lockup. Instead, do this:

     brk delete 5-
     det
     att

The other problem is that if you leave Swat doing nothing while it's
detached, it will do the garbage collection. This seems to cause the
'Geos exited' error. If it does the garbage collection while it's
attached, that seems to be okay.


Name of a geode.

SDK: ALL_GEOS:PUBLIC
Question:
I wrote a new program, and later decided to change the name of it to
something else. Now when I use Swat and try to send the program to the
target computer, Swat tells me it can't find the program. What can I do?

Answer:
Search for every instance of the old name and make sure to change it to
the new name. To simplify things, make the name of the directory, name of
the .GP file, and the permanent name in the .GP file all the same. The
only name that should be different is the longname in the .GP file.


Swat can't read tcl module.

SDK: ALL_GEOS:PUBLIC
Q. I get the following error when trying to run Swat on the SDK for
   GEOS 2.0 (Ensemble, Zoomer):

   Couldn't read File module error-handling code (E:\PCGEOS\TCL\file-err.tcl)

A. Check your swat.cfg file in the BIN directory. There should be a
   line like this:

   syslib    e:\pcgeos\tcl

   Change that line to the appropriate location, or alternatively, map
   a drive E: that goes to the directory containing "pcgeos\tcl".


How to dismiss a dialog after intercepting MSG_GEN_GUP_INTERACTION_COMMAND.

SDK: ALL_GEOS:PUBLIC
Say you've created a subclass of GenInteractionClass and you are using
it to intercept the MSG_GEN_GUP_INTERACTION_COMMAND. In your method you
handled the case where the InteractionCommand parameter equals something
like IC_APPLY. After you've processed the IC_APPLY you want to make the
dialog disappear. To do this simply change the "command" parameter to be
IC_DISMISS and then call the superclass. Here is an example:

@method MyInteractionClass, MSG_GEN_GUP_INTERACTION_COMMAND
{

      /*
       * See if we want to handle this command.
       */
    if ( IC_APPLY == command ) {
        /*
         * Do our thing here.
         */

          /*
           * Now we change the command to be "dismiss". When we call
           * the superclass below the dialog will close itself.
           */
        command = IC_DISMISS;
    }

      /*
       * Call the superclass to handle the command, whether it
       * be IC_DISMISS or something else.
       */
    return( @callsuper() );
}


Swat error: ILLEGAL_RESOURCE

SDK: ALL_GEOS:PUBLIC
Question:
I get an ILLEGAL_RESOURCE error in my program. Why is that?

Answer:
If you're using GeodeGetOptrNS, make sure your program is
multi-launchable. In other words, take out the "single" in the "type" line
of your .GP file. This is how GeodeGetOptrNS works; you can't avoid
making the program multi-launchable.

Another way this error could occur is if you forgot to create a LOCAL.MK
file with the LINK_FLAGS line in it. You'll need this with multi-source
apps when you use GeodeGetOptrNS. Here is a sample:

    # Pass flag for (somewhat) unsafe resource
    # fixups for multi-launchability.
    LINKFLAGS += -r
    #include <$(SYSMAKEFILE)>

You need that fourth line so that the system makefile is included during
the compile.

See also: Multi-Source File Goc Applications


How to connect Swat to an actual OmniGo device.

SDK: OMNIGO:PUBLIC
Question:
How can I debug my application on an actual OmniGo device?

Answer:
There is a batch file called ss1 which will start the Swat stub at
9600 baud. You can start the Swat stub in one of two ways:

   1. Remove "geos" from the last line of the OmniGo's autoexec.bat file.
      Rebooting with the new autoexec file will land you at the DOS prompt
      (which is hidden behind the splash screen). From here you can
      type "ss1" to launch the Swat stub or "geos" to continue the
      OmniGo's normal startup.

or

   2. To start the Swat stub during OmniGo startup:
    1) Reboot the OmniGo by pressing SHIFT-ON-NEXT keys.

    2) Hold down the 'c' key until a dialog box comes up. It will
           ask "Discard all data?"

    3) Press 'n' (to keep data).

    4) Wait about three seconds.

    5) Hit CTRL-C. This will break out of autoexec.bat. The splash
           screen is still up (and will be throughout the DOS session).
           Type 'y' to cancel execution of the autoexec.bat process.

    6) Type the following:
        mcb
        cd geoworks
        ss1
       This will put you in b:\geoworks and run ss1.

   The only catch is, on boot-up, the power driver will turn off the
   on-board serial port to save power. To get around this, after you
   attach with Swat, you need to do the following:

   1. Hit CTRL-C to halt Swat right after the line:
      Looking for "geos    kern"...C:/OMNIGO/LIBRARY/KERNEL/OMNI100.SYM

   2. In DOS or whatever File Manager you're using, delete the file
      \OMNIGO\DRIVER\POWER\JEDI\JPWR.GYM
      Make a copy of
      \OMNIGO\DRIVER\POWER\JEDI\JPWR.SYM and name it JPWR.GYM.
      You'll only have to do this step once.

   3. Type "spawn jpwr".

   4. Type "continue".

   5. When Swat halts in jpwr, type "assign serialPowerStatus 3" and
      then "continue".

   This will cause the power driver to leave the serial port on, and
   therefore you can continue to debug.

Another thing you can try is downloading the "OmniGo DOS Mode" text
driver by Jan Sedlak. Although this is not a Geoworks supported
program, it does make debugging on the OmniGo significantly easier.
Here are the basic steps:

  1. Find the DOS text mode driver by Jan Sedlak (or an equivalent one).
     You can get one from my web site, in the Software page. Use your
     web browser to go to http://members.aol.com/nfiedler/
  2. Use Geoworks Installer to install the DOS text mode driver on your
     OmniGo. Installer is now known as Install Manager. You can find
     Installer at http://members.aol.com/nfiedler/software.html
  3. Reboot the OmniGo using the SHIFT-ON-NEXT keys.
  4. At the DOS prompt, perform step 6 of the procedure outlined above.
     Don't forget you'll have to deal with JPWR as mentioned above.

When you need to enter GEOS from the DOS prompt, type "geos".


Text controllers and read-only text objects

SDK: ALL_GEOS:PUBLIC
Question:
I can't get the font and size controllers to work with a GenText in
a small app I'm working on. The GenText is just a display text, so its
GI_attrs field is set GA_READ_ONLY.

Answer:
Remove the GA_READ_ONLY. This makes the FontControl and PointSizeControl
disabled because they can't change a read-only text object.


Line number of cursor in text object.

SDK: ALL_GEOS:PUBLIC
Question:
How do I get the line number that a cursor is on in a text object?

Answer:
Use this code snippet, substituting "MyText" for the optr to the text
object you are interested in:

    dword         lineNum, position;
    VisTextRange  range;

      /* Get the current cursor position. */
    @call MyText::MSG_VIS_TEXT_GET_SELECTION_RANGE( &range );

      /* If no selection, then this is the cursor position. */
    position = range.VTR_start;

      /* I found this message in vtextc.goh */
       * Add the 1 to get first line to be number one
       * instead of zero. */
    lineNum = 1 + ( @call MyText::
                        MSG_VIS_TEXT_GET_LINE_FROM_OFFSET( position ) );

Thanks to John F. Howard, a GeoRep and ISV, for this answer.


Uncommon key sequences to watch for in text objects.

SDK: N9000C:PUBLIC
Q. I want to have a read-only text object that lets the user select
   text. The field is also only single line and the text is longer
   than the field is wide, so scrolling is needed. What I've done
   is created a GenText object that is not set read-only but instead
   uses a VisTextCustomFilterData array to block all characters.
   This works fine, but certain keypresses still make it through:

   1) Control-T seems to redraw the whole screen and focus is moved
      to top left.

   2) Control-x, control-backspace and control-delete clear the
      text in currently selected text item.

   3) Control-shift-m brings up a dialog "No menu available".

A. You're going to have to subclass MSG_META_KBD_CHAR for the text
   class and capture those key sequences.


Real-time timers

SDK: ALL_GEOS:PUBLIC
Question:
How do I set real-time timers using TimerStart?

Answer:
TIMER_EVENT_REAL_TIME starts a real-time clock on the device that will
send a message at some particular date and time. You pass the date that
the event should happen in the "ticks" parameter and the time of day in
the "interval" parameter of TimerStart.

The date is stored in a compressed format that is word-sized. The year
(since 1980) is in the high 7 bits, the month is in the next 4 bits, and
the day is in the low 5-bits.

The hour is stored in the high byte of "interval" and the minute is stored
in the low byte of "interval.

For example, if I wanted to have a wakeup notification sent on March 5,
1996 at 8:05am, I would set up the "ticks" and "interval" parameter as
follows:

    ticks = 0x2065;
     (year  = 1996-1980 = 16 = 0x10,  0x10 << 9 = 0x2000
      month = 3,                      0x03 << 5 = 0x0060
      day   = 5,                      0x05 << 0 = 0x0005)

    interval = 0x0805;

By the way, another option is to use the Real-Time Clock Manager library
of GEOS. Search on RTCM to find the documentation on the RTCM functions.
Also, check out the OmniGo Alarm Clock program, available from
http://members.aol.com/nfiedler/software.html, which uses RTCM and comes
with the source code.


Setting the undo context.

SDK: ALL_GEOS:PUBLIC
Question:
I recently changed my program from multiple-document interface to
single-document interface. When I open a document, everything works fine.
When I close that document and open a second one, the Undo no longer
works. What gives? (I'm using a text object for the document.)

Answer:
For some reason, the text object is being told to not send undo
messages to the EditControl. To fix this, in your
MSG_META_DOC_OUTPUT_ATTACH_UI_TO_DOCUMENT method (or wherever is
appropriate for your program), send the message

    @send textObj::MSG_VIS_TEXT_SET_FEATURES( VTF_ALLOW_UNDO, 0 );

This will make the text object turn on its undo support.


Optimizing your Application's State Files

SDK: ALL_GEOS:PUBLIC
When an application saves to state, it is basically saving the
instance data of any objects in your application that have been
modified.  This can be quite a lot if you have a UI intensive
application.  The problem with saving much of this instance data
to state is that it will not be needed when restoring from state.
Furthermore, it will take up disk space on a device with limited
space.

REDUCING STATE FILE
===================
There are several ways to can eliminate or reduce the size of a
state file:

To prevent the application from creating a state file, subclass
MSG_GEN_PROCESS_CREATE_NEW_STATE_FILE and return NullHandle.
If you need to maintain a minimal amount of state information,
you can store that information in the INI file.

To reduce the size of a state file, you can prevent entire
resources from being saved to state or single objects within a
resource from being saved to state.

* for resources, the notDetachable flag will prevent the resource
  from being saved to the state file.
    @start SomeResource, notDetachable;

* for single objects, the ignoreDirty flag will prevent that
  object from being save do to state.
    @object SomeClass SomeObject = ignoreDirty {

SAVING SPECIALIZED DATA
=======================
Geos allows you to save an extra block of data in the state file.
You do this in MSG_GEN_PROCESS_CLOSE_APPLICATION by simply
returning the extra block from the message. This extra block's
handle will be given to you in MSG_GEN_PROCESS_OPEN_APPLICATION
when the application is restarted.

DEBUGGING STATE SAVING
======================
To help you in optimizing the information you allow to be saved to
state, use "showcalls -V". It will show you the loading and unloading
of resources during save-to-state and restore-from-state.


What happens to CPU when N9000C's lid get's closed?

SDK: N9000C:PUBLIC
Q. How can I receive notification of the lid closing on the Nokia
   9000 Communicator? I want to update a VM file before the CPU
   shuts down.

A. To receive notification that the lid is closed an application
   should register on the GCN list GCNSLT_RESPONDER_NOTIFICATIONS.
   It should watch for MSG_META_NOTIFY with a notificationType of
   GWNT_RESPONDER_NOTIFICATION, manufID of MANUFACTURER_ID_GEOWORKS,
   and data equal to RNT_LID_CLOSED. (ResponderNotificationType is
   defined in CInclude\Internal\respondr.goh)

   When the lid closes, you have 30 seconds before the CPU turns off
   --additionally, the CPU will not turn off until it enters the idle
   loop. As long as your code is executing, the CPU will remain running.


Compiling GOC libraries that @classdecl classes

SDK: ALL_GEOS:PUBLIC
When compiling a library that defines and declares its own class(es),
you must pass the -L  to GOC.  If you don't do this, you will
see compile errors on those files that @classdecl the new class(es).

To pass -L to GOC, you'll have to define a local.mk file in your
library directory, like this:

    GOCFLAGS	+= -L

    #include <$(SYSMAKEFILE)>

"libname" is the name of the library from the .gp file.


How to add HINTs and ATTRs

SDK: ALL_GEOS:PUBLIC
You can dynamically add and remove HINTs and ATTRs to generic objects.
MSG_GEN_ADD_GEOMETRY_HINT or MSG_META_ADD_VAR_DATA are used to add;
MSG_GEN_REMOVE_GEOMETRY_HINT or MSG_META_DELETE_VAR_DATA are used to
remove the hint from the object.

MSG_META_ADD_VAR_DATA and MSG_META_DELETE_VAR_DATA are the more generic
message.  That is, they can properly add or remove any hint or attribute.
But they do not invalidate the object, so it will not redraw with the
new hint/attr settings.  You can send MSG_VIS_INVALIDATE to the object
to get it to redraw with the new hint/attr.

MSG_GEN_ADD_GEOMETRY_HINT and MSG_GEN_REMOVE_GEOMETRY_HINT are used
specifically for hints and attributes that would effect the object's
geometry.  There is a list of hints and attributes that this message
can handle in genC.def (in the Include directory of any Geos SDK).
The messages will automatically cause the object's geometry to
recalculate.  If you use these messages to add a hint or attribute that
they don't know about, they may try to add it (not guaranteed, though),
but will not properly add any extra data that the hint/attr needs.

Here are two examples of how you add attributes to an object:

-----------------

@chunk TCHAR  helpContext[] = _TEXT("myHelp");

...

{
   TCHAR *ptrHelpContext;

   /* lock the helpContext chunk and get its pointer */
   MemLock(OptrToHandle(@helpContext));
   ptrHelpContext = LMemDeref(@helpContext);

   /* add the atttribute */
   @call ::MSG_META_ADD_VAR_DATA(
        (VDF_SAVE_TO_STATE | ATTR_GEN_HELP_CONTEXT),
        strlen(ptrHelpContext),
        ptrHelpContext);

   /* unlock the block that contains helpContext */
   MemUnlock(OptrToHandle(@helpContext));
}

-----------------

@chunk VisTextCustomFilterData FilterArray[] = {
        {C_SPACE, 0xffff} /* this filters out all text */
};

/* Then write a method that sends MSG_META_ADD_VAR_DATA like this: */
{
   ChunkHandle filterChunk[1];

   filterChunk[0] = @FilterArray;

   @call GetChildHandle(oself), textObj::MSG_META_ADD_VAR_DATA(
        (VDF_SAVE_TO_STATE|ATTR_VIS_TEXT_CUSTOM_FILTER),
        sizeof(ChunkHandle),
        filterChunk);
}


The structure of GEODEs (both disk and memory).

SDK: ALL_GEOS:PUBLIC
This file contains the specification and technical design for the
structure of GEODEs, both on disk and in memory.

The original file is located in /s/p/Spec/geode.doc and was last updated
$Id: geode.doc,v 1.25 89/09/28 19:24:29 tony Exp $

****************************************************************************

geodeContents:
geodeGoals		- Goals and objectives for GEODEs
geodeOverview		- Overview of GEODEs
geodeDisk		- GEODE structure on disk
geodeCoreBlock		- Structure of a GEODE's core block
geodeLibraries		- Implementation of libraries
geodeRelocations	- Implementation of relocation tables
geodeResources		- Implementation of resources
geodeDrivers		- Implementation of drivers

****************************************************************************

Goals and objectives for GEODEs
-------------------------------
geodeGoals:

    PC GEOS supports many different types of files and processes.  Some
of these are: applications, drivers, libraries and resources.  These things,
called "GEODEs" (a geode is a special lump of rock that, if you break it open,
contains all sorts of beautiful crystals inside. The analogy seems apt),
share a common structure.  This common structure:

    * Be protected mode compatible.

    * Allows flexibility -- a driver can easily have initialized data, an
      associated process and resources.

    * Conserves code -- The same kernel code loads any code segment,
      whether part of an application, a driver or a library.

    * Allows objects to be loaded as resources.

****************************************************************************

Overview of GEODEs
------------------
geodeSummary:
See also	[ contents, geodeContents, codeFlowContents ]

A GEODE is a combination of:

On disk:
    * A signature that marks the file as being a geode
    * A header that contains name, version, type and resource tables
    * Resources (blocks of code or data)
    * For each resource, a table of relocations for that resource

In memory:
    * A "core block" that contains the system variables (many of which
      come from the geode header on disk)
    * A "dgroup" that contains the initialized and uninitialized data
      for the geode.  This segment also contains the stack for the first
      thread (if a process)
    * For each thread: a stack segment for the thread
    * Resource segments that contain data loaded from the resources on disk

    Examples of GEODEs and their typical components are:

    * Applications -- Code, initialized data, event queue, stack, resources
              and possibly an imported library table.
    * Library -- Code, an exported library table and possibly initialized
             data, stack and resources.
    * Driver -- Code, an exported library table and possibly initialized
            data, stack and resources.

GEODE structure on disk
-----------------------
geodeDisk:
See also	[ contents, geodeContents, geosFileStructure ]
        [ appCallKernel ]

    GEODEs are MS-DOS files with the extension ".geo".

    The file is composed of several parts which appear in this order:

    * The header which is a fixed size and contains basic information about
      the GEODE.  Since the header is discarded after loading the GEODE,
      pieces of information that are only needed during the loading process
      are kept here.

    * The core data information which is variable sized and contains tables
      depending on the composition of the GEODE.  This information is
      loaded into the core block and is left there.  Thus pieces of
      information that are needed at any time while the GEODE is active
      are kept here.

    * Load tables (OPTIONAL).  Tables only needed while loading GEODE.

    * Initialized data (OPTIONAL).

    * Resource segments (code and/or data) (OPTIONAL).

    The structure of the file is:

name			size	description
----			----	-----------

    *** HEADER ***

                *** Generic file information ***
                *** This part will be common to all PC
                *** GEOS files.
geodehSignature		dword	signature -- "GEOS" with high bits of G, O set
geodehAttibutes		word	flags, see [ geodeAttributes ]
geodehFileType		word	GEODE file type, see [ geodeAttributes ]
geodehVersion		word	version of GEODE format - 1 for now
geodehResourceCount	word	number of resources
geodehImportLibraryCount word	number of imported libraries
geodehUDataSize		word	size of uninitialized data

                    *** Object information
geodehClassOffset	word	offset of geode's class table (if any)
geodehClassSegment	word	segment of geode's class table (if any)

                    *** User interface information
geodehAppObjChunkHandle	word	LMem handle of application object
geodehAppObjResource	word	Resource ID of application object

    *** CORE DATA INFORMATION ***

                *** Standard information
GH_geodeHandle		word	handle to this segment (0 in file)

                *** Generic information ***
GH_geodeAttr		word	COPY OF geodehAttributes
GH_geodeFileType	word	COPY OF geodehFileType
GH_geodeVersion		word	COPY OF geodehVersion
GH_geodeSerial		word	Serial number for geode (set by exe2geos)

GH_geodeName		8 byte	name (permanent name of GEODE) (must match
                library name and file name if a library)
GH_geodeNameExt		4 byte	name extension
GH_geodeRevision	word	revision of GEODE
GH_geodeRefCount	word	reference count for GEODE

                *** Driver variables
GH_driverTabOff		word	offset (in memory) of driver table (table is
                part of idata)
GH_driverTabSegment	word	resource ID of driver table (converted to
                segment when loaded)

                *** Exported library information
GH_libraryEntryOff	word	offset of library entry routine
GH_libraryEntrySegment	word	resource ID of library entry routine table
                (converted to segment when loaded)
GH_exportLibTabOff	word	Offset to entry point table for
                exported library routines
GH_exportLibTabSegment	word	resource ID of entry point table (converted to
                segment when loaded)

                *** Imported library information ***
GH_libCount		word	number of imported library table entries
GH_libOffset		word	offset (in memory) of imported library table
                (0 in file)

                *** Resource information ***
GH_resCount		word	number of resources
GH_resHandleOff		word	offset (in memory) of resource handle table
                (0 in file)
GH_resPosOff		word	offset (in memory) of resource position table
                (0 in file)
GH_resRelocOff		word	offset (in memory) of resource relocation size
                table
                (0 in file)

    *** END OF CORE DATA ***

    *** LOAD TABLES ***

                *** Imported library table (OPTIONAL) ***
geodeLibraryTable	#libs*8	imported library table, each entry being the
                name of the library.

                *** Resource table ***
geodeResourceHandles	#res*2	size of each resource
geodeResourceFilePos	#res*4	position of each code module in file
geodeResourceRelocSize	#res*2	size of each module's relocation table
geodeResourceFlags	#res*2	allocation flags for each resource (high byte
                currently unused)

    *** RESOURCE SEGMENTS (MUST BE AT LEAST ONE) ***

                *** For each resource segment
            ???	resource
            #rel*2	relocation table

Structure of a GEODE
--------------------
geodeCoreBlock:
See also	[ contents, geodeContents ]

    In memory, every GEODE has a core block.  The core block is a fixed
block that contains information about the GEODE.  The core block contains:

    * GEODE global variables: version, type, name, etc.

    * Process variables: Valid only if this GEODE is a process

    * Imported library table (optional)

    * Resource tables

name		size	description
----		----	-----------
    *** GEODE global variables

    *** The first variables are a copy of the core block information
        from the GEODE file.

                *** General variables
GH_geoHandle		word	handle to GEODE's .geo file
GH_parentProcess	word	handle of parent process
GH_nextGeode		word	segment address of next GEODE on list

    *** The remaining state variables are only present if the GEODE is
    *** a process

                *** Object information
PH_geodeClass		dword	pointer to geode's class structure
PH_appObject
PH_vmHandle
PH_savedBlockPtr

PH_firstThread
PH_processAttr
PH_processStatus

PH_eventFrontPtr
PH_eventBackPtr
PH_eventCounter
PH_eventSem

PH_stdFileHandles
PH_lastPath
PH_currentPath

    *** Resource table (optional)

resourceHandles		#res*2	handle of each resource
resourceFilePos		#res*4	position of each code module in file
resourceRelocSize	#res*2  size of each module's relocation table

    *** Imported library table (optional)

librarySegTable		#libs*2	segment address of library's core block

Relocations
-----------
geodeRelocations:
See also	[ contents, geodeContents ]

    When PC GEOS loads in resources, several types of references
need to be relocated.  A relocation table immediately follows the data for
each resource.  Each relocation entry is two words: one word being relocation
data and the other word being the offset of the relocation.  The first word of
data at the relocation gives additional information.

Relocation entry in table:

DeclareEnum	GeodeRelocationSources, byte

    ; Relocation to a kernel entry point.
    ;	GRE_extra - unused
    ;	word at relocation - kernel entry point number
    Enum	GeodeRelocationSources, GRS_KERNEL

    ; Relocation to a library entry point.
    ;	GRE_extra - imported library number
    ;	word at relocation - library entry point number
    Enum	GeodeRelocationSources, GRS_LIBRARY

    ; Relocation to a resource of the geode.  This is never used with
    ; GRT_OFFSET or GRT_FAR_PTR since the linker eliminates GRT_OFFSET and
    ; convert GRT_FAR_PTR to GRT_SEGMENT.
    ;	GRE_extra - unused
    ;	word at relocation - resource number
    ;	for GRT_CALL - word at relocation+2 - offset of call
    Enum	GeodeRelocationSources, GRS_RESOURCE	;geode's resource

DeclareEnum	GeodeRelocationTypes, byte

    ; Relocation to a far pointer to an entry point (4 bytes).  If the
    ; target is movable then the segment is replaced by the handle>>4.  The
    ; second word of data at the target is not used.
    Enum	GeodeRelocationTypes, GRT_FAR_PTR

    ; Relocation to the offset of an entry point (2 bytes).
    Enum	GeodeRelocationTypes, GRT_OFFSET

    ; Relocation to the segment of an entry point (2 bytes).  If the
    ; target is movable then the segment is replace by the handle>>4.
    Enum	GeodeRelocationTypes, GRT_SEGMENT

    ; Relocation to the handle of an entry point (2 bytes).
    Enum	GeodeRelocationTypes, GRT_HANDLE

    ; Relocation to a call to a possibly movable routine (5 bytes).  The
    ; offset stored points to the byte AFTER the call opcode.  If the
    ; target is fixed, behavior is the same as GRT_FAR_PTR.  If the
    ; target is movable, the call opcode is replaced with a software
    ; interrupt and the other three bytes are replaced with data that
    ; defines the call.
    ;    Library calls:
    ;	bytes 0 and 1:INT LIBRARY_CALL_INT
    ;	byte 2: high byte of library handle
    ;	byte 3: (low byte of library handle) | (high 4 bits of entry #)
    ;
    ;	byte 4: low byte of library entry #
    ;    Geode resource calls:
    ;	Sixteen Software interrupts are used for geode resource calls
    ;	with the low four bits of the interrupt number being the
    ;	low byte of the handle to call
    ;	bytes 0 and 1:INT RESOURCE_CALL_INT..RESOURCE_CALL_INT+15
    ;	byte 2: high byte of handle
    ;	byte 3 and 4: offset of call
    Enum	GeodeRelocationTypes, GRT_CALL

GeodeRelocationInfo	record	GRI_SOURCE:4=GeodeRelocationSources, GRI_TYPE:4=GeodeRelocationTypes

GeodeRelocationEntry	struc
    GRE_info	db	GeodeRelocationInfo
    GRE_extra	db	?			;extra data depending on source
    GRE_offset	dw	?			;offset of relocation
GeodeRelocationEntry	ends

GEODE management
----------------
geodeManagement:
See also	[ contents, geodeContents ]

    PC GEOS keeps a linked list of all GEODEs in the system.  The
list is ordered chronologically, the first GEODE in the list is the
oldest, the last GEODE in the list is the youngest.  This ordering is
maintained by adding new GEODEs at the end of the list.

    When a GEODE is loaded the internal routine FindMatchingGeode
is called to see if another instance of the GEODE is already loaded.
If this is the case, the shared resource handles are copied from the first
instance.

    When a GEODE is removed (via GeodeRemove), it is removed
from the GEODE list and the routine FindMatchingGeode is called.  If
it returns TRUE, the shared resource handles are not freed. If the handles
are owned by the removed geode, their ownership changes to the next instance
of the geode still around.

    The GEODE variable geodeRefCount is set to (PROCESS + DRIVER)
when the GEODE is loaded.  Each call to the internal routine
UseLibrary increments geodeRefCount, each call to FreeLibrary
decrements it.  When the count reaches zero the GEODE is removed from
memory.

    Entry into the GEODE management routines GeodeLoad and
GeodeRemove is controlled by the semaphore geodeSem.

General GEODE routines
----------------------
geodeRoutines:
See also	[ contents, geodeContents ]

GeodeInfoSystem:
    Desc:	Return information about the GEODEs in the system.
    Pass:
    Return:	word - number of drivers loaded
        word - number of libraries loaded
        word - number of processes loaded
        word - total number of GEODEs loaded
        word - number of system GEODEs

GeodeLoad:
    Desc:	Load a GEODE and take action depending on its type.  If the
        GEODE is a process, a process is created.  If the GEODE is a
        library, the library is loaded and initialized.  If the GEODE
        is a driver, the driver is loaded and initialized
    Pass:	word - attributes to match
        word - attributes to NOT match
        word - flags for file type to match (0 matches all)
    Return:	word - error code

GeodeEnum:
    Desc:	Enumerate the current GEODEs in the system.  The
        GeodeInfoSystem routine can be called to find the number of
        GEODEs loaded.
    Pass:	pointer - buffer for GeodeEnumStruct structures
        word - max number of structures that can fit in the buffer
        word - attributes to match
        word - attributes to NOT match
    Return:	in buffer - names and handles of geodes
        word - number of geodes found

GeodeFind:
    Desc:	Find a GEODE given its name.  Note that this routine might
        return handles to drivers and libraries that are in the
        kernel (handle < 80h).  These handles can only be used for
        the driver and library functions.
    Pass:	pointer - name of GEODE to find
        word - attributes to match
        word - attributes to NOT match
    Return:	word - handle of driver

GeodeInfo:
    Desc:	Return information about a GEODE
    Pass:	word - handle of GEODE to get info for
    Return:	word - GEODE attributes
        word - GEODE segment address
        word - GEODE type

Drivers
-------
geodeDrivers:
See also	[ contents, geodeContents ]

    Drivers are primarily used to link PC GEOS to the hardware.  Drivers
are linked together with the nextDriver field in the core block.  Drivers
are accessed through a single entry point, their strategy routine.  This
routine is located in the first code block at the offset given in the core
block.

    A driver's strategy address is obtained by calling GeodeInfo to get the
driver's info table address and looking up the strategy routine in this table.

    The strategy routine is passed a function number that selects the
driver function to execute.  The function number is passed in the DI.  The
functions are listed in "Driver Functions" below.

GeodeRemoveDriver:
    Desc:	Remove a driver
    Pass:	word - handle of driver to remove
    Return:

GeodeInfoDriver:
    Desc:	Return information about a driver
    Pass:	word - handle of driver to get info for
    Return:	pointer - driver's info table

GeodeInfoDefaultDriver:
    Desc:	Return information about default drivers
    Pass:	none
    Return:	word - handle of default video driver

    Drivers have a information table in them that can be accessed
externally.  The table is pointed to by driverTable.  The first part of the
table is the same for all dirvers, the rest is driver type specific.  The
standard first part is:

strategy		dword		;segment:offset of strategy routine
driverAttributes	word		;device attributes for driver
driverType		word		;type of driver

Library routines
----------------
geodeLibraries:
See also	[ contents, geodeContents ]

    Libraries provide a means for sharing code between applications.
Libraries are referred to by name.  The name of the library is the permanent
name of its GEODE.  When a GEODE is loaded, all libraries used by the GEODE are
loaded by calling the kernel routine UseLibrary.

    Libraries are accessed via the first code block which must be fixed.
Library entry points can be anywhere in this code block.

    The kernel keeps track of libraries by linking them together in a
list pointed to by libraryListPtr.

    The (internal) kernel routines to implement libraries are:

UseLibrary:
    Desc:	Use the given library.  If it is not loaded, find it and
        load it.  If it is loaded, increment is reference count.
    Pass:	pointer - name of library to use
    Return:	word - handle of library

    Libraries must have one special routine, "LibraryEntry".  The
LibraryEntry routine is called to initialize and to exit the library.  This
routine is called each time a process uses or stops using the library.

LibraryEntry:
    Desc:	Initialize or exit a library.
    Pass:	di - LibraryCallTypes:
            LCT_ATTACH - When loaded
            LCT_DETACH - When about to go away
        cx:dx - data from command line
        ds - core block for library
    Return:	none
    Can destroy:	ax, bx, cx, dx, si, di, bp, ds, es

Resources
---------
geodeResources:
See also	[ contents, geodeContents ]

    Resources are segments of data belonging to the GEODE.  Resources are
identified by handles.  The handles are memory handles with the "otherInfo"
field reserved.

    In addition to these routines, the heap routines can be used with
resource handles.  Specifically, MemUnlock will unlock a locked
resource and MemDiscard will remove a resource from memory.

GeodeLockResource:
    Desc:	Use the given resource.  If it is not loaded, allocate a block
        of memory for it and load it.  Lock the resource.
    Pass:	word - resource handle
    Return:	word - segment address of resource (locked)

Geode Attributes and Types
--------------------------
geodeAttributes:
See also	[ contents, geodeContents ]

    The geodeAttributes word is defined as:

    bit 15: set for process
    bit 14: set for library
    bit 13: set for driver
    bit 12: set for resource file
    bit 11: set for auto-exec
    bit 10: set if GEODE file must be kept open after loading
    bit 9:  set if GEODE is a system GEODE (part of the kernel)
    bit 8: set if GEODE is multi-launchable (will be clear, e.g., for
           drivers).
    bits 7-0: reserved

    The geodeType word is defined as:

    1 - Application
    2 - Library
    3 - Driver

        This is used primarily to indicate where to find the .geo file if it's
not in the current directory (e.g. if a geode is found in the Application
source tree, its geodeType would be Application).

    The driverAttributes word is defined as:

    bit 15: set if driver supports "file system" interface
    bit 14: set if driver is a character device (valid only if bit 15 set)

    The driverType word is defined as:

    1 - Video driver
    2 - Input device driver
    3 - Mass storage block device driver
    4 - Serial I/O character device driver
    5 - Parallel I/O character device driver

Driver Functions
----------------
driverFunctions:
See also	[ contents, geodeContents ]

    Driver function numbers are multiples of two to allow faster access
to a jump table.  The following driver functions are available:

Number	Name		Description
------	----		-----------

    0 - 4 *** These functions are available for all drivers

0	DR_INIT		Initialize the driver
            Pass: ds - driver's core block
            Return: carry - set if error
            Destoyed: ax, bx, cx, dx, si, di, bp, ds, es

2	DR_EXIT		Exit the driver
            Pass: ds - driver's core block
            Return: none
            Destoyed: ax, bx, cx, dx, si, di, bp, ds, es

    4 - 9998 *** These functions are driver type dependent

    10000 - ... *** These functions are predefined but are only available
            if the corresponding driver attribute bit is set.

exe2geos
--------

    exe2geos is a tool that converts ".exe" and ".map" files output by
link86 into ".geo" files.

Symbol				Description
------				-----------
PERM_{name} = 1			Permanent name of geode is {name}
NEXT_EXT_{name} = 1		Name extension of geode is {name}
_REFL_{name} = {value}		Allocation flags for resource {name} are {value}
_PCM_{number} = {addr}		Relocation to resourceHandles+2*modNum needs
                to be done at {addr}
_LH_{number} = {addr}		Relocation to library number needs
                to be done at {addr}
REVISION = {value}		This is revision {value} of this geode
PROCESS = {value}		Geode is a process if {value} non-zero
DRIVER = {value}		Geode is a driver if {value} non-zero
LIBRARY = {value}		Geode is a library if {value} non-zero
MULTI_LAUNCHABLE = {value}	Geode is multi-launchable if {value} non-zero
AUTO_EXEC = {value}		Geode is an auto-exec file if {value} non-zero
FILE_TYPE = {value}		geodeFileType set to {value}
eventQueue = {addr}		Address of event queue is {addr}
EVENT_SIZE = {value}		Event queue is {value} bytes long
librarySegTable = {addr}	librarySegTable is at {addr}
NUMBER_OF_LIBRARIES = {value}	Geode imports {value} libraries
resourceHandles = {addr}	Table resourceHandles is at {addr}
resourceFilePos = {addr}	Table resourceFilePos is at {addr}
resourceRelocSize = {addr}	Table resourceRelocSize is at {addr}
NUMBER_OF_RESOURCES = {value}	Geode has {value} resources
exportLibraryTable = {addr}	Table exportLibraryTable is at {addr}

    Process only
_mT_Process = {addr}		Process method table is at {addr}
_hT_Process = {addr}		Process handler table is at {addr}
_mC_Process = {number}		Process has {number} methods

    Library only
LibraryEntry = {addr}		Library entry point is {addr}

    Driver only
DriverTable = {addr}		Driver info table is at {addr}

Segment			Description
-------			-----------
gdata			applvars
idata			initialized data and code in core block (in any)
udata			uninitialized data
sSize			stacks
{name} 'CODE'		resource module {name}
{name} 'LBRY'		library definitions of imported library {name}
{any} 'KERN'		definitions for PC GEOS kernel


death due to CANNOT_UNRELOCATE

SDK: ALL_GEOS:PUBLIC
If you are trying to save an object resource to a VMFile and you get
"death due to CANNOT_UNRELOCATE", the problem is most likely in the
class definition of one of the objects.  Check the library that defines
the class to make sure that it is exporting the class (this is done in
the .gp file) and that your application is using the correct version
of the library (do "pmake lib" on the library so the libraries .ldf file
and .geo file match).

Also realize that you can only (easily) save objects that are subclassed
off VisClass and MetaClass.  GenClass objects are modified by the specific
UI and thus require special handling before saving to a VMFile.


Using @self instead of fixing up pself.

SDK: ALL_GEOS:PUBLIC
* Version 3.0 of the GEOS kernel will now automatically fix 'pself'
  in C message handlers. The app writer no longer need worry about
  'pself' becoming invalid.

GOC:
* Added a new keyword '@self' to be used in place of 'pself'. You can
  still continue to use 'pself' as '@self' is just an alias for 'pself'.
  But using '@self' will allow you to pass the instance data pointer to
  functions and not worry about it becoming invalid. You never need to
  fixup '@self', it will always point to your objects instance data.

  Example:

    @method MyTriggerClass, MSG_GEN_SET_USABLE {
              /*
               * pself and @self are both pointers to MyTriggerInstance.
               */
        if ( @self->GI_states != pself->GI_states ) {
        CFatalError( ERROR_IN_MY_CODE );
            }
        @callsuper();
              /*
               * No need to deref since oself and @self are always valid
               * after a system call (@callsuper or @call method).
               */
        if ( !( @self->GI_states & GS_USABLE ) ) {
        CFatalError( ERROR_IN_MY_CODE );
            }
        AllocateChunk( @self, oself );
    }

    void AllocateChunk( MyTriggerInstance *@self, optr oself ) {
              /*
               * you can continue to use @self as you did in the
               * message handler.
               */
        if ( !( @self->GI_states & GS_USABLE ) ) {
        CFatalError( ERROR_IN_JOONS_CODE );
            }
              /*
               * and @self will remain valid even if the object
               * block moves.
               */
        @self->MTI_chunk = LMemAlloc( OptrToHandle( oself ), 4096 );
    }


What are .SYM and .GYM files?

SDK: ALL_GEOS:PUBLIC
.SYM files contain all the symbol names, structure definitions, etc.
They are specific to a particular compile of a geode.
Glue will automatically create a .SYM file for your geode when you
compile it. Swat then uses the .SYM file to display meaningful information
when you're debugging your application.

.GYM files are "generic" symbol files. They are not specific to a particular
compile of a geode. Instead they contain less information and are valid for
all compiles of the geode. The advantage is that one .GYM file can be used
for all versions of a geode on the SDK. The disadvantage is that
less information is stored. This is useful only for system geodes which
are not being debugged, and thus the detailed information is not needed.


Swatting a Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
To connect Swat to an actual Nokia 9000 Communicator, do one of the following:

Press Shift+d+o (all three simultaneously):
You will get text on the LCD screen, and see the Swat stub sit there and
wait for you to attach Swat on your host machine. You will not see the
splash screen. Press all three keys immediately after putting your battery
in the Nokia. You can attach the six pin connector anytime after this,
followed by attaching Swat.

Press Shift+d+b (all three simultaneously):
You will see Nokia 9000 startup normally. But you can attach Swat anytime
after the splash screen appears.

The baud rate is 38400.


ECCheckBounds and ec flag settings.

SDK: ALL_GEOS:PUBLIC
Are you getting the ADDRESS_OUT_OF_BOUNDS error on the following code (or
something similar):

    ptr = VMLock( fileHan, vmBlkHan, &memHan );
    ECCheckBounds( ptr );

or

    ptr = MemDeref( memHan );
    ECCheckBounds( ptr );

This probably happens because you have the lmem ec flag turned on. When
this ec flag is on, ECCheckBounds will do some extra checking. One of the
things it does to recognize the type of block the pointer points to. If
it's pointing to an lmem block then ECCheckBounds will make sure that the
pointer is pointing to either a chunk handle or a chunk. If it's not, it
is out of bounds. However, that may not be a problem for you if you have
some information at the beginning of the block that is internal to your
program.

So, in summary, it may seem like a good idea to turn on these ec flags,
but be aware that not all errors you get are actually errors for what your
application is doing.


Expression syntax error using MSG_VIS_TEXT_CREATE_TRANSFER_FORMAT.

SDK: BETA:PUBLIC, 2.0:PUBLIC
To fix this error, go into the VTEXTC.GOH file, located in
\PCGEOS\INCLUDE\OBJECTS, and change the return type of the message to
VMBlockHandle. Unfortunately in the 2.0 SDK this message's return type was
mistyped as VMBlockhandle, with a lower-case "h". This causes BCC to
return an "expression syntax" error.


Setting up a callback routine for driver routines.

SDK: ALL_GEOS:PUBLIC
Here is how to set up the callback pointer for a driver routine:

passParams.dx = PtrToSegment( MemLockFixedOrMovable( &CallbackRoutine ) );
passParams.cx = PtrToOffset( &CallbackRoutine );

where CallbackRoutine is a routine that you want called by the given
driver routine.

Here is an example:

void _pascal CallbackRoutine( void ) {
...
}

void YourInitRoutine( void ) {
    DriverPassParams   passParams;
    DriverReturnParams returnParams;

    passParams.dx = PtrToSegment( MemLockFixedOrMovable( &CallbackRoutine ) );
    passParams.cx = PtrToOffset( &CallbackRoutine );
    DriverCallEntryPoint( driverHandle,
                          DR_SOME_DRIVER_ENTRY_POINT,
                          &passParams, &returnParams );
    if ( CARRY_FLAG & returnParams.flags ) {
        UserStandardSound( SST_ERROR );
    }
}


Bug in UI.GOH file.

SDK: 2.0:PUBLIC, OMNIGO:PUBLIC
UIEO_DESK_ACCESSORY_LIST and UIEO_GEOS_TASKS_LIST are swapped in the
ui.goh file and they should really be:

#define UIEO_DESK_ACCESSORY_LIST 0x0200
#define UIEO_GEOS_TASKS_LIST     0x0400


OmniGo Serial flow control

SDK: OMNIGO:PUBLIC
Here is some important information about the OmniGo 100
serial port's hardware flow control lines.

The only pins connected are
  Tx (transmit)
  Rx (receive)
  RTS (request to send)
  CTS (clear to send)

The following pins are not connected and can not be used for
flow control
  DTR (data terminal ready)
  DSR (data set ready)
  RI (ring)
  CD (carrier detect)

DTR is wired to digitizer, messing with it will blank
screen.
DSR is wired to the battery indicator.

On the OmniGo, the built-in serial port is COM 1 and the
PCMCIA serial port is COM 4.

Q. Can I use hardware flow control on the OmniGo?

A. Yes and no.  Yes you can use RTS/CTS, but you cannot use
DTR.

On the OmniGo, DTR is always high, but when the transceiver
isn't powered on, the external DTR pin isn't driven.  Since
the pin is floating, it will most likely appear as neither
HIGH nor LOW.

Q. How do I know if data has been received at a serial port?
Is there an explicit message sent? or do I have to poll
using SerialQuery()?

A. You can set up a message for serial event notification.
See the SDK_C\Serial2 sample application.


Fonts, Nimbus Font Converter, GEOS font format

SDK: ALL_GEOS:PUBLIC
There may be more documentation on the font format in the
SDK, but here is some information.

 char 4 dup "BSWF"
 byte 0 ;minor version #
 byte 1 ;major version #
 word # ;size of header
 word FontIDs ;unique 16-bit ID
 word 0x1000 ;which font rasterizer to use (0x1000 == GEOS)
 byte  FontFamily --
  bit 7: must be 0
  bit 6: 1 if fixed width, 0 if proportional
  bit 5: 1 if landscape, 0 if portrait (bitmap fonts only)
  bit 4: 1 if outline font, 0 if bitmap only
  bits 0-3:
  - 0 - serif (eg. URW Roman)
  - 1 - sans serif (eg. URW Sans)
  - 2 - script (eg. Shattuck Avenue)
  - 3 - ornamental (eg. Cooperstown)
  - 4 - symbol (eg. URW SymbolPS)
  - 5 - mono-spaced (eg. Courier)
 byte char 20 dup(?)

The name must be NULL-terminated (and therefore can be up to
19 characters).

If you have trouble getting the italic or bold versions of
fonts to convert as part of the same file as the plain
versions, here is some information which might help. Finding
out if this is appropriate will require looking at the
Nimbus font files with a disk editor of some sort, so it is
not for the weak-hearted.

The Nimbus Font Converter looks at several fields in the
header of the Nimbus file(s) to get this:

(1) offset 84: full name of font

This should be the name of the font, plus any styles. For
example, the original Nimbus file for the bold-italic
version of URW Sans has "URW Sans Bold Italic" for this
field. If there are several files that contain different
styles of the same font, the 'basename' in the 'fullname'
should be the same. For example, for "URW Sans", the 4 files
would contain "URW Sans", "URW Sans Italic", "URW Sans
Bold", and "URW Sans Bold Italic". If the 'basename' does
not match, then the fonts will not be placed together. If
the 'fullname' for any of the fonts is missing any part of
the style, then the Nimbus Font Converter won't be able to
distinguish which is which style.

(2) offset 304: weight

This should be the weight of the font, such as "Bold",
"Extra Bold", or "Heavy". This should be set correctly so
that for some fonts, the different weights of "Bold" can be
distinguished. For example, many fonts may come with a
"Normal" weight, and a "Bold" weight. However, some fonts
may come with a "Heavy" weight instead of the "Bold". If
this field is not set correctly, then the Nimbus Font
Converter may have problems similar to distinguishing
separate styles, as mentioned above.

Some fonts that are compatible with the Nimbus Font
Converter are included in ZSoft's "SoftType" program. It
includes 60 or so Nimbus-Q font files, some of which are
various styles of a particular font (eg. Bold, Italic, and
Bold-Italic), and some of which are the same fonts that are
already included with GEOS software (eg. URW Sans). There
may be other sources of Nimbus-Q fonts, but this is one that
we know of (because we used it for some testing of the
Nimbus Font Converter.)


Chunks in a global block

SDK: ALL_GEOS:PUBLIC
Q. How many chunks can reside within a global block?

A. 10920. The answer comes from the following calculations:

  (65536 - (16 for LMemBlockHeader)) / (6 per chunk) = 10920

There are 6 bytes minimum per chunk, since the ChunkHandle
takes up a word, there's a word needed to store the size of
the chunk (which is stored before the chunk data itself),
and one word for the data. Even if you only use one byte of
data, the next chunk would be allocated on a word boundary.


Mouse messages

SDK: ALL_GEOS:PUBLIC
Q. Are any messages passed while the mouse pointer is moving
across the screen when it is not dragging any objects?

A. Yes, mouse messages are constantly being passed as it
moves across the screen. That's partially why mouse handlers
return MRF_PROCESSED, so that the mouse message isn't passed
to other objects. An object will receive MSG_META_PTR when
the pointer moves inside its VisBounds, whether the button
is down or not. That's why the TicTac sample application
sets a "dragging" flag on the mouse press, so that the
MSG_META_PTR method knows whether to process or ignore the
event.


Mouse pointer appearance

SDK: ALL_GEOS:PUBLIC
Q. Are messages used to change the shape of the mouse
pointer, i.e. from the arrow to the I-beam?  An example
would be moving the mouse pointer from the menu to the
document area in GeoWrite.

A. Two common choices are to change the mouse image when it
is over a GenView and after handling a mouse event. For the
former, use MSG_GEN_VIEW_SET_PTR_IMAGE. For the latter, you
can return MRF_SET_POINTER_IMAGE from the mouse event. The
details can be found in Concepts 11.2.4.


Palette manipulation

SDK: ALL_GEOS:PUBLIC
Q. What is "palette manipulation" and can you give an
example?

A. Each window in GEOS has an associated color palette that
is a list of RGB values to use for various colors. You may
change any or all of the color values in a window's palette
using GrCreatePalette(), GrSetPalette(), and
GrSetPaletteEntry().

GEOS will use the palette from the currently active window.
If it uses custom colors, then other (inactive) windows will
also be drawn with the same values, so they may appear
distorted. You can read Concepts 24.3.1.3 for more details.
However, this is an advanced graphics feature and is rarely
used in most applications.


Target software installation problems

SDK: ALL_GEOS:PUBLIC
Q. The target emulation software won't run. Swat gives the error

   ATTEMPTED_TO_PERFORM_UNSUPPORTED_FUNCTION_BEFORE_APPROPRIATE
   _IFS_DRIVER_WAS_LOADED.

A. GEOS does not recognize the DOS version on your target machine.

   If you're using Windows 95, you'll need to enter these three
   lines at the DOS prompt, then reboot the machine:

      CD\WINDOWS
      SETVER LOADER.EXE 6.3
      SETVER LOADEREC.EXE 6.3

   If you're using PC DOS 7, you'll need to make sure that this
   line is in your config.sys file:

      DEVICE=C:\DOS\SETVER.EXE

   then reboot your machine and enter this line at the DOS prompt:

      SETVER LOADEREC.EXE 6.3

   then reboot your machine again.

   Another approach is to "force-load" the DOS 4 file system driver
   by adding this line to the [system] section of the GEOS.INI file
   in the root directory of the target software:

      fs = ms4.geo

   For the EC target software, you'd use this line:

      fs = ms4ec.geo


Note button

SDK: OMNIGO:PUBLIC
Q. The "Note" button does nothing the first time it is hit.
The second time, it says "Unable to create the note.  The
document may be a template, or it may be in use."

A. The support for the "Note" trigger isn't completely
automatic. You have to add a NoteShellClass object to the
app. Also, your application is responsible for saving the
NoteShell's data into the VM file.

Here's what you should do:

In your *.goc file:

1. Include the Geos header file that defines NoteShellClass.
  @include

2. Create a new subclass of NoteShellClass.

3. Create an object of your new subclass of NoteShellClass.

4. Make it a child of the GenApplication object.

5. Add it to the following GCN lists:
  MGCNLT_ACTIVE_LIST (same as DocumentControl)
  GAGCNLT_STARTUP_LOAD_OPTIONS

6. Intercept MSG_GEN_DISPLAY_CLOSE for your subclass of
NoteShellClass:
  @method YourNoteShellClass, MSG_GEN_DISPLAY_CLOSE
  {
  /*
   * First, save away the NoteShell data into a VM file.
   */

  /*
   * Now, close the NoteShell
   */
  @send self::MSG_NOTE_SHELL_CLOSE_DISPLAY();
   }

7. In your *.gp file:
  - Add "library notes" to load the notes library
  - Export your new subclass of NoteShellClass


OmniGo JTableClass

SDK: OMNIGO:PUBLIC
Q. What is the difference between TableClass and
JTableClass?

A. JTableClass is a subclass of TableClass that contains
OmniGo-specific functionality. If you are writing your
application for the OmniGo, use JTableClass.

Q. How can my application tell when a cell is being edited?

A. You can check TI_privateFlags for TPF_EDIT_CELL_TEXT.

Q. The right side of the table is cut off. This is true not
just for the table itself, but also for the scrolling
controls in the title bar, which I have no control over.

A. The problem is that the table's column widths add up to
240 or more. Change the widths to add up to about 238. You
can play with the value to get it how you want it to look;
235 leaves a bit too much room on the right.

Q. How can I monitor when a user changes the selected cell
in a Table?

A. Unfortunately, there is no default mechanism which will
send you MSG_TABLE_SELECT whenever the selection changes.

You will have to subclass these messages and have them send
you notification whenever the selection changes:
  MSG_TABLE_CHANGE_ROW_RANGE_SELECTION - initiated by cursor
keys
  MSG_TABLE_SELECT - initiated by pen/pointer selection
  MSG_TABLE_REDRAW_CURRENT_SELECTION - selection changed by
scrolling action
  MSG_SET_CURRENT_SELECTION - program initiated selection
change.

Q. How can I set a default selection row for a table? I have
successfully managed to make a single cell be the default
selection but never the row.

A. Use MSG_TABLE_SELECT(tcl, (TRIT_ROW|TCF_START_SELECT));
"(TRIT_ROW|TCF_START_SELECT)" will tell it to select the
entire row.

Q. I have noticed that in a multi column table on the
OmniGo, I can cursor up and down but not left and right.
What do I have to do to allow the user to change columns?

A. You can make the table scroll horizontally by making the
GenView that contains the table scrollable in the horizontal
dimension. BUT DON'T DO THIS! It violates the OmniGo UI
Specification to have anything wider than the screen.
Horizontal scrolling on the OmniGo is strongly discouraged.

To make a table show different columns, you should provide
UI to allow the user to signal the app that s/he wants to
view a different set of columns.

Q. How can I start to edit a table cell from the keyboard
(i.e. not double-tapping the pen)?

A. You can intercept MSG_META_KBD_CHAR at the Table object,
and if it's the Enter key, then do the following:

Make a local variable of type TableEditCellTextParams
structure. Use MSG_TABLE_GET_CURRENT_SELECTION to get the
current selected cell, then set the TableEditCellTextParams
structure's TECT_cells field with that cell; set the
TECT_text to NullHandle, and TECT_length to 0. Then call
MSG_TABLE_START_EDIT_CELL_TEXT on yourself, passing in the
TableEditCellTextParams structure.

Q. How can I make a Table cell accept ink input?

A. Add a line like this to your
MSG_TABLE_START_EDIT_CELL_TEXT method:
  @call
MyTableView::MSG_GEN_VIEW_SET_INK_TYPE(GVIT_QUERY_OUTPUT);

Then do something similar for MSG_TABLE_STOP_EDIT_CELL_TEXT:
  @call
MyTableView::MSG_GEN_VIEW_SET_INK_TYPE(GVIT_PRESSES_ARE_NOT_
INK);

Make sure to @callsuper() before each of the above.


OmniGo serial driver

SDK: OMNIGO:PUBLIC
Q. I am using the OmniGo SDK to write an app that will use
the serial port. Whenever I try to include the line
  library streamc
in my .gp file, the linker tells me that "library could not
be found in any platform files." If the line
  platform omnigo
is removed from the file, the error does not occur. This
happens with the sample serial apps in the SDK. As soon as
the platform statement is added to either serial.gp or
serial2.gp sample app files, the same problem occurs. Any
suggestions?

A. Due to a glitch at production time, the streamc library
entry was inadvertently omitted from the omnigo.plt platform
file.

There are 2 ways to work around this:

1. Use the "platform omnigo" line in your .gp file, but also
add the line "exempt streamc". This will tell Glue to ignore
the streamc library when checking protocols in the platform
file.

2. The streamc library geode on the SDK (in
\OMNIGO\LIBRARY\STREAMC) is a newer version than that which
was shipped in ROM on the OmniGo 100 device. If you're using
some of the new features (listed below and in the serial2
sample app), then make sure your application checks the
protocols of the streamc library to ensure your app is using
the correct (newer) version of the library.

In this case, edit the omnigo.plt platform file to include
an entry for streamc. The file is
\OMNIGO\INCLUDE\LDF\omnigo.plt. Add the following line
(alphabetically):

  streamc  1  1

This will allow Geos to put up the "system file missing"
dialog if an earlier version of the streamc library geode is
in place when your app runs. Since the OmniGo device itself
has an earlier version of the library geode, you must
package the newer streamC geode (located in
\OMNIGO\LIBRARY\STREAMC) with your application when you ship
it.

The newer version of the streamc library includes the
following new routines. If you're using any of these, then
you should use fix # 2. (These are the same routines that
are listed in the serial2 sample application source file,
serial2.goc.)
  SerialLoadDriver()
  ParallelLoadDriver()
  StreamSetMessageNotify()
  StreamSetRoutineNotify()
  StreamSetDataRoutineNotify()
  StreamSetNoNotify()
  StreamSetThreshold()


MSG_VIS_TEXT_GET_LINE_INFO

SDK: OMNIGO:PUBLIC
Here is an example of how MSG_VIS_TEXT_GET_LINE_INFO can be
used. In this example, the routine takes the character
position (which could have been gotten by
MSG_VIS_TEXT_GET_SELECTION_PTR) and returns the number of
characters on that line.

word GetCharacterCountForThisLine(dword charPosition)
{
  VisTextGetLineInfoReturnValues retValue;
  VisTextGetLineInfoParameters  vtglip;
  LineInfo lineInfo;

 /*
  * Convert the character position to the line number that
  * the character is on.
  */

  vtglip.VTGLIP_line = @call Text::
  MSG_VIS_TEXT_GET_LINE_FROM_OFFSET(charPosition);

 /*
  * Set up the pointer to the buffer that VIS_TEXT_GET_LINE_INFO
  * will fill in.  In this case, we just want to basic line info.
  * If you want more FieldInfo structures, make sure to provide
  * a larger structure.
  */

  vtgip.VTGLIP_buffer = &lineInfo;
  vtgip.VTGLIP_bsize = sizeof(LineInfo);

 /*
  * Get the line information
  */

  @call Text::MSG_VIS_TEXT_GET_LINE_INFO(&retValue,
&vtglip);

 /*
  * Return the number of characters on the selected line.
  * However, only return a word size because we'll never
  * run on a device whose screen can allow more than 32,000
  * characters on a single line.
  */

  return (lineInfo.LI_count.WAAH_low);
}


OmniGo power on and off.

SDK: OMNIGO:PUBLIC
Q:
How can my application detect when the user has turned
the power on or off on the OmniGo 100?

A:
Unless your application is affected by external events
(such as serial input) or for some other reason needs to
know when the OmniGo powers on or off, you should not worry
about power notifications.

If your application does require this information, then it
can register a notification routine with the power driver.
There are only a limited number of vectors available, so
your registration is not guaranteed to be successful.

During device power down, there is nothing you can do to
prevent the powerdown.

On powerup, your routine can @send a message to let your
application know that the unit is powering back on. The
notification routine should be small to prevent power on/off
from becoming sluggish.

Here is how you register for notification:

   #define DR_POWER_ON_OFF_NOTIFY 26

   GeodeHandle powerDriverHandle;
   DriverPassParams passParams;
   DriverReturnParams returnParams;

   powerDriverHandle = GeodeGetDefaultDriver( GDDT_POWER_MANAGEMENT );
   ...
   DriverCallEntryPoint( powerDriverHandle,
                         DR_POWER_ON_OFF_NOTIFY,
                         &passParams,
                         &returnParams );

In passParams, dx:cx = fptr to call back routine.

returnParams will have carry set if you could not register
for the notification (because too many routines are already
registered).

The callback routine must be written in assembly because the
ax register will contain either ax = 0 (PNC_POWER_SHUTTING_OFF) or
ax = 1 (PNC_POWER_TURNING_ON).


Linking text and list objects.

SDK: ALL_GEOS:PUBLIC
Q:
I would like to know how to link a GenText to a
DynamicList object. It appears that this is what happens in
GeoManager when the files are displayed as names rather than
icons. It seems as if tabs are used to align various data
elements. There is mention of this in the Text Objects
chapter of the Objects book of the SDK. It says that the
vardata instance ATTR_GEN_TEXT_RUNS_ITEM_GROUP links the
text object to an item group but provides no further
details.

A:
Instead of creating vis objects in the list, I would
handle MSG_GEN_DYNAMIC_LIST_GET_ITEM_CLASS and return your
own subclass of GenItem and handle its VIS_DRAW.

If you want to know what the ATTR you mentioned does, look
in gTextC.def

What ATTR_GEN_TEXT_RUNS_ITEM_GROUPS does is send the
visMoniker of the selected item over to a text item. That
doesn't sound like what you want to do.

In your case, you might consider making each item a VisClass
object so you can handle MSG_VIS_DRAW. Or you can work
directly with the GenDynamicList to handle its MSG_VIS_DRAW.

GeoManager uses its own subclasses to perform the needed
functionality of displaying the files/folders in various
formats. If you swat the GEO2XEC desktop emulation and take
a look at DesktopViewClass (a GenView subclass) and the
objects linked to it, you can see what it is doing.


Using TimerStart for real-time events.

SDK: ALL_GEOS:PUBLIC
There are two concepts of real-time clock alarms:
1) An event that is registered with the Real-time Clock Manager,
2) A simple timer that sends the event at a given time.

The benefit of registering an event with the RTCM is that the timer
will not be stopped and freed when your application exits (this is
what happens if you start a standard timer with TimerStart()).
The RTCM event is registered via call to RTCMRegisterEvent().
The specified message will be sent to your application's process.
If you application is not currently running, the RTCM will launch
it and send the message.

TimerStart(TIMER_EVENT_REAL_TIME), similarly, starts a real-time
clock on the device that will send a message at the date and time
you specify.  The big difference is that this timer will be freed
by the system when your application exits, so it is only useful
for near-term real-time events.

For TIMER_EVENT_REAL_TIME, you pass the date that the event should
happen in the "ticks" parameter and the time of day in the "interval"
parameter of TimerStart().

The date is stored in a compressed format that is word-sized.
The year (since 1980) is in the high 7 bits; the month is in
the next 4 bits; and the day is in the low 5-bits.

The hour is stored in the high byte of "interval" and the
minute is stored in the low byte of "interval."

For example, if I wanted to have a wakeup notification sent
on March 5, 1996 at 8:05am, I would set up the "ticks" and
"interval" parameter as follows:

ticks = 0x2065;
 (year = 1996-1980 = 16 = 0x10,  0x10 << 9 = 0x2000;
  month = 3,  0x03 << 5 = 0x0060;
  day = 5,  0x05 << 0 = 0x0005)

interval = 0x0805;

No matter which real-time event you are considering, you
may find it useful to use the TimerFileDateTime structure
with TimerGetFileDateTime() or the TimerDateAndTime structure
with TimerGetDateAndTime().

To help in calculating new dates based on the current time,
you can use LocalCalcDaysInMonth().


OmniGo SDK versus 2.0 SDK

SDK: BETA:PUBLIC, 2.0:PUBLIC, OMNIGO:PUBLIC
Q:
What is the difference between the OmniGo SDK and the
GEOS 2.0 SDK?

A:
In a nutshell, the OmniGo SDK is targeted towards
application development for the HP OmniGo 100 device; the
Geos 2.0 SDK provides an environment for developing
applications for Geos 2.0 based devices or software (such as
Casio Z-7000, IBM SchoolView, and Geoworks Ensemble).

The main differences are that the OmniGo SDK provides:
 - a development environment for writing applications for Geos 2.1
 - libraries and documentation specific to the OmniGo 100
 - an OmniGo 100 emulation for debugging purposes

The Geos 2.0 SDK provides:
 - a development environment for writing applications for Geos 2.0
 - debugging emulators for Casio Z-7000, Sharp PT-9000,
Geoworks Ensemble

Q:
Can I use the Geos 2.0 SDK to write applications for the OmniGo 100?

A:
Yes. The Geos 2.0 SDK may be used to write applications
for the OmniGo 100.  Likewise, the OmniGo SDK may be used to
write applications for Geos 2.0 based products.

Developers using the 2.0 SDK may have some difficulty fully
testing their applications for the OmniGo since the 2.0 SDK
does not contain an OmniGo 100 emulator.


Using NoteShellClass and NoteClass.

SDK: OMNIGO:PUBLIC
Q:
I put a "Note" button in my OmniGo function bar area. I
want it to look like all the other Note buttons--its moniker
should be "Note#" where '#' is a graphic of a little piece
of note paper. How can I display that graphic?

A:
This has to be done in assembly. There is an example of
this in SDK_Omni\DocUI.


How to use PCMCIA change notification.

SDK: ALL_GEOS:PUBLIC
Q:
Will I receive notification if my application is using a
file that is located on the PCMCIA card and the user closes
out the card?

A:
The PCMCIA library will notify you in this case. It does
this by sending MSG_META_REMOVING_DISK to your process
object, but only if your application is using a file that is
on the card.

We recommend that your application quit (without saving to
state) when it finds out that this has happened.

Warning: Make sure you're not putting your process object on
the GCN list that sends out MSG_META_REMOVING_DISK
(GCNSLT_REMOVABLE_DISK). Because if you do, then your
process object will always receive MSG_META_REMOVING_DISK
when a card is removed, not just when you have a file open
on the card (in fact, you'll get the message twice).


The OmniGo and its state files.

SDK: OMNIGO:PUBLIC
Pressing FN+F3 will shut down the currently running
application and force it to save to its state file.

SHIFT+ON+NEXT or pressing the reset button on the back of
the OmniGo will delete all state files and the clipboard
(without deleting the other contents of the RAMdisk).

When the OmniGo is turned off, processing is suspended but
applications are not shut down to state. Power-down and
power-up are basically transparent to applications. On
power-up, MSG_NOTIFY_DATE_TIME_CHANGE is sent over the
GCNSLT_DATE_TIME GCN list.

There are three ways to limit the size of the application's
state file.

1. Completely disable the state file for your application.
Write a handler for MSG_GEN_PROCESS_CREATE_NEW_STATE_FILE
and simply return NullHandle. If your application needs to
save some small amount of information between sessions,
consider saving it in the ini file instead of in a state
file.

2. Marking a resource as notDetachable will prevent objects
in that resource from saving to state.

3. Marking an object ignoreDirty will prevent that object
from saving to state.


Drivers and libraries on the SDK.

SDK: ALL_GEOS:PUBLIC
Printer, scanner, and fax drivers are not part of the published API.
There could be many reasons for this decision; we have a number of
libraries and drivers we choose not to publish for one reason or
another.

If you find a file missing from the CD-ROM that you feel you need, the
best thing to do is to send an email or fax to Developer Services at
Geoworks requesting the file and describing why you need it. If we have
such a file or set of files, we can then proceed with a decision whether
to create a special license just for you.

In many cases we may choose to restrict access to certain APIs and make
them available only upon request. Sometimes this is a requirement levied
by an OEM or other partner; sometimes the API contains licensed code which
we are not allowed to redistribute as an API; sometimes the API itself has
characteristics that keep us from publishing it.


How to create and use OmniGo icons.

SDK: OMNIGO:PUBLIC
Q:
What is the correct procedure for installing an icon on
the OmniGo?

A:
Check out the sample app in Appl\SDK_Omni\OmniGoUI. The
message to look for is MSG_GEN_APPLICATION_INSTALL_TOKEN.

Q:
What is the correct size and format (squashed, tiny,
etc.) for an OmniGo icon?

A:
The icon size is tiny and 18x18 pixels. You can see an
example of icons in SDK_Omni\OmniGoUI\Art\omnigoui.goh.


Why is C++ not supported in the SDK?

SDK: ALL_GEOS:PUBLIC
Question:
Why doesn't the GEOS SDK support C++?

Answer:
I'll try to explain why it isn't as easy as just linking a
Borland C++ object file to the GEOS libraries to generate a
GEOS object oriented application.

When we were developing our user interface software we chose
a particular implementation of objects, classes, message
passing, etc. We made these choices because they allowed us
to do some things that were required to implement generic
user-interface objects that would transform themselves into
specific user-interface objects. Doing this requires a form
of multiple inheritance that is not supported in most C++
compilers.

C++ is an object-oriented approach to C that is implemented
by the compiler, and not by the system. This is why C++
compilers exist for UNIX (as an example) which does not
provide any sort of system level objects. All of the support
is done in the compiler.

When you send a message to an object in C++, that "send" is
bound to a piece of code that ties directly into the
message-handler for the object. When you link to C++ objects
which are defined in libraries (eg: in a user-interface
library) that "send" is tied directly to an entry point in
that library.

Now consider the problem of a specific user-interface. You
want to send a message to an object. This message may be
handled by the generic object (which could probably be
easily interfaced to C++ because the handler is known at the
time your program is linked). This message may be handled by
the specific user interface (or it may not). This is a
problem because the specific user interface is not available
at the time you link your program and therefore the linker
cannot link your message to a specific user-interface
routine (as C++ requires).

The message may also be handled by the visual objects which
implement the generic user interface. If you knew that this
was the case you could probably link to that library, but
since the visual representation is determined by the
specific UI you really can't.

So the problem is this: C++ requires that the
compiler/linker can *know* what routine will actually be
called by sending a message to an object. This is not
possible when interacting with GEOS user-interface objects.

Having made this choice for our user-interface objects, we
added support for these sorts of objects to the operating
system and these sorts of objects are now used throughout
our system.

Most of the objects in our system don't make use of this
ability which is so integral to the specific UI so we could
probably create C++ libraries for things like the Graphics-
Object library (and others).

Unfortunately since we can't easily provide C++ libraries to
allow interaction with our user-interface objects, we have
chosen not to support C++ at this time. We may find a way to
make this stuff work (by providing class libraries for
objects which will reside between the application and the
user-interface and which will send off messages to the user
interface object using the GEOS model of sending messages)
but it was a significant enough task that we have chosen to
put it off for another time.


The GEOS SDK versus IZL (Interpreted Zoomer Language)

SDK: ALL_GEOS:PUBLIC
IZL is a scripting language, originally designed for the
Zoomer and expanded somewhat for the OmniGo 100. IZL
applications can be used on the Zoomer, the OmniGo 100, and
with the GEOS desktop software.

In difficulty, IZL is somewhat like using the old, familiar
BASIC programming language (QBASIC or GWBASIC are included
with MS DOS -- that BASIC language). IZL is not the same or
similar to BASIC in its syntax, but the programming skill
and experience level required to use it are about the same.
IZL is an interpreted language, which means that the IZL
runtime interpreter must be running in order to use a
program written in the IZL language.

The interpreter is the runtime application that is available
for download on CompuServe or America Online or from Feras
Technologies' site on the World Wide Web. There are lots of
sample IZL applications also available online. The IZL
compiler is a commercial package available from Feras
Technologies.

IZL allows the programmer to use a subset of the objects and
features in GEOS, like buttons, text entry fields, etc. You
can also use any of the 99 GEOS spreadsheet functions in
your application, for example. The newer version of IZL
provides access to the serial port routines, too. Beyond
that, IZL provides the basics of programming logic which can
be used to combine those GEOS features into an application.

By contrast, the GEOS SDK is a full-featured, professional
development environment. Applications developed with the SDK
do not require a runtime interpreter. The SDK compiles them
into GEOS executables. IZL itself was created by a
programmer using the SDK, for example.

The SDK can be used to create applications or libraries or
even drivers for GEOS. SDK-created applications can make use
of all the features and objects in GEOS, plus new objects
coded in C or Assembly by the programmer. The SDK was
designed for an experienced C language programmer.


Find trigger in document control.

SDK: OMNIGO:PUBLIC
Q:
In the document control on the OmniGo, the "Find..." button does
nothing. What is it supposed to do? If it really is supposed
to do nothing in that context, shouldn't it be NOT_ENABLED?

A:
The "Find" button is managed by a SearchReplaceControl
object. It's enabled, because the user ought to be able to
search for text within the documents listed -- it's only
NOT GS_ENABLED when the File Selector shows no files.

It does nothing, because the application needs to handle the
searching itself. See the sample application DocUI, which is
in the SDK_Omni sample app tree, for an example of using
MSG_SEARCH.

Q:
When I implement the "Find" trigger on the OmniGo in the
DocumentControl's FileSelector, it always crashes. What's
going on?

A:
There is a bug in the handler for MSG_SEARCH which
requires that an object be at the chunk 002Ch in the object
resource that contains the DocumentControl object.

The workaround is to manipulate the objects so that an
object actually does exist in that chunk. You can use the
"objwalk" command in Swat (for the handle use that of the
DocumentControl object) to assist in determining where
objects are located in the resource.


Using the Swat heapspace command.

SDK: ALL_GEOS:PUBLIC
Some GEOS devices, like the Zoomer and OmniGo, use a
mechanism called the "transparent launch model." Under this
scheme, each application estimates its worst-case scenario
usage of memory or space in the global heap. When an
application is launched, it passes this value to the kernel.
If that amount of memory is not free, then other
applications are shut down in order to free up the required
amount.

Thus, IT IS IMPORTANT THAT EVERY APPLICATION RUNNING ON
THESE DEVICES SPECIFY A "HEAPSPACE" VALUE.

The heapspace value is calculated in the Swat debugger using
the "heapspace" command and declared in the *.GP file using
the "heapspace " entry. Without this number, your
application may adversely affect performance on the GEOS
device. If the number is too low, it can result in crashes
and/or data loss. If it's too high, fewer geodes will be
cached and system performance will suffer.

The "heapspace" command in Swat is a TCL script which
determines how much heapspace an application uses. Usage is:
"heapspace ." As of this writing, the current
version of this command does not give an accurate number. We
are fixing this problem; here is a workaround for the
meantime.

How to Measure Heapspace

The heapspace tool works by scanning the entire handle table
and tabulating information about block sizes. The size of
any memory block is stored in its handle entry in the handle
table. "heapspace " will add up the sizes of all
the blocks being used by  and any libraries
 depends on.

To use the tool, you must do the following:

- Finish coding and debugging your application and all
libraries it uses. Make sure you're really done: if future
revisions of your program require more memory, you will have
to compute the heapspace again.

- Run your application on the actual device. This will
result in more accurate numbers. You must connect to the
OmniGo or Zoomer with Swat to measure your application's
heapspace usage. Read the file \INSTALL\OMNIGO.TXT on the
CD-ROM for more information on debugging from an actual
OmniGo 100 device.

- In Swat, do "heapspace " at various points in
your application. Try it a few times when several UI objects
are onscreen, or when the application is doing anything that
requires lots of resources to be loaded into memory. Menus
aren't built out until they are first opened, so make sure
to open all the menus in turn before computing heapspace.

- Make the adjustments for system geodes detailed below.

- After taking many such measurements, when you begin to
feel confident that you have taken a measurement that really
reflects the maximum heap usage for your app, record the
value in your application's *.GP file. The two ways to do
this are in kbytes, e.g.:

    heapspace 13k

or in paragraphs, as in:

    heapspace 832

These are equivalent statements. If you don't specify a "k"
after the number, it is assumed to be expressed in
paragraphs. A paragraph is 16 bytes.

As you will see below, there are complicating factors on the
OmniGo that require some additional work to make heapspace
measurements.

The Problem & Solution

The main problem with the existing heapspace tool is its
failure to account for eXecute-In-Place (XIP) code
resources. These resources are executed directly from ROM,
and consequently don't need to be loaded into memory or
counted towards a geode's heapspace value.

The heapspace value for an application includes the values
for the libraries it uses. Certain libraries on each system
(OmniGo, Zoomer, PT-9000, etc.) are flagged as "system
geodes" and are counted in the sysReserve value stored in
the INI file. They don't need to be counted again when
adding up the application's values, since they're always
loaded.

The current version of the heapspace tool doesn't subtract
system geodes' heapspace values correctly for the OminGo,
because there are many more system geodes on OmniGo than
there were on previous platforms. The subtraction currently
needs to be done by hand.

System Geodes:
  ansic
  cardid
  cidfs
  color
  conview
  db
  fontman
  gadgets
  geos
  jedit
  jerror
  jkbd
  jlib
  jmotif
  jotter
  jpen
  jpwr
  jtable
  jutils
  jvideo
  key
  math
  ms4
  nimbus
  nonts
  notes
  palm
  pccom
  pcmcia
  pen
  rtcm
  ruler
  serial
  sound
  standard
  stream
  styles
  table
  text
  ucdriver
  vgfs
  vidmem

Basically, if you find any of these in the output from the
heapspace tool, subtract them from your total.

Conclusion

Every final, shipping product will need a "heapspace".
However, in order to calculate an accurate number, you need
to perform this step after most of your coding and debugging
is complete. By the time most of you reach this step, the
"heapspace" Swat command may be fixed, so check with
Geoworks developer support if you have not already received
or downloaded an update, or use the procedure outlined in
this article.


Minimum BCC++ for GEOS development.

SDK: ALL_GEOS:PUBLIC
This is the "stripped down" Borland C directory that one
programmer uses for GEOS development. This is specific to
BCC++ version 3.1. Newer versions of the compiler may
require a slightly different list.

 Directory of  c:\pcgeos\bcc\*.*

INCLUDE				21.10.94 18:13
bcc.exe		672150		11.06.92 3:10
cpp.exe		131625		11.06.92 3:10
dpmiload.exe	22212		11.06.92 3:10
dpmimem.dll	24932		11.06.92 3:10
turboc.cfg	23		21.10.94 18:29

 850,942 bytes in 6 file(s)

 Directory of  c:\pcgeos\bcc\include\*.*

stdarg.h	895		11.06.92 3:10
stddef.h	726		11.06.92 3:10
_defs.h		2303		11.06.92 3:10
_null.h		287		11.06.92 3:10

 4,211 bytes in 4 file(s)

The file turboc.cfg contains the line:

  -I\PCGEOS\BCC\INCLUDE

This is necessary to locate the compiler-dependent
include files from BCC. Other include directories
will be specified at compile-time by the makefile.


Using Gstrings vs. bitmaps.

SDK: ALL_GEOS:PUBLIC
Question:
To draw a small icon, is it faster to call drawing
routines, or use a bitmap? If bitmaps are better, how do I
create one?

Answer:
It depends on the type of bitmap (simple or
huge/complex), the specific graphics routines you're using,
and the dimensions of the graphic. There are other
considerations besides speed, too -- large bitmaps generally
take up a lot of space compared to gstrings.

You could test out your specific case by timing how long it
takes to draw, say, 100 copies of the graphic in your app.
This should exaggerate any speed difference to where it's
readily apparent which one is faster. It would be hard to
guess in advance. All things considered, however, for a
small icon, a bitmap is likely to be faster.

Within certain limitations, you can create bitmaps using the
Icon Editor or with the tools in the draw layer of GeoWrite.
Both are included in the GEOS2XNC target software. To read
more about bitmaps, start with section 23.7 in the Concepts
book.


Dgroup and static strings.

SDK: ALL_GEOS:PUBLIC
When developing for GEOS running on a desktop PC, you don't
need to worry too much about fixed size because most
contemporary PCs have several megs of RAM and lots of extra
space on the harddrive (and a fast CPU to swap blocks
around).

If you want your application to coexist with other
applications on a palmtop device, then you need to pay
attention to the fixed size.

Certain things, like the class table, must go into a fixed
resource, but this is generally not too large. The most
common reason for a growing dgroup (which is a fixed
resource) is global variables and static local variables.

Global variables are easy to recognize because they are
declared outside of a method or routine.

Static local variables can be recognized if you declare them
with the "static" keyword. They can also sneak in as static
strings. For example, if you do this:

  sprintf( someVar, "this is a static string\n" );

the string in quotes gets converted by the compiler into a
static string (and thus goes into the dgroup). Another
example:

  char * someString = "this is another static";

Although you might think the string is a local variable, it
is not. someString is local, but it points to the string
which is located in dgroup.

In cases where you are using static strings like the above
examples, it is best to declare them in a data resource and
then lock and dereference them. Example of how to do that:

@start MyDataResource;

@chunk char SomeStringChunk[] = "this string is in a chunk";

@end MyDataResource;

...

{
  char * someString;

  MemLock( OptrToHandle( @SomeStringChunk ) );
  someString = LMemDeref( @SomeStringChunk );

  /* use someString here */

  MemUnlock( OptrToHandle( @SomeStringChunk ) );
}


Debugging memory leaks using Swat.

SDK: ALL_GEOS:PUBLIC
Among the more common but difficult errors to find are pointers
to unlocked blocks. These can cause seemingly random memory
leaks because the block may not move immediately. The memory
manager only moves the block when it needs to.

To help you track down these errors, use Swat and set "ec
+segment +unlockMove" (+free and +lmemMove are also useful
in tracking down memory leaks). The segment flag will cause
the EC version of Geos to check the segment registers to
make sure they are valid. The unlockMove flag will cause
blocks to get moved whenever their lock count reaches zero.

If you call a routine with a parameter that is a pointer to
a unlocked block, you will get a death due to
ILLEGAL_SEGMENT. You can then do a regs, which will display
something like this:

  (someapp:0) 4 => regs
  AX a000h 40960  BX 5820h 22560  CX 00f4h  244
  DX cccch 52428  SI 170bh  5899  DI 0001h  1
  BP 0888h  2184  SP 0878h  2168

  CS  323fh  handle 1b30h (geos::ECCode)
  DS  170bh  handle 15d0h (geos::dgroup)
  SS  544eh  handle 55e0h (dgroup)
  ES  9dc9h  handle 5960h
  IP  01b6h  (geos::ECCode::ECCheckSegment+19)
  Flags: OF=0 DF=0 IF=1 TF=0 SF=0 ZF=1 AF=0 PF=1 CF=0

And from that you can do a phandle on the handle associated
with the ES and DS segment registers to see how many locks
are on the block. What you are looking for is a lock count
of zero like in the following example.

  (someapp:0) 5 => phandle 5960h
  address: 0x9dc9  size: 0x12  prev: 0x5890  next: 0x5a40
  owner: 0x2450 (notebk)  Swapable
  Locked 0 times  Last Use: 4214h  OtherInfo: 1h

Now you look at the pointer variables in your application to
see if any are pointing to the block. In the above example,
the pointer would point to 9dc9h:0000h.


OmniGo, installing an application

SDK: OMNIGO:PUBLIC
Question:
For testing purposes, how is an application transferred
to the OmniGo? Where in the OmniGo is the app stored?

Answer:
The application is stored in the RAM disk. The easiest
way to upload the application is:

1. Reboot the OmniGo (shift-on-next keys) to make sure the
previous version of your app is not running in the
background.

2. Run the Transfer application and connect.

3. Use PCSend. It comes with the SDK and should be in the
PCGEOS\BIN directory. You will need to set the ptty
environment variable to have the same baud rate as the
OmniGo, either 9600 or 19200. In DOS you can do this with
the SET command. For example:

  C:\PCGEOS\APPL\SDK_C\MYAPP> set ptty=2,9600

will tell PCSend to use com2 at 9600 baud. There's more
information about pcsend, pcget, and pccom in the tools
book.

You will need to specify sending the application to the
World directory. Otherwise it will end up in the root
Geoworks directory where HomeScreen won't recognize it. You
specify the directory like this:

  pcsend myapp.geo /d:world

which will send myapp.geo to the World directory on the
OmniGo.

Question:
How will my customers install my application on their
OmniGo?

Answer:
Geoworks has created a freely distributable installer
application that you can find on CompuServe (the Geoworks
library at go GEOSDK), America OnLine (the Geoworks
Development Files library at keyword GEOSDK), or the
Geoworks website (http://www.geoworks.com).

You must use Shipper to "package" your application into a
.gpk file. The users then use the Geoworks Installer to
install your .gpk file to the OmniGo.


Converting WWFixedAsDword to floating point.

SDK: ALL_GEOS:PUBLIC
Question:
I need to convert a value that is returned from a GenList
Class (the message is MSG_GEN_GET_VALUE). The value is
returned as a WWFixedAsDWord. I have some code for
converting a WWFixed to FloatNum, but it does not work with
the WWFixedAsDword. Is there any way around this problem?

Answer:
Floating point numbers in Geos follow the Intel IEEE 754
standard. In this format, floating point numbers are 80 bits
(10 bytes) long. In GOC and C, use "long double".

Here is some sample code to convert a WWFixedAsDWord to a
double, and also to the Geos/Intel 80-bit floating point
format:

 WWFixedAsDWord numWWFixed;
 word           intPart;
 word           fracPart;
 double         numIEEE64;
 long double    numGeos80;

 numWWFixed = @call MyGenValue::MSG_GEN_VALUE_GET_VALUE();
   /*
    * Convert WWFixedAsDWord to double.
    */
 intPart = IntegerOf( numWWFixed );
 fracPart = FractionOf( numWWFixed );
 numIEEE64 = (double)intPart + (double)fracPart / 65536;
   /*
    * Now convert it to the Geos 80-bit format.
    */
 FloatIEEE64ToGeos80( &numIEEE64 );
   /*
    * The result is pushed on the FP stack.
    */
 FloatPopNumber( &numGeos80 );

For further information on floating point numbers, see the
documentation: Concepts book Appendix D and the header files
float.h and math.h.


Making your app localizable.

SDK: ALL_GEOS:PUBLIC
Question:
What must I do to make my application localizable?

Answer:
You should read Chapter 8 "Localization" of the Concepts
book. This chapter covers many of the concepts and routines
needed to make your application easily localizable.

In a nutshell, here's what you need to consider:

1. Put localizable strings in @chunks so you can use ResEdit
to modify the strings.

2. Use Local...() routines for formatting strings (for date,
currency, measurement, etc.) and other string manipulation.

3. Register for notification of changes to user settings.

Question:
How can my application receive notification of changes in
date/time format or other formatting that the user can
change?

Answer:
Put your application on the
GCNSLT_NOTIFY_INIT_FILE_CHANGE GCN list and watch for
MSG_META_NOTIFY( MANUFACTURER_ID_GEOWORKS,
GWNT_INIT_FILE_CHANGE). The parameter "data" will be the
InitFileEntry that changed. Here are the possible values of
"data":

  IFE_DATE_TIME_FORMAT
  IFE_NUMBER_FORMAT
  IFE_CURRENCY_FORMAT
  IFE_PUNCTUATION
  IFE_OWNER_INFO
  IFE_SYSTEM_SOUND
  IFE_INK_THICKNESS


Determining the platform my app is running on.

SDK: ALL_GEOS:PUBLIC
Q. How can my application determine what platform or device
   it is running on?

A. This information is in the INI file. Under the [ui]
   category, the productName key will be the name of the
   product. For example:

     Platform:                 productName =:
     ---------                 --------------
     Casio Z-7000              Zoomer
     Brother DTP               NIKE
     HP OmniGo 100             HP OmniGo 100
     Nokia 9000 Communicator   Responder Build x.x (where x.x is version #)

   You can get this information with the InitFileReadString()
   routine.


OmniGo, GenPrimary

SDK: OMNIGO:PUBLIC
Q. I cannot get the GenPrimary on the OmniGo to be a
floating window like I can in Ensemble or like Clip&Go. How
can I do this?

A. On the OmniGo, GenPrimary is forced to be full-screen no
matter what. To get around this, you will have to make a
GenInteraction (GIV_DIALOG) and use that as the floating
window.

If you wish to make the GenPrimary hidden so your
application is only represented by a floating window, attach
(GI_comp) the dialog box to the GenApplication object.  In
MSG_GEN_PROCESS_OPEN_APPLICATION, send
MSG_GEN_INTERACTION_INITIATE to the dialog box (and make the
dialog box GIA_NOT_USER_INITIATABLE).


Mouse in OmniGo emulation

SDK: OMNIGO:PUBLIC
The OmniGo SDK's emulation software for the OmniGo has no
Preferences module, so it's impossible to change the mouse
driver while running the emulation software.

The OmniGo emulation comes preset to use the "No Idea"
driver, which will work on the majority of systems.

If your mouse does not work in the OmniGo emulation
software, install and configure the GEOS2XNC software and
get your mouse working there. Then exit and examine the
GEOS.INI file for GEOS2XNC and copy/paste the appropriate
mouse driver entries into the OmniGo emulation's GEOS.INI
file.


Windows NT

SDK: ALL_GEOS:PUBLIC
Windows NT works fine for the host (development) machine,
although Win95 is reported to be a lot faster.

It's been reported that on some systems Swat under NT needs
IRQ 4, in which case you'll need

  PTTY=1,19200,4

in your AUTOEXEC.BAT.

Geos will not run under Windows NT, so your target machine
must be running DOS or Windows 95.


Opening an application in the background

SDK: ALL_GEOS:PUBLIC
Q. I tried to open an application via IACPConnect with
   MSG_GEN_PROCESS_OPEN_APPLICATION. I want the application to open
   behind other applications.

   So, after I get the launch block from IACPCreateDefaultLaunchBlock, I
   locked down the block, set ALB_launchFlags to ALF_DO_NOT_OPEN_ON_TOP
   and unlock it before calling IACPConnect. However, the appl still opens
   up on top. Then, I tried ALF_OPEN_IN_BACK and it still doesn't work.

   At last, I tried both ALF_DO_NOT_OPEN_ON_TOP and ALF_OPEN_IN_BACK,
   and then it works. How come? It sounds like either one of the flags
   should be enough. Am I missing something?

A. Looking at the code, I see these flags being checked in a couple of
   different places. If the app is being opened for the first time, in
   the MSG_META_ATTACH handler MSG_GEN_BRING_TOP is sent unless
   ALF_DO_NOT_OPEN_ON_TOP is set. In IACPOpenConnection the app is not
   sent MSG_GEN_BRING_TO_TOP if either of the two flags is set. I think
   that ALF_OPEN_IN_BACK is used to set the app's layer id to be lower
   than all others already open.


Broken C-Stub: ChunkArraySort

SDK: ALL_GEOS:PUBLIC
C Routine:  ChunkArraySort
Date Fixed: 4/14/95

The C stub for ChunkArraySort wasn't quite correct in early versions
of the system. To use it you will have to write the callback routine
in assembly. You'll also have to call ChunkArraySort from assembly,
so that the C callback routine is not activated.


How to use GeodeFind.

SDK: ALL_GEOS:PUBLIC
GeodeFind will find a running geode given its permanent name and return a
GeodeHandle for that geode. Note that this only works on geodes that are
currently running in the system. It will not work on geodes that are simply
on the disk drive somewhere.

Here is a sample of how to use GeodeFind:

    ghGeode = GeodeFind( "spool", 5, 0, 0 );
    sprintf( handleStr, "%04xh", ghGeode );


Geos user error messages

SDK: 2.0:PUBLIC

GEOS ERROR MESSAGES

This document contains a comprehensive list of the error messages in
GEOS. In GEOS 2.0 there are two kinds of error messages. One kind of
error appears in a dialog box, and often suggests ways to recover from
the problem, with buttons for you to tap on.

The second kind of error message appears as a white box in the center
of the screen. Unlike the first kind of error, these boxes do not
contain any buttons; in most cases, you have no choice but to reset
the unit by pressing a fire button and/or the reset button inside the
battery compartment.

All GEOS error messages contain an error code. Some error messages are
caused by a temporary condition. In many cases, you can simply repeat
the operation without the error reappearing. Sometimes the error
message description is followed by some suggested ways to fix the
problem.

The message listed here may differ slightly from the message on your
screen. If the message includes specific information, such as a file
name, this is indicated by a bracketed word. For example:

FM-06. You cannot copy or move [name] to one of its own folders.

On the screen, [name] is replaced by the actual name of the file
or folder.

DOCUMENT CONTROL ERRORS

DC-01: You cannot have more than 99 untitled documents. Close or
remove some of these documents before continuing.

DC-02: There is not enough free space on the device to [perform
the action]. Remove some files from the device to free up space.

DC-03: There are too many open files to [perform the action].

DC-04: Could not [perform the action]. You may wish to try again.
If the problem continues, the device may contain errors or be
unreadable.

DC-05: The device is write protected. Remove the write protection
and click OK to try to [perform the action] again, or click
Cancel.

DC-06: Could not [perform the action]. The document is already
open. You may have it open in another application or, if you are
on a network, someone else may be using it.

DC-08: The document is damaged. You will need to restore it from a
backup copy to continue.

DC-09: The document [filename] cannot be opened because it was
created with an older version of this application.

DC-10: The document [filename] cannot be opened because it was
created with a more recent version of this application.

DC-11: The document [filename] is not a type that can be opened by
this application.

DC-12: Could not save document [filename] - DOS or network reports
error [number]. You may wish to try again or consult your DOS or
network manual.

DC-13: An error was encountered trying to change the type of
[expression]. The operation could not be completed.

DC-14: An error was encountered while trying to change the
password for [filename]. The operation could not be completed.

DC-15: An error occurred while trying to rename the document. The
operation could not be completed.

DC-16: An error occurred while trying to back up the document. The
operation could not be completed.

DC-17: An error occurred trying to revert to the backup copy of
this document. The operation could not be completed.

DC-18: An error occurred trying to set the default empty document.
The operation could not be completed.

DC-19: The name [filename] is not a legal name for a document for
this application.

DOSEXEC ERRORS

DE-01: Unable to run DOS Program (probably caused by bad path)

FILE MANAGER ERRORS

File Manager error messages often appear when you are working with
items in File Manager, such as the Wastebasket. In many cases, you
can easily correct the problem and repeat the operation without
further error.

FM-01. Could not find the file or folder. It may have been
deleted. Rescan the drives to see the current view of an open
window to determine if the file is really there.

FM-02. Could not find the requested folder. Rescan the drives to
see the current view of an open window to determine if the file is
really there.

FM-03. [name] cannot be accessed. It may already be in use or be a
read-only file. This message may appear if you attempt to save a
read-only file.

FM-04. Unable to locate this drive. Restart your unit.

FM-05. You cannot copy or move a file to itself. This usually
occurs when you accidentally select the wrong file in the file
selector dialog box. Select a different destination for the copy
or move. This can also occur when dragging a file icon to the icon
of the folder which contains it.

FM-06. You cannot copy or move [name] to one of its own folders.
This usually occurs when you accidentally select the wrong folder
in the file selector dialog box. Select a different destination
for the copy or move. This could also occur if you have several
windows open and try to move a folder into one of the subfolders
it contains.

FM-07. The destination already contains a folder named [name],
which cannot be overwritten because it contains the item you are
moving or copying. This usually occurs when you accidentally
select the wrong folder in the file selector dialog box. Select a
different destination for the copy or move. This could also occur
if you try to move a folder icon into its own window.

FM-08. You cannot perform this operation with the root folder.

FM-09. Could not open the folder. You already have the maximum
number of 32 folders open. Close one or more open folders and try
again.

FM-10. Please re-enter the name using a valid name format. For DOS
files, use the standard DOS format. For other applications and
documents, the name can be up to 32 characters long. The DOS
format is eight characters for the file name, followed by an
optional period and 3-character extension.

FM-11. [name] is not an application or document that can be opened
directly.

FM-12. You cannot format the drive containing the system software.
You probably selected the wrong drive letter. Pick a different
drive and try again.

FM-13. There is not enough room on the destination drive to copy
this file. Empty the Wastebasket or remove some files from the
device and try again.

FM-14. [name] could not be thrown away because the Wastebasket is
full. Empty the Wastebasket and try again. The Wastebasket can
only hold a certain number of documents.

FM-15. There is not enough memory available to perform this
operation. Close some windows or applications and try again.

FM-16. Another DOS program is already being launched. [name]
cannot be launched at this time. Try launching (starting) the
program again later.

FM-17. Could not delete the folder [name]. It may not be empty or
you may not have the privilege to delete it. The folder probably
contains items which you are not allowed to delete, such as read-
only files. Open the folder and try deleting each item inside
individually to determine which caused this message.

FM-18. This folder contains too many files. Not all of the
filenames can be displayed. File Manager can only display about
400 items in a folder window. The remaining items are in the
folder, but will not display on the screen.

FM-19. Could not rename the drive. You may not be allowed to
change the name of the selected drive.

FM-20. Could not create the folder [name]. There may not be enough
room on the destination drive. Remove some files and folders to
open up some additional space on the drive.

FM-21. A new folder cannot be created at this level. The path is
too long. You can rename higher-level folders to create a shorter
path name. DOS has a maximum length for path names. If you have
used long names for folders or have many folders within folders,
this maximum can be exceeded.

FM-22. Invalid characters in the volume name. Re-enter the volume
name using valid characters. You can use the following characters
in drive volume names: alphabetic characters, digits, and tilde !
@ # $ % ^ & ( ) _ - { }. You cannot use periods, commas, blanks,
colons, asterisks, and any other characters not included above.

FM-27. An error occurred during this operation. Please try again.

FM-28. Cannot find the application for [name]. Try opening it from
within an application. The document was created using a DOS
application. You must start the application and then open the
document from within it.

FM-29. Unable to open the file. The file may be corrupted. If you
tried opening the file by double-clicking, try opening it from
within the application. If this is unsuccessful, you may have to
use data recovery software to salvage your data.

FM-30. Couldn't find [name]. Unable open the file. The file may
have been deleted or moved. Choose Rescan Drives from the File
Manager menus, and check again to see if the file is really there.

FM-31. Could not open [name] because a required system file is
missing.

FM-32. [name] is not an application or document that can be
opened.

FM-33. There is not enough memory available to open the file as
requested. Close windows and applications that you are not
currently using and try again.

FM-34. The application is too new to work with this version of the
system software.

FM-35. The application is too old to work with this version of the
system software.

FM-36. The application is already running on this system.

FM-37. The application is incompatible with this version of the
system software.

FM-38. Could not locate a required system file. Restart your unit.

FM-39. Unable to start a driver needed by the application. Restart
your unit.

FM-40. Unable to open a system file needed by the application.
Restart your unit.

FM-41. Drive too full to open [name]. Some applications need free
drive space to open a document. Either delete unnecessary files or
copy the file to another drive before trying to open the file
again.

FM-42. You are in the process of exiting the system. You cannot
open anything at this time.

FM-43. Unable to find the application that created [name]. If you
know where to find the application, open the application first and
then try opening the document from there.

FM-44. Cannot open this item.

FM-45. This folder has been moved or deleted.

FM-46. The [name] item cannot be placed here.

FM-47. The expected icon could not be found, so another will be
substituted.

FM-48. You cannot recover a file to the Wastebasket. Choose
another location for the Recover operation.

FM-49. Nothing was selected. You must select an item on which to
perform the operation.

FM-50. [filename] cannot be moved.

FM-51. [filename] cannot be copied.

FM-52. [filename] cannot be deleted.

FM-53. The folder [name] is currently open and cannot be deleted.
Close the folder and try deleting it again.

FM-54. This device is write protected. Move the write protect
switch and try the operation again.

FM-55. The requested drive does not exist. If you are using a
network drive, try exiting GEOS, restarting your unit, and
repeating the operation.

FM-56. Could not find formatted media.

FM-57. A file or folder with the same name already exists. Use a
different name for the new item.

FM-58, -59, -60, -61, -62. The format was unsuccessful.

FM-63. This contains a file or application that is currently in
use.

FM-65. The format was unsuccessful. The device is write protected.
To format you must move the write protection switch.

FM-66. The device format was unsuccessful.

FM-67. There is not enough memory available to copy the disk.
Close windows and applications that you are not currently using
before trying to copy the disk.

FM-68. The disk copy was unsuccessful. The source disk could not
be read and may be damaged.

FM-69. The disk copy was unsuccessful. The destination disk could
not be written to. Try again using a different disk.

FM-70. The disk copy was unsuccessful. The destination disk may be
damaged. Try again using a different disk.

FM-71. The disk copy was unsuccessful. The destination disk
contains a file or application that is currently in use. These
items must be closed before you can copy over the disk.

FM-72. The disk copy was unsuccessful. The destination disk is
write protected. To copy over this disk you must remove (or move)
the write protection tab.

FM-73. The source and destination disks are incompatible. The
destination disk cannot be formatted the same as the source disk.
Try using the same drive and type of disk for both source and
destination disks.

FM-74. The source disk does not appear to be formatted. Please
check the disk and try again.

FM-76. First, you must select the item(s) you wish to open.

FM-77. First, you must select the item(s) you wish to remove.

FM-78. First, you must select the item(s) you wish to copy.

FM-106. Could not delete or rename the folder [name]. It is a
system folder.
You cannot delete or change the names of system folders.

FM-108. This name contains no visible characters, please choose
again.

FM-109. The format has been canceled. This must be formatted again
before it can be used. Try formatting again.

FM-110. There is not enough memory available to format.

FM-111. The disk copy was unsuccessful. The destination disk may
be damaged. Try again using a different disk.

FM-112. The disk copy has been canceled. The destination disk will
need to be reformatted before it can be used again. Format the
destination disk, then try the disk copy again.

FM-123. The DOS Launcher Template file cannot be found.

FM-124. The DOS Launcher Template file cannot be read.

FM-125. Because of an error the Launcher could not be created.

FM-126. You cannot throw away files already in the Wastebasket.

FM-127. A connection is already in progress. Please terminate it
before opening another.

FM-128. Could not load the Remote File System driver - connection
attempt failed.

FM-129. There is not enough room on the destination disk to copy
this file. Remove some files from the destination disk to make
room, or try copying to another disk.

FM-130. A file or folder with the same name already exists. Use a
different name for the new item.

FM-131. You must complete File Linking before running any other
applications.

FM-132. Unable to start File Transfer Mode.

FM-134. Unable to start File Linking - configuration error.

FM-135. Unable to start File Linking - already connected.

FM-136. Unable to start File Linking - a previous connection is
currently in the process of being closed.

FM-137. Unable to start File Linking - port is already in use or
does not exist.

FM-138. Unable to start File Linking - not enough memory.

FM-139. Unable to modify this file or folder.

FM-140. The maximum number of folders has already been created in
WORLD.

HELP SYSTEM ERROR MESSAGES

These error messages appear when you try to view online help.
Usually the problem is only with the online help section of the
software, and does not affect the rest of GEOS.

HP-01. Error in help. File [name] not found. You may need to re-
install your software.

HP-02. Error in help. Unable to find "context" section in help
file [file name]. Please note the exact text of this message if it
recurs. A portion of the help file has been damaged.

HP-03: Error in help: The decompression library could not be
loaded. You may need to re-install your software.

HP-04: Error in help: The file  is not a valid help
file. You may need to re-install your software.

HP-05: Error in help: The file  is incompatible with the
current software. You may need to re-install your software.

IMPORT/EXPORT ERRORS

IM-03. There was an error in reading the translation library named
[filename]. The file may contain errors or be damaged.

IM-04. The library named [filename] does not seem to be a valid
translation library. It may contain errors or be damaged.

IM-07. There are too many open files for the import/export to
proceed. You should close some files or increase the number of
file handles available.

IM-08. A disk error was encountered while opening the file. The
disk or file may contain errors or be damaged.

IM-10. The destination disk is write protected or full. Remove the
write protection, or delete some files, then try again.

IM-11. Unable to change to the specified folder.

IM-12. Could not create a temporary import/export holding file.
The disk may be full, or it may contain errors or be damaged.

IM-13. Could not create the import/export thread.

IM-14. No translation libraries could be found. You cannot import
or export without translation libraries.

OPERATING SYSTEM ERRORS

Operating system error messages have a KR or KRX prefix. Most of
these errors have very terse text and an error code, and originate
in the GEOS system software.

For most of these errors, you must restart your unit. Sometimes
the error message will tell you to press a fire button. In some
cases, though, this will not work. In either case, you should then
restart your unit by pressing the Restart button in the battery
compartment. Often this will fix a problem.

KR-01 to KR-11, and KR-18
Messages KR-01 through KR-11 and KR-18 have no explanation in the
error message itself. Often these messages indicate a temporary
problem in the hardware. Restarting your unit may solve the
problem.

KR-01. Divide by zero.

KR-02. Arithmetic overflow.

KR-03. Array index out of bounds.

KR-04. Coprocessor/memory parity error.

KR-05. Single-step complete.

KR-06. Breakpoint hit.

KR-07. Illegal instruction executed.

KR-08. Non-existent routine called.

KR-09. Bad handle passed to system.

KR-10. Illegal segment passed to MoveBlock.

KR-11. Handle Table Full.

KR-18. Unable to swap in block.

KR-12 to KR-xx
The following error messages do not always require that you
restart your unit. However, unless otherwise noted, try restarting
your unit to solve the problem.

KR-12. Out of system resource handles.

KR-13. Cannot allocate required local memory.

KR-14. Error in [name]. Operation cannot be completed.

KR-15. Low on system resource handles. Please exit an application.
Your unit is almost out of memory. Try closing documents
immediately.

KR-16. Conventional memory (below 640KB) is full.

KR-17. Swap space is full. You may be low on disk space. Try
exiting some applications and closing documents immediately. To
make more disk space, try deleting some old files in your Document
folder.

KR-20. GEOS.INI file is damaged. Restart the unit to make a fresh
copy.

KR-21. Error restoring state. Please exit and restart the system.

KR-22. Error reading VM file. The document or application data
file may be damaged.

KR-23. Cannot load a required system file (geos.ini or kernel).
You may need to reinstall the system software.

KR-25. Cannot load a required system file (vidmem). You may need
to reinstall the system software.

KR-26. Cannot load a required system file (keyboard). You may need
to reinstall the system software.

KR-27. Cannot load a required system file (ui). You may need to
reinstall the system software.

KR-28. Cannot find USERDATA\FONT folder. You may need to reinstall
the system software.

KR-29. No valid font files found in USERDATA\FONT folder.

KR-30. Cannot load a required system file (sysfont). You may need
to reinstall the system software.

KR-31. DOS version too old. You need DOS version 3.0 or higher.

KR-32. Unable to register the disk containing the main system
folder.

KR-33. File system driver for drive [name] not loaded.

KR-34. Unable to identify file system in use.

KR-35. The system is unable to exit. Please restart your unit.

KR-36. No room to write GEOS.INI. Please make room now.

KRX-xx. Undefined error in [name]. An error has been detected by
this part of the program. The number is passed on from the
detecting software.

MATH LIBRARY ERRORS

MT-01. You cannot define a format without giving it a name. Enter
a name and try again.

MT-02. A format with this name already exists. Enter a new name
and try again.

MT-03. You have reached the limit for the number of user-defined
formats. The operation could not be completed.

MT-04. Unable to create format.

PARSE ERRORS

PL-01. The formula you have entered has a mistake. It may contain
a typo with a numerical digit or other error. Check the formula
carefully for errors.

PL-02: The formula you have entered has a mistake. It may contain
an invalid cell reference or other error. Check the formula
carefully for errors.

PL-03: There is a missing or extra quotation mark. Ensure that you
have an equal number of opening and closing quotation marks.

PL-04: The formula you have entered has a mistake. There may be a
cell reference that is too large. The column and cell of a cell
reference cannot be greater than IV:8192.

PL-05: The formula you have entered has a mistake. There may be a
cell reference that is too large. The column and cell of a cell
reference cannot be greater than IV:8192.

PL-06: The formula you have entered has a mistake. It may contain
a function, cell reference, or operator that does exist or is not
allowed. Check the formula carefully for errors.

PL-07: The formula you have entered has a mistake. Check the
formula carefully for errors.

PL-08: This formula is too complex (too many operators and
functions). Try breaking it down into smaller parts or simplifying
it.

PL-09: The formula you have entered has a mistake. It may be that
a function in this formula is missing an opening or closing
parenthesis. Check the formula carefully for matching parentheses.

PL-10: There are names in this formula that have not yet been
defined. But they can't be defined because there are already too
many. you will need to delete some unused names or use regular
cell references in this formula to continue.

PL-11: This formula is too complex (out of stack space). Try
breaking it down into smaller parts or simplifying it.

PL-12: There are too many names dependent on each other in this
expression. Try breaking the expression down into simpler parts.

PL-13: There are too many cell references that depend on each
other in this expression. Try breaking the expression down into
simpler parts.

GEOPLANNER

PL-07: The description for this event is too long. Some of the
text at the end of the event has been deleted.

PRINTER ERROR MESSAGES

The SL error messages occur when you print documents. Often they
indicate a temporary condition that you can correct.

SL-01. The printer is not responding. Click OK to try printing
again or Cancel to quit.

SL-02. The printer [name] is warming up.

SL-03. The printer is warming up.

SL-04. The printer [name] needs to be serviced.

SL-05. The printer needs to be serviced.

SL-06. Check the paper feed error on the printer [name]. Click OK
to continue printing.

SL-07. Check the paper feed error on the printer. Click OK to
continue printing.

SL-08. The printer [name] is not responding and may be off-line.
Return the printer to on-line status and click OK to try again or
Cancel to quit.

SL-09. The printer is not responding and may be off-line. Return
the printer to on-line status and click OK to try again or Cancel
to quit.

SL-10. The printer [name] is out of paper. Refill the paper tray
and click OK to continue.

SL-11. The printer is out of paper. Refill the paper tray and
click OK to continue.

SL-12. The printer [name] is out of toner. Replace the toner and
click OK to continue.

SL-13. The printer is out of toner. Replace the toner and click OK
to continue.

SL-14. The printer [name] is off-line. Switch the printer on-line
and click OK to continue, or Cancel to quit.

SL-15. The printer is off-line. Switch the printer on-line and
click OK to continue, or Cancel to quit.

SL-16. The printer [name] needs attention. Check the printer
connections and make sure it is on-line. You may have to turn the
printer off and then on again. When the printer is ready, click OK
to resume printing or click Cancel to stop printing this document.

SL-17. The printer needs attention. Check the printer connections
and make sure it is on-line. You may have to turn the printer off
and then on again. When the printer is ready, click OK to resume
printing or click Cancel to stop printing this document.

SL-18. The printer [name] on the [number] port is not responding.
Check the printer connections and click OK to try again or Cancel
to quit.

SL-19. The printer is not responding. Check the printer
connections and click OK to try again or Cancel to quit.

SL-20. The spool file has been deleted. Please print the document
again.

SL-21. Couldn't load the driver for printer [name]. Free up some
memory by closing windows and applications you're not using. If
you're still unable to print, the driver may have been deleted and
you should try reinstalling the software.

SL-22. Couldn't load the printer driver. Free up some memory by
closing windows and applications you're not using. If you're still
unable to print, the driver may have been deleted and you should
try reinstalling the software.

SL-23. Couldn't load the printer port driver. Free up some memory
by closing windows and applications you're not using. If you're
still unable to print, the driver may have been deleted and you
should try reinstalling the software.

SL-24. No printers have been installed. Before you can print, you
need to install the printer (or printers) you will be using.

SL-25. Printer [name] can't be used to print this type of file.
The print mode (graphics or text) doesn't match. Try using another
printer.

SL-26. The printer can't be used to print this type of file. The
print mode (graphics or text) doesn't match. Try using another
printer.

SL-27. There is not enough memory to print. Click OK to try again,
or click Cancel to quit. You should close some windows or quit
some applications to free up some memory before trying to print
again.

SL-28. Couldn't print. The VIDMEM driver was not found and may
have been deleted and you should try reinstalling the software.

SL-29. Couldn't print because the port is currently in use. Try
again later.

SL-30. The printer is not responding. Check the printer
connections and try again. If you're still unable to print, check
the printer settings.

SL-31. The communications port for this printer is not working.
Please select another port or make sure this port is working.

SL-32. The printer [printer name] needs attention. Your print job
has been canceled. Check the printer connections and make sure it
is on-line. You may have to turn the printer off and then on
again. When the printer is ready, resubmit your job.

SL-33. The printer needs attention. Your print job has been
canceled. Check the printer connections and make sure it is on-
line. You may have to turn the printer off and then on again. When
the printer is ready, resubmit your job.

SL-34. The disk containing the output file is full. You need more
room on the disk to which you are trying to print. Try removing
old files from your disk to make room, or try printing the file to
another disk.

SL-35. A file system error occurred writing the output file. Try
printing to a file again. Check that your disk is not full.

SL-36. The output file cannot be opened. You may be trying to
overwrite a file that is write protected. Try using another file
name, or try placing the file in another folder.

SL-37: Unable to convert page . You are probably out of
disk space.

SL-38: Unable to convert document page. You are probably out of
disk space.

SL-39: No printer (driver?) installed

STYLES LIBRARY

ST-01: This action would cause a style to be based on itself or on
a derivative of itself, which is illegal.

ST-02: A style with this name already exists.

IMPEX

TR-00: An error occurred while importing or exporting.

TR-01: The file you selected to import does not appear to be in
the format you specified. You may have selected the wrong format,
or the file may contain errors.

TR-04: The selected format is not currently supported for import
or export.

TR-05: An error occurred during export.

TR-06: An error occurred while accessing a file during import or
export. The file or disk may contain errors or be damaged.

TR-07: The disk is full and the operation could not be completed.
You may wish to free up space on the disk by deleting files, then
try again.

TR-08: An error occurred while opening a file during import or
export. The file or disk may contain errors or be damaged.

TR-09: An error occurred while reading a file during import or
export. The file or disk may contain errors or be damaged.

TR-10: An error occurred while writing to a file during import or
export. The file or disk may contain errors or be damaged.

TR-11: The file you are trying to import or export is too large to
be processed. Try splitting the file into two or more pieces and
importing or exporting them one at a time.

TR-12: Unable to allocate enough memory to complete the import or
export. Try closing some applications.

TR-13: An error occurred while trying to create an intermediate
holding file. The disk may be full, or it may contain errors or be
damaged.

USER INTERFACE ERROR MESSAGES

Like operating system error messages, user interface error
messages indicate a problem with the GEOS's control software, and
are usually not recoverable. Restart your unit.

UI-01. The device is too full to create the work area state file.

UI-02. Could not create state file. DOS error encountered.

UI-03. Unable to load the specific UI library file. You may need
to re-install the software.

UI-04. Unable to open the clipboard file.

UI-05. Unable to allocate enough memory to collect pen input.

UI-06. Unable to load the Handwriting Recognition Library.

UI-07. Unable to load application.

UI-08. Unable to load print spooler. You may need to re-install
the software.

UI-09. Unable to allocate undo space.

UI-12. There is not enough memory available to start this
application. Free some memory by closing windows and applications
you are not using. Then try again.

UI-13. The application could not be found. The file may be
missing, or it may contain errors or be damaged. You may wish to
re-install the software. Or, if you are attached to a network,
there may be an error in the network configuration.

UI-14. An associated library file could not be found. The file may
be missing, or it may contain errors or be damaged. You may wish
to re-install the software. Or, if you are attached to a network,
there may be an error in the network configuration.

UI-15. Could not read the disk. It may be damaged or unformatted.
If this is a floppy drive, the door may not be closed or the disk
may not be fully inserted. Or, if you are attached to a network,
there may be an error in the network configuration.

UI-16. The application is incompatible with this version of the
system software.

UI-17. There is not enough room on the disk. You may want to move
files not in use to another disk or delete unnecessary files.

UI-19. Unable to locate the expected disk: The drive in which it
was located no longer exists. If you are attached to a network,
there may be an error in the network configuration or you may not
be logged in properly.

UI-20. Unable to locate the expected disk: There is not enough
memory to keep track of the disk. Close some windows or
applications to free up memory, then try again.

UI-21. Unable to locate the expected disk: The drive in which the
disk is located is otherwise occupied. You may wish to try again
later.

UI-22. Unable to locate the expected disk: You are not connected
to the appropriate server to which the disk belongs.

UI-23. Unable to locate the expected disk: You do not have
permission to use the appropriate network disk volume.

UI-24. Unable to locate the expected disk: There is no free drive
letter to which the network disk may be mapped.

UI-25. Unable to open the shared token database file using the
path specified in the GEOS.INI. Restart your unit.

UI-26. Unable to open the local token database file in the
PRIVDATA folder. Try deleting the file.

UI-27. The shared token database file on the path specified in the
GEOS.INI file is


Disabling the hard icon bar on Geos devices

SDK: ALL_GEOS:PUBLIC
Disabling the Hard Icon Bar on GEOS devices
===========================================

The hard icon-bar cannot be disabled through the .ini file.  However,
this may be done via code.   An application, once started, may watch
for messages from the hard icon-bar, capture these messages, and do
any manipulation it wishes with these messages.

Hard icon presses come in MSG_META_NOTIFY with the parameters
    manufID = MANUFACTURER_ID_GEOWORKS and
    notificationType = GWNT_HARD_ICON_BAR_FUNCTION or
                       GWNT_STARTUP_INDEXED_APP
    parameter = hard icon that was pressed
                (only for GWNT_STARTUP_INDEXED_APP)

To keep the press inactive, Subclass the application object, and
intercept MSG_META_NOTIFY.  In MSG_META_NOTIFY, if the parameters match
those mentioned above, simply swallow the message (i.e. don't call the
superclass).  Everything else should be passed to the superclass to allow
standard functions to proceed.

To capturing a specific icon, only worry about the notification type
GWNT_START_UP_INDEXED_APP.  When this notification comes in, the variable
called "parameter" will have the number of the icon pressed.  This
notification is for all icons except the launcher (very left most icon).
The other icons are numbered 0 thru 8, counting up from the left to right.
For example, the clock icon is number 4 and the help ('?' mark) is 8.
-------------
(Sample code)

@class		MyApplicationClass, GenApplicationClass;
@endc
@classdecl	MyApplicationClass;

.
.
.

@method MyApplicationClass, MSG_META_NOTIFY
{
    /* call the superclass only if the message doesn't deal with the
     * hard icon-bar. */
    if(!(manufID == MANUFACTURER_ID_GEOWORKS &&
         (notificationType == GWNT_HARD_ICON_BAR_FUNCTION ||
          notificationType == GWNT_STARTUP_INDEXED_APP)))
    {
        @callsuper();
    }
}


Choosing between 12-hour and 24-hour format.

SDK: ALL_GEOS:PUBLIC
Q. How do I tell if the user prefers their time display in 12-hour
   or 24-hour format?

A. Call LocalGetDateTimeFormat(buffer, DTF_HM) and do some analysis
   on the returned string. The string will look something like this:

      |HH|:|Zm| |AP|

   or

      |Zh|:|Zm|

   The first string is for 12 hour time format, the second is for 24
   hour. If you scan the string for "AP" and find it, that means the
   format is 12 hour. You probably don't want to try checking for "Zh"
   since that is not a guarantee that the format is 24 hour.

   This all assumes the user hasn't mangled the time format via the
   Preferences application. However, ever since the OmniGo we don't
   allow the user that kind of flexibility.


Clipboard enabling OmniGo input fields

SDK: OMNIGO:PUBLIC
This information is based on the Official Specification for how
cut/copy/paste work in OmniGo input fields (all types).

I will first define some terms:
    input field -- any object that's based on a text object,
      including VisText, GenText, GenValue, editable date/time
      gadgets, etc.  It does NOT include radio buttons, scrolling
      lists, GenTriggers, date selectors, or other non-editable
      objects.  It DOES include multi-line text objects.

    clipboard-enabled -- works with the clipboard (selection
      can be cut/copied/pasted/deleted).

    jedit library -- Chris Thomas' super-nifty library for
      making the clipboard Fun 'n' EZ.

The rules are:

    - if you don't have an Edit control, then you've got nothing
      to worry about.  All your input fields will work with the
      clipboard via the Graffiti input box (gestures) and the
      keyboard (cut/copy/paste keys).  This is transparent.

    - if you DO have an Edit control, then upon receipt of a
      MSG_META_CLIPBOARD_*, you should call the appropriate
      routine in the JEdit library (JEditEditScreenCut,
      JEditEditScreenUpdateEditControlPaste, etc.) to "register"
      the interaction containing the focused input field to be
      clipboard-enabled.

    - the system will assume your Edit Control is in your Application
      menu. Technically, it just searches the parent-child tree
      starting at the app object until it finds an Edit control.
      If your Edit control is elsewhere, you're going to have to
      move it.

    - non-input fields cannot be clipboard-enabled without doing
      lots of special work at the application level.  The JEdit
      library does not support this and never will.  Non-input
      fields are objects that don't have an editable text object
      in them.

    - If you have an object in the title bar that needs to be
      clipboard-enabled (an unlikely circumstance), you should
      put it in its own GenInteraction and give that interaction
      HINT_SEEK_TITLE_BAR_LEFT/RIGHT.  That will give you an optr
      to pass to the JEdit library.

  If you are not interested in using the JEdit library, and you have
  an Edit control in your application and want to support input
  fields being clipboard-enabled, you're going to have to find a
  way to send your clipboard messages to the focus, rather than the
  target. You're probably better off using the JEdit library.


Dynamically Loading Libraries

SDK: ALL_GEOS:PUBLIC
Using Dynamically Loaded Libraries
==================================
Calling routines from dynamically loaded libraries is quite easy.
The basics are all there is to it, so once you learn the basics,
you've learned to use DLL routines.  The three main steps are:
1. call GeodeUseLibrary to load the library and get its handle
2. access the library routines
3. release the library with GeodeFreeLibrary.

Setup
-----
These two lines should be added to your .GOC file
#include
@include  /* the header file for your library, if it exists */

In your .GP file, add the line
library mylib noload   # "mylib" is the name of your library

GeodeUseLibrary
---------------
Pass the (DOS style) name of the library, the major and minor protocol
numbers of that library, and a pointer to a GeodeLoadError structure.
You need to set the working directory to that of the library.  In most
cases, the library is in the System directory.

Calling the library routines
----------------------------
ProcGetLibraryEntry
ProcCallFixedOrMovable_cdecl or ProcCallFixedOrMovable_pascal

To access the routines in the library, you must first get the pointer
to the routine using ProcGetLibraryEntry().  Then call the routine
with one of the two ProcCallFixedOrMovable_...() routines.  Geoworks
library routines are always declared as _pascal, so you should use
ProcCallFixedOrMovable_pascal on them.  You can find out for sure
whether the routine is _pascal or _cdecl by looking it up in the
header file (grep for the routine name in the Include directory).

You can determine the entryNumber (second parameter of ProcGetLibraryEntry)
from the "export" lines in the library's .GP file.  The first line
corresponds to zero, with the values increasing by one for each successive
line.  If the creator of the library has #defined these values in the
library's .H (or .GOH) file, you could include this in your application's
source file and use these definitions for the entryNumber parameter.

GeodeFreeLibrary
----------------
If you dynamically load the library, then it is your responsibility to
free the library.  This is done simply by calling GeodeFreeLibrary().

Example
-------
    #define MY_LIB_ROUTINE_A  0
    #define MY_LIB_ROUTINE_B  1
    #define MY_LIB_ROUTINE_C  2
    #define MY_LIB_ROUTINE_D  3

    #if ERROR_CHECK
    static char *myLibName = "mylibec.geo";
    #else
    static char *myLibName = "mylib.geo";
    #endif

    GeodeHandle    myLibHandle;
    GeodeLoadError err;
    dword          returnValue;

    /* First store the current setting of the standard path and then set it
     * to the system directory, where all the library geodes should be. */
    FilePushDir();
    FileSetStandardPath(SP_SYSTEM);

    (myLibHandle = GeodeUseLibrary(myLibName, 0, 0, &err);

    if(myLibHandle != NullHandle)
    {
        returnValue = ProcCallFixedOrMovable_cdecl(
            ProcGetLibraryEntry(myLibHandle, MY_LIB_ROUTINE_A),
            /* library routine parameters go here */);
    }

    /* Restore the previous standard path setting. */
    FilePopDir();

Additional Information
----------------------
GeodeLoadErrors
  GLE_PROTOCOL_IMPORTER_TOO_RECENT
  GLE_PROTOCOL_IMPORTER_TOO_OLD
  GLE_FILE_NOT_FOUND
  GLE_LIBRARY_NOT_FOUND
  GLE_FILE_READ_ERROR
  GLE_NOT_GEOS_FILE
  GLE_NOT_GEOS_EXECUTABLE_FILE
  GLE_ATTRIBUTE_MISMATCH
  GLE_MEMORY_ALLOCATION_ERROR
  GLE_NOT_MULTI_LAUNCHABLE
  GLE_LIBRARY_PROTOCOL_ERROR
  GLE_LIBRARY_LOAD_ERROR
  GLE_DRIVER_INIT_ERROR
  GLE_LIBRARY_INIT_ERROR
  GLE_DISK_TOO_FULL
  GLE_FIELD_DETACHING
  GLE_INSUFFICIENT_HEAP_SPACE


How to get the GeodeHandle of a driver

SDK: ALL_GEOS:PUBLIC
Q. I want to get the Geode Handle of a driver (from C) so that I can
   use that handle as an argument to GeodeInfoDriver (to get the
   strategy routine). The techdocs say that I could use GeodeUseDriver,
   but "it is much easier to automatically load the drivers you need by
   indicating them in your geode parameters file."

   Well, if I put the driver in my .gp file, how can I get the handle
   of it? Or really, how do I use a driver that I put in my .gp file?

A. If you know the geode is already loaded, as you do in this case,
   and you know the permanent name of the geode, (i.e., "serial",
   "mouse"), you can do:

    driverHandle = GeodeFind( "mouse   ",
                              GEODE_NAME_SIZE,
                              GA_DRIVER,
                              0 );

   If the driver you're looking for is of one of the types listed in
   GeodeDefaultDriverType, you can use GeodeGetDefaultDriver.


Common programming mistakes of Geos neophytes

SDK: ALL_GEOS:PUBLIC
The following is a list of common mistakes commited by programmers
who are new to Geos.

1. Not using EC code to catch errors
   Since Geos is multithreaded and unlocked memory blocks can be moved
   out from under a pointer, debugging memory scribbling is quite
   difficult.  Become familiar with the EC routines that are available
   within Geos and use them liberally.  When compiled as non-EC, these
   routines become empty stubs, so they won't impact the performance of
   the shipping version of your application.

   Related to this is stress testing your application with swat.  By
   simply turning on many of the EC flags, you can find many bugs that
   would otherwise take days to find and duplicate.  Here is a partial
   list of flags to set:

   General Memory
    +unlockMove
      Force unlocked blocks to move whenever possible.  This
      causes memory leaks to be more consistently reproducable.
    +free
      Checks free blocks on the heap, which normally
      should contain 0xCC. If they don't, a fatal
      error is generated, and information about the
      previous blocks on the heap are dumped.

      The previous block is useful because often you
      will just be writing past the end of a block.
      Often you can just figure out what this previous
      block is, and then track the bug looking at the
      code.

   LMem (chunk, huge array, DB, etc.)
    +lmem
      Checks the lmem internal structures. If you
      find that an LMBH_handle (or another header
      field) is messed up, this is frequently useful
      for finding out when it is happening.
    +lmemMove
      Force lmem blocks to move whenever possible
    +high
      Simply increases the level of lmem checking.

   VMFiles
    +vm
      Checks VM file consistency
    +vmemDiscard
      Forces clean VM blocks to be discarded when unlocked
    +analVM
      Extensive VM memory checking

   Miscellaneous
    +graphics
      Checks gstrings and similar graphics stuff
    +segment
      Extensive segment checking
    +text
      Performs extra error checking on Text objects

2. Variables
   - Global variables, static variables and static strings take up
     space in dgroup.  dgroup is a fixed block, so the bigger it gets
     the more grief it causes the memory manager.  Move as much of
     statics and globals to object instance data or chunks in a data
     block.

   - Local variables are stored on the stack.  This is only a bad thing
     when you have a local variable that is a huge structure or array
     (10s or 100s of bytes) because it could cause the stack to overflow.
     To reduce the size of variables on the stack, change the variable
     to a handle, optr, or ptr to a block or chunk that contains the
     structure.

     You can see the value of the stack pointer register for each frame
     on the stack by doing "backtrace -rsp" in swat.

3. Memory
  - Make sure to check for failed memory allocations or locks.  (This can
    be determined by checking for NullHandle or null pointer.)
  - Don't allocate many memory blocks for small data structures.  Each
    block takes up a global handle (of which there are usually only 3000
    total) so don't create many blocks that each hold a small amount of
    data.  This will eat away at the global handle table and can lead
    to crashes or other memory problems.
  - Don't let object resources get too big (break out into multiple resources)
  - In a method handler, pself can be invalidated after calling another
    message or when performing an LMem action on the obj block (oself).
    Make sure to re-dereference pself (with ObjDerefGen or ObjDerefVis)
    when using it after one of these invalidating actions.  On the other
    hand, don't overkill by dereferencing after every routine call, too.
    (Note, this has changed for products after the N9000; see @self.)

4. Threads
  - Do not allow your application's ui thread to make calls to its process
    thread.  This can result in deadlock because the process thread must
    occasionally make calls to the ui thread.
  - All objects in a Gen tree must be run by the same thread (usually the
    ui thread).

5. Files
  - Always check for successful file open/create.  You can simply check
    if the returned FileHandle is NullHandle.  If the file could not be
    opened or created and you try to access the file, it will crash the
    system.

6. UI and Generic object trees
  - The GenProcessClass has no instance data. NONE! It is a hybrid
    class that has no space allocated for instance data. If you try to give
    it instance data you are guaranteed to get memory scribbling errors.
  - Remember to use the neverSaved flag on ProcessClass @classdecl.  Do
    not use this flag on objects that have instance data unless the
    object is marked ignoreDirty.
  - Don't over-use HINT_DEFAULT_FOCUS or HINT_DEFAULT_TARGET.  Only one
    object at a given level in the gen tree can have the default focus
    or target.

7. Localization
  - The resource of chunks to be localized must be marked with the lmem
    flag.  This can be done in the .gp file by adding "lmem" to the
    resource declaration.

8. Graphics
  - Difference between a GString and a GState.  A GString is a data
    structure containing a sequence of graphics commands (see gstring.h).
    A GState contains information that keeps track of how to draw (the
    colors, scaling, current text font, etc.).  A GState can contain a
    gstring.  A GString cannot contain a GState.

9. Miscellaneous
  - For standard menus (like "File" or "Edit") use
    ATTR_GEN_INTERACTION_GROUP_TYPE = GIGT_????_MENU


Fixing STACK_OVERFLOW

SDK: ALL_GEOS:PUBLIC
If you are experiencing "death due to STACK_OVERFLOW", you can use the
backtrace command in Swat to view the stack usage.  In Swat, stop in
the method/routine you are concerned about and type "backtrace -rsp"
this means "show register sp for each stack frame in the backtrace".
When analyzing the stack usage, you should be concerned by any large
changes in the sp value between frames, and by sp's value nearing about
250.

There are several ways to fix the stack usage problem.  Here are some
considerations.

1) Reducing the size of local variables
==========================================================

If your routine/method has large local arrays or structures in it,
you should consider moving the array/structure to a global data
block or allocating a block dynamically (using MemAlloc).  This
concern is due to the fact that local variables are stored on the
stack, so large local variables will eat up lots of stack space.

Example:
--------
This code creates a local variable of 2 bytes to hold the handle
of a block that contains a 200-byte character string, rather than
creating a local variable to hold the string itself (char myStr[200]).

Also, the handle is passed to another routine, instead of passing
the string itself.

   @method MyProcessClass, MSG_MY_MSG
   {
      MemHandle myStrHandle;
      char *myStr;

      myStrHandle = MemAlloc(200, HF_FIXED, HAF_LOCK);

      if ( myStrHandle == NullHandle )
      {
         return(-1);  /* return error */
      }
      else
      {
         myStr = MemDeref(myStrHandle);

         /* ... perform your code here. */

         AnotherRoutineThatNeedsTheString(myStrHandle);

         MemFree(myStrHandle);
         return(0);  /* return okay */
      }
   }

2) forceQueue'ing messages
==========================================================

For messages that are deeply embedded, @send the message with the
"forceQueue" flag.  This assures that the message will be placed on
the message queue, so it will have the full stack space when it is
Bhandled.  The syntax is: "@send, forceQueue MyObject::MSG_MY_MSG".

The reason for the forceQueue flag is that if the destination
object is run by the same thread as the calling object, then the
sent message will be handled immediately as if it were an @call.
The forceQueue flag compels the system to always put the event on
the thread's message queue so it won't be executed until after the
current code (and all the code frames on the stack) return, and
after any other events that are already on the queue have returned.
This gives the queued message the entire stack to work with.

If the message to send is somewhat time-critical, you can also add the
flag insertAtFront, which puts the event at the start of the queue,
so it gets executed before any other events in the queue.

Note that the forceQueue flag cannot be used with @call.

3) Avoid deeply-nested routine calls
==========================================================

Similar to 2) above, deeply nested routine calls will eat away at
the stack.  Try to arrange your code to avoid this -- perhaps by
sending message (using @send, forceQueue instead), or by rearranging
how your code is called, to more routines are called from a higher
level.

4) Increasing the size of the UI stack (this only works for
   applications, not for libraries)
==========================================================

As a final option (and this should only be used as a last resort), you
can increase the size of the stacks for each thread in your application.

To change the stack size of your application's process thread, use the
"stack" keyword in your .gp file:

    stack 3000

The parameter is in bytes; the default is 2000 bytes.

To change the stack size of your application's ui thread, subclass
MSG_PROCESS_CREATE_UI_THREAD as follows:

   @method MyProcessClass, MSG_PROCESS_CREATE_UI_THREAD
   {
      stackSize = 3000;     /* set new stack size to 3000 bytes */
      @callsuper();
   }

You should use backtrace to determine the minimum increase that you
need to make to the stack.


Moving class defns to their own resource (out of dgroup)

SDK: ALL_GEOS:PUBLIC
If you have defined so many subclasses in your application that
glue complains that your dgroup is getting too large (>10kb), then
you might consider moving your class definition tables out of dgroup
and into their own resource.  (Consider this after you've decided that
you really need all those subclasses, and you've combined/removed
as many as you can.)

You also need to do this (i.e., put your class tables in their own
resource) if your application will reside in ROM on a device and
run XIP.

All the classes will still be in the same (fixed) block, but at least
the stack (2kb) won't be in that block as well.

To do this, simply define your classes as usual in your .goc file, but
make the following change in your .gp file:

        resource MYCLASSSTRUCTURES      fixed read-only shared

(If the app is named Hello, do NOT name your new resource
HELLOCLASSSTRUCTURES, since that's the default name -- choose
something else, as done above.)

You'll also have to create a local.mk file, to customize the makefile.
It should look exactly as follows:

#
# -C flag puts class tables in their own resource,
# instead of dgroup.
#
GOCFLAGS        += -CMyClassStructures
#
# Include the system makefile.
#
#include <$(SYSMAKEFILE)>

N.B.: The Swat command "classes" will no longer work, since the
command looks in dgroup to find your class definitions.  So you'll
have to set breakpoints in your methods using alternate means (viewing
the source code and using the mouse to set the breakpoint; or using
"stop at :" syntax.)

One slight benefit above that of reducing the size of dgroup is that
if your app is ever made XIP, this is one of the steps you'd have to
do anyway.


dealing with heap allocation warnings on the emulator

SDK: ALL_GEOS:PUBLIC
This article suggests ways to reduce warnings from swat about
GLOBAL_HEAP_IS_CONGESTED_SO_THREAD_IS_SLEEPING. This is caused when
an allocation on the global heap has failed and the caller passed
HAF_NO_ERR.  The current thread gets slept in the hopes that memory
will become available when other threads complete their tasks. To
avoid this situation, accept errors when calling MemAlloc or
MemReAlloc, and then try to allocate a smaller piece of memory or
notify the user that the current operation has failed.

For emulators of XIP systems, this warning is occasionally caused by
the large sized (10-16K) code resources.  Here are some suggestions for
clearing up conventional memory to allow more resources to be loaded:
    - Move DOS drivers and TSRs to high memory.  How you do this
      depends on the version of DOS (In MS-DOS 6, you can use
      Memmaker).
    - If using Netware drivers, you can reduce the size of IPXODI
      with the "/a" or "/d" option.  If you don't use SPX, then
      the "/a" option will save you 9K.
    - Have Geos load its XMS driver by adding the following to
          the emulator's .ini file:
        [system]
        memory = {
        diskec.geo
        xmsec.geo
        }
    - If possible, don't load unecessary drivers (CD-ROM, network).
    - System handles take up a small amount of memory so, during
      development, you can reduce the number of handles (default
      is 3000) by adding:
        [system]
        handles = 2000


White Paper on Writing Error-Checking code

SDK: ALL_GEOS:PUBLIC
Writing EC code into your GEOS apps
===================================

I'm sure you've experienced a time when you were setting the value of
variables indirectly by using a pointer to the variables. And I'm sure at
some point that pointer was trashed or not dereferenced and you started
writing all over memory. Well, GEOS has a routine to check for that
(ECCheckBounds). Just think how much time you could save by using EC
routines to catch such problems as illegal handles, corrupt chunk arrays,
and bad return values. And don't think that you're going to slow down your
app by using EC routines. The EC routines are only needed while you are
testing your application. Once you've debugged your app and are ready to
ship, just compile without the EC routines and you'll have a fast, correct
application.

Now that I've convinced you to use error-checking code in your GEOS apps,
lets take a look at how to use EC code.

The first thing you must learn to do is surround EC routine calls with the
EC() macro. Using the EC() macro tells GOC to include the error-checking
code in only the EC version of your app. When you compile the NC version
of your app, GOC will ignore anything inside the parentheses of the EC()
macro. This is good for two reasons. First, not all EC routines are found
in the NC version of GEOS. Second, you don't want to slow down your
shipping app with calls to EC routines once you've debugged your app.

The second thing to know is that there are many EC routines in GEOS that
check all kinds of things. Many check handles such as memory handles, file
handles, vmem handles, lmem handles, and gstate handles. One routine
you'll have to watch for is ECCheckGStateHandle. The C stub for this
routine had a bug in it that caused it to always cause an ILLEGAL_HANDLE
error. You can, however, call the assembly version of the routine and it
will work. The error in the C stub was fixed as of 8/8/96.

Thirdly, not only can you use EC routines in GEOS to find bugs, but you
can also write your own error checking code that checks internal data
structures and values. For instance, if a routine is called and you are
expecting a parameter whose value falls within a certain range, you can
check that using the EC_ERROR_IF() macro. EC_ERROR_IF lets you evaluate a
boolean expression, and if it is true a fatal error will be flagged. And
since this is an EC macro it will only be included in the EC version of
your geode.

Now that you have an idea of how to use EC routines in your GEOS
application, lets review the advantages to using EC code:

  - Catch bugs sooner, before they cause other misleading problems.
  - Catch bugs you wouldn't otherwise find (ie. system doesn't check for them).
  - Helps produce near-perfect programs (we can dream).


Sending SMS messages to certain applications.

SDK: N9000C:PUBLIC
An SMS message can be prefixed by the followed character string, in order
to send that SMS message to a particular application:

    //XXXXnnnnn\r

where XXXX  = TokenChars (always exactly 4)
      nnnnn = TokenID (MANUFACTURER_ID_XXXX, assigned to developer by
                       Geoworks)
and the "//" and "\r" are mandatory.

On the Nokia 9000 Communicator, when the on-board Mailbox receives an
SMS message with such a string prefix, it will notify the recipient
application that it has an SMS message waiting for it.

It is important that the application ID (or, GeodeToken, the combination
of the TokenChars and TokenID) actually reference an application that
resides on the phone.  If it doesn't, then when the code is debugged using
the target PC emulator with Swat, the developer will see a crash with
the following "Death due to":

HOW_CAN_APPLICATION_HAVE_NO_NAME?			enum FatalErrors
; Trying to generate notification to the Indicator application on the
; Nokia 9000 platform, but the name of the application that has a message
; isn't known. Since _NO_UNKNOWN_APPS_ALLOWED is defined for this platform,
; it should not be possible for the name to be unknown but there be a
; message.

And _NO_UNKNOWN_APPS_ALLOWED means this:

; _NO_UNKNOWN_APPS_ALLOWED	Don't allow messages to be registered
;				for applications that can't be found
;				at registration time. This is usually
;				turned on when _CONTROL_PANELS is turned
;				off, as without a control panel,
;				messages for unknown apps cannot be
;				deleted.

So if you're developing an application for the Nokia 9000 Communicator
that sends SMS messages directly to an application, DON'T send an SMS
message to an application that may not be there.


Passing HeapFlags to MemAlloc.

SDK: ALL_GEOS:PUBLIC
Q:
I get a BAD_ALLOC_FLAGS error when I try to use MemAlloc. What flags
should I be passing to MemAlloc so it will work?

A:

You must pass either HF_FIXED, HF_DISCARDABLE, HF_SWAPABLE, or
HF_DISCARDED to MemAlloc. If you don't pass one of those flags then you
will get an ALLOC_BAD_FLAGS error.


Multilaunchability and your geode.

SDK: ALL_GEOS:PUBLIC
If you're writing a multi-launchable geode, you will have to use
GeodeGetOptrNS to reference any static objects. No longer will you be able
to do:

  @send MyAppObject::MSG_GEN_APPLICATION_SOME_MESSAGE();

Instead you'll have to do something like this:

  optr app;
  app = GeodeGetOptrNS( @MyAppObject );
  @send app::MSG_GEN_APPLICATION_SOME_MESSAGE();

It is recommended that you instead write only single-launchable geodes.
This way you won't have to use GeodeGetOptrNS and you'll maintain your
sanity. To make sure your app will compile as single-launchable, put the
word "single" in the type line in your .GP file.

By the way, using GeodeGetOptrNS in a single-launchable app will cause an
ILLEGAL_HANDLE error.


How to get rid of LS_CANNOT_LOCATE_KERNEL error.

SDK: N9000C:PUBLIC
If you're using the Nokia SDK and you get an LS_CANNOT_LOCATE_KERNEL
error, simply quit Swat, reboot the target, and start over.


Can't run Swat. Missing swat.tcl file.

SDK: ALL_GEOS:PUBLIC
If you can't run Swat because of a missing SWAT.TCL file, the problem
could lie in the SWAT.CFG file. Swat will exit when it can't find the
SWAT.TCL file, which is in the TCL directory of your root SDK directory
(usually PCGEOS). If you installed the SDK to a directory named something
other than PCGEOS then Swat won't be able to find the TCL directory. The
SWAT.CFG file is responsible for telling Swat where to look for the TCL
directory. So to fix the problem use your favorite editor to change the
SWAT.CFG file. Look for the line:

  syslib TCL

And change it to:

  syslib \\TCL

where  is the name of the directory where you installed the SDK.
This should allow Swat to find the SWAT.TCL file and thus work correctly.


GenText in a properties dialog.

SDK: ALL_GEOS:PUBLIC
If you have a GenText object in a properties dialog, you will have a
slight problem. For instance, bring up the dialog and type some text into
the GenText. Then click on Cancel in the dialog. Now activate the dialog
again. Edit the text in the GenText. Notice how the Ok trigger doesn't
become enabled like it did the first time.

To fix this you must set the modified status of the GenText when the
dialog is initiated. To do this, make a subclass of GenInteractionClass
and use that class for the dialog object. Then intercept the
MSG_GEN_INTERACTION_INITIATE message and in your handler call the
superclass, then send the following message:

  @send textObj::MSG_GEN_TEXT_SET_MODIFIED_STATE( FALSE );

Now when you type something in the GenText it will always send out its
status message to the interaction, and the Ok trigger will become enabled,
as it should.


Glue: 'warning fixing up unused space in lmem resource...'

SDK: ALL_GEOS:PUBLIC
Q. Using the new Nokia 9000 SDK, when compiling, I've recently seen a
   notice by Glue that I've not seen before:

       Warning fixing up unused space in lmem resource INTERFACE

   Any idea where this comes from?

A. This is a recent change to Glue that works around a bug in BCC
   that is inserting a small amount of extra space into certain object
   resources. Glue turns the extra space into a free chunk, and produces
   the warning. It shouldn't have any effect on the app, but if you do
   an lhwalk on INTERFACE, you'll see the free chunk.


Copyright message in your geodes

SDK: ALL_GEOS:PUBLIC


How to avoid transparent detaches.

SDK: ALL_GEOS:PUBLIC
To prevent your application from transparently detaching, set the
AS_AVOID_TRANSPARENT_DETACH bit of the GAI_states field of your
GenApplication object. Two examples below:

@object GenApplicatoinClass MyApp = {
    GAI_states = @default | AS_AVOID_TRANSPARENT_DETACH;
}

MyApp = GenApplication {
    appState = default +avoidTransparentDetach;
}

This flag just prevents the app from getting on the list of potential
transparent detach candidates. Sometimes MSG_META_TRANSPARENT_DETACH
will be sent directly to apps to get them to shutdown. In this case
you should intercept MSG_META_TRANSPARENT_DETACH at the application
object and do nothing if the AS_AVOID_TRANSPARENT_DETACH flag is set.


Keyboard driver on N9000.

SDK: N9000C:PUBLIC
There is currently no keyboard driver for the Nokia 9000 Communicator when
running in DOS mode. If you are swatting on a Nokia phone and you
detach Swat you will be returned to a DOS prompt on the phone. You won't
be able to type anything at the DOS prompt, so you'll have to remove
the battery and reinsert it to restart the phone.


Strange glue error.

SDK: ALL_GEOS:PUBLIC
Glue error:
  PASS2MS.C: Line 483: assert(os-1 != ObjFirstEntry(osh, ObjSym)) failed.

Solution:
  You have a resource incorrectly marked as "data." In the
resource definition where you have:

@start ResourceName, data;

take out the ", data" and it should work. The reason this is a problem is
you probably have an @chunkArray defined as the first chunk in the
resource. Another way to fix the bug is to define a dummy chunk. For
instance:

@start CellData, data;
@chunkArray byte myArray = { 3, 3, 4, 5, 6 };
@end CellData;

will cause an error. If you change it to:

@start CellData, data;
@chunk byte dummy = 3;
@chunkArray byte myArray = { 3, 3, 4, 5, 6 };
@end CellData;

or

@start CellData;
@chunkArray byte myArray = { 3, 3, 4, 5, 6 };
@end CellData;

Either way you will avoid the GOC bug.


Running SDK from CD-ROM or network

SDK: ALL_GEOS:PUBLIC
To run an SDK from a CD-ROM or network drive:

Set two environment variables in DOS:

    LOCAL_ROOT : this is where your local application development
             tree lives
    ROOT_DIR   : the root of the CD-ROM/network SDK tree

e.g., if you're running the SDK off the E:\ drive: but your local
development tree is C:\N9000C\APPL, then set:

    set LOCAL_ROOT=E:\PCGEOS
    set ROOT_DIR=C:\N9000C\APPL

Then alter your path to include your ROOT_DIR\BIN:

    set PATH=%ROOT_DIR%\BIN;%PATH%

NOTE:  If E:\ is a CD-ROM drive, then when you compile, you must pass
the -Hu flag to BCC, which will disable the generation of precompiled
header files (*.poh and *.doh) in the ROOT_DIR\INCLUDE directory: this
directory is unwritable on a CD-ROM!

To pass this flag to BCC, create a LOCAL.MK file in your source directory
like this:

#
# Pass -Hu flag to BCC to prevent generation of precompiled
# header files (*.poh, *.doh) in the INCLUDE directory
#
CCOMFLAGS	+= -Hu
#
# Include the standard makefile
#
#include <$(SYSMAKEFILE)>


How to retrieve a Chunk or ChunkArray from a VMFile

SDK: ALL_GEOS:PUBLIC
It is easy to store a LMem block in a VMFile.  To open a VMFile and
retrieve a chunk from its LMem block is a little more challanging.
The reason is that you need the ChunkHandle to dereference the chunk,
but you don't necessarily know what ChunkHandles to use for this newly
loaded block.

Well, actually you do know the ChunkHandle.  The ChunkHandles are stored
in the ChunkHandle table which is referenced by LMBH_offset of the
LMemBlockHeader.  This is most useful when there is only one large chunk
in the block (such as a ChunkArray).  You access the ChunkHandle, like
this:

optr MyGetChunkOptrRoutine(VMFileHandle file, VMBlockHandle block)
{
    LMemBlockHeader *blockHeader;
    MemHandle blockHandle;
    ChunkHandle chunkHandle;

    blockHeader = VMLock(file, block, &blockHandle);

    chunkHandle = blockHeader->LMBH_offset;

    return (ConstructOptr(blockHandle, chunkHandle));
}

If you are storing a LMemBlock with many chunks in it, your best bet is to
save the ChunkHandles to the VMFile's mapblock for easy retrieval.


Debugging tips for difficult problems

SDK: ALL_GEOS:PUBLIC
These suggestions were given by the OmniGo development team who had to
track down several of their more difficult bugs with these techniques.

 - Use showcalls -o to watch how far the application gets before it
   dies.

 - Then put tons of sprintf statements in all suspect routines
   and have them write to a logfile.  You can then further pinpoint
   the problem by examining the logfile.

 - Once you've narrowed down to a particular function, examine
   the code and postulate theories as to how it could be failing.
   Try various solutions until something works.


Using the SDK with Borland C++ 5.0.

SDK: ALL_GEOS:PUBLIC
When using BC 5.0 you must have an even number of methods defined for
your classes. This is because the #pragma option -a is broken in Borland
C++. It hasn't been fixed even in the 5.02 release of Borland C++. GOC
uses this pragma to word align the class structures. Since it is not
working now, you'll have to maintain an even number of methods for each
class you define in your source code. This can be as simple as defining
a dummy method, like this:

@method MyClass, MSG_META_INITIALIZE
{

    @callsuper();
}

Even if the message is never sent to that class, the point is that
you've reserved space for it in the class structure, making the
class structure an even number of bytes long.

This error only shows up if you have more than one class declared, as
in this case:

@classdecl FirstClass;  /* Has an odd number of methods. */
@classdecl SecondClass; /* This class will be messed up, as
                         * well as any subsequent classes. */

There could also be a problem with defining odd-sized global variables.
It could hose the word alignment for the class table, and the tools
wouldn't be able to do anything about it. For example:

  char myHosingArray[3] = { 'a', 'b', 'c' };

  @classdecl MyHosedClass;


Dialogs under the Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
To make program initiatable dialogs look good under the Nokia interface
you have to have a GenInteraction wrapper around the ComplexMoniker
dialog, like so:

@object GenInteractionClass DBFGotoScreen = {
    GI_comp = @DBFGotoScreenBox;
    GII_attrs = @default | GIA_NOT_USER_INITIATABLE;
    GII_visibility = GIV_DIALOG;
}

@chunk TCHAR DBFGotoScreenMoniker[] = _TEXT("Jump To Record");
@object ComplexMonikerClass DBFGotoScreenBox = {
    ComplexMoniker = GenInteractionClass;
    CMI_topText = @DBFGotoScreenMoniker;
    CMI_fontSize = FOAM_NORMAL_FONT_SIZE;
    GI_comp = ...;
    HINT_DRAW_IN_BOX;
    HINT_PLACE_MONIKER_ABOVE;
    HINT_EXPAND_WIDTH_TO_FIT_PARENT;
    HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
    HINT_COMPLEX_MONIKER_DRAW_SEPARATOR;
}


Swat repeatedly reports 'version mismatch' while loading sym files

SDK: ALL_GEOS:PUBLIC
When you start getting "version mismatch" messages during Swat's startup,
you can check one of two things:

 - Your FILES setting in CONFIG.SYS is too low, increase it.  It should
   be at least 80.
 - Your target emulator is out of date. This happens when you install a
   newer version of the SDK but forget to reinstall the target emulator
   software. The host software would then be newer than the target emulator
   and thus you'll get version mismatches.


Get emulators to work more like devices

SDK: ALL_GEOS:PUBLIC
To get the memory in your SDK emulator to work more like an actual
device, disable the swap drivers in the geosec.ini file.  You can do
it like this:
    [system]
    memory = {}	; will only use conventional memory

You can also limit the amount of heapspace available by setting the
maxTotalHeapSpace key in ini file.  The following example limits the
heap space to 496K.
    [system]
    maxTotalHeapSpace = 496


OmniGo file formats

SDK: OMNIGO:PUBLIC
We don't have full information about the file formats since the PIMs
were written by HP in Singapore.  For Apptbook, Phonebook, and
Database the file formats should be compatible with 100LX and 200LX.

The format for storing Notes is somewhat different due to the Note's
ability to store ink.  But the plain text portion of an OmniGo note
record entry is very similar to a 100LX note record (so that an OGo
could still read 100LX notes).

A good place to look is Chapter 7 of the OmniGo book (that is, the GeosSDK
techdoc about the OmniGo).  And also at the sample application in
Appl\SDK_Omni\HPDB.

Here is what information we have about the Notepad and Phonebook (and
Jotter, for what that's worth) files:


Performance profiling your code in swat

SDK: ALL_GEOS:PUBLIC
The following swat commands can help you in finding areas in
your code that need optimizing.

timebrk
    Manipulates breakpoints that calculate the amount of time
    executing between their starting point and a specified ending point.
    The breakpoints also record the number of times their start is hit,
    so you can figure the average amount of time per hit.

tbrk
    Manipulates breakpoints that tally the number of times they are
    hit without stopping execution of the machine -- the breakpoint is
    noted and the machine is immediately continued. Such a breakpoint
    allows for real-time performance analysis.

cycles
    Counts the number of machine cycles a given set of instructions
    takes to execute on a particular processor.


Fax driver INI settings and misc. information

SDK: ALL_GEOS:PUBLIC
1) What are the pertinent .ini settings for fax?

Here are the fax-related ini settings.  I tried to comment things that
don't seem obvious.

[printer]
printers = {
Fax Print Driver on Unknown
Adobe LaserJet II Cartridge (PostScript) on COM2
}
numPrinters = 1
count = 2
numFacsimiles = 1
defaultPrinter = 0

[Fax Print Driver on Unknown]
type = 2
driver = EC Fax Print Driver
device = Fax Print Driver
port = UNKNOWN
intermittent = false

[media]
com2 = 0400000003000000		; tells mailbox fax is available
com3 = 01000000
com1 = 01000000

[FAX]
senderName = Jim Wood who has a very very long name that goes off the page
senderCompany = Geoworks
senderVoiceNum = 206.545.0327
senderFaxNum = 206.545.1050
senderStationID = Jimmy's fax machine

[modemLurker]
detectData = false	; don't look for a data call
detectFax = true	; do answer fax calls
faxAppToken = FAXR	; application to launch on receive
faxAppManID = 0
dataDriver = EC Class 2 Fax Input Driver
dataDriverEntry = 14
autoAnswer = true	; used by faxreceive also
ringThreshold = 1	; "                  "

[faxIn]
faxinDriverName = EC Class 1 Fax Input Driver
class = 2
capabilities = 1,5,0,0,0,0,0,0  ; set via fax preferences
comPort = 2

[faxout]
flags = 6			; FaxoutDialFlags in faxOutDr.def
faxoutDriverName = EC Class 1 Fax Output Driver
class = 1
comPort = 0
capabilities = 05001000
timeout = 30

[coverPage]
path = F:\ensec\userdata\template\fax_temp
scrapbook = Fax templates
scrap = Coverpage template

2) What happens when memory gets low during fax receive?

If we run out when we are about to answer the phone, we don't answer.

If we run out while we are receiveing image data we ignore all the extra
data.  Any data that has already been written to the file will be kept
(so partial pages are not deleted, nor are complete pages).

If we are out of space when we are going to start a page, we end the session.
So, if we ran out of space during page 2, we will wait until we are done with
that page before we end the session (the sender can't be told to stop in the
middle of a page).

If we are unable to save our faxfile because we ran out of space, we delete
the last page and try again, we delete pages until we can save the file.
So in this case you might not actually get a partial page even though we
tried to keep it.  If all the pages get deleted then we nuke the file.

3) Do the faxin drivers and faxrec communicate via gcn lists?

No.  Faxrec (and the faxsend transport driver) register with the
driver they are using.  When they do that they pass an optr, and a few
messages that are to be sent to that optr for whatever communicating
needs to be sent back.

                mov     cx, es:[processHandle]

                mov     ax, MSG_FAXRECEIVE_TIMER
                mov     bx, MSG_FAXRECEIVE_FAX_NOTIFICATION
                mov     bp, MSG_FAXRECEIVE_UPDATE_STATUS

                mov     di, DR_FAXIN_REGISTER
                call    es:[receiveDriver]       ; carry set on failure

So the input driver will be sending MSG_FAXRECEIVE_FAX_NOTIFICATION to the
process object when it wants to send out a FRFN_*

Whenever faxrec is to "send" something back it just calls the driver function
(DR_FAXIN_*)

4) Do the fax in/out drivers run on their own threads?

No.  They run on the thread of the caller.  The faxsend transport driver
creates a thread whose only job is to service the notifications from the
output driver (until the driver is done, then it does cleanup stuff).
Faxreceive uses its process thread to run the driver.


How to resolve Internal Error 177.

SDK: N9000C:PUBLIC
If you recently changed a Generic object to a ComplexMonikerClass
object, and you received an "Internal Error 177" error message
when your program started up, then be sure to fill in the CMI_topText
field. Here is an example:

BAD
---
@visMoniker MyTriggerTitle = "Title";
@object ComplexMonikerClass MyTrigger =
{
    ComplexMoniker = GenTriggerClass;
    GI_visMoniker = @MyTriggerTitle;
    GTI_destination = SomeDialog;
    GTI_actionMsg = MSG_GEN_INTERACTION_INITIATE;
    HINT_SEEK_MENU_BAR;
    HINT_SEEK_REPLY_BAR;
    HINT_SEEK_SLOT = 0;
}

GOOD
----
@chunk TCHAR MyTriggerTitle[] = "Title";
@object ComplexMonikerClass MyTrigger =
{
    ComplexMoniker = GenTriggerClass;
    CMI_topText = @MyTriggerTitle;
    GTI_destination = SomeDialog;
    GTI_actionMsg = MSG_GEN_INTERACTION_INITIATE;
    HINT_SEEK_MENU_BAR;
    HINT_SEEK_REPLY_BAR;
    HINT_SEEK_SLOT = 0;
}

As you can see we don't use GI_visMoniker to specify the visMoniker.
Instead we use the CMI_topText field of the ComplexMonikerClass.


N9000C doesn't support non-exclusive lists.

SDK: N9000C:PUBLIC
Q: A Nokia 9000 spui question: If a non-exclusive GenItem group is
   given the hint HINT_ITEM_GROUP_DISPLAY_CURRENT_SELECTION and more
   than 1 item is selected, how will the selected items be displayed
   in the interaction?
   It would be nice if they were all displayed in a comma-separated
   list.

A: The Nokia 9000 Communicator does not support non-exclusive lists.


How to configure Windows NT so Swat will break on Ctrl-C.

SDK: BETA:PUBLIC, 2.0:PUBLIC, OMNIGO:PUBLIC
This is in regards to the DOS version of the GEOS SDKs.

The problem with Ctrl-C was that I couldn't gain control of the target
PC from the host. I'm running Windows NT Workstation 3.51 on the host
and MS-DOS 7.0 (Windows '95) on the target.

I eventually got it to work by setting the FILES setting from 150 to
170 within my CONFIG.NT file. [The higher the FILES setting the
better.]


Why ATTR_GEN_TEXT_SET_OBJECT_ENABLED_WHEN_TEXT_EXISTS won't work.

SDK: 2.0:PUBLIC
Q: Why can't I get ATTR_GEN_TEXT_SET_OBJECT_ENABLED_WHEN_TEXT_EXISTS
   to work?

A: It has a slight problem in the 2.0 version of the SDK/OS. In
   2.0 the optr is not resolved properly and will cause a system
   crash when a message is sent to the object that is to be made
   enabled. The OmniGo and subsequent versions of the SDK/OS work
   correctly.


What's stored in dgroup?

SDK: ALL_GEOS:PUBLIC
There is no "okay" size for dgroup, you should strive to minimize its
size as much as possible. The dgroup block contains:
 - class structures
 - global variables
 - static local variables
 - static constants and strings that are not in chunks
 - the process thread's stack

If you have static data, like strings, they should be put into chunks
in a data resource. For example, this will get put in dgroup:

    char myLocalStr = "This is a static string\n"

You can use @chunk to put the string in a data resource (see the
sample applications SDK_C\Serial and Serial2).

Other global and static variables should be put into chunks in a data
resource or incorporated into the instance data of an object. The
latter option is best if the variable is mainly used by a single
object.

There isn't much you can do about the class definition table unless
you can consolidate several classes into one, or move the class definition
table into another resource. Moving class definitions into another fixed
block is arguably worse than keeping them all in dgroup.


How to setup VisContent with no children.

SDK: ALL_GEOS:PUBLIC
When you have a VisContent that has no children and you want it to
have a particular size, you should set the VCGA_CUSTOM_MANAGE_CHILDREN
bit of the VCI_geoAttrs field of the VisContent. This will tell the
geometry manager that the content should not try to calculate its own
VI_bounds and thus your content will maintain whatever size you give it.
Otherwise the content will make itself fit the size of its children.
With no children, its size will become zero. When the size becomes zero,
the view takes away the scroll bars/arrows and you cannot interact with
the content via pen input.


Backup/Restore on the N9000

SDK: N9000C:PUBLIC
The present backup/restore application can only back data files
that reside in the Document directory (SP_DOCUMENT) or in a
subdirectory below the Document directory.  Any file in any
such subdirectory will be backed up as part of a "documents" or
an "all data" backup; it doesn't matter how many files belong to
a particular application.


Text object doesn't widen to handle longer string

SDK: ALL_GEOS:PUBLIC
If a text object, when it first appears on screen (Vis part being
built out), has a null string or a short string, it won't widen
itself properly when you replace the string with a longer string.

Adding HINT_EXPAND_WIDTH_TO_FIT_PARENT will work-around this bug.

Alternatively, you could stick in a string with lots of spaces
statically.


Why and when to use EC code.

SDK: ALL_GEOS:PUBLIC
You should use EC code in your geode at every available
opportunity. It will help you catch errors in your program more
quickly and find errors you wouldn't otherwise have caught. Here are
some questions and answers regarding when to use EC code:

Q:
So what is the the theory behind EC code?  How much is good,
and how much is too much?

A:
Put in as much EC code as possible.  It is great for catching bugs
now and in the future (when some other poor soul is maintaining the
code).  A good basic rule is to check all parameters coming into a
function and all values returned from a function call. Also checking
global variables before passing them to a function is a good idea.

The non-EC version of EC routines are just stubs that immediately
return, so EC code will have minimal impact on your application's
performance.  Additionally, you can encapsulate EC routines in the
EC() macro, which will prevent even the stub from being called when
you compile for non-EC.

Q:
Almost every kernel routine (like MemAlloc, FileOpen) can "fail".
Should I add EC routines to check for failure?

A:
No.  You always want your application to handle failures (can't
open the file or can't allocate memory) gracefully in both EC and
non-EC versions.  Routines like ECCheckMemHandle or ECCheckFileHandle
should be used to check variables as they are passed around the
system (when calling routines or messages).  This catches mistakes
like when other programmers accidentally call your routine with the
wrong parameters.


Make non-changing resource blocks read-only

SDK: ALL_GEOS:PUBLIC
If you store read-only data in a resource block, you can mark that
block read-only in your .GP file.  This will allow the system to
discard the block when memory needs to be compacted.

Here's an example of setting a resource as read-only:

    resource TEXTSTRINGS data lmem read-only

For more information about resource flags, see the GP chapter of the
C Reference book.


Broken C-stub: FileCreateLink

SDK: ALL_GEOS:PUBLIC
C Function: FileCreateLink
Date Fixed: 7/25/97

This c-stub was destroying the ds and di registers. There is no
work-around for using this function on devices before the fix
was made.


How to call a driver's strategy routine from C

SDK: ALL_GEOS:PUBLIC
Q:
How do you call a driver's strategy routine from C?

A:
There is a routine in streamc.h called DriverCallEntryPoint that will
do what you want.  Unfortunately, the driver function numbers are
usually not defined in C, so you have to determine them by counting
the DriverFunction (DR_XXX) entries in the def files.  (The first five
DriverFunctions are in driver.def
    0 - DR_INIT
    2 - DR_INIT_WITH_GEODE_HANDLE
    4 - DR_EXIT
    6 - DR_SUSPEND
    8 - DR_UNSUSPEND
so most other drivers continue their numbering from there, i.e. 10.)

Here's examples of accessing two of the stream driver functions:

Setting serial driver event notifications is accomplished thru a call
to the driver geode.  Most of the serial driver functions have
corresponding library routines; the two  of interest that do not are
DR_STREAM_SET_NOTIFY and DR_STREAM_SET_THRESHOLD.  These are accessed
by calling DriverCallEntryPoint and specifying one of the
DR_STREAM_... functions.  DR_STREAM_SET_NOTIFY allows one to setup a
notification message or routine that will be sent/called when a
specific event occurs (data arrives, error occurs).
DR_STREAM_SET_THRESHOLD sets the number of bytes of received/sent data
that will cause a DR_STREAM_SET_NOTIFY event to occur (for the case of
DR_STREAM_SET_NOTIFY being set to STREAM_EVENT_DATA).
DriverCallEntryPoint info and an example usage follow.

extern	void	_pascal
DriverCallEntryPoint (Handle driver,
             word func,
             DriverPassParams *passParams,
             DriverReturnParams *returnParams);

/*
 * func is on of the driver functions to call
 */
#define DR_STREAM_SET_NOTIFY	14
#define DR_STREAM_SET_THRESHOLD	22

/*
 * DriverPassParams is used to pass arguments into DriverCallEntryPoint.  See
 * the specific DR_STREAM_... function in Include\Internal\StreamDR.def for
 * descriptions of which registers need to be set and which will return values.
 */
typedef	struct
{
     word	ax;
     word	bx;
     word	cx;
     word	dx;
     word	si;
     word	bp;
     word	ds;
     word	es;
} DriverPassParams;

/*
 * DriverPassParams is used to return results from DriverCallEntryPoint.
 */
typedef	struct
{
     word	ax;
     word	bx;
     word	cx;
     word	dx;
     word	si;
    word	di;
    word	bp;
    word	ds;
    word	es;
    CPUFlags	flags;
} DriverReturnParams;

/******EXAMPLE FOR SETTING UP NOTIFICATION OF SERIAL DATA EVENT*******
 * DR_STREAM_SET_NOTIFY passes the following and returns nothing.
 *	PASS:ax	= StreamNotifyType that identifies for which side of
 *			  the stream and what event the notifier is being
 *			  registered.
 *		bx	= stream token
 *		cx:dx	= address of handling routine, if SNM_ROUTINE
 *			  destination of output if SNM_MESSAGE
 *		bp	= AX to pass if STREAM_MODE_ROUTINE (except for SNE_DATA with
 *			  threshold of 1, in which case this value is passed in
 *			  CX); method to send if STREAM_MODE_MESSAGE.
/*
    DriverPassParams  dpp;
    DriverReturnParams drp;
    StreamToken serialPort = SERIAL_COM1;

/* set up StreamNotifyType for StreamReader, data event notification
 * (STREAM_EVENT_DATA), and notification mode by a message */
dpp.ax =
      ((1 << STREAM_TYPE_READER_OFFSET) |    /* 1 = reader, 0 = writer */
      (STREAM_EVENT_DATA << STREAM_TYPE_EVENT_OFFSET) | /* data notification */
      (STREAM_MODE_MESSAGE << STREAM_TYPE_HOW_OFFSET)); /* see below about this */
dpp.bx = serialPort;
/* need to confirm the following three lines. */
/*
 * MySerialNotifyObject is the object that contains a method handler for
 * MSG_MSNO_DATA_NOTIFY.
 */
dpp.cx = OptrToHandle(@MySerialNotifyObject);
dpp.dx = OptrToChunk(@MySerialNotifyObject);
dpp.bp = MSG_MSNO_DATA_NOTIFY;   /* message to send to MySerialNotifyObject */

DriverCallEntryPoint(serialDriver, DR_STREAM_SET_NOTIFY, &dpp, &drp);

/* DR_STREAM_SET_THRESHOLD passes the following and returns nothing.
 *	PASS:ax	= StreamNotifyType that identifies for which side of
 *			  the stream and what event the notifier is being
 *			  registered.
 *		bx	= stream token
 *		cx	= threshold (number of bytes that must be available
 *			  for reading, or for which space must be available
 *			  for writing)
/*
dpp.ax = STREAM_ROLES_READER;
dpp.bx = serialPort;
dpp.cx = 1; /* send notification on each byte received */

DriverCallEntryPoint(serialDriver, DR_STREAM_SET_THRESHOLD, &dpp, &drp);


Where to send MSG_META_QUIT

SDK: ALL_GEOS:PUBLIC
Always send MSG_META_QUIT to the application object. The application
object will then initiate the application shutdown sequence by sending
MSG_META_QUIT--with a QuitLevel parameter--to the process and to objects
on the MGCNLT_ACTIVE_LIST (gcn list).

If you send MSG_META_QUIT to the process object you will get a
UI_PROCESS_INVALID_QUIT_LEVEL error. This occurs because you aren't
passing a valid QuitLevel in register DX. Since the application object
is designed to properly handle MSG_META_QUIT, you should avoid ever
sending MSG_META_QUIT to the process object.

See the MSG_META_QUIT comments in Include\metaC.def for more detail
about the operation of MSG_META_QUIT.


Keep getting compiler errors in a scan.c file.

SDK: ALL_GEOS:PUBLIC
Q. When I run "mkmf" on my source code, I get this error:

   Assertion failed: *cp == '\n', file scan.c line 1658
   Abnormal program termination

   What does that mean? What do I need to do to fix it?

A. The cause of the error is simple - you don't have a blank line
   at the end of all your source files. This happens because of a
   bug in one of the C routines (unputc()) that the tools use. A
   resolution to this bug may not be possible, so you'll need to
   maintain a blank line at the end of all of your source code files.

   Note, the error only seems to show up when the last line of a
   source file (either .goh or .goc) has an @endif or #endif and
   is not followed by an EOL (end-of-line) character.


Timeout with SerialRead(STREAM_BLOCK)

SDK: ALL_GEOS:PUBLIC
SerialRead by itself can only block or not block. You will need
to create the block with timeout functionality yourself. This is
fairly easy to do. Simply create a routine that checks the serial
port then sleeps for a bit, then checks again.

For example:

StreamError
SerialReadTimeout( Handle driver,
                   StreamToken stream,
                   word timeout,
                   word buffSize,
                   byte *buffer,
                   word *numBytesRead )
{
    word bytesAvail;

    /*
     * loop until the reqested number of bytes is
     * available or timeout is reached (timeout==0).
     */
    SerialQuery( driver, stream, STREAM_ROLES_READER, &bytesAvail );
    while ( ( bytesAvail < *numBytesRead ) && ( --timeout ) ) {
        if ( bytesAvail < *numBytesRead ) {
            /* sleep one tick (1/60 of second) */
            ThreadSleep( 1 );
        }
        SerialQuery( driver, stream, STREAM_ROLES_READER, &bytesAvail );
    };

    /*
     * at this point, we've either timed out or the
     * requested number of bytes are waiting for us.
     * if timeout, then return a TIMEOUT error (0xff)
     * otherwise call SerialRead().
     */
    if ( timeout == 0 ) {
        /* arbitrarily chose 0xFF to represent timeout on return.
         * It could be whatever you want, though */
        return 0xFF;
    }
    else {
        return( SerialRead( driver, stream, STREAM_NO_BLOCK,
                            buffSize, buffer, numBytesRead ) );
    }
}


About ViewerClass libraries

SDK: N9000C:PUBLIC
The viewer library must exist in the SP_SYSTEM directory (or a
subdirectory).  ViewerLibraryOpen expects VP_libraryName to contain
the path and name of the library relative to SP_SYSTEM.

If you want to check for the existence of the library, you can use
GeodeUseLibrary.  The good thing about this is that it doesn't
slow down the system much because if it loads the library, then
ViewerLibraryOpen doesn't need to (i.e., the library is only
loaded once).  You have to call GeodeFreeLibrary after the call to
ViewerLibraryOpen so that the library can be freed, though.

[vilFileTable]
NOTE = nedit.geo
SMSF = smsed.geo
FAXN = nedit.geo
...>


How to use VisUpdateModes

SDK: ALL_GEOS:PUBLIC
Here is a brief description of how and when to use the various
VisUpdateModes.

    VUM_NOW:
    Use this sparingly!  If you have a *single* object
    to update, you may use it, but it generally causes a huge
    number of geometry invalidations and recalculations to
    occur in your application.

        The easiest way to screw things up is to use VUM_NOW
        indiscriminately.  When in doubt, you should use
        VUM_DELAYED_VIA_APP_QUEUE; intuitively you might think
        it would be slower, but in pratice you're often doing
        multiple updates, so it's usually as fast or faster than
        VUM_NOW.

    VUM_DELAYED_VIA_APP_QUEUE:
    This is the mode you should use if you are invalidating more
    than one object.  For example, if you are changing monikers
    for each item in an item group, you should pass this mode
    along with MSG_GEN_REPLACE_VIS_MONIKER.

    This causes all the geometry invalidations/recalculations
    to occur at once, which is much faster and less prone to
    race conditions.

    VUM_DELAYED_VIA_UI_QUEUE:
    This one should not be used unless you are doing something in
    the system's UI thread, in which case it is used in the same
    context as VUM_DELAYED_VIA_APP_QUEUE.  In fact, VUM_NOW is
    rarely used in the UI: using it during updates can result
    in infinite recursion.

    VUM_MANUAL:
    This one is typically used for synchronization between
    threads.  For example, if you have objects that are being
    updated on your UI thread, but you must wait for your process
    thread to finish doing something before displaying the results,
    you should use this mode, and then do the invalidation
    yourself.

    Use VUM_MANUAL with caution!  It's easy to forget to do the
    invalidation, in which case your app will be in an
    indeterminate state.


How to intercept dialog close message.

SDK: ALL_GEOS:PUBLIC
Section 7.4.2 Dismissing Interactions in the Objects manual covers
how to intercept the MSG_GEN_GUP_INTERACTION_COMMAND message. This
message is sent when the dialog is being closed either through
system control or by a user response.

For instance, if you have a dialog with several different triggers
and the user can click on any one of these, you might want to
intercept this message to see which button was pressed. You can also
use it to see if the dialog is being shutdown. This occurs when the
application is told to shutdown by the system. The InteractionCommand
value will be IC_NULL.


'no valid font files in userdata\font' when running under Windows 95

SDK: ALL_GEOS:PUBLIC
RUNNING GEOS EMULATOR WITH WINDOWS95

The following tips work on most PCs.  If, after running through these
steps, the Geos emulator still doesn't work, try re-installing it and
then running thru the steps.

1. From the MS-DOS prompt, type the following commands, substituting
the drives and paths for your particular system:

 SETVER  LOADER.EXE 5.0
 SETVER  LOADEREC.EXE 5.0

In most cases,  is "C:\WINDOWS".

As an alternative, you can add a line like this to the [system]
section of the GEOS.INI file in the emulation:

  fs = ms4.geo

For the EC version, use  "fs = ms4ec.geo"

This forces Geos to load the appropriate file system driver,
since the kernel was written before DOS 7 and doesn't know
which driver to use.

2. Close the MS-DOS window and choose Start/Shut Down/Restart the
   computer.

3. Once you are back in Windows, Right-click Start and choose Explore.

4. In the Explorer, switch to the Drive containing the Geos emulator
   folder and double-click to open the folder.

5. Scroll down and find the LOADER (or LOADEREC) file that has the
   MS-DOS icon.  Right-click the file icon and choose Properties.
   Check to see that the file is a Shortcut to MS-DOS Program and
   the filename LOADER.PIF.  This is the file you want.

6. In LOADER Properties, click the Program tab. Check to see that the
   path and working directory is correct to your LOADER folder. If
   the drive letter is wrong, change it. Click Apply.

7. In LOADER Properties, click the Advanced button. Examine the
   following two items. Check them as below and then click OK.

    [X] Prevent MS-DOS-based programs from detecting Windows.
    [ ] Suggest MS-DOS mode as necessary.

8. Click the Memory tab. Check to see that all items are set to Auto.
   (In addition, you may try leaving the Memory Properties for
   Conventional Memory/Protected UNCHECKED and Extended (XMS)
   Memory/Uses HMA CHECKED.)

9. Click the Screen tab. Set Usage to Full-screen, initial size:
   Default. Leave Window and Performance buttons CHECKED. Click Apply
   and click OK.

10. You should be able to double click on the LOADER.PIF file -- the
    one with the MS-DOS icon -- and successfully launch the emulator.

11. If you get a KR-01 error, edit the GEOS.INI for the emulator
    and change "continueSetup = true" to "continueSetup = false".


When to use ObjDerefGen/ObjDerefVis

SDK: ALL_GEOS:PUBLIC
pself is automatically set to point to an object's instance data
at the start of a method handler (except as noted below).  There
are conditions when you will need to re-dereference pself in the
method handler.  These conditions are:

+ You need to redereference after calling any message and after
  @callsuper.

+ If the class is a master or variant (has either keyword in the
  class definition), then you need to dereference pself at the
  beginning of the method.  (If your class is a subclass of a
  standard Geos class, then you do not need to dereference at
  the beginning.)


PCCom protocol (for OmniGo)

SDK: OMNIGO:PUBLIC
This info is specific to the PCCom protocol used by the OmniGo 100
Transfer application.  It is current as of Februrary 1996.
The following commands should work on future versions of the PCCom
library.  However future versions may contain extra commands not
listed below.

The PCCom Library utilizes a simple file transfer protocol.
Basically, send  to signal the beginning of a command.  Then send
the two character command plus any parameters.  Terminate the command with
'!'.

Here is a list of the current PCCom commands:

AD!
    Available drives.  Displays all the drives known to the system with
    their disk labels.

AK(On|Off)!
    Turns acknowledgement on or off.  If ack is on, whenever a
    transaction is successfully complete, the host will receive
    ACK and display "Ack Received."; if a transaction is
    unsuccessful, the host will receive NAK and display
    "Nak Recieved."

    By omitting On|Off arg, you can get the current status of
    acknowledgement.  This can be used to "ping" the remote unit.

CD!
    change to the specified drive or directory

CP!!
    Make a copy of the file named  and name the copy

EB(On|Off)!
    Turns echo back on or off.  If echo back is on, all the output to the
    server side is echoed back to client.  If argument is omitted, displays
    the current status of echo back.  On/off string is case insensitive.

EX
    Exit.  Tells the remove PCCom to close the serial connection.

FS:!
    Displays the amount of free space in the specified driver.  If path is
    omitted, displays free space on current driver.

LL!
    Long listing of files. LL command displays the following in addition to
    normal LS command:
      DOS attributes, a: archive
              d: sub directory
              v: volume file
              s: system
              h: hidden
              r: read only
      GEOS name, 	  32 char file name
      release number,
      creator,
      token,
      protocol number,

    Creator and other geode token are displayed in the following format:
        "4-letter token"[Manufacturer's ID number]

LM!
    Medium listing of files. This is LL without creator, geode token, and
    protocol number.  As you will notice, LL will display 2 lines of info
    per file.  LM displays one line per file.

LS!
    List the directory contents.

MD!
    Create a directory with the given name.

MV!!
    rename the file from  to

RD!
    Remove the directory with the given name.

RF!
    Delete the file of the given name.

XF
    Transfer a file.  This is fairly involved.  The following
    describes the transfer protocol.

  These constants will be used in the explanation below.

  ACK		equ	0		; everything OK
  NAK		equ	1		; not OK, try again
  NAK_QUIT	equ	2		; not OK, give up
  SYNC		equ	0ffh

  BLOCK_START		equ	01h
  BLOCK_END		equ	02h
  BLOCK_QUOTE		equ	03h

  There can be at most 1K of data per block, and since BLOCK_START,
  BLOCK_END, and BLOCK_QUOTE are reserved values, any data with one of
  these values must be "quoted".

  The CRC value for a block of data is a word calculated using the
  algorithm described below, in CalcCRC().

  ------------------------------------------------------------------------
  SENDING A FILE
  ------------------------------------------------------------------------

  Sending a file to the remote machine involves the steps below. A file
  may be sent by any program that can access the serial port.

  Note that if the block is not received correctly the first time,
  the receiver will give up after 3 more attempts to receive it.

  If you want to make the sending of the filename more robust, you can
  send it in the first data block, which contains this data:

      !PCCom File Transfer Filename Block!

  Calculate the CRC for this block in the usual manner, but send CRC+1.
  This special block should only be re-sent 1 time if it is not successfully
  received, instead of the normal 3 times.

send XF<0x1>				(alert PCCom a file is coming )
send      	    	(destination file name)
read byte
wait for SYNC
send
while (not EOF) {
  resend:
    if (first block) {	    	    	    	(this part is optional)
        send BLOCK_START
    send the special block
        send BLOCK_END
    send CRC + 1
    } else {
        send BLOCK_START
    while (more bytes in block) {
            get next byte in block
        if (byte == BLOCK_START, BLOCK_END, or BLOCK_QUOTE) {
            send BLOCK_QUOTE
        send (byte + BLOCK_QUOTE)
        }
        else
            send byte
        endif
    }
    send BLOCK_END
    send CRC (word value, send low byte first)
    read byte
    if (byte == NAK)
        goto resend
    elif (byte != SYNC)
        quit
    endif
    read next block from file
    }
send byte 0
send byte 0
wait for ACK

  ------------------------------------------------------------------------
  RETRIEVING A FILE
  ------------------------------------------------------------------------

  Retrieving a file from a machine running PCCom is straightforward
  and uses the same file transfer protocol shown above for sending a
  file. The sequence of commands is different, however, and is listed
  below.  There is no special first block for file retrieval analagous
  to that for file send.

  Note that if the PCCom library does not get a SYNC after sending a
  block of data, it will resend it 3 more times before giving up.

send XF<0x4>			    (alert PCCom you want a file)
send      	    (source file name, can contain
                                                  wildcard characters)
wait for SYNC 	    	    	    	    (PCCom must acknowledge receipt
                                                  of the file name)
while (read byte == SYNC)    	    	    (wait for PCCom to find next file)
  read 	    (the destination file name)
  send SYNC
  read filesize (dword)
  while (filesize > 0) {
    read byte
    if (byte = BLOCK_START) {
        while (read byte != BLOCK_END) {
        if (byte == BLOCK_QUOTE) {
            read byte
            byte = byte - BLOCK_QUOTE
        }
        write byte to output buffer
        filesize = filesize - 1
    }
    read CRC
    if (CRC = CalcCRC(buffer))
        send SYNC
        write buffer to destination file
    else
        send NAK
    endif
    else
        send NAK
    endif
    }
  read checksum (word)
  if (checksum == 0)
    send ACK
  else
    send NAK
  }

 *---------------------------------------------------------------------*
         CalcCRC
 *---------------------------------------------------------------------*
  SUMMARY:	Calculate the CRC on a block of data.
  PASS:		char *buf		Pointer to the data buffer
         short size		Size of the data buffer
         short checksum		Previous checksum (0 at first)
  RETURN:	CRC value (2 bytes)
 *---------------------------------------------------------------------*

short	crcTable[] = {
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

unsigned short		IncCRC(unsigned short crc, char c){
    return ((crc << 8) ^ crcTable[((crc >> 8) ^ c) & 0xff]);
}

short		CalcCRC(char *buf, short size, short checksum){
    for (;size >= 0; size--){
     checksum = IncCRC(checksum, *buf++);
    }
    return checksum;
}


Example of AccessPointControlClass and how to use it.

SDK: N9000C:PUBLIC
Q. How do N9000C applications usually select the access point to use
   if there are several alternative choices in TCP/IP domain?

A. An AccessPointControlClass object is used. Here is an example of
   how such an object would be defined.

   @chunk TCHAR AccessPointText[] = "Internet access points";
   @object ComplexMonikerClass AccessList = {
    ComplexMoniker = AccessPointControlClass;
    CMI_iconBitmap = CMB_SERVICES_DEFINE;
    CMI_topText = @AccessPointText;
    CMI_textStyle = @default & TS_BOLD;
    GCI_output = process;
    APCI_editMsg = MSG_SERVICES_EDIT_ACCESS_POINT;
    APCI_accessType = APT_INTERNET;
    ATTR_GEN_CONTROL_REQUIRE_UI = (APCF_LIST | APCF_EDIT);
    ATTR_COMPLEX_MONIKER_PLACE_BITMAP_AT_LEFT;
    HINT_INDENT_CHILDREN;
    HINT_DRAW_IN_BOX;
    HINT_DRAW_SHADOW;
    HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
    HINT_FIXED_SIZE = {
            ( SST_PIXELS | FOAM_DEFAULT_COMPONENT_WIDTH ),
            0,
            0
        };
   }

Q. If I go to see the list of available internet access points I only
   see the access point name of each entry in the list. That name would
   be an obvious choice for a "key" to find one specific access point?

A. The user identifies access points by name. The system identifies them
   by their ID number. The access point controller displays the names to
   the user, and passes the ID number of the selection to the
   application. The ID is what is used as part of the address.

   Applications should keep track of the ID internally and translate that
   to the name only when displaying the access point to users. This way
   the most current name will always be displayed. If the user types in
   a name, translate it to the ID immediately and store that.

Q. If so, it is still somewhat unclear what property to search for when
   using AccessPointGetStringPropertyBuffer() to find the name of the
   access point name displayed in the access point list?

A. You'd do something like this:

   AccessPointGetStringPropertyBuffer( myid,
                                       (char*)APSP_NAME,
                                       &mybuf,
                                       &buflen );


GenTriggers and IC_XXXX (InteractionCommands)

SDK: ALL_GEOS:PUBLIC
Using ATTR_GEN_TRIGGER_INTERACTION_COMMAND and GenTriggers:

1/  ATTR_GEN_TRIGGER_INTERACTION_COMMAND only works on a GenTrigger
    if BOTH GTI_destination AND GTI_actionMsg are NOT SET.

    If either is set, the ATTR_GEN_TRIGGER_INTERACTION_COMMAND will be
    ignored.

2/  Each GenTrigger in a single dialog box must use a unique
    InteractionCommand.  I.e., you cannot have two triggers in
    a single dialog box both return IC_DISMISS.

3/  If you want two triggers to return the same InteractionCommand,
    set ATTR_GEN_TRIGGER_INTERACTION_COMMAND = {IC_XXXX} on one,
    and have the other send a message, whose method sends MSG_GEN_GUP_-
    INTERACTION_COMMAND(IC_DISMISS) back to the dialog.


Finding the total size of an LMem block

SDK: ALL_GEOS:PUBLIC
Question:
==========
When I type "lhwalk" for an object block of an application, Swat
tells me the size is 4524 bytes.  When I add up the sizes of the
objects & chunks within the block, however, I get 4269 bytes.

Swat also tells me the number of handles for this block is 40, so
I figure another 80 bytes for the chunk handle table.  Add in another
16 bytes for the LMemBlockHeader and the total is 4365 bytes.

Additionally, Swat says there is no free space, and it shows no free
chunks in the lhwalk.  So why the discrepancy (4524 vs 4365) ?
What am I doing wrong ?

Answer:
========
What you're forgetting is the overhead in chunk sizes.

Remember that chunks are padded to be dword-aligned.  Also, the
size of the chunk is stored in the word preceding the chunk data.
So, each chunk has different overhead: 2 to 5 bytes for each chunk.

Here's how to calculate the exact LMem block size:

  LMBH_blockSize = chunk sizes + free space + LMem header +
                   Chunk Handle table size + chunk size overhead

                 = sum( chunk sizes ) + LMBH_totalFree + LMBH_offset +
                   (LMBH_nHandles x 2) + sum( overhead )


Pmake hangs with McAfee virus checker

SDK: ALL_GEOS:PUBLIC
It has been reported that pmake will freeze up on some PCs when
the McAfee virus checker is set to check all files.  The problem
occurs when pmake creates its temporary files.

To fix the problem, set McAfee to only check executables.


How to print a formatted string to a file

SDK: ALL_GEOS:PUBLIC
Q:
I went looking for fprintf, but didn't find it.  Is there something similar
to print a formatted string to a file in GEOS?

A:
What you can do is sprintf to a string variable and then write the string
variable to file using FileWrite.


How to set breakpoints in foam library routines.

SDK: N9000C:PUBLIC
Q. Why won't swat let me switch to the foam library thread?  I'm trying
   to break in one of the foam routines (FoamGetFreeDiskSpace), but swat
   says that "foam has no current frame" or "illegal address".

A. Don't try to switch to the foam thread, since there is none.
   You can set the breakpoint like this (by specifying the library):

    brk foam::FoamGetFreeDiskSpace

   or by setting "sym-default foam" and then setting the break point
   normally: "brk FoamGetFreeDiskSpace"


Making your application FileTransfer friendly.

SDK: N9000C:PUBLIC
If you're writing a Nokia 9000 application that creates, views, edits, or
otherwise opens documents, here are a couple of things that need to happen
for those documents to be properly transferred to and from a PC through the
connectivity application while your app is accessing the files.

Briefly, the way that the connectivity apps transfer files is this: an
initial attempt is made to FileOpen the document in question with Read/Write
and deny Read/Write permissions; if the file isn't currently in use by one
of the other applications in memory, then this FileOpen should succeed, and
the transfer will commence.

However, if another application has the file open, the FileOpen will error
with ERROR_SHARING_VIOLATION. At this point, the connectivity app will
attempt to contact that particular application and ask that it relinquish
its hold on the file long enough to complete the transfer. The way it does
this is to look up the file in the document registry for an owner of
the file. If your application has a file open and *doesn't* register the
file by calling IACPRegisterDocument, then there will be no way for the
connectivity app to contact your application, and the transfer of that
particular document will fail. This, then, is the first requirement:

 * If your application opens any file that could potentially be
 * transferred by the connectivity apps (which is basically everything
 * under the DOCUMENT directory, the contact database, and calendar
 * data), then it needs to register those files with the document
 * registry via IACPRegisterDocument.

Once the connectivity app connects with your app, it'll send a
MSG_META_IACP_ALLOW_FILE_ACCESS and wait for your app to process the
message before it tries opening the file again. The second requirement,
then:

 * Your application must handle MSG_META_IACP_ALLOW_FILE_ACCESS
 * to close the file in question down. Or, you can add the hint
 * HINT_APPLICATION_QUIT_ON_IACP_ALLOW_FILE_ACCESS to your app
 * object, which should cause your application to transparently
 * detach, which will hopefully close any files it had open.

When the connectivity application is finished transferring the document,
it sends MSG_META_IACP_NOTIFY_FILE_ACCESS_FINISHED over the same
connection to let the app know that it's OK to reopen the file, if it
hadn't shutdown in the first place. If it had shut down, then you need to
gracefully handle the case where your data file changes between sessions.

 * Your application must not save information to its state file
 * that might cause problems if a data file disappears, appears,
 * or changes in any other way between sessions.


Perl installation error

SDK: ALL_GEOS:PUBLIC
When installing perl, if you get the error:

 "Couldn't retrieve path information from session manager!!
  Win32::RegSetValueEx: Type not specified, cannot set Path"

You can finish the install by manually adding perl information
to your Registry. To do this, launch RegEdit and add the following
string entries under HKEY_LOCAL_MACHINE\SOFTWARE\ActiveWare\Perl5:

      BIN
      PRIVLIB

Also add the following key to HKEY_CLASSES_ROOT

    .pl	"Perl"


How to determine available memory for an application

SDK: ALL_GEOS:PUBLIC
There are several ways your application can reserve or check for the
largest available block size.

First and foremost, you can use GeodeRequestSpace(). This will check
to see if the desired space is available. If it is, it reserves the
space and returns a "reservation" handle. Then allocate and use the
memory you need. When done, free the memory and call GeodeReturnSpace()
to free the reservation.

To simply poll the system, you can use SysGetInfo(SGIT_LARGEST_FREE_BLOCK).
This returns a dword that contains the size of the largest available
memory block (the size is in paragraphs (1 paragraph = 16 bytes)).

Another thing you can do to check mem size is to do a MemAlloc with
the desired size. If it returns null handle, then you know that there
wasn't enough space. One benefit of this option over the SysGetInfo
option is that, if the largest free block isn't big enough, MemAlloc
will compress the memory in an attempt to create a memory block that
is large enough.


Determining free disk space with DiskGetVolumeFreeSpace()

SDK: ALL_GEOS:PUBLIC
To determine the approximate* disk space available to your
application, call DiskGetVolumeFreeSpace.  This routine
will show how much space is still available on the given
disk.

* - The word "approximate" is used because other applications may
  be simultaneously writing files to disk, which means the actual
  available disk space may vary.


Using FoamStandardDialogOptrNoBlock vs PutUpDialogViaUIThread

SDK: N9000C:PUBLIC
Q. Can FoamStandardDialogOptrNoBlock be used in place of
   PutUpDialogViaUIThread?

A. Well, this is a little tricky. Here are the issues, if you don't
   use FoamStandardDialogOptrNoBlock:

1) The dialog has to be runnable by the system UI thread (not your
   application), which means you have to use a template dialog, and
   call UserCreateDialog from the UI thread (see how to do this below).

2) Since you want a no-blocking dialog (since you cannot put up a
   blocking dialog on the UI thread) you need some way to make the
   dialog free itself when it goes away. Hence, the dialog box itself
   should not be an instance of GenInteraction, but rather an instance
   of SelfDestroyingDialogClass.

   If you use FoamStandardDialogOptrNoBlock, it handles creating and
   freeing the dialog for you, so you don't have to worry about the above
   issues. You *do*, however, need to call it from the UI thread. Here's
   how to do it:

    1) Get the handle of the UI thread:

        ThreadHandle uiHandle;
                optr         uiOptr;
        uiHandle = SysGetInfo( SGIT_UI_PROCESS );

    2) Send a message to the UI thread, passing a routine that will
       be called on that thread:

                uiOptr = ConstructOptr( uiHandle, 0 );
        @call uiOptr::MSG_PROCESS_CALL_ROUTINE(
                    0, 0, 0, 0, 0, 0, DisplayDialog );

    3) Have that routine call FoamStandardDialogOptrNoBlock

        void DisplayDialog() {
            ...
            FoamStandardDialogOptrNoBlock(...)
            ...
        }

   You can either have separate routines for each dialog you display,
   or change your DisplayDialog routine to have some assembly code
   that accepts parameters in registers.


Protocol levels of libraries on various Geos Devices

SDK: ALL_GEOS:PUBLIC
        Ensmbl	Casio	Ensmbl	HP OGo	Nokia
Geode		2.0	Z-7000	2.01	100	9000C
=====================================================
accpnt		-.-	-.-	-.-	-.-	3.1
ansic		1.1	1.1	1.3	1.5	1.5
ascii		4.0	4.0	4.0	4.0	-.-
bitmap		8.0	8.0	8.1	-.-	-.-
bmp		4.0	4.0	4.0	-.-	-.-
borlandc	1.0	1.0	1.0	1.0	1.0
cardid		-.-	-.-	-.-	1.0	-.-
cards		111.0	111.0	111.0	111.0	-.-
cell		3.0	3.0	3.0	3.0	3.0
chart		6.0	6.0	6.1	-.-	-.-
clp		4.0	4.0	4.0	-.-	-.-
color		2.0	2.0	2.0	2.0	2.0
compress	1.0	1.0	1.0	1.0	1.0
config		9.0	9.0	9.2	-.-	9.6
connect		-.-	-.-	-.-	-.-	21.0
contlog		-.-	-.-	-.-	-.-	5.0
contdb		-.-	-.-	-.-	-.-	2.2
convert		1.0	1.0	1.0	-.-	-.-
conview		-.-	-.-	-.-	1.1	-.-
csv		4.0	4.0	4.0	-.-	-.-
cvttool		1.0	1.0	1.0	-.-	-.-
datepick	-.-	1.0	-.-	-.-	-.-
db		-.-	-.-	-.-	2.0	-.-
dbase3		4.0	4.0	4.0	-.-	-.-
dbase4		4.0	4.0	4.0	-.-	-.-
dhcp		-.-	-.-	-.-	-.-	0.0
dib		1.0	1.0	1.0	-.-	-.-
dwrite		4.0	4.0	4.0	-.-	-.-
eps		4.0	4.0	4.0	-.-	4.1
faxctrl		-.-	-.-	-.-	-.-	3.0
faxfile		-.-	-.-	-.-	-.-	3.5
faxvw		-.-	-.-	-.-	-.-	1.0
foamdb		-.-	-.-	-.-	-.-	2.5
foam		-.-	-.-	-.-	-.-	14.0
ffile		29.0	29.0	29.0	-.-	-.-
gadgets		-.-	-.-	-.-	4.1	-.-
game		2.0	2.0	2.0	2.0	2.0
geos		654.1	654.3	654.16	654.33	654.51
gif		4.0	4.0	4.0	-.-	-.-
grobj		534.0	534.0	534.1	-.-	-.-
hpmlib		-.-	-.-	-.-	3.0	-.-
hprefcn		-.-	-.-	2.0	-.-	-.-
impex		14.0	14.0	14.1	-.-	14.1
int8087		1.0	1.0	1.0	1.0	1.0
intx87		1.0	1.0	1.0	-.-	1.0
irlmp		-.-	-.-	-.-	-.-	0.2
jedidemo	-.-	-.-	-.-	1.0	-.-
jedit		-.-	-.-	-.-	1.3	-.-
jerror		-.-	-.-	-.-	1.1	-.-
jlib		-.-	-.-	-.-	1.2	-.-
jotter		-.-	-.-	-.-	1.1	-.-
jtable		-.-	-.-	-.-	4.0	-.-
jutils		-.-	-.-	-.-	1.3	-.-
jwtime		-.-	-.-	-.-	5.0	-.-
key		-.-	-.-	-.-	1.0	-.-
log		-.-	-.-	-.-	-.-	0.0
lot123		4.0	4.0	4.0	-.-	-.-
lot123ss	4.0	4.0	4.0	-.-	-.-
mailbox		-.-	-.-	-.-	-.-	3.2
math		7.0	7.0	7.2	7.2	7.2
mmate		4.0	4.0	4.0	-.-	-.-
msmfile		1.0	1.0	1.0	-.-	-.-
msword		4.0	4.0	4.0	-.-	-.-
mtable		-.-	-.-	-.-	1.0	-.-
nedit		-.-	-.-	-.-	-.-	1.0
net		5.2	5.2	5.2	-.-	5.2
netutils	-.-	-.-	-.-	-.-	1.3
notes		-.-	-.-	-.-	2.9	-.-
outbox		-.-	-.-	-.-	-.-	0.0
palm		-.-	-.-	-.-	2.0	-.-
parse		4.0	4.0	4.2	4.2	4.2
pccom		-.-	-.-	-.-	1.0	1.1
pcmcia		-.-	-.-	-.-	1.1	-.-
pcx		4.0	4.0	4.0	-.-	-.-
pen		1.0	1.1	1.3	1.5	-.-
prefbg		2.0	2.0	2.0	-.-	-.-
prefcomp	2.0	2.0	2.0	-.-	-.-
preffont	2.0	2.0	2.0	-.-	-.-
prefintl	-.-	-.-	2.0	-.-	-.-
prefkbd		2.0	2.0	2.0	-.-	-.-
preflf		2.0	2.0	2.0	-.-	-.-
preflink	2.0	2.0	-.-	-.-	-.-
preflo		2.0	2.0	2.0	-.-	-.-
prefmous	2.0	2.0	2.0	-.-	-.-
prefos		2.0	2.0	2.0	-.-	-.-
prefsnd		2.0	2.0	2.0	-.-	-.-
preftd		2.0	2.0	2.0	-.-	-.-
prefts		2.0	2.0	2.0	-.-	-.-
prefuic		-.-	-.-	-.-	-.-	-.-
prefvid		-.-	2.0	2.0	-.-	-.-
resolver	-.-	-.-	-.-	-.-	0.1
respondr	-.-	-.-	-.-	-.-	0.6
rtf		4.0	4.0	-.-	-.-	-.-
rtcm		-.-	-.-	-.-	1.0	1.0
ruler		6.0	6.0	6.1	6.1	6.1
rwtime		-.-	-.-	-.-	-.-	0.1
saver		15.0	15.0	15.0	-.-	15.0
security	-.-	-.-	-.-	-.-	3.0
shell		5.0	5.0	5.0	-.-	-.-
smsed		-.-	-.-	-.-	-.-	5.0
smsend		-.-	-.-	-.-	-.-	0.0
socket		-.-	-.-	-.-	-.-	3.4
sound		4.0	4.0	4.1	4.3	4.4
spell		105.0	105.0	105.0	-.-	-.-
spline		11.0	11.0	11.1	-.-	-.-
spool		621.0	621.0	621.2	621.4	621.6
ssheet		12.0	12.0	12.0	12.2	-.-
ssmeta		2.0	2.0	2.0	2.0	2.0
streamc		-.-	-.-	-.-	1.1	1.2
styles		1.0	1.0	1.0	1.0	1.0
swap		601.0	601.0	601.1	601.1	601.1
table		-.-	-.-	-.-	3.1	-.-
telnet		-.-	-.-	-.-	-.-	1.0
text		3.0	3.1	3.2	3.13	3.15
tif		4.0	4.0	4.0	-.-	-.-
ui		743.1	743.2	743.3	743.9	743.20
viewer		-.-	-.-	-.-	-.-	1.4
vsstb		-.-	-.-	-.-	-.-	0.0
winword		4.0	-.-	4.0	-.-	-.-
wperf4		4.0	-.-	4.0	-.-	-.-
wperf5		4.0	-.-	4.0	-.-	-.-
wstar		4.0	-.-	4.0	-.-	-.-
xywrite		4.0	-.-	4.0	-.-	-.-
zoomconn	2.0	2.0	-.-	-.-	-.-
zoomdgtz	2.0	2.0	-.-	-.-	-.-
zoomer		-.-	6.0	-.-	-.-	-.-
zoomhw		-.-	2.0	-.-	-.-	-.-
zoomintl	-.-	2.0	-.-	-.-	-.-
zoomkbd		-.-	2.0	-.-	-.-	-.-
zoomprnt	-.-	2.0	-.-	-.-	-.-
zoomtd		-.-	2.0	-.-	-.-	-.-
zoomuser	-.-	2.0	-.-	-.-	-.-

Notes:
1) "-.-" denotes the geode is not resident on the given device

2) devices are:
    Ensmbl 2.0   = Ensemble 2.0 (desktop OS)
    Casio Z-7000 = Casio Z-7000 (PDA)
    Ensmbl 2.01  = Ensemble 2.01 (desktop OS)
    HP OGo 100   = HP OmniGo 100 (PDA)
      Nokia 9000C  = Nokia 9000 Communicator (Smart Phone)


How do you call a library function written in C, from assembly?

SDK: ALL_GEOS:PUBLIC
Q:
How do you call a library function written in C, from assembly?

A:
There are a variety of issues which need to be adressed in order to answer
this question.

Return value
------------
If the function is defined to return a word, the value will be stored in
register ax, and dx will be trashed.

If the function is defined to return a dword, the high word of the value
will be in dx, and the low word in ax.

Calling convention
------------------
If the function is defined as _cdecl:
o	Arguments are pushed onto the stack from right to left. As you'd
    expect, an argument that requires more than a word is pushed so as
    to be stored properly as a variable on the stack
o       The calling function is responsible for removing the arguments from
    the stack when it is returned to.
o	The global name of the function (i.e. the name that the linker sees
    and that you must use when writing in assembly) is formed by
    prepending an underscore ('_') to the mixed-case version of the name.

If the function is defined _pascal:

o	Arguments are pushed onto the stack from left to right. As you'd
    expect, an argument that requires more than a word is pushed so as
    to be stored properly as a variable on the stack.
o	The called function is responsible for removing the arguments from
    the stack when it returns.
o	The global name of the function (i.e. the name that the linker sees
    and that you must use when writing in assembly) is formed by
    upcasing all letters in the mixed-case version of the name.

Examples

If the function is defined as

    word _cdecl foo(word a, word b)

the assembly code would be :

    push b
    push a
    call foo	; es, di, si, bx, cx trashed, ax holds return value
    add sp, 4	; restore the stack from before the 2 pushes

If the function is declared as

    dword _pascal foo(word a, word b)

the assembly code would be :

    push a
    push b
    call FOO  ; es, di, si, bx, cx trashed, dx.ax holds return value
    ; callee pops args off stack


File operations applied to directories.

SDK: ALL_GEOS:PUBLIC
Q. Do file operations apply to directories. In other words, can you
   rename a file by calling FileRename?

A. In this case, yes, renaming a directory is done using
   FileRename. The File Manager source code at
   http://members.aol.com/nfiedler/software.html does
   renaming, moving, copying and deleting of files and
   directories.

   Here is a summary of operations for files and directories:

   Operation    File        Folder (aka directory)
   -----------------------------------------------
   Rename       FileRename  FileRename
   Delete       FileDelete  FileDeleteDir
   Move         FileMove    n/a
   Copy         FileCopy    n/a

   In the case of moving or copying directories you'll have to manually
   do the necessary FileDeleteDir and FileCreateDir. You'll also have
   to move all of the contents of the directories manually. Again, see
   the File Manager source code for examples.


How to make SocketRecv() event-driven.

SDK: N9000C:PUBLIC
Q. Can the API SocketRecv() be made event-driven? That is, can I
   "register" a callback function and have it called back whenever
   the status of SocketRecv() changes?

A. There is no direct way to receive data in an event driven manner,
   so you will need to set up a thread to scan for data. Spawn a
   separate thread to have a loop that calls (and blocks on)
   SocketCheckReady, and sends out appropriate messages or call the
   callback routines when something changes.


How to call a C function from assembly.

SDK: ALL_GEOS:PUBLIC
Q. How do you call a C routine, from assembly?

A. Declare the routine name as "global" in assembly so the assembly
   compiler knows the routine is declared in another source file.
   Example:
    global	DRIVERINIT:far

   If the C function is defined as a standard routine (either the
   "_cdecl" flag or no routine type flag), then your push the
   parameters in reverse order, call the routine, then fix the
   stack pointer (SP).  For example:

   routine defined in C code as:
     word _cdecl foo(word a, word b)

   assembly code would do this:
     push b
     push a
     call _foo ; es, di, si, bx, cx trashed, ax holds return value
     add sp, 4 ; 4 is the two word-sized parameters, you could also
           ; use the "pop" command twice.

   If the function is defined as pascal type, then you push the
   parameters in order they are defined in the routine and call
   the routine name in all uppercase.  Example:

   routine defined in C code as:
     dword _pascal foo(word a, word b)

   assembly code:
     push a
     push b
     call FOO  ; es, di, si, bx, cx trashed, dx.ax holds return value
     ; don't need to fix up stack pointer because C routine does that

NOTE: if possible, you should define your C routines with the _pascal
pragma.  The pascal calling convention is smaller and faster than the
C calling convention.

---------- Here's some sample code as an example ----------

**In the .def file:

; Define the following assembly and C routines as globally available.
    global    POWERONOFFCALLBACK:far
    global    CALLINTOC:far

**In the .goh file:

/* Declare globally available C routines. */
extern void
    _pascal PowerOnOffCallBack( word onOffValue );

**In the .asm file:

; Assembly function that will call C function.
callbackCode segment

CALLINTOC proc far
    uses ax
    .enter

    push ax
    call POWERONOFFCALLBACK

    .leave
    ret

CALLINTOC endp

callbackCode ends

; We don't know the segments for the C routines, so don't report errors.
.warn -unknown

**In the .goc file:

extern void _pascal
PowerOnOffCallBack( word onOffValue )
{
    ...
}


How to use the IrCOMM API.

SDK: N9000C:PUBLIC
Q. What's the fastest way to push a couple of bytes out the Ir port
   on the N9000? In other words, can I talk to the Ir port just as
   a serial port?

A. The IrCOMM API is the same as the serial driver API defined in
   streamC.h. However, you should use TinyTP instead of IrCOMM,
   unless there is a particular reason to use IrCOMM.

   Look in irlmp.h for TinyTP info and routines.


Use the Bison font for password entry

SDK: ALL_GEOS:PUBLIC
Q. How to implement a password entry field in a GenText object?

A. There's a font that displays "*" no matter which character you type.
It is the 13 point Bison font. You can set the character attributes
of the GenText object using FID_BISON.

@chunk VisTextCharAttr Bison13CharAttr = CHAR_ATTR_FONT_SIZE(FID_BISON, 13);

You might also consider making sure the text object does not allow
cut/copy so the password can not be copied to the clipboard and pasted
somewhere else as another font (thus displaying the password).


Information on writing C stubs in GEOS.

SDK: ALL_GEOS:PUBLIC
The following is a list of which registers a C-stub can trash and
which it should not alter:

Trash: ax bx cx dx es
Save:  ds di si bp

Note: Be aware that C routines use ax and dx as return values (ax for
word-sized return values and axdx for dword-sized).

As for the size of the parameters on the stack, they must all be a
multiple of word size. For example, if you have a list like this:

SOMEFUNCTIONNAME	proc	far	param1:ParamType,
                    param2:optr,
                    param3:word

where ParamType is a byte in size. This causes a problem because
the C compiler will push a byte-sized parameter onto the stack as
a word (a limitation of the Intel architecture) and the c-stub
must take the parameter as a multiple of a word size. Therefore
you must change the c-stub to something like this:

SOMEFUNCTIONNAME	proc	far	param1:word,
                    param2:optr,
                    param3:word


Using LOCAL_ROOT and ROOT_DIR to network your SDK

SDK: N9000C:PUBLIC, OMNIGO:PLAN, DOVE:PUBLIC, PENELOPE:PUBLIC, 3.0:PUBLIC
When using the SDK on a network or running multiple versions of the
SDK (e.g., OmniGo, N9000, etc.) you can seperate your development
directory from the rest of the SDK (tools, header files, symbol files,
and such) by setting up the ROOT_DIR and LOCAL_ROOT environment
variables.

With these two environment variables setup, the SDK will look for
files first in the development area defined by LOCAL_ROOT and, failing
to find them, will look in ROOT_DIR.

For example, if you have an environment like this:
    ROOT_DIR=S:\GEOSDK
    LOCAL_ROOT=C:\PCGEOS

You can keep the SDK files (tools, headers, etc.) installed on the S:
drive.  The individual developer, though, can use source code on his
PC.  For example, if a developer has the above envariables set and
does a pmake in C:\PCGeos\Appl\SDK_C\MyApp, pmake will compile the
source code in the PC's local directory.  If files are missing from
the local PC directory (like the *.gp file), they will be taken from
S:\30SDK\Appl\SDK_C\MyApp.

If you are developing an application for several platforms (e.g.,
OmniGo and N9000), you can set up LOCAL_ROOT to point to the directory
tree which contains your single set of source code and set ROOT_DIR
to the SDK for which you want to compile the application.

You can use the tools from the latest SDK for compiling.  Otherwise
you will have to modify your PATH environment variable to set the
BIN directory to use.  On caveat to using the same tools for
different platforms is that you will have to delete the SYMDIR
files that SWAT caches directories in.  Otherwise, whenever you
switch ROOT_DIR and run swat, it will read the wrong symbol files.


Special Key mappings for OmniGo Emulator

SDK: OMNIGO:PUBLIC
F1 .. F5 = map to menu slots at bottom of screen
ctrl-F1  = Help
ctrl-F3  = detach application (shut down to state)
F6       = Menu
F7       = Prev (similar to page-up key)
Shift+F7 = Next (similar to page-down key)
F8       = Date (in input field, enters the current date)
Shift+F8 = Time (in input field, enters the current time)
F9       = Cut
F10      = Copy
F11      = Paste
F12      = launch Jotter

ctrl-alt-del = shutdown Geos (on many PCs, this is
    not properly captured, so the PC reboots)


Death due to CORRUPTED_INI_FILE

SDK: ALL_GEOS:PUBLIC
Death due to CORRUPTED_INI_FILE

Concepts docs say this:
InitFileWriteString() takes a pointer to the null-terminated character
string to be written. If the character string contains carriage returns
or line feeds, it will automatically be converted into a blob.

Caveat is this:
The problem is in documentation.  The string you pass in must
have carriage return and linefeed pairs (i.e., "\r\n") seperating
the items in the blob.  Using "\r" or "\n" alone will not work.

For example, this code:
    InitFileWriteString("MyCat","MyKey","AAA\r\nBBB\r\nCCC");
    InitFileSave();
    InitFileCommit();

Will work properly and create this INI entry:
    [MyCat]
    MyKey = {
    AAA
    BBB
    CCC
    }


Why does the SDK not support Microsoft's compiler?

SDK: ALL_GEOS:PUBLIC
Question:

What are the problems with trying to use Microsoft's C compilers with GOC?
I remember someone telling me the problem was that they don't
support long enough variable names. Is that so? Is there anything
else that prevents Geoworks' SDK from supporting them?

Answer:

Early versions only supported 31 significant characters in the
identifiers, which doesn't work in the face of
GAGCNLT_APP_TARGET_NOTIFY_TEXT_CHAR_ATTR_CHANGE and other
similar labels in the Geos SDK.

Supposedly the newer Microsoft Compilers (7.0 or newer) allow the
needed longer identifier names, but Microsoft has so far
refused to publish their obj file (debugging symbol info) format,
so Geoworks has been unable to support it.

There are also problems because the compiler doesn't take argument
files so arguments have to be passed via an environment variable
(not too big of a problem, but an additional complication).


Glue/Pmake delay fixes

SDK: ALL_GEOS:PUBLIC
There have been reports that on some systems, Glue or PMake takes a long
time to run (35 seconds on a 486/66).

The fix is to add "SET DOSX=-MAXV 0" to your autoexec.bat file

Reason: there is a conflict between the Phar-Lap DOS extender used
by the SDK tools and MS-DOS's EMM386 (version 6.0 and later)
that causes delays before the tools will execute.  A couple of
possible work-arounds:

    * Use a different memory manager than Microsoft's EMM386, or just
      comment out the EMM386.EXE line from your CONFIG.SYS

    * Run the thing from a Windows DOS box, since (for a change) this
      problem disappears under Windows.

A good way to test this thing is to just type "glue" without any parameters.
If everything is okay, glue should spit out a usage line almost immediately.
Otherwise, it will pause a while.


MailboxGetVMFile() usage when sending SMS message

SDK: N9000C:PUBLIC
When building an SMS message to send out, you'll use
MailboxGetVMFile() to build a VM file to hold the SMS message.
The first parameter to MailboxGetVMFile() is the # of blocks to
attach to the VMFile. (These blocks hold the body of the message.)

Since SMS msgs are short (160 chars), one need only attach 1 block
to the VM file, so pass 1 as the first parameter:

        MailboxGetVMFile(1, &vmStatus);

You may have seen some examples of MailboxGetVMFile() usage where
0 is passed as the first parameter. Passing 0 means "use the default
value [of blocks to attach to the VM file]," where the default is
VMS_DEFAULT_NUM_BLOCKS, which = 64. This is more than is necessary for
an SMS message, and takes up space in the VMFileHeader.

So if you're creating an SMS message, only attach 1 block to the VM file.


Writing a Socket Link Driver

SDK: N9000C:PUBLIC, PENELOPE:PUBLIC, DOVE:PUBLIC, 3.0:PUBLIC
The following document explains how to write a driver to interface
with TCP/IP and sockets on the Nokia 9000 Communicator.

-----------------------------------------------------------------------------
             WRITING A SOCKET LINK DRIVER
-----------------------------------------------------------------------------

Include files:

The necessary data structures are in Include/Internal/socketDr.def and
socketInt.def.  There are no GOC equivalents for these files.

Defining entry points:

There are two entry points that must be listed in the
SocketDriverInfoStruct.  The first is the normal driver entry point,
in DIS_entry, the second is the client entry point at
SDIS_clientStrat.

DIS_entry uses the DR_SOCKET_* functions in socketDr.def
SDIS_clientStrat uses the SCO_* functions in socketInt.def
   This field is actually only used for incoming calls.

Configuring the driver:

In the init file, category "[tcpip]" change "link = PPP Driver" to
your own driver.  There is no need to change the linkDomain entry.
Your driver should then know how to load PPP.

At this time, there is no way for your driver to get between PPP and
TCP on incoming calls, since the path to the TCP driver is hard coded
into PPP.  On the other hand, there is also currently no way to
activate PPP's ability to answer incoming calls.

I plan to modify PPP to look up the name of the IP driver from the
init file, probably under "[ppp]"/"ipDriver".  If you cause your
driver to be listed in this key, and set SDIS_clientStrat correctly,
then it will work correctly if and when we enable incoming PPP calls.

General notes:

For most calls (either up or down), you should be able to simply pass
the request through unchanged.  You can do this on the caller's
thread, if you wish, or on your own thread.  However, if TCP calls a
function in your driver, do not call TCP back on the same thread.
Similarly, do not call PPP back with PPP's thread.  Doing so is likely
to cause deadlock.

-----------------------------------------------------------------------------
                 DR functions
-----------------------------------------------------------------------------
These functions are used for calls from TCP into PPP.

DR_INIT/DR_EXIT: the kernel calls this when the driver is loaded/unloaded
DR_SUSPEND/DR_UNSUSPEND: not relevant to the Nokia 9000

DR_SOCKET_REGISTER:
    After loading PPP, TCP will call this to establish certain parameters
    for the call.
        domain handle:  this is an ID number that TCP assigns to
            PPP, which PPP will use to identify itself, in case
            TCP is using any other link drivers
        domain name:  PPP ignores this, but pass it through anyway
        client entry: the address at which PPP will callback to TCP
        (overrides SDIS_clientStrat)
        SocketDriverType - ignored - should be SDT_LINK
        client handle:  how TCP will identify itself to PPP, in case
        PPP has any other clients
        sequenced header size - not relevant
        datagram header size - the minimum amount of space TCP should
                 reserve in front of any TCP data, so PPP can
         rewrite the headers in place.

DR_SOCKET_UNREGISTER:
    When TCP is done with PPP, it will call this to tell PPP to
    clean up and free unneeded resources.

DR_SOCKET_ALLOC_CONNECTION:
    Allocate a connection ID number, which will (presumably) be
    used for a connect request soon.  The ID is allocated before
    connecting so there is a way to identify a particular connect
    request in order to cancel it.

DR_SOCKET_LINK_CONNECT_REQUEST
    Open the serial port, dial the modem, negotiate with the PPP server.

    If there is an immediate error, it will be returned here, otherwise
    the driver will connect asynchronously and call back with the
    result later.

    timeout: the overall time in ticks PPP is allowed to spend connecting
    connection handle:  the ID returned by ALLOC_CONNECTION
    address: the first three fields of a TcpAccpntResolvedAddress
        (link size, link type, and access point ID, but no IP address)

DR_SOCKET_DATA_CONNECT_REQUEST
    Not relevant to PPP

DR_SOCKET_STOP_LINK_CONNECT
    Stop trying to connect.  PPP will call SCO_CONNECTION_CLOSED when
        it has completely shut down the connection.

DR_SOCKET_DISCONNECT_REQUEST
    This is the normal way to shut down a PPP connection.  For PPP,
    the close type is ignored.

DR_SOCKET_SEND_DATA
    Not relevant to PPP

DR_SOCKET_SEND_DATAGRAM
    Send one IP segment over the PPP link.

    buffer	- this is a chunk inside of a Huge LMem (see netutils.def)
             If you resize it, use HugeLMemReAlloc, not LMemReAlloc
    buffer size     - the size of the entire chunk, including headers
    client handle   - as above
    address size	- ignored
    address		- ignored

    The data inside the buffer will be in the following form (note
    that the packet contains duplicates of all the parameters
        listed above)

    --------------------------------------
        |                                    |
        |  PacketHeader                      |
        |                                    |
        --------------------------------------
        |                                    |
        |  (optional free space)             |
        |                                    |
        --------------------------------------  <-- PH_dataOffset
        |                                    |
        |   TCP header                       |
        |                                    |
        --------------------------------------
        |                                    |
        |   IP header                        |
        |                                    |
        --------------------------------------
        |                                    |
        |   data                             |
        |                                    |
        --------------------------------------
        |                                    |
        |   (optional free space)            |
        |                                    |
        --------------------------------------

    The SequencedPacketHeader is defined in socketInt.def, the TCP
        and IP headers are per the RFC.

DR_SOCKET_RESET_REQUEST
    In PPP, this is functionally identical to DR_SOCKET_DISCONNECT_REQUEST,
    sans the ignored close type parameter.

DR_SOCKET_GET_INFO
    Retrieves various useful bits of information from the driver.

DR_SOCKET_ATTACH/REJECT - not relevant to PPP

DR_SOCKET_RESOLVE_ADDR
    PPP just copies the source address to the destination address,
    since there is nothing for it to resolve.

DR_SOCKET_SET/GET_OPTION - not relevant to PPP

DR_SOCKET_STOP_RESOLVE
DR_SOCKET_CLOSE_MEDIUM
DR_SOCKET_MEDIUM_CONNECT_REQUEST
    All of these are irrelevant.

DR_SOCKET_MEDIUM_ACTIVATED
    Requests PPP to handle an incoming call.  This is called directly
    by the datarec geode, and does not come from TCP.  PPP will answer
    the call and set up the connection, then notify TCP of the new
    link via SCO_LINK_OPENED.

-----------------------------------------------------------------------------
                SCO Functions
-----------------------------------------------------------------------------

These are the calls PPP makes up to TCP, through the entry point specified
in when TCP registerd with PPP for outgoing calls, or through
SDIS_clientStrat for incoming calls.

SCO_GET_PROTOCOL
    If PPP loads TCP, it usese this to check the revision level
    of TCP's downward API.  (as opposed to the offical geode
    protocol, which refers to the upward API)

SCO_ADD_DOMAIN
    Again, if PPP loads TCP, it registers using this function.  The
    data exchanged is the same as for DR_SOCKET_REGISTER.  Note
    that TCP does not return a new strategy pointer, however; PPP
    just continues to use SDIS_clientStrat.

SCO_LINK_OPENED
    There is an incoming call.  The address is actually the local
    IP address, not the link address.  (size should be 4)

SCO_LINK_CLOSED
    PPP tells TCP that a phone call has been dropped
    close type is ignored
    error parameter indicates why the call was dropped, if known

SCO_RECEIVE_PACKET
    PPP passes a packet of data to TCP.  The data is in the same
    format as for SCO_SEND_DATAGRAM.  There are no oother
    parameters, since all the relevant data is inside the packet.

SCO_CONNECT_REQUESTED
    Not relevant to TCP

SCO_CONNECT_CONFIRMED
    The connection TCP requested with DR_SOCKET_LINK_CONNECT_REQUEST
    was successful.  TCP will query DR_SOCKET_GET_INFO to find out
    what the local IP address is.

SCO_CONNECT_FAILED
    The connection TCP requested was not successful.  This is
    functionally identical to SCO_LINK_CLOSED.


Use of wild cards in string searches

SDK: ALL_GEOS:PUBLIC
Many GEOS libraries (such as Pen, DataStore, and ContDB) support the use
of wild cards in string searches.

GEOS wild card values are defined as follows:

    typedef ByteEnum WildCard;
    #define WC_MATCH_SINGLE_CHAR   	    0x10
    #define WC_MATCH_MULTIPLE_CHARS     0x11
    #define WC_MATCH_WHITESPACE_CHAR    0x12

These wildcards tell the search mechanism to accept any character
in the allotted space. For example, passing WC_MATCH_MULTIPLE_CHAR
instructs the search mechanism to accept any number of random characters
in that place in the search string.

Example:

    /* get text from text object */
        textLen = @call SearchText::MSG_VIS_TEXT_GET_ALL_PTR( buffer );

    /* check for wild cards */
    for ( i = 0; i < textLen; i++ )
    {
        if ( buffer[i] == '*' )
        {
        buffer[i] = WC_MATCH_MULTIPLE_CHARS;
        }
    }

    /*
     * You can now pass "buffer" as your search string
     * to a system level search routine.
     */


Deleting all files ('del *.*') with FileEnum & FileDelete

SDK: ALL_GEOS:PUBLIC
There is no routine that deletes all files in a given folder.
What you need to do it use FileEnum to return a list of files
and delete each file in the list.

Here is the basic setup you need to do:

/* Put the MatchAttrs in a data resource */
@start FileEnumMatchAttrs, data;

   @chunk FileExtAttrDesc MatchAttrs[] =
     {
         { FEA_FILE_TYPE, (void *)0, /* this will be filled in later */
           sizeof( GeodeToken ), NULL },
         { FEA_END_OF_LIST, 0, 0, NULL }
     };

   @chunk GeosFileType fileTypes =
    (GFT_NOT_GEOS_FILE | GFT_EXECUTABLE | GFT_VM | GFT_DATA);

@end FileEnumMatchAttrs;

/* The routine to find and delete the files should look something like
 * this: */
MyFileDeleteAll()
{
    FileExtAttrDesc *attrsToMatch;
    FileEnumParams fileEnumParams;
    MemHandle fileNameListHandle;
    word filesNotHandled;
    TCHAR * fileNameListPtr;

    /*
     * first set up the attribute for FileEnum to match.  In this
     * case, I am use the document's creator, which will be the
     * GeodeToken of your geode.
     */
    MemLock(OptrToHandle(@MatchAttrs));
    attrsToMatch = LMemDeref(@MatchAttrs);
    attrsToMatch->FEAD_value = LMemDeref(@fileTypes);

    /*
     * Set the search flags to search all files, but not directories.
     * (FILE_ENUM_ALL_FILE_TYPES does not include FESF_DIRS).
     */
    fileEnumParams.FEP_searchFlags = FILE_ENUM_ALL_FILE_TYPES
    /*
     * Return the file's Geos filename.  FE_BUFSIZE_UNLIMITED
     * allows the return buffer size to be as large as necessary.
     */
    fileEnumParams.FEP_returnAttrs = (void *) FESRT_NAME;
    fileEnumParams.FEP_returnSize = FILE_LONGNAME_BUFFER_SIZE;
    fileEnumParams.FEP_bufSize = FE_BUFSIZE_UNLIMITED;
    /*
     * Set matchAttrs to zero so it will match anything.
     * Don't skip any files
     * Don't need a callback.
     *
     */
    fileEnumParams.FEP_matchAttrs = 0;
    fileEnumParams.FEP_skipCount = 0;
    fileEnumParams.FEP_callback = 0;

    numOfFiles = FileEnum( &fileEnumParams,
               &fileNameListHandle,
               &filesNotHandled );

    MemLock(OptrToHandle(@MatchAttrs));

    /*
     * Delete all the files in the list returned by FileEnum.
     * First check to see if any files where found and the buffer
     * was successfully created (fileNameListHandle will be
     * NullHandle, which is zero, the buffer couldn't be created).
     */
    if ( numOfFiles && fileNameListHandle )
    {
        fileNameListPtr = MemLock(fileNameListHandle);

        while(numOfFiles--)
        {
            FileDelete(fileNameListPtr);
            fileNameListPtr += FILE_LONGNAME_BUFFER_SIZE;
        }

        MemUnlock(fileNameListHandle);
    }
}


geode cannot be multi-launchable and handle relocation GLUE errors

SDK: ALL_GEOS:PUBLIC
When you get errors like the following:

    Error SOURCE.GOC 73: Error handle relocation from shared/read-only to
         unshared/writable segment
    INTERFACE Error LCLIT.GOC 73: Error geode cannot be multi-launchable

It is becuase you don't have the "single" flag set in the "type" line
of your .gp file.  The type line should look something like this:
    type   appl, process, single

You will generally want your application to be single launchable,
especially on smartphones and PDA devices.  If you are writing an
application that you do want to make multi-launchable (that is,
more than one instance of the application can be launched
concurrently), then you will need to use GeodeGetOptrNS on any
static optrs in your source code.  Here is an example of using
that:
    @send GeodeGetOptrNS(@MyObject)::MSG_META_DUMMY();

NOTE: GeodeGetOptrNS will cause a single launchable application
to crash, so don't use it if you have the "single" flag set.


How to intercept MSG_META_KBD_CHAR

SDK: ALL_GEOS:PUBLIC
There are many instances when you will want your application
to intercept keyboard input events.  To gain a general
understanding of how user input works in GEOS, you should
read the Input chapter of the Concepts book (especially
section 11.1.4 "Input Hierarchies").

In essence, you will either want to intercept all keyboard
events received by your application or only keyboard events
destined for a specific object in your application.

To capture all keyboard input received by your application,
handle MSG_META_KBD_CHAR at your GenApplicationClass level.
Otherwise, handle it at the specific object.

You can use the two following swat commands to show you
which objects in your application receive MSG_META_KBD_CHAR.

    "mwatch MSG_META_KBD_CHAR" will show you how the
        message is passed from object to object and
        which objects receive the message

    "focus -a" will display the focus tree from the
        application object (that's what -a flag does)
        down to the focus node.


GStrings in VMFile based text objects.

SDK: ALL_GEOS:PUBLIC
I just found a feature of gstrings in VM-based text objects:

If the storage of a text object is a VM file, then all gstrings added
as graphic characters _must_ also be stored in a VM file (not
necessarily the same VM file).  GStrings stored in chunks of an LMem
block are not copied into the text object's VM file.

The reason this does not cause problems every time is because the VM
text object can actually use a graphic stored in a chunk, but the VM
text data structures that keep track of the graphics aren't designed
to keep track of graphics stored in chunks - only graphics stored in
the VM file.  The first chunk-based graphic added will appear to be
added correctly, but any other graphics added will not.  A random (but
likely) outcome is that the text object will not add a second,
different graphic to the text, but use the first graphic again.  This
is the reason that the same image icon is being displayed for
different types of image icons.

I suggest the following course of action:

  - When copying the GStrings from the template block, create the
    duplicate gstring with GST_VMEM instead of GST_CHUNK,
    passing the file handle of the VM file used to store the
    text (the clipboard file, right?).  This will create the GString
    in the same VM file with the text object.

  - Change HLineChunk, ImageMapChunk, etc to be type VMBlockHandle
    instead of ChunkHandle, and store the block handle returned
    from GrCreateGString.

  - in appendImage, set VTG_vmChain to contain a VMChain (high
    word = VM block of gstring, low word = 0), and pass the
    VM file handle of the gstring to MSG_VIS_TEXT_REPLACE_WITH_GRAPHIC:

    graphic.VTG_vmChain = VMCHAIN_MAKE_FROM_VM_BLOCK(myGString);

        @call GlobalTextOptr::MSG_VIS_TEXT_REPLACE_WITH_GRAPHIC
            (graphic, ClipboardGetClipboardFile(), 0,
        textRange.VTR_end,textRange.VTR_start);

  - It is _very_ important that at some point, the copied gstrings
    in the VM file are explicitly freed (with VMFreeVMChain).
    This could happen at the same time that MSG_VIS_TEXT_DELETE_ALL
    is called, or just once whenever the application exits.  This
    is even more important than in the LMem case, because
    the Clipboard VM file is persistent storage, and storage
    leaks will cause the file to grow without bound, using up
    more and more of the file system.

  - Again, there's no need to maintain a reference counter for the
    number of times each graphic is used, as the text object
    copies the graphic to it's own internal storage and
    automatically deletes the internal copy when it is no longer
    needed.

The above changes are not difficult to make, and won't affect
your design of the browser.

With VM-based graphics, there is an optimization that could be
made:

  - Instead of copying the gstrings out of the template resource
    into the clipboard file temporarily, the graphic gstrings could
    be permanently stored in a ROM-based VM file, and directly
    appended from that file.  This would avoid the need to copy
    them into the clipboard file, and also the need to free the
    gstring storage afterward.  However, I don't believe these
    steps add much overhead to the entire process of rendering a
    document, so perhaps it is not worth pursuing.


What is the _TEXT resource for?

SDK: ALL_GEOS:PUBLIC
Resource names that end in "_TEXT" are code resource.  Usually,
these resources are named by appending "_TEXT" to the name of
the source file that contains routines or method handlers.  (For
example, if your file is called myapp.goc, the resource is called
MYAPP_TEXT.)

The resource that is named "_TEXT" without anything prepended is
a special code resource that contains some standard routines for
Borland C (Run Time Language).


Reseting Zoomer card slot

SDK: BETA:PUBLIC, 2.0:PUBLIC
Note that this operation is performed at the BIOS level.  It is not part
of the GEOS Socket API. The code shown below is untested and may not work.
CardServices and SocketServices is an unpublished, unsupported API.

  On a socket-services only platform, reseting the card is accomplished
  by sending Socket Services the ResetSocket command (90h).

    ;
    ;  To reset a socket (at the socket services layer)
    ;  All you need to do is send a reset command for
    ;  appropriate adapter and socket.  On the Zoomer
    ;  the slot is Adapter 0, Socket 0.
        xor	al, al		; al <- Adapter (0 = 1st adapter)
        mov	bl, al		; bl <- Socket (0 = 1st socket)
        mov	ah, 090h	; ah <- SSCommand (ResetSocket)
        int	1ah		; 1Ah = SocketServices interrupt
        jc	error	; => AH has error code
    ;
    ;  To test the RESET line, do a GetStatus on the
    ;  socket, and check the SBM_RDYBSY pin (#16).
        xor	al, al		; al <- Adapter (0 = 1st adapter)
        mov	bl, al		; bl <- Socket (0 = 1st socket)
        mov	ah, 08fh	; ah <- SSCommand (GetStatus)
        int	1ah		; 1Ah = SocketServices interrupt
        jc	error	; => AH has error code

        test	bh, 040h	; b6 has RDYBSY line
        stc			; assume it's set
        jnz	done		; return Carry SET if RDYBSY line high
        clc			; return Carry CLEAR if line low


Make dismissed parent dialog automatically dismiss its child dialog

SDK: ALL_GEOS:PUBLIC
If a dialog that is a child of another dialog is initiated via
MSG_GEN_INTERACTION_INITIATE, rather than an associated trigger object,
the Geometry Manager does not automatically bring down the child dialog
when its parent is dismissed.  To make the parent dialog automatically
bring down a (single) manually-initiated child dialog, add these hints
and flags to the parent dialog object:

  GI_attrs = @default | GA_NOTIFY_VISIBILITY;
  ATTR_GEN_VISIBILITY_DESTINATION = @TheChildDialog;
  ATTR_GEN_VISIBILITY_MESSAGE = MSG_GEN_GUP_INTERACTION_COMMAND;
  ATTR_GEN_VISIBILITY_DATA = ( (dword)IC_DISMISS << sizeof( word ) );
     /* Pass IC_DISMISS in proper word parameter
      * for MSG_GEN_GUP_INTERACTION_COMMAND.  */


C stub for ChunkArrayEnum has a bug.

SDK: BETA:PUBLIC, 2.0:PUBLIC, OMNIGO:PUBLIC
The C version of ChunkArrayEnum() that shipped on GEOS 2.0 and 2.1
devices (Z-7000, Ensemble, Omni Go 100) had a bug.  This bug prevents
a callback function from being able to correctly referenced global
variables.  This is caused by the ds register not being properly
updated between calls to the callback function.

For example, the following code may not work because "Test String" is
(effectively) a global variable.  The second time MyCallBack is called,
the pointer to "Test String" may instead point somewhere else. The
workaround is not to use global variables.

@method MyProcessClass, MSG_MY_PROCESS_SEND {
    ...
    ChunkArrayEnumHandles( aBlock, theList, &theID, MyCallBack );
    ...
}

Boolean _pascal
MyCallBack( void * el,
            void * retVal )
{
    ...
    cmpResult = LocalCmpStrings( "Test String", el->field1, 0 );
    ...
}


ProcCallFixedOrMovable gives 'no prototype' compiler warning

SDK: ALL_GEOS:PUBLIC
When you use one of the ProcCallFixedOrMovable routine, Goc/Bcc will
Give you the warning

      ProcCallFixedOrMovable..() called with no prototype.

This is because the ProcCallFixedOrMovable..() routines are declared
with empty parameters since the number of arguments can vary.
Unfortunately, this confuses the Borland compiliner.  You should
ignore this "no prototype" warning.


How does GEOS SocketAccept/SocketListen compare to BSD?

SDK: ALL_GEOS:PUBLIC
Q. Is there something different in the way GEOS SocketListen() and
   SocketAccept() works in comparison with the functionality of the
   Berkeley listen and accept commands?

A. The functionality is the same, to the extent that I understand
   BSD sockets. SocketAccept() doesn't have the ability to return
   an address, though.


HOW_CAN_APPLICATION_HAVE_NO_NAME error

SDK: N9000C:PUBLIC
If you get the HOW_CAN_APPLICATION_HAVE_NO_NAME error when you try to
connect swat to the N9000 emulator, there is probably a problem with
the mailbox.  To fix the problem, go to DOS and delete all the files
in the PRIVDATA\MAILBOX\ directory.

When you reattach Swat you might be asked "Do you want to abort?"
Type "n[enter]" followed by "c[enter]" to continue.  You may need
to do this about five or six times until all the files are properly
rebuilt.  This abort query occurs because of a problem with one of
the symbol files.


Capturing screen dumps on the Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
One way to create screen dumps of the Nokia 9000 Communicator is to
use the Screen Dumper application that is included in the SDK.
Screen Dumper gets installed to both EC and NC targets, under the
ExtraApps directory. Just run the target Emulator; use ctrl-F12 to
start up Extra Apps, select [EC] Screen Dumper.

Quick Usage:
============
The UI is ugly (since it was designed for desktop GEOS) but usable.

1/ Use the Tab or arrow keys to navigate down to Formats.
2/ Use Enter to open up the list box of choices.
3/ Use Tab or arrow keys to highlight a choice.
4/ Use F1 to select a choice, which closes the dialog.
5/ Use F1 again to Banish the screen dumper app from the screen.

6/ Go to the app which you want dumps of.
7/ Use ctrl-shift-tab to freeze the screen for dumping.
8/ Use F3 to dump the screen.
9/ File goes to C:\N9000EC\Document\Dump.xxx (where xxx=3-digit integer,
   starting with 000 and auto-incrementing).

For complete help with Screendumper, see below text file.

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

Screen Dumper Instructions

Introduction
------------

As part of our on-going efforts to make PC/GEOS more enjoyable, we
at Geoworks have released for your use a simple utility, called
"Screen Dumper," that allows you to dump screens, windows, and even
portions of a window to DOS files. This is the manual for that utility.
Screen Dumper creates screen dumps in many formats, including
Encapsulated PostScript and TIFF. It can even create color dumps.

Before we go further, it's time for a disclaimer:

"Screen Dumper" is unsupported software. It is provided as-is in the
hope that it will be useful, but without any warranty of any kind,
express or implied. On no account will Geoworks be responsible for
any damage arising out of the use of this program.  If you're not
comfortable using this utility on these terms, please don't use it.

Before You Dump Your First Screen
---------------------------------

Before you attempt to dump a screen, the screen dumper will make sure
your PC/GEOS system is properly configured. This configuration
involves disabling the blinking of text cursor throughout the system
in order to avoid a deadlock (similar to gridlock) when you dump all
or part of the screen.

When you launch the screen dumper for the first time, you will get a
dialog box telling you that it must turn off the blinking of your
cursor. When you click Ok, PC/GEOS will shutdown and automatically
restart, leaving you just where you were, but with your text cursor
not blinking. When you are done dumping screens, you may wish to
re-enable the blinking by choosing the Enable Blinking Cursor Again
option from the Options menu. The blinking will be back when next you
start up PC/GEOS.

Start Screen Dumper and Set the Options
---------------------------------------

Start PC/GEOS the way you normally would and enter the Professional
Workspace. Double-click the Screen Dumper icon in the GeoManager
window to start the utility. The Screen Dumper window appears:

You should click Read Me the first time you launch Screen Dumper so
you know under what conditions you are using it. Once you've read it,
you can ignore that button forever.

By now it's too late to point you to the Help text, since you're
reading this manual, but it'll provide you with a quick summary of the
keys you can use to create screen dumps, should you forget.

You should change the options in the window before you dump your first
screen.

Base Name: Screen Dumper uses this name to create the file for each
screen dump. It replaces the percent symbol (%) with the current Dump
number. So, if you had a base name of

    \screens\dump%

the first file you would create would be "\screens\dump00.tif"
(assuming that you were dumping in TIFF format). The next file
would be "\screens\dump01.tif" and so on.

If you don't make this name absolute (by starting with a \), the path
you give will be taken as relative to the DOCUMENT directory in the
GEOWORKS tree.

Dump Number: Each screen that you dump is placed into its own file. To
give each file a unique name, Screen Dumper replaces the percent sign
(%) in the Base Name with the current Dump Number. Every time that you
dump something, the number goes up by one.

Normally you change the Dump Number by clicking the two arrows.
However, if you decide to enter a number from the keyboard, you must
press Return before the number will take effect.

Formats: You can dump screens in any one of five formats:

Raw Bitmap
This is a format that is useful only here at Geoworks and is included
only for historical reasons. It places the different slices of the
screen dump in an internal bitmap format that we used to convert to
PostScript before we changed Screen Dumper to create PostScript dumps.

Full-Page PostScript
Used to create single-page full-screen dumps, usually, though it will
work with any of the regular dumping options (given below). The main
differences between this and Encapsulated PostScript is a full-page
dump has a showpage command at the end of the dump, and the dump is
centered in the indicated page space (See PostScript Parameters,
described below).

Encapsulated PostScript
This is a good format to use if you wish to include a screen dump in
a document that is to be printed on a PostScript printer.

TIFF
Creates a black and white, 16-color, or greyscale TIFF file in Intel
byte-order. Some Macintosh programs have had difficulty with files
produced in this manner.

PC-Paintbrush
This is the standard PCX format used in the PC world. Screen Dumper
can create either black and white, or color PCX files.

Note that no bit image is produced with either of the PostScript
options. If you import the file to PageMaker or some other graphics
program, you will see a grey box, not a screen image. This has no
effect on the printed output.

Annotation:
Screen Dumper can create a log of all the screens dumped. Turn the
Enable option on and change the Log name to be the appropriate file
name. Turn Append on if you want to preserve the current contents of
the log file, or turn it off if you want to completely replace the
current contents.

With the Enable option turned on, Screen Dumper presents a dialog box
every time you dump a screen. In this dialog box, you can enter a bit
of text that identifies the screen that you've dumped. This text is
then added, along with the file name, to the log file.

Banish:
You can leave the Screen Dumper window on the screen if you choose.
However, if it gets in the way of your screen dump, you can banish
it before dumping. When you click Banish on the menu bar, the window
disappears, even though the program is still present and functioning.
To get the banished Screen Dumper window back, enter control mode by
holding CTRL and SHIFT and then pressing TAB. Press F1 to get the
window back.

Options:
When you choose either PostScript option, or the TIFF option, there
are additional parameters you can set. These are available as the
Postscript and TIFF entries in the Options menu.

Set the PostScript Options, if necessary

When you choose to dump in either of the two PostScript formats, you
have additional options that can affect the final output:

Image Name:
The name that you enter here appears on the grey box that represents
the PostScript image when you paste it into your document (in some
desktop publishing programs, such as PageMaker). The name serves only
to document the contents of the screen dump file; it has no effect on
the image itself, or on the name of the file in which the dump is placed.

Color:
Choose the type of color model you wish to use for the screen dumps.
You should choose a model that works with the equipment that you will
use to print the dumps. Use RGB if you will be viewing the dumps on a
color monitor. For color printers, CMYK is usually the appropriate
color model, while Greyscale is best for black and white printers and
monitors. The resulting screen dump for both RGB and CMYK uses the
color extensions to PostScript (specifically, the colorimage operator).
If the device doesn't support this operator, you should choose
Greyscale, as choosing the wrong model will likely give you a
PostScript error when you attempt to print the document.

Number of Copies:
For full-page PostScript images, you can print several copies of each
dump. This is especially important for color PostScript dumps, as some
dumps can take up to half an hour to process, but once processed, the
printer can print several copies relatively quickly. Enter the number
of copies desired in this field.

Orientation:
This option is mostly for full-page PostScript format. If you choose
Portrait orientation, the image will print normally. If you choose
Landscape orientation, the image will print sideways. This is useful
for full-page dumps, as it is much closer to the aspect ratio of a
monitor than Portrait is.

Width, Height:
This is the size of the image, in inches. Your dump will appear to be
this size when you print it. If the dump isn't actually this size on
the screen, then it will be stretched to fit. There currently is no
way to have Screen Dumper automatically size the Width and Height to
match the dump, so you will have to manually size the image when you
import it into your document.

Paper Size:
This option is only relevant to full-page PostScript screen dumps.
You can choose the size of the paper on which you print the image.
The image will be centered within this space.

Set the TIFF Options, if necessary

If you are dumping to a TIFF file, you have additional options that
may be reached using the TIFF entry in the Options menu:

Dump Color As:
When dumping to a TIFF file on a color screen, the colors can be placed
in the file as-is, or mapped to the appropriate level of gray (one of
16). This option has no effect if you're dumping a monochrome screen.

Image Compression:
This option is currently not supported, but will allow you to specify
how the image is to be compressed, if it is to be compressed. Packbits
is a simple run-length encoding scheme used on the Macintosh, while
LZW is an adaptive compression scheme that is widely used and provides
good compression for color dumps. As a general rule, you should use
Packbits for monochrome dumps and LZW for color dumps. Be aware,
however, that some programs (notably older versions of PageMaker)
cannot handle LZW-compressed images.

Using the Screen Dumper
-----------------------

Prepare the screen dump by starting the necessary applications and
opening the appropriate documents. When the screen is properly set up,
dump the portion of the screen that interests you.

One way to dump a screen is to enter control mode and press one of the
function keys. In some cases, you can simply press a shortcut key.

While you are in control mode, the screen is frozen and you can type
Screen Dumper commands on the keyboard. You can still move the pointer
around on the screen, but it will return to its original position when
you leave control mode (either by dumping the screen or by pressing ESC).

Dumping the Entire Screen
-------------------------
Press  SHIFT + PrtScrn

Or, hold down CTRL and SHIFT, and press TAB. This freezes GEOS temporarily
and puts you in Dumper control mode. Press F6 to dump the screen.

If you've enabled the Annotation feature, a dialog box will appear so
you can enter a description of the dump:

Annotate: This writes the notes to the log file you selected in the
main window preceded by the name of the file to which the dump was
made, e.g.:

    ================
    betadocs\dump03.pcx
    That was the annotation box

Cancel dump: Clicking this causes the dump number not to increase and
the dump to effectively be forgotten. Use this if you made a mistake
in the dump and want to go back and do it again.

Dumping a Particular Window
---------------------------

1. Hold down CTRL and SHIFT, and press TAB. This freezes PC/GEOS
   temporarily and puts you in Dumper control mode.

2. Position the pointer on the title bar of the window you wish
   to dump.

3. Press F3 to dump the window without the pointer, or press F4
   to dump both the window and the pointer.

If you've enabled the Annotation feature, a dialog box will appear so
that you can enter a description of the dump (see above). Click
Annotate to complete the dump.

For keyboards that contain the extended function keys, you can skip
all three steps above and simply press F11 to dump the window without
the pointer, or press F12 to dump the window with the pointer.

Dumping a Portion of the Screen
-------------------------------

1. Hold down CTRL and SHIFT, and press TAB. This freezes GEOS
   temporarily and puts you in Dumper control mode.

2. Press F5 to show the dump rectangle. This dotted rectangle
   outlines the area of the screen that will be dumped. Change the
   size and position of the dump rectangle with the numeric keypad.

Keypad Key	Action
------------------------------------------------------------------------------
1 to 9		Moves the dump rectangle one pixel in the
        direction of the key (e.g., pressing 9 moves
        the rectangle one pixel up and to the right).

ALT + key	Move the dump rectangle eight pixels at a time.

SHIFT + key	Enlarges the dump rectangle one pixel in the given
        direction. Hold ALT down, too, to enlarge it eight
        pixels at a time.

CTRL + SHIFT + key	Shrinks the dump rectangle one pixel in the
        given direction. Hold down ALT, too, to shrink it
        eight pixels at a time.

3.	Press F6 to dump the screen surrounded by the dump rectangle.

If you wish to dump the same portion of the screen over and over
again, position and size the dump rectangle the first time you dump
the screen. For subsequent dumps, press CTRL + SHIFT + TAB to enter
control mode and press F6 to dump the same area as before.

If you decide not to dump...

If you've decided not to dump after already pressing CTRL + SHIFT +
TAB to enter control mode, press ESC to leave control mode and "thaw"
GEOS.

Tips and Advice
---------------

Experience has shown there are some quirks you should know in order to
use the Screen Dumper well.

Placing EPS into PageMaker

Screen Dumper does not include a bit-image of the screen with
PostScript dumps. While this has no effect on printing, it does mean
that most programs will only show you a grey box when you import the
dump. The program should display the name you gave the image in the
PostScript Parameters box, so you won't be lost.

TIFF dumps

When you select TIFF format, Screen Dumper dumps the screen in PC TIFF
format. You may find it difficult to import PC TIFF files into
Macintosh programs (though some programs, notably PageMaker, can
handle importing PC TIFF files). In order to even see the file in a
file selector, you may need to use "Res Edit" to change the file's
token to be TIFF (we set the creator to be DGDR-Digital Darkroom_).
Some programs prefer color TIFF files to be in the form of greyscale
dumps (e.g. Aldus Freehand_) while others have fits if given a
greyscale dump and much prefer color (e.g. Aldus PageMaker). You'll
have to experiment.

When dumping a window, put the pointer on the title bar

When you dump a window, Screen Dumper dumps the window that is
directly under the pointer. In many cases, though, PC/GEOS windows are
built up from a few little windows that don't look like windows. The
GeoManager window is a good example of this. The icons sit inside a
window within the GeoManager window. If you were to put the pointer
over this area and dump the window, you would get the icons and the
surrounding rectangle, but not the surrounding GeoManager window.

To avoid this kind of problem, always put the pointer on the title bar
before dumping the window. This will dump the window and all the
windows contained within it.

Setup Screen Dumper, then exit PC/GEOS to freeze its state

It can take a bit of time to prepare Screen Dumper. If PC/GEOS should
crash for any reason, you will have to prepare Screen Dumper all over
again (since it won't have been able to save its state).

For this reason, it's usually a good idea to shut down PC/GEOS as soon
as you've set up for your first dump, to force Screen Dumper to save
its state. This way, if PC/GEOS should crash while you're dumping a
screen, Screen Dumper will still be prepared when you start PC/GEOS
again. Just be sure not to answer "Reset Professional Workspace" when
Welcome asks what it should do about the abnormal exit that occurred
last time.


How the null modem lines should be connected.

SDK: ALL_GEOS:PUBLIC
See also: Why does Swat "time out"?

Are you experiencing the error "Can't contact PC: Call timed out"
when you run Swat? Does PCCom seem to work correctly between the
the two PCs? If so, then perhaps you have a null modem cable that
is not a true null modem. Swat is picky about the exact wiring of
the null modem cables. Below are the configurations we recommend
for your null modem cable.

Here are two possible configurations for 9-pin cables:

In  Out    In   Out
-------    --------
1   4      1    -
2   3      2    3
3   2      3    2
4   1,6    4    6
5   5      5    5
6   4      6    4
7   8      7    8
8   7      8    7

Here are three possible configurations for 25-pin cables:

In  Out    In   Out    In   Out
-------    --------    --------
1   1      1    -      1    1
2   3      2    3      2    3
3   2      3    2      3    2
4   8      4    1      4    5
5   20     5    -      5    4
6   20     6    -      6    20
7   7      7    7      7    7
8   4      8    -      8    20
.
.
20  5,6    20   1      20   6,8


Swat can't find all the symbol files under Windows NT.

SDK: ALL_GEOS:PUBLIC
Q. I am running Windows NT on the host PC, but when I connect to the
   target using Swat in the Command Prompt window, Swat finds only the
   first 15 symbol files. For example, Swat connects and finds the symbol
   files for the first 15 geodes, but refuses to find the rest of the
   symbol files. When I connect Swat using Windows 3.1 on the host it
   works fine. Is there something about DOS boxes in NT that I should
   know about?

A. Increase the "FILES" setting in the \winnt\system32\config.nt file.
   Then restart the command prompt. (Files should be at least 80, but not
   more than 255.)

   The FILES setting is important even if you are using DOS or Windows
   3.1 or '95. The difference is the FILES is set in the \AUTOEXEC.BAT
   file.


How to write screen savers.

SDK: ALL_GEOS:PUBLIC
******************************************************************************
                 INTRODUCTION
******************************************************************************

This file describes the operation of the Generic Screen Saver process-library,
also known as "GW After Hours".

The purpose of this process-library is to make the writing of cool little
screen savers as easy as possible, handling all interfacing with the Flow
object, putting up a window on which to draw, and other functions common to
screen savers.

******************************************************************************
               WHAT A SCREEN SAVER MUST PROVIDE
******************************************************************************

A screen saver is a library whose token is SSAV. It is stored in the
SYSTEM\SAVERS directory and provides 6 predefined entry points, whose order is
defined by the SaverFunctions enumerated type defined in saver.def:

SF_START                enum    SaverFunctions
;       Begin saving the screen.  Screen savers must draw *everything*
;	they want for the initial screen at this point.  If you wish to
;	implement a saver that modifies the screen, your start routine
;	needs do nothing extra to the screen.  If not, you must blank
;	the screen.  SaverInitBlank() is provided to simplify this.
;
;       Pass:   cx      = window handle on which to draw
;		dx	= width of the window
;		si	= height of the window
;               di      = gstate handle to use in the drawing
;		bp.low	= DisplayType
;       Return: nothing

SF_STOP                 enum    SaverFunctions
;       Stop saving the screen. When this function returns, the window
;       used for the screen saver will be made unavailable.
;
;       Pass:   nothing
;       Return: nothing

SF_FETCH_UI           	enum    SaverFunctions
;       Fetch any UI gadgets for the setting of specific screen-saver
;       parameters into the GenInteraction passed.
;
;       Pass:   nothing
;       Return: ^lcx:dx	= root of tree holding the UI for the library. All the
;			  gadgetry should be in this block.  cx == 0 if no
;			  gadgetry installed.
;			  The root should be marked not usable.
;			  The returned block must be a duplicated block
;			  with 'saver' as the owner.
;		ax	= first entry point number used in output descriptors
;			  in tree. 0 if no entry points used.
;		bx	= last entry point number used.

SF_FETCH_HELP		enum SaverFunctions
;	Fetch any saver specific help for the saver.
;	Pass:	nothing
;	Return:	^lcx:dx = root of tree holding help for the saver.  All the
;			  help should be in this block.  cx == 0 if no help.
;			  The root should be marked not usable.
;			  The returned block must be a duplicated block
;			  with 'saver' as the owner.

SF_SAVE_STATE		enum	SaverFunctions
;	Return any extra state the library wants to save across shutdowns.
;
;	Pass:	cx	= handle of block to which to append the state
;			  information
;		dx	= offset at which to store the information.
;	Return:	nothing
;

SF_RESTORE_STATE	enum	SaverFunctions
;	Restore any extra state the library saved before shutdown.
;
;	Pass:	cx	= handle of block with extra saved state
;		dx	= offset from which to restore the information
;	Return:	nothing
;

SF_SAVE_OPTIONS		enum	SaverFunctions
;	If the specific saver has any options besides those dictated by
;	its UI tree, or if the saver has chosen not to use the classes
;	provided by the generic saver library, those options should be
;	saved during this call.
;
;	Pass:	nothing
;	Return:	nothing

These routines are not allowed to destroy any registers other than AX and BX,
which are used to call them (via ProcCallLibraryRoutine).

A screen saver *may not* use any gstate other than that provided to it in the
SF_START call, nor may it change the default transformation or the application
clipping region. This is to allow future versions of the generic library to
have multiple specific savers operating at once, if so desired.

A typical screen saver will wish to provide user-settable options to control
its actions. This is accomplished with the SF_FETCH_UI function. The tree
returned should meet the following criteria:

    * It must reside entirely within a single, duplicated block run by the
      UI thread.
    * It should contain a single SaverInteractionClass object that holds
      the ini file category in which the user-settable options are stored.
    * The root of the tree must be a SaverInteraction object.
    * Where you would normally use a GenRange object, use a OptRange
      object instead, setting the key under which the range's value is
      to be stored (and from which it is to be fetched when the option
      tree is brought up on screen).
    * Where you would normally use a GenList object, use an OptList
      object instead. The list must use the listMethod and
      listMethodIsData attributes (these are the defaults set in
      saver.uih), and should store a unique value in the method field
      of each GenListEntry object within the list.

      If the list is exclusive, the "method" for the current exclusive
      will be stored in the .ini file when the list's option value is
      saved and will be sought to set the current exclusive when the
      option is restored.

      If the list is non-exclusive, the "method" values for the entries
      should consist of bitmasks. When the option is saved, the method
      values for all set entries will be bitwise-or'ed to form the value
      stored in the .ini file. When the option is restored, each method
      value is and'ed with the value stored in the .ini file, and all
      entries for which the resulting value is non-zero will be turned on.

      Again you must provide the key under which this value is to be stored.
    * If you want to use a GenTextEdit object to hold an editable
      string option, use a OptTextEdit object instead.
    * Where you would normally send a method to your process (from an
      action descriptor in one of your objects), use something like the
      following macro:

        #define CALL_QIX(routine) METHOD_SAVER_CALL_SPECIFIC, 					  "enum " #routine

      This will cause the entry-point number of the given routine to be
      placed in the optr field of the action descriptor. This optr will
      eventually be fixed-up by the generic library so the routine you
      give will be called when the action descriptor is activated, passing
      all the usual data that come with that action. The example is
      taken from the Qix screen saver, which is a very good place to look
      if you get confused.

******************************************************************************
                 WHAT YOU GET
******************************************************************************

"GW After Hours" provides a few routines, classes and methods for use by a
screen saver:

global  SaverStartTimer:far
;
;       Sets up a timer to call a routine in the specific screen-saver
;       library on the screen saver's own thread.
;
;       Pass:   al      = TIMER_EVENT_CONTINUAL or TIMER_EVENT_ONE_SHOT
;               cx      = count until first timeout
;               di      = interval, for continual timer
;               dx      = library entry point in specific screen-saver
;                         library to call when event comes in.
;       Return: ax      = timer ID
;               bx      = timer handle
;

You are responsible for shutting off any timer you start, as well as dealing
with receiving queued timer events after your SF_STOP entry point has been
called.  Qix and other savers deal with this by storing the GState handle
they receive on start, zeroing it on stop, and checking for a non-zero
GState handle before doing anything in their timed routine.

global	SaverRandom:far
;
;	Return a random number in the passed range.
;
;	Pass:	dl	= max for returned number
;	Return:	dx	= random number between 0 and DL-1
;

This is a very simple random-number generator for use in all kinds of
situations. Note that the number returned does *not* include that passed in DL.

global	SaverFindOptions:far
;
;	Locate the root of the specific options tree.
;
;	Pass:	nothing
;	Return:	carry clear if found:
;			^lcx:dx	= optr of tree root
;		carry set if not found
;

A specific saver can call this from SF_RESTORE_STATE to locate the options
tree that it returned in its previous incarnation. This is useful if the saver
needs the handle of the duplicated option block for whatever reason.

global	SaverSetSpecProcClass:far
;
;	Set a class as an auxiliary process class. Any method not already
;	fielded by the generic saver's own process class will be sent to the
;	auxiliary class. The class should have SaverClass as its superclass.
;
;	Pass:	cx:dx	= far pointer of auxiliary class.
;	Return:	nothing.
;

This allows the specific saver to receive methods from other parts of the
system without having to instantiate some object or other each time it is
loaded. In fact, one can use this instead of special constants and
METHOD_SAVER_CALL_SPECIFIC in one's options UI tree if one so desires. The
class so passed is placed between the generic saver's own private process
class and the published global SaverClass. All the SaverClass methods that the
generic saver fields are actually bound at the SaverClass level, not the
private saver class's level, allowing the specific saver to receive these
methods before the generic saver does. This can be useful if one wishes to
call SaverSetWinType just before the window is opened, for example.

;==============================================================================
;
; 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.


Why does Swat 'time out'?

SDK: ALL_GEOS:PUBLIC
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.


ViewerLibraryOpen crashes when library/driver does not exist.

SDK: N9000C:PUBLIC
Q. How can I check if a library or driver exists on the Nokia 9000
   Communicator before I try to use it with ViewerLibraryOpen?

A. You can check if the library exists before calling ViewerLibraryOpen
   with something like the following:

    GeodeHandle	geode;

    FilePushDir();
    FileSetStandardPath( SP_SYSTEM );
    geode = GeodeUseLibrary( libraryName, 0, 0, &error );
    FilePopDir();

    if ( geode == NULL ) {
    /* library does not exist */
    }
    else {
    /* library does exist */

    GeodeFreeLibrary( geode ); /* unload the library */

    /* Can now call ViewerLibraryOpen without fear of the
       EC VIL_LIBRARY_LOAD_ERROR error. */
    }

   One caveat: the XIP'ed (built in) libraries and drivers are not
   visible on the file system, so you will not be able to find them.
   The XIP'ed applications are visible, though.


Sending classed events in IACP

SDK: ALL_GEOS:PUBLIC
When specifying a class in your recorded message, only use
system defined classes.  Subclasses specific to your application
may not work properly.

For example, if the server (remote) application has defined
HappyApplicationClass, which is a subclass of GenApplicationClass,
you will want to specify GenApplicationClass in the event you
@record.

For example, the following is WRONG:

    sendEvent = @record HappyApplicationClass::MSG_HAPPY_DO_SMILE();

while this is CORRECT:

    sendEvent = @record GenApplicationClass::MSG_HAPPY_DO_SMILE();


Glue error: 'test2.eobj: struct foo.bar: field type mismatch'

SDK: ALL_GEOS:PUBLIC
Q. I have a developer who is porting old code in which the same structure
   name ("Foo") is defined it 2 different .c files (not .goc files).  But
   it is defined to be one thing in one file, and another in the second
   file.

   ------FILE 1-------
   struct foo {
       int * bar;
   };
   struct foo var1;

   -----FILE 2--------
   struct foo {
       char * bar;
   };
   struct foo var2;

   However, glue complains:
   error: test2.eobj: struct foo.bar: field type mismatch
   Type fptr(signed(2)) not same as type fptr(int(1)).

   I'm not exactly sure why this is happening.  Clearly it seems like a
   bad idea to do this, but I'm not sure why it is an error (The developer
   says it works when compiled for DOS/Windoze)

A. I'm pretty sure that glue simply doesn't support having a separate
   namespace for each .obj file, at least not for "types". Even this
   will not work:

   foo.c:
       char * x;

   bar.c:
       int x;

   All variables declared outside of routines in C for GEOS get put
   into that geodes DGROUP, so there is not a separate name space for
   them.


How to hide objects from the user.

SDK: ALL_GEOS:PUBLIC
Here's a template for a "hidden group" object:

@object GenInteractionClass MyHiddenGroup = {
    GI_comp = ;
    GII_attrs = @default | GIA_NOT_USER_INITIATABLE;
    GII_visibility = GIV_DIALOG;
}

Any objects that are children of this hidden group will not be visible
to the user. You could put dialogs under this object and then display
them using MSG_GEN_INTERACTION_INITIATE or UserDoDialog. Be sure that
any dialogs under the hidden group have a GII_visibility of GIV_DIALOG.
If you forget to set this the dialog will not appear when you send the
MSG_GEN_INTERACTION_INITIATE message.

The hidden group should be a child of a visible object in the Gen tree,
most likely the GenPrimary.


How do I get the thread handle of the UI thread?

SDK: ALL_GEOS:PUBLIC
Q. How do I get the handle of my application's ui thread? In other words,
   the thread that runs the application object and GenPrimary (as opposed
   to the system ui thread).

A. Use MemGetInfo on your ui block using MGIT_EXEC_THREAD. For instance,
   you could do something like the following:

     ThreadHandle uiThread;
     uiThread = MemGetInfo( OptrToHandle( @MyApplication ),
                            MGIT_EXEC_THREAD );

   This is assuming you've properly defined the resource containing the
   application object in your .gp file (i.e. have its resource set to
   ui-object).


@dispatch gives compile time error

SDK: ALL_GEOS:PUBLIC
Q. If I try a "@dispatch null::null::myEvent;", the compiler gives
   an error. In fact, I cannot convince @dispatch to accept any of
   the alternative objects or messages. Nor will it have anything
   to do with the 'noFree' flag. What's wrong?

A. Currently, GOC accepts the following grammar for @dispatch and
   @dispatchcall:

   @dispatch ;
   @dispatchcall () ;

   If you want to change the recorded destination, call
   MessageSetDestination() first, then do the @dispatch.


Don't allow zero-sized elements of variable-sized ChunkArray

SDK: ALL_GEOS:PUBLIC
The system code makes the assumption that no variable-sized element
of a chunk array has zero size.  The system will allow you to create
zero-sized elements, but it can lead to memory scribbling and other
mysterious and unpredictable bugs.


Glue:

Glue: _TEXT is very large, that is a BAD thing

SDK: ALL_GEOS:PUBLIC
Here's what to do if Glue starts giving you this warning
    Warning: _TEXT is very large, that is a BAD thing

First of all, this error indicates that the code resource in the
.goc file is too large (has grown larger than 10K).  The code
resource is automatically created and contains code from your method
handlers.

To reduce the size of the _TEXT resource, you must take some of the
methods out of that source file and put them into a new file.  For
instance, I usually have a .goc file for each class's methods.  If
I've got process class methods, I have a process.goc file for them.
If I've got a subclassed view class then I have a view.goc file for
those methods.

If you have never split your code into multiple source files before,
check out the file LRGSORCE.TXT on the Developer Relations web site:

  http://www.geoworks.com/devrel/download.htm


Automatically updating protocol numbers with GREV.

SDK: ALL_GEOS:PUBLIC
Q. Are there special rules with respect to version numbers and protocol
   numbers of device drivers?

   For example in driver.def is the following definitions:

     ; Protocol number for "DriverFunction" interface. All other driver
     ; protocols
     ; will be based on this number.
     ;
     DRIVER_PROTO_MAJOR	equ	2
     DRIVER_PROTO_MINOR	equ	0

   and in the header for DR_INIT:

     protominor KernelDR_INITWithGeodeHandle ; etype

   What are the (standard) means to control version numbers and protocol
   numbers? I used the -P and -R parameters of Glue to set my version
   number to 2.0.0.0 and my Protocol number to 2.0. I know GREV can also
   be used to control version numbers, but I had difficulties using it.

A. Use Grev. It is the tool for setting both the protocol and revision
   numbers of the geode you're writing. The -P and -R only display the
   current protocol and revision numbers, not change them. Here are some
   examples of using grev:

   - Create .rev file:
     grev new myapp.rev

   - Update protocol major number:
     grev NPM myapp.rev

   - Update protocol minor number:
     grev npm myapp.rev

   - Change release/revision number:
     grev newrev myapp.rev x.y.z

     [Note that the book is incorrect in showing only two digits. Grev
     wants three period-separated numbers.]

   For more information on grev, see section 10.7 in the Tools book.


Limitations to using ThreadDestroy in GOC.

SDK: ALL_GEOS:PUBLIC
ThreadDestroy and its C stub should never be called from a movable
resource, or from a fixed resource that is called (indirectly) from
some movable resource, as ThreadDestroy does not return to its caller
and all the movable resources in the calling stack will be left locked
forever.

The solution is to never call ThreadDestroy. Instead, use ThreadCreate to
begin executing a certain routine. When that routine is finished, the
system will call ThreadDestroy to get rid of the thread for you.

The above is only true for procedural threads created using ThreadCreate.
For event-driven threads created with MSG_PROCESS_CREATE_EVENT_THREAD
you should send MSG_META_QUIT to the new thread to destroy it. You can
send the message from the same thread or from a different thread.


BORLAND.C: assert(los->u.localVar.type == typeIndex) failed

SDK: ALL_GEOS:PUBLIC
Q. I get the following error when I compile:

   BORLAND.C: Line 2778: assert(los->u.localVar.type == typeIndex) failed.
   ***error code  -1

A. This may be caused by odd variable declarations. Check your source
   code for such things as a local variable shadowing a global or a nest
   scope of local variables or something else unusual with a local
   variable.


How to make a dialog box with no triggers.

SDK: ALL_GEOS:PUBLIC
Q. How can I have a small dialog on the screen that doesn't have any of
   the default Ok or Cancel triggers on it?

A. Yes, here is some sample code that explains the necessary hints and
   attributes to make a dialog with no triggers. Note that this code can
   be made to work on any GEOS platform, although this particular sample
   was written for the Nokia 9000 Communicator.

  /*
   * This object groups all the program-initiated
   * objects together into one place. See the
   * SDK_C/GENINTER sample application for an
   * explanation of this concept.
   */
@object GenInteractionClass PopUpHiddenGroup = {
    GI_comp = @PopUpFlashBox;
    GII_attrs = @default | GIA_NOT_USER_INITIATABLE;
}

  /*
   * This is the popup dialog. It has one child, the
   * text input object PopUpFlashText.
   */
@object GenInteractionClass PopUpFlashBox = {
    GI_comp = @PopUpFlashText;
    GII_attrs = @default | GIA_NOT_USER_INITIATABLE
                         | GIA_INITIATED_VIA_USER_DO_DIALOG
                         | GIA_MODAL;
    GII_visibility = GIV_DIALOG;
      /*
       * This prevents the automatic Ok and Cancel triggers
       * from appearing.
       */
    GII_type = GIT_MULTIPLE_RESPONSE;
      /*
       * This makes the window the correct size (small).
       */
    HINT_WINDOW_NO_TITLE_BAR;
      /*
       * Modify these two values to position the dialog
       * on the screen, relative to the primary window.
       */
    HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT = {
        SWSS_RATIO | PCT_15,
        SWSS_RATIO | PCT_5
    };
}

/********************************************************************
 *		Code for PopUpApplicationClass
 * This class is just a subclass of FoamSubApplicationClass. You
 * could use GenApplicationClass if you're writing for some other
 * version of GEOS.
 *******************************************************************/

/********************************************************************
 *		MSG_META_KBD_CHAR
 ********************************************************************
 * SYNOPSIS:     Intercept the keyboard press at the application
 *               level. Here we can handle it appropriately.
 * PARAMETERS:   word character
 *               word flags
 *               word state
 * RETURNS:      void
 * SIDE EFFECTS: none
 * STRATEGY:     First call the superclass so the default keypress
 *               handling behavior is performed. Then check to see
 *               that this is the release of the spacebar. If it is
 *               then we can initiate the popup dialog.
 * REVISION HISTORY:
 *	Name	Date		Description
 *	----	----		-----------
 *	NF	1/7/97          Initial version
 *******************************************************************/
@method PopUpApplicationClass, MSG_META_KBD_CHAR
{
      /*
       * icReply - Return value from UserDoDialog. Indicates how the
       *           dialog was closed.
       */
    InteractionCommand icReply;

    @callsuper();

    if ( ( flags & CF_RELEASE ) &&
         ( ' ' == character ) ) {
        icReply = UserDoDialog( @PopUpFlashBox );
        /*
         * icReply will be one of several things:
         * IC_OK      - User hit Enter.
         * IC_DISMISS - User hit Esc.
         * IC_NULL    - System is shutting down.
         */
        if ( IC_OK == icReply ) {
              /*
               * Dismiss the interaction since IC_OK doesn't
               * do that automatically.
               * Here you can grab text from PopUpFlashText.
               */
            @send PopUpFlashBox::MSG_GEN_GUP_INTERACTION_COMMAND(
                IC_DISMISS );
        }
    }
} /* MSG_META_KBD_CHAR */

/********************************************************************
 *		Code for PopUpTextClass
 * This is just a subclass of GenTextClass.
 *******************************************************************/

/********************************************************************
 *		MSG_META_KBD_CHAR
 ********************************************************************
 * SYNOPSIS:     Intercept the keyboard press at the input text
 *               level. Here we can handle it appropriately.
 * PARAMETERS:   word character
 *               word flags
 *               word state
 * RETURNS:      void
 * SIDE EFFECTS: none
 * STRATEGY:     First call the superclass so the default keypress
 *               handling behavior is performed. Then check to see
 *               that this is either a Return or an Esc.
 * REVISION HISTORY:
 *	Name	Date		Description
 *	----	----		-----------
 *	NF	1/7/97          Initial version
 *******************************************************************/
@method PopUpTextClass, MSG_META_KBD_CHAR
{

      /*
       * Superclass for single-line GenText doesn't
       * do anything with Enter or Esc.
       */
    @callsuper();

    if ( flags & CF_RELEASE ) {
        if ( C_ENTER == ( character & 0x00FF ) )  {
            @send PopUpFlashBox::MSG_GEN_GUP_INTERACTION_COMMAND(
                IC_OK );
        }
        if ( C_ESCAPE == ( character & 0x00FF ) )  {
            @send PopUpFlashBox::MSG_GEN_GUP_INTERACTION_COMMAND(
                IC_DISMISS );
        }
    }
} /* MSG_META_KBD_CHAR */


What is the _inline macro (or what is CHANGE_SEGMENT)?

SDK: ALL_GEOS:PUBLIC
Q. What is "_inline"? It used to be in the irFaxMod sample app and it
   doesn't compile under Borland C++.

   or

   I've seen some code that has the words CHANGE_SEGMENT and
   RESET_SEGMENT. What are they used for?

A. The _inline macro is a HighC directive to produce assembly code in
   the middle of your C code. You can replace it with the equivalent
   asm directive in Borland C++. Here is an example:

   #define PUSH_DS _inline( 0x1e )  /* push ds */

   replace the above line with:

   #define PUSH_DS asm { push ds };

   Although, in that particular usage in IrFaxMod where ds is set up to
   point to the geode's own dgroup, it's better to use the CHANGE_SEGMENT
   and RESET_SEGMENT macros, defined like so:

   #define CHANGE_SEGMENT  word wTemp;                            asm { mov wTemp, ds };                            GeodeLoadDGroup( GeodeGetCodeProcessHandle() )

   #define RESET_SEGMENT   asm { mov ds, wTemp }

   Using CHANGE_SEGMENT stores the current DGROUP segment in the wTemp
   variable, and loads DS with the library's dgroup. RESET_SEGMENT
   restores the app's DGROUP segment. Use the macros like so:

   CHANGE_SEGMENT;

   /* code here */

   RESET_SEGMENT;


How to remove an object and resource created by ObjDuplicateResource.

SDK: ALL_GEOS:PUBLIC
Q. How do I remove an object and resource created by ObjDuplicateResource.

A. After disconnecting the object from the object tree (use MSG_VIS_REMOVE,
   MSG_GEN_REMOVE, or a similar message), use ObjFreeDuplicate.  This will
   free the resource block that contains the object.


How do I reset the Nokia 9000 Communicator?

SDK: N9000C:PUBLIC
Option 1:

To reset the Nokia 9000 Communicator and effectively erase every bit of
data on the phone (except, of course, the factory settings and data) you
must pull out the main battery, put it back in, then hold down the keys
Shift-Esc-f. You will be prompted to format the RAM of the device and you
can cancel here if you don't really want to erase the data. Once the phone
has been reset you must re-enter all of the user data again, including
your home country, name, and address.

Option 2:

To delete just the GEOS.INI file you can use Ctrl-Esc-[right arrow].
This will erase some of your user settings. It is used mainly in the
event that the INI file becomes corrupted by an unfinished application.


Why FileEnum returns non-zero but invalid handle

SDK: ALL_GEOS:PUBLIC
FileEnum normally returns the number of files matched as a return value.
Therefore a return of zero means no matches found. You would think that
you could check for non-zero return value to signal that some files where
found. However this isn't quite so. The one time that FileEnum returns
non-zero on failure is when an error occured during the search.  If an
error occurs during the search, FileEnum returns -1. Because of this,
you cannot assume that a non-zero return value equates to files being
found; you must check if the returned value is -1.

Usually, you will come across this quirk by getting a Death due to
ILLEGAL_HANDLE after calling FileEnum. On failure, FileEnum returned
a non-zero value along with a null memory handle.


What does the 'noload' keyword mean in the .gp file?

SDK: ALL_GEOS:PUBLIC
The 'noload' keyword means that the library doesn't automatically get
loaded when your application starts up. However, if your application
calls routines within the library, the 'noload' flag will be ignored
by Glue.

What noload does allow you to do is refer to constants defined within
a given library without actually forcing that geode to be loaded.
It's very handy when you want to share a data structure, but not
actually share any code.

If you do want to call routines within the library without Glue
ignoring the 'noload' flag, you will need to access the routines
via the library's entry point routine. Here's an example of
how that is done:

    libHandle = GeodeUseLibrary( "mylibrary",
                                 MAJOR_PROTO,
                                 MINOR_PROTO,
                                 &errs );
    funcPtr = ProcGetLibraryEntry( libHandle, entryNumber );
    ProcCallFixedOrMovable_pascal( [function_parameters,] funcPtr );

Remember that you need to call GeodeUseLibrary to load the library before
trying to call the routines.


Recreating a lazarus condition

SDK: ALL_GEOS:PUBLIC
The Lazarus effect occurs when an app is exited, and restarted again
before it was fully exited. Generally what will happen is global
variables will already be initialized and memory blocks and UI elements
will already exist. This can lead to memory leaks and UI problems if
you aren't testing for this condition. Handling these problems is
generally as simple as checking for the existing UI objects or
memory blocks, as well as initializing global variables in your
MSG_GEN_PROCESS_OPEN_APPLICATION method.

Here's how to test for the lazarus condition:
 - start the app
 - break in swat
 - type "exit {appname}"

As soon as the home screen is visible and before the app fully exits,
hit its icon to start it up again.

This causes a lazarus condition: the app goes all the way down to
engine mode, then realizes it needs to restart and runs
MSG_GEN_PROCESS_OPEN_APPLICATION without the usual cleanup code
getting executed (in MSG_GEN_PROCESS_CLOSE_APPLICATION, for example).

This can cause problems if the app expects dgroup data to be
initialized a certain way or if items are dynamically allocated and
manipulated on startup without checking if they have already been
created. Eventually, dgroup will be automatically reinitialized in
this case, but not as things stand, so watch out.

There are a number of ways you can tell if your app is restarting
without fully detaching: the AppAttachFlags passed in
MSG_GEN_PROCESS_OPEN_APPLICATION mention it. Or you can add some
vardata element to an object on startup and check for its existence
before doing one-time-only code.


How to right justify text in a GenText object.

SDK: ALL_GEOS:PUBLIC
Q. How do I get a GenText's text to be right justified?

A. Add the following attribute to the text object definition:

   ATTR_GEN_TEXT_DEFAULT_PARA_ATTR = {
       ( J_RIGHT << VTDPA_JUSTIFICATION_OFFSET )
   };

   There is also a J_LEFT and a J_CENTER which will left justify and
   center the text, respectively.


How does RGB color index mapping work?

SDK: 2.0:PUBLIC
Q. How does RGB to color index mapping work? When we call GrMapColorRGB,
   passing a created gstate with a null window handle, the value that
   comes back is consistent, but that what gets displayed using that
   index is somewhat random.

A. There is a bug in GrMapColorRGB (for the OmniGo and Nokia 9000) so it
   only works when the passed gstate is associated with a window and has
   a palette. To work around this, you can use GrMapColorRGB like this:

    WindowHandle window;
    GStateHandle gstate;
    int          index;

    window = @call GeodeGetAppObject( 0 )::MSG_VIS_QUERY_WINDOW();
    gstate = GrCreateState( window );
    GrCreatePalette( gstate );
    GrMapColorRGB( gstate, red, green, blue, (Color*)&index );
    GrDestroyState( gstate );

   The values returned by GrMapColorRGB is based on the default palette
   for the given device and is independent of the video driver. You can
   change the palette you use by calling GrCreatePalette.

   If you want to have just 16 colors, call GrCreatePalette and then
   GrSetPalette to clear out the last 240 entries.

       gstate = GrCreateState( window );
       GrCreatePalette( gstate );
       memset( nullColors, 0, 240 * sizeof( RGBValue ) );
       GrSetPalette( gstate, nullColors, 16, 240 );
       GrMapColorRGB( ... );


Mixing C and assembly - an introduction.

SDK: ALL_GEOS:PUBLIC
You may sometimes wish to combine GOC and Esp code in a single
application. There are two main times when you may want to do
this. You may be writing an application in GOC, but find that the
application is spending a lot of time in a few critical routines; in
this case, you may be able to improve efficiency by rewriting those
few routines in assembly. If you don't want to rewrite the rest of the
application, you will have to write those routines so they can be
called from C.

On the other hand, you may be writing a library that has a lot of
time-consuming routines. In this case, you may find it worthwhile to
rewrite the entire library in assembly, while preserving a GOC
interface. That way, all the applications that use the library will be
able to take advantage of the efficiency of assembly code. (For
example, most GEOS system libraries are written in assembly.)

In particular, if you design a new object class that is being used by
many different applications, it may be worthwhile to write a library
which defines that class of object. You can write all the method code
in assembly, while providing a GOC interface; this lets every
application that uses the class take advantage of assembly's
efficiency.

    A.1	Calling Conventions

Glue can automatically link Esp routines into a GOC application or
library. The programmer, however, has to write the routine to present
an appropriate interface. To do this, the programmer will have to
understand GOC calling conventions.

GOC uses the calling conventions of whatever C compiler it is
using. All C compilers support standard-C calling
conventions. Furthermore, all C compilers that work with the GEOS SDK
(including Borland and High-C) allow a specific routine to use Pascal
coding conventions.

You can use either the C or the Pascal coding conventions. However,
most GEOS GOC routines use the Pascal calling conventions, and we
encourage programmers to do the same. The Pascal calling conventions
are generally more efficient than the C conventions. The only time you
will need to use C calling-conventions is when your routine takes a
variable number of arguments (as, e.g., printf() does).

There are three basic differences between C and Pascal calling
conventions. The differences are listed in brief here, and discussed
at length below:

+ In the C calling conventions, arguments are pushed right-to-left
  (the last argument in the routine declaration is the first argument
  pushed). In the Pascal convention, arguments are pushed
  left-to-right.

+ In the C calling convention, the caller pops arguments off the stack
  after the called routine returns. In the Pascal calling convention,
  the called routine pops the arguments off the stack before
  returning.

+ In the C calling convention, the routine may be in mixed-case. In
  the Pascal calling convention, the routine name is automatically
  folded to ALL-CAPS.

    A.1.1	Passing Arguments

Arguments are passed differently in the C and Pascal calling
conventions. As noted above, if a routine uses the C pass-and-return
conventions, it expects the arguments to be pushed from right to left;
if the routine uses Pascal calling conventions, it expects the
arguments to be passed from left to right.

For example, suppose you write two similar routines, one of which uses
the C calling conventions and one of which uses the Pascal
conventions:

extern void _cdecl
CRoutine( int cArg1, int cArg2, int cArg3 );

extern void _pascal
PascalRoutine( int pArg1, int pArg2, int pArg3 );

When you call the C-style routine, the C compiler generates code to
push the arguments on the stack, pushing first cArg3, then cArg2, then
cArg1. It then leaves space for a call to the external routine (Glue
takes care of filling this in). When the routine returns, it pops
three words off the stack. Thus, the GOC code

CRoutine( 11, 22, 33 );

is compiled to something like

push 33			; argument cArg3
push 22			; argument cArg2
push 11			; argument cArg1
call CRoutine		; The linker fills this in

; Here the routine is called, and returns,
; destroying its own stack frame but leaving the
; passed arguments on the stack

add	sp, 6		; Pop 3 words off the stack

When you call the Pascal-style routine, the C compiler generates code
to push the arguments on the stack, pushing first pArg1, then pArg2,
then pArg3. It then leaves space for a call to the external routine
(Glue takes care of filling this in). The called routine takes care of
popping the arguments off the stack; when execution returns to the
caller, they have already been popped.  Thus, the GOC code

PRoutine( 11, 22, 33 );

is compiled to something like

push 11			; argument pArg1
push 22			; argument pArg2
push 33			; argument pArg3
call PRoutine		; The linker fills this in

; Here the routine is called, and returns,
; destroying its own stack frame and popping the
; passed arguments off the stack

    A.1.2	Naming Conventions

There is one other major difference between C and Pascal routine
conventions. In C, the names of routines are case-significant. You can
(e.g.) have three different routines named "MyProc", "MYPROC", and
"myproc". In Pascal, on the other hand, case is not significant. No
matter what case you use when you name a routine or variable, the
compiler folds the case to ALL-CAPS.

This means that when you define or declare a routine to use the Pascal
calling conventions, many C compilers will, again, fold case to
all-capital letters. (For example, the Borland compiler does this.)
This means that in the Esp file where the routine is defined, you must
give it a name in ALL-CAPS. In the C file, you may not need to do
this; with many compilers, you can declare the routine to have a
mixed-case name, and the case will automatically be folded to
ALL-CAPS. For details, check your C compiler's documentation.

As an example, suppose you write a routine in assembly language,
called MyEspRoutine; but you wish to have a C resource call that
routine. (Let's assume the routine passes and returns nothing, for
simplicity's sake.) Further suppose your compiler is the Borland C++
compiler. In this case, you would name the routine thus in the Esp
code:

MYESPROUTINE			proc far

and declare the routine thus in your GOC file:

extern void
_pascal			MyEspRoutine( void );

    A.2	Adding Esp Code to a GOC Geode

Most people will find it easiest to write applications in GOC. For
most purposes, GOC is efficient enough; after all, whenever an
application is running a system routine, or sending a message to a
system-defined object, it is most likely executing assembly code.

However, some applications may have very computation-heavy,
time-consuming routines. This can be exacerbated if the application is
intended to run on a slower platform, or if the time-consuming
routines cannot (for some reason) be compiled efficiently. In this
case, you can sometimes improve efficiency significantly by rewriting
just those routines in assembly language.

All the routines in any single code resource must be written in the
same language (GOC or Esp). You will therefore have to segregate your
Esp routines into one or more resources. Since you lose efficiency if
resources are too small, it may be best to simply put all the Esp
routines into a single resource. Simply write an assembly file with
the routines; then declare all the routines in a C header file as
"extern". mkmf will automatically generate appropriate instructions to
compile and link the two resources.

For example, suppose you are writing a geode in GOC. This geode has a
single routine, AddUpThree(), that is passed three integers, adds them
up, and returns the sum. Let's suppose you wish to rewrite this
routine in assembly.

At first, this routine might be written like this:

Code Display A-1 The AddUpThree routine, in GOC

/***********************************************************************
 *		AddUpThree
 ***********************************************************************
 * SYNOPSIS:	 Adds three integers, and returns the sum.
 ***********************************************************************/
int
AddUpThree( int firstArg, int secondArg, int thirdArg )
{
    /* This would be so much faster in assembly... */
    return( firstArg + secondArg + thirdArg );
}

/* Then, in the body of some other routine, we'd call it like this: */

/* ... */
mySum = AddUpThree( 10, 20, 30 );
/* ... */

If we want to rewrite the routine in assembly, we must do two
things. First, we must write the actual routine in a .asm file:

Code Display A-2 The AddUpThree routine, in Esp

; First, we declare the routine name for export:

EspCode		segment
global	ADDUPTHREE:far
EspCode		ends

; We instruct Esp to use the "GEOS Convention", i.e. to use the Pascal
; pass-and-return convention and the medium memory model:
SetGeosConvention

And we write the actual routine:

COMMENT @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        ADDUPTHREE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

SYNOPSIS:	Add three integers; return the sum.

CALLED BY:	C resource; uses Pascal conventions

PASS:		On stack:	firstArg		(integer)
                secondArg		(integer)
                thirdArg		(integer)

RETURN:		Sum of arguments (in ax)

DESTROYED:	Check what registers your compiler lets you destroy

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@

ADDUPTHREE	proc	far	firstArg:word, secondArg:word, thirdArg:word

    .enter

    mov	ax, firstArg
    add	ax, secondArg
    add	ax, thirdArg

    .leave	; destroys stack frame

    ret	; pops arguments off stack

ADDUPTHREE		endp

Now, you just have to put an appropriate declaration in the C file (or
a C header file). Remember, different compilers handle the Pascal
naming conventions differently. Let's assume you're using Borland C++,
which automatically folds case for Pascal-convention routine names:

Code Display A-3 Declaring the Assembly Routine in a C File

/* We assume this application will be compiled by the Borland C++ compiler,
 * which automatically folds case of Pascal-convention routines. This means
 * that the linker will look for a routine named ADDUPTHREE.
 */

extern int _pascal
AddUpThree( int firstArg, int secondArg, int thirdArg );

/* We call the routine the same way we did before: */
/* ... */
mySum = AddUpThree( 10, 20, 30 );
/* ... */

    A.3	Writing an Esp Library

You may wish to write a library in Esp whose routines can be called by
either GOC or Esp code. This is very much like writing a library in
GOC. Simply write all the exported routines to use pascal
pass-and-return conventions. Remember to write both a GOC header file
and an Esp header file; that way, an application can include whichever
of these is appropriate. Make sure that both of these header files are
maintained in tandem, and accurately reflect the state of the library.

If you are writing an object library, you will need to write an Espire
header file (.uih), as well as the GOC and Esp header files. All three
header files must be maintained in tandem. Espire is discussed in "The
UI Compiler," Chapter 4.

The library is composed of three basic parts. First, there are the
header files. You will need to write at least one header file, in the
language in which the library is written. Ordinarily, you would write
two: one in GOC, and one in Esp. That way, the library's routines
could be called from either language. If you are writing an object
library, you will also have to write an Espire header file.

You might need to write an "entry point" routine, to handle
bookkeeping for the library. However, this is not always necessary;
some libraries do not have an entry point routine. Writing an entry
point routine in Esp is much like writing an entry point routine in
GOC.

Finally, you will have to write the code resources themselves. This is
much like writing a code resource for an application. The exported
routines should follow C or (preferably) Pascal calling conventions,
so they can be called by GOC code. The internal routines, if any, need
not follow these conventions.

    A.3.1	Esp Library Entry Points

Writing an entry point in Esp is very much like writing an entry point
in GOC. The routine has to perform the same basic functions, and may
be called under the same circumstances.

Not all libraries will need an entry point routine. If you do not
define an entry point in the library's .gp file, the kernel will not
try to call an entry point for the library.

The entry point is passed two arguments:

di	This is a member of the LibraryCallType enumerated type

cx	If di contains LCT_NEW_CLIENT or LCT_CLIENT_EXIT, cx contains
    the handle of the client geode; otherwise, this register's value
    is not defined.

The library should set CF if there is an error, and clear CF otherwise.

    A.3.2	Important Macros

DefLib, StartLibrary, EndLibrary

Every library will need some header files. Because a header file may
be included many times in a single object file, you should use certain
macros to prevent the data in the header from being compiled more than
once.

Every assembly header file should begin with the line

StartLibrary

and end with

EndLibrary

This macro checks to see if the library's header file has already been
included in the current compilation. If it has, the header file will
not be included again.

A code library's code files should include the library's header
file. However, when including the header file, it should not use
UseLib the way a regular application does. Instead, it should use
DefLib thus:

DefLib <  >

This macro includes the library's header file, but informs the Esp
assembler that the file is being included in the code of the library
itself.

    A.3.3	An Example of a Code Library

Suppose you want to write a code library in Esp, but you want the
library to be callable from either C or Assembly applications. For the
sake of argument, suppose that library contains only a single routine,
AsmLibDivByTwo(), which is passed an integer, shifts it to the right
one bit (using an arithmetic shift, to preserve the sign of the
integer), and returns the result. (Once you've written a library with
one routine, it's easy to add more.)

First we'll write the header files for the library. These header files
can contain definitions of structures, records, or enumerated types;
in this example, though, they define the exported routine.

Code Display A-4 A Library's Assembly Header File

COMMENT @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FILE:		asmlib.def

DESCRIPTION:

    This is the assembly header file for the AsmLib library. Make
    sure that it and CInclude/asmlib.h are maintained in tandem!

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@

StartLibrary	asmlib

include geos.def

; Structures, macros, etc. could be defined here...

; Now list exported routines

global	ASMLIBDIVBYTWO:far

; PASS:		(on stack)
;		intArg	= signed, 16-bit integer

; RETURN:		ax 	= IntArg / 2

; DESTROYED:		none

; SIDE EFFECTS:		Argument popped off the stackArgument popped off the
;		stack (as per pascal calling convention)

EndLibrary	asmlib

This file is very straightforward. Note that the name of the routine
is given in ALL-CAPS; this is because the routine is defined as using
the Pascal calling conventions. The C header file is slightly more
complicated:

Code Display A-5 A Library's C Header File

/***********************************************************************
 * FILE:	  asmlib.h
 ***********************************************************************/

#ifndef _ASMLIB_H_

#define _ASMLIB_H_

#include

/* Structures, macros, etc. could be defined here... */

/* Now list exported routines */

extern int
_pascal AsmLibDivByTwo(int numerator);

#ifdef __HIGHC__	/* High C needs to be told to convert the routine
             * name to ALL-CAPS */

pragma Alias (AsmLibDivByTwo, "ASMLIBDIVBYTWO");

#endif /* _ASMLIB_H_ */

The High-C compiler does not automatically convert the name of a
Pascal-style routine to ALL-CAPS, so we use a pragma to instruct it to
translate AsmLibDivByTwo to ASMLIBDIVBYTWO when compiling.

Now let's write the routine itself. Again, let's use the Pascal
conventions. The routine is passed a single argument, on the stack; it
returns an integer in ax.

Code Display A-6 A Library's Source Code File

COMMENT @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FILE:		asmlib.asm

ROUTINES:

    Name			Description
    ----			-----------
    ASMLIBDIVBYTWO		Divides an integer by two.

DESCRIPTION:

    This contains the code for the CodeLib library. Only one routine is
    defined, a simple divide-by-two routine. If the library had an entry-point
    routine, it might be put in this file.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@

include	geos.def
include	library.def
include resource.def

SetGeosConvention	; This macro instructs the assembler that the file will
            ; be using the pascal calling convention. This means
            ; that passed arguments will be popped off the stack
            ; automatically.

DefLib	asmlib.def

Main	segment resource  ; This resource has all code for this library

COMMENT @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        ASMLIBDIVBYTWO
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

SYNOPSIS:	This routine divides an integer by two. It uses Pascal calling
        conventions.

CALLED BY:	GLOBAL

PASS:		(on stack)
        intArg	= signed, 16-bit integer

RETURN:		ax 	= IntArg / 2

DESTROYED:	none

SIDE EFFECTS:	Argument popped off the stackArgument popped off the stack
;		(as per pascal calling convention)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@
ASMLIBDIVBYTWO		proc	far	intArg:sword

    .enter		; set up stack frame
    mov	ax, intArg
    sar	ax, 1
    .leave		; Destroy stack frame
    ret		; Since we're using the pascal calling convention, this
            ; "return" will pop the arguments off the stack.

ASMLIBDIVBYTWO	endp

Main	ends

Again, the code is fairly straightforward. This routine does not assume that
any values are passed in any registers. In practice, each C compiler passes
certain values in the registers to called routines, and also allows called
routines to destroy certain registers. You should check the documentation for
any C compilers which may link in the library before you rely on this.

Finally, the library needs a .gp file for the linker:

Code Display A-7 A Library's .gp File

##############################################################################
#
# FILE:		asmlib.gp
#
#	This is a sample library for the GEOS SDK. It demonstrates how
#	to write a simple Esp code library, which exports a single
#	routine.
#
##############################################################################

name asmlib.lib

library geos

#
# Specify geode type
type	library,single

#
# Information for the geode's extended attributes
#
longname	"Sample Assembly Code Library"

tokenchars	"SASL"
tokenid		0

#
# Define the library "entry point" here, if the library has one. You would
# do it like this:
#	entry	AsmLibEntryRoutine
#
# (This library doesn't have an entry point.)

#
# Define resources other than standard discardable code
# (this library has none)
#

#
# Exported routines
#
export ASMLIBDIVBYTWO

Again, this is straightforward. The only difference between this and
an application's .gp file is that the geode's type is "library", not
"appl". Also, if the library has an entry point routine, that routine
would be specified here with the "entry" keyword, as shown above.

Figure 1-1 Calling a routine with C calling conventions

(1) Just before the routine is called, the arguments are pushed on the
    stack; the last argument declared is pushed first.

(2) When the routine is called, it sets up its own stack frame below
    the passed arguments.

(3) When the routine returns, it pops its own stack frame off the
    stack, but leaves the passed arguments intact. The caller is
    responsible for popping the arguments off the stack. Figure 1-2
    Calling a routine with Pascal calling conventions.

(1) Just before the routine is called, the arguments are pushed on the
    stack; the first argument declared is pushed first.

(2) When the routine is called, it sets up its own stack frame below
    the passed arguments.

(3) When the routine returns, it pops its own stack frame and the
    passed arguments off the stack.


How do I load another geode?

SDK: ALL_GEOS:PUBLIC
There are several ways that your geode can launch another geode. There
is the very generic GeodeLoad, but there are also much easier routines
that are specific for the type of Geode. Here are the routines:

For an Application:
    UserLoadApplication
    IACPConnect

For a Library:
    GeodeUseLibrary (and GeodeFreeLibrary when finished)

For a Driver:
    GeodeUseDriver (and GeodeFreeDriver when finished)
    GeodeGetDefaultDriver for a standard Geos driver


What messages are good for initializing objects or the application?

SDK: ALL_GEOS:PUBLIC
Depending on what you want to initialize, there are several messages
that can be used.

For general application startup/shutdown work, use
    MSG_GEN_PROCESS_OPEN_APPLICATION & MSG_GEN_PROCESS_CLOSE_APPLICATION

For specific generic objects, use
    MSG_VIS_OPEN & MSG_VIS_CLOSE
    MSG_SPEC_BUILD

For dialogs, use
    MSG_GEN_INTERACTION_INITIATE & MSG_GEN_GUP_INTERACTION_COMMAND

For any object that you create dynamically, you can handle
    MSG_META_INITIALIZE.

In special cases, register on the MGCNLT_ACTIVE_LIST GCN list and handle
    MSG_META_ATTACH & MSG_META_DETACH

MSG_GEN_PROCESS_OPEN_APPLICATION is commonly used for setting up a
variety of things (opening an application specific vmfile for example).
Generally, you will want to do your specific processing after calling
the super class handler.

MSG_VIS_OPEN is sent to an object each time it or the tree that it is
in is visually built out.  This is usually once per launching of the
application.  Although it will not necessary occur when the application
is first launched.

MSG_SPEC_BUILD is similar to MSG_VIS_OPEN, but gets sent to generic
objects to tell them to build out their specific UI portions.

MSG_GEN_INTERACTION_INITIATE actually initiates bringing the dialog
onscreen.  Handle MSG_GEN_GUP_INTERACTION_COMMAND and watch for
IC_DISMISS to determine when the dialog is being brought offscreen.

MSG_META_INITIALIZE is only sent when a master class part of the
object is created.  When an object is statically defined, the Gen part
is already created statically, but the Vis part is not.  Hence when
the app starts, MSG_META_INITIALIZE is sent to the Vis part (which
bypasses your attempt to handle the message) but not the Gen part.
If you dynamically instantiate an object MSG_META_INITIALIZE will be
sent to the Gen part as well.

MSG_META_ATTACH and MSG_META_DETACH are received by an objects that
subscribe to the MGCNLT_ACTIVE_LIST.  This is really only necessary
for special cases, like a library that creates an object and wants
notification for when that object is attached and detached from an
application's object tree.


How do I get multiple columns in my GenDynamicList?

SDK: N9000C:PUBLIC
If you are using a GenDynamicList object and would like to have the
appearance of multiple columns, and you are using the Nokia 9000
Communicator SDK, you can use the CreateVisMonikerLine() function to
achieve this. Here is a sample of how that is done:

    optr             moniker;
    VisMonikerColumn colTable[2];
    char             str1[10] = "First";
    char             str2[10] = "Second";

    colTable[0].VMC_width = strlen( str1 );
    colTable[0].VMC_ptr = str1;
    colTable[0].VMC_just = J_LEFT;
    colTable[0].VMC_style = TS_PLAIN;
    colTable[0].VMC_border = CB_LEFT;
    colTable[1].VMC_width = strlen( str2 );
    colTable[1].VMC_ptr = str2;
    colTable[1].VMC_just = J_LEFT;
    colTable[1].VMC_style = TS_PLAIN;
    colTable[1].VMC_border = CB_LEFT;
    moniker = CreateVisMonikerLine( 12, FID_RESPONDER, 2, colTable );

    /*
     * You can now use moniker as a parameter to the GenDynamicList
     * in the MSG_GEN_DYNAMIC_LIST_REPLACE_ITEM_MONIKER_OPTR.
     * You would then free the moniker using MemFree, like so:
     */
    MemFree( OptrToHandle( moniker ) );


Getting the 'spinning world' dialog box for FAX, SMS, et al.

SDK: N9000C:PUBLIC
This gives a general overview of how to provide the user feedback
dialog that many of the Nokia applications use when sending a
file (FAX, SMS, etc.). This is the dialog that says, "Starting
to send ....", and displays an animated picture of the Earth with
an envelope spinning around it.

First, you need to use MailboxAddressControlClass to put up the
feedback dialog. Send MSG_MAILBOX_ADDRESS_CONTROL_CREATE_FEEDBACK()
to your MailboxAddressControlClass object with an optr to an
uninitialized MSCTransaction structure.

Upon returning, MSCT_feedback of the MSCTransaction structure
will contain the optr to the feedback dialog (FlashingNoteClass).

You must also set up a method for freeing the dialog's resource
afterwards. One easy way to do this is to send a timed event
like this:

    hTimer = TimerStart( TIMER_EVENT_ONE_SHOT,
                         ,
                         ,
                         MSG_GEN_DESTROY_AND_FREE_BLOCK,
                         0,
                         &timerID );
    /*
     * For safety, we make the mailbox own the timer. This way,
     * the timer event won't get freed if our application shuts
     * down before the timer fires.
     */
    hMailboxApp = GeodeFind( "mailbox", 7, 0, 0 );
    HandleModifyOwner( hTimer, hMailboxApp );

If you want, you can set the duration the dialog stays up by sending
MSG_FLASHING_NOTE_SET_DURATION (value must be more than 300).
Although it is not necessary, since MSG_GEN_DESTROY_AND_FREE_BLOCK
will take down the dialog when it is destroying it.


Can you set the No Carrier timeout (S7 register) on the N9000?

SDK: N9000C:PUBLIC
You will not be able to change the connection timeout when using
the ModemDial function.

This timeout is calculated beginning from the establishment of the
Radio Link Protocol (RLP) to detection of the carrier (CONNECT
response). So the timer is not started when a call is dialed with
the ATD or answered with the ATA- command.  The remote end has
already answered the call when this timer is started.  (This way
GSM signalling delays are not taken into account.)

Here is another explanation:

The traditional (previous generation) GSM-Data card is using the
modem S7-register slightly differently than Nokia 9000 Communicator.

This is how it normally works (Data Card):

1. Modem command: "ATS7=30"       (try to call next 30 sec.)
2. Modem command: "ATD0508534673" (dial 050-8534673)
3. Modem rings until A) 30 sec has passed or
                     B) gets "CONNECT" reply.

This is how the Nokia 9000 Communicator works:

1. Modem command: "ATS7=30"        (try to call next 30 sec.)
2. Modem command: "ATD0508534673"  (ring 050-8534673)
3. Modem rings until A) 60 sec has gone (this time is fixed) or
                     B) we get "ATA" reply (before the "CONNECT") and
4. Then we wait until A) we get the "CONNECT" reply or
                      B) 30 sec has gone.

So on the Nokia 9000 Communicator the S7 means time between
ATA -> CONNECT when normally it means time between ATD -> CONNECT.


Strange crashes with the emulators.

SDK: ALL_GEOS:PUBLIC
If you get any of the following errors while starting one of the SDK
emulators:

    KRX-181
    KR-29
    UI-26

    or in Swat:  COULD_NOT_OPEN_LOCAL_TOKEN_DATABASE_FILE

These errors can be caused by some files in the emulator directory being
marked as read-only. To fix this simply do "attrib -r *.* /s" from the
root of the emulator directory.


Zoomer emulator fails to start.

SDK: 2.0:PUBLIC
On the Zoomer NC emulator if you forget to load a DOS mouse driver you
will get an ILLEGAL_HANDLE error when the zsetup program executes.

On the Zoomer EC emulator if you forget to load a DOS mouse driver you
will get a FATAL_TE_SINGLE_STEP error when the zsetup program executes.

By "DOS mouse driver" I mean the popular mouse.com or lmouse.com program.
You normally launch this TSR (Terminate-and-Stay-Resident) from the
autoexec.bat file.


COM and LPT port recognition in GEOS.

SDK: ALL_GEOS:PUBLIC
Background

GEOS automatically recognizes a system's parallel (LPT) and serial
(COM) ports by checking data in the system's BIOS area. If it does not
recognize a port, the user will not be able to access it--it will
appear "grayed out" in every menu in which it appears.

Note that you can usually force GEOS to recognize a serial port by
adding its port number and IRQ to the [serial] category of the geos.ini
file.  For example, to tell GEOS that port 3 is on IRQ 5, add this:

[serial]
port 3 = 5

The crucial BIOS data consists of a set of port addresses and of an
"equipment word" listing which ports actually exist. Without the
address list, no program--GEOS nor any DOS program--can use a
port. The equipment word is ignored by some software, but GEOS does
look to this piece of data to establish whether a port exists.

An incorrect or overwritten "equipment word" will cause GEOS to not
recognize ("gray out") a system's serial and parallel ports.

Details

Here is the port data from a typical SYSINFO file:
Bios data area (0040h:0):

0000: f8 03 f8 02 e8 03 e8 02 78 03 00 00 00 00 00 00 "......x......"

0010: 61 48 af 80 02 00 00 00 00 00 26 00 26 00 0d 1c "aH......&.&..."

Port information is located in these two lines of BIOS data, dumped
directly from BIOS hardware. Serial port locations are listed
least-significant-byte-first at these locations:

0000: f8 03 f8 02 e8 03 e8 02

Translation: COM1, 2, 3, and 4 are located at 03f8, 02f8, 03e8, and
02e8, respectively.

From the same data, here is the location of the parallel port LPT1:

0000: f8 03 f8 02 e8 03 e8 02 78 03 00 00 00 00 00 00 "......x......"

This again is least-significant-byte-first, so LPT1: is located at
0378. On this machine, there is no LPT2:

The other key piece of data (and the one that sometimes causes
trouble) is the equipment word on the next line, in this case

0010: 61 48

This is a sort of list of exactly what equipment is installed on the
machine, including the number of parallel and serial ports installed.

Again reading least-significant-byte first, this example translates to
4861 hex. In binary:

 0100 1000 0110 0001

This gets interpreted as follows:

bit number  -  interpretation  -  in this case
----------  -  --------------  -  ------------

bit 0  -  set if IPL floppy present          -  yes
bit 1  -  set if math coprocessor installed  -  no
bit 2  -  set if ps/2 mouse installed        -  no
bit 3  -  set if ps/1 sound board installed  -  no

bits 4&5  -  video mode, as follows:  -  80x25 color

bit 5  -  bit 4
  0  -  0  -  usually EGA
  0  -  1  -  40x25 color
  1  -  0  -  80x25 color
  1  -  1  -  80x25 mono

bits 6&7      - # of floppy drives  2
bit 8         - reserved
bits 9,10,&11 - # of serial ports  4
bits 12&13    - reserved
bits 14&15    - # of parallel ports  1

If this equipment word is corrupted or overwritten, GEOS may not allow
access to the serial or parallel ports.


Serial ports, detecting and specifying in GEOS.INI.

SDK: ALL_GEOS:PUBLIC
DETECTING PORTS
---------------

GEOS determines which ports are available by checking the memory
locations 40:0 through 40:F.

Before running GEOS, you can use debug (or sid, if you're a DR DOS user)
to see which ports are enabled. If any of the four COM port locations
contain zeros, then that's as far as GEOS will go.

The same information should be in your SYSINFO file, too. Here's an example:

  Bios data area (0040h:0):
  0000: f8 03 f8 02 e8 02 00 00 78 03 00 00 00 00 00 00

F8 03 means COM 1 is active and available.
F8 02 is COM 2
E8 02 is COM 4
E8 03 would be COM 3 if it were there.

If it looks like this:
  Bios data area (0040h:0):
  0000: f8 03 f8 02 00 00 e8 02 78 03 00 00 00 00 00 00

then GEOS will never see COM4.

If it looks like this:
  Bios data area (0040h:0):
  0000: f8 03 f8 02 e8 03 e8 02 78 03 00 00 00 00 00 00

then it means you have all four COM ports available (and 78 03 is your
first parallel port).

Keep in mind that SYSINFO is only created when you first install GEOS,
so if things have changed in your hardware since you originally
installed GEOS, then you might not have current information in SYSINFO.
Using debug or sid will display things as they are now.

To use debug or sid, enter DEBUG or SID at the DOS prompt, then enter

  d 40:0

at the debug or sid prompt.
then enter q to quit.

You can also use debug or sid to poke values into those locations and
force GEOS to see ports that don't really exist.

INSTALLING GEOS PORT PROBLEMS
-----------------------------

Symptom: After running textual setup, the screen turns gray, then GEOS
locks up.

Cause: When graphical setup starts, it loads the serial driver which
tries to figure out which COM ports exists and what their interrupt
levels are. This problem can happen if the user has any COM ports set
to non-standard interrupt levels. The standard interrupt levels are:

  COM1 = 4
  COM2 = 3
  COM3 = 4
  COM4 = 3

The interrupt levels are set by DIP switches or jumpers on serial port
cards and modems cards. Some cards don't allow changing the interrupt
levels from the standard 4 (for COM1) and 3 (for COM2).

Work around: Add entries to the GEOS.INI file for each of the COM ports.
The entries are of the form 'portX = Y' (where X is the COM port number
and Y is that port's interrupt level) in the [serial] section. For
example:

[serial]
port1 = 4
port2 = 3
port3 = 5
port4 = 2

If a COM port doesn't exist, its entry can be omitted.


Socket error (specifically 5402).

SDK: N9000C:PUBLIC
  The socket error of 5402 is in decimal. It is a combination of
SE_LINK_FAILED / SSDE_INVALID_ACCPNT, a SocketError type and a
SpecSocketDrError type. Most of the Socket routines return a hybrid error
value, a combination of SocketError and SpecSocketDrError. This is
mentioned in the sockmisc.def file in the \pcgeos\include directory.

  INVALID_ACCPNT means either the access point does not exist, or that
it does not contain a phone number. If it is the latter case then you need
to call AccessPointGetType and verify that the access point you get is an
APT_INTERNET or not.


Declaring a Method As a Routine

SDK: ALL_GEOS:PUBLIC
If you have a class called HelloCounterClass then the "truncated" class
name is HelloCounter. The name of the message type for that class is
HelloCounterMessages. Thus all messages defined in HelloCounterClass
are of type HelloCounterMessages.

Shown below is the definition of the MSG_HELLO_COUNTER_RECALCULATE_VALUE
message, the function prototype for HelloCounterRecalculateValue, and how
the the method and function can be combined into one. This saves space and
makes the purpose of the code more clear.

@class HelloCounterClass;
@message int MSG_HELLO_COUNTER_RECALCULATE_VALUE(
    HelloPriority priority,
    word          randomDatum,
    char          aLetter );
@endc;

  /*
   * Function prototype, used if functions will call this
   * routine and the compiler hasn't see the routine
   * definition yet (i.e. it's defined in another file).
   */
extern int _pascal HelloCounterRecalculateValue(
    optr                 oself,
    HelloCounterMessages message,
    HelloPriority        priority,
    word                 randomDatum,
    char                 aLetter );

  /*
   * Here's where we combine the method and the function
   * into one unit of code to save space.
   */
@method HelloCounterRecalculate, HelloCounterClass,
    MSG_HELLO_COUNTER_RECALCULATE_VALUE {

    /* method code goes here... */
}


How to sort a chunk array.

SDK: ALL_GEOS:PUBLIC
The C stub for the ChunkArraySort function is broken on GEOS devices that
shipped before August 1996 (specifically, Casio Z-7000 & HP OmniGo 100).
To get around this problem you can use the ArrayQuickSort function instead.
It will only work on chunk arrays in which the elements are all the same
size (of course, ChunkArraySort has the same requirement, so not a real
problem). Be sure to lock down the chunk array and dereference it before
calling ArrayQuickSort.


Controllers and their help files.

SDK: ALL_GEOS:PUBLIC
Normally GenControl objects use the name of the library they are defined
in as the name of the help file that they will open when the user presses
the help button. If the attribute shown below is set, the library name
will not be used. Instead the help library will continue to go up the
generic tree looking for a help context.

ATTR_GEN_CONTROL_DO_NOT_USE_LIBRARY_NAME_FOR_HELP;

This can be useful if your application is using a system defined controller
and you want it to provide help specific to your application.


Testing FAXing with Class 2 modems.

SDK: N9000C:PUBLIC
The Class 2 fax/modem drivers written for the Nokia 9000
Communicator emulator do not support ECM. If you try to use
the modem with ECM on, your faxes will probably never be sent.

To turn ECM off go to Settings in the Fax app, ECM is near the
bottom.

The Class 1 drivers still ignore ECM so if you are using those
drivers you do not have to make any changes yet.


Broken C-stubs: Token...() routines

SDK: ALL_GEOS:PUBLIC
The following Token routines have broken c-stubs for all GEOS based
products shipping before January 1997 (specifically: Ensemble 2.x,
Casio Z-7000, Sharp PT-9000, Tandy Z-PDA, AST GridPad 2390, HP OmniGo
100/120, Nokia 9000 Communicator, and New Deal Office 2.5):

TokenGetTokenInfo 	- trashes memory
TokenLookupMoniker 	- stack corruption
TokenLoadMonikerBlock 	- stack corruption
TokenLoadMonikerChunk 	- stack corruption
TokenLoadMonikerBuffer 	- stack corruption
TokenLockTokenMoniker 	- stack corruption

There are currently no known work-arounds.


Deleting .sym & .gym files to save disk space.

SDK: ALL_GEOS:PUBLIC
If the SDK is taking too much disk space, you can trim down the amount
of disk space used by deleting SYM files. If a SYM file is missing,
Swat will use the geode's GYM file.

GYM files are Generic Symbol files. They contain just enough information
to make swat happy, but are generic enough that they can be used on most
versions of the corresponding geode (radical changes in the geode can
cause problems, though). The one drawback to using GYM files is that you
won't get the detail of symbol information when stepping through a system
geode.

There are a couple of geodes for which Swat requires the detailed
information in the SYM files. These are the Loader, Kernel, Generic UI,
and Specific UI. All others (usually) don't matter.


Determining version, country code or keyboard type on N9000C.

SDK: N9000C:PUBLIC
You can get version information from the INI file on the Nokia 9000
Communicator. The information is stored as a string in [UI]swSerialNumber.
The string is 27 characters long. This same string can be seen on the last
line of About this product. The whole string looks like this:

    000000/00/2a0030808044001/0.

The interesting part is: 2a0030808044001. The three first characters
identify hardware version (here 2.10), six following characters identify
software version (here 03.08.08), three following characters identify the
country code (44 = Great Britain) and the last three characters identify
the keyboard type (here 001 = English).

Here is sample code that shows how to extract the version information:

@start StringRes;
    @chunk TCHAR UICategory[] = "ui";
    @chunk TCHAR SWSerialNumber[] = "swSerialNumber";
@end StringRes;

...

@method TestProcessClass, MSG_TEST_PROCESS_GET_VERSION
{
    TCHAR   version[28] = "";
    TCHAR * category;
    TCHAR * key;
    word    value;

    MemLock( OptrToHandle( @UICategory ) );
    category = (TCHAR *) LMemDeref( @UICategory );
    key      = (TCHAR *) LMemDeref( @SWSerialNumber );
    InitFileReadStringBuffer( category,
         key,
         version,
         IFRF_SIZE | 28,
         &value );

    /*
     * Extract the information you want from version string.
     */
    MemUnlock( OptrToHandle( @UICategory ) );
}


Creating Fonts for GEOS.

SDK: ALL_GEOS:PUBLIC
  There are two kinds of fonts for Geos: bitmap and vector (outline).
  Sans and Mono are examples of vector fonts.
  Jsys and Notepad are examples of bitmap fonts.

  VECTOR FONTS

  There are a couple softwares that will convert True Type or
  Adobe Type 1 fonts to Geos format.

  A company named Ancer Technologies (Atech), now out of business,
  produced a font converter named AllType that would convert from
  Type 1 or True Type directly to Geos format. AllType is hard to
  find, but last I heard it was available from the Download
  SuperStore on Prodigy or from Softdisk at 1-800-831-2694.

  Micrologic, located in Emeryville CA, makes two software
  products that may be used to convert Type 1 fonts to Geos format.
  You need both More Import and More Type.

  1. More Import (MI) will import Type 1 fonts to MicroLogic's own
  proprietary format. MicroLogic's More Fonts package includes MI starting
  with version 3.0. Owners of earlier versions of More Fonts or folks who
  own More Type (see below) can purchase MI directly from MicroLogic.

  2. More Type (MT) will export fonts from MicroLogic's own proprietary
  format to Geos format directly... or to NimbusQ (URW Generic) format,
  which the Geos Nimbus Font Converter will then convert to Geos format.

  The Geos Nimbus Font Converter will convert NimbusQ fonts to
  Geos format. It's available as part of Geoworks version 1.2
  desktop software, known as Ensemble or Quick Start.

  FontMonger, a Windows-based font conversion program, will convert
  fonts to a NimbusQ format that the Geos Nimbus Font Converter will
  recognize and will then convert to Geos format.

  I've seen some public domain cyrillic fonts converted to Geos
  format on BBSs, online services, and at Internet sites -- but
  the quality of PD fonts isn't usually very good.

  BITMAP FONTS

  Bitmap fonts are used for screen display, but not for printing.
  I don't know the details about how these are created...


Weird keyboard remapping after running PCCOM in a Win95 DOS box.

SDK: ALL_GEOS:PUBLIC
Q. When I run PCCOM in a DOS window on Windows '95, when I exit, keyboard
   processing is different - some characters are echoed fine, others do
   different things. First instance, "I"s do nothing, "J"s act like
   backspaces, etc. It's like they being interpreted as control characters.
   The problem is I can't type the word "EXIT" to get back to Windows, or the
   word "BREAK" to disable control-character processing (I don't know if that
   would help). Also, the display characteristics (chars per line, lines per
   screen) are different. Any suggestions as to how I can restore normal
   keyboard processing and screen characteristics?

A. The problem is that on a laptop, the numkeys are underneath the
   characters on the right side of the keyboard ('P', 'O', 'I', etc.) But,
   I think we got the problem solved now. We need to press Shift-NumKey to
   turn off numlock after starting PCCom. Everything works fine now.


How to make a 'font' setting for the mail editor.

SDK: N9000C:PUBLIC
Here is how to make a "font" setting for the mail editor which would
work in a similar way to the one in the Notebook app - just a menu of
fonts whose selection will be stored in the init file.

This is very complicated. A font control is not intended to work
independently of a text object, so you have to use an invisible text
object and some UI tricks.

Here is how Notebook does this:
* Create a dummy text object, not connected to the gen tree (I don't
  know if all these settings are required, but the safest approach
  is to use them all).

(TextSetupVisTextClass is a subclass of VisTextClass)

/*
 * Text object only used to set and get the text attributes.
 */
@class TextSetupVisTextClass TextSetupTextObject = {
    VI_optFlags = (@default) & ~VOF_GEOMETRY_INVALID;
    VI_attrs = (@default) | VA_REALIZED;
    VTI_state = VTS_EDITABLE | VTS_TARGETABLE;
    VTI_storageFlags = (@default) | VTSF_MULTIPLE_CHAR_ATTRS;
    VTI_charAttrRuns = @NotesEditTextCharAttrRuns;
    ATTR_VIS_TEXT_NOTIFY_EVEN_IF_NOT_TARGETED;
}

* Set the output of the font control to this text.
* When you open the settings window, read the current font information
  from the init file and set the appropriate parameters on the text
  object: MSG_VIS_TEXT_SET_FONT_ID(id, TEXT_ADDRESS_PAST_END, 0).
* Subclass MSG_VIS_TEXT_SET_FONT_ID to call superclass (which will set
  the controller), and then write the value to the init file.


How can I get the optr of a dialog's OK or Cancel trigger?

SDK: ALL_GEOS:PUBLIC
There is no way to get the optr of dialog's trigger if it is system
defined. You can however define your own trigger and thus easily
have its optr. Make the trigger a child of the dialog object and
add ATTR_GEN_TRIGGER_INTERACTION_COMMAND to the trigger. This
will cause it to perform all the functionality of a system defined
trigger.

ATTR_GEN_TRIGGER_INTERACTION_COMMAND takes a InteractionCommand like
IC_OK or IC_DISMISS.


How to make a simple terminal type text object

SDK: N9000C:PUBLIC
Q. For test/demo purposes we still would like to have a simple "stdio
   window" teletype console. Our test application would print text lines
   there and the window would scroll (like teletype screens usually do).

A. You can use a GenTextClass object. There are several examples of
   using this type of object. If you look at SDK_C\Serial or
   SDK_C\Serial2 sample application, they use GenTextClass objects in
   ways like you would want to.

   I will provide you with an example that should fit your specific
   needs. The following will create a text object that allows scrolling
   and text input by the user (you can disable input by adding the line
   "GI_attrs = @default | GA_READ_ONLY;" and removing the
   HINT_DEFAULT_FOCUS). It also uses the TERMINAL font, which is a font
   on the Nokia 9000 Communictor that allows you to display 80 characters
   per line.

   @object GenTextClass TeleText = {
       GTXI_attrs = @default | GTA_INIT_SCROLLING;
       GTXI_text  = "";
       ATTR_GEN_TEXT_CHAR_ATTR = @TeleTextCharAttrs;
       HINT_EXPAND_WIDTH_TO_FIT_PARENT;
       HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
       HINT_DEFAULT_FOCUS;
   }

   @chunk VisTextCharAttr TeleTextCharAttrs =
       CHAR_ATTR_FONT_SIZE( FID_TERMINAL, 16 );

   To add text to this text object, you would send
   MSG_VIS_TEXT_APPEND_PTR (or MSG_VIS_TEXT_APPEND_OPTR if the text to
   append is in a block).

   Normally, GenText objects simply append text and wrap as it reaches
   the right side of the object. You can add hard returns to force text
   to start at the right hand side of the text object. GEOS uses the
   '\r' character (0x0D hex) for carriage returns.

   If you want to put a grey frame around the text object (on the Nokia
   9000 Communicator), you will need to use the ComplexMonikerClass.
   Here is how you would do that:

   /*
    * We establish a grey rectangle around the text object to
    * make it stand out.
    */
   @chunk TCHAR InputMoniker[] = "Input";
   @object ComplexMonikerClass InputBox = {
       ComplexMoniker = GreyFrameClass;
       CMI_topText = @InputMoniker;
       CMI_textStyle = @default & ~TS_BOLD;
       GI_comp = @TeleText;  /* Note this points to the above defined
                                GenTextClass object. */
       HINT_CENTER_MONIKER;
       HINT_PLACE_MONIKER_TO_LEFT;
       HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
      HINT_EXPAND_WIDTH_TO_FIT_PARENT;
   }


How to get string of ClassStruct?

SDK: ALL_GEOS:PUBLIC
Q. Is there any convenient way I can find out the ClassStruct
   of a class given its name as a string?

   e.g.:
       ClassStruct * cs = foo( "ConverterClass" );

A. I'm afraid not, as the compiler doesn't store the names of the class
   (or any other compile-time symbol, for that matter) in any run-time
   location.


I get '

I get '.GEO' not remade due to errors.

SDK: ALL_GEOS:PUBLIC
'.GEO' not remade due to errors

is usually the result of a corrupt file in the Include directory.
Replace the three *.mk files in your Include directory with the
three from the CD-ROM.

If that doesn't work, then replace the files in the PCGEOS\BIN
directory.


Configuring Swat to run under Windows 3.1.

SDK: ALL_GEOS:PUBLIC
If you want to make Swat EC or Swat NC work from within Windows and
it doesn't seem to be working, i.e. you get errors like these:

  Phar Lap err 10049: Ran out of stack buffers

or

  Can't contact PC: Call timed out

Windows 3.1 doesn't treat COM 3 and 4 the same way it handles COM 1
and 2. If you've got the null modem cable connected to COM 3 or 4 try
connecting it to COM 1 or 2 and that should help Swat work correctly.


How is register es passed to process class methods?

SDK: ALL_GEOS:PUBLIC
Q. In the handler of a process class message, what does ES segment
   register contain when it is passed in? Does it point to the segment
   of the process class, dgroup, or something else? How about in both
   XIP and non-XIP cases?

A. It always points to the segment of the process class. If the class is
   in dgroup, es points to dgroup. If the class is in a separate resource,
   es points to that resource.

   Usually, class definitions are put in dgorup in non-XIP and a separate
   resource in XIP. So, usually, es points to dgroup in non-XIP and the
   separate resource in XIP.


How to safely synchronize threads accessing shared data

SDK: ALL_GEOS:PUBLIC
If your application or library provides data that will be accessed
by multiple threads, you should use semaphores to synchronize data
access.

First you must create the semaphore that will be used to control
access.  This is done with ThreadAllocSem().  Pass the value with
which to initialize the semaphore; this value represents the number
of threads that can grab the semaphore before other grab attempts
will block.  Typically, the passed value will be one.

You then use ThreadPSem() to attempt to gain access to the semaphore.
The thread will block until access is granted.

ThreadVSem() is used to release access.

For more information, see Concepts book, appendix B.5 "Synchronizing
Threads"


Details of VisMonikers

SDK: ALL_GEOS:PUBLIC
A visMoniker is a semi-complex structure which can be either a gstring
or simple text.  When you use the simple text, like

    @visMoniker MyMoniker = 'S',"SomeMoniker";

the only information stored is the text string and the offset to the
mnemonic.

If you use the full power of the visMoniker by associating a gstring
to it, you can set any type of text or graphic information you want
for that visMoniker.  Here is an example that sets the font to
FID_LED with a point size of 12.0:
    @visMoniker MyMoniker = {
        gstring {
            GSSaveTransform(),
            GSSetFont(FID_LED, 12.0),
            GSDrawText(2,2),
            "Some Moniker",
            GSRestoreTransform(),
            GSEndGString()
        }
    };

To help you understand the VisMoniker, here is a brief description
of the structure of a VisMoniker:
    VM_type (byte sized flag)
    VMT_MONIKER_LIST - if this set, then VM_data
        will be a list of VisMonikerListEntry structs.
    VMT_GSTRING - if set, the VM_data is a
        VisMonikerWithGString struct. if clear, then
        VM_data is a VisMonikerWithText struct.
    VM_width
    cached width of moniker
    VM_data
    Either VisMonikerWithText or VisMonikerWithGString
    depending on VM_type.
        VisMonikerText
            VMT_mnemonicOffset - offset to mnemonic, -1 if none
            VMT_text - start of null-terminated text
        VisMonikerGString
            VMGS_height - cached gstring height
            VMGS_gstring - start of gstring data


BORLAND.C: Line 2491: assert(base == ((genptr)sos - scopeOff)) failed

SDK: ALL_GEOS:PUBLIC
BORLAND.C: Line 2491: assert(base == ((genptr)sos - scopeOff)) failed.

This error is caused by the symbol for a variable being in a
block that is not within the lexical scope of the variable.

The most probable culprit for this is a source file that is
too large.  Try splitting the source into multiple files (this
can also speed compilation as files that are unchanged between
compilation do not need to be recompiled).

There is a description of how to split your source file up into
multiple files in the downloads section of the Geoworks web page
http://www.geoworks.com/devrel/download.htm

Some considerations when splitting up source code:
- The standard paradigm we use for multiple files under GOC is to have
  all object declarations in one file and then spread method code for
  individual classes into separate files.
- GLUE does not create the links between objects if they are in
  seperate source files.  By keeping children in the same file as
  their parent (i.e., all objects that are statically connected should
  be in the same file) you don't have to use MSG_GEN_ADD_CHILD to
  dynamically link objects that should be linked, but were located in
  seperate source files.

If the problem is not caused by an overly large source file, here are
some other possible reasons for the problem:
- if you are using a common variable name across multiple source files
- if you have defined an extra-ordinarily large number of variables
  within a given scope.  (Again, it's not clear how many is too many.)


How to set mouse pointer images

SDK: ALL_GEOS:PUBLIC
There are several ways to set the pointer image for the mouse.  Which
one you use will depend on what you are trying to do.  In a nutshell,
the options are:
 1. Set the busy/wait cursor with MARK_BUSY messages
 2. Drag/drop cursor
 2. Specify an image while the cursor is over a GenViewClass object
 3. Specify an image while the cursor is over any given object

1. Setting the busy/wait cursor:
The system puts up a busy cursor whenever MSG_GEN_SYSTEM_MARK_BUSY or
MSG_GEN_APPLICATION_MARK_BUSY is sent.  The busy cursor is cancelled
with MSG_GEN_APPLICATION_MARK_NOT_BUSY and MSG_GEN_SYSTEM_MARK_NOT_BUSY.

2. You can set the cursor to the standard drag and drop images by
calling ClipboardSetQuickTransferFeedback() or initiating a clipboard
action with ClipboardStartQuickTransfer().  ClipboardEndQuickTransfer()
will reset the image.

3. Specify point image to display in GenViewClass object.
Send MSG_GEN_VIEW_SET_PTR_IMAGE to the object.  See Defining A Cursor
Image and Mask below.

4. Specify image for an object
One can change the cursor when handling mouse messages.  Each of the
mouse message's MouseReturnParams *retVal structure can take an optr
to a new cursor image, if retVal->flags includes MRF_SET_POINTER_IMAGE.
Generally, if you are handling the mouse message, you will want to
return
    retVal->flags = MRF_PROCESSED | MRF_SET_POINTER_IMAGE;

To reset the default pointer image, use MRF_CLEAR_POINTER_IMAGE.

See Defining A Cursor Image and Mask below.

Defining A Cursor Image and Mask
--------------------------------
To define a cursor image and mask, use the PointerDef16, PointerDef32,
or PointerDef64 structures which are defined in graphics.h.  Here is
an example of a simple cross using the most common pointer size:

@chunk PointerDef16 CrossHair = {
    16, /* pointer width */
    16, /* pointer height */
    8,  /* X offset to hot spot from left */
    8,  /* Y offset to hot spot from top of image */
    /* PD_mask */
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    /* PD_image */
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0xFF, 0xFF,
    0xFF, 0xFF,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80,
    0x01, 0x80 };

The picture data for the pointer is organized as two buffers
that immediately follow the PointerDef structure.  The first buffer
is the mask, the second buffer is the image.  Each buffer is
organized in scan line order, left to right and top to bottom.
The bits in the mask and image combine with the existing screen
contents in the following way:

        mask	image	->	screen
        pixel	pixel		pixel
        -----	-----		------
          0	  0		unchanged
          0	  1		xor
          1	  0		black
          1	  1		white


Accessing a word of a dword variable (eg, handle of optr) in assembly

SDK: ALL_GEOS:PUBLIC
In ESP, you can grab the chunk or handle of an optr with the
".chunk" and ".handle" postfix.  Here's an example:

mov	oself.handle, ds
mov	oself.chunk,  si

You could also use ".segment" and ".offset" or ".high" and ".low"
for similar needs.


MSG_GEN_APPLICATION_MARK_BUSY not working over dialog box.

SDK: ALL_GEOS:PUBLIC
Q. We've got a dialog box that comes up while we read info
   (slowly) from the network. It's sys_modal. We want to
   set the busy cursor. We send MSG_GEN_APPLICATION_MARK_BUSY,
   but the cursor is only busy when it's over the primary - if
   we move it over the dialog it is NOT busy. What am I doing
   wrong?

A. By default modal/sysmodal dialogs override input restrictions.
   You can change this by adding the attribute
   ATTR_GEN_INTERACTION_ABIDE_BY_INPUT_RESTRICTIONS to the dialog.


'Internal (memory) error' in GEOS.

SDK: ALL_GEOS:PUBLIC
  Three possible error messages and their generic meanings:

Internal (memory) error. (Retry/Reboot)
       Running out of heap space

Internal (memory) error. (Continue)
       Running out of handles

Internal (memory) error. (Reboot)
       Fatal errors, KR-0 to gazillion.

  If you're getting these errors while running your app, you should
probably run the app in the error-checking demo with Swat connected.
That will give you more meaningful error messages and help you find
the bug.


Calling an assembly routine from GOC.

SDK: ALL_GEOS:PUBLIC
Q. I'm writing a Goc application with a single routine in assembly.
   I prototype the routine (MyDraw) as follows in myapp.goc:

     extern void _far _pascal MyDraw( GStateHandle gstate );

   mydraw.asm contains the Esp source for MyDraw.

   Both files compile successfully, but Glue fails, giving the error:

     file "myapp.goc", line 261: error: MyDraw undefined
     *** Error code 1

   How can I get Glue to link in the routine in the Esp resource?

A. Since you declared MyDraw, in myapp.goc, as using the Pascal
   calling convention, you need do the following in mydraw.asm:

     1) Up-case the name of the MyDraw routine to HELLOMDRAW.
     2) Bracket the routine with SetGeosConvention before and
        SetDefaultConvention after to let Esp know that parameters
        will be passed onto the stack in the same order as Pascal.

   Here is an example:

     SetGeosConvention
     global MYDRAW:far
     MYDRAW     proc    far                          arg1:word arg2:MyStruct ...other args, if any...
             ... body of function ...
     MYDRAW     endp
     SetDefaultConvention


Serial and IR ports on the Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
You can access both the "tether" serial port and the IR port via
serial com ports.  The port numbers are:

Serial: COM 1
IrDA:   COM 3

Use the Serial..() routines described in the techdocs.


FileMove() an example

SDK: ALL_GEOS:PUBLIC
To move a file, use the FileMove() routine.  The following
example should help illustrate how the routine is used.  Both
examples move the file "somefilename" from Document\Download
to System\Printer.  The difference is in the standard path
used as a starting point for the source and destination
DiskHandle.  (StandardPaths can always be used as DiskHandles
to reference a specific standard GEOS directory.)

FileMove("Document\\Download\\somefilename",
     "System\\Printer\\somefilename",
     SP_TOP,
      SP_TOP);

FileMove("Download\\somefilename",
     "somefilename",
     SP_DOCUMENT,
      SP_PRINTER_DRIVERS);


Some miscellaneous IrDA information.

SDK: N9000C:PUBLIC
Q. What is TinyTP?

A. TinyTP is the preferred protocol layer through which apps
   should use IrDA.

Q. Is IrCOMM enough to send/retrieve data through the Ir port?

A. Yes, but use of IrCOMM is discouraged unless there is a reason
   you can't use TinyTP.

Q. What COM# is the Ir port?

A. The IrDA port is on COM2.

Q. Which driver do you load?

A. If you want to use IrCOMM, you load ircomm.geo instead of the
   serial driver.

Here is some info on settings you'll put into the geos[ec].ini file:

;[irlmp]
;       deviceInfo =
;               Hint bits and nickname returned by discovery.
;
;[ircomm]
;       flushTime = 2
;
;       The number of ticks before forcing a packet to be sent from the
;       output stream before it reaches the threshold (which is the packet
;       size).
;
; [irlap]                         IRLAP Driver
;
; driver = IRLAP Driver (Socket interface only)
; address =
 (Socket interface only)
;
; port = SerialPortNum (default is SERIAL_COM1)
;
; Negotiation parameters:
;
; baudRate              = IrlapParamBaudRate            ;default 9600 bps
; maxTurnaround         = IrlapParamMaxTurnAround       ;default 500 ms
; dataSize              = IrlapParamDataSize            ;default 64 bytes
; windowSize            = IrlapParamWindowSize          ;default 1 frame
; numBOFs               = IrlapParamNumBof              ;default 5 BOFs
; minTurnaround         = IrlapParamMinTurnaround       ;default 1 ms
; linkDisconnect        = IrlapParamLinkDisconnect      ;default 3 seconds
;
;       Irlap negotiation parameters are records.  Entries are numbers
;       that represent appropriate masks.  Each mask should turn on all
;       the bits that correspond to the capacities that the current
;       station can support.
;
;       e.g. dataSize = 15 = 00001111b which means it can support
;       data sizes of 512, 256, 128 and 64 bytes.


I get 'class

I get 'class is multiply defined'.

SDK: ALL_GEOS:PUBLIC
Q. We have a class definition for FooProcessClass.  When the
   definition is in the .def file, Esp gives a "Class FooProcessClass
   is multiply defined" error.  When we move the declaration into
   the .asm file, the error goes away.

A. The .def file is being included by more than one asm file, so you
   end up with multiple definitions of the class.


Warning: segment

Warning: segment not known?

SDK: ALL_GEOS:PUBLIC
Q. "warning: segment  not known"
   I get this warning when compiling my code with Esp.  Does this
   condition impact the generated code ?

A. "warning: segment  not known" can require an extra byte
   per call because if the routine is in a local segment, it can use
   less bytes to make the call if it knows the appropriate place
   (like the .def file) that declares what segment the routine is in.


Sending messages from .asm when classes are in .goc

SDK: ALL_GEOS:PUBLIC
Q. Our partner has an application that has a .GOC and a .ASM file.
   She declares her classes and messages in the .GOC file, but wants
   to be able to send the messages from her .ASM file.  Should she
   just define a .def file that has all the corresponding class and
   message definition and include that file in her assembly.

A. Yes. If any of the messages take parameters or return values,
   she'll have to use the GOC syntax to bind them to registers.
   See any of the .goh files for examples of doing this.

   Also, make sure the assembly definition of the message uses a
   different name than the C definition. Otherwise glue will complain
   that the message is multiply defined. Adding the suffix "_ASM" is
   the standard thing to do in this case.


Calling a library function in C from assembly.

SDK: ALL_GEOS:PUBLIC
Q. How do you call a library function in C, from assembly?

A. If the C function is defined as:

     word _cdecl foo(word a, word b)

   Then do this in assembly to call it:

     push b
     push a
     call foo  ; es, di, si, bx, cx trashed, ax holds return value
     add sp, 4

   Else if the C function is defined as:

     dword _pascal foo(word a, word b)

   Then do this in assembly to call it:

     push a
     push b
     call FOO  ; es, di, si, bx, cx trashed, dx.ax holds return value
     ; callee pops args off stack


Are there any known errors in the header files?

SDK: BETA:PUBLIC
Q. Are there any known errors in the header files?

A. In the Beta1.0 release, the following definitions need to be fixed
   so the C compiler knows that they are hex:

   graphics.h -  line 231: EOREGREC 8000h        -> should be 0x8000

   math.h -      line 248: FORMAT_ID_PREF 8000h  -> should be 0x8000
                 line 251: FORMAT_PARAM_ID 63h   -> should be 0x63
                 line 340: FLOAT_FORMAT_FORMAT_NAME_NOT_FOUND 7fffh
                                                 -> should be 0x7fff


FileEnum returns an invalid number of files.

SDK: ALL_GEOS:PUBLIC
Q. FileEnum() is not returning the number of files that it finds.
   I am currently working around it by looking for invalid values in the
   file information structures as I go through the file array created by
   FileEnum(). When I see an invalid value (I'm already off the end of
   the array), I stop processing.

A. This is a bug in the C stub for FileEnum(). Here is a better
   solution to the problem:

   count = MemGetInfo( memHan, MGIT_SIZE ) / sizeof( FEDosInfo );

   where FEDosInfo could be the value you used for the
   FE_params.FEP_returnSize field before calling FileEnum, and memHan
   is the memory handle returned by FileEnum.

   The bug was fixed a long time ago, so this probably won't affect you.


Running the Bullet demo (Sharp PT-9000 emulator).

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. I tried using the PT9000 emulator software and the screen
   looks garbled. How do I fix this?

A. The PT9000 needs a 640x440 display. Thus, you need to use a
   VGA or better display to run the PT9000 demo.


Bullet demo crashes in Preferences app.

SDK: 2.0:PUBLIC, BETA:PUBLIC
Q. When I run the Bullet (PT9000) demo, if I make any changes in
   the Preferences, it locks up, saying the GEOS.INI file is
   corrupt.

A. The problem is that the GEOS.INI file has garbage in it. To
   fix this, use the MS-DOS editor, scroll down to the bottom
   to the end of the file. There should be some strange characters
   there. Delete those and save the file. The PT9000 emulator
   should run fine then.


Using ClipboardEndQuickTransfer correctly.

SDK: ALL_GEOS:PUBLIC
Q. I am trying to implement drag and drop into my program, and I
   want to get the name of the transfer item. However, when I use
   this code to do it, I get a VM_HANDLE_NOT_IN_USE error:

     TransferBlockID           transferID; /* File/Block of item header. */
     MemHandle                 itemMem;    /* Mem block for item header. */
     ClipboardItemHeader *     itemPtr;    /* Pointer to item header. */
     ClipboardEndQuickTransfer( PasteCommon( CIF_QUICK, textOD,
                                pself->GDI_fileHandle, &itemBlock ) );
     transferID = ClipboardGetQuickItemInfo();
     itemPtr = VMLock( FileFromTransferBlockID( transferID ),
                       BlockFromTransferBlockID( transferID ),
                       &itemMem );
        /*
         * Add the new item to the map block.
         */
     @call self::MSG_SB_DOCUMENT_ADD_ITEM( itemBlock, itemPtr );
     VMUnlock( itemMem );

A. Here is how to do it:

     ClipboardQuickNotifyFlags retFlags;  /* Returned from PasteCommon. */
     retFlags = PasteCommon( CIF_QUICK, textOD,
                             pself->GDI_fileHandle, &itemBlock );
     transferID = ClipboardGetQuickItemInfo();
     itemPtr = VMLock( FileFromTransferBlockID( transferID ),
                       BlockFromTransferBlockID( transferID ),
                       &itemMem );
        /*
         * Add the new item to the map block.
         */
     @call self::MSG_SB_DOCUMENT_ADD_ITEM( itemBlock, itemPtr );
     VMUnlock( itemMem );
     ClipboardEndQuickTransfer( retFlags );

   (The PasteCommon function is in the ClipSamp sample program on the
   GEOS SDK disk.) The reason this code fragment works is that it is
   getting the information from the item header BEFORE calling
   ClipboardEndQuickTransfer, which destroys that header. So, in the
   previous fragment, we were calling for a VM block that was just
   freed, and thus we get the error message.


I get the 'Undefined structure '_ClassStruct'' warning.

SDK: ALL_GEOS:PUBLIC
Q. When I compile I get the following warning:

     Warning file.c 163: Undefined structure '_ClassStruct'

   Is this a serious warning?

A. No. It is a fluke caused by one of the header files. If you
   include the geos.h header file without including object.h,
   you'll get this warning. You can ignore it as long as you
   don't use "ClassStruct" in your code.


Compiler error 'resource not found'.

SDK: ALL_GEOS:PUBLIC
Q. I keep getting the compiler error 'resource not found' when I add the
   line 'resource  ui-object' to my .GP file.

A. That is because a resource (in GEOS) defines a segment of memory
   (which contains data or objects) used by your application, not a routine
   name (nor an object name).  These resources are managed by the memory
   manager and can be moved around in memory or swapped out to storage if
   they are not being used.  In the source code, you define a resource with
   the @start /@end  directives (for example,
   Hello.goc has the resource AppResource).  See section 5.4.3.2 of the
   Concepts book (Concepts\CCoding.txt) for more information on declaring
   segment resources and chunks (chunks define smaller sections of segment
   resources).


Using the neverSaved option in a subclass.

SDK: ALL_GEOS:PUBLIC
Q. When can I use the neverSaved option for declaring a subclass?

A. The neverSaved option is only meaningful for ProcessClass because
   the process class does not have instance data, so it should not
   (cannot) be saved to state.


BCC complains about an illegal # character.

SDK: ALL_GEOS:PUBLIC
Q. BCC complains about an illegal '#' character in my GOC file, but I
   can't find it.

A. If the end of your goc file is immediately after a closing brace,
   on the same line as the brace rather than on the next line, GOC places
   a #pragma immediately after the closing brace and then bcc complains
   about it. You get an error telling you there is an illegal character
   '#' in the goc file, but of course it is actually in the C file. This
   is something that should be corrected by GOC, though it is considered
   "bad form" not to have a newline just before end-of-file.


Minimal Borland C++ installation for v3.1

SDK: ALL_GEOS:PUBLIC
Q. What parts of Borland C++ do I need to work with Goc (i.e. what is
   the minimal installation)?

A. For Borland C++ 3.1, you need the following:
    bcc.exe   	- the Borland C compiler
    cpp.exe   	- Borland's C pre-processor
    rtm.exe   	- used by bcc
    dpmi16bi.ovl	- used by bcc
        Include/stddef.h
        Include/_defs.h

   For BorlandC 4.0, the default install option for Borland C 4.0
   is to leave almost everything on the CD, installing only a few
   configuration files (about 100KB worth) to the hard drive.


Using the GCI_output correctly.

SDK: ALL_GEOS:PUBLIC
Q. I get the following error when I compile:

    Must take address of a memory location.
    Multiple declaration for 'optr'
    (Line numbers usually off by one.)

A. Make sure any TO_APP_TARGET and similar destinations in the object
   definition are surrounded by parentheses.
   For example:

       GCI_output = ( TO_APP_TARGET );


Directly accessing CIF_TEXT on the Clipboard.

SDK: ALL_GEOS:PUBLIC
Direct clipboard manipulation of text is possible. As a
proof-of-concept, some sample code which grabs info from the
clipboard's text vmchain is at the end of this article.

Here is some information about the VMChains in the
TextTransferBlockHeader

TextTransferBlockHeader
    TTBH_text		  huge array of chars
    TTBH_charAttrRuns	  huge array TextRunArrayElement
    TTBH_paraAttrRuns	  huge array TextRunArrayElement
    TTBH_typeRuns	  huge array TextRunArrayElement
    TTBH_graphicRuns	  huge array TextRunArrayElement
    TTBH_charAttrElements element array of VisTextCharAttr
    TTBH_paraAttrElements element array of VisTextParaAttr (variable sized)
    TTBH_typeElements	  (element array?) of VisTextType
    TTBH_graphicElements  (element array?) of VisTextGraphic
    TTBH_styles		  vm block handle
    TTBH_names		  vm block handle
    TTBH_pageSetup	  VMChain of PageSetupInfo

TTBH_pageSetup really is a VMChain, so you can hop from block to
block using PSI_meta.VMCL_next. (The structure in each VMBlock is a
PageSetupInfo struct.);

Here's the code snippet for dealing with CIF_TEXT:

----------Start Code Sample----------
/***********************************************************************
 *		PasteCommonText
 ***********************************************************************
 * SYNOPSIS:	 Go through and grab bits of data from the clipboard
 *		 text vmchain tree.
 *
 * CALLED BY:	 (INTERNAL) PasteCommon
 * RETURN:	 ClipboardQuickNotifyFlags for ClipboardEndQuickTransfer
 * SIDE EFFECTS: none
 *
 * STRATEGY:
 *
 * REVISION HISTORY:
 *	Name	Date		Description
 *	----	----		-----------
 *	eb	7/95		Initial Revision
 *
 ***********************************************************************/
static ClipboardQuickNotifyFlags
PasteCommonText(ClipboardQueryArgs *query, ClipboardRequestArgs *request)
{
    ClipboardQuickNotifyFlags retVal;

    MemHandle		     handleTTBH;
    TextTransferBlockHeader *ptrTTBH;

    char                    *clpbdText;

    /* need these for messing with the element array chunk */
    LMemBlockHeader         *ptrLMemBH;
    ChunkHandle              elmntChnkH;

    /* need these for the CharAttr runs and elements */
    TextRunArrayElement     *clpbdCAR;
    MemHandle                handleCAE;
    VisTextCharAttr         *clpbdCAE;
    word                     elemSize;
    dword                    elemCount;

    /*
     * Fetch the file/block handle of transfer format
     * TEXT_FORMAT is MANUFACTURER_ID_GEOWORKS::CIF_TEXT
     */
    ClipboardRequestItemFormat(TEXT_FORMAT, query->CQA_header, request);

    /*
     * Get the TextTransferBlockHeader struct, which is a VMChainTree.
     * (It is defined in vTextC.goh.). This will point to the various
     * vmchains that make up the elements of text and formatting info.
     */
    ptrTTBH = VMLock(request->CRA_file,
             VMCHAIN_GET_VM_BLOCK(request->CRA_data),
             &handleTTBH);

    /*
     * ****GET TEXT****
     * First we grab the plain text from the clipboard. The text vmchain
     * is a HugeArray.
     */

    /*
     * Get the total size of the text that is stored.
     */
     elemCount = HugeArrayGetCount(request->CRA_file,
          VMCHAIN_GET_VM_BLOCK(ptrTTBH->TTBH_text));

    /*
     * Now get a pointer to the text pointer (*clpbdText). elemSize also
     * tells the size of the block of text.
     */
    HugeArrayLock(request->CRA_file,
          VMCHAIN_GET_VM_BLOCK(ptrTTBH->TTBH_text),
          0, &clpbdText, &elemSize);

    HugeArrayUnlock(clpbdText);

    /*
     * ****GET CHARACTER ATTRIBUTES****
     * The character attribute information is stored in two arrays.
     * One array, TTBH_charAttrElements, stores an array of
     * VisTextCharAttr elements. It is stored in an ElementArray,
     * so we will use ChunkArray routines to access the info.
     *
     * The other array, TTBH_charAttrRuns, stores an array of
     * TextRunArrayElement elements. These are in a HugeArray.
     */
    if(VMCHAIN_GET_VM_BLOCK(ptrTTBH->TTBH_charAttrRuns))
    {
    /*
     * Enum thru the runs. There are two ways we could enum thru these
     * runs. One is to start at the beginning (element 0) and go thru
     * until we reach an element that has TRAE_position =
     * TEXT_ADDRESS_PAST_END and and TRAE_token = CA_NULL_ELEMENT.
     * The other way is to get the element count and use a for loop to
     * enumerate thru the list. (We will use the latter approach in
     * this example.) Be careful because the last element in the list
     * has TRAE_token = CA_NULL_ELEMENT, which is not a valid token
     * into the element array.
     */

    /*
     * Get element the first (0) element from character attribute run.
     */
    HugeArrayLock(request->CRA_file,
              VMCHAIN_GET_VM_BLOCK(ptrTTBH->TTBH_charAttrRuns),
              0, &clpbdCAR, &elemSize);
    do {
        /*
         * Now get the character attributes for the specified run.
         * To get the optr to the chunk array, we need the block
         * handle, which we get with VMLock.  Putting VMLock inside
         * of a loop like this is really a bad idea, but it was done
         * in this case to keep all the necessary functionality close
         * together. (otherwise you would have to page up and down
         * looking for where handleCAE was set.)
         *
         * Since this block contains an element array, it is an LMem
         * type block. Therefore, it contains an LMemBlockHeader at
         * the beginning and the header contains the chunk to the
         * element array. So we use this to get the handle and chunk
         * to the element array.
         */
        ptrLMemBH = VMLock(request->CRA_file,
          VMCHAIN_GET_VM_BLOCK(ptrTTBH->TTBH_charAttrElements),
          &handleCAE);
        /* If you do "phandle handleCAE", you see that the block contains
         * lmem. Thus you can use "print LMemBlockHeader *ptrLMemBH"
         * to see the structure. */
        elmntChnkH = ptrLMemBH->LMBH_offset;

        clpbdCAE = ChunkArrayElementToPtr(
                ConstructOptr(handleCAE, elmntChnkH),
                clpbdCAR->TRAE_token,
                &elemSize);
        /* here is a good place in swat to do a "print *clpbdCAE" */
        VMUnlock(handleCAE);

        /*
         * Now get next run.
         */
        HugeArrayNext(&clpbdCAR, &elemSize);

        /*
         * Fall thru when we reach the end-of-runs marker, otherwise,
         * loop back up and get the info.
         */
    } while (clpbdCAR->TRAE_token != CA_NULL_ELEMENT);

    HugeArrayUnlock(clpbdCAR);
    }

    /*
     * ****GET PARAGRAPH ATTRIBUTES****
     * This is almost exactly the same as the character attributes
     * except that the VisTextParaAttr is variable sized due to
     * VTMPA_tabList, which is tacked on to the end of the structure
     * if the text has special tabs set up for the paragraph. See
     * the Tab structure.
     *
     * We leave the coding as an excercise for you.
     */

    VMUnlock(handleTTBH);

    retVal = CQNF_COPY;

    return(retVal);
}
----------End Code Sample----------


Function is prototyped, but compiler complains that it's not.

SDK: ALL_GEOS:PUBLIC
Q. I have a question about using functions in GOC. Whenever I make
   a function, the compiler ignores my prototype and generates a
   warning saying I'm calling a function without prototyping it.
   The code works, it just gives an annoying warning it shouldn't
   give when it compiles. This happens when my prototype is either
   in a .h file or the .goc file. But if I put my prototype in a .goh
   file, it gets ignored even more and causes errors when I try to use
   the function. It gives two messages, one a warning and the other
   an error. First it warns me I didn't prototype the function, then
   it errors out saying my parameters/return type don't match those
   of the prototype. That doesn't make sense. It saying I didn't
   prototype it, then saying I'm not using the prototype I declared.
   Am I doing something wrong?

   For example, I used some files from a C library I made. I took
   the .c and .h files and added them to the program. But when I
   compile the program, all my function calls from the .goc file
   complain I didn't prototype the function. But when it compiles
   the .c files, it doesn't complain about not prototyping. The
   prototypes are in a .h file that is included into both the .goc
   and .c files.

A. You're probably doing something like this:

    void MyFunc();

   This will fix it:

    void MyFunc( void );

   Sorry, no cool explanation as to why this makes a difference.
   Just know that it does.


What is the difference between focus and target.

SDK: ALL_GEOS:PUBLIC
Q. I noticed that most controllers have GCI_output = TO_APP_TARGET.
   What is the difference between focus and target?

A. You can set GCI_output to anything you want, but you are right
   that generally controllers work with the target mechanism.

   Focus is where input (such as keyboard and mouse) are directed.
   Focus is set by such actions as placing the mouse pointer over
   an object and clicking on it or by using the tab key to move the
   focus from one object to the next.

   Target in many cases will follow the focus, but only if the object
   that is gaining the focus has GA_TARGETABLE set.  Text objects are
   good candidates for GA_TARGETABLE; triggers and lists are not
   (unless you want a controller or something to be able to send a
   message to the trigger/list).

   There is a third input flow channel called model, which essentially
   provides a secondary target hierarchy and is used with documents.
   These three targeting mechanisms are discussed in the Input chapter
   of the Concepts book (Concepts\CInput).


Turning off features in GenDocumentControl.

SDK: ALL_GEOS:PUBLIC
Q. I see that we can supply our own visual monikers for the
   DocumentControl dialog.  If we set those attributes to null
   will it remove them from the dialog?

A. No.

   What you really want to do is turn the features off in the
   controller.  ATTR_GEN_CONTROL_PROHIBIT_UI is an easy way to
   do this; it stems from GenControlClass, the super class of
   GenDocumentControlClass.

   The feature set for GenDocumentControlClass can be found in the
   GDCFeatures flags record.  As an example (in Goc), to use the
   default intermediate features but to make sure the New feature
   is turned off set:

    ATTR_GEN_CONTROL_PROHIBIT_UI = { GDCF_NEW };

   You can also make sure that specific features are supported, by
   using ATTR_GEN_CONTROL_REQUIRE_UI.


Using undo with a text object.

SDK: ALL_GEOS:PUBLIC
Q. How does one implement the Undo function with a VisText object?
   We are using the GenEditControl and setting the VTF_ALLOW_UNDO
   feature, however we receive an error stating the context must be
   set up before issuing undo messages.

A. The context is a number to allow for multiple undo's, which you
   must set manually (so that you can have a different context for
   each text object).  What you can do is send
   MSG_GEN_PROCESS_UNDO_SET_CONTEXT sometime before the application
   starts tracking undo-able things.  One place to send this message
   is in MSG_GEN_PROCESS_OPEN_APPLICATION.

   Here's an example:

   dword oldContext;
   oldContext = @call MyProcess::MSG_GEN_PROCESS_UNDO_SET_CONTEXT( 1 );


Why is the SpellControl object disabled?

SDK: ALL_GEOS:PUBLIC
Q. When I implement SpellControl, the spell checker is always inactive
   (not enabled).

A. You need to tell your DocumentControl object to notify the SpellControl
   object when there is text available.  This is accomplished in the
   instance data GDCI_enableDisableList.  The following example
   illustrates how to setup and use GDCI_enableDisableList.

     @object GenDocumentControlClass MyDocControl = {
         GDCI_enableDisableList = EnableDisableList;
     }
     @chunk optr EnableDisableList[] = {
         @MySpellControl
     };
     @object SpellControlClass MySpellControl = {
     }


Spell checker shows up as a little button.

SDK: ALL_GEOS:PUBLIC
Q. I am trying to use the SpellChecker in my program, but when I
   test it I just get a little box with a disabled button. Am I
   doing something wrong?

A. The spell checker is disabled in the GEOS EC and NC versions
   because Geoworks did not license the checker for the SDK versions
   of GEOS. It is only available in the full GEOS version that is
   not part of the GEOS SDK.

   Also, the SpellControl is one of those that is not to be put in a
   GenInteraction. It should be a direct child of the Edit menu:

      @object GenInteractionClass MyEditMenu = {
        GI_comp = @MySpellControl;
        ...
      } /* MyEditMenu */

      @object SpellControlClass MySpellControl = {
         GI_visMoniker = "Check Spelling";
         GI_states = @default | GS_ENABLED; /* Must enable. */
         GCI_output = ( TO_APP_TARGET ); /* Go to text object. */
      } /* MySpellControl */


SearchReplaceControl isn't enabling correctly.

SDK: ALL_GEOS:PUBLIC
Q. Why aren't the triggers in the Find/Replace controller enabled,
   even after I type some text in the Find field?

A. In the SearchReplaceControl you need to have the following
   attribute:

     ATTR_SEARCH_CONTROL_INTERACT_ONLY_WITH_TARGETED_TEXT_OBJECTS;

   This will make the triggers become enabled at the appropriate
   time. Here is a sample SearchReplaceControl object:

     @object GenInteractionClass MyEditMenu = {
         GI_comp = @MySearchReplaceControl;
         ...
     }

     @object SearchReplaceControlClass MySearchReplaceControl = {
         GI_visMoniker = "Find and Replace";
         GI_states = @default & ~GS_ENABLED;
         GII_visibility = GIV_DIALOG;
         ATTR_SEARCH_CONTROL_INTERACT_ONLY_WITH_TARGETED_TEXT_OBJECTS;
         ATTR_GEN_DESTINATION_CLASS = { (ClassStruct*)&MyTextClass };
     }

   This example is for text objects, which is generally what the
   Find/Replace is used on. You should only have to make minor
   modifications to make this work with other kinds of objects.


Using PointSizeControl to change size of text object.

SDK: ALL_GEOS:PUBLIC
Q. I have a PointSizeControl object that works to set the size
   of a VisText object. I am trying to have the point size saved
   when the program exits and then load that point size when the
   program starts. I have the size information saved to the GEOS.INI
   file, and that seems to be working fine. However, when the
   program starts, it does all the message sending, but the
   point size control is set to 8 point, instead of whatever it's
   supposed to be.

A. The problem here is that the PointSizeControl has this field:

       GCI_output = ( TO_APP_TARGET );

   If your text object does not have the target when the
   MSG_PSC_SET_POINT_SIZE is sent then that size change will be
   ignored completely. To remedy this, set the GCI_output to
   the text object, like this:

       GCI_output = @MyTextObject;

   If you can't do this (eg., because the text object is duplicated
   by the document control) then make sure the text object receives
   the MSG_META_GRAB_TARGET_EXCL message before you send the
   MSG_PSC_SET_POINT_SIZE message.


Text object isn't doing the undo, but it did work at first.

SDK: ALL_GEOS:PUBLIC
Q. I recently changed my program from multiple-document interface
   to single-document interface. When I open a document, everything
   works fine. When I close that document and open a second one, the
   Undo no longer works. What gives? (I'm using a text object for
   the document.)

A. For some reason or another the text object is being told to
   not send undo messages to the EditControl. To fix this, in your
   MSG_META_DOC_OUTPUT_ATTACH_UI_TO_DOCUMENT method (or wherever is
   appropriate for your program), send the message

      @send textObj::MSG_VIS_TEXT_SET_FEATURES( VTF_ALLOW_UNDO, 0 );

   This will make the text object turn on it's undo support.


Using text controllers on a read-only object.

SDK: ALL_GEOS:PUBLIC
Q. I can't get the font and size controllers to work with a GenText
   I have in a small app I'm working on. The GenText is just a
   display text, so it's GI_attrs is set GA_READ_ONLY.

A. Remove the GA_READ_ONLY. This makes the FontControl and
   PointSizeControl disabled.


DB item gets last two bytes stomped on.

SDK: ALL_GEOS:PUBLIC
Q. I'm having trouble retrieving the data that I have placed into the
   default record when I create the database. When I am retrieving
   the data later, each piece of data has had its last two bytes
   stomped on, usually with two bytes containing 0xCC. Each item has
   the following format:

    typedef struct {
            unsigned short size;
            char           data[1];
    } DBField;

   where size is the size of the data, and data is the address of the
   first byte of the data.

A. You are not allocating the correct size for the items. The size
   needs to include the word of data that gives the size of the db
   item. (In other words, add sizeof( word ) to the db item size.)

   For problems like this, you can gather more information by using the
   various LMem related EC flags in Swat ('help ec' in Swat for more
   information). Those flags will enable various extra internal error
   checking and may well give more insight as to what's happening.


Does DBFree cause any moving of locked item blocks?

SDK: ALL_GEOS:PUBLIC
Q. Is it safe to assume that a call to DBFree will not result in moving
   of any locked item blocks or items ?

A. Yes, it is safe. In fact, any calls to MemFree, LMemFree, etc. are
   safe. The only way a locked block (and therefore a locked DBItem)
   can be moved is by explicitly resizing the block. For DB item blocks,
   this would mean calling DBReAlloc.


VM chain vs. VM blocks in MSG_INK_SAVE_TO_DB_ITEM.

SDK: ALL_GEOS:PUBLIC
Q. MSG_INK_SAVE_TO_DB_ITEM is documented as:
   "Return: AX.BP - DB group/item written to (VM Chain)"
                                              --------
   Does that mean that it could create a chain of VM blocks instead
   of a single DBItem?

A. This syntax was derived from the fact that DB Groups are stored in
   multiple VM blocks. This is to allow growing populations of DB
   items within the group to expand over 64K (though I think the
   primary reasoning is to allow blocks within the group to stay
   around the optimal 2-6K size without restricting the total sizes
   of all the items to 6K).

   Because of this methodology, the creation of a new DB Item can
   cause the creation of a new VM block. This will probably not
   happen until the previous items in the group take up more than
   4-6K. In any case, I'm sure it can't create more than one
   additional block at a time. If you've only got a few ink items
   in the group, it won't create multiple blocks in the chain.


What file attributes does GenDocumentControl take into account?

SDK: ALL_GEOS:PUBLIC
Q. Exactly which regular attributes and extended attributes does the
   document control take into account?  Is there a way that I can look at
   a file's extended attributes with the debugger?  It seems the only other
   way would be to programmatically request each one to get the settings.
   Then, if I don't know which ones the doc control is looking for I will
   have to set all of them for each file I create.

A. There's FEA_FILE_ATTR (FA_RDONLY), FEA_PROTOCOL, FEA_TOKEN,
   FEA_CREATOR, FEA_FLAGS (public/template stuff), FEA_USER_NOTES
   (for display in the file open box), FEA_PASSWORD (all 0 if no password),
   and FEA_RELEASE (just sets it). (It also does FEA_DISK and FEA_FILE_ID,
   but those aren't settable.)

   The file token is what is needed to see the thing in a file-open box.
   The creator token is needed if you double-click the file. The
   FEA_FILE_TYPE is needed by the VM system. the protocol is needed once
   the file is opened and should match the protocol bound into the document
   group object.


'Find' button on the OmniGo document control.

SDK: OMNIGO:PUBLIC
Q. In the document control, the "Find..." button does nothing.
   What is it supposed to do? If it really is supposed to do
   nothing in that context, shouldn't it be NOT_ENABLED?

A. The "Find" button is managed by a SearchReplaceControl object.
   It's enabled, because the user ought to be able to search for
   text within the documents listed -- it's only ~GS_ENABLED when
   the File Selector shows no files.

   It does nothing, because the application needs to handle the
   searching itself. See the sample application DocUI, which is
   in the SDK_Omni sample app tree, for an example of using
   MSG_SEARCH.


'Find' button crashes when I handle searching.

SDK: OMNIGO:PUBLIC
Q. When implementing the "Find" trigger in the DocumentControl's
   FileSelector, it always crashes.  What's going on?

A. There is a bug in the handler for MSG_SEARCH which requires
   that an object be at the chunk 002ch in the object resource
   that contains the DocumentControl object.

   The workaround is to manipulate the objects so that an object
   actually does exist in that chunk.  You can use the "objwalk"
   command in Swat (for the handle use that of the DocumentControl
   object) to assist in determining where objects are located in
   the resource.


'Note' button doesn't work correctly.

SDK: OMNIGO:PUBLIC
Q. The "Note" button does nothing the first time it is hit.  The
   second time, it says "Unable to create the note.  The document may
   be a template, or it may be in use."

A. The support for the "Note" trigger isn't completely automatic.
   You have to add a NoteShellClass object to the app.  Also, your
   application is responsible for saving the NoteShell's data into
   the VM file.

   Here's what you should do:

   In your *.goc file:
   ===================
   1. Include the Geos header file that defines NoteShellClass.
      @include

   2. Create a new subclass of NoteShellClass.

   3. Create an object of your new subclass of NoteShellClass.

   4. Make it a child of the GenApplication object.

   5. Add it to the following GCN lists:
      MGCNLT_ACTIVE_LIST (same as DocumentControl)
      GAGCNLT_STARTUP_LOAD_OPTIONS

   6. Intercept MSG_GEN_DISPLAY_CLOSE for your subclass of NoteShellClass:
      @method YourNoteShellClass, MSG_GEN_DISPLAY_CLOSE
      {
          /*
           * First, save away the NoteShell data into a VM file.
           */

          /*
           * Now, close the NoteShell
           */
          @send self::MSG_NOTE_SHELL_CLOSE_DISPLAY();
      }

   In your *.gp file:
   ==================
   1. Add "library notes" to load the notes library

   2. Export your new subclass of NoteShellClass


HINT_APPLICATION_QUIT_ON_IACP_ALLOW_FILE_ACCESS isn't working.

SDK: OMNIGO:PUBLIC
Q. HINT_APPLICATION_QUIT_ON_IACP_ALLOW_FILE_ACCESS isn't working.
   My application is running with a document open. I then use
   Transfer to try to restore an earlier version of the data file,
   I get the message "Restore Error. Can't access the data in memory.
   Close the application for which you are restoring data and try
   again." If I try restoring a second time, the error message is
   not given. It properly restores the old data file.

A. DocumentControl automatically handles IACP file access requests, so
   don't use HINT_APPLICATION_QUIT_ON_IACP_ALLOW_FILE_ACCESS. The
   problem with this hint is that it causes the application to shutdown,
   but the document gets closed near the end of the shutdown procedure.
   Because the application shutdown process is asynchronous, the document
   will most likely not be closed by the time Transfer receives feedback
   that the application is shutting down.

   NOTE: If your application stores datafile-specific information (such
   as a data cache), you will still have problems, because the datafile
   could be altered by the Transfer application, leaving your stored
   information incorrect. In this case, you should reset the information
   during MSG_GEN_DOCUMENT_CLOSE_FILE or MSG_GEN_DOCUMENT_REOPEN_FILE.


'No Document' in window title bar.

SDK: ALL_GEOS:PUBLIC
Q. In my text editor, if I have two documents opened and I use the
   Window menu to switch between them, the document display will draw
   twice, and the name in the primary's title bar will be "No Document"
   instead of the file's name.

A. Remove the GDCF_NAME_ON_PRIMARY flag in the GenDocumentControl.
   To do this, simply add the following line to your
   GenDocumentControlClass object:

       GDCI_features = @default & ~GDCF_NAME_ON_PRIMARY;

   The document name will still be on the primary's title bar, but
   it won't do the "No Document" thing and the display will stop
   drawing twice after the first time you switch to that document.


I get the OBJ_BLOCK_DUPLICATE_NOT_DISCARDED error when opening a document.

SDK: ALL_GEOS:PUBLIC
Q. I am setting up my application using the single-document
   interface and I get this error in Swat:

     OBJ_BLOCK_DUPLICATE_NOT_DISCARDED

   when I try to open a file.

A. In the procedural model you must take out the GDGI_genDisplay
   instance from the GenDocumentGroup object definition. If this
   field is non-null the GenDocumentGroup will automatically try
   to duplicate the display object resource. You don't want this
   to happen under the SDI mode.


Useful key combinations for Nokia 9000.

SDK: N9000C:PUBLIC
Here are some useful key combinations, that are good to know.
For all of these, you must pull out the battery and reinsert
it, then quickly press and hold one of these key combinations.

1. Press and hold Shift, Esc and left arrow during the phone's
   reboot sequence. This will bring up a file system check.

2. Press and hold Shift, Esc and right arrow during the phone's
   reboot sequence. You will be asked if you would like to delete
   the state files. You will lose the settings but the data will
   be intact.

3. Press and hold Shift, Esc and f during the phone's reboot
   sequence. You will be asked if you want to format the RAM
   disks in the phone. This will delete everything that you have
   on the communicator.


Is it possible to call a driver strategy routine from C?

SDK: ALL_GEOS:PUBLIC
Q. Is it possible to call a driver strategy routine from C?

A. Here's something you can try:

   DriverPassParams   dpp;
   DriverReturnParams drp;
   StreamToken        serialPort = SERIAL_COM1;

     /*
      * Set up StreamNotifyType for StreamReader, data event
      * notification (STREAM_EVENT_DATA), and notification mode by
      * a message.
      */
   dpp.ax = ( ( 1 << STREAM_TYPE_READER_OFFSET ) |
              ( STREAM_EVENT_DATA << STREAM_TYPE_EVENT_OFFSET ) |
              ( STREAM_MODE_MESSAGE << STREAM_TYPE_HOW_OFFSET ) );
   dpp.bx = serialPort;

     /*
      * MySerialNotifyObject is the object that contains a method
      * handler for MSG_MSNO_DATA_NOTIFY.
      */
   dpp.cx = OptrToHandle( @MySerialNotifyObject );
   dpp.dx = OptrToChunk( @MySerialNotifyObject );
   dpp.bp = MSG_MSNO_DATA_NOTIFY;

     /*
      * 14 equals DR_STREAM_SET_NOTIFY
      */
   DriverCallEntryPoint( serialDriver, 14, &dpp, &drp );


Error-checking version Non-error-checking version of system.

SDK: ALL_GEOS:PUBLIC
Q. What's the difference between the EC and NC versions (and how do tools
   such as PCS automatically handle these)?

A. See "The Error-Checking Version" in section 6.5 of Concepts Vol. 1
   in the documentation for information on this topic.


App crashes in EC but not in NC.

SDK: ALL_GEOS:PUBLIC
Q. My app works in GEOS NC, but causes a fatal error in GEOS EC. Swat
   says that the app is bombing out just as it launches because
   backtrace shows nothing that is from my app.

A. Make sure that only the subclassing of ProcessClass has the option
   "neverSaved." EC does not take well to other subclassed objects
   having the neverSaved option set.


ECCheckGStateHandle always gives an ILLEGAL_HANDLE.

SDK: ALL_GEOS:PUBLIC
Q. I've added some EC code to my app and noticed that whenever I
   call ECCheckGStateHandle I always get an ILLEGAL_HANDLE. Why
   is this happening?

A. The C stub for ECCheckGStateHandle was using the wrong registers
   and thus would always have an illegal handle. This error was
   fixed on August 9, 1996.
   In the meantime, if you really want to check the validity of
   a gstate handle, you can write a C stub of your own which
   simply takes the handle parameter and calls ECCheckGStateHandle
   from an assembly subroutine.


What does KR-06 mean?

SDK: ALL_GEOS:PUBLIC
Q. I would like to know what KR-06 really is?  According to the document,
   it says KR-06 means "breakpoint hit",  but I still don't know what that
   means.

A. The routine FatalError was called for some reason, which ends in a
   breakpoint. Often KR-06 messages are caused by some really random
   wacky burp in the hardware or software. A reset of the hardware and
   software will correct the problem. (If something happened to a file
   on disk, the problem will not go away until the file is replaced.)


My fatal errors aren't seen in Swat.

SDK: ALL_GEOS:PUBLIC
Q. I get the following warning in swat when I'm stepping through
   EC_ERROR_IF() when the failcase is true:

   628:    EC_ERROR_IF( tempLogFileH == NullHandle,
                        SAMPLE_TEMP_LOG_FILE_NOT_CREATED );
   Warning: brk2: error: not a valid type
   Stepping in /staff/pcgeos/Library/Kernel/Boot/bootBoot.asm...
   878:        push    bp, si, ds, ax

   This is how I've set up this FatalError:

   typedef enum {

       SAMPLE_TEMP_LOG_FILE_NOT_CREATED,
       /* the handle of the log file is Null when it shouldn't be */

   } FatalErrors;

   What am I doing wrong?

A. You need to declare a fake global variable of type FatalErrors
   in GOC, in order for your FatalErrors to fold in properly with
   the system-defined FatalErrors.  (You don't need to do this in
   assembly).

   Here's more on why this is the case:

   InteractionCommand is a type that's actually defined in a .h or
   .goh file. FatalErrors isn't (it's unique to the geode being
   created, and thus always begins at 0). The FatalErrors enum is
   one of these things that's actually really cool, but few people
   really understand it. The number of times people have defined
   FatalErrors members in global .def files is amazing.

   In essence, there are multiple FatalErrors enumerated types, one
   defined by each geode. Swat determines in which FatalErrors
   enumerated type to look up an error code by seeing which geode
   owns the routine that called FatalError. It's really quite simple.
   This behaviour is why it's pointless to define fatal error codes
   in a .def file in Include: unless the code that's including the
   .def file is going to be generating those error codes, there's no
   point in having them defined.


So what is the the theory behind EC code?

SDK: ALL_GEOS:PUBLIC
Q. So what is the the theory behind EC code?  How much is good,
   and how much is too much?

A. Put in as much EC code as possible.  It is great for catching bugs
   now and in the future (when some other poor soul is maintaining the
   code).  A good basic rule is to check all parameters coming into a
   function and all values returned from a function call. Also checking
   global variables before passing them to a function is a good idea.

   The non-EC version of EC routines are just stubs that immediately
   return, so EC code will have minimal impact on your application's
   performance.  Additionally, you can encapsulate EC routines in the
   EC() macro, which will prevent even the stub from being called when
   you compile for non-EC.


When should I use the EC routines?

SDK: ALL_GEOS:PUBLIC
Q. Almost every kernel routine (like MemAlloc, FileOpen) can "fail".
   Should I add EC routines to check for failure?

A. No. You always want your application to handle failures (can't
   open the file or can't allocate memory) gracefully in both EC and
   non-EC versions. Routines like ECCheckMemHandle or ECCheckFileHandle
   should be used to check variables as they are passed around the
   system (when calling routines or messages). This catches mistakes
   like when other programmers accidentally call your routine with the
   wrong parameters.


Optimizing graphics in a VisLargeText object.

SDK: ALL_GEOS:PUBLIC
Q. Now that I know that VisLargeText object make copies from my
   GStrings I have another question. If I have 100 identical images
   in one page then there are 100 copies of the image in VisLargeText
   object's VMFile. Can I optimize so that only one copy of the image
   exists and there is 100 pointers to that GString?

A. VisTextClass already attempts to optimize graphics. If you use the
   same VisTextGraphic data each time you insert, VisText will simply
   increment the reference count to the first occurrence of that graphic
   and not bother copying the new graphic into the text VM file.

   If you don't have the VisTextGraphic data anymore, you could use
   MSG_VIS_TEXT_GET_GRAPHIC_AT_POSITION to get the graphic you inserted
   earlier and get the VisTextGraphic structure. Then you can use this to
   call MSG_VIS_TEXT_REPLACE_WITH_GRAPHIC again.


Rules for overwriting libraries with NSERVER (the installer)

SDK: N9000C:PUBLIC
When NServer installs geodes and files that already exist on the
phone, protocols are checked and actions are taken based the
following tables.

For documents and data files:
 Major	Minor
 -----	-----
 Higher	---	Prompt user, install document and continue install
 Lower	---	Ignore file and continue install
 Same	Lower	Prompt user, install document and continue install
 Same	Same	Prompt user, install document and continue install
 Same	Higher	Prompt user, install document and continue install

 When replacing documents and data files, the Connect dialog type
 CSDBT_REPLACE_EXISTING_DOCUMENT is used (see connect.goh). This
 dialog is displayed for each document that is being replaced.

For Applications:
 Major	Minor
 -----	-----
 Higher	---	Prompt user, install file and continue install
 Lower	---	Ignore file and continue install
 Same	Lower	Ignore file and continue install
 Same	Same	Prompt user, install file and continue install
 Same	Higher	Prompt user, install file and continue install

For libraries and drivers:
 Major	Minor
 -----	-----
 Higher	---	Abort whole install because package is not compatible
 Lower	---	Abort whole install because package is not compatible
 Same	Lower	Ignore file and continue install
 Same	Same	Ignore file and continue install
 Same	Higher	Prompt user, install file and continue install

 When replacing applications, libraries and drivers, the
 CSDBT_REPLACE_EXISTING_SOFTWARE dialog is used. This dialog
 is only displayed once per package install.


Creating a file with read-only attributes.

SDK: ALL_GEOS:PUBLIC
Q. My call to FileCreate now gets "Death due to CREATE_BAD_FLAGS"
   Here's the call

    fileHan = FileCreate("sample.rec",
        (FILE_CREATE_TRUNCATE | FCF_NATIVE |
         FILE_ACCESS_R | FILE_DENY_NONE),
        FILE_ATTR_NORMAL);

A. As stated in the Routines book under FileCreate(), a file cannot be
   created in read-only mode.  You must open it with write access.
   And, if you open it with write access, you must open it deny-write
   for others.

   Try using FILE_ACCESS_RW | FILE_DENY_RW, as shown in the example
   which accompanies the FileCreate() reference entry.


Comparing file paths for equality.

SDK: ALL_GEOS:PUBLIC
Q. Given two full directory path strings (including the drive letters),
   how can I check whether the two refer to different files ?

   Doing a string compare of the paths will not cover all cases, since
   it is possible to have two different drive letters mapped to the
   same drive.

A. Call FileGetPathExtAttributes(FEA_MULTIPLE, 2, [FEA_FILE_ID, FEA_DISK])
   for each one (from assembly one can call IACPGetDocumentID) and compare
   the attributes of the files.


Using FileEnum on a standard path.

SDK: ALL_GEOS:PUBLIC
Q. If you use FileEnum in a standard path, will it return multiple
   entries, if those entries have the same file name.

A. No -- local versions of files will override remote versions


Checking return values from the File routines.

SDK: ALL_GEOS:PUBLIC
Q. How can I tell when an error occurs in FileRead()?  The docs mention
   that errors will be set "in the thread's error value."  What is that
   and how do I access it?

A. FileRead will return -1 and you can then use ThreadGetError().
   It returns a word with the thread's error value.  It should be
   one of the enum type FileError (file.def) or Error (in file.h).


Opening with VMOpen results in FAULTING_IN_VM_BLOCKS.

SDK: ALL_GEOS:PUBLIC
Q. I am opening a document using VMOpen with the following parameters:

    mode = VMO_OPEN
    flags = VMAF_FORCE_READ_ONLY
    compression = 0

   After calling VMOpen, I get "WARNING: FAULTING_IN_VM_BLOCKS" in Swat.
   Subsequent operations seems to work fine.  What does this mean?

A. Since you did not pass VMAF_FORCE_DENY_WRITE, the VM manager is
   bringing the whole file into memory to make sure you get a
   consistent copy in case another app opens the same doc and
   writes to it.  This requires a lot of system memory, so unless
   you have a good reason not to, I would suggest adding the flag
   VMAF_FORCE_DENY_WRITE.


What is the VM_COMPRESS_HOSED FatalError?

SDK: ALL_GEOS:PUBLIC
Q. What is the exact meaning of the VM_COMPRESS_HOSED FatalError?

A. It signifies a problem in the VM system (or in whatever created the
   VM file) that has generated a file with a gap in it (i.e. there are
   bytes in the file that are not covered by a VM block handle that
   tracks used space or one that tracks free space in the file).


Having two map blocks in a single VM file.

SDK: ALL_GEOS:PUBLIC
Q. There are two routines which allow one to set map structures for a
   VM file: DBSetMap and VMSetMapBlock. The first sets a db-item as
   the map structure, while the second sets a VM block as the map. Can
   the two (map item and map block) exist together in a single VM file?

A. Yes, a VM file can have both a map block and a map item.


Object relocation/unrelocation in Vis/Meta objects in VM files.

SDK: ALL_GEOS:PUBLIC
Q. I have objects spread among different VM blocks. Some of these are
   Vis objects, and will be connected together via the standard Vis
   linkage, while other ones will be meta objects, and will contain
   optrs to some of the Vis objects in their instance data (the Vis
   objects have optrs to meta objects in their instance data as well).

   I'm unclear about how much of the object relocation/unrelocation the
   VM code will do. Will I have to do all the relocation work myself?

A. Object relocations are performed whenever the object block is read in
   from the file.

   Make sure you call VMPreserveBlocksHandle whenever you call VMAlloc
   (or VMAttach) for any blocks that will contain objects. Also, make
   sure your class definitions are set up properly so that object
   relocations will happen.

   And, of course, make sure the VMA_OBJECT_ATTRS attributes are set for
   the file.


Locking VM block before sending to an object in that block.

SDK: ALL_GEOS:PUBLIC
Q. I am calling VMPreserveBlocksHandle on a VM file object block. Do
   I need to VMLock the block manually to send a message to an object
   within it?

A. It is a bad idea to call VMLock directly on an object block. If you
   just want to send a message to that object, use VMVMBlockToMemBlock
   to get the memory handle for that block, and then use ObjMessage.
   If you really need to lock that block, use VMVMBlockToMemBlock,
   followed by ObjLockObjBlock.


Writing a huge array to disk.

SDK: ALL_GEOS:PUBLIC
Q. How can I cause a huge array to be written out to disk after I dirty
   it?

A. VMUpdate


Checking for error in MSG_GEN_DOCUMENT_OPEN.

SDK: ALL_GEOS:PUBLIC
Q. I have a text editor and when I try to open the GEOS.INI file
   an error dialog appears saying I can't open the file. This I
   understand, but later on the program crashes when I try to
   exit.

A. The problem is in the GenDocument object that is created for the
   GEOS.INI file. Even though a message appears saying you can't
   open the file, a GenDocument object was created for it, and
   unfortunately, it remains in memory, uninitialized, waiting to
   cause an error later on. To solve this, in your
   MSG_GEN_DOCUMENT_OPEN handler check for an error returned by the
   superclass, then remove the GenDocument object.
   Here is a sample:

@method ZTEDocumentClass, MSG_GEN_DOCUMENT_OPEN {
    word * error;   /* Error value from ReadDataFromFile. */
    optr   ourText; /* Pointer to current text object. */

      /*
       * Check if error occurred during open.
       * If so, cancel the open. Return error status.
       * (Don't try to do MSG_GEN_DESTROY, that gives an error.)
       */
    if ( @callsuper() ) {
        @send self::MSG_GEN_REMOVE( VUM_NOW, 0 );
        return( TRUE );
    }
    else {
          /*
           * Read in text file by calling read data function.
           * Prepare necessary parameters first.
           */
        pself = ObjDerefGen( oself );
        ourText = ConstructOptr( pself->ZTEDI_textHandle,
                                 OptrToChunk( @ZTEText) );
        if ( ReadDataFromFile( pself->GDI_fileHandle, ourText, error ) ) {
            *fileOrError = *error;
            return( TRUE );
        }
        else {
            return( FALSE );
        }
    }
} /* MSG_GEN_DOCUMENT_OPEN */


RCM_textStyleClear in MSG_COMPLEX_MONIKER_REPLACE_MONIKER

SDK: N9000C:PUBLIC
In the message MSG_COMPLEX_MONIKER_REPLACE_MONIKER, the flags set in the
RCM_textStyleClear parameter are supposed to be cleared in the complex
moniker object. Instead, they invert the flags. So if you are, say,
trying to turn off TS_BOLD, you actually get a moniker whose bold state
is the opposite of what it was before.


Displaying text in a table.

SDK: ALL_GEOS:PUBLIC
Q. I need to use a fixed size font to display a table. How should I
   specify that I need a non-proportional font?

A. If you're working with a GState and view, GrSetFont() will do the job.
   If you're working with a text object, then MSG_VIS_TEXT_SET_FONT_ID is in
   order (or MSG_VIS_TEXT_SET_CHAR_ATTR if you're setting multiple attributes).

   If trying to find a fixed width font to use, then it depends on whether
   you need to print or not.
     No printing: Bison or URW Mono.
        Printing: URW Mono.

   If it's on Zoomer, then URW Mono doesn't have hand-tuned bitmaps and
   might not be desirable for screen display, depending on the pointsize
   being used. If you wish to find a font dynamically, then GrEnumFonts()
   can be used to find a list of matching fonts.

   Finally, depending on the table, you don't necessarily need to restrict
   yourself to fixed width fonts.  You can set tabs (including decimal tabs)
   in a text object to force things to line up.  Or if in a GState/view
   setup, you can use font metrics information to calculate text sizes and
   right-justify the entries without too much trouble. Note that the numbers
   in many (not all) fonts are fixed width.


How to change mouse pointer over vis objects.

SDK: ALL_GEOS:PUBLIC
Q. I have a Vis object and I want the mouse to work as if it were a
   GenInteraction and show the crossed circle when the mouse passes
   outside the bounds of the vis object. It seems that I have to
   intercept the mouse events, check if the pointer is outside the
   vis object and then set the pointer image appropriately.

   Question: How can we access the optr to the standard mouse pointer
   bitmaps? Or is there an easier way to work with Vis objects similar
   to setting the Gen object modal?

A. VisClass does not support the GenClass modal behavior, you will
   have to implement it yourself. Not only does the mouse pointer
   image have to change, but the Vis object has to grab the mouse,
   so that no one else gets any ptr messages while the Vis object
   is in the "modal" state.

   I don't think you can access the standard mouse pointer bitmaps.

   MSG_META_PTR is intercepted, and if the mouse is over our vis
   object, these MouseReturnFlags are returned

      MRF_SET_POINTER_IMAGE | MRF_PROCESSED

   along with the optr of the bitmap to use as the pointer image.
   When the mouse moves out of the bounds of the object,
   MRF_CLEAR_POINTER_IMAGE is returned.


What MSG_GEN_ITEM_GROUP_SET_MODIFIED_STATE actually does.

SDK: ALL_GEOS:PUBLIC
Q. I would like clarification on what MSG_GEN_ITEM_GROUP_SET_MODIFIED_STATE
   actually does. My impression is that setting this to TRUE would
   cause the GIGI_applyMsg to get sent out the NEXT time the group
   gets an apply message. Is this true?  Does this cause the STATUS
   message (if any set) to go out as well (I believe not).

A. Here's how I've used it when it applies to a GenValue, but the
   same should apply to GenItem, GenBoolean and the rest.

Say you have an object...

@object GenValueClass SampleValue = {
    GVLI_destination = process;
    GVLI_applyMsg = MSG_SAMPLE_VALUE_APPLY;
    /* setup as needed */
}

...and you want the program to change it's value....

/* Set to 'not indeterminate' meaning the value is good and ready to use
 * indeterminate = TRUE - value not ready to use, not displayed
 * indeterminate = FALSE - value ready to use and is diaplayed */

@call SampleValue::MSG_GEN_VALUE_SET_VALUE(newSampleValue, FALSE);

/* But the apply mechanism has not been notified that the value has
 * been changed. */

/* Set the modified state so the apply mechanism knows the value has
 * been updated. Basically this enables-TRUE (or disables-FALSE) the
 * apply trigger. */

@call SampleValue::MSG_GEN_VALUE_SET_MODIFIED_STATE(TRUE);

/* Now if we want to send the apply as if it was triggered...
 * This means if the apply trigger is not enabled (MODIFIED_STATE=FALSE)
 * then no applyMsg is sent. In this case, this will cause the process
 * to recieve a MSG_SAMPLE_VALUE_APPLY. */

@call SampleValue::MSG_GEN_APPLY();

I haven't used any status messages, so I don't know if they would be
sent on a MSG_GEN_APPLY. But my understanding is that a MSG_GEN_APPLY
is the same as clicking on the Apply trigger.


GenBoolean in dialog gives UI_GEOMETRY_WIDTH_TOO_LARGE error

SDK: N9000C:PUBLIC
Q. I keep getting UI_GEOMETRY_WIDTH_TOO_LARGE on the two GenBooleans
   in the following listing:

       @chunk TCHAR HelloListTitle[] = "Boolean Group";
       @object ComplexMonikerClass HelloListBox = {
           ComplexMoniker = GenInteractionClass;
           CMI_topText = @HelloListTitle;
           CMI_iconBitmap = CMB_WARNING_TITLE_ICON;
           CMI_textStyle = TS_ITALIC;
           CMI_fontSize = FOAM_NORMAL_FONT_SIZE;
           GI_comp = @HelloBooList;
           GII_visibility = GIV_POPUP;
           GII_attrs = @default | GIA_NOT_USER_INITIATABLE;
           GII_type = GIT_PROPERTIES;
           ATTR_COMPLEX_MONIKER_PLACE_BITMAP_AT_LEFT;
           HINT_PLACE_MONIKER_TO_LEFT;
           HINT_PLACE_MONIKER_ABOVE;
           HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
           HINT_EXPAND_WIDTH_TO_FIT_PARENT;
           HINT_COMPLEX_MONIKER_DONT_DRAW_SEPARATOR;
       }

       @object GenBooleanGroupClass HelloBooList = {
           GI_visMoniker = "Colors:";
           GI_comp = @HelloBoo1,
                     @HelloBoo2;
       }

       @object GenBooleanClass HelloBoo1 = {
           GI_visMoniker = "Red";
           GBI_identifier = C_RED;
       }

       @object GenBooleanClass HelloBoo2 = {
           GI_visMoniker = "Blue";
           GBI_identifier = C_BLUE;
       }

   Their sizes are over 16,000 points wide. The boolean group object
   is 0,0,-32768,-32768. If I move the boolean group from the dialog
   to the primary it works okay. What am I doing wrong?

A. It's extremely likely that GenBooleans only work when you have a
   proper properties box (which means at least that you have
   HINT_CENTER_CHILDREN_ON_MONIKERS on the top interaction). The
   other thing to check is that the dialog containing HelloListBox
   is of type GIV_DIALOG and not GIV_POPUP.


Everything you ever wanted to know about GEOS fonts.

SDK: ALL_GEOS:PUBLIC
Information about Geoworks fonts and different font formats.

The world of outline fonts is somewhat complex. There are many
companies involved at several different levels. This document
will attempt to clarify some of the terms involved and where
companies fit into the scheme of things, as well as describing
ways to add more fonts to your Geoworks software.

Overview
========
There are four different types of companies involved with outline
fonts: foundries, rasterizer companies, application companies,
and converter companies.

Foundry - designs outline fonts. An example of this is URW, which
designed typefaces such as URW Roman. Foundries license their
typeface designs to other companies.

Rasterizer Company - creates the software for rendering outline
fonts for display. An example of this is Digital Typeface
Corporation (DTC), which has a rasterizer known as Nimbus-Q.
Companies that create rasterizers make money by either licensing
the rasterizer algorithm to other companies, or by creating
separate software which adds this capability to existing
programs. Traditionally, the fonts used with rasterizing
software are licensed from a foundry. For example, many of
DTC's fonts were licensed from URW.

Application Company - licenses rasterizing software for use in
a PC application. An example of this is Geoworks, which licensed
the Nimbus-Q rasterizer from DTC for use in Geoworks. The fonts
for Geoworks were also licensed from DTC, who in turn licensed
the designs from URW.

Converter Company - makes software to convert between one or
more of the font formats. This market has come into existence
because of the large number of (incompatible) font formats.
Conversion programs allow application users to use more fonts
than might otherwise be available for the font format their
application uses. An example of this is MI.EXE from MicroLogic
Software, which converts Adobe Type 1 fonts into MicroLogic's
MLS font format.

To keep things interesting, a number of companies fall into
more than one of the above categories. For example, Adobe has
designed some of its own fonts (acting as a foundry), created
its own rasterizer (acting as a rasterizer company), and also
sells the rasterizer as an add-on product for both Windows and
the Macintosh (acting as an application company).

The Geoworks font format
========================
Geoworks licensed its rasterizer and fonts from Digital Typeface
Corporation (DTC) which acquired the company that created the
Nimbus-Q rasterizer and licensed the designs for its fonts from
URW. Geoworks uses a derivative of the Nimbus-Q format, not the
native Nimbus-Q format.

Here are the original nine Geoworks outline fonts along with names
of equivalent or near-equivalent fonts from other companies.
    Geoworks Name		Is Similar To
    =============		=============
    Cranbrook		Century Schoolbook
    Cooperstown		Cooper Black
    Sather Gothic		Franklin Gothic
    Shattuck Avenue		Park Avenue
    Superb			Broadway
    URW Mono		Courier
    URW Roman		Times Roman
    URW Sans		Helvetica
    URW Symbol		Postscript Symbol

There are a number of other ways you can make additional fonts for
GEOS:

+ ATech Software published a conversion program called AllType
  which will convert a large number of formats, including Adobe
  Type 1, True Type, ATech's FastFont format, Nimbus-Q, and
  Geoworks into any of the other formats. Atech is no longer in
  business, but AllType is distributed by Page Technology:

    Page Technology Marketing, Inc.
    10671 Roselle Street, Suite 100
    San Diego, California 92121-1525
    (619) 658-0191
    Fax (619) 658-0194
    Http://www.tfb.com/pagetech/
    Email: pagetech@tfb.com

+ MicroLogic Software offers a font converter that can convert to
  Geoworks font format.  You need MoreFontsImport to convert the
  Type 1 font to the MLS proprietary format.  Then use MoreType
  to convert the font to Geoworks format.

    MoreType and MoreFontsImport from
    MicroLogic
    1351 Ocean Ave.
    Emeryville, CA 94608
    (510) 652-5464

Now that they're converted, what do I do?
=========================================
Once the fonts are converted to the Geoworks format, simply copy
the font files into the USERDATA/FONT directory.  Restart GEOS
and it will find the new fonts.


Seeing what apps have a document opened.

SDK: ALL_GEOS:PUBLIC
Q. How does one find out all the applications that have
   a particular document file open?  The problem is that
   IACPConnect() requires a GeodeToken to determine which
   servers to connect to.

A. Well, IACP maintains a registry of all the open docs.
   Unfortunately, the only way to make use of it is to perform
   an IACPConnect. The token is easy enough to come by:
   FileGetPathExtAttributes(FEA_CREATOR, filename, disk). Create
   an AppLaunchBlock with the document name and a 0 disk handle
   for the app, and voila.

   A more reasonable approach would be to get the CREATOR token
   and do an IACPConnect with no AppLaunchBlock, then send the
   appropriate recorded message with a DocumentCommonParams for
   the document as stack data in the recorded message, sending it
   TO_MODEL to the GenDocumentGroupClass object (likely).


Getting the token ID of a running application.

SDK: ALL_GEOS:PUBLIC
Q. I got the optr for an application from
   MSG_GEN_FIELD_GET_TOP_GEN_APPLICATION, and I would like to get the
   tokenID for that application. How can I get it?

A. Ultimately you want to call GeodeGetInfo, which requires a GeodeHandle.
   You can get the GeodeHandle from MemOwner(OptrToHandle())


How do I use GeodeFind on an app?

SDK: ALL_GEOS:PUBLIC
Q. How do I make GeodeFind work?  I am using the DOS file name for
   the application and I double checked to see that the application
   is on the disk, but its always returns 0.

A. Use the geode's permanent name, not the file name. The permanent
   name is specified in the .gp file in the "name" field.


Increasing the size of an interaction to fit buttons.

SDK: ALL_GEOS:PUBLIC
Q. I have two GenTriggers inside a GenInteraction. I increased the
   space between the two GenTriggers with HINT_CUSTOM_CHILD_SPACING.
   I would also like to increase the size of GenInteraction so that
   there is more space between the GenInteraction border and the
   GenTrigger borders. How can I make the GenInteraction become
   larger, or how can I increase the distance between the GenTriggers
   and the border of the GenInteraction?

A. Use HINT_INCLUDE_ENDS_IN_CHILD_SPACING on the GenInteraction.

   All of this geometry stuff is in Chapter 12 of the Concepts Book.


Making a Gen object large enough, but not too large.

SDK: ALL_GEOS:PUBLIC
Q. How do you set the "desired" width for a GenText object? Specifically,
   I'd like to be able to have a GenText that is roughly 500 pixels wide,
   but never so wide as to push the GenInteraction it is inside of off of
   the screen (i.e. forced to shrink on the Casio Z-7000/Tandy Z-PDA).

A. This will cover both requirements:
    HINT_INITIAL_SIZE = { (SST_PIXELS | 500), 0 },
    HINT_MAXIMUM_SIZE = { (SST_PERCENT_OF_FIELD_WIDTH | PCT_100), 0 };


Resizing an interaction using hints.

SDK: ALL_GEOS:PUBLIC
Q. HINT_EXPAND_HEIGHT_TO_FIT_PARENT is getting ignored in my
   GenInteraction (GIV_POPUP) which has a FileSelector child.

A. HINT_EXPAND_{HEIGHT/WIDTH}_TO_FIT_PARENT and
   HINT_{FIXED/MINIMUM/MAXIMUM/INITIAL}_SIZE don't do anything on
   windowed objects. You have to use HINT_SIZE_WINDOW.. hints.


Using the HINT_SIZE_WINDOW_AS_RATIO_OF_.. hints.

SDK: ALL_GEOS:PUBLIC
Q. Every time I use HINT_SIZE_WINDOW_AS_RATIO_OF_(PARENT or FIELD),
   my window is larger than the screen. My PCT_xx values are far
   less than 100. I am using them on GenInteractions.

A. Make sure to use SWSS_RATIO like this:
    HINT_SIZE_WINDOW_AS_RATIO_OF_PARENT = {
        ( SWSS_RATIO | PCT_40 ),
        ( SWSS_RATIO | PCT_60 )
    };


Keeping a dialog on top of other windows.

SDK: ALL_GEOS:PUBLIC
Q. How can I make a dialog (GenInteraction, GIV_DIALOG) always stay
   on top of other dialogs in my application?

A. Use window layering, which allows you to set the "height" that you
   want the dialog box to display at.  See section 2.6.1.7 (Window
   Management) of the Objects book for more information.


Finding the screen height and width of the system.

SDK: ALL_GEOS:PUBLIC
Q. How can I get the screen width and height on any system?

A. There is no specific API to get general system metric information.
   For your specific request to get the screen width and height, you
   will need to do use MSG_GEN_GUP_CALL_OBJECT_OF_CLASS to send
   MSG_VIS_GET_BOUNDS to the GenFieldClass. MSG_VIS_GET_BOUNDS returns
   the current bounds of an object in a variable of type Rectangle.

   The GenField object is kind of a backdrop that everything else sits
   on. (Section 28.4 of the Objects 3 book [Objects\OSysObj.txt]
   describes the GenFieldClass in more detail.)


How to make a menu not pinnable.

SDK: ALL_GEOS:PUBLIC
Q. How can I make a popup menu not pinnable?

A. HINT_INFREQUENTLY_USED


Running apps on the device, protocol conflicts.

SDK: ALL_GEOS:PUBLIC
Q. When we try to run our application on the Casio Z-7000, we receive
   the error: "This application is incompatible with this version of
   the system software.  Error Code: FM-37."  How do we get our programs
   to run on this device?

A. Put "platform zoomer" in your .gp file. For the OmniGo, try "platform
   omnigo"; on the Nokia 9000 Communicator, use "platform n9000".


Using the functions in ansic library.

SDK: ALL_GEOS:PUBLIC
Q. My application uses the functions memcpy and memset. The string.h
   file is included in the program, but when recompiling, I get:
   "Error _memcpy undefined" and "Error _memset undefined". What am I
   doing wrong?

A. You need to add "library ansic" to your .GP file. This will tell
   Glue to link in the AnsiC library.


Compiling source files that are too large.

SDK: ALL_GEOS:PUBLIC
Q. Why am I getting this Glue error?

   BORLAND.C: Line 2466: assert(base == ((genptr)sos - scopeOff)) failed.
   *** Error code 1

Q. This is caused by having a source file that is too huge.  I would
   suggest splitting the source into multiple files (this can also
   speed compilation as files that are unchanged between compilation
   do not need to be recompiled).

   Some considerations when splitting up source code:
     *	keep all objects that are in the generic tree within the same
    file (i.e., all objects that are statically connected should
    be in the same file).  If you split up the objects into several
    source files, you will need to use MSG_GEN_ADD_CHILD to
    dynamically link them because during compilation time Glue does
    not create the links between objects if they are in separate
    source files.

     *	The standard paradigm for multiple files under GOC is to have all
    object declarations in one file, and routines and method handlers
    grouped in source files by the object that they support.


Forgetting to declare the resources in the .gp file.

SDK: ALL_GEOS:PUBLIC
Q. When compiling, Glue complains:
   "Error test.gp 41: resource CommonCode not defined"

   though the .goc file has:
    @start CommonCode;
    [ ... ]
    @end CommonCode

   what does the err message mean?

A. It means you didn't declare the resources in the .gp file.
   Add a line something like this:
    resource COMMONCODE shared


Extension on application name in .gp file.

SDK: ALL_GEOS:PUBLIC
Q. In the *.gp file, there's the "name hello.app" line.
   What are all the options for the three character extension?

A. Any suffix is valid.  These are the standard ones Geoworks uses:
   app	= application
   lib	= library
   drvr	= driver
   ifsd	= File system driver
   spui	= specific UI
   kern	= kernel


What is c-api for in the .gp file?

SDK: ALL_GEOS:PUBLIC
Q. What is the purpose of the "c-api" flag on the "type" line of a
   .gp file?

A. This is needed for libraries and preferences modules that are
   written in Goc. It tells the kernel to call the library entry
   point by passing stuff on the stack.


What does HAF_NO_ERR do in MemAlloc

SDK: ALL_GEOS:PUBLIC
> If I call MemAlloc with HAF_NO_ERR, what will actually happen? Will it
> just wait forever if it can't allocate enough space?

HAF_NO_ERR causes MemAlloc to not return until it can allocate the
memory.  After several attempts (either 3 or 8, not sure which) to
allocate the memory, the system will put up a SysNotify dialog box
saying the system is out of memory (with the option to reboot or
retry the attempt to allocate memory).

Just as some background: When MemAlloc fails to find the necessary
memory, it sleeps the threads for several ticks in hopes that some
other thread will happen to free up memory that it had been using.


I get the OBJ_LOCK_OBJ_BLOCK_BY_WRONG_THREAD death.

SDK: ALL_GEOS:PUBLIC
Q. I just added a new source file to my program, and I get this error
   when my program starts up:
     OBJ_LOCK_OBJ_BLOCK_BY_WRONG_THREAD

A. Make sure the resource in the new file is listed in the .GP file.
   If it's not, it defaults to 'object' type and can't be run if the
   objects in the new file are children of objects that are in the
   'ui-object' thread.


How can I get the directory path for my application?

SDK: ALL_GEOS:PUBLIC
Q. How can I get the directory path for my application?

A. The GenApplicationClass has instance data (GAI_appRef) containing the
   path where the application was launched from.
   MSG_GEN_APPLICATION_GET_APP_INSTANCE_REFERENCE returns GAI_appRef as
   a block handle of the structure AppInstanceReference.

   typedef struct {
       PathName       AIR_fileName;
       FileLongName   AIR_stateFile;
       DiskHandle     AIR_diskHandle;
       byte           AIR_savedDiskData[1];
   } AppInstanceReference;


Dialog at the bottom of the screen.

SDK: ALL_GEOS:PUBLIC
Q. I have a GenInteractionClass object that I wish to display at the
   bottom of my application's view on the Zoomer (similar to the way
   the pop-up keyboard works). What HINT/ATTR would allow me to make
   the bottom of this object align to the bottom of the screen?

A. HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT = {
        SWSS_RATIO|PCT_nn, SWSS_RATIO|PCT_nn
   };
   where 'nn' (from PCT_nn) is a multiple of five from 0 to 100.


Getting a GenFileSelector to show both DOS and GEOS files.

SDK: ALL_GEOS:PUBLIC
Q. In GenFileSelector, when I set GDCI_selectorType = GFST_ALL_FILES,
   it doesn't show both DOS and GEOS files. How can I get it to show
   all files (both DOS and GEOS)

A. Subclass GenDocumentControl and override the method
   MSG_GEN_DOCUMENT_CONTROL_CONFIGURE_FILE_SELECTOR. The prototype for
   that method is as follows

    @message MSG_GEN_DOCUMENT_CONTROL_CONFIGURE_FILE_SELECTOR
        (optr fileSelector, word flags);

   In this case, the flags are the GenDocumentControlAttrs structure,
   which is described in the docs as well as the header file.

   In the override of this method, you can do what it says:
   configure the file selector - to list all types of files.


Specifying the path to open in a GenFileSelector.

SDK: ALL_GEOS:PUBLIC
Q. When limiting the search in a file selector to a single directory,
   how does one specify the name of the directory in the .ui file?

A. To specify the path of a GenFileSelector, add ATTR_GEN_PATH_DATA.

   To limit the ability to change directories, you'll have to turn off
   the FSA_ALLOW_CHANGE_DIRS attribute.


Adding text to a GenText using MSG_VIS_TEXT_APPEND_PTR.

SDK: ALL_GEOS:PUBLIC
Q. I have an application that writes lots of text to a GenText
   object by calling MSG_VIS_TEXT_APPEND_PTR.  After a while
   the system crashes and gives the following message:

   WARNING: FAULTING_IN_VM_BLOCKS
   Death due to TS_LOCK_TEXT_PTR_INVALID_RETURN_VALUE

A. Your text object has gotten larger than 20K.  This is because
   the system only checks to see if a text object has gotten too
   large when the user is entering text.  You should either use a
   VisLargeText object or monitor the amount of data that you are
   adding to the GenText and begin removing old text as the GenText
   fills up.


Using ATTR_GEN_TEXT_CHAR_ATTR in a text object.

SDK: ALL_GEOS:PUBLIC
Q. I have a problem setting ATTR_GEN_TEXT_CHAR_ATTR.  Here is a sample
   of what I am doing:

    ATTR_GEN_TEXT_CHAR_ATTR = { 	   {{{2, 0}}, CA_NULL_ELEMENT}, VTDF_BERKELEY, {0, VTDS_12}, 	   0, {C_BLACK, CF_INDEX, 0, 0}, 0, FWI_MEDIUM, FW_NORMAL, 	   0, SDM_100, {0}, {C_WHITE, CF_INDEX, 0, 0}, SDM_0, {0}, 	   {0,0,0,0,0,0,0}};

A. ATTR_GEN_TEXT_CHAR_ATTR should have a chunk handle, so do this:

    /* Define a chunk to hold the data */
    @chunk VisTextCharAttr myTextCharAttr = {
       {{{2, 0}}, CA_NULL_ELEMENT}, VTDF_BERKELEY, {0, VTDS_12}, 	   0, {C_BLACK, CF_INDEX, 0, 0}, 0, FWI_MEDIUM, FW_NORMAL, 	   0, SDM_100, {0}, {C_WHITE, CF_INDEX, 0, 0}, SDM_0, {0}, 	   {0,0,0,0,0,0,0}};

    /* in your object, use that chunk */
    ATTR_GEN_CHAR_ATTR = @myTextCharAttr;


Reverse video for GenText objects.

SDK: ALL_GEOS:PUBLIC
Q. Is there an easy way to cause the text field of a GenTextClass
   object to be displayed in reverse video?

A. Use HINT_TEXT_WASH_COLOR. If you set the background to black,
   you will have to change the character attributes so the characters
   are not black.


Pasting gstrings (graphics) into a GenText.

SDK: ALL_GEOS:PUBLIC
Q. Given a GenText object, could I stick a GString into its text somehow?
   Would weird things happen to the line spacing?

A. You can paste a gstring into the GeoWrite text layer. The text
   library takes care of figuring out the line spacing based on the size
   of the graphic. GeoWrite uses a subclass of VisText to do this, but
   help files created in GeoWrite are displayed using a subclass of
   GenText. If you use GeoWrite to insert the graphic into the text,
   then copy the portion of the text which includes the graphic to the
   clipboard, you could paste it into a GenText.

   After 3/1/97 GeoWrite became NewWrite since NewDeal now owns the
   desktop software.


Subclassing MSG_GEN_VALUE_GET_VALUE_TEXT in GenValueClass.

SDK: ALL_GEOS:PUBLIC
Q. I have a message handler for MSG_GEN_VALUE_GET_VALUE_TEXT
   which provides the kind of display string I need. The
   length of the value field in the display seems to be fixed
   so that my string is clipped.

A. Make sure you do not @callsuper, as that will set the
   sizing to the width of a WWFixed value.


Adding items to a menu that don't show up.

SDK: ALL_GEOS:PUBLIC
Q. I added a couple of entries to a menu and now the contents of the
   menu don't appear when I click on it. I looked at the source
   code, but I just can't see what's wrong.

A. Sometimes when you add items to a menu (or any other object tree)
   you forget to change all the links. Here's a rough example:

     @object class object1 = {
         GI_comp = @object2,
                   @object3;
     }

     @object class object2 = {
     }

     @object class object3 = {
     }

   Now say I want to add an object4 and group it with object3:
     @object class object1 = {
         GI_comp = @object2,
                   @object3;
     }

     @object class object2 = {
     }

     @object class objectgroup = {
         GI_comp = @object3,
                   @object4;
     }

     @object class object3 = {
     }

     @object class object4 = {
     }

   Now I'm sure you can see something was forgotten, as this is a
   simple example. I forgot to change the GI_comp field in object1,
   so it's pointing to the wrong object. It should be like this:

     @object class object1 = {
         GI_comp = @object2,
                   @objectgroup;
     }

   In a more complex object tree, spotting this error is difficult.


Floating windows on the OmniGo.

SDK: OMNIGO:PUBLIC
Q. I cannot get the GenPrimary to be a floating window (like you can in
   Ensemble or like Clip & Go. How can I do this?

A. On the OmniGo, GenPrimary is forced to be full-screen no matter
   what. To get around this, you will have to make a GenInteraction
   (GIV_DIALOG) and use that as the floating window.

   If you wish to make the GenPrimary hidden so your application is only
   represented by a floating window, attach (GI_comp) the dialog box to
   the GenApplication object. In MSG_GEN_PROCESS_OPEN_APPLICATION, send
   MSG_GEN_INTERACTION_INITIATE to the dialog box (and make the dialog
   box GIA_NOT_USER_INITIATABLE).


Borland C can't find the stddef.h file.

SDK: ALL_GEOS:PUBLIC
Q. Goc keeps telling me that it can't find stddef.h. I found stddef.h
   in the Borland C++ include directory, but not in the PCGeos include
   directory. Is that the right place for it to be?  What should I do?

A. This problem usually occurs because you move or change BorlandC's
   root directory, but don't update the turbo.cfg file that contains
   pointers to the borlandc bin and include directories. First, make
   sure that \BIN is in your path. Second, check the
   turbo.cfg file in the borland bin directory. It should have the
   following lines in it:
        -IC:\BORLANDC\INCLUDE
        -IC:\BORLANDC\LIB

   (if you have the Borland compiler on a drive other than C: or in a
   directory other than BORLANDC, please read that into the preceding
   suggestions.)


How should BIOS calls be made in GOC?

SDK: ALL_GEOS:PUBLIC
Q. How should BIOS calls be made in GOC?

A. BIOS calls can be dangerous, as the GEOS kernel controls many of them
   (serial ports, timers, etc.). This will also limit your application
   to operate only on hardware that provides the necessary BIOS. With
   that said, you can use in-line assembly code to generate an interrupt.
   The syntax looks like this:

        SysLockBIOS();
    asm {
             mov     ax, 10
             int     21h
    }
        SysUnlockBIOS();

   Keep in mind that GEOS interrupts will not be processed. Thus your
   app will not thread or task switch. Try to keep your excursions in
   BIOS-land to a minimum in number and duration.


Using @ifdef/@endif in GOC code.

SDK: ALL_GEOS:PUBLIC
Q. I have the following code fragment in my program and I get a
   Goc error saying "ifdef is undefined".

   @chunk optr enableDisableList[] = {
       @ifdef ZOOMER
       @MySaveTrigger,
       @endif
       @MyOtherObject
   };

A. The problem there is Goc thinks @ifdef is an object, instead of
   a directive. To fix it, have the @ifdef and @endif against the
   left margin, like this:

   @chunk optr enableDisableList[] = {
   @ifdef ZOOMER
       @MySaveTrigger,
   @endif
       @MyOtherObject
   };


I get the 'open conditional' error in Borland C.

SDK: ALL_GEOS:PUBLIC
Q. I have the following code fragment in my global.goh and I get a
   Goc error saying "Open conditional...".

    @extern object @SomeObject;
    @ifdef ZOOMER
    @extern object @AnotherObject;
    @endif
    @extern object @MyOtherObject;

A. The problem there is Goc doesn't like it when the @ifdef and
   @endif are not against the left margin. Fix it be bringing
   the @ifdef and @endif to the very left side of the document.
   For example:

    @extern object @SomeObject;
@ifdef ZOOMER
    @extern object @AnotherObject;
@endif
    @extern object @MyOtherObject;


I get this error in GOC: realloc: Illegal address (0x0)

SDK: ALL_GEOS:PUBLIC
Q. I get the following error when GOC runs:

   realloc: Illegal address (0x0)

A. This is a problem with the memory system. The only solution I
   have found is to exit all the applications and reset the system.
   It doesn't happen if you have 16MB of RAM or more.


Is there an @else directive in GOC?

SDK: ALL_GEOS:PUBLIC
Q. The Concepts book mentions the @if and @endif directives, but no
   @else. Is there one?

A. Yes. For whatever reason, the @else didn't make it into the
   documentation. It is available and works just like a #else only
   it's used with code that contains @ symbols (just as the @if
   directive is used with code containing @ symbols).


I get this GOC error: End of file in resource declaration

SDK: ALL_GEOS:PUBLIC
Q. I get the following error when GOC runs:

   End of file in resource declaration...

A. Put a  semicolon (;) at the end of the @chunk declarations.
   Strange, but that fixes the error.


Bitmaps versus gstrings/drawing routines.

SDK: ALL_GEOS:PUBLIC
Q. To draw a small icon, is it faster to call drawing routines, or
   use a bitmap? If bitmaps are better, how do I create one?

A. It depends on the type of bitmap (simple or huge/complex), the
   specific Graphics routines you're using, and the dimensions of
   the graphic. There are other considerations besides speed, too--
   large bitmaps generally take up a lot of space compared to
   gstrings.

   You could test out your specific case by timing how long it takes
   to draw, say, 100 copies of the graphic in your app. This should
   exaggerate any speed difference to where it's readily apparent
   which one is faster. It would be hard to guess in advance.


How do I use GrCreateBitmap?

SDK: ALL_GEOS:PUBLIC
Q. How do I use GrCreateBitmap?

A. GrCreateBitmap returns a GState that points to a large bitmap
   structure (which in turn is stored in a huge array). One then
   draws using the returned GState, which stores the image in the
   bitmap.


Using the fire buttons on the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. How can I  use the Zoomer's fire buttons (and presumably the joystick
   button) in my application?

A. Look at section "Controls" in the Zoomer portion of the
   documentation. It includes the following:

   Input from the buttons acts as "keyboard" input, using a custom set of
   "keys."

   These keyboard input events will have a character whose top byte has the
   value CS_CONTROL and whose bottom byte has one of the following VChar
   ( "virtual character" ) values:

   VC_JOYSTICK_135  VC_JOYSTICK_90  VC_JOYSTICK_45
   VC_JOYSTICK_180  _______________  VC_JOYSTICK_0
   VC_JOYSTICK_225  VC_JOYSTICK_270  VC_JOYSTICK_315

   VC_FIRE_BUTTON_1  VC_FIRE_BUTTON_2

   The VC_JOYSTICK values correspond to the Zoomer directional keys. Note
   that the Zoomer has just four directional buttons-the 45, 135, 225, and
   315 degree values will be passed when the user is pressing two buttons
   at once. The VC_FIRE_BUTTON values correspond to the two zoomer fire
   buttons.


Missing libraries on the Zoomer platform.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. I'm developing an application for the Zoomer platform. I was
   testing it on the GEOS2XEC version and it worked fine. But, when
   I try to run the program from the ZOOMEREC version of GEOS it says
   "Missing library or component." What's wrong?

A. The problem is there are libraries missing from the Zoomer.
   Here is a list of all the missing libraries on the Zoomer:
     Bitmap        Chart       Convert
     DIB           FFile       FileStream
     Game          GrObj       MSMFile
     Saver         Spell       Spline
     SSheet        SSMeta


Accessing power-management on the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. How do I access the power management system on the Zoomer. That is,
   how do I request battery level information?

A. The only way to access the Zoomer power management is through an
   "internal" assembly interface. At this time, that interface is not
   published in our SDK. Additionally, there is no way to get battery
   level information on the Zoomer at all, even using the assembly
   interface.


Accessing the infrared (ir) port on the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. How can I code for the infrared port on the Zoomer?

A. The serial API controls both the physical RS-232C and the IR.  You
   can select which method of communication to use by selecting the com
   port as follows:

           Com1 = Serial RS-232C port
           Com2 = Short Range IR (18 inches)
           Com3 = Long Range IR (36 inches)
           Com4 = PCMCIA serial device

   Note that the long range IR (Com3) uses a *lot* of power while the com
   port is open, so it is best to send out the data in a burst, then shut
   down the port.


Serial driver doesn't work on the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. The Serial driver doesn't seem to work on Zoomer. Is it compatible?

A. It is compatible with the Zoomer. Please read the documentation about
   the "platform" and "publish" gp file directives, which can be found in
   the Routines book. You need to specify in your .gp file that you
   are developing geodes that you want to be able to run on the Zoomer.
   You do that by adding "platform zoomer" to your .gp file and by
   adding "exempt streamc" to your .gp file. Also, be sure that
   \PCGEOS\INCLUDE\LDF\ZOOMER.PLT is not marked read-only.


Running PCCOM on the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. From within our geode running on the Zoomer, will we be able to,
   triggered by the user, run pccom like the Casio Z-7000/Tandy Z-PDA
   File Manager does?

A. Sure, just DosExec PCCOM.EXE. Actually, you'll want to use the
   .ini file settings that indicate the correct parameters to pass
   to PCCOM (for baud, etc.). Category is 'fileTransfer', keys are
   'command' and 'parameters'.


Calling UserStandardSound more than once rapidly.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. If I call UserStandardSound( SST_KEY_CLICK ) followed almost
   immediately by UserStandardSound( SST_WARNING ), the latter
   sound (SST_WARNING) is never heard. This happens on the
   PC Zoomer emulation.

A. This problem is only on the PC. The problem is because the
   app is requesting to play two sounds at the same time, but the
   PC hardware can only support one. The Casio Z-7000 and Tandy
   Z-PDA, however, have three separate tone generators, so the app
   could send UserStandardSound() three times before running
   into problems.

   If you want to have all the clicks cue up, you need to use a
   sound stream instead of calling UserStandardSound(). Or you
   need to make the app pause for 1 tick (via TimerSleep) before
   sending out the SST_WARNING.


How can I run Swat using a Zoomer as my target machine?

SDK: ALL_GEOS:PUBLIC
Q. How can I run Swat using a Zoomer as my target machine?

A. There are other methods, but here's one way to run Swat with a Zoomer
   as the target machine (in ten easy steps):

   1. You may need to perform a full reset on the Zoomer to free space in
      the RAM disk. You'll need space for your application plus at least 273k.
      (To do a full reset, press and release the reset button in the battery
      compartment while holding down both fire buttons. Keep holding down
      both fire buttons for a few seconds, then release. Then press and
      release the A button.)

   2. Copy \TARGET\ZOOM\LOADER.EXE from the SDK CD to the \PCGEOS\LOADER      directory on the host machine.

   3. Connect the serial cable from your host machine to the Zoomer.
      Check your baud rate for PCCOM. (If you've reset the Zoomer, it will
      be at the default 19200. If need be, run Preferences on the Zoomer and
      change the baud rate for File Transfer mode.)

   4. On the Zoomer, run File Manager, tap the Connect menu, tap File
      Transfer, tap the "Switch to File Transfer Mode" button in the
      dialog box.

   5. On the host machine, CD to the \TARGET\ZOOM directory on the CD and
      enter the following commands to send the three files to the Zoomer
      (page Z.12 of the sdk documentation--\ZOOMDOC):
        PCSEND GEOS.GEO
        PCSEND LOADER.EXE
        PCSEND SWAT.EXE

   6. Press a fire button on the Zoomer to exit PCCOM. (If it won't exit
      for some reason, perform a warm reset by pressing the reset button in
      the battery compartment without holding the fire buttons.)

   7. On the Zoomer, run File Manager, go to the \GEOWORKS directory and
      move GEOS.GEO to the \SYSTEM directory. Here's a step-by-step:
        A. tap to select the file: GEOS Kernel (GEOS.GEO)
        B. tap Move in the File menu
        C. select SYSTEM in the Move dialog box
        D. tap the Move button

   8. When ready to run Swat, tap File Transfer in the Connect menu
      on the Zoomer.

   9. Run Swat on the host machine.

   10. Swat will report it can't find hwrrom.lib, palmui.lib, and
       alarm.app. Enter "Ignore" for each of those.


Running tasks in the background.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. We need to run background tasks on the Zoomer. I use ThreadCreate
   to start background task, but Glue reports:

   Error MAP1BKG.GP 19: Usage of THREADCREATE requires geos minor protocol 9,
   but platform files only allow minor protocol 3

A. This is caused by an enhancement in our new kernel. Since Casio
   Z-7000 and Tandy Z-PDA use the old kernel, it cannot use the additions
   to thread create. To overcome this, you can call ThreadCreate_Old.
   To use ThreadCreate_Old, you must provide the prototype for it and
   at surround the call with push/pop of the si register. Here is an
   example:

    extern ThreadHandle
        _pascal ThreadCreate_Old(word priority,
             word valueToPass,
             word (*startRoutine)(word valuePassed),
             word stackSize,
             GeodeHandle owner);
    .
    .
    .
    asm push si;
    thread = ThreadCreate_Old();
    asm pop si;


How to convert ink objects into bitmaps.

SDK: ALL_GEOS:PUBLIC
Q. Please tell me how I could convert vm data from inkclass objects
   into standard bitmap files (e.g. PCX, BMP, etc.).

A. Here's an outline of what you need to do to convert ink data to a
   standard graphics format.

   The first step would be to instantiate an ink object, and
   load it with the ink data you want to convert to a bitmap.

   To convert the ink data to GEOS bitmap format, create a
   bitmap with GrCreateBitmap() -- this results in a gstate
   for drawing into the bitmap.  Then have the ink object draw
   itself by sending it a MSG_VIS_DRAW (you might want to pass
   DF_EXPOSED and DF_PRINT as the draw flags for MSG_VIS_DRAW)
   passing the gstate of the bitmap.

   You finally use an export controller in your application to
   convert the GEOS bitmap data to one of the supported graphics
   formats (PCX, BMP, etc.).  The impex library is covered in
   chapter 16 of the Objects book.  (I would recommend minimum
   reading of section 16.1.2, 16.2 - 16.2.1.2, and 16.2.3.)


Using bitmap tools.

SDK: ALL_GEOS:PUBLIC
Q. I want to use the bitmap tools in my paint program. Where are
   they in the header files?

A. The bitmap tool controller is defined in INCLUDE/OBJECTS/
   BITMAPC.GOH. The controller class is VisBitmapToolControlClass
   and this is used just like GrObjToolControlClass. You will have
   to edit the BITMAPC.GOH file before you can use it. There is a
   struct defined in it that is also defined in GROBJ.GOH, and if
   you're using both (which is highly likely), then you should
   comment out the struct in BITMAPC.GOH called RectDWFixed. It is
   not used in BITMAPC.GOH anyway.


Does the OmniGo support gray scale?

SDK: OMNIGO:PUBLIC
Q. Does the OmniGo support gray scale?

A. No.


How can I disable Help controller features?

SDK: ALL_GEOS:PUBLIC
Q. How can I get rid of (or disable) the contents button of the help
   dialog (if we decide not to display the contents at all) ?

A. On your HelpControl object, add the following:
    ATTR_GEN_CONTROL_PROHIBIT_UI = HPCF_CONTENTS;

   If you look in INCLUDE\OBJECTS\HELPCC.H, you will see a data type
   called HPDFeatures. Mix and match these features with the GenControl
   attributes ATTR_GEN_CONTROL_PROHIBIT_UI and ATTR_GEN_CONTROL_REQUIRE_UI
   to change the help controller's UI gadgetry.


Undocumented help contexts in standard controllers.

SDK: ALL_GEOS:PUBLIC
Q. I just finished creating a help file for my program, and I
   generated it and so on. When I start my program and click on the
   help button in the New/Open box, I get an error message that says:

   Error in help: Unable to find
   "dbDCBig" section in help file "texted
   ". Please note the exact text of this
   message if it occurs.
   Error Code: HP-02

   What does this mean and how do I fix it?

A. What has happened here is the GenDocumentControl has a line like this:

   ATTR_GEN_HELP_CONTEXT = "dbDCBig"; /* You can't change this easily. */

   What you must do is add a context to your help file with the name
   dbDCBig. In this context you can put something about how to open and
   create documents, or at least put in hyperlinks to contexts that
   discuss those topics.

   There are other help contexts related to the GenDocumentControl.
   They are dbDCCopy, dbDCOpen, and dbDCSaveAs.

   The PrintControl class also has a context, dbPrint, which goes
   with the main Print dialog.

   There may be more "secret" contexts like this one that you must
   add to your help file. To find them, run your program and click
   on ANY help triggers you see, and note the name of the section
   in the box if you get the error.


Help file names must be padded to eight spaces.

SDK: ALL_GEOS:PUBLIC
Q. I created a new help file for my program, and when I try to view
   the help, I get an error message that it can't find the file.
   I have the two spaces after the name that it seems to want, but
   it still doesn't find it.

A. The two spaces after the name of the help file is coincidental.
   To name your help files, first, take the name of your program
   and make it all lowercase letters. Then, pad the name with
   spaces until you have eight characters. All help file names are
   in lowercase and are eight letters long.


Pressing Fn-F1 as opposed to tapping on the ? button.

SDK: OMNIGO:PUBLIC
Q. When I press Fn-F1 to bring up help for my OmniGo application,
   it doesn't bring up context sensitive help. When I press the "?"
   icon to bring up help, it is context sensitive, so it brings up
   help about the current object. What's the difference?

A. This is a Geos problem (it will be fixed in the next version of
   the OmniGo). Anyway, here's what you can do to make Fn-F1 bring
   up context sensitive help. Intercept MSG_META_BRING_UP_HELP for
   the GenApplicationClass object and send yourself
   MSG_GEN_APPLICATION_BRING_UP_HELP.


Using the appropriate InitFile routine.

SDK: ALL_GEOS:PUBLIC
Q. I was attempting to use InitFileReadDataBlock for getting the file
   transfer settings from the ini file. Though the "parameters" key
   was definitely set under the "fileTransfer" category, I was getting
   a size of zero and an empty data block (I was getting a successful
   return from the call).

A. You must use the appropriate InitFileRead.. routine for a given
   INI file item. That is to say that if the item is a string value
   then you need to use InitFileReadString.. and if the item is an
   integer value then you would use InitFileReadInteger().


Having ink turn into text in a view.

SDK: ALL_GEOS:PUBLIC
Q. We're using VisText objects. The text objects appear and are editable
   via the PC keyboard and the floating keyboard. However, the user can't
   write any ink in the object for HWR. Clicking and dragging the mouse
   simply selects text. What attribute needs to be set so that it will
   also allow pen input (ink->HWR)?

A. The general rule is, unless you know for sure what you're doing, set
   GVI_inkType = GVIT_QUERY_OUTPUT on the view. GVIT_QUERY_OUTPUT, when
   used with system-provided objects (ink object, text object) will always
   work.

   The default for GVI_inkType is GVIT_PRESSES_ARE_NOT_INK.


Setting the brush size for drawing ink.

SDK: ALL_GEOS:PUBLIC
Q. How do I set the brush size in IDIP_brushsize?  I tried 0x0002, but
   it is not working.

A. IDIP_brushsize (part of InkDestinationInfoParams) is a word size
   parameter, which provides a byte each for the X and Y brush size.
   To set this correctly to a brush size of 2 (for example), you need
   to set IDIP_brushsize to 0x0202, rather than 0x0002.


What is happening when ink is entered?

SDK: ALL_GEOS:PUBLIC
Q. What is happening when ink is entered?

A. When the user clicks on an area of the screen that accepts ink
   input (for example, on a view that has its GVI_inkType field set
   to GVIT_PRESSES_ARE_INK), the object that is clicked on notifies
   the system that it should start drawing/collecting ink.

   Since the system will (in most cases) erase the ink after the user
   is done, it first saves as much of the screen as is possible (on the
   Casio Z-7000 and Tandy Z-PDA, the entire screen is saved) and restores
   it when the user is done entering ink, without requiring any redrawing
   by the application (this is why you do not get a MSG_META_EXPOSED after
   the user draws ink.)

   Ink delivery is one of the rare places in the system where you get
   a MSG_META_NOTIFY_WITH_DATA_BLOCK without being on any GCN list. There
   is no GWNT_INK GCN list (at least, no messages are ever sent to it),
   and so you need not worry about adding yourself to it. In your
   application, when the user has finished drawing ink in your GenView,
   the system erases the ink, and sends the ink (via
   MSG_META_NOTIFY_WITH_DATA_BLOCK) to the view, which sends it to the
   optr stored in its GVI_content field.

   Make sure to set the VI_bounds of your ink object.  Its default is
   0 pixels by 0 pixels, which would not allow the user to enter ink on
   it.

   Also, if you the ink object is the only child of the content, you will
   want to set the IF_ONLY_CHILD_OF_CONTENT flag on the ink object, which
   will cause the ink object to use some internal optimizations that can
   speed up ink entry.


Grabbing a line of text under the mouse.

SDK: ALL_GEOS:PUBLIC
Q. How do I detect a mouse click on a text object at a given line, and
   then get the text for just that line?

A. Subclass MSG_META_START_SELECT, and given the mouse position,
   Use: MSG_VIS_TEXT_GET_TEXT_POSITION_FROM_COORD to map the mouse
   click to a text position, MSG_VIS_TEXT_GET_LINE_FROM_OFFSET to
   map from a text offset to a line, and MSG_VIS_TEXT_GET_LINE_INFO
   to get the number of characters in the line, then you can grab
   the text using MSG_VIS_TEXT_GET_TEXT_RANGE or one of its brethren.


Why must MRF_PROCESSED be returned for mouse events?

SDK: ALL_GEOS:PUBLIC
Q. Why must MRF_PROCESSED be returned for mouse events?

A. The MRF_PROCESSED flag is there so the parent window will know whether
   a child was hit or the window background was hit, as windows can have
   their own behavior if their background is hit.


Where should MSG_VIS_RELEASE_MOUSE be called?

SDK: ALL_GEOS:PUBLIC
Q. The techdocs state that MSG_VIS_RELEASE_MOUSE will typically be
   called in the handler to MSG_META_END_SELECT; however, in the
   TicTac sample app, it is called in the handler for
   MSG_VIS_LOST_GADGET_EXCLUSIVE. Where is the preferred place
   to call MSG_VIS_RELEASE_MOUSE?

A. The MSG_META_END_SELECT handler calls MSG_VIS_RELEASE_GADGET_EXCL,
   so that ends up sending MSG_VIS_LOST_GADGET_EXCLUSIVE anyway.
   The latter is preferable (at least in cases where the object grabbing
   the mouse can get the gadget exclusive), because if the gadget
   exclusive is lost in some other way (like the application exiting or
   something unexpected like that), the mouse will still be released.


Mouse events combined with keypresses.

SDK: ALL_GEOS:PUBLIC
Q. How do I detect when the user is holding the Control key and
   clicking the mouse button at the same time? Also, what about the
   Shift keys?

A. When you receive a MSG_META_START_SELECT, you will get a
   parameter called inputState. The high byte of this word parameter
   contains data indicating the special mode of the mouse click.
   For a normal mouse click, the following bits are set:
     UIFA_SELECT | UIFA_IN

   For a Control-click (holding Control key while clicking mouse):
     UIFA_SELECT | UIFA_PREF_A | UIFA_IN

   For a Shift-click (holding Shift key while clicking mouse):
     UIFA_SELECT | UIFA_CONSTRAIN | UIFA_PREF_B | UIFA_IN

   So, to detect when the user is holding down the Control key and
   clicking the mouse at the same time, do this in your
   MSG_META_START_SELECT method:

     if ( GET_UI_FUNCTIONS_ACTIVE( inputState ) & UIFA_PREF_A ) {
        /* User clicking while pressing Control */
     }

   For detecting when the user is pressing the Shift key and clicking:
     if ( GET_UI_FUNCTIONS_ACTIVE( inputState ) & UIFA_PREF_B ) {
        /* User clicking while holding Shift key. */
     }


Installing files to the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. On the Casio Z-7000, we are having problems with our installation
   program because it seems that directories are "invisible" to
   pcsend until the directory has been "touched" by the user.

A. The problem is not that directories are "invisible" but rather that
   they simply don't exist.

   This is actually a "problem" with drive mapping. You are using
   PCSEND on the B: drive and expecting to see all the directories on
   A: that are mapped properly by GEOS. Since DataLight's ROMDOS
   doesn't do such mapping through our @dirname.000 files, PCSEND
   doesn't either.

   The solution is to create the directory if it does not exist, and
   then copy the file there.


Running the SDK installer.

SDK: ALL_GEOS:PUBLIC
Q. I keep getting an error similar to "error 2249 in script line 789"
   What does this mean and how can I fix it?

A. I don't know specifically what it means, but it's the very message
   that always comes up if you try to install the SDK on a machine
   that is running the original "bad" EMM386.EXE that came with Novell
   DOS 7, or if the machine doesn't have enough memory to run the
   installer (minimum is 520k).


I get 'Error in line 83: code 2247.' when installing SDK.

SDK: ALL_GEOS:PUBLIC
Q. I'm getting an error message when trying to install the SDK software
   on my target machine. The message is: installation script problem -
   "Error in line 83: code 2247." What should I do?

A. Make sure there are no files with filename extensions of .000,
   .001, .002, etc. in the root directory of the target machine. Try
   placing the INSTALL.EXE and TARGET.PVL files in a subdirectory on
   the target (any subdirectory) by changing to that directory and
   running PCCOM from there.


Installing target software more quickly.

SDK: ALL_GEOS:PUBLIC
Q. Is there a way to speed up the installation of the files to my
   target machine?

A. If you're using MS-DOS 6. The Microsoft InterLink Server, a
   LapLink-like utility, is bundled in the MS-DOS 6 upgrade. You simply
   run INTERSVR.EXE on the "host" machine, and add "DEVICE = INTERLNK.EXE"
   to the target machine's CONFIG.SYS. and your host's C: drive is
   suddenly accessible to the target machine as drive F: (or whatever).
   You can then transfer, for example, a three MB TARGET.PVL file
   between the two at 115200 baud in about 7 minutes, instead of
   the usual 40+ minutes at 19200 baud.

   If you're using DR DOS 6, there's a utility called FILELINK that might
   allow faster communication over the serial port on your system.
   Type FILELINK /? at the DR DOS prompt to see the command line switches
   available.


How can I install my application/Bindery book to the OmniGo?

SDK: OMNIGO:PUBLIC
Q. How can I install my application/Bindery book to the OmniGo?

A. Geoworks has created a freeware installer application that you
   can find on the Geoworks web site at:

   http://www.geoworks.com/devrel/download.htm


How to upload apps to the OmniGo for testing.

SDK: OMNIGO:PUBLIC
Q. For testing purposes, how is an application uploaded to the OmniGo?
   Where in OmniGo is the app stored once it's uploaded?

A. The application is stored in the RAM disk. The easiest way to
   upload the application is:

   1. Reboot the OmniGo (shift-on-next keys) to make sure the previous
      version of your app is not running in the background

   2. Run the Transfer application and connect.

   3. Use PCSend (comes with the SDK; it should be in the PCGEOS\BIN
      dir) you will need to set the ptty environment variable to have
      the same baud rate as the OmniGo (either 9600 or 19200). In
      DOS you can do this with the SET command. For example:
    C:\PCGEOS\APPL\SDK_C\MYAPP> set ptty=2,9600
      will tell PCSend to use com2 at 9600 baud. (there's more
      information about pcsend, pcget, and pccom in the tools book.)

   You will need to specify sending the application to the world
   directory otherwise it will end up in the root Geoworks directory
   where HomeScreen can't get to it. You specify the directory like
   this:

    pcsend myapp.geo /d:world

   which will send myapp.geo to the World directory on the OmniGo.


Putting up a 'please wait' dialog.

SDK: ALL_GEOS:PUBLIC
Q. What routines do I use to put up and take down a notice saying
   "please wait"?

A. I assume that in this case you don't want a thread-blocking routine
   such as UserDoDialog(). (I.e. you aren't requesting a response from
   the user, such as through an 'OK' trigger.)

   You can create a GenInteraction (set GII_visibility = GIV_DIALOG and
   GII_attrs = @default | GIA_NOT_USER_INITIATABLE) with a GenGlyph
   child, whose GI_visMoniker is "please wait", and make it a child
   of the GenApplication.  To bring it on-screen, send
   MSG_GEN_INTERACTION_INITIATE to the GenInteraction.  To take it down,
   you can send IC_DISMISS through MSG_GEN_GUP_INTERACTION_COMMAND.

   You probably also want to make the dialog modal.


Replacing the functionality of dialog buttons.

SDK: ALL_GEOS:PUBLIC
Q. For a GenInteraction type organizational, visibility dialog,
   there is an Exit button for the dialog. I would like to replace/extend
   the action of that button. Can I substitute the Exit button in the UI
   with another GenTrigger through a ATTR_GEN_TRIGGER_INTERACTION_COMMAND?
   If so, what? Or can I subclass a message in the GenInteractionClass to
   intercept the message that the trigger is sending or something?

A. ATTR_GEN_TRIGGER_INTERACTION_COMMAND = {IC_EXIT} only works for
   triggers that are in a GIV_POPUP GenInteraction (not GIV_DIALOG).
   Therefore, you should create your own Exit trigger. Use a GenTrigger
   that sends a message to a destination (this constitutes the additional
   functionality), and add to it the GA_SIGNAL_INTERACTION_COMPLETE
   attribute. Put HINT_SEEK_REPLY_BAR on the trigger as well.


How can I reposition a modal dialog box?

SDK: ALL_GEOS:PUBLIC
Q. How can I reposition a modal dialog box?

A. Modal dialog boxes are automatically centered on the screen by the
   specific UI.  This could be overridden using
   HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT or another _WINDOW_ hint.


Adding buttons to DatePicker dialog in OmniGo.

SDK: OMNIGO:PUBLIC
Q. I would like to add a button or two to the DatePicker dialog
   for my own uses. Can I do this without the source code?

A. DatePicker is a GenInteractionClass object. You can add
   children to the DatePicker with MSG_GEN_ADD_CHILD. (Other
   GenInteraction messages should work on it as well.)


Command dialog vs. properties dialog.

SDK: ALL_GEOS:PUBLIC
Q. I have a modal dialog with OK and Cancel triggers, but the OK trigger
   is initially not enabled.

   The OK trigger only becomes enable if you change one of the default
   settings.  How can I force it to start out enabled?

A. Make it a command dialog instead of a properties dialog.


Is there a way to tell when a GenInteraction is dismissed?

SDK: ALL_GEOS:PUBLIC
Q. Is there a way to tell when a GenInteraction is dismissed?

A. Intercept MSG_GEN_GUP_INTERACTION_COMMAND and check that the command
   parameter equals IC_DISMISS.


Keyboard shortcuts won't work but beep instead.

SDK: ALL_GEOS:PUBLIC
Q. The keyboard shortcuts in my program don't work. For instance,
   if I try Ctrl-P, I get a beep instead of the Print panel.

A. To fix this, just add GA_KBD_SEARCH_PATH to the GI_attrs of your
   GenPrimary, and menu groups, such as the File menu. This allows
   GEOS to search those branches of the tree for the keyboard
   accelerator.


Getting the item in a list with the focus.

SDK: ALL_GEOS:PUBLIC
Q. How do I fetch the number of a current item, the one marked with a
   dot line rectangle, in a non-exclusive dynamic list? None of the
   GenItemGroupClass messages seem to get it.

A. The item marked with a "dot line rectangle" is actually the focus item.
   You can use a message to get the current focus item, but this is generally
   a bad idea because the focus may change between message calls. That is,
   the "dot line rectangle" is only an intermediate state, like when you're
   dragging the mouse over a menu before selecting one of the items. It's
   OK for those items to react in some way, but for another object to query
   and then act is asking for timing trouble.

   If you need to act when the dot line rectangle moves to another item,
   the best thing to do is to have the item intercept
   MSG_META_GAINED_FOCUS_EXCL and send some custom notification message to
   the object that's interested in the state.


Ignoring input when a list selection is made.

SDK: ALL_GEOS:PUBLIC
Q. Is it possible to make a GenDynamicList ignore input when a selection
   is made? I tried setting GI_attrs = @default | GA_INITIATES_INPUT_IGNORE
   but it didn't seem to work.

A. That should work. The ignore only lasts for as long as it takes to
   make a trip to the list's output object's event queue and back. The
   exceptions to that rule follow:

   If the GenDynamicList and the GenDynamicList's output object (destination)
   are run by different threads, then GA_INITIATES_INPUT_IGNORE won't work.
   To fix this you need to change the GenDynamicList's destination to be
   some object which is run by the same thread as the GenDynamicList.

   If the GenDynamicList is in a System modal box, it will need
   ATTR_GEN_INTERACTION_ABIDE_BY_INPUT_RESTRICTIONS on it, since modal
   boxes otherwise ignore input restrictions.


Intercepting MSG_META_END_SELECT with a dynamic list object.

SDK: ALL_GEOS:PUBLIC
Q. I've noticed that when I subclass GenDynamicListClass and then try to
   intercept MSG_META_END_SELECT, I don't ever see the message (but I can
   intercept MSG_META_START_SELECT just fine). Any ideas on this one?

A. If you are not calling @callsuper, then you must return MRF_PROCESSED
   (MouseReturnFlag that says this object had processed the mouse
   message). If that is not the problem, then you probably need to grab
   the mouse.


What does MSG_GEN_ITEM_GROUP_SET_MODIFIED_STATE do exactly?

SDK: ALL_GEOS:PUBLIC
Q. I would like clarification on what MSG_GEN_ITEM_GROUP_SET_MODIFIED_STATE
   actually does. My impression is that setting this to TRUE would cause
   the GIGI_applyMsg to get sent out the next time the group gets an apply
   message. Is this true?  Does this cause the STATUS message (if any set)
   to go out as well (I believe not).

A. MSG_GEN_ITEM_GROUP_SET_MODIFIED_STATE:
   Items are normally marked as "not modified" anytime their state is
   set, marked "modified" anytime the user interacts with them, and marked
   "not modified" again on MSG_APPLY. This primitive provides a way to
   control the modified status outside of these events. Items can be
   operated on via this message, even if they are not usable, not enabled,
   or not represented by a GenItem in the GenItemGroup (useful for linked
   GenItemGroups).


Specifying the height or size of a dynamic list object.

SDK: ALL_GEOS:PUBLIC
Q. How can I specify number of items to show in a scrollable GenDynamicList
   or the height of GenDynamicList window (thus specify # of items to show
   indirectly)?

A. You need to use HINT_INITAL_SIZE like this:

   HINT_INITIAL_SIZE = {
       0,
       ( SST_LINES_OF_TEXT | 4 ),
       4
   };

   This will specify that the dynamic list show 4 items. When you change
   the "4" in the second line, be sure to change the "4" in the third
   line as well, since that second 4 tells the geometry manager how
   many items to display.


Having an initial selection in a GenItemGroup.

SDK: ALL_GEOS:PUBLIC
Q. When I set the three GenItemGoups to GIGBT_EXCLUSIVE it starts
   off with none of the three selected. I can select any (or all)
   of the three but I can never get one deselected.

   When they are set GIGBT_NON_EXCLUSIVE it starts off with none
   selected again. I can select any (or all) of the three and I can
   unselect them too.

   How can I make sure one, and only one, is selected?

A. What you describe is the correct default behavior.

   If you want an initial selection, add GIGI_selection = @Choice1Item
   in your first GenItemGroup.


Linking GenItemGroups using ATTR_GEN_ITEM_GROUP_LINK.

SDK: ALL_GEOS:PUBLIC
Q. Are linked GenItemGroups currently supported? I tried without
   success to use this feature. The documentation states that a
   selection is exclusive across all the linked groups, but that's
   no how it worked for me.

A. Linked Gen Item groups are supported (use ATTR_GEN_ITEM_GROUP_LINK),
   but you have to do most of the work yourself.

   To get them to work, have each linked GenItemGroup send out the same
   status message (ATTR_GEN_ITEM_GROUP_STATUS_MESSAGE). In the handler
   for this message, find out what item has been selected and broadcast
   that selection (with MSG_GEN_ITEM_GROUP_SET_SINGLE_SELECTION) to each
   item group. Since each Item in all the Item Groups should have a
   unique identifier, only one item will be selected.


Keycodes on the OmniGo.

SDK: OMNIGO:PUBLIC
Q. What key codes are used on the OmniGo for the Next/Prev keys?
   VC_NEXT and VC_PREVIOUS are the codes for Page Up / Page Dn.

A. VC_NEXT_BUTTON and VC_PREV_BUTTON map to Next/Prev keys.


Avoiding the floating keyboard.

SDK: ALL_GEOS:PUBLIC
Q. What's the HINT/ATTR/inst-var to avoid bringing up the floating
   keyboard?

A. ATTR_GEN_WINDOW_KBD_OVERRIDE: you can set it in the GenApplication
   or popup/dialog GenInteraction. The three settings for this attr
   are:

        KO_NO_KEYBOARD - no floating keyboard will be made available
        for any of the children in this window.

        KO_KEYBOARD_REQUIRED - forces the a floating keyboard to be
        brought up whenever this window comes on-screen.

    KO_KEYBOARD_EMBEDDED - means that the application is providing
        a keyboard, so no floating keyboard is needed.


Support for new floating keyboards.

SDK: ALL_GEOS:PUBLIC
Q. I remember hearing earlier about Geoworks desire to allow for new
   on-screen keyboards for pen based systems.

A. Yes, there is support for this. An application needs to supply
   its own PenInputControl (a child of the application object), put
   it on MGCNLT_ACTIVE_LIST (GCN list), and add
   ATTR_GEN_PEN_INPUT_CONTROL_IS_FLOATING_KEYBOARD and
   HINT_DONT_KEEP_INITIALLY_ONSCREEN to it (all of this can be done
   statically). GII_visibility should be GIV_DIALOG and
   GII_attrs = GIA_NOT_USER_INITIATABLE.

   The optr of the object should be stored in
   ATTR_GEN_APPLICATION_KBD_OBJ.

   The app can use ATTR_GEN_PEN_INPUT_CONTROL_CUSTOM_CHAR_TABLE_DATA
   to specify a app-custom keyboard layout.


How do I access a dynamically loaded library?

SDK: ALL_GEOS:PUBLIC
Q. How do I use a GEOS library that was loaded dynamically with
   GeodeUseLibrary() rather than declared in the .GP file during
   compilation time?

A. Accessing library routines is rather confusing until it is explained.
   Here's a short description.

   Using Dynamically Loaded Libraries

   Calling routines from dynamically loaded libraries is quite easy. The
   basics are all there is to it, so once you learn the basics, you've
   learned to use libraries. The three main steps are:
   1. call GeodeUseLibrary to load the library and get its handle
   2. access the library routines
   3. release the library with GeodeFreeLibrary.

   Setup

   These two lines should be added to your .GOC file:
   #include
   @include  /* the header file for your library, if it exists */

   In your .GP file, add the line:
   library mylib noload   # "mylib" is the name of your library

   GeodeUseLibrary

   Pass the (DOS style) name of the library, the major and minor protocol
   numbers of that library, and a pointer to a GeodeLoadError structure.

   Calling the library routines

   ProcGetLibraryEntry
   ProcCallFixedOrMovable_cdecl or ProcCallFixedOrMovable_pascal

   To access the routines in the library, you must first get the pointer
   to the routine using ProcGetLibraryEntryEntry.  Then call the routine
   with one of the two ProcCallFixedOrMovable_...() routines.

   You can determine the entryNumber (second parameter of ProcGetLibraryEntry)
   from the "export" lines in the library's .GP file.  The first line
   corresponds to zero, with the values increasing by one for each
   successive line. If the creator of the library has #defined these values
   in the library's .H (or .GOH) file, you could include this in your
   application's source file and use these definitions for the entryNumber
   parameter.

   GeodeFreeLibrary

   If you dynamically load the library, then it is your responsibility to
   free the library.  This is done simply by calling GeodeFreeLibrary().

   Example

     #define MY_LIB_ROUTINE_A  0
     #define MY_LIB_ROUTINE_B  1
     #define MY_LIB_ROUTINE_C  2
     #define MY_LIB_ROUTINE_D  3

     #if ERROR_CHECK
     static char *myLibName = "mylibec.geo";
     #else
     static char *myLibName = "mylib.geo";
     #endif

     GeodeHandle  myLibHandle;
     GeodeLoadError err;
     dword  returnValue;

     /* First store the current setting of the standard path and then set it
     * to the system directory, where all the library geodes should be. */
     FilePushDir();
     FileSetStandardPath(SP_SYSTEM);

     (myLibHandle = GeodeUseLibrary(myLibName, 0, 0, &err);

     if(myLibHandle != NullHandle)
     {
     returnValue = ProcCallFixedOrMovable_cdecl(
     ProcGetLibraryEntry(myLibHandle, MY_LIB_ROUTINE_A),
     /* library routine parameters go here */);
     }

     /* Restore the previous standard path setting. */
     FilePopDir();

   Additional Information

   GeodeLoadErrors
     GLE_PROTOCOL_IMPORTER_TOO_RECENT
     GLE_PROTOCOL_IMPORTER_TOO_OLD
     GLE_FILE_NOT_FOUND
     GLE_LIBRARY_NOT_FOUND
     GLE_FILE_READ_ERROR
     GLE_NOT_GEOS_FILE
     GLE_NOT_GEOS_EXECUTABLE_FILE
     GLE_ATTRIBUTE_MISMATCH
     GLE_MEMORY_ALLOCATION_ERROR
     GLE_NOT_MULTI_LAUNCHABLE
     GLE_LIBRARY_PROTOCOL_ERROR
     GLE_LIBRARY_LOAD_ERROR
     GLE_DRIVER_INIT_ERROR
     GLE_LIBRARY_INIT_ERROR
     GLE_DISK_TOO_FULL
     GLE_FIELD_DETACHING
     GLE_INSUFFICIENT_HEAP_SPACE


Localizing an application.

SDK: ALL_GEOS:PUBLIC
Q. What must I do to make my application localizable?

A. You should read Chapter 8 "Localization" of the Concepts book.
   This chapter covers many of the concepts and routines needed to
   make your application easily localizable.

   In a nutshell, here's what you need to consider:
   1. Put localizable strings in @chunks so you can use ResEdit to
      modify the strings.
   2. Use Local...() routines for formatting strings (for date,
      currency, measurement, etc.) and other string manipulation.
   3. Register for notification of changes to user settings.  (see
      following question.)


Changes in date/time format.

SDK: ALL_GEOS:PUBLIC
Q. How can I receive notification of changes in date/time format or
   other formatting that the user can change?

A. Put yourself on the GCNSLT_NOTIFY_INIT_FILE_CHANGE gcnlist and watch
   for MSG_META_NOTIFY(MANUFACTURER_ID_GEOWORKS,GWNT_INIT_FILE_CHANGE).
   The parameter "data" will be the InitFileEntry that changed.  Here
   are the possible values of "data":

       IFE_DATE_TIME_FORMAT
       IFE_NUMBER_FORMAT
       IFE_CURRENCY_FORMAT
       IFE_PUNCTUATION
       IFE_OWNER_INFO
       IFE_SYSTEM_SOUND
       IFE_INK_THICKNESS


How to create the .vm file for localizing.

SDK: ALL_GEOS:PUBLIC
Q. How do I generate the .VM file required as input to the Resource
   Editor?

A. There are three ways you can generate the .vm file.

    1. pmake full
    2. pmake .vm
    3. loc -o .vm *.rsc


How to display floating point values.

SDK: ALL_GEOS:PUBLIC
Q. How does one display a floating point value in GOC?  I tried
   sprintf( statusString, "f = %f", myFloat ), but it evaluates to
   statusString containing "f = X" (same with %F, %E, %e, %g).

A. Use FloatFloatToAscii. The AnsiC lib does not depend on the
   math library and thus sprintf can't deal with GEOS floats.


How would you convert a DWFixed into a WWFixed?

SDK: ALL_GEOS:PUBLIC
Q. How would you convert a DWFixed into a WWFixed in C?

A. Here is an example: wwf is a variable of WWFixed and dwf is a
   variable of type DWFixed.
    wwf.WWF_frac = dwf_WWF.frac;
    wwf.WWF_int = (word)dwf_WWF.int;


Calling C functions using function pointers.

SDK: ALL_GEOS:PUBLIC
Q. I am having difficulty using far pointers to functions in PCGEOS.
   For example if a have a function with the prototype:

        void far _pascal MyFoo( int bogus1, int bogus2 );

   and a function pointer declared as:

        void (far _pascal * YourFoo)( int, int );

   the following assignment does not work correctly:

        YourFoo = MyFoo;

A. Since GEOS swaps memory around, your function pointer is actually
   a virtual pointer. You need to lock down the block that contains
   the routine (MyFoo) before making the function call. You can do
   this in one of two ways:

        YourFoo = MemLockFixedOrMovable( MyFoo );
        (*YourFoo)( bog1, bog2 );
        MemUnlockFixedOrMovable( MyFoo );

   or

    YourFoo = MyFoo;
    ProcCallFixedOrMovable_pascal( bog2, bog1, YourFoo );
    /* note that parameters are in reverse order */


Do chunk arrays have to be in LMem blocks?

SDK: ALL_GEOS:PUBLIC
Q. Do chunk arrays have to be in LMem blocks?

A. ChunkArrayCreate calls LMemAlloc, so yes, chunk arrays do have
   to be in LMem blocks.


How is the memory used on the OmniGo?

SDK: OMNIGO:PUBLIC
Q. How big is the RAM disk on the OmniGo? How big is the heap?
   Don't they both have to add up to 1M?  I have a real live OmniGo
   in my hands, and Transfer says "35Kb used, 373Kb free".  This
   adds up to 408K.  Where's the missing 168Kb?

A. In the Transfer application, "Memory available" refers to RAM disk
   space, since available heapspace is an elusive and generally
   worthless measurement (what with fragmentation, max available block
   size, etc.)

   On the OmniGo, the 1 Meg of RAM is divided as follows:

    Video Memory		32k
    Heap Space		576k
    RAM Disk Space		416k
            Total	1024k

   As the RAM disk is a FAT file system, a certain percentage of
   the memory must be allocated to the FAT itself.  The system
   also uses part of the RAM disk for the INI-file, clipboard file,
   etc.  All those use about 8Kb, which leaves 408Kb for general
   usage.  This is why in Transfer, you only see a total available
   space of 408Kb.


Are ObjChunkFlags kept with chunks in LMem blocks?

SDK: ALL_GEOS:PUBLIC
Q. Are ObjChunkFlags also kept with chunks in general LMem
   blocks (non-obj)?

A. ObjChunkFlags are used only in Object Blocks. Chunks in
   LMem Blocks do not use these flags.


Differentiating static vs. dynamic LMem blocks.

SDK: ALL_GEOS:PUBLIC
Q. Is there a way to tell whether a chunk in an LMem block was created
   statically (defined in a resource), or dynamically at runtime?

A. You can use OCF_IN_RESOURCE for this. But, you will first have
   to set LMF_HAS_FLAGS (LocalMemoryFlags) when you create the
   block so that the kernel will expect ObjChunkFlags to be in
   the first chunk. (Esp currently won't create a flags chunk for
   you, so you'd have to do that yourself, if defining the resource
   statically, nor is there a way to tell UIC that you want the
   resource to have flags, except to make it an object resource).
   The kernel looks only for the LMF_HAS_FLAGS bit to decide whether
   to treat the first chunk in the block as a flags chunk.


Is it OK to use LMemContract on Object blocks?

SDK: ALL_GEOS:PUBLIC
Q. Is it OK to use LMemContract on Object blocks?

A. Yes. An Object Block is a LMem of type LMEM_TYPE_OBJ_BLOCK, so
   you can use LMem.. routines on it.


What is a MemHandle?

SDK: ALL_GEOS:PUBLIC
Q. I used GrGetBitmap to save the background, but it returns a MemHandle.
   Where can I find the definition for MemHandle. And how to make use
   of the information returned by XYSize?

A. GrGetBitmap returns a MemHandle to a newly allocated memory block
   containing the bitmap. The memory handle is an indirect reference
   to that memory block.

   A MemHandle is a very important type in GEOS; you really need to
   understand it to effectively develop GEOS applications. At a very
   basic level, a MemHandle is just a 16-bit value used to locate a
   memory block. Look in chapter 15 of the Concepts manual to get an
   in-depth discussion of memory management. To access the memory block,
   use MemLock(). This will restrict the block from being moved around
   in memory and return a pointer to the beginning of the block/bitmap.
   When you are finished accessing the block, use MemUnlock to allow
   the block to be movable again (the pointer to the block will now be
   invalid). When you have no more use for the memory block, will have
   to free the block with MemFree().


Will MemAlloc return a block larger than what's currently free?

SDK: ALL_GEOS:PUBLIC
Q. Will MemAlloc ever return a block bigger than
   MemGetInfo( SGIT_LARGEST_FREE_BLOCK )?

A. Yes. MemAlloc compacts the heap if there is not a big enough block.


Will Mem.. routines move locked blocks?

SDK: ALL_GEOS:PUBLIC
Q. Is it possible that MemAlloc(), MemLock() or MemUnlock() routine
   moves an object meaning that I have to dereference pself after
   the call like I do after @send, @call or ObjInstantiate() ?

A. No. MemAlloc() and MemLock() can cause unlocked blocks to move on the
   global heap, but not locked blocks. If an object is executing code
   (e.g. one of its handlers was called), then the object's block must
   be locked on the global heap, so MemLock() and MemAlloc() will not
   cause the object block to move.


How to free an object block run by UI thread.

SDK: ALL_GEOS:PUBLIC
Q. How does one go about freeing an object block from the process thread
   when the object block is run by, say, the UI thread? ObjFreeObjBlock
   crashes when I try to do this.

A. Send MSG_META_BLOCK_FREE to an object in that block.


When GEOS allocates dgroups, where does it put them?

SDK: ALL_GEOS:PUBLIC
Q. When GEOS allocates dgroups, where does it put them?

A. dgroup is allocated as a fixed memory block, so it is allocated
   at the bottom end of the heap (if possible).


Calculating the exact size of an LMem block.

SDK: ALL_GEOS:PUBLIC
Q. When I type "lhwalk" for an object block of an application, Swat
   tells me the size is 4524 bytes. When I add up the sizes of the
   objects & chunks within the block, however, I get 4269 bytes.

   Swat also tells me the number of handles for this block is 40, so
   I figure another 80 bytes for the chunk handle table. Add in another
   16 bytes for the LMemBlockHeader and the total is 4365 bytes.

   Additionally, Swat says there is no free space, and it shows no free
   chunks in the lhwalk. So why the discrepancy (4524 vs 4365)?
   What am I doing wrong?

A. What you're forgetting is the overhead in chunk sizes.

   Remember that chunks are padded to be dword-aligned. Also, the
   size of the chunk is stored in the word preceding the chunk data.
   So, each chunk has different overhead: 2 to 5 bytes for each chunk.

   Here's how to calculate the exact LMem block size:

   LMBH_blockSize = chunk sizes + free space + LMem header +
                    Chunk Handle table size + chunk size overhead

                  = sum( chunk sizes ) + LMBH_totalFree + LMBH_offset +
                    (LMBH_nHandles x 2) + sum( overhead )


Moving things out of dgroup.

SDK: ALL_GEOS:PUBLIC
Q. I've created numerous subclasses in my application from the GEOS
   superclasses, adding methods and instance data. I've tried to keep
   my global variables to nil. I know that my subclass templates are
   stored in the dgroup.

   One problem: my compiles are indicating that my dgroup is getting
   to be inefficiently large (>1KB). I'm not sure as to what to do to
   decrease the size of my dgroup. Ideas?

A. It turns out that you can move your class definitions to their own
   resource. All the classes must still be in the same (fixed) block,
   but at least the stack (2kb) won't be in that block as well.

   To do this, simply define your classes as usual in your .goc file,
   but make the following change in your .gp file:

   resource MYCLASSSTRUCTURES fixed read-only shared

   (If the app is named Hello, DON'T name your new resource
   HELLOCLASSSTRUCTURES, since that's the default name -- choose
   something else, as done above.)

   You'll also have to create a local.mk file, to customize the
   makefile. It should look exactly as follows:

   #
   # -C flag puts class tables in their own resource,
   # instead of dgroup.
   #
   GOCFLAGS        += -CMyClassStructures
   #
   # Include the system makefile.
   #
   #include <$(SYSMAKEFILE)>

   Note: The Swat command "classes" will no longer work, since the
   command looks in dgroup to find your class definitions. So you'll
   have to set breakpoints in your methods using alternate means
   (viewing the source code and using the mouse to set the breakpoint;
   or using "stop at :" syntax.

   One slight benefit above that of reducing the size of dgroup is
   that if your app is ever made XIP, this is one of the steps you'd
   have to do.


How to make a subclassed UI object grab the focus.

SDK: ALL_GEOS:PUBLIC
Q. I have a bunch of custom objects inside a GenInteraction. The problem
   is I cannot select them via the normal focus navigation methods
   (e.g. tab key, cursor keys). The focus skips straight over my custom
   objects and only highlights on the system UI objects.

A. Intercept MSG_SPEC_NAVIGATION_QUERY for your subclassed object and
   do this:

/*********************************************************************
 *              MSG_SPEC_NAVIGATION_QUERY
 *********************************************************************
 * SYNOPSIS:     We've been asked by the system whether we are capable
 *               of receiving the focus or not.
 * PARAMETERS:   NavigationQueryParams * retValue
 *               optr                    queryOrigin
 *               NavigationFlags         navFlags
 * RETURNS:      Boolean - TRUE if this is the object to get the focus
 * SIDE EFFECTS: none
 * STRATEGY:     Prepare the parameters for MSG_SPEC_NAVIATE_COMMON
 *               (checking to make sure we are a usable object) and
 *               then call the common navigation method to do the
 *               real work. Stuff the return values into retVal and
 *               return the true/false flag to the caller.
 ********************************************************************/
@method SomeSubClass, MSG_SPEC_NAVIGATION_QUERY
{
      /*
       * params - spec navigation parameters
       * reply  - the reply we will return
       */
    NavigateCommonParams params;
    Boolean              reply;

    params.NCP_object = queryOrigin;
    params.NCP_navFlags = navFlags;
    if ( @call self::MSG_GEN_GET_USABLE() ) {
        params.NCP_navCommonFlags = NCF_IS_FOCUSABLE;
    }
    else {
        params.NCP_navCommonFlags = 0;
    }
    params.NCP_genPart = OptrToChunk( oself );
    reply = @call self::MSG_SPEC_NAVIGATE_COMMON( ¶ms );
    retValue->NQP_navFlags = params.NCP_navFlags;
    retValue->NQP_backtrackFlag = params.NCP_backtrackFlag;
    retValue->NQP_nextObject = params.NCP_object;
    return( reply );
} /* MSG_SPEC_NAVIGATION_QUERY */


TextLargeRunArrayHeader defined incorrectly.

SDK: ALL_GEOS:PUBLIC
TextLargeRunArrayHeader is improperly defined in
CInclude/Objects/vTextC.goh. Here is the proper definition:

    typedef struct {
        HugeArrayDirectory  TLRAH_meta;
        VMBlockHandle       TLRAH_elementVMBlock;
    } TextLargeRunArrayHeader1;


How is text in a VisLargeText stored?

SDK: ALL_GEOS:PUBLIC
Q. If I read a large text file into a single region of a VisLargeText
   object, will all of the text be in memory at once, or is the text object
   smart enough to keep some text on "disk" instead of on the heap?

A. The text object takes care of intelligently managing the HugeArray in
   which the text is stored, so that only as much text is in memory as is
   needed. The fact that the text is all within the same region should
   make no difference.


How to localize with the original source code.

SDK: ALL_GEOS:PUBLIC
If you have the SDK, you can run LOC.EXE in a directory by itself and it will
create a LOC.VM file which contains contains the filename UNKNOWN.

Copy that LOC.VM file into a directory along with the Geode you wish to
localize. Use GeoManager to rename the Geode UNKNOWN (its DOS name will then
be UNKNOWN.000). Now run ResEdit, click New, and choose LOC.VM.

You won't get the original programmer's labels or localization notes, and
there may be some other limitations, but you will be able to edit each block
in each resource and generate a new geode.


My messages miss the object I was aiming for.

SDK: ALL_GEOS:PUBLIC
Q. When I call MSG_SUCH_AND_SUCH, why does it go off into space
   rather than call the correct source code?

A. You more than likely sent it to the wrong object.  Make sure that
   it is being sent to an object that it can handle it.


Static object trees spread across multiple source files.

SDK: ALL_GEOS:PUBLIC
Q. In Goc I have a primary and one of it's children is defined in a
   separate file. When I launch the program, that child has no link
   (GI_link = null). This hoses the program when one of it's siblings
   tries to find their parent. Is there something special I have to
   do to make this work?

A. Goc will only create links between statically declared objects if
   they are within the same source file. So, you can either put all
   of the objects that are in your generic object tree into the same
   source file, or you can call MSG_GEN_ADD_CHILD to dynamically add
   the child when you open the application.


UI object trees crossing thread boundaries.

SDK: ALL_GEOS:PUBLIC
Q. I dynamically instantiate the generic objects in an object block
   owned by the process thread. I would like to display those objects
   and thus I need to attach them to the UI tree. However, the UI tree
   is owned by the ui-thread. Simply attaching these objects to the
   tree causes the error "OBJ_LOCK_OBJ_BLOCK_BY_WRONG_THREAD".

A. You cannot have normal generic objects under your GenApplication
   running in a different thread from the GenApplication objects and
   the objects underneath it. The only place where a thread boundary
   is allowed is the GenView/Content. The right thing to do is to
   change the owning thread of your object block to the ui-thread.

   Another way of overcoming this is to make the app single threaded,
   so everything is in the same thread.


Causing an application to quit.

SDK: ALL_GEOS:PUBLIC
Q. When I quit my demo application by sending MSG_META_QUIT to my
   process object, the app exits. After returning to GeoManager,
   however, the system crashes. What did I do?

A. You should be sending MSG_META_QUIT to your Application object,
   not your process object.

   If you send MSG_META_QUIT to the process object you will get a
   UI_PROCESS_INVALID_QUIT_LEVEL error. This occurs because you aren't
   passing a valid QuitLevel in register DX. Since the application object
   is designed to properly handle MSG_META_QUIT, you should avoid ever
   sending MSG_META_QUIT to the process object.

   See the MSG_META_QUIT comments in Include\metaC.def for more detail
   about the operation of MSG_META_QUIT.


Sending a message to the current document object.

SDK: ALL_GEOS:PUBLIC
Q. How does one interact with the immediate document (I guess its
   called the focus) of a multiple document group?

A. To send messages along the focus hierarchy, @record the message and
   then send it using MSG_META_SEND_CLASSED_EVENT passing the travel
   option TO_FOCUS.


Sending notification messages to controllers.

SDK: ALL_GEOS:PUBLIC
Q. I am notifying a controller of a change using a notification. I use
   MSG_META_NOTIFY_WITH_DATA_BLOCK where the block consists of only a
   handle to a memory block containing strings. The handle to the memory
   block containing is the same for each notification. I have noticed
   that after the first notification none of them seem to reach the
   controllers. I believe notifications are cached and duplicates
   discarded although I couldn't confirm this with the manual. Is this
   true? What is the typical way of sending identical notifications to
   a controller so that the controllers get each one?

A. Duplicate status events are ignored. If they are identical, there
   is no need to send multiple ones. If they are not identical, you
   should generate unique notifications.

   By the way, you do not need to use MSG_META_NOTIFY_WITH_DATA_BLOCK directly.
   The normal way controllers get notifications is by adding themselves
   to the necessary GCN list. When a change occurs, the object in which
   the change occurred should then call GCNListSend or send
   MSG_META_GCN_LIST_SEND. The system will then send the
   MSG_META_NOTIFY_WITH_DATA_BLOCK to the objects on the GCN list.


How can I tell if the system is shutting down?

SDK: ALL_GEOS:PUBLIC
Q. I would like to save some data in the state file during system
   shutdown (like Exit to DOS). What messages and parameters in
   messages are special so that I can tell GEOS is being shut down
   instead of application exits normally? I don't want the app to
   spend time saving data for restoring state when the app exits
   normally.

A. In your application's  message handler for
   MSG_GEN_PROCESS_CLOSE_APPLICATION you can @call
   MSG_GEN_APPLICATION_GET_STATE to the application object.
   Test ApplicationStates for AS_DETACHING.


How to destroy objects created with ObjInstaniate.

SDK: ALL_GEOS:PUBLIC
Q. I am using ObjInstaniate to create objects. Once I no longer
   need them, how do I destroy them?

A. For Gen objects: MSG_GEN_DESTROY
   For Vis objects: MSG_VIS_DESTROY
   If your object is not a Gen or Vis subclass: MSG_META_OBJ_FREE


Freeing duplicate object resources.

SDK: ALL_GEOS:PUBLIC
Q. What is the technical reason for why ObjFreeObjBlock cannot be
   used on duplicated resources (and ObjFreeDuplicate must be used
   instead)?

A. ObjFreeObjBlock is a higher-level routine -- it performs various
   queue-flushing operations, and eventually calls ObjFreeDuplicate
   (if the block is a duplicate block). Thus you can use ObjFreeObjBlock
   in place of ObjFreeDuplicate. Another option is to send
   MSG_META_BLOCK_FREE to an object in the block.


I get a BAD_DS error in Swat.

SDK: ALL_GEOS:PUBLIC
Q. I get a BAD_DS error in Swat, and I think it's related to this
   code:

     {
         ...
         textOD = GeodeGetOptrNS( @FMVolumePathText );
         @send textOD::MSG_VIS_TEXT_REPLACE_ALL_PTR(
             pathBuffer, LocalStringLength( pathBuffer ) );
         MemFree( pathBufferHandle );
     }

A. The problem here is that the block you're using to send the
   string in is being freed before the text object gets a chance to
   see it. If you change the @send to an @call, the routine will
   work, since the call will be blocked until the text object is
   done with the memory block. After the text object is done, then
   your routine will continue with the next line of code, namely
   the MemFree.


I get an ILLEGAL_HANDLE error when referring to objects.

SDK: ALL_GEOS:PUBLIC
Q. I get this error in my program:

     ILLEGAL_HANDLE

   and it seems to be associated with this line:

     @send MyPrimary::MSG_META_DO_STUFF( @MyObject );

   This code is in the primary.goc file and "MyObject" is defined in
   appUI.goc file.

A. The problem is with multi-source files you can't refer to
   objects in another source file just by their name. You have to
   use the function GeodeGetOptrNS to get a valid optr. Here is
   how to fix that line:

     optr primary;

     primary = GeodeGetOptrNS( @MyPrimary );
     @send primary::MSG_META_DO_STUFF( GeodeGetOptrNS( @MyObject ));

   You'll also have to make the program multi-launchable. Take out
   the "single" in the type line of your .GP file.


Can I remove messages from the thread queue?

SDK: ALL_GEOS:PUBLIC
Q. Does GEOS support removing messages from a message queue? And if
   so where should I look to learn how to do it?

A. No, unless you are willing to manipulate the queue data structure
   yourself.

   The best you can do is to use MF_CUSTOM in ObjMessage, then in your
   callback change HE_method of any unwanted event to MSG_META_NULL.
   This way the original message is wiped out, though the event handle
   is still allocated until it is dispatched.

   Note that this is only possible in assembly.


Size and format of OmniGo icons on Homescreen.

SDK: OMNIGO:PUBLIC
Q. What is the correct size and format (squashed, tiny, etc...)
   for an OmniGo icon?

A. The icon size is tiny and 18x18 pixels. You can see an example
   of icons in SDK_Omni\OmniGoUI\Art\omnigoui.goh.


When to free a dynamic visMoniker on a Vis object.

SDK: ALL_GEOS:PUBLIC
Q. In a visual gadget I am calling self::MSG_VIS_CREATE_VIS_MONIKER
   to create a visual moniker chunk from a char*. I want the object
   to clear the chunk containing the moniker from memory when it
   receives MSG_VIS_DESTROY. Where is the best place to do this?

A. MSG_META_FINAL_OBJ_FREE is the preferred solution, but it would
   probably be okay earlier on too.


Declaring visMonikers in separate resources.

SDK: ALL_GEOS:PUBLIC
Q. We have a resource which is 10K. It is a dialog that includes
   five 64x64 graphic monikers assigned to triggers. Since we were
   told that resource size over 4K can be a potential problem, I am
   wondering if we have to split this resource. If so, how can one
   move a GI_visMoniker into a different resource?

A. A VisMoniker or VisMonikerList must be in the same resource as
   the object as only the chunk handle of the moniker or moniker list
   is stored with the object.

   A moniker list stores optrs to its monikers, so the vis monikers
   can be in a different resource from the moniker list (and the object
   that uses that moniker list).

   You should be able to put the monikers into the new resource in
   whatever way you are currently declaring them.


How to get mono-spaced font for visMonikers.

SDK: ALL_GEOS:PUBLIC
Q. Is there a way to force a fixed space font for moniker text?

A. You can set up the visMoniker with a GString that sets the font,
   however it is easier to set the font in the Object that will be
   displaying the moniker. You could use MSG_VIS_TEXT_SET_FONT_ID
   for most text objects. (You could also use MSG_VIS_TEXT_SET_CHAR_ATTR
   for setting multiple attributes.)


What syntax should I use for MSG_GEN_RELOC_MONIKER_LIST?

SDK: ALL_GEOS:PUBLIC
Q. What syntax should I use for MSG_GEN_RELOC_MONIKER_LIST? And do
   I need to declare the monikers as @reloc in addition to using
   MSG_GEN_RELOC_MONIKER_LIST?

A. @send self::MSG_GEN_RELOC_MONIKER_LIST( ConstructOptr(
       OptrToHandle( oself ), pself->FTI_altMoniker ), 0 );

   And no, do not use @reloc.

   There is some additional complexity if those moniker lists are to
   be saved to state, because you'll also need to unrelocate at that
   time. I advise marking them 'ignoreDirty'. Note that you can
   only relocate once, not each time you set the moniker.


How to create notes file on N9000.

SDK: N9000C:PUBLIC
Q. How do I create a notes file on the N9000 and store data in it?

A. To create a Notes file and store text in it:

   * Create an empty foam document file using FoamDocCreate.

   * Open the file using FoamDocOpen.

   * Initialize the conversion by calling FoamDocConvertFromDosInit.
     This function will create a temporary text object that you
     append text to. You can use regular text object messages like
     MSG_VIS_TEXT_APPEND_PTR.

   * When you are done appending text to the temporary text object
     call FoamDocConvertFromDosDone passing the file handle of your
     new foam document. The function will create text transfer items
     from the text object and store them in the foam document file.

   After this the new foam document can be viewed and edited by NoteBook.


How does FDocumentDir use the .INI docPath settings?

SDK: N9000C:PUBLIC
Q. How does FDocumentDir use the .INI docPath settings?

A. If an application wants to store its documents in its own
   subdirectory below the DOCUMENT directory (as many of the
   Nokia applications do), it can do this with FoamSetDocumentDir.
   First, it must add the subdirectory name to the appDocPaths
   category in the ini file, so the system knows the subdirectory
   name.

   Here are the default keys within the appDocPaths category (and
   their corresponding FDocumentDir enum):

     [appDocPaths]
     lastDocPath = 8
     docPath1 = Own texts          ; FDD_CREATED_TEXTS
     docPath2 = Received faxes     ; FDD_RECEIVED_FAXES
     docPath3 = Received messages  ; FDD_RECEIVED_SM
     docPath4 = Received email     ; FDD_RECEIVED_MAIL
     docPath5 = Standard messages  ; FDD_MESSAGE_TEMPLATES
     docPath6 = Business cards     ; FDD_BUSINESS_CARDS
     docPath7 = Downloaded files   ; FDD_DOWNLOADED_FILES
     docPath8 = WWWHotlist         ; FDD_WWW_HOTLIST

   To add your own path to this list, first your need to get the
   "lastDocPath" so you know the path entry number that your
   application will use. You should not assume the "docPath9"
   will be available because another application could be using
   it. The best thing to do is store your path number in an
   application specific ini category, that way your application
   can use whatever path number is available and it will also be
   able to determine if the ini file has been reset (if the user
   for some reason resets the device to its factory defaults).

   You can use InitFileReadInteger() to get lastDocPath number;
   increment the returned number to get the docPath number that
   you should use; then write the new number to lastDocPath
   with InitFileWriteInteger(). Remember to save the number to
   your application's ini file category. Finally, add your
   docPath to the list by creating a key that is "docPath" plus
   the ASCII value for your path number and write it to the ini
   file with InitFileWriteString. Lastly, you need to call
   InitFileCommit() so all your ini file modification are actually
   changed in the ini file.

   Once you've done this, you can now use FoamPathMake() or
   FoamPathMakeSP() to create the FoamPathHandle for the new
   directory. With this new handle you can use it just like a
   FDocumentDir enum in any of the usual foam library routines.


I keep getting 'Do you want to abort? [ynp]' in Swat.

SDK: N9000C:PUBLIC
Q. Sometimes an app trashes the mailbox, so one needs to remove
   the mbox_adm.000 file from Privdata\Mailbox.

   When you restart Swat, you go through a long loop of patients:

     mltd, faxfile, viewer, faxsendt, viewer, smsed, smbcard, smsend,
     smtd, netutils, irlmp, config, spooltd, netutils, socket, mlms,
     mlmi

   Then you get:

     Do you want to abort? [ynp]
     Returning to top level
     (mailbox:0) 6 => c

   Back to the long loop of patients:

     mltd, faxfile, viewer, faxsendt, viewer, smsed, smbcard, smsend,
     smtd, netutils, irlamp, config, spooltd, netutils, socket, mlms,
     mlmi

   Then, again:

     Do you want to abort? [ynp]

   So what's wrong and what can I do about it?

A. The problem is caused by the mlmi.sym file, which has a bug in it.
   Look on the Dev-Rel Downloads page for a fixed version of this file:

   http://www.geoworks.com/DevRel/SelfHelp/Download/index.html


How is memory used on the Nokia 9000 Communicator?

SDK: N9000C:PUBLIC
Q. How is memory used on the Nokia 9000 Communicator?

A. The Nokia 9000 Communicator has 8 megabytes of Flash RAM in it.
   It is partitioned as follows:

     4 MB for "ROM" for the OS and applications
     2 MB for application execution and heap space
     2 MB for user data storage (essentially a RAM disk)


Getting the little icon in OmniGo slots.

SDK: OMNIGO:PUBLIC
Q. I put a "Note" button in my OmniGo function bar area. I want it to
   look like all the other Note buttons--its moniker should be "Note#"
   where '#' is a graphic of a little piece of note paper. How can I
   display that graphics?

A. This has to be done in assembly. There is an example of this in
   SDK_Omni\DocUI


Who does the underlining of bitmap fonts?

SDK: ALL_GEOS:PUBLIC
When using a bitmapped font with the underline attribute set,
the underlining is not part of the bitmap. The system draws
the underline seperately.


Making window movable/resizable.

SDK: OMNIGO:PUBLIC
Q. I cannot get the GenPrimary to be a floating window (like you can in
   Ensemble or like Clip & Go). How can I do this?

A. On the OmniGo, GenPrimary is forced to be full-screen no matter
   what. To get around this, you will have to make a GenInteraction
   (GIV_DIALOG) and use that as the floating window.

   If you wish to make the GenPrimary hidden so your application is only
   represented by a floating window, attach (GI_comp) the dialog box to
   the GenApplication object. In MSG_GEN_PROCESS_OPEN_APPLICATION, send
   MSG_GEN_INTERACTION_INITIATE to the dialog box (and make the dialog
   box GIA_NOT_USER_INITIATABLE).


PCMCIA card not recognized when OmniGo reboots.

SDK: OMNIGO:PUBLIC
Q. I noticed that if I reboot the OmniGo with a PCMCIA card plugged
   in (even an ordinary serial card), the OmniGo claims that the card
   I inserted is unreadable or maybe write protected. But if I then
   powercycle the unit, it does not complain.

A. The OmniGo cannot recognize a card if you reboot with a PCMCIA
   card plugged in. You can't insert a card until after rebooting,
   and after you've done the pen calibration screen, then turning
   the unit off. The OmniGo is just not able to recognize any cards
   until after the pen calibration has completed--that's the way the
   software was built.


PCMCIA card draws power from OmniGo.

SDK: OMNIGO:PUBLIC
Q. I noticed that the OmniGo draws a lot more current if a PCMCIA card
   is plugged into its slot, even if no programs are actively using
   the card. Would it be possible for the OmniGo to power down the
   PCMCIA port if no one is using it?

A. No. There are no power buffers to the PCMCIA port. If there is
   a card in the device, and the device is on, expect a significant
   power drain.


Differences between OmniGo SDK and 2.0 SDK.

SDK: OMNIGO:PUBLIC
Q. What is the difference between the OmniGo SDK and the GEOS 2.0 SDK?

A. In a nutshell, the OmniGo SDK is targeted towards application
   development for the HP OmniGo 100 device; the Geos 2.0 SDK provides
   an environment for developing applications for Geos 2.0 based devices
   (such as Casio Z-7000, IBM School View, and Geoworks Ensemble).

   The main differences are that the OmniGo SDK provides:
   - a development environment for writing applications for Geos 2.1
   - libraries and documentation specific to the OmniGo 100
   - an OmniGo 100 emulation for debugging purposes

   The Geos 2.0 SDK provides:
   - a development environment for writing applications for Geos 2.0
   - debugging emulators for Casio Z-7000, Sharp PT-9000, Geoworks
     Ensemble


Writing for OmniGo with the 2.0 SDK.

SDK: OMNIGO:PUBLIC
Q. Can I use the Geos 2.0 SDK to write applications for the OmniGo 100?

A. Yes. The Geos 2.0 SDK may be used to write applications for the
   OmniGo 100. Likewise, the OmniGo SDK may be used to write
   applications for Geos 2.0 based products.

   Developers may have some difficulty fully testing the application
   since the 2.0 SDK does not contain an OmniGo 100 emulator. You can
   debug your app running on the OmniGo, but this will drain the OmniGo's
   batteries faster since the serial port would be open constantly to
   remain connected to Swat.


Detecting power down on the OmniGo.

SDK: ALL_GEOS:PUBLIC
Q. How can my application detect when the user has turned the power
   on or off on the OmniGo 100?

A. First of all, unless your application is affected by external events
   (such as serial input) or for some other reason needs to know when
   the OmniGo powers on or off, you should not worry about power
   notifications.

   If your application does require this information, then it can
   register a notification routine with the power driver. There is
   only a limited number of vectors available, so your registration
   is not guaranteed to be successful.

   During device power down, there is nothing you can do to prevent the
   powerdown.

   On powerup, your routine can @send a message to let your application
   know that unit is powering back on. The notification routine should
   be small to prevent power on/off from becoming sluggish.

   Here is how you register for notification:
       #define DR_POWER_ON_OFF_NOTIFY 26

       GeodeHandle        powerDriverHandle;
       DriverPassParams   passParams;
       DriverReturnParams returnParams;

       powerDriverHandle = GeodeGetDefaultDriver( GDDT_POWER_MANAGEMENT );
       ...
       DriverCallEntryPoint ( powerDriverHandle,
                  DR_POWER_ON_OFF_NOTIFY,
                  &passParams,
                  &returnParams );

   In passParams, dx:cx = fptr to call back routine.

   returnParams will have carry set if you could not register for the
   notification (because too many routines are already registered).

   The callback routine must be written in assembly because the ax
   register will contain either ax = 0 (PNC_POWER_SHUTTING_OFF) or
   ax = 1 (PNC_POWER_TURNING_ON).


What is the port number for a PCMCIA serial card?

SDK: OMNIGO:PUBLIC
Q. What is the port number for a PCMCIA serial card?

A. On the OmniGo, com1 is the built-in serial port and com4 is
   the PCMCIA serial port.


Can I use hardware flow control on the OmniGo?

SDK: OMNIGO:PUBLIC
Q. Can I use hardware flow control on the OmniGo?

A. Yes and no. Yes you can use RTS/CTS, but you cannot use DTR.

   On the OmniGo, DTR is always high, but when the transceiver isn't
   powered on, the external DTR pin isn't driven. Since the pin is
   floating, it will most likely appear as neither HIGH nor LOW.


How can I force my application to shutdown to state?

SDK: OMNIGO:PUBLIC
Q. How can I force my application to shutdown to state?

A. On the OmniGo, you can hit FN-F3.


OmniGo powerdown cause saving to state?

SDK: OMNIGO:PUBLIC
Q. What happens when the unit is turned off? It doesn't go through
   the state file save/restore mechanism, does it?
   I'm asking because this can't be tested on the emulator.

A. When the OmniGo is turned off, processing is suspending, but
   Applications are not shut down to state. Power-down and -up
   are basically transparent to applications. On power-up,
   MSG_NOTIFY_DATE_TIME_CHANGE is sent over the GCNSLT_DATE_TIME
   GCN list.


How to delete state files and clipboard on OmniGo.

SDK: OMNIGO:PUBLIC
Q. Is there a way for the user to delete all state files or the state
   file for a particular app without clearing the RAM disk?

A. On the OmniGo, resetting with Shift-On-Next will clear the state
   files and clipboard.


What is the difference between TableClass and JTableClass?

SDK: OMNIGO:PUBLIC
Q. What is the difference between TableClass and JTableClass?

A. JTableClass is a subclass of TableClass that contains
   OmniGo-specific functionality. If you are writing your
   application for the OmniGo, use JTableClass.


How can my application tell when a cell is being edited?

SDK: OMNIGO:PUBLIC
Q. How can my application tell when a cell is being edited?

A. You can check TI_privateFlags for TPF_EDIT_CELL_TEXT.


Width of table is too large.

SDK: OMNIGO:PUBLIC
Q. The right side of the table is cut off. This is true not just for
   the table itself, but also for the scrolling controls in the title
   bar, which I have no control over.

A. The problem is that the table's column widths add up to 240 or
   more. Change the widths to add up to about 238. You can play with
   the value to get it how you want it to look; 235 leaves a bit too
   much room on the right.


How to tell when user changes table cell.

SDK: OMNIGO:PUBLIC
Q. How can I monitor when a user changes the selected cell in a Table?

A. Unfortunately, there is no default mechanism which will send you
   MSG_TABLE_SELECT whenever the selection changes.

   You will have to subclass these messages and have them send you
   notification whenever the selection changes:
   MSG_TABLE_CHANGE_ROW_RANGE_SELECTION - initiated by cursor keys
   MSG_TABLE_SELECT - initiated by pen/pointer selection
   MSG_TABLE_REDRAW_CURRENT_SELECTION - selection changed by scrolling
   action MSG_SET_CURRENT_SELECTION - program initiated selection change.


How to set a default selected row.

SDK: OMNIGO:PUBLIC
Q. How can I set a default selection row for a table?
   I have successfully managed to make a single cell be the default
   selection but never the row.

A. Use MSG_TABLE_SELECT(tcl, (TRIT_ROW|TCF_START_SELECT));
   "(TRIT_ROW|TCF_START_SELECT)" will tell it to select the entire row.


Changing to a different column.

SDK: OMNIGO:PUBLIC
Q. I have noticed that in a multi-column table on the OmniGo, I can
   cursor up and down but not left and right. What do I have to do
   to allow the user to change columns?

A. You can make the table scroll horizontally by making the GenView
   that contains the table scrollable in the horizontal dimension.
   BUT DON'T DO THIS! It violates the OmniGo UI Specification to have
   anything wider than the screen. Horizontal scrolling on the OmniGo
   is strongly discouraged.

   To make a table show different columns, you'll have to provide UI to
   allow the user to signal the app that s/he wants to view a different
   set of columns.


How to start editing a cell from keyboard.

SDK: OMNIGO:PUBLIC
Q. How can I start to edit a table cell from the keyboard (i.e. not
   doubling-tapping the pen)?

A. You can intercept MSG_META_KBD_CHAR at the Table object, and if it's
   the Enter key, then do the following:

   Make a local variable of type TableEditCellTextParams structure. Use
   MSG_TABLE_GET_CURRENT_SELECTION to get the current selected cell, then
   set the TableEditCellTextParams structure's TECT_cells field with that
   cell; set the TECT_text to NullHandle, and TECT_length to 0. Then
   call MSG_TABLE_START_EDIT_CELL_TEXT on yourself, passing in the
   TableEditCellTextParams structure.


How can I make a Table cell accept ink input?

SDK: OMNIGO:PUBLIC
Q. How can I make a Table cell accept ink input?

A. Add a line like this to your MSG_TABLE_START_EDIT_CELL_TEXT method:
     @call MyTableView::MSG_GEN_VIEW_SET_INK_TYPE(GVIT_QUERY_OUTPUT);

   Then do something similar for MSG_TABLE_STOP_EDIT_CELL_TEXT:
     @call MyTableView::MSG_GEN_VIEW_SET_INK_TYPE(GVIT_PRESSES_ARE_NOT_INK);

   Make sure to @callsuper() before each of the above.


Will I get notification when PCMCIA card is removed?

SDK: ALL_GEOS:PUBLIC
Q. Will I receive notification if my application is using a file that
   is located on the PCMCIA card and the user closes out the card?

A. The PCMCIA library will notify you in this case. It does this by
   sending MSG_META_REMOVING_DISK to your process object, but only if
   you're application is using a file that is on the card.

   We recommend that your application quit (without saving to state)
   when it finds out that this has happened.

   Warning: make sure you're not putting your process object on the GCN
   list that sends out MSG_META_REMOVING_DISK (GCNSLT_REMOVABLE_DISK).
   Because if you do, then your process object will always receive
   MSG_META_REMOVING_DISK when a card is removed, not just when you have
   a file open on the card (plus you'll get the message twice).


How to tell when PCMCIA card is inserted.

SDK: ALL_GEOS:PUBLIC
Q. How can one tell when a PCMCIA SRAM card has been inserted into the
   Casio Z-7000 or Tandy Z-PDA?

A. MSG_NOTIFY_DRIVE_CHANGE will go out on the GCN list GCNSLT_FILE_SYSTEM
   when a valid filesystem card has been inserted.

   Note that you should also handle MSG_META_REMOVING_DISK received
   over the same GCN list. If the disk handle is the one you are
   currently updating, you need to stop the update ASAP and close
   the file in question, then do a FilePopDir so you are no longer
   referring to the card.


App in RAM, library on the PCMCIA card.

SDK: ALL_GEOS:PUBLIC
Q. If my application resides on the internal RAM disk of the Casio
   Z-7000/Tandy Z-PDA, but uses a library located on a PCMCIA card,
   what happens if the card is removed while the library is still in
   use?

A. If an on-card library is to be used by a not-on-card application, then
   either the not-on-card application needs to watch for META_REMOVING_DISK
   messages on behalf of the library (as Preferences now does) or the
   library itself has to arrange to be on the GCNSLT_FILE_SYSTEM list
   (i.e. have an event-driven thread or an object run by the application)
   that watches for such notifications and forces the client application
   to shut down.


Apps on PCMCIA card don't show up in app menu.

SDK: ALL_GEOS:PUBLIC
Q. I know that to have an application 'automatically' show up in the
   launcher menu, you need to have that app in the World directory. What
   I don't know is how to get a flash card to alias itself into the World
   directory.

A. On the PCMCIA card, create a directory structures \GEOWORKS\WORLD.
   GEOS will alias standard directories (WORLD, SYSTEM, USERDATA,...)
   and files that are under \GEOWORKS so they show up as if they were
   on the internal drive.

   The most common directories you might put on a PCMCIA card are:
    \GEOWORKS\WORLD - for applications
    \GEOWORKS\SYSTEM - for libraries and drivers
    \GEOWORKS\DOCUMENT  - for documents and application data files
    \GEOWORKS\USERDATA\HELP  - for application help files


Printing text and graphics to the printer.

SDK: ALL_GEOS:PUBLIC
Q. My application prints text and graphics to the printer. When I print,
   all of the grobj objects print fine, but my text is too small, and my
   graphics don't print at all.

A. You are probably using the system font (which is a bitmap font).
   Bitmap fonts are not scaled, so on a printer with high DPI, the bitmap
   font is printed very small. To print bitmaps to the printer, you need
   to use the GrDrawBitmap() functions, not GrDrawImage().


How is MSG_PRINT_CONTROL_SET_TOTAL_PAGE_RANGE used?

SDK: ALL_GEOS:PUBLIC
Q. How is the information settable via
   MSG_PRINT_CONTROL_SET_TOTAL_PAGE_RANGE used? Is it only used
   by the print dialog's page range objects?

A. You surmise correctly. The information is then passed on to the
   Spool library (when calling SpoolAddJob).


Print control is always disabled.

SDK: ALL_GEOS:PUBLIC
Q. The 'Print...' option in the File menu is always disabled. Is
   there something I am forgetting to do?

A. The PrintControlClass was designed for multiple document interface,
    so it is not expecting to have a printable object ready at first.
    For SDI, you will need to either statically set GS_ENABLED or send
    MSG_GEN_SET_ENABLED to the PrintControl object.


Text looks too small in printer output.

SDK: ALL_GEOS:PUBLIC
Q. When the form prints, the boxes, buttons and check-boxes in the form
   all look the proper size, but the text is very small. It looks okay
   When I draw text to the screen. What am I doing wrong here?

A. The system font is a bitmap font. Bitmap fonts are not scaled, so on
   a hi-res printer, the font is very small, and on a low-res printer,
   the font is bigger. You will need to use an outline font (like Roman)
   for printing.


GrDrawBitmap versus GrDrawImage.

SDK: ALL_GEOS:PUBLIC
Q. My bitmaps do not print at all. I think this is because I use the
   function GrDrawImage instead of GrDrawBitmap, but I have yet to test
   this theory.

A. GrDrawImage doesn't works when printing. You need to use GrDrawBitmap
   or GrFillBitmap.


Bit mask versus area patterns when printing.

SDK: ALL_GEOS:PUBLIC
Q. When I am drawing to the screen and call the GString command:

       GSSetAreaMask	SDM_VERTICAL
       GSFillRect	...

   The vertical line pattern is clearly visible. However, when drawing
   to the printer, the vertical lines in the pattern are so close that
   it appears to be a solid color. I tried using GSApplyScale to increase
   the resolution (the distance between the vertical lines of the pattern)
   but it does not seem to do anything. Am I missing some command or
   something?

A. The reason this is happening is that the mask is bit oriented, so on
   a high resolution device (like your printer) the bits are very close
   together. You should use GSSetAreaPattern (with PT_SYSTEM_HATCH and
   SH_VERTICAL) so the system will maintain a consistent hatch pattern
   on all devices.


Knowing when user cancels printing.

SDK: ALL_GEOS:PUBLIC
Q. Is there a way to tell if the user hit cancel in the Print Control
   Box? Does the spooler send out any sort of notification?

A. Not externally, no. But there is the visibility notification,
   MSG_PRINT_NOTIFY_PRINT_DB, that gets sent out whenever the dialog
   comes off the screen.


Why can't I make GeoFile?

SDK: ALL_GEOS:PUBLIC
Q. Why can't I make GeoFile?

A. MAKEFILE and DEPENDS.MK should not have been installed on your host.
   Delete them from the \GEOFILE directory then "mkmf" and "pmake depend"
   them normally. Note that you'll get some warnings, but none will
   stop the successful compilation of GeoFile.


Knowing what file is needed for an application to run.

SDK: ALL_GEOS:PUBLIC
Q. When I try to run a sample application, I get a message:

   "Could not open "EC SampleApp" because a required system file is missing."

   Under SWAT it says: "Re-using patient pen. Pen exited." Which file am
   I missing?

A. It's pretty difficult for us to tell from that information.  Before
   starting up EC SampleApp, break to the Swat prompt and type
   "showcalls -L". This will show all libraries being loaded; hopefully,
   this will tell you what library you're missing.


CRC routine for PCCOM has a bug.

SDK: ALL_GEOS:PUBLIC
Q. The code for calculating the CRC for PCCOM file transfer appears to
   have a bug.

A. That's right. The loop should be

     for ( ; size > 0; size-- )

   not

     for ( ; size >= 0 ; size-- )


LEVELS.GOC won't compile. Why not?

SDK: ALL_GEOS:PUBLIC
Q. LEVELS.GOC won't compile. Why not?

A. There are two objects that need to have their visMonikers slightly
   modified (go to line #474 and 479). The pound sign (#) is what is
   causing the problem. You can do one of two things to allow the
   compilation to work:

   1. Remove the '#' sign from the string (example below).  This will
      allow the 1 character to remain the keyboard navigation key (if you
      push '1' it will select that trigger).

        GI_visMoniker = '1', "Child #1";
        *change to*
        GI_visMoniker = '1', "Child 1";

   2. Place a '\' before the '#'. This will allow the pre-processor to
      handle the # sign, but for some reason, it cannot use the keyboard
      navigation.

        GI_visMoniker = '1', "Child #1";
        *change to*
        GI_visMoniker = '1', "Child \#1";


Serial port activity notification.

SDK: ALL_GEOS:PUBLIC
Q. How do I know if data has been received at a serial port? Is there
   an explicit message sent? Or do I have to poll using SerialQuery()?

A. You can set up a message for serial event notification. See the
   SDK_C\Serial2 sample application.


What's the difference between SerialModes SM_RAW, _RARE, and _COOKED?

SDK: ALL_GEOS:PUBLIC
SM_RAW, SM_RARE, and SM_COOKED control how the driver treats incoming
serial data.

In SM_COOKED mode, the driver obeys software flow control (XON/XOFF)
and limits characters to 7 bits (to deal with errant parity bits
masquerading as 8-bit, no-parity data).

In SM_RARE mode, flow control is still provided, but incoming data
is untouched (except for the stripping out XON and XOFF bytes
from the input stream).

In SM_RAW mode, flow control is disabled.


How can I limit the size of my application's state file?

SDK: ALL_GEOS:PUBLIC
Q. How can I limit the size of my application's state file?

A. There are three ways to limit the size of the application's
   state file.

   1. Completely disable the state file for your application.
      Write a handler for MSG_GEN_PROCESS_CREATE_NEW_STATE_FILE
      and simply return NullHandle. If your application needs
      to save some small amount of information between sessions,
      consider saving it in the ini file instead of to state file.
   2. Marking a resource as notDetachable will prevent objects
      in that resource from saving to state.
   3. Marking an object ignoreDirty will prevent that object
      from saving to state.


Saving global variables to state file.

SDK: ALL_GEOS:PUBLIC
Q. I have various global variables. How can I save them to the
   state file when my application shuts down?

A. Intercept MSG_GEN_PROCESS_CLOSE_APPLICATION. Have the message
   handler copy the global variables to a global memory block and
   return the handle of that block. The system will automatically
   save this block to the state file. When the application is
   resumed, MSG_GEN_PROCESS_OPEN_APPLICATION will provide a memory
   handle of the additional data block that was saved earlier.
   Your application can then copy this information back to the
   global variables.


Causing an application to quit.

SDK: ALL_GEOS:PUBLIC
Q. What is the proper way to shut down an application? Is there a
   message that will shut down the application regardless of what UI
   objects are active (such as a modal dialog up)?

A. Send MSG_META_DETACH to the application object. For the callerID
   parameter, pass zero. (callerID is useful if you are writing
   your own handlers for MSG_META_DETACH and want some way to ID the
   object that sent the message.)

   Another option: You can send MSG_META_QUIT to the application object.
   This will cause your application to completely shut down. It will
   not save a state file.


Forcing no state file to be saved.

SDK: ALL_GEOS:PUBLIC
Q. How can I prevent my application from saving to state, so that it
   comes up "new" every time.

A. Subclass MSG_GEN_PROCESS_CREATE_NEW_STATE_FILE and return NullHandle.


Splitting code into multiple source files.

SDK: ALL_GEOS:PUBLIC
Q. I just split my application up into multiple source files and
   moved my code out of the PCGEOS branch so that I am sure to
   always have a 'clean' installation. Everything seems to work
   fine with one exception: when Swat is loading my geode or my
   geode's symbol table, it waits for a while and responds with:

    Looking for "ff      Eapp"...
    Can't find executable file for "ff   Eapp" (version mismatch?)
    Answer "quit" to exit to the shell
    Answer "detach" to detach and return to top level
    Answer "ignore" to ignore this patient
    Where is it? C:\DEV\PCGEOS\FF/

   If I respond with FFEC.GEO, everything continues fine. How can
   I make this stop?

A. Add the following to your Swat.cfg file (at the end):

    "5 [your directory name]"

   where "[your directory name]" is replaced by the path name of your
   development directory. Note though that this directory must be
   under the root PCGEOS directory.


Locating a bad pointer/handle in a geode.

SDK: ALL_GEOS:PUBLIC
Q. I've got a bad pointer and/or handle floating around in my app and
   I'm trying to use Swat to track it down.

A. Look up the documentation of the 'ec' command in Swat (type 'help ec'
   inside of Swat and/or look at page 109 in the Tools book). The idea
   is for you to use various ec flag settings to get specific help from
   the system itself in:

    1) Locating the bug directly, and
    2) forcing the bug to manifest itself sooner and/or reliably.


Swat is giving me an error about RPC.

SDK: ALL_GEOS:PUBLIC
Q. Swat is giving me an error about RPC.

A. If you run Swat with the target machine not in the GEOSEC or
   GEOSNC directory, you will get a RPC error. On the target machine,
   change directory to GEOSEC and run pccom.


Interrupt 3: Breakpoint trap

SDK: ALL_GEOS:PUBLIC
Q. What is causing this in Swat

   *** No explanation available ***
   Interrupt 3: Breakpoint trap
   Stopped in FatalError, address 2282h:01c8h
   CheckHandleLegal+30: MOV   AX, 12 (000ch)

A. Regarding interrupt 3:  When you get something like this, a random
   interrupt in Swat that just kills everything, you can often stop it
   from happening by invoking PCCOM differently on the target. Add 10 to
   the interrupt number, turn it into hexadecimal, and make PCCOM ignore
   that number. For example, you would run PCCOM thus:

    PCCOM /i:d

   This would make PCCOM ignore the unwanted mouse-generated interrupt.

   Using a bus mouse instead of a serial mouse may also take care of it.


What parts of Swat should I learn first?

SDK: ALL_GEOS:PUBLIC
Q. Swat is rather daunting to learn. What parts should I learn first?

A. My best suggestion for Swat is to check out the Tutorial book. It not
   only shows the basics of writing an application, but also how to debug
   one.

   Other things that are helpful to know:
   1) If your application crashes upon launching, then simply running it
      from Swat may give you a Death due to ... and explanations will tell
      you what is wrong.

   2) backtrace can give you an idea of what objects and methods the
      problem is in.

   3) GENTREE and VISTREE will display the object tree for you

   4) PGEN (and most other P... commands) is good for printing out the
      contents of a generic object. "pgen GI_link" can be used to see
      what the object is linked to (or what the link value is).

   5) SRCWIN will open a window to display any source code (when it is
      available).

   6) SSTEP (and ISTEP) can be quite usefull. You can even step through
      the kernel if you want to look at assembly.

   7) Set break points with BRK and STOP IN

   8) Use FRAME to check different methods/routines in the stack frame
      (show with a backtrace).

   9) MWATCH and OBJWATCH are very useful for watching messages


How can you tell who sends a particular message in Swat?

SDK: ALL_GEOS:PUBLIC
Q. How can you tell who sends a particular message in Swat?
   Is there any way to see when a given message is put on the queue,
   rather that when it is delivered (as mwatch and objwatch seem to
   operate)? I am trying to track down where a particular message is
   coming from.

A. Try 'cbrk ObjMessage ax= bx= si='


Overwriting the chunk boundary.

SDK: ALL_GEOS:PUBLIC
Q. Is there ec code to check to see if the data you are writing into
   a chunk over writes the chunk boundary? (not ec lmem in Swat, but
   ec code I can add to the source)?

A. You can either call ECCheckBounds, or use the EC_BOUNDS or Assert_fptr
   macros. They all do the same thing (call ECCheckBounds), which checks
   chunk boundaries, but only if ECF_LMEM error checking is set.


I get Phar Lap err 10049: Ran out of stack buffers when I run Swat.

SDK: ALL_GEOS:PUBLIC
Q. Swat works fine in DOS, but it gives me errors when I try to run
   Swat in Windows 3.1. I get errors like "Can't contact PC: Call
   timed out" or "Phar Lap err 10049: Ran out of stack buffers".

A. You need to tell Windows the com port's IRQ level (port address
   will usually set itself correctly, but you might have to set this,
   too). You can do this in Control Panel. Select Ports, then
   the port number you are working with, then Advanced...
   The most common IRQ levels used by com ports are 3,4 and 5.


What flags should I set for the ec command in Swat?

SDK: ALL_GEOS:PUBLIC
Q. What flags should I set for the ec command in Swat?

A. When developing and testing and app, turning on the various ec
   flags is an incredibly simply way to force many lurking bugs to
   reveal themselves. The minimum ec setting you should use are
   +normal, +segment, +high. These will catch most common mistakes,
   like unlocking a block of memory and then passing, as a parameter,
   pointer into that block of memory.

  +lmemMove and +unlockMove are also good as they cause the block to
   move around more often, which will reveal bugs such as pointers
   to unlocked blocks.

   If you are using VM files, +vmemDiscard is good.


Switching threads within a patient in Swat.

SDK: ALL_GEOS:PUBLIC
Q. The Swat command-line prompt is normally something like
   [manager:0] 30 ==>. I can "patient name" to get "manager". But what
   Swat command do I use to get the thread number "0"?

A. sw patient:0 or just :0


Why won't Swat run under OS/2?

SDK: ALL_GEOS:PUBLIC
Q. Why won't Swat run under OS/2?

A. Because the Phar Lap memory manager used by our SDK doesn't work
   with OS/2.


Table patient doesn't have any objects in it.

SDK: ALL_GEOS:PUBLIC
Q. In Swat I tried to look at the messages going to the CoffeeTable
   object in table.goc, but Swat said that the patient table had no
   threads, classes, or objects. Was Swat returning results for a
   library called table? I did the same actions for chart.goc, and
   things appeared to work correctly.

A. Yes, the patient "table" is a library. You want to use the patient
   "tablesam" (this name is found in the .gp file).


API for the FoamDocConvert.. routines.

SDK: N9000C:PUBLIC
The Foam library routines are documented in HTML format. Please see
http://www.geoworks.com/devrel/sdk-doc/Routines/index.html for these
routines.

But while you're here, check out these descriptions.

FoamDocConvertFromDosInit:
SYNOPSIS: Initialize the DOS to document conversion. The
      function returns an optr of a temporary text object used
      in the conversion.
PASS:	  void
RETURN:	  optr - temorary text object.
SIDE FX:  none

FoamDocConvertFromDosAppend
SYNOPSIS: Append a buffer of DOS text to the temporary text object.
      The DOS text is converted to the GEOS character set; CR's
      and Ctrl-Z are removed.
PASS:	  optr    object       - temporary text object
      TCHAR * buffer       - fptr to buffer of text to append
      word    bufferLength - number of characters to append.
                 (0 if null-terminated).
RETURN:	  void
SIDE FX:  none

FoamDocConvertFromDosDone
SYNOPSIS: Function is called when done appending to the temporary text
      object. A text transfer item is created from the text object
      and stored in the specified document. The text object is
      then destroyed.
PASS:	  DocumentHandle docHandle - DocumentHandle
      optr           object    - Temporary text object
RETURN:	  void
SIDE FX:  none

FoamDocConvertToDosInit
SYNOPSIS: Initializes the Document to Dos conversion, returning an
      optr of a temporary text object used in the conversion.
      All calls to FoamDocConvertToDosInit must be offset by
      a call to FoamDocConvertToDosDone.
PASS:	  DocumentHandle docHandle - DocumentHandle
RETURN:	  optr - Temporary text object
SIDE FX:  none

FoamDocConvertToDosRange
SYNOPSIS: Retrieve a range of text from the document into a specified
      buffer.  The buffer must be able to hold the number of bytes
      requested.  The call is responsible for making sure this
      is the case.
      The buffer must be at least TWICE as large as the size
      of data requested. That means, if you want to get 1K
      data, the buffer allocated should be able to hold 2K
      data beginning at ES:DI.
PASS:	  optr    object   - Text object
      TCHAR * buffer   - fptr of buffer for text
      dword   startPos - start position
      dword   endPos   - end position
RETURN:	  word - number of characters returned.
SIDE FX:  none

FoamDocConvertToDosDone
SYNOPSIS: Function is called when done retrieving text from the
      temporary text object.
PASS:	  optr object - Temporary text object.
RETURN:	  void
SIDE FX:  none


Using modem with GEOS 2.0 SDK on Windows NT.

SDK: N9000C:PUBLIC
Using modem (NT or DOS SDK):

* adjust .ini file settings
* attach modem
* set up access point(s) under "settings"
* refer to access point of choice under "settings" for each app

------------------------------------------------------------
Setting up internet service (access points)

If you need to use Internet appls except Terminal, you need to
configure access points. Access points are the configuration
infomration when dialing up your internet service provider.

The very basic things you need to know about your internet service
provider are:

Phone number. Make sure this is the PPP phone number, not just a
regular terminal phone number. We do not support manual PPP login
nor dial-back service.

Username to login

Password. You can put it in when defining access point. It will be
saved to .INI file. If you do not want it to be saved, select "Prompt
password" to "Yes" and you will be prompted for password every time
you login to PPP.

Modem initialisation (optional). Some special modem settings in order
to connect to particular internet service providers. This field is
usually left blank.

IP address, Default gateway and Network mask (optional). They are not
really used. You can leave them blank.

Primary nameserver. If you want to resolve address like
"geoworks.com", you have to put this in. Bascially, this is the
address of the DNS server that looks up your unresolved address. (See
internet resources for more info)

Secondary nameserver (optional). This is used when primary nameserver
fails to resolve the address.

These access points are what you would choose from when prompted for
"Internet Access" from the individual internet application settings.

------------------------------------------------------------
Running Internet applications on PC Demo

Equipment:

      Modem. If you want to fax, you need a Class 1 compatible
      fax/modem (Class 2 is not good enough).
      Serial cable to connect modem and PC

Notes:

    1. The port used by PC is determined by

      [faxout]
      comPort = 0

in .ini file. In the above example, it is using com port 1. To use com
port 2, substitute 0 with 2. The values are actually SerialPortNum
enum. Please be reminded com3 is usually used by IR, although you can
tweak IR to use another port.

    2. You may also need to set this in .INI file:

      [security]
      mediaAlwaysAvailable = true

If you add this setting after demo is booted up, please restart the
demo so that this INI setting is re-read in Security library.

    3. If your modem lights blink or if it gives dial sounds when you
       try to connect, that means you have successfully opened the port.

------------------------------------------------------------
Running Internet applications on prototypes in non-GSM environment

Equipment:

      Modem. If you want to fax, you need a Class 1 compatible
      fax/modem (Class 2 is not good enough).
      Serial cables to connect N9000C prototypes and modem
      6-pin N9000C adaptor
      9-25 pin adaptors (optional)
      Gender changes (optional)
      Null modem
      N9000C special modem dongle that uses DCE to DTE cable. (See
      attachment for a diagram of the wiring.)

      IMPORTANT: The order of the null modem and N9000C special modem
      dongle matters. Sometimes, if you randomly connect it, it may
      still work because of some changed states in the modem. The
      proven way of using them is to have DTE end of N9000C modem
      dongle connecting to the null modem and then to N9000C:

      Modem <-> (DCE) N9000C modem dongle (DTE) <-> null modem <-> N9000C

      The N9000C modem dongles should have been labelled which end to
      connect to N9000C. You can insert gender changers in between so
      long as no wiring is altered. Since both ends of the null modem
      are symmetrical, its direction does not matter.

Notes:

    1. You need to make sure

      [faxout]
      comPort = 0   ; or 2 (com port 2) if it does not connect.

is in .INI file.

    2. Make sure

      [security]
      mediaAlwaysAvailable = true

is in the .INI file. Otherwise, you will get the error dialog box that
reads, "Phone turned off or not ready. Check phone and try again."
when you try to connect. Please reboot the machine if you add/change
this line using the Ini editor.

    3. If your modem lights blink or if it gives dial sounds when you
       try to connect, that means you have successfully opened the port.


The NT SDK crashes badly, and BorlandC can't be found.

SDK: N9000C:PUBLIC
Q. We received the new NT SDK last week but only really got around to
   using it properly this week. There are two of us using the system. I
   am having problems with the pmake command. It comes up with the
   following:

   --- MODEM.EOBJ ---
   goc -DDO_ERROR_CHECKING -D__GEOS__ -IMODEM -Ic:/PCGEOS/raw/MODEM
    -Ic:/PCGEOS/N9000V11//CInclude -Ic:/PCGEOS/N9000V11/CInclude  -I.
   -Ic:/PCGEOS/raw -I- -IMODEM -Ic:/PCGEOS/raw/MODEM
    -Ic:/PCGEOS/N9000V11//CInclude -Ic:/PCGEOS/N9000V11/CInclude  -I.
   -Ic:/PCGEOS/raw     -w -l  -cb -o MODEM_e.c MODEM.GOC
   bcc -DDO_ERROR_CHECKING -D__GEOS__ -Ot -c -v -y -w -g255 -w-amp -w-pin
   -w-cln -w-sig -w-sus -i200  -ml  -I. -IC:/PCGEOS/RAW
   -IC:/PCGEOS/N9000V11//CINCLUDE -IC:/PCGEOS/N9000V11/CINCLUDE
       -oMODEM.EOBJ MODEM_e.c
   The system cannot execute the specified program

   My colleague got a similar message on running mkmf saying that it
   couldn't find a specified file. After this his machine went to a blue
   screen with an error message. Unfortunately he restarted before I had
   a chance to note what it said. On re-starting however he kept getting
   the message

   ***STOP 0x00000067 (0x00000000, 0x00000000, 0x00000000, 0x00000000)
   CONFIG_INITIALISATION_FAILED

   followed by lots of lines of Data and he wasn't able to boot NT again.
   Even using the Last Known Good Profile didn't resurrect it the first
   time. Luckily it worked on the second attempt (something he tried in
   desperation).

A. I guess the first thing to find out is what version of NT they're
   using, and what service pack they're using. The only time I've seen
   that has been when using non-service-pack'd versions of NT 3.51.

   If they're using 3.51, are they using Service Pack 4 or higher (SP5 is
   the latest, and I recommend switching to it).

   If they're using 4.0, they should be using Service Pack 1.

   As for the Borland problem, they should verify that they have

   CCOM=@dosfront bcc       [this is probably the cause of "The System
                            cannot find the program specified", 'cuz
                            you get that error when you pass too many
                            args to a 16-bit app]
   GOC_COMPILER_DIR=c:\bc5  [or wherever. But not c:\bc5\bin]

   set in their Environment (Control Panel -> System -> Environment).


I get 'death due to NOT_MEM_HANDLE'.

SDK: ALL_GEOS:PUBLIC
Q. Swat gave me a "death due to NOT_MEM_HANDLE". But my handle
   variable is set to 5890h, which looks valid to me.

A. Use the phandle command (i.e., "phandle 5890h") to get info about
   your handle. I am guessing that the handle's block was freed,
   which phandle will tell you.


How can I run Swat using a Zoomer as my target machine?

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. How can I run Swat using a Zoomer as my target machine?

A. There are other methods, but here's one way to run Swat with a Zoomer
   as the target machine (in ten easy steps):

   1. You may need to perform a full reset on the Zoomer to free space in
      the RAM disk. You'll need space for your application plus at least 273k.
      (To do a full reset, press and release the reset button in the battery
      compartment while holding down both fire buttons. Keep holding down
      both fire buttons for a few seconds, then release. Then press and
      release the A button.)

   2. Copy \TARGET\ZOOM\LOADER.EXE from the SDK CD to the \PCGEOS\LOADER      directory on the host machine.

   3. Connect the serial cable from your host machine to the Zoomer.
      Check your baud rate for PCCOM. (If you've reset the Zoomer, it will
      be at the default 19200. If need be, run Preferences on the Zoomer and
      change the baud rate for File Transfer mode.)

   4. On the Zoomer, run File Manager, tap the Connect menu, tap File
      Transfer, tap the "Switch to File Transfer Mode" button in the
      dialog box.

   5. On the host machine, CD to the \TARGET\ZOOM directory on the CD and
      enter the following commands to send the three files to the Zoomer
      (page Z.12 of the sdk documentation--\ZOOMDOC):
        PCSEND GEOS.GEO
        PCSEND LOADER.EXE
        PCSEND SWAT.EXE

   6. Press a fire button on the Zoomer to exit PCCOM. (If it won't exit
      for some reason, perform a warm reset by pressing the reset button in
      the battery compartment without holding the fire buttons.)

   7. On the Zoomer, run File Manager, go to the \GEOWORKS directory and
      move GEOS.GEO to the \SYSTEM directory. Here's a step-by-step:
        A. tap to select the file: GEOS Kernel (GEOS.GEO)
        B. tap Move in the File menu
        C. select SYSTEM in the Move dialog box
        D. tap the Move button

   8. When ready to run Swat, tap File Transfer in the Connect menu
      on the Zoomer.

   9. Run Swat on the host machine.

   10. Swat will report it can't find hwrrom.lib, palmui.lib, and
       alarm.app. Enter "ignore" for each of those.


I get a CORRUPT_LINKAGE error in Swat.

SDK: ALL_GEOS:PUBLIC
Q. I get this error in Swat:

   CORRUPT_LINKAGE (This happens when I start my program.)

A. What's wrong is you probably have a VisClass object as a child of
   a GenClass object. VisClass objects don't have GI_comp fields,
   thus the generic tree has a "hole" in it where the VisClass
   object is. To remedy the problem, make sure the VisClass is the
   only child of the GenClass object.


Mismanaging breakpoints in Swat causes crash.

SDK: ALL_GEOS:PUBLIC
Q. Sometimes when I detach in Swat, then reattach, I get the
   'Geos exited' message and a prompt, but I can't type anything.
   I then have to end the task in Windows, or reset the machine
   if I'm running Swat from the DOS prompt.

A. The problem here is most likely that you are using software
   breaks. To solve this, don't do anything with the breaks while
   you are detached from the target computer. Here's what you
   shouldn't do:

     det
     brk delete 5-
     att

   This will cause Swat to lockup. Instead, do this:

     det
     att
     CTRL-C
     brk delete 5-

   The other problem is that if you leave Swat doing nothing
   while it's detached, it will do the garbage collection. This
   seems to make it do the 'Geos exited' error. If it does the
   garbage collection while it's attached, that seems to be okay.


Swat can't find my geode after changing the name.

SDK: ALL_GEOS:PUBLIC
Q. I wrote a new program, and later decided to change the name of
   it to something else. Now when I use Swat and try to send the
   program to the target computer, Swat tells me it can't find
   the program. What can I do?

A. Search for every instance of the old name and make sure to
   change it to the new name. This should only be necessary in
   the .GP file. To simplify things, make the name of the directory,
   name of the .GP file, and the permanent name in the .GP file all
   the same. The only name that should be different is the longname
   in the .GP.


Swat can't run under Windows 3.1.

SDK: ALL_GEOS:PUBLIC
Q. I am trying to run Swat from within Windows 3.1. I get these
   errors.

   Phar Lap err 10049: Ran out of stack buffers

   or

   Can't contact PC: Call timed out

A. Try putting the null modem at COM 1 or COM 2. Windows 3.1 doesn't
   seem to like when you use COM 3 or COM 4 in a DOS prompt. This will
   require reconfiguring your I/O cards and their interrupts, but it
   will let you run Swat under Windows.

   Note, Windows 95 does not have this problem.


I get a 'PC timed out' error when starting Swat.

SDK: ALL_GEOS:PUBLIC
Q. I get a "PC timed out" error when I use Swat, but everything
   seems to be set up correctly as far as the null modem settings.

A. Sometimes it's not always the modem settings that cause a time
   out with Swat. If you're in the wrong directory on the target
   machine, Swat will give you a time-out error. This doesn't make
   sense, but that's how it is. You should be in the GEOS2XEC or
   ZOOMEREC directory when running PCCOM on the target.

   Also, if you're running under Windows '95 or NT and have a
   command prompt window opened, and it's using the serial port,
   Swat won't be able to use that port. Make sure to close any
   prompts that had at any time used the serial port (i.e. you ran
   Swat or pccom, pcsend, pcget, etc.).


I get an ILLEGAL_RESOURCE error in my program.

SDK: ALL_GEOS:PUBLIC
Q. I get an ILLEGAL_RESOURCE error in my program. Why is that?

A. If you're using GeodeGetOptrNS, make sure your program is
   multi-launchable. In other words, take out the "single" in the
   "type" line of your .GP file. This is just how the function
   works, and you can't avoid making the program multi-launchable.

   Another way this error could occur is if you forgot to create a
   LOCAL.MK file with the LINK_FLAGS line in it. You'll need this
   with multi-source apps when you use GeodeGetOptrNS.
   Here is a sample:

     # Pass flag for (somewhat) unsafe resource fixups for
     # multi-launchability.
     LINKFLAGS       += -r
     #include <$(SYSMAKEFILE)>

   You need that third line so that the system makefile is
   included during the compile.


Changing the font in a GenDynamicList object.

SDK: ALL_GEOS:PUBLIC
Q. Is it possible to change the font to display items in GenDynamicListClass
   the same way as it is done with MSG_VIS_TEXT_SET_FONT_ID? Can the font
   size be changed for GenDynamicListClass?

A. The way to do this is to specify the list entry monikers as GStrings
   rather than as normal text strings. In the GStrings, include the
   GR_SET_FONT command. GStrings are described in the graphics chapters
   of the SDK documentation.

   One caveat:  All the items are constrained to the same height,
   calculated via HINT_FIXED_SIZE on the list.


How are GEOS and DOS character sets different?

SDK: ALL_GEOS:PUBLIC
Q. What are the similarities and differences between GEOS and DOS
   character sets?

A. GEOS supports almost all roman-based languages.

   Geos uses mostly ASCII, which defines chars 0 to 127. Some of the
   control chars have different meanings. Above 127 are from Geos
   unique chars, that foreign languages (European), typographicals
   (like dagger and trademark), currency (yen), and math symbols
   (like infinity). You can find out the specific char codes from
   Include/char.def file.

   Geos does not have the IBM PC graphics chars (i.e., lower left corner
   piece with two lines).

   And then there is DBCS, in which is piled every character in existence,
   PLUS the kitchen sink.


Size of string versus string length.

SDK: ALL_GEOS:PUBLIC
Q. In terms of strings, what is the difference between size and length?

A. size = # of bytes, length = # of chars
   They are the same for SBCS, but size = 2*length for DBCS.


How can I get the metric width of a character?

SDK: ALL_GEOS:PUBLIC
Q. How can I get the metric width of a character?

A. You can use GrTextWidth (which returns the width in point size)


VisLargeText region array information.

SDK: ALL_GEOS:PUBLIC
Q. Is the region array information preserved across saving/loading of
   documents? Or does this information get rebuilt like the line
   array? (This is regarding a VisLargeText object.)

   If the region array needs to be rebuilt, how do I tell the text
   object to do that?  The line array is rebuilt automatically if the
   text object has a NULL for VTI_lineArray. However, if
   VLTI_regionArray is NULL, I get the fatal error:
   VIS_TEXT_LARGE_OBJECT_MUST_HAVE_REGION_ARRAY.

A. Call MSG_VIS_TEXT_CREATE_STORAGE passing regionFlag as non-zero to
   create regions.


Misusing threads to do more than one task.

SDK: ALL_GEOS:PUBLIC
Q. I need to open a dialog containing a text window and a Cancel button
   to show progress messages and handle user cancellation of an operation.
   The operation is a single method which also initializes the dialog. It
   sends status text strings to be displayed in the text window and checks
   if Cancel has been pressed. To do that, it calls two application messages
   periodically.

   However, the dialog does not show up until the operation method, the one
   that initializes it, returns. Is there any way to force the dialog update
   without its preliminary opening (it works fine if I open it before the
   user selected to connect)?

   While the operation method is working, mouse events are not processed,
   so I can not click on the Cancel button. How do I yield the control to
   the UI to handle the mouse within this slow operation?

A. I believe you can't really easily accomplish what you want in a single
   method. In fact, what you really want is two different threads working,
   which implies two different objects in charge.

   The first thread (probably your process thread) should be doing the
   connection work and sending notification messages to the progress
   dialog box. The second thread (probably your UI thread) should run
   the dialog box and send a cancellation message to the first thread
   when the Cancel
   button is hit.

   The SDK documentation has a section in the GenInteraction chapter of
   the Objects book that deals with progress interactions. Check out the
   on-line documentation. The ASCII file you want to look in is on the
   disc: \TECHDOCS\ASCII\OBJECTS\OGENINT.TXT. Look for section 7.3.2.4,
   called "Progress Interactions."


Using the old ThreadCreate on the Zoomer.

SDK: BETA:PUBLIC, 2.0:PUBLIC
Q. We need to run background tasks on the Zoomer. I use ThreadCreate
   to start background task, but Glue reports:

   Error MAP1BKG.GP 19: Usage of THREADCREATE requires geos minor protocol 9,
   but platform files only allow minor protocol 3

A. This is caused by an enhancement in our new kernel. Since Casio
   Z-7000 and Tandy Z-PDA use the old kernel, it cannot use the additions
   to thread create. To overcome this, you can call ThreadCreate_Old.
   To use ThreadCreate_Old, you must provide the prototype for it and
   at surround the call with push/pop of the si register. Here is an
   example:

    extern ThreadHandle
        _pascal ThreadCreate_Old(word priority,
             word valueToPass,
             word (*startRoutine)(word valuePassed),
             word stackSize,
             GeodeHandle owner);
    .
    .
    .
    _asm push si;
    thread = ThreadCreate_Old();
    _asm pop si;


How do I set real-time timers using TimerStart?

SDK: ALL_GEOS:PUBLIC
Q. How do I set real-time timers using TimerStart?

A. TIMER_EVENT_REAL_TIME starts a real-time clock on the device that
   will send a message at some particular date and time. You pass the
   date that the event should happen in the "ticks" parameter and the
   time of day in the "interval" parameter of TimerStart.

   The date is stored in a compressed format that is word-sized. The
   year (since 1980) is in the high 7 bits; the month is in the next
   4 bits; and the day is in the low 5-bits.

   The hour is stored in the high byte of "interval" and the minute is
   stored in the low byte of "interval.

   For example, if I wanted to have a wakeup notification sent on March 5,
   1996 at 8:05am, I would set up the "ticks" and "interval" parameter as
   follows:

   ticks = 0x2065;
    (year  = 1996-1980 = 16 = 0x10,  0x10 << 9 = 0x2000
     month = 3,                      0x03 << 5 = 0x0060
     day   = 5,                      0x05 << 0 = 0x0005)

   interval = 0x0805;


Why can't PCS find my pattern file?

SDK: ALL_GEOS:PUBLIC
Q. Why can't PCS find my pattern file?

A. PCS can't open the pattern file, PCS.PAT in the INCLUDE directory,
   if its read-only attribute is set. Due to a bug in the installation
   procedure, many files are installed with the read-only attribute on
   certain machines. The best thing to do is enter "attrib -r *.* /s" at
   the DOS prompt from the root of \PCGEOS on the host machine to clear
   this attribute from all the files.


Reasons why 'pmake depend' can fail to find cpp in the path.

SDK: ALL_GEOS:PUBLIC
Q. pmake depend cannot find cpp. Why?

A. Check your CONFIG.SYS and AUTOEXEC.BAT files for anti-virus programs
   that might be incompatible with the development tools, like this one:

     DEVICE=c:\NDW\NAV&.SYS /b

Q. I get an error from pmake depend that says:

   "STDDEFS.H can't be found, make sure CPP is in the path"

A. Check that turboc.cfg (in borlandc's bin directory) has a valid drive
   and directory settings. For example, "-IC:\BC45\INCLUDE"


Remote commands in pccom.

SDK: ALL_GEOS:PUBLIC
Q. When I attempt to use the remote command capabilities of PCCOM, I
   am having mixed success. I am able to get the target machine to clear,
   do ls and exit. Whenever I try a command like CD, MD, or delete file,
   it always says "Path not found."

A. All of the commands work. You need to put a '!' after *each* argument.
   Also, be sure to use DOS file path conventions. Check the Tools
   book in Chapter 10 under "pccom".


SDK tools are running slowly.

SDK: ALL_GEOS:PUBLIC
Q. The SDK tools are very slow. Glue will take up to 20 seconds
   before it starts linking all the object modules. How can I
   speed things up?

A. Our tools use the Phar-Lap DOS extender, which  has some problems
   with EMM386.EXE in MS-DOS 6.X. This problem causes delays before
   the programs start executing which are proportional to the amount
   of memory on the machine.

   To fix this problem, add the following to your autoexec.bat file
    set DOSX=-MAXV 0


I get Interrupt 2: Non-maskable interrupt in Swat.

SDK: ALL_GEOS:PUBLIC
Q. Interrupt 2: Non-maskable interrupt
   Stopped in ffc3h:000eh, address ffc3h:000eh
   BIOS+64574:

   I keep on getting this when I am attached to Swat. However, if I
   just type continue at the Swat prompt, everything is fine but each
   time I hit a trigger, I get the same interrupt.

A. You need to mask out interrupt 2. To do this, first add 8
   (int2 * 4 bytes) to the interrupt number to be masked (2+8=a),
   and then pass the result with the /i flag in the call to the
   Swat stub.


I always get a warning about .rdf files not included.

SDK: ALL_GEOS:PUBLIC
Q. Every PMAKE DEPEND had this warning:

   WARNING: file "APPNAME.ASM", line xxx: Couldn't find include
   file APPNAME.RDF

A. That's normal; the .RDF (.rdef) file is generated by uic during
   compile time.


Defining a class that is not a subclass of a GEOS class.

SDK: ALL_GEOS:PUBLIC
Q. How do I define a new class that is not a subclass of any of the
   GEOS subclasses?

A. Use a syntax similar to this:

   @class MyNewClass, meta;
   @endc;

   However, you can't actually declare an object from this class. It
   will not have a class pointer and thus will be unclassed, causing
   any number of problems in GEOS. Instead, you will be much better
   off if you subclass from MetaClass. It defines all the messages for
   managing objects in GEOS.


How to force a repaint of the content.

SDK: ALL_GEOS:PUBLIC
Q. What is the message to send to a VisContent which will make it
   repaint itself and its visual children? I am doing a lot of
   VUM_MANUAL things and want to repaint the content at the end of
   my routine. The message will be sent by an object running in my
   application thread.

A. Send MSG_VIS_VUP_UPDATE_WIN_GROUP with VUM_NOW (assuming that your
   VUM_MANUALs have invalidated things).


Adding a VisComp child to GenDocument object.

SDK: ALL_GEOS:PUBLIC
Q. How and when is the best time for someone to add a VisComp as a
   child of a GenDocument? I am trying to do it in the
   MSG_GEN_DOCUMENT_ATTACH_UI_TO_DOCUMENT handler, but at that point
   the Vis master part of the document object isn't built out.

A. You should be able to do it after calling the superclass.
   MSG_VIS_ADD_CHILD will force it to be built out.


Getting a VisText to display itself.

SDK: ALL_GEOS:PUBLIC
Q. We've got a simple application that has a dialog brought up by
   MSG_GEN_INTERACTION_INITIATE. In that dialog are a GenView and two
   triggers. In the GenView are a VisContent and a VisText under that.

   The problem? Even though apparently the text gets added to the VisText
   object's VTI_text chunk, the text object never displays it.

A. VisText doesn't do any geometry handling, so you have to do it yourself.
   (Presumably there's a good reason you are not using a GenText.) The
   content and text object will have zero bounds, since nothing has been
   done. If the content's bounds are zero, nothing will get drawn. You
   should at least stuff bounds for the text object, the content will
   follow suit.


Mouse events to only go to top Vis object.

SDK: ALL_GEOS:PUBLIC
Q. I have several Vis objects that overlay each other. I want mouse
   events to get detected only by the top (from the user's viewpoint)
   object and ignore the rest. How can I do this?

A. Clear the VA_DETECTABLE bit from any vis object that aren't eligible
   to be clicked on.


API available for HWR?

SDK: ALL_GEOS:PUBLIC
Q. Does the SDK include an API for handwriting recognition? Is it in
   the docs? If so, where?

A. Look in Include/hwr.h.


Using the serial driver and Serial sample app.

SDK: ALL_GEOS:PUBLIC
Q. Where's the serial driver? How come the Serial sample application
   doesn't work?

A. Download the STREAMC files from the Downloads page of the Geoworks
   Developer Relations web site:

     http://www.geoworks.com/DevRel/SelfHelp/Download/

NOTE: The file is no longer available from the web site. All current
      SDKs do not have the problem of the missing streamc library.


Setup.exe says fatal error in script line 1007

SDK: ALL_GEOS:PUBLIC
The SDK Setup.exe files are designed for Windows 3.x only.  If you
are installing to Windows 95/NT, use loader.exe (the DOS installer)
instead.

You will need to then set up a dos-launcher icon for SWAT.EXE.


Values of keys on the N9000 keyboard.

SDK: N9000C:PUBLIC
Following are keys on the Nokia 9000 Communicator and their corresponding
VChar values.  Use these in MSG_META_KBD_CHAR handling.

Keys on left side of display:
  Up arrow      =>   VC_PREVIOUS
  Down arrow    =>   VC_NEXT

Keys on the right side of display:
  Top button    =>   VC_F1
  Second button =>   VC_F2
  Third button  =>   VC_F3
  Bottom button =>   VC_F4

Arrow keys on the keyboard:
  Up arrow      =>   VC_UP
  Down arrow    =>   VC_DOWN
  Right arrow   =>   VC_RIGHT
  Left arrow    =>   VC_LEFT


Swat can't find your geode's symbol file.

SDK: N9000C:PUBLIC
If swat insists that it cannot find your geode's symbol file, check
your emulator launcher icons (the icons with names like "N9000 EC
with Swat"). Make sure that the directories in "Target" and "Start
in" (under the shortcut tab) match each other. If they do not, even
if you give the correct path, swat will complain about the sym file
having the wrong serial number.

For example, I had the following settings, which caused problems.

Target:   c:\pcgeos\Target\n9000.ec\localpc\ss.bat
Start in: c:\pcgeos\{local_root}\Target\n9000.ec\localpc

Changing it like this, fixed the problem.

Target:   c:\pcgeos\{local_root}\Target\n9000.ec\localpc\ss.bat
Start in: c:\pcgeos\{local_root}\Target\n9000.ec\localpc

Where {local_root} is your local branch directory.


Focus tip when adding and removing children in a GenContent

SDK: ALL_GEOS:PUBLIC
If you dynamically remove all the focus children in your GenContent and
then add new ones, you need to send MSG_META_CONTENT_APPLY_DEFAULT_FOCUS
to the parent GenContent.  Otherwise none of the children will get the
focus by default.


Ignoring keyboard input - how to.

SDK: ALL_GEOS:PUBLIC
Q. Is there a way to ignore a bunch of MSG_META_KDB_CHAR?  I need to do
   this right after dismissing a dialog until I do some other stuff.

A. Send MSG_GEN_APPLICATION_IGNORE_INPUT to your application object to
   begin ignoring input and MSG_GEN_APPLICATION_ACCEPT_INPUT to resume
   input handling.


How to make a VisText editable on the Nokia 9000.

SDK: N9000C:PUBLIC
Q. I've got a VisText object in my app and I can't edit it. What am I
   doing wrong?

A. Does the object have the focus? You can check this in Swat using
   the "focus" or "pobj -f" commands. If the object does not have
   the focus then you must manually set it using the message
   MSG_META_GRAB_FOCUS_EXCL.


How to have local variables in esp and still get the value of bp.

SDK: ALL_GEOS:PUBLIC
Q. If I'm writing an Esp procedure that uses local variables, how do
   I get the inital value of bp?

A. When a procedure takes parameters in BP and uses local variables,
   BP can be saved before the stack frame is allocated.  Following
   are examples of strategies for saving the value of BP.

   1. Saving BP in a local variable

   BP can be saved into the first push-initialized variable.

      ; ^hbp = GState to draw to
      CircleVisDraw   method  dynamic CircleClass, MSG_VIS_DRAW
      gStateHandle    local   hptr.GState     push    bp
      count           local   word
                      .enter

                      ......
                      mov     di, ss:[gStateHandle]
                      call    GrDrawPoint

   2. Saving BP in another register

      ; ^hbp = GState to draw to
      CircleVisDraw   method  dynamic CircleClass, MSG_VIS_DRAW
      count           local   word

                      mov     di, bp          ; ^hdi = GState
                      .enter
                      ......
                      call    GrDrawPoint


Environment variables used by the WinNT GEOS SDK.

SDK: ALL_GEOS:PUBLIC
The following Environment variables are used by Goc and Glue on
the WinNT GEOS SDK:

CCOM:
  The C compiler that you are using. Currently only "bcc"
  (BorlandC) is supported. A typical setting is:

    CCOM=@dosfront bcc

  Note that the "@dosfront " is only needed if you are using Borland C++
  V4.5. V5.0 will work correctly with long path names without the need
  for the dosfront utility.

GOC_COMPILER_DIR:
  Points to the main directory of your C compiler that you are using.
  A typical setting is:

    GOC_COMPILER_DIR=c:\bc45

ROOT_DIR:
  The main directory of the GEOS SDK. A typical setting is:

     ROOT_DIR=c:/pcgeos

  Note the use of the / as opposed to \. This prevents problems with
  Swat interpreting \t as a tab character. So something like c:\tigger
  would look like c:[tab]igger to Swat.


Registry entries used by the WinNT GEOS SDK.

SDK: ALL_GEOS:PUBLIC
The following entries are set in the Windows NT Registry in
HKEY_CURRENT_USER/Software/Geoworks/ntsdk30. They are used by
Swat on the WinNT GEOS SDK:

BRANCH:
  The "branch" directory Swat will use to find symbol files.
  A typical setting is:

    BRANCH = N9000V11

LOCAL_ROOT:
  The main directory of your working branch. A typical setting is:

    LOCAL_ROOT = c:/pcgeos/jdoe

ROOT_DIR:
  The main directory of the GEOS SDK. A typical setting is:

     ROOT_DIR = c:/pcgeos


I get a HANDLE_FREE error; seems to be a local variable problem.

SDK: ALL_GEOS:PUBLIC
If I have the following function definition:

void
MyFunction( TCHAR * ptcData )
{
    TCHAR buffer[12];
    strcpy( buffer, ptcData );
}

and change it to be like so:

@start MyResource, data;
@chunk TCHAR buffer[] = "123456789012";
@end MyResource;

void
MyFunction( TCHAR * ptcData )
{
    TCHAR buffer[12];
    MemLock( OptrToHandle( @buffer ) );
    strcpy( (TCHAR*)LMemDeref( @buffer ), ptcData );
    MemUnlock( OptrToHandle( @buffer ) );
}

I don't get a compiler warning at all, and at run-time I get an
HANDLE_FREE error. I don't believe that the compiler can check for
problems like this (between global/local variables and chunk names)
but it is something to be wary of.


Turning off date/time column in ExtendedFileSelectorClass.

SDK: N9000C:PUBLIC
Q. How can I make the ExtendedFileSelectorClass only display file names
   and not the date/time fields?

A. HINT_FILE_SELECTOR_MINIMIZE_WIDTH does this.


Getting a message's number given the message name.

SDK: ALL_GEOS:PUBLIC
Q. How do I find out the number of a message, given the name of the
   message. For instance, what is the number associated with the
   message MSG_GEN_DISPLAY_SET_NOT_MAXIMIZED?

A. In Swat, using the "whatis" command on the message, like so:

   => whatis MSG_GEN_DISPLAY_SET_NOT_MAXIMIZED

   If the message is defined within an application, you will have to
   switch to that patient before Swat will "see" the message.


Can I send an SMS message locally to another app?

SDK: N9000C:PUBLIC, 3.0:PUBLIC
Q. Can I send an SMS message from one application on the phone to another
   app on the same phone, without having to send through the GSM network?

A. Yes, you can do that. You must set the transport ID to GMTID_LOCAL in
   the MRA_transport field of the MailboxRegisterMessageArgs structure.


Dual video mode on the Nokia 9000 Communicator

SDK: N9000C:PUBLIC
* Nokia 9000i Communicator operates 4-color mode most of the time,
  because it is faster.

* Any application can switch the system into 8-color mode for as
  long as it wishes. This is done by sending the message
  MSG_GEN_APPLICATION_CHANGE_DISPLAY_MODE, which is defined in
  gAppC.goh. The DisplayMode type is defined in win.h.

* The system keeps track of how many applications wish to be in
  high definition mode, and stays in that mode as long as at least
  one application so wishes.

* When switching from low-def to hi-def mode, no existing pixels
  will change color. Only newly drawn pixels will be seen in the
  additional four shades of gray.

* It is up to the application developer to decide when it is
  appropriate to switch into and out of hidef mode. The app may or
  may not choose to relinquish hidef mode when it is not visible to
  the user. If the app does not switch back to low-def mode before
  exiting, the system will be stuck in hidef mode until a reboot.

* There is a sample application in Appl/SDK_9000/HiDef.geo

---------------------------------------

Q. At what point can I set the hidef mode for my app?

A. You need to intercept any one message which occurs before you
   try to draw the hidef graphic. It will do no harm to intercept
   multiple messages. There is no need to balance the mode change
   calls, as long as they are all to the same applicatoin object.

Q. What is the default mode?

A. The default mode is low-definition.

Q. Since when has the hidef mode been available? What happens if I
   send the message in versions of the OS before the hidef feature
   was added?

A. The mode switching has been available since whatever build came
   next after March 3, 1997. If you try to use the message
   MSG_GEN_APPLICATION_CHANGE_DISPLAY_MODE on an earlier build,
   nothing will happen since the message will just be ignored.

   While it is true that nothing bad will happen if you send a
   non-existent message to his application object, it is also true
   that by referring to that message, your application will have a
   protocol such that it probably will not load on a pre-Nokia 9000i
   system.


Redirecting stderr for the WinNT-based GEOS SDK tools.

SDK: ALL_GEOS:PUBLIC
Q. How can I capture the error messages I get when compiling using the
   WinNT-based GEOS SDK?

A. Use the "2>" redirection. For example:

   pmake 2> errors.txt > out.txt

   This directs error messages to a file called errors.txt and all other
   output to a file called out.txt.


How to get the handle of the System's UI thread

SDK: ALL_GEOS:PUBLIC
Occasionally, you will need the handle of the system's UI thread.
To get that, simply do this:

    ThreadHandle tHan;
    tHan = SysGetInfo( SGIT_UI_PROCESS );


Pmake command isn't working

SDK: ALL_GEOS:PUBLIC
If you get the following error when running pmake:

goc -DDO_ERROR_CHECKING -D__GEOS__ -IMYFILE -Ic:/PCGEOS/jdoe/MYFILE
 -Ic:/PCGEOS/N9000V11//CInclude -Ic:/PCGEOS/N9000V11/CInclude  -I.
-Ic:/PCGEOS/jdoe -I- -IMYFILE -Ic:/PCGEOS/jdoe/MYFILE
 -Ic:/PCGEOS/N9000V11//CInclude -Ic:/PCGEOS/N9000V11/CInclude  -I.
-Ic:/PCGEOS/jdoe     -w -l  -cb -o MYFILE_e.c MYFILE.GOC
bcc -DDO_ERROR_CHECKING -D__GEOS__ -Ot -c -v -y -w -g255 -w-amp -w-pin
-w-cln -w-sig -w-sus -i200  -ml  -I. -IC:/PCGEOS/JDOE
-IC:/PCGEOS/N9000V11//CINCLUDE -IC:/PCGEOS/N9000V11/CINCLUDE
    -oMYFILE.EOBJ MYFILE_e.c
The system cannot execute the specified program

The problem is most likely that the Borland compiler is not
being found. Check to see that you have the following set in
your environment (access the environment from Control Panel ->
System -> Environment):

CCOM=@dosfront bcc       [this is probably the cause of "The System
                          cannot find the program specified", because
              you get that error when you pass too many
              arguments to a 16-bit app]
GOC_COMPILER_DIR=c:\bc45 [or whatever your compiler's main directory is]


SEND in Swat says, 'Error: Unable to find source .geo file'

SDK: ALL_GEOS:PUBLIC
If you use the "send" command in Swat and it gives you the following
error:

  Error: Unable to find source .geo file

You need to exit Swat, run GEOS Setup and set the local root to your
local directory (for example c:\pcgeos\jdoe).


Tips on Swatting a Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
Since all the system code on the Nokia 9000 Communicator is run from
ROM, trying to set breakpoints in that code can cause strange things
to happen.


C compilers supported by GEOS SDK.

SDK: ALL_GEOS:PUBLIC
Q. What Compilers can I use with the GEOS SDK?

A. Currently the following compiler is supported:

     Borland C++ version 3.1 thru 4.52.

   Borland C++ version 5.0 can be used, but it has some bugs
   in it that you must be aware of (see the article in our
   knowledge database).

   No other compilers are currently supported. Specifically,
   neither Microsoft C++ nor Turbo C++ are supported.


What fonts are available on the Nokia 9000 Communicator?

SDK: N9000C:PUBLIC
Q. What fonts are available on the Nokia 9000 Communicator?

A. Here is a list of all the fonts available

                                 Point         Type
        Font                     Sizes        Styles
        ------------------------------------------------
        FID_RESPONDER             16          P, B
                                  14             B
                                  17          P
                                  18          P, B, I, BI
                                  20             B,    BI
        FID_TERMINAL              8,16        P
        FID_TERMINAL_GRAPHIC      8,16        P
        FID_DTC_URW_SANS           --
        FID_DTC_URW_MONO           --
        FID_DTC_URW_ROMAN          --
        FID_BISON                  --

   Notes:
   - Type Styles: P = Plain
                  B = Bold
                  I = Plain Italic
                 BI = Bold Italic
   - FID_TERMINAL and FID_TERMINAL_GRAPHIC are tiny, 7 pixel wide
     fonts that are useful for views that need to display 80
     characters per line (such as terminal or telnet). They have
     the same width (7 pixels) for both the 8 and 16 point fonts,
     16 points is there when you only need 12 lines of text (it is
     stretched vertically to be more readable).
   - FID_TERMINAL_GRAPHIC has VT100 graphics characters above 80h.
   - FID_DTC_URW_MONO is useful for printing.
   - All the fonts with Point Size of "--" are outline fonts, so
     you can use any font size with them.  The others are bitmap
     fonts with only the given point size and type styles available.
   - FID_BISON is for passwords and has only 1 character, the "*".


Sizing and positioning a FFileSelector object.

SDK: N9000C:PUBLIC
Q. I have problems positioning and sizing a FileSelector and text edit
   object in the same GenInteraction. The file selector is not wide
   enough. It should be as wide as parent.

   I tried HINT_EXPAND_WIDTH_TO_FIT_PARENT, but it did not help.

A. There are two parts to this problem. First, to expand the width of
   the file selector, use HINT_FILE_SELECTOR_FILE_LIST_WIDTH. This
   will specify the width to make the file selector (in average
   character-widths). You will have to try different numbers to
   see which looks best for your specific needs.

   The other problem is that the parent does not have the hints
   HINT_EXPAND_HEIGHT_TO_FIT_PARENT and HINT_EXPAND_WIDTH_TO_FIT_PARENT
   so it is not expanding to fit its parent. If you add those hints to
   the grouping interaction, it will also expand.

Q. MyShowXBox position is unstable. I want to fix the position to
   middle and bottom of Interaction.

A. HINT_FULL_JUSTIFY_CHILDREN_VERTICALLY will take care of placing
   MyShowXBox at the bottom of SelectXGroup (the GenInteraction).

   You can add HINT_CENTER_CHILDREN_HORIZONTALLY to make MyShowXBox
   position to the middle (horizontally) of the GenInteraction.


How to delete files from GenDocumentControl on OmniGo.

SDK: OMNIGO:PUBLIC
Q. How do I have a "delete" feature in my OmniGo application, so the user
   can delete the highlighted file?

A. The application menu can contain a GenEditControl. Add a "Delete"
   trigger and have it send the message MSG_META_DELETE to the target. The
   target just happens to be the GenDocumentControl while it is on screen.
   It will handle deleting the highlighted file.


FFileSelectorClass and FileOpenControlClass explained.

SDK: N9000C:PUBLIC
Q. What is FFilesSelectorClass for?

A. FFileSelectorClass is a GenFileSelector subclass that
   provides the Nokia 9000's special look and feel. The
   only thing it provides is a list of files, nothing else.

Q. What is FileOpenControlClass for?

A. FileOpenControlClass contains all the extra UI for opening,
   closing, renaming, etc. files that the FFileSelectorClass
   object displays.

   That list of files you see in the FileOpenControlClass object
   is a FFileSelectorClass object. FFileSelectorClass is used
   primarily in this context.

   FFileSelectorClass is really just a subclass of GenFileSelectorClass,
   although I think only a subset of GenFileSelectorClass functionality
   can really be used on the Nokia 9000.


Testing for floating point math errors.

SDK: ALL_GEOS:PUBLIC
To test the validity of floating point math results in GEOS,
compare the exponent part of the result to FP_NAN to determine
if an error has occured.

Example:

    word CheckForFloatError( void ) {
        FloatNum num;
        word     err = 0;  /* zero signifies no error */

        FloatPopNumber( &num );
        if ( FLOAT_EXPONENT( num ) == FP_NAN ) {
            err = -1; /* error occured */
        }

          /*
           * Put the number back on the FP stack.
           */
        FloatPushNumber( &num );
        return( err );
    }


DBCS character constants for localization.

SDK: ALL_GEOS:PUBLIC
Q. Are the character constants, like '\0' or '\n', dealt with correctly
   in the DBCS environment? Or is there a more localizeable way to put
   null chars and carriage returns in TCHAR strings?

A. Those will work fine as long you have TCHAR strings. You could also
   use C_NULL and C_CARRIAGE_RETURN from unicode.h. Note that if you
   want to compile DBCS geodes with C code, you'll need to do so with
   the PC SDK as HighC doesn't support TCHAR (wchar).


How to prevent the Swat stub from intercepting NMI.

SDK: ALL_GEOS:PUBLIC
Q. In our device the power driver wants to intercept NMI (INT 2).
   If I boot the device without the swat stub, it works fine. If I boot
   it with "swat /s ...", attach Swat host, and continue, it works
   fine too. But if I boot it with "swat ..." (without /s) and attach
   Swat host later, NMI is now hooked up to the Swat stub instead of the
   power driver. It looks like somehow the stub steals the vector from
   the power driver.

   How can I prevent the stub from intercepting INT 2?

A. Try using the /a or /i:2 switches. They should do what you want.


The Help button changed on Nokia 9000i emulator.

SDK: N9000C:PUBLIC
The help button has changed for the Nokia 9000i emulator.
You need to press Shift+Help to get help on the device.
Press left Shift+Insert on the PC emulator. The button will
be renamed on hardware to provide some other functionality,
thus prompting the change on the PC emulator.


How to tell if a dialog is displayed or not?

SDK: ALL_GEOS:PUBLIC
Q. How can I tell if a dialog is currently being displayed onscreen?

A. To determine if a dialog is currently displayed or not, call
   MSG_VIS_GET_ATTRS to see if VA_REALIZED is set.


How to modify paths to ini files.

SDK: ALL_GEOS:PUBLIC
Q. I want to modify the ini file to link to my own ini file, that
   way I can use the InitFile routines to read my ini file's keys.
   However, when I modify the "ini" key in the [paths] category and
   then try to read my ini keys, the InitFileRead fails.

A. You need to reboot the phone before the change to [paths]/ini
   takes effect, as that key is only read during bootup.


HINT_DRAW_IN_BOX invalidates HINT_PLACE_MONIKER_TO_LEFT

SDK: N9000C:PUBLIC
If you need to use HINT_DRAW_IN_BOX, be aware that it invalidates
HINT_PLACE_MONIKER_TO_LEFT. In other words, HINT_PLACE_MONIKER_TO_LEFT
has no effect if HINT_DRAW_IN_BOX is used.


How to get your Manufacturer ID.

SDK: ALL_GEOS:PUBLIC
If you need a manufacturer ID, send a request to orders@geoworks.com.

Why do you need a manufacturer ID? The manufacturerID is part of
a GeodeToken structure. The GeodeToken is used in many ways. Most
commonly, it is used to uniquely identify your application or library.
An application's icon is stored (in a file called the TokenDatabase)
based on the application's GeodeToken. Also, a file usually contains
the GeodeToken of the application that created it. There are several
other less common needs for a GeodeToken (libraries need it when
defining new general change notification lists).


Using the InitFileReadStringSectionBlock routine wisely.

SDK: ALL_GEOS:PUBLIC
Q. When I use the InitFileReadStringSectionBlock routine the returned
   MemHandle is not a NullHandle.  However, the system crashes
   when I try to free the MemHandle. The size variable shows that the
   size of the string is zero.

   I was wondering how could I know when a new block is allocated.
   I believe that I have to free it or otherwise there will be a
   memory block that is never freed. Any ideas? Should I totally
   ignore the MemHandle and just check the size variable?

A. To know when InitFileReadStringSectionBlock did not find what you
   wanted you should check the dataSize parameter. It will be zero if
   the routine did not find the string section. However, the block
   parameter will be garbage and ECCheckMemHandle routine won't always
   catch the problem. The best thing is to check dataSize and if it's
   zero, then don't do anything with the block parameter at all. If
   dataSize is non-zero then you can use block and reference the string
   stored in it.


How to convert a hex number to a message name in Swat.

SDK: ALL_GEOS:PUBLIC
How to turn a 4 digit hex number into a message name in Swat:

1. Find out the class of the target object for the message.
2. Print the hex number as decimal (e.g. 6a02h = 27138)
3. Type "whatis MSG_MOST_LIKELY_MATCH"
4. Compare the whatis output to the number you're looking for.
   - If it's way off, try another class.
   - If it's close, look in the header file for that class and count
     up or down to that message (they are numbered in the order they're
     defined in the header).


How to break up large code segments without breaking up the source file.

SDK: ALL_GEOS:PUBLIC
Q. Is there any way to break up a large code segment without breaking
   up the source file?

A. There is if you are using Borland C++ 4.5.  Use the following
   pragma command:

   #pragma codeseg MYRESOURCENAME

   All code between that pragma and the next pragma (or the end of the
   source file, which ever comes first) will go into a resource called
   MYRESOURCENAME. You can substitute "MYRESOURCENAME" with any name you
   like.


What does the 'on_stack' directive mean in an .asm file?

SDK: ALL_GEOS:PUBLIC
Q. What does the "on_stack" directive do in a .asm file?

A. on_stack passes a string to Swat to tell it where registers and
   return addresses are saved on the stack. this allows Swat to
   backtrace through functions that don't conform to its expectation of
   calling procedure. For example, if you jump from one procedure to
   another procedure, swat is unable to backtrace because it can't find a
   call on the stack to the routine it's in. however, if you put an
   "on_stack retf" declaration at the start of the routine that gets
   jumped to, then you tell swat that at ss:sp it will find the far
   return address and it will be able to backtrace. registers are
   declared starting from what ss:sp points to and moving up, thus:

   foo 	proc far jmp
    on_stack	retf
    push	ax, bx, cx
    on_stack	cx bx ax retf

   would tell Swat the right information.

   A couple tricks, though:
    - if a function contains an on_stack directive, Swat gives up all
      responsibility for figuring out what's on the stack; it trusts
      what's in the on_stack string. this means that when you push
      registers on the stack, you need to generate a new on_stack
      directive telling swat about the new register
    - if you push a bunch of registers, it's usually sufficient to just
      put an on_stack at the end of the sequence for all the registers.
      this means that if the thread context-switches away during that
      sequence, you won't be able to backtrace the thread, but how often
      does that really happen?
    - swat knows nothing about control flow in the function. as far as
      it's concerned, on_stack is valid from the place at which it's set
      through to the end of the function, unless another on_stack is
      encountered.
    - if you push the flags register, say register "cc" is on the stack
      (condition codes).
    - if the old xipPage mapping is pushed, say register "xipPage" is on
      the stack.
    - possible return types are "retn", "retf", "iret", "ret=register"
      if a near return address is in a register, and stackbot=xx.yy
      if the return address is in the stack below TPD_stackBot. xx is the
      name of the structure there, and yy is the field within it (can also
      be of the form xx.yy,zz where zz is the name of the field that
      contains the previous xipPage, meaning this function changed the XIP
      page mapping)


How to make app load on bootup.

SDK: ALL_GEOS:PUBLIC
Q. How do I make my application startup when the device reboots?
   And further, how would I make my application be the default
   app, instead of the Phone app?

A. To make an application start on bootup, you can change the .ini file.
   In the [uiFeatures] category there is a key called "defaultLauncher"
   which points to a geode under the SP_APPLICATION ("world") directory.
   By default it points to the Phone app on the Nokia 9000.

   If you just want your app loaded at bootup and not necessarily on
   top of other applications, you can use the "execOnStartup" key in
   the [ui] category. This key is a name list that specifies geodes that
   are to be launched but none will be on top because the [uiFeatures]
   "defaultLauncher" geode will be on top automatically.

   Here are some examples of how these might look:

[uiFeatures]
defaultLauncher = MyApp
defaultLauncher = EC MyApp

[ui]
execOnStartup = Extrapps\EC Test
execOnStartup = {
   Extrapps\EC Test
   MyApp
}

   To modify the defaultLauncher key, use InitFileWriteString(). To change
   the execOnStartup key, use InitFileWriteStringSection(). Be sure not to
   remove existing entries already there. And if you change the default
   launcher entry, it might be a good idea to move that app to the
   execOnStartup list.

   While you are testing with the EC demo, all names of apps must be
   preceded by "EC ". In the non-EC demo, remove the "EC ".


Grabbing the text of a vis moniker?

SDK: ALL_GEOS:PUBLIC
Q. How do I access the text of a vis moniker? All I've found so far is
   the GenClass message MSG_GEN_GET_VIS_MONIKER which gives me a chunk
   handle. What can I do with that?

A. Use code like this to extract the text from a textual VisMoniker:

    MemHandle    mh;
    ChunkHandle  ch;
    VisMoniker * ptr;
    TCHAR        buffer[10];

    ch = @call TestPrimary::MSG_GEN_GET_VIS_MONIKER();
    mh = OptrToHandle( @TestPrimary );
    // we're running in the ui thread, so we can call this on ui objects
    ObjLockObjBlock( mh );
    ptr = LMemDerefHandles( mh, ch );
    // must make sure it's not a gstring or moniker list
    if ( ( ptr->VM_type & ( VMLET_GSTRING | VMLET_MONIKER_LIST ) ) == 0 ) {
        // note the typecast to force C to add the correct values
        ptr = (byte*)ptr + sizeof( VisMoniker );
        ptr = (byte*)ptr + 1;
        strncpy( buffer, ptr, 10 );
    }
    MemUnlock( mh );


Printing from the Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
Yes, printing is supported on the N9000. Currently the only built-in
driver is for PostScript enabled printers.  There is an add-on printer
driver for the HP DeskJet available from Club Nokia
(http://www.club.nokia.com/mobile_office/9000/soft/soft.html) which
will work with any DeskJet from 340 to 870 cXi.

Currently printing is only supported through the IrDA port. You cannot
print through the serial port.


How to tell what hardware N9000 app is running on.

SDK: N9000C:PUBLIC
There's a new function available that will tell you what hardware an
app is running on. It's called RespGetPDAHardwareInfo and takes no
parameters and returns a PDAHardwareInfo. This will tell you whether
you're running on a N9000 or N9000i or a PC demo running the N9000
emulator software. It will also tell you if the backlight feature
is available.

See CInclude/Internal/respondr.goh for more details.


Using the modemc library on the Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
The .GEO and .SYM file for the ModemC library is missing from the
Windows NT-based Nokia 9000 Communicator SDK version 1.1. The missing
files are available for download on the Downloads page of the
Developer Relations web site:

http://www.geoworks.com/DevRel/SelfHelp/Download/

Look under the "Nokia SDK Updates" heading.


IMEI = International Mobile Equipment Identity

SDK: N9000C:PUBLIC
IMEI stands for International Mobile Equipment Identity.

An IMEI uniquely identifies a particular mobile. On the
the Nokia 9000, this ID can be retrieved via the EciGetImei()
routine.


Mixing sizing hints in a single object.

SDK: ALL_GEOS:PUBLIC
Q. Here's an object I'm defining. It's not sizing correctly.
   I want it to expand the height to fit the parent, but it's
   not working.

   @object FFileSelectorClass MyFileSelection = {
       GFSI_destination = process;
       GFSI_notificationMsg = MSG_MY_PROCESS_UPDATE_X;
       ATTR_GEN_FILE_SELECTOR_CREATOR_MATCH = {
           MY_LIST_ITEM_TOKEN, 0
       };
       ATTR_FFS_DOCUMENT_DIR = MY_LIST_DIRECTORY;
       HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
       HINT_FIXED_SIZE = {
           SST_PIXELS | 0, 127
       };
   }

A. Are you sure you want to use HINT_FIXED_SIZE? Did you mean to use
   HINT_MAXIMUM_SIZE instead? The reason I ask is you set up
   HINT_FIXED_SIZE to fix the height at 127 pixels (because SST_PIXELS
   is the default) and then used HINT_EXPAND_HEIGHT_TO_FIT_PARENT,
   which will have no effect because the HINT_FIXED_SIZE height setting
   will override the expand height hint.


Can application access outer buttons on Nokia 9000?

SDK: N9000C:PUBLIC
Q. Can users access my application using the outside keypad (i.e.,
   the phone lid is closed so the PDA keyboard is not accessible)?

   In other words, how can my application monitor the outside keypad?

A. This is not possible because the phone is not designed in such a
   way to allow access to both inside and outside keypads.

   Furthermore, when the lid is closed, the PDA side of the Nokia
   9000 goes into sleep (suspend) mode. Because of this, your
   application wouldn't be able to monitor the outside keypad anyway.


Can an application initiate a voice call on the Nokia 9000?

SDK: N9000C:PUBLIC
Q. Can an application initiate a voice call on the Nokia 9000?

A. No, an application can only initiate data calls. Data calls
   are initiated via the ModemC and VirtualSerial libraries.


Nokia 9000 Communicator UI paper.

SDK: N9000C:PUBLIC
Nokia has written a paper containing User Interface guidelines
and specifications. If you are in need of such information, send
email to 9000.sw.developer@nmp.nokia.com requesting the "NOKIA
9000 Communicator User Interface, introduction for developers".


Using extended registers in GEOS.

SDK: ALL_GEOS:PUBLIC
If you write assembly code that uses extended registers be aware
that when GEOS performs context switch does NOT save the high 16
bits of the extended registers.

Essentially, this means don't use extended registers in standard
GEOS methods and routines. You may use them in interrupt routines
and driver functions.

NOTE: Most GEOS devices use CPUs that do not have extended
registers, so using extended-register commands will limit the
platforms your application will run on.


The EciGetImei() function for Nokia 9000 phones.

SDK: N9000C:PUBLIC
This function is only available on phones with build 4.8 or later.
You can check the software build by looking in the GEOS.INI file
under the [ui] category in the "swSerialNumber" key.

To read the phone's IMEI number, you will need to use the EciGetImei()
function, provided by the eci library. This function takes one
parameter, a pointer to a buffer to fill with the code number string.
The buffer must be at least 17 bytes long, to hold the null-terminated
16-character code string. The function returns zero if the IMEI code
was read succesfully, non-zero otherwise.

@include

@method TestProcessClass, MSG_TEST_PROCESS_GET_IMEI {
    TCHAR imei[17] = "";

    if ( EciGetImei( imei ) == 0 ) {
      /*
       * We got IMEI code, do any check you want.
       */
    }
    else {
      /*
       * For some reason the query failed.
       */
    }
}


What happens when power-down (suspend) occurs in GEOS?

SDK: ALL_GEOS:PUBLIC
When a GEOS device is inactive for a specific amount of time, the
CPU goes into suspend mode. What does this mean for your application?
Nothing. Suspend is transparent to your application. Basically, all
that happens is the clock stops and the system goes into a suspended
animation. When the system is brought out of suspend mode, your
application is not aware that it ever stopped.


Proper buffer size for FloatFloatToAscii_StdFormat()

SDK: ALL_GEOS:PUBLIC
When using FloatFloatToAscii_StdFormat() make sure that the buffer
you pass to it is FLOAT_TO_ASCII_NORMAL_BUF_LEN in size
(FLOAT_TO_ASCII_HUGE_BUF_LEN if using FFAF_DONT_USE_SCIENTIFIC)

For example:

    char resultBuf[FLOAT_TO_ASCII_NORMAL_BUF_LEN];
    FloatFloatToAsciiFormatFlags format = FFAF_FROM_ADDR;
    FloatFloatToAscii_StdFormat( resultBuf, &floatNum, format, 6, 3 );

If the buffer is smaller, the system will overwrite the buffer,
causing memory trashing bugs to occur.


Apps suspending when device is closed.

SDK: N9000C:PUBLIC
Q. So what happens when the N9000 phone is closed (i.e. the PDA side is
   "put to sleep")? Does the CPU stop running immediately or does it wait
   for all the threads to go idle? I realize mailbox and RTCM events still
   occur, but do normal apps keep running? Is there a way to force the
   apps to continue running?

A. Thirty seconds after the lid is closed, if no thread is running, the
   PDA suspends. If the threads keep running (in an infinite loop), the
   PDA will never suspend. This is bad, though, since the battery will
   be run down. If the threads go idle, the PDA will suspend.


Glue can't find my library's LDF file.

SDK: ALL_GEOS:PUBLIC
When writing a library, "pmake lib" will make the library and copy
its LDF file to:

    \pcgeos\$USER\Include

(where $USER is your working branch). This will allow you to
make test applications to test your library.

If you are working on a multi-person project, you need to "install"
your LDF file to:

    $SDK_ROOT\$BRANCH\Installed\Include

so your team members have access to the LDF file. (Where $SDK_ROOT
is the location of the shared files and $BRANCH is the branch you
are working in. Run GEOS Setup to see the SDK Root and Branch
settings.)


How do I send messages to an object in Swat?

SDK: ALL_GEOS:PUBLIC
Q. I need to have my app run the handler for MSG_META_TRANSPARENT_DETACH.
   However, I can't (or more likely shouldn't) send this from within the
   application, so I was wondering if there was any way for me to send it
   from Swat.

A. omfq MSG_META_TRANSPARENT_DETACH *MyApp

   The command "omfq" stands for ObjMessageForceQueue and calls
   ObjMessage with the flag MF_FORCE_QUEUE to force the message to be
   placed on the object's message queue. When control is returned to
   the emulator (i.e. you type "c" in Swat) the message will be
   processed.


Fixed versus Movable memory block usage.

SDK: ALL_GEOS:PUBLIC
Q: Which type of memory is better to allocate, a movable
   or a fixed and locked block?

A: Movable is always better!

   The usual recommendation is for short-lived blocks to be alloced
   movable, even if they'll spend there entire lives locked down.

   The main reason for this is to reduce heap fragmentation. Fixed
   blocks get allocated at the bottom of the heap, and movable blocks
   get locked down at the top. By marking your block movable, once it
   has been freed, that free space will quickly be reused by other
   locked movable blocks.

   If another fixed block is allocated after yours, when your block is
   freed, it will leave a hole in the fixed memory area.


Configuring PC to drive RBUS traffic.

SDK: ALL_GEOS:PUBLIC
Q. How should I configure my PC that runs NT SDK to
   drive rbus traffic to the external port (COM)?

A. To get the PC/NT software to use RBUS and communicate
   with a CMT module plugged into Com2, one needs to:

  - Place the following geodes in the SYSTEM directory of the target:

      Library/Foam/OEM/rbus/rbus{ec}.geo
      Library/Foam/OEM/vp/vp{ec}.geo
      Library/Foam/OEM/vser/vser{ec}.geo

  - Add/Change the geos.ini file:

    [security]
    override = false


SMSO_dataCodingScheme, SMSO_userDataLength, SMSO_userDataHeader

SDK: N9000C:PUBLIC
Q. What are these fields for? Is it really necessary to include them?

A. These fields are for sending 8-bit SMS messages. If you want to
   send 8-bit data in your message you should set SMSO_dataCodingScheme
   to 0xF4. This tells the SMS system that the user data is 8-bit and
   that it can contain null bytes. Setting this field to any other
   value indicates that the message is 7-bit.

   If SMSO_dataCodingScheme is set to be 8-bit then you should set the
   size of the user data in SMSO_userDataLength. Setting this allows
   the data to contain null bytes.

   You should also set the SMSO_userDataHeader field to TRUE if there
   is a header at the beginning of the user data.


Random stuff about printing in GEOS.

SDK: ALL_GEOS:PUBLIC
Q. @call printControl::MSG_PRINT_CONTROL_GET_PAPER_SIZE( &pd );
   pss->PSS_paperHeight = PAPER_HEIGHT( pd );
   pss->PSS_paperWidth = PAPER_WIDTH( pd );

   I'm assuming that this value is the physical paper size?

A. It is the height and width of the paper in points (1 point = 1/72 inch).

--------------------

Q. @call printControl::MSG_PRINT_CONTROL_GET_PRINTER_MARGINS
       ( &(pss->PSS_printerMargins), TRUE );

   TRUE sets the document margins to be the same as the printer
   margins. But what are "document margins," and what effect
   do they have on the print job?

A. I believe that these margins are useful when you are not actively
   placing text/graphics (e.g., GrDrawTextAtCP).

--------------------

Q. dsp.PCDSP_width = pss->PSS_paperWidth;
   dsp.PCDSP_height = pss->PSS_paperHeight * ( pss->PSS_pageNo + 1 );
   @call (pss->PSS_printControl)::
       MSG_PRINT_CONTROL_SET_EXTENDED_DOC_SIZE( &dsp );

A. You need to make sure that PCI_endPage is set to PSS_pageNo.

--------------------

Q. When the second page finally comes out, the font has been reset
   to the original font (a bitmap font, which comes out teeny tiny)
   instead of MONO. The margins have also shifted a bit. What gives?

A. This could be caused by GrInitDefaultTransform.


What FAX modem do I need to use with Nokia emulators?

SDK: N9000C:PUBLIC
The Nokia 9000 Communicator emulator only works with modems that
support Class 1. The modem of choice for Class 1 is US Robotics
Sportster.

The Nokia 9000i Communicator emulator only works with modems that
support Class 2. The modem of choice for Class 2 is Macronix.


How to create a new page size in PageSizeControl.

SDK: ALL_GEOS:PUBLIC
Q. How do I create a new page size so that the PageSizeControl object
   will allow the user to select it from the page size list?

A. It's a four step process:

   1. SpoolCreatePaperSize()
   2. SpoolGetPaperSizeOrder()
   3. Modify the order array to add the new paper size number (which
      was returned by SpoolCreatePaperSize).
   4. SpoolSetPaperSizeOrder()


General guide for optimizing your GEOS code.

SDK: ALL_GEOS:PUBLIC
Here's some general issues to consider for optimizing your application:
for speed and memory usage:

* Don't keep blocks locked longer than necessary as it fragments the
  memory and causes the memory manager grief.  (If you are in a loop
  or something that frequently accesses a block, do keep the block
  locked since frequent lock/unlock takes up unnecessary CPU cycles.)

* Make sure to always use movable blocks; HF_FIXED blocks are always
  bad because they permanently fragment the fixed heap space.

* Static variables are stored in dgroup.  dgroup doesn't move, so
  pointers to data in dgroup can be maintained without the need to
  lock/dereference.  The trade-off is that dgrup is a HF_FIXED block,
  which will cause problems as mentioned above.

* When possible, use ChunkArrays rather than HugeArrays. While huge
  arrays allow arrays to be larger than 64K, they do so thru a level
  of abstraction that requires more computing to access an item in the
  array. Same is true of DB items.

* When performing visual updates, DO NOT use VUM_NOW.  Instead use
  VUM_DELAYED_VIA_APP_QUEUE. This will allow all the updates to occur
  simultaneously, which prevents the surge of redundent UI calculations
  cause by multiple updates using VUM_NOW.

* Processing a message call takes a mimimum of 3 times as long as a
  routine call, so use routines in loops or other parts of code that
  require speed efficiency.

* Code that must run quickly can be run by a seperate thread with the
  ThreadPriority set appropriately (something higher than PRIORITY_FOCUS).

* When using graphics, gstrings are generally faster than bitmaps for
  images that are comprised mostly of geometric shapes. For drawing
  bitmaps GrFillBitmap() is faster than GrDrawBitmap(), but the bitmap
  is drawn monochrome.

* Borland compiler optimizations. These flags will tell Borland C to
  optimize compilation for speed/size.  Set these flags with the
  CCOMFLAGS flag in your local.mk file. CAVEAT:  We Have Not Tested
  All These Flags and cannot guarantee that Borland will generate
  correct code when these flags are used.

 -O1 size optimization
 -b- Allocate enums as ints [default: off] (makes enums byte-size when
     possible)
 -Z Suppress redundant loads
 -Oc Optimize locally
 -Og Optimize globally
 -Ob Dead-code elimination
 -Oe Global register allocation (required for -Ob)
 -O Jump optimizations
 -Ol Loop optimization
 -Op Copy propagation (improves performance, and doesn't increase code size)

  The following flags all yielded good size reductions:
        -Z -Os -O
  Minor gains were seen with:
        -Ol -d


Tab chars in UnderlinedVisText (or UGenText) causes 'Internal error'

SDK: N9000C:PUBLIC
In UnderlinedVisText or UnderlinedGenText objects, pressing
the tab key results in 'Internal error ...' and [Reboot] dialog.

This is only for the first generation (build 3.8.8) 9000s.

This is a stack-trashing bug in UnderlinedVisTextClass.

The workaround is to set up your underlined text objects so that tabs
can never get inserted. This can be done by:

  - Adding a text filter that filters out tabs (VTF_NO_TABS for VisText,
    or one of the GenText filters that doesn't allow tabs), OR
  - If a GenText, set GTA_USE_TAB_FOR_NAVIGATION

Even though this bug did get fixed for future revisions, developers
will still have to use the workaround if they want to be backwards
compatible with the first generation Nokia 9000 Communicators.


Missing C-stub: GrSetVMFile

SDK: ALL_GEOS:PUBLIC
C routine:  GrSetVMFile
Date Fixed: 1/95

It turns out that there is a missing C stub for the GrSetVMFile
routine before January 1995. You can still use the routine, but
it will require writing a C stub and compiling that stub into your
application. This is not too difficult, so I have included a small
.asm source file that you should put in your application directory.
This will compile with the rest of your application (so you will
have to clean the directory and redo mkmf and pmake depend).

The C stub itself is written in assembly like this (I called the
file grsetvm.asm):

;---------------------begin grsetvm.asm-----------------------
include geos.def
include graphics.def			; contains GrSetVMFile routine

global GRSETVMFILE:far			; allow C-stub to be used externally

CommonCode	segment resource	; a code resource block

GRSETVMFILE	proc far gsHandle:word,
             vmHandle:word
    .enter

    ; save di because Goc doesn't like it being trashed
    push	di

    ; put all parameters into the necessary registers
    mov	di, gsHandle
    mov	ax, vmHandle

    ; call the assembly version of this routine
    call	GrSetVMFile

    ; no return parameters to worry about

    ; remember to restore di
    pop	di

    .leave
    ret
GRSETVMFILE	endp

CommonCode	ends			; end of code resource block
;----------------------end grsetvm.asm------------------------

Since GrSetVMFile is already prototyped in graphics.h, you don't need
to worry about prototyping the routine.

The capitalized routine name (i.e., GRSETVMFILE) in the .asm file
corresponds to the mixed-case routine name (i.e., GrSetVMFile) in
the .goc or .goh file. (The _pascal directive in the prototype causes
the C compiler to upper-case the entire routine name, which is why the
C stub routine name is all upper-case.)

The call to the mixed-case routine name in the .asm file is the
routine name in the graphics library.


Broken C-stub: SpoolGetPaperSizeOrder

SDK: ALL_GEOS:PUBLIC
C Routine:  SpoolGetPaperSizeOrder
Date Fixed: 7/18/97

The c-stub for SpoolGetPaperSizeOrder is broken because it does not
take the proper parameters. It needs to have a fourth parameter,
namely the PageType. Use this fixed function prototype and c-stub
in your application if you want to get the paper size order from
the spool library.

/*
 * Put this function prototype in your .goc file so it will know
 * about the new C-stub routine.
 */
extern void
    _pascal SpoolGetPaperSizeOrderFixed(byte *orderBuf,
                    byte *userDefBuf,
                    PaperSizeOrderInfo *numBuf,
                    PageType pageType);

; ------------------------- spool.asm -------------------------------

; include necessary header files
include         stdapp.def
include         spool.def

; make this C-stub available for external use
global SPOOLGETPAPERSIZEORDERFIXED:far

; start our code resource
CommonCode	segment resource

; define this internal structure for our stub
PaperSizeOrderInfo      struct
        PSOI_numOrdered word
        PSOI_numUnused  word
PaperSizeOrderInfo      ends

; turn on the pascal parameter-passing convention
SetGeosConvention

; start our C-stub
SPOOLGETPAPERSIZEORDERFIXED proc far	orderBuf:fptr.byte,
                           userDefBuf:fptr.byte,
                        numBuf:fptr.PaperSizeOrderInfo,
                        pageType:PageType
                    ; above params must be word-sized
        ;
        ; These are the registers this stub will use, save them.
        ;
        uses	ds, es, di, si
        .enter				; directive to save registers
        les	di, ss:[orderBuf]	; load first param
        lds	si, ss:[userDefBuf]	; load second param
        push	bp			; save bp here, not in uses
        mov	bp, ss:[pageType]	; load third param
        call	SpoolGetPaperSizeOrder	; call asm routine
        ;
        ; Restore bp here because accessing the local variables
        ; requires bp.
        ;
        pop	bp
        les	di, ss:[numBuf]		; make pointer to buffer
        ;
        ; Set the number of page size orders retrieved
        ; and those left unused.
        ;
        mov	es:[di].PSOI_numOrdered, cx
        mov	es:[di].PSOI_numUnused, dx
        .leave				; this restores registers
        ret
SPOOLGETPAPERSIZEORDERFIXED	endp

; return to C parameter-passing convention
SetDefaultConvention

; end code resource
CommonCode	ends


Missing C-stub: GeodeForEach

SDK: ALL_GEOS:PUBLIC
C Routine:  GeodeForEach
Date Fixed: n/a

In the assembly code below is a callback routine called
GeodeEnumCallback, which GeodeForEach calls for each geode it
finds on the list. GeodeEnumCallback does the actual work of
GeodeForEach. You will want to change this to fit your specific
needs.

In your C source code, preferably in a header file, you will
need to add a routine prototype declaration for GeodeForEach and
typedef a structure GeodeEnumParams. The structure can be
used to pass parameters to GeodeEnumCallback. For example,
GEP_geodeHandle should contain a GeodeHandle. (Since you
want to enumerate thru the entire list, you should pass
NullHandle for this element of the structure.) The other
elements can be used as you need them.

;---------------------begin genum.h-----------------------
void _pascal GeodeForEach( GeodeEnumParams * gep );

typedef struct {
    GeodeHandle GEP_geodeHanle;	/* geode from which to start.
                 * 0 if entire geodes list is
                   * to be traversed. */
    word GEP_callbackParamBP;
    word GEP_callbackParamDX;
    word GEP_callbackParamCX;
    word GEP_callbackParamAX;
} GeodeEnumParams;
;---------------------end genum.h-----------------------

;---------------------begin genum.asm-----------------------
include geos.def
include geoworks.def		; contains some GCN list stuff
include geode.def		; contains GeodeGetInfo structs
include Intneral/geodeStr.def	; contains GeodeType structs

global GEODEFOREACH:far		; allow c-stub to be used by externally

; This structure lets us pass register values between the C
; and the assembly routines
GeodeEnumParams	struct
    GEP_geodeHandle		word
        GEP_callbackParamBP	word
    GEP_callbackParamDX	word
        GEP_callbackParamCX	word
        GEP_callbackParamAX	word
GeodeEnumParams	ends

CommonCode	segment resource

SetGeosConvention

COMMENT @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        GeodeEnumCallback
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
PASS:		bx	= handle of geode to process
        ax, cx, dx, bp = data as passed to GeodeForEach
                 or returned from previous callback
        (for this example bx:si = app's optr)

RETURN:		if successful:
            carry set
        (for this example, carry is set by GCNList remove)

DESTROYED:	es, ds
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@
GeodeEnumCallback	proc	far
    uses	ax, bx, cx, dx, si, di, bp
    .enter

    ;
    ; Put your call-back code here.
    ; You could even call a C function from here.
    ; See the Knowledge Base for the article
    ; "How to call a C function from assembly" by searching
    ; on the keyword "assembly".
    ;

    .leave
    ret
GeodeEnumCallback	endp

COMMENT @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        GeodeForEach
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
C DECLARATION:
extern void GeodeForEach(GeodeEnumParams *gep);

DESCRIPTION:
    GeodeForEach sets up the registers for GeodeForEach.
    GeodeForEach enumerates thru the list of launched
    geodes (applications, libraries, and drivers) and
    calls a callback routine for each geode if finds.

    The callback routine must be written in assembly.
    An example of the callback routine is included in
    the assembly module below. You should modify this
    callback routine to meet your specific needs.

PASS:	GeodeEnumParams structure

RETURNS:
    on failure (geode not found) GEP_geodeHandle = NullHandle
    on success GEP_geodeHandle = GeodeHandle of geode and other
        elements of GeodeEnumParams structure filled in.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@
GEODEFOREACH	proc	far	params:fptr

    uses si, di, ds, es
    .enter

    push	ds		; save real ds

    ; load up registers
    lds	si, ss:params	; ds:si <- ptr to params

        mov	bx, ds:[si].GEP_geodeHandle
        mov	bp, ds:[si].GEP_callbackParamBP
        mov	dx, ds:[si].GEP_callbackParamDX
        mov	cx, ds:[si].GEP_callbackParamCX
        mov	ax, ds:[si].GEP_callbackParamAX

    push	si		; save ptr to params
    ; di:si = virtual far ptr to callback routine
        mov	di, cs
    mov	si, offset GeodeEnumCallback

        call	GeodeForEach

        ; restor pointer to params and put results there
    pop	si		; ds:si <- ptr to params

        mov	ds:[si].GEP_geodeHandle, bx

    ; if no geode found (bx==0), then don't waste time on rest
        tst	bx
        jz	done
        mov	ds:[si].GEP_callbackParamBP, bp
        mov	ds:[si].GEP_callbackParamDX, dx
        mov	ds:[si].GEP_callbackParamCX, cx
        mov	ds:[si].GEP_callbackParamAX, ax

done:
    pop	ds			;restore real DS

    .leave
    ret

GEODEFOREACH	endp

SetDefaultConvention

CommonCode	ends

;---------------------end genum.asm-----------------------


Revision file directory on WinNT-based GEOS SDK.

SDK: ALL_GEOS:PUBLIC
You will notice that on the WinNT-based SDK, the revision file
for your geode is expected to be in the BRANCH directory, not
your WORKING directory

This is the correct functionality. The reason for using the
BRANCH directory rather than your personal WORKING directory
is so the revision file exists in a common directory for
group projects. You want a common revision file to reflect
changes made by any of the group members.

If you want to make the tools use the revision file in your
WORKING directory, modify the geos.mk file like this:

#if   define(GEODE) && exists($(CURRENT_DIR)/$(GEODE).rev)
REVFILE     = $(CURRENT_DIR)/$(GEODE).rev

(In otherwords, change INSTALL_DIR to CURRENT_DIR.)


Broken C-stubs: HugeArrayCreate, HugeArrayGetCount

SDK: ALL_GEOS:PUBLIC
C Routine:  HugeArrayCreate
Date Fixed: 5/5/94

Suggested fix for this routine:

HugeArrayCreate:
    asm push di
    arrayBlock = HugeArrayCreate( ... );	/* pass params normally */
    asm pop  di

------------------------------------------------------------

C Routine:  HugeArrayGetCount
Date Fixed: 5/5/94

Suggested fix for this routine:

HugeArrayGetCount:
    asm push di
    asm mov  di, vmFileHandle		/* pass in vm file */
    numItems = HugeArrayGetCount( ... );	/* pass params normally */
    asm pop di


Broken C-stub: InitFileEnumStringSection

SDK: ALL_GEOS:PUBLIC
C Routine:  InitFileEnumStringSection
Date Fixed: 9/12/96

Suggested fix:

The broken c-stub had two registers swapped which caused the "key"
pointer to be invalid. You can work around this by passing a
pointer that has its high and low words swapped, thus countering
the swapping that the broken C-stub would do.


Directly accessing CIF_INK on the clipboard.

SDK: ALL_GEOS:PUBLIC
This information is only pertinant to devices that allow pen input.

Ink Format
==========
Ink on the clipboard is stored as a DBGroupAndItem. CIFI_vmChain
(which is the same as CRA_data) contains the DBGroupAndItem for the
ink item.  (Thus you can do
    myPtr = DBLock( cra->CRA_file,
            DBGroupFromDBGroupAndItem( cra->CRA_data ),
            DBItemFromDBGroupAndItem( cra->CRA_data ) );
to get a pointer to the ink data.)

The item of ink is stored in compressed format. For which the format is:

    XYSize (dword) - size of the area clipped by user
    PointBlockHeader (word) - number of points in the ink
    compacted data (as bits)

Here's the format of the compacted data:

When compacting:
    Output X delta first, then Y delta. The first X and Y values
    you output must be an absolute 15-bit position.

    if (delta == 0)
        Output (00)
    else if (delta == 1)
        Output (01)
    else if (delta == -1)
        Output (11)
    else if (delta >= -8 && delta < -1) /* Output 3-bit negative delta */
        Output (1001000 | (ABS(delta) - 1))
    else if (delta <= 8 && delta > 1) /* Output 3-bit positive delta */
        Output (1000000 | (delta - 1))
    else	/* Output 15-bit absolute position) */
        Output (1011 0000 0000 0000 000 | delta);

    At the end of each segment, output (1000000) (note, this is 7 bits,
    not 8).

When uncompacting:

        If you encounter:       it means:

    00			a delta of zero
    01			a delta of 1
    11			a delta of -1

    100 0 000		Terminate the current segment

    100 0 xxx		the xxx bits are a positive
                (delta - 1).  e.g.:
                    100 0001 = 2
                    100 0010 = 3
                    100 0011 = 4
                    100 0100 = 5
                    100 0101 = 6
                    100 0110 = 7
                    100 0111 = 8

    100 1 000		reserved for future use

    100 1 xxx		the xxx bits are a negative
                (delta - 1).  e.g.:
                    100 1001 = -2
                    100 1010 = -3
                    100 1011 = -4
                    100 1100 = -5
                    100 1101 = -6
                    100 1110 = -7
                    100 1111 = -8

    101 0 xxxxxx			the x bits are a reserved
                    keyword - not currently used

    101 1 xxxx xxxx xxxx xxx	the x bits are an absolute
                    position, not a delta

You will always encounter a 1011 token (an absolute position) before
encountering any deltas.

Here is an example of the compressed ink data for the number '4'.
And to ellucidate, here is a picture of what the 4 looks like (note
the two coordinates are given to help orient you).

          *--(3,0)
(0,1)--*  *
       *****
          *
          *

First line drawn is the "side-ways L" part. It goes down from 0,1 and
cuts right to 4,2. The second line is the main vertical. It starts at
3,0 and goes down to 3,4.

Thus the data in the clipboard is:

XYSize = 6,6 				(6x6 is just an arbitrary number)
numPoints = 5				(there are 5 coordinate points)
data =	101 1 0000 0000 0000 000	(initial X)
    101 1 0000 0000 0000 001	(initial Y)
    00				(X no delta)
    01				(Y delta 1)
    100 0011			(X delta 4)
    00				(Y no delta)
    100 0000			(end of first segment)

    101 1 0000 0000 0000 011	(initial X)
    101 1 0000 0000 0000 000	(initial Y)
    00				(X no delta)
    100 0011			(Y delta 4)
    100 0000			(end of second segment)


Manually setting the MailboxRegisterMessageArgs for email.

SDK: N9000C:PUBLIC
The following is a rough description of the values to set for manually
sending an emaill on the Nokia 9000 Communicator.

    MRA_bodyStorage.MS_id    = GMSID_VM_TREE
    MRA_bodyStorage.MS_manuf = MANUFACTURER_ID_GEOWORKS
    MRA_bodyFormat.MDF_id    = GMDFID_TEXT_ARRAY
    MRA_bodyFormat.MDF_manuf = MANUFACTURER_ID_GEOWORKS
   *MRA_bodyRef              = pointer to VMTreeAppRef
        VMTAR_vmChain = VMBlockHandle in upper word referencing
                HugeArray that is the text of the email
        VMTAR_vmFile  = VMFileHandle returned by MailboxGetVMFile()
    MRA_bodyRefLen           = sizeof(VMTreeAppRef)
    MRA_transport.MT_id      = GMTID_SMTP
    MRA_transport.MT_manuf   = MANUFACTURER_ID_GEOWORKS
    MRA_transOption          = 0
   *MRA_transAddrs           = pointer to MailboxTransAddr
        *MTA_transAddr = pointer to MBACAddress
                MBACA_opaqueSize = 2
                MBACA_opaque = string of chars (not a pointer)
                    to the Sending host (see Sending
                    settings in the Mail app on the 9000)
        MTA_transAddrLen = 35h  (seems to always be 35h)
        *MTA_userTransAddr = pointer to string (usually the user
                name portion of the email address)
    MRA_numTransAddrs        = 1 (there's always only one MailboxTransAddr)
    MRA_transData            = DBGroupAndItem referencing an
                EnvelopeInTransData struct (as defined
                by Nokia) in the mailbox admin file.
        EITD_fileName[36] = name of file to contain message
                    ("Messages 0")
        EITD_VMFileHandle = VMFileHandle to file containing
                ENVELOPE and ADDRESS info.  This is
                usually the same as VMTAR_vmfile.
        EITD_VMBlockHandle = VMBlockHandle of block containing
                ENVELOPE and ADDRESS info
        EITD_MimeEncoding = 1-on, 0-off
        EITD_numFiles = 0  (seems to always be zero)
    MRA_flags                = MMF_PRIORITY = MMP_FIRST_CLASS
                               MMF_VERB     = MDV_READ
                               MMF_DELETE_BODY_AFTER_TRANSMISSION
   *MRA_summary              = pointer to a text string (usually the
                email's subject)
    MRA_destApp.GT_chars     = "NBOK"
    MRA_destApp.GT_manufID   = MANUFACTURER_ID_GEOWORKS
    MRA_startBound           = MAILBOX_NOW
    MRA_endBound             = MAILBOX_ETERNITY

ENVELOPE structure
    VMChainTree vmt.VMCT_meta.VMC_next = VM_CHAIN_TREE
                vmt.VMCT_meta.VMC_offset = 24h (seems to always be 24h)
                vmt.VMCT_meta.VMC_count = equation for this seems to be
            13 + (5 * number of TO, CC, and BCC addresses).
            example: if you send to one person and CC two,
            people, that is 3, so the value is (13+5*3)=28.
    word        link_id      = 2  (seems to always be 2)
    dword       return_path  = -1
    dword       from         = zero-based index into the array of ADDRESS
                structures.  (usually this is index zero)
    dword       sender       = -1
    dword       reply_to     = -1
    dword       to           = zero-based index into the array of ADDRESS
                structures.  (usually this is index 1).
                The trans driver will put all the elements
                        in the array from the "to" index up to
                (but not including) the "cc" index into
                the email's TO line.
    dword       cc           = zero-based index into the array of ADDRESS
                structures.  (must be greater than "to")
                The trans driver will put all the elements
                        in the array from the "cc" index up to
                (but not including) the "bcc" index (or
                     last element if no bcc) into the email's
                CC line
    dword       bcc          = -1
    dword       remail       = 0
    dword       date         = DBGroupAndItem containing date string
                  vmfile is that defined in EITD_VMFileHandle.
                ("Wed, 23 Jul 1997 15:52 0042")
    dword       subject      = DBGroupAndItem containing subject string
                (same as MRA_summary)
                vmfile is that defined in EITD_VMFileHandle.
    dword       in_reply_to  = 0
    dword       message_id   = 0
    dword       newsgroups   = 0
    dword       sending_host = DBGroupAndItem containing the sending host
                (see notes under MTA_transAddr)
                vmfile is that defined in EITD_VMFileHandle.
    dword       next         = 0

ADDRESS structure
    notes: The ADDRESS structure lives in the same block as the
           ENVELOPE structure.  Directly following the ENVELOPE
           structure is an array of ADDRESS structures.  The first
           (zero) element in the array is the sender's email address.
           Following that are the email addresses for the to, cc,
           and bcc elements of the ENVELOPE structure.

    dword personal  = 0
    dword adl       = 0
    dword mailbox   = DBGroupAdnItem containing username part of email
            address (all the stuff before the @)
            vmfile is that defined in EITD_VMFileHandle.
    dword host      = DBGroupAdnItem containing domain name part of email
            address (all the stuff after the @)
            vmfile is that defined in EITD_VMFileHandle.
    dword error     = 0


Missing C-stub: ObjSetEventInfo

SDK: ALL_GEOS:PUBLIC
C Function:   ObjSetEventInfo
Date Removed: 7/25/97

This function was removed from the object.h file on 7/25/97 because
it has been replaced by MessageSetDestination.


Broken C-stub: SpoolCreatePrinter

SDK: ALL_GEOS:PUBLIC
C Function: SpoolCreatePrinter
Date Fixed: 7/25/97

This c-stub had a byte-sized parameter which caused a problem with
the stack. There is no work-around for this routine on devices
before this fix was made.


Broken C-stub: SpoolGetNumPrinters

SDK: ALL_GEOS:PUBLIC
C Function: SpoolGetNumPrinters
Date Fixed: 7/25/97

This c-stub had a byte-sized parameter that caused a problem with
the stack. There is no work-around for this function on devices
before the fix was made.


Avoiding having the focus move to a GenTrigger.

SDK: ALL_GEOS:PUBLIC
To prevent a GenTrigger from grabbing the focus when it
is clicked on, put it inside a GenInteraction which has
HINT_TOOLBOX set.


Using grev on the Windows NT-based GEOS SDK.

SDK: N9000C:PUBLIC
grev for the Windows NT-based SDK was not working correctly before
August 1, 1997. The problem was that the .mk files are passing a
-b (branch) option to grev. Then grev looks in the .rev file for a
revision for that branch. There isn't a "newbranch" for the ntsdk
so the user can't specify a branch revision.

The easiest fix is to change the global .mk so it doesn't pass .
The only problem with this is a developer can't use the same .rev for
multiple branches. To make this fix, edit the Include/win32/geos.mk file
and delete lines 344-346.

A fix was made to correct this problem for future NT-based SDKs.


Broken C-stub: FoamDBBinarySearch

SDK: ALL_GEOS:PUBLIC
C Function: FoamDBBinarySearcy
Date Fixed: 7/30/97

This routine did take a pointer to a callback routine and thus did not
correctly set up the parameters for the call to the assembly routine.
This led to a jump into space and prossible crash.

There is no work-around for this bug.


0x11 (17) bytes being filtered of the inbound serial stream

SDK: ALL_GEOS:PUBLIC
If you have turned on software flow control or are using
SERIAL_MODE_RARE, the system will filter out 0x11 bytes in
the inbound serial stream because it thinks these bytes are
XON flowcontrol commands.

     XON = ctrl-q = 0x11 = 17
    XOFF = ctrl-s = 0x13 = 19

If you are sending these bytes as data, you should turn off
software flow control and not use SERIAL_MODE_RARE.

SerialMode defines how the data is filtered when received.  Here is
the definitions of the serial modes as I understand them:

SERIAL_MODE_RAW
    Do not filter input stream (including XON and XOFF).

SERIAL_MODE_RARE
    Same as _RAW, but obey XON/XOFF flow-control and use it on input.

SERIAL_MODE_COOKED
    Obey software flow-control. Also strip the high bit from the
    input stream (i.e., 7-bit input bytes).


Broken C-stub: WinScroll

SDK: ALL_GEOS:PUBLIC
C Function: WinScroll
Date Fixed: 7/21/97

This c-stub was not taking the correct types and number of parameters
and was basically not useful. There is a work-around for devices made
before the fix was installed, shown below:

You have to remove the 'WinScroll' definition and the 'WINSCROLL' alias
line from 'win.h'. Then GLUE links the WinScroll call to the assembler
routine rather than to the c-stub. You have to make the function call
outside the ASM part because the internal assembler would only create
a fixed far call instead of a relocatable call.

void far WinScroll( void );
void C_WinScroll( WindowHandle   win,
                  WWFixedAsDWord xMove,
                  WWFixedAsDWord yMove,
                  PointWWFixed * scrollAmt )
{
  asm {
    mov     dx, word (xMove+2)
    mov     cx, word (xMove)
    mov     bx, word (yMove+2)
    mov     ax, word (yMove)
    mov     di, win
  }
  WinScroll();
  asm {
    mov     word (scrollAmt).PF_x.WWF_int, dx
    mov     word (scrollAmt).PF_x.WWF_frac, cx
    mov     word (scrollAmt).PF_y.WWF_int, bx
    mov     word (scrollAmt).PF_y.WWF_frac, ax
  }
};


Using Shipper

SDK: OMNIGO:PUBLIC
The basic concept behind the Shipper program is it allows you to create
"packages" for OmniGo users. These packages contain the files that you
place in the packages. A package is then read by the Installer program
and installs the files in the package to the user's OmniGo. Typically
you create a package that contains e-books made with Bindery. Developers
who write programs for the OmniGo also use Shipper to allow users to
install their programs onto their OmniGo.

I will only cover the basics of using Shipper as the online help is
quite extensive and explains all the details about using Shipper.

First, start Shipper. This displays a blank "package" screen. You can
fill in the title and description of your package in this screen.
Then you can add files to the package by clicking the "Add Files" button.
These files will be stored in the package. The Installer program will
later take these files and copy them to the OmniGo.

For each of the source files in the package, be sure to specify the
correct destination path. This specifies the location where the file
will be copied to on the OmniGo itself. Since the path is dependent
on the type of file you're installing, I won't get into what valid
destination paths are.

The version number for a source file simply tells the Installer whether
this file should replace a file if it already exists on the OmniGo.
So if you make a new version of your package, simply increment the
version number and Installer will overwrite the old version of the file
on the OmniGo.

Once you've done all of this you can now save the package to a file.
Do this by selecting Save from the File menu. A dialog appears in which
you can specify the location and name for the package. Once the package
is saved you can make this package available to other users who will
use the Installer program to install the package files to their OmniGo.


How to have transparent backgrounds on bitmaps.

SDK: N9000C:PUBLIC
Q. Is it possible in GEOS, especially on the Nokia 9000, to have
   icons with transparent backgrounds?

A. If you've got a PCX file that you want to convert to an icon,
   the 'm' switch in cvtpcx allows you to say that one of the colors
   is masked out. You need to know the decimal number corresponding
   to the color - a program like Paint Shop Pro or Neopaint should
   tell you this info. From the documentation on cvtpcx:

    -m     Pixel to be masked out. Any pixel containing this
                  color (a decimal number) will be given a 0 bit in
                  the mask for the color bitmap. Defaults to none.

   Light cyan is used for the transparent mask on the N9000. Specify
   that light cyan is the mask in the cvtpcx script with "-m11".


What does MSG_GEN_APPLICATION_INSTALL_ICON do?

SDK: ALL_GEOS:PUBLIC
The message MSG_GEN_APPLICATION_INSTALL_ICON when sent to a GenApplication
object calls the following:

TokenGetTokenInfo() - see if token is already defined or not
TokenDefineToken()  - if not defined, define it now


Broken C-stub: GrMapColorRGB

SDK: ALL_GEOS:PUBLIC
C Function: GrMapColorRGB
Date Fixed: 1/23/97

This routine was treating the index pointer as a pointer to a word and
thus trashing the byte next to the byte pointed to by index. The only
work-around is to put trashable bytes around the variable pointed to
by index.


Setting up the Nokia 9000 Emulator for internet access

SDK: N9000C:PUBLIC
Extensive instructions for setting up the Nokia 9000 emulator
for internet access exist in the Mobile Publisher Program
section of our web page.  Within that section, select the
Development Aids link and then the Emulator Information link.


My localizable strings aren't appearing in ResEdit.

SDK: ALL_GEOS:PUBLIC
Q. I've got a resource defined like so:

   @start Strings, data;
   @chunk TCHAR ErrorMessage[] = "There was an error.";
   @localize "an error message that should be localized";
   @end Strings;

   The problem is when you try to localize this in ResEdit you can't see
   the "Strings" resource at all. What am I doing wrong?

A. How is the resource listed in the .gp file? If you have it marked as
   "data" then it will not be editable by ResEdit. Instead, use "lmem"
   which implies "data" but still allows the strings to be localized.


80x86 interrupts

SDK: ALL_GEOS:PUBLIC
Q. On 80x86, what are some examples of maskable interrupts that are not
   IRQ's?

   Can divide-by-zero interrupt or "INT 21h" interrupt happen when the
   interrupt flag is clear?

A. IRQs are the exception rather than the rule. They are only maskable
   because the CPU has the ability to ignore the INT signal generated by
   the interrupt controller (by clearing the interrupt flag) and because
   the interruper controller itself can mask out the interrupt request.

   Interrupts are not maskable, but some can be prevented at the source.
   This is what happens when you mask an IRQ (the interrupt controller
   prevents the INT signal from being raised) or if you CLI (the CPU
   ignores the INT line).

   Exceptions, like divide-by-zero, will generate an interrupt no matter
   what. It does not use the INT signal, it is generated internally by the
   CPU. Likewise, INT21h is a software interrupt. If some software is
   running with interrupts disabled and executes an INT 21h (or INT
   anything, really), then the INT 21h handler will be executed no matter
   the state of the Interrupt flag.

   The way an IRQ happens is that the PIC (interrupt controller) has a
   signal raised on one of its IR (interrupt request) lines. If that IR
   isn't masked and an interrupt of a higher priority isn't currently being
   services (EOI hasn't been sent yet), the PIC will raise the INT line to
   the CPU. When the CPU is ready to process the interrupt (Interrupt flag
   must be set!), the CPU will respond with an INTA (interrupt
   acknowledgement) signal which tells the PIC that the next interrupt will
   be serviced. Then the CPU generates another INTA signal (after INT is
   lowered?) that tells the PIC to put the offset into the interrupt table
   on the bus. The CPU reads this offset and generates the appropriate
   interrupt (INT8 for IRQ0, for example). I thought it was interesting
   that the actual offset into the interrupt table comes from the PIC, not
   the CPU, but anyway. Once the interrupt handler has completed, the EOI
   (end of interrupt) is sent to the PIC. If another, lower or equal
   priority interrupt has occurred, the cycle repeats.

   That's probably more than you wanted to know, but I thought I should
   share this wonderful information that I read from an 8259 Intel PIC spec
   a couple of years ago.

   By the way, the NMI is also just another INT (INT 2, to be exact). It
   is generated by the CPU similarly to how divide-by-zero is generated,
   although external sources can generate it by raising the CPUs NMI line.
   Contrary to its name (non-maskable interrupt), it can be masked. There
   is a bit in some I/O register (I can't remember which one.. PORTB, I
   think?) that prevents the CPU from generating an NMI.

   Keep in mind that it's maskable only with external hardware, as opposed
   to INT. Note also that having the PIC provide the vector number means
   the PIC can be told to place those IRQ levels anywhere in the interrupt
   table you want. The PC designers decided to put them at INT8, but got
   wise when the AT came along and put them at 70, out of the space Intel
   had reserved for their own use (and which Intel used in the 80286 and
   later chips).


Adding an object to the keyboard path in ESP.

SDK: ALL_GEOS:PUBLIC
Q. I've got a Generic object in ESP and I want it to be in the
   keyboard search path. I've defined the genAttributes like so:

      genAttributes = default +targetable, +kbdPath;

   But it's not compiling, saying that this is a syntax error.

A. kbdPath is a keyword in UIC, so you can't use it as the name of an
   attribute. The syntax for kbdPath is as follows:

      class GenViewControl = GenControl, kbdPath {
          .
          .
          .
      }

   This allows UIC to set the GA_KBD_SEARCH_PATH bit on all objects
   up the generic tree.


The token database as it is stored in ROM.

SDK: ALL_GEOS:PUBLIC
Q. How is the token database stored on devices? Is there a default
   database stored in ROM? What happens when new tokens are added?
   Can I remove tokens that are a part of the default set?

A. Yes, there is a default one in ROM which is not modifiable. You
   cannot remove any default icons. New tokens are added to a local
   token_da.000 in the Flash RAM. You can overwrite those tokens and
   the local one is searched before the default one.


The proper usage of @localize and monikers.

SDK: ALL_GEOS:PUBLIC
The big things that would aid the localization process are:

- @localize instructions on almost every string, especially
  all of the non product-specific system geodes.

- Get rid of any unused strings in the system, so it's clear
  to localizers that they don't have to be changed.

- Change any UI, in both system and app geodes, so that
  definitions like:

     @object GenTriggerClass Foo = {
         GI_visMoniker = "Bar";
     }

  is instead:

     @visMoniker BarMoniker = "Bar";
     @object GenTriggerClass Foo = {
         GI_visMoniker = @BarMoniker;
     }

  The second version is more clear to the localizer, and more
  importantly, ResEdit can track it when chunks move around
  from one build to the next, and knows not to throw up its
  hands. Apparently this is a supreme headache for localizers.


Dialup scripting on N9000

SDK: N9000C:PUBLIC
Q. I am interested in setting up a system which will run a script before
   making a PPP connection for Internet access. We have a client who's IP
   requires interaction (to choose server, ID, password, etc.) BEFORE the
   PPP is established.

A. The Nokia 9000i PPP stack includes a scripting module that can:

   - Await input and send responses.
   - Parse IP addresses from the input and use them as the DNS
     server to use, and/or local IP address of the device.
   - Prompt the user for simple string responses (like username,
     password, etc.)

   There is no support for anything like this in the previous PPP driver.


Where to place temporary files on the Nokia 9000.

SDK: ALL_GEOS:PUBLIC
Q. I want to create a "temporary" VM file that will be wiped out if
   the device is rebooted. Shall I simply put the file in the SP_STATE
   directory (which is emptied automatically on startup on Responder),
   or does another more appropriate directory have this behavior, or is
   there an attribute I can stick on the VM file (I couldn't find one)
   to force this feature?

A. Put it into SP_WASTE_BASKET which is actually [state], that is
   cleaned when GEOS boots.


Keeping the focus object visible in a scrolling GenView.

SDK: ALL_GEOS:PUBLIC
Q. If I've got a GenView/GenContent pair set up to contain several
   generic objects, I have to intercept MSG_META_KBD_CHAR and
   manually set the focus to the next object if the user presses
   the Tab key. For some reason, when tabbing to an object that is
   not visible the view will not always scroll to make it visible.
   The same is true when intercepting a Shift-Tab and calling
   MSG_GEN_NAVIGATE_TO_PREVIOUS_FIELD. What am I doing wrong? How
   do I get the tab key to make the item visible when it gets the
   focus?

   And using the cursor up/down keys for object navigation seems
   pretty inconsistent about making objects visible. It seems that
   both cursor up/down and my manual Tab key handling do almost the
   same thing.

A. Handling the Tab key presses shouldn't be necessary. Gen objects
   in GEOS already use the Tab key for navigation, even in a GenView.
   Make sure that the GenContent object has the hint
   HINT_CONTENT_KEEP_FOCUS_VISIBLE, which will scroll the view
   whenever the focus changes.


Code names in the GEOS header files

SDK: ALL_GEOS:PUBLIC
The following is a list of not-so-confidential code names that
you may find in the GEOS header files. This list is meant only
to satiate curiosity.

Bullet
     Sharp PT-9000 project (tablet sized PDA).

Clavin
     The Mailbox (inbox/outbox) universal communication project for
     GEOS 3.0.

Condo
     A project to create a hypertext book reader (and a corresponding
     authoring tool) for the OmniGo and Ensemble products.

Foam
     The main utility library for the Nokia 9000 Communicator products.
     A euphemism for Phone.

Jedi
     HP Omnigo 100 project.

Leia
     HP Omnigo 120 project.

Nike
     Brother Ensemble Personal Desktop Publisher project
     (dedicated word processor).

Pizza
     Project to localize GEOS to Japanese (DBCS support).

Redwood
     Canon StarWriter Pro 5000 Personal Publishing System (PPS) project.

Wizard
     IBM Schoolview project.

Zoomer
     Casio Z-7000 PDA. Also marketed with AST, and Tandy.


How to use WWFixed (and its ilk) variables

SDK: ALL_GEOS:PUBLIC
All the mathematical functions for WWFixed are in the graphics.h
header file.

The following macros are provided to help in manipulating WWFixed
variables:

MakeWWFixed
    Creates a WWFixed structure from a floating point number
    or dword number.

WWFixedToFrac
    Returns the fractional part of a WWFixed.

WWFixedToInt
    Returns the integer part of a WWFixed.


How to use FileID for something useful.

SDK: ALL_GEOS:PUBLIC
Q. How do I turn a FileID into a file name?

A. You'll need to save the FileID of the files you are interested
   in, then check if it matches the FileID passed in the notification.
   The FileID is an extended attribute. You can get it with
   FileGetHandleExtAttributes or FileGetPathExtAttributes or you can
   have it returned by FileEnum.


FileSelector focus showing when it shouldn't?

SDK: N9000C:PUBLIC
Q. And about FileSelectors, they used to not have the selection bar when not
   focused, and a HINT_FILE_SELECTOR_SHOW_SELECTION_EVEN_WHEN_NOT_FOCUS to
   change that. Now this hint seems to be forced on.

A. When we added multi-selection to list objects, there were these big
   visual glitches with the selection bar. We really tried to fix it in
   other ways, but they all had their problems, and in the end, the fix
   ended up being one that caused the selection bar always to be shown
   (although maybe only for non-exclusive lists).

   The only case on the existing Lizzy software where a list could lose
   the focus anyway was in the file transfer view, which also used a
   thick black border to indicate focus. So it was decided that this
   change was OK. Kind of makes these hints worthless, though.


The normal keys down count is zero?

SDK: N9000C:PUBLIC
Q. I get the following warning every time I press the Tab key in my
   MSG_META_KBD_CHAR handler for my VisText class:

     WARNING_NORMAL_KEYS_DOWN_COUNT_BEING_ZERO_BEFORE_DECREMENT

   I am filtering out the tab keys and handling them specially.

A. If you don't @callsuper when flag is CF_FIRST_PRESS, but @callsuper
   when it is released, VisText is going to complain because it is
   keeping count of the number of keys pressed at the same time. This
   warning is being taken out in newer versions of the Nokia 9000i.


I get TOO_MANY_PRIMARY_FSDs in Swat.

SDK: ALL_GEOS:PUBLIC
If you're trying to run a GEOS demo and you get the error:

TOO_MANY_PRIMARY_FSDs

just change the fs line under the [system] category to be the
primaryFSD line. That will force GEOS to load only the specified
file system driver and not attempt to load anything else based on
the DOS version on your system.

Another solution is to run the setver command and add two entries
to it, like so:

setver loader.exe 9.0
setver loaderec.exe 9.0

This tricks GEOS into using the correct FSD (whatever that is).


Viewer library change regarding the undo feature.

SDK: N9000C:PUBLIC
Q. If I use the SDK_9000/FileSel sample to open a newly created Notes
   document it will crash with UNDO_OBJECT_MUST_BE_RUN_BY_PROCESS_THREAD.
   What needs to be done to avoid this crash?

A. The NotesEdit library supports undo, unfortunately, this only works if
   the app that launches it has only one thread (i.e., no app UI thread).
   As a workaround, when you call the Viewer library (ViewerLibraryOpen)
   you can pass VA_NO_UNDO to ensure the undo feature is not used.


What does IACPSendMessageAndWait() do exactly?

SDK: ALL_GEOS:PUBLIC
Q. Is it true that this call returns as soon as the message being
   sent is placed on the destination queue, and not after the
   message has been handled, which means that you cannot reliably
   used any return values from the message?

A. The call will not return until the IACP Server (usually the
   GenApplication object) has executed the method handler for
   the the message, so that's not the problem.

   The problem with return values is that the message is actually
   delivered via a force-queue, so there is no way to return a
   value directly.


Parse error caused by missing semicolon.

SDK: ALL_GEOS:PUBLIC
Here is some example output from pmake:

> pmake
Error FILE.GOC 297: This chunk () is not localizable
Error FILE.GOC 298: parse error
Error FILE.GOC 301: parse error
Error FILE.GOC 301: CMI_topText is not a valid instance variable or vardata element for this object

Now here is the code that is causing the problem:

@object class name = {
     // usual stuff here
     HINT_DRAW_SHADOW;
     HINT_FIXED_SIZE = {
          SST_PIXELS | FOAM_DEFAULT_COMPONENT_WIDTH + 25, 0, 0
     }
}

Notice the missing semicolon after HINT_FIXED_SIZE. After adding a
semicolon after the closing brace of the HINT_FIXED_SIZE the code
will compile correctly.


Dynamic heap space request.

SDK: ALL_GEOS:PUBLIC
Q. Is there any way for a geode to dynamically request more heap space
   for itself? I want to allocate a memory block to cache some data,
   but I won't know how big to make it until the geode actually runs.
   Instead of adding the worst possible case to the geode's heapspace
   parameter, I'm wondering if there's a function I can call to inform
   the system that I'm going to now take more heap than I promised when
   I launched, so it can decide whether to detach more apps.

A. Use GeodeRequestSpace followed by GeodeReturnSpace. This will allow
   you to reserve an amount of heapspace and then actually acquire it.
   The parameters for GeodeRequestSpace are 'amount' and 'gh' which is
   the amount of space required in kilobytes and the GeodeHandle of the
   application that requires the space. Pass the returned
   ReservationHandle to GeodeReturnSpace when you're done to make the
   space available to other applications.


KR-xx error codes and a brief description of each.

SDK: ALL_GEOS:PUBLIC
KS_TE_DIVIDE_BY_ZERO			KR-01
KS_TE_OVERFLOW				KR-02
KS_TE_BOUND				KR-03
KS_TE_FPU_EXCEPTION			KR-04
KS_TE_SINGLE_STEP			KR-05
KS_TE_BREAKPOINT			KR-06
KS_TE_ILLEGAL_INST			KR-07
KS_SYS_EMPTY_CALLED			KR-08
KS_ILLEGAL_HANDLE			KR-09
KS_BAD_MOVE_BLOCK			KR-10
KS_HANDLE_TABLE_FULL			KR-12
KS_CANNOT_ALLOC_LOCAL_MEM		KR-13
KS_UNRECOVERABLE_ERROR_IN		KR-14
KS_LOW_ON_HANDLES_2			KR-15
KS_MEMORY_FULL2				KR-16
KS_SWAP_DEVICES_FULL_PART_TWO		KR-17
KS_SWAP_IN_ERROR			KR-18
corruptedIniBufferStringOne		KR-20
objLoadError1				KR-21
objVMLoadError1				KR-22
KS_CANNOT_LOAD_MEMORY_VIDEO_DRIVER	KR-25
KS_CANNOT_LOAD_KEYBOARD_DRIVER		KR-26
KS_CANNOT_LOAD_UI			KR-27
KS_BAD_FONT_PATH			KR-28
KS_NO_FONT_FILES			KR-29
KS_DEFAULT_FONT_NOT_FOUND		KR-30
KS_UNSUPPORTED_DOS_VERSION		KR-31
KS_UNABLE_TO_REGISTER_TOP_LEVEL_DISK	KR-32
KS_FILE_SYSTEM_DRIVER_FOR_DRIVE		KR-33
KS_NOT_LOADED				KR-33
KS_PRIMARY_FSD_NOT_LOADED		KR-34
unableToExit				KR-35
noSpaceForIniString2			KR-36


Reading the GeosFileHeader of a VM file

SDK: ALL_GEOS:PUBLIC
Q. How can I open a GEOS file and be able to read the entire file,
   including the special 256 byte GEOS file header?

A. Set the high bit of the FileAccessFlags (which is essentially setting
   the FFAF_RAW) when you call FileOpen().  This will open the file as
   if it were a plain DOS file.


Printing the objects on a GCN list from Swat.

SDK: ALL_GEOS:PUBLIC
You can check what objects are on a particular GCN list by using the
Swat 'pobjgcnlist' command. Here's the basic syntax:

  pobjgcnlist GAGCNLT_WINDOWS [appobj cmgr]

Type "help pobjgcnlist" in Swat for more details.


Broken C-stub: SpoolGetPaperSize

SDK: ALL_GEOS:PUBLIC
C Routine:  SpoolGetPaperSize
Date Fixed: 9/12/97

This routine would trash register bp and thus would trash memory
as it tried to return the sizeInfo struct. There is no work-around
for this problem.


What is SEGMENT_CS and how is it used?

SDK: ALL_GEOS:PUBLIC
Q. What is the difference between:

    mov	bx, SEGMENT_CS

   and

    mov	bx, cs

A. The first one generates XIP-friendly references to the current code
   resource, which can be passed to API's that allow addresses to be
   expressed by virtual far pointer. Virtual far pointers are used by
   certain routines (ProcCallFixedOrMovable) to signal that the resource
   has to be locked/loaded before the pointer can be used.

   if	_FXIP
    SEGMENT_CS	equ
   else
    SEGMENT_CS	equ
   endif


Hex number format in source files.

SDK: ALL_GEOS:PUBLIC
Q. I have a .ui file has these lines:

    gstring {
        GSBeginString
        GSDrawBitmapAtCP <(EndInkTestLCIcon-StartInkTestLCIcon)>
        StartInkTestLCIcon label byte
        Bitmap <64,40,BMC_PACKBITS, mask BMT_MASK or BMF_4BIT>
        db	0feh, 000h, 001h, 00fh, 0c0h, 0feh, 000h
        db	0f3h, 0ddh, 002h, 070h, 000h, 007h, 0f2h, 0ddh
        ......

   When I do mkmf, CPP32.EXE complains "Error : incorrect
   number format". If I change the numbers to 0xnn, the error goes away.

   If I do "set cpp=cpp.exe" before running mkmf, it can handle 0nnh
   format without error. Is this the expected behavior?

A. This is a problem when the Borland preprocessor is used instead of
   uicpp.exe for processing .ui files. The Borland preprocessor does
   more than just process '#' directives: it inserts spaces around the
   numbers, for an unknown reason, which ESP then chokes on.
   I don't know why mkmf is using bcc32 instead of uicpp.


What does the 'Change' button send out?

SDK: N9000C:PUBLIC
Q. What message does the "Change" button send out when it's activated?
   This is the button that shows up automatically in a GIT_PROPERTIES
   type GIV_DIALOG.

   I'm having trouble getting this type of screen of these to show up
   when it's the 1st screen displayed by the app, so I'd like to
   incorporate the change button on a GIT_ORGANIZATIONAL interaction
   first screen, and in a different spot (slot 1), and be able to
   interact with some GenItemGroups on this screen.

A. It sends MSG_GEN_GUP_INTERACTION(IC_CHANGE) up the GenTree, to be
   handled by the dialog object. It doesn't look like GenPrimaries
   handle it, only GIT_PROPERTIES dialogs.

   If your dialog is not a GIT_PROPERTIES, and you still want a CHANGE
   trigger, you'll need to explicitly define one in your UI tree, with
   ATTR_GEN_INTERACTION_COMMAND = IC_CHANGE. You need not supply a
   moniker - the standard one will be added by the spui.


hardIconBar entries disappear from the geos.ini file

SDK: N9000C:PUBLIC
Q. I've got a Nokia 9000 demo running and I have just one geos.ini file
   that contains all the usual settings. Everything runs fine in the
   demo except that F8, F12, and Ctrl-F12 don't do anything (they should
   normally launch Services, System, and Extras respectively). I add
   the appX entries to the [hardIconBar] category of the geos.ini file
   but as soon as I start the demo those fields disappear. What is
   going on?

A. Those three entries change dynamically at run time. If you use F8 to
   launch the Services app, then use the Services app to launch www,
   the F8 key will be reassigned to launch www instead of Services.

   When the system reboots we want to make sure that F8 launches Extras
   again, so the system clears the entry. The good entries should be
   in net.ini anyway. Yes, you have to keep a net.ini around.


TIMER_EVENT_ONE_SHOT vs. TIMER_EVENT_CONTINUAL

SDK: ALL_GEOS:PUBLIC
Q. We were told to use lots of TIMER_EVENT_ONE_SHOT instead of one
   TIMER_EVENT_CONTINUAL. Why? I use a timer that updates seconds
   on-screen. If I used lots of ONE_SHOT timers instead of one
   CONTINUAL, wouldn't the timing get wrong?

A. I think the concern here is that if the thread receiving the
   continual timer events blocks for a long period of time, a lot
   of events will get placed in the queue.  When the thread continues
   processing, it will get bombarded with timer events, possibly
   causing problems with the logic of the program, or causing a lot
   of flickering updates or something.

   If you use one shot timers, you know that you are going to receive
   exactly one event. But you're right, you shouldn't use a series of
   one one-shots for precision timing. If you need to know the precise
   time when one of these events go off, query it from the system
   instead of counting timer events.


Using '@send, forceQueue @visChildren' causes a crash.

SDK: ALL_GEOS:PUBLIC
Q. In my VisContent class I'm doing something like the following in
   one of the methods:

   @send, forceQueue @visChildren::MSG_VIS_REDRAW_ENTIRE_OBJECT();

   However, this crashes with a BAD_FLAGS_CANNOT_BE_USED_WITH_MF_RECORD
   death error in Swat. If I remove the ", forceQueue" then it works
   fine. Why is that?

A. That's because the @visChildren is implemented in such a way that
   it uses the MF_RECORD flag when calling ObjMessage and you can't
   have both the MF_RECORD and MF_FORCE_QUEUE on the same message.

   I don't know what this means as far as trying to work around it and
   force the message onto the receiving object's message queue. I would
   bet that because it's an @visChildren that the message will
   automatically go onto the message queue.


Lid just opened on Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
Q. Is there a way to detect if the lid has just been opened on the
   Nokia 9000 Communicator? Or how about when the phone goes on or
   off?

A. Yes, you can register for noticiations by adding yourself to the
   GCNSLT_RESPONDER_NOTIFICATIONS GCN list. Wait for the message
   MSG_META_NOTIFY and check for the GWNT_RESPONDER_NOTIFICATION
   notification type in the notificationType parameter. Check the
   data parameter for one of several ResponderNotificationType's.
   The two you're interested in would be RNT_LID_OPEN and
   RNT_LID_CLOSED. There are more listed in
   Include/Internal/respondrStr.def and CInclude/Internal/respondr.goh.


Minimize size on item group loses keypresses.

SDK: ALL_GEOS:PUBLIC
Q. If I use HINT_ITEM_GROUP_MINIMIZE_SIZE in the MainHotList below, all
   trigger keypresses are lost. How can I minimize the list size and
   still use triggers? This is on the Responder.

   @object GenDynamicListClass MainHotlist = {
        GIGI_destination = @MainHotlist;
        GDLI_numItems = 0;
   // this hint causes the problem
        HINT_ITEM_GROUP_MINIMIZE_SIZE;
        HINT_ITEM_GROUP_SCROLLABLE;
        HINT_ITEM_GROUP_SHOW_SELECTION_EVEN_WHEN_NOT_FOCUS;
   }

   @chunk TCHAR titleMainUrl[] = "Address";
   @object ComplexMonikerClass MainUrl = {
        ComplexMoniker = WWWGreyFrameClass;
        CMI_topText = @titleMainUrl;
        GI_comp = @MainUrlBox;
        HINT_EXPAND_WIDTH_TO_FIT_PARENT;
        HINT_PLACE_MONIKER_TO_RIGHT;
   }

   @object TextWithListClass MainUrlBox = {
        GTXI_attrs = @default | GTA_SINGLE_LINE_TEXT;
        GTXI_maxLength = GD_MAX_LEN_URL;
        TWLC_listObj = MainHotlist;
        HINT_DEFAULT_FOCUS;
        HINT_EXPAND_WIDTH_TO_FIT_PARENT;
   }

   Removing the hint makes the command triggers (F1-F4) work again. I
   watched for MSG_META_KBD_CHAR and it goes to all the same objects with or
   without the hint. It seems to be something in the way the dynamic list
   handles the keypresses based on the hint.

A. MINIMIZE_SIZE causes dynamic lists to turn into popup lists, not to
   make them smaller, which sounds like what you're trying to do. When a
   list becomes a popup list it will eat the keypresses.


InitFileSave() and what it really does.

SDK: ALL_GEOS:PUBLIC
There is a bit of confusion about InitFileSave. Despite it's name and
header ("Saves the initfile") it does not save/commit anything to
geos.ini. It makes a backup copy of geos.ini in privdata/ini.bak.


Keypresses don't reach triggers from TextWithList object.

SDK: N9000C:PUBLIC
Q. I have the following dialog in my application and all the keypresses
   are eaten by the text object such that the triggers no longer work.
   What could be wrong here?

   @object TextWithListClass SearchBox = {
      GTXI_attrs = @default | GTA_SINGLE_LINE_TEXT;
      GTXI_maxLength = 100;
      HINT_DEFAULT_FOCUS;
      HINT_EXPAND_WIDTH_TO_FIT_PARENT;
      ATTR_GEN_TEXT_CUSTOM_FILTER = @SEARCH_TEXT_FILTER;
   }

   If I add a GenDynamicList to the dialog then the whole thing works
   fine. Taking out the text filter doesn't help. Taking out the text
   object does. Why?

A. Because you're using a TextWithListClass object and those needs to
   point to a list object. Otherwise it will throw away the keypresses
   that it doesn't want, rather than forwarding them on to the list.


Check for objects in the same resource.

SDK: ALL_GEOS:PUBLIC
Q. I want to do a compile time check to make sure two objects are in
   the same resource. The following doesn't work for me. What will?

   CheckHack

   error: file "UI\uiList.asm", line 8826: ContactSearchText, ContactListDetailsContent undefined

   Is there a way to get the resource id or something?

A. Why, yes:

   CheckHack


Swat can't find my geode when I use 'send'.

SDK: ALL_GEOS:PUBLIC
Q. When I type "send mygeode" in Swat, it comes back and says it can't
   find my geode. Why is that happening?

A. There could be several causes of this problem:

   - your FILES setting is too low in config.sys (or config.nt on
     Windows NT systems); make it at least 100 or 120

   - the geode name is case-sensitive, be sure you're typing the
     correct name; e.g. "send aixtract" vs. "send AIxtract"

   - the "name" line in your .gp file doesn't match the name of
     your geode; make sure the directory containing your app, the
     name of the .gp file, and the name in the "name" line of your
     .gp file all match exactly (although the directory name can
     be of different case)

   - you are using a specific geode filename such as "geodeec.geo";
     Swat can't always find the geode if you type the exact file
     name of the geode (because Swat deals with "patients" not
     files). Instead, type "send mygeode" as opposed to
     "send mygeode.geo". Swat will determine, based on what demo
     you are running, whether it should send the EC or non-EC
     version of your geode.


How to access instance data for other master levels.

SDK: ALL_GEOS:PUBLIC
Q. I want to access the Vis instance data of my GenClass object. How
   would I go about getting a pointer to the Vis master level data?

A. You would basically have to define a pointer variable of the
   correct type and then use one of the ObjDeref..() functions. Here
   is an example:

   VisInstance * visPtr;
   visPtr = ObjDerefVis( oself );

   This example turns oself into a pointer to the Vis instance of
   the object. You could access other classes' instance data by
   using a different data type in the place of "VisInstance". For
   example, if you had a class called MySpecialClass you would
   define the variable type to be "MySpecialInstance". As you can
   see the data type is simply the class name, minus the "Class"
   suffix, with an "Instance" suffix added onto it.


Fonts in text transfer items

SDK: ALL_GEOS:PUBLIC
Q. Has anyone played with making text transfer items? I'd like to know
   how to set the font of the text that goes into the transfer item.
   Using the obvious MSG_VIS_TEXT_SET_FONT_ID doesn't have any effect.
   It's as if it ignores whatever properties the text has when making
   the clipboard transfer item.

A. When using TextAllocClipboardObject() the second variable determines
   what type of text object to create. It's a VisTextStorageFlags type.
   To transfer multiple character attributes you would use:

      VMFileHandle  hfilTransfer;
      optr          odText;
      VMBlockHandle hvmTransferItem;
      hfilTransfer = ClipboardGetClipboardFile();
      odText = TextAllocClipboardObject(
          hfilTransfer, VTSF_MULTIPLE_CHAR_ATTRS, 0 );

   You now have a text object that you can use all your regular messages
   on, such as:

      FontID fid = FID_UNIVERSITY;
      @call odText::MSG_VIS_TEXT_REPLACE_ALL_PTR( "Some text", 0 );
      @call odText::MSG_VIS_TEXT_SET_FONT_ID(
          fid, TEXT_ADDRESS_PAST_END, 0 );

   Then finish up with:

      hvmTransferItem = TextFinishWithClipboardObject(
          odText,
          TCO_RETURN_TRANSFER_ITEM,
          ConstructOptr( GeodeGetProcessHandle(), NullChunk ),
          "Test text" );

   This is explained in Include\Objects\vTextC.def. Search for
   TextAllocClipboardObject.


Offset of Vis master part of instance data.

SDK: ALL_GEOS:PUBLIC
Q. How do I get the offset to the Vis instance data?

A. "word_offsetof(VisBase, Vis_offset)" should work.


I get a UI_CANNOT_LOAD_SPECIFIC_UI error in Swat.

SDK: ALL_GEOS:PUBLIC
Whenever that happens, that means the ini file is munged and user
library tries to load motif (instead of rudy). To check whether
this is the case, after it crashes in swat, do a "pini ui" and
check for "specific = rudy{ec}.geo".

The other two classic reasons for this are:

1) Bad protocol number on some geode;
   use "showcalls -L" to verify

2) Not enough file handles in config.sys or config.nt. Check
   config.sys or set a breakpoint at the end of FileOpen if
   it returns CF set. Then do "print FileError ax" to see if
   the error is not enough files.


I get the WARNING_CONTDB_GEODE_NOT_IN_XREF_TABLE.

SDK: N9000C:PUBLIC
Q. I get this warning when I try to send an SMS message:

    WARNING_CONTDB_GEODE_NOT_IN_XREF_TABLE

A. You may get this message while sending SMS or doing some other
   operation that uses the contact database.

   It implies that if the "current" database is changed in the middle
   of the operation, you will get strange results (some of the
   operations will happen on one database and other operations will
   happen on the new database).

   On a related matter, if you want to make sure the database doesn't
   change on you, you should be using ContactGetDBHandle() and
   ContactReleaseDBHandle() calls around your entire operation. Many
   places get and release db handle multiple times in a function. It
   is necessary to get the handle at the beginning and release it at
   the end. That will guarantee that each call to GetDBHandle will
   return the same handle (which is what most people want).

   However, if you grab the handle and never release it and then
   someone changes the current db in cmgr, your app will never use the
   newly selected db (almost all apps are supposed to use the newly
   selected db).


Installing the OmniGo SDK under Windows '95.

SDK: OMNIGO:PUBLIC
Q. I'm trying to install the OmniGo SDK 2.1 on my machine, but it
   keeps aborting with an error in the install script. I'm running
   Windows '95.

A. Instead of running the SETUP.EXE program, double-click on the
   INSTALL.EXE. This is the "DOS" version of the SDK installer and
   will allow you to bypass any errors in the script.


How to get the IP address of my end of socket connection.

SDK: ALL_GEOS:PUBLIC
You would use the routine SocketGetMediumAddress() to get the IP address
of the machine running your application. This is the address that the
other end of the socket connection is using to talk to your end of the
socket.

Typically you would pass the following parameters to this routine:

domain = "tcpip",0
buffer = a ptr to a memory chunk in the following format:
     SocketAddress		; (socket.h)
     < < port #, MANUFACTURER_ID_SOCKET_16BIT_PORT >,
       6, "TCPIP",		; size "TCPIP" + null, ptr to TCHAR (nulled)
           9			; size ExtendedSACAddress + size dword
         >
         ExtendedSACAddress	; (sockmisc.h)
     < 3,			; size for this strucuture
       LT_ID,
       access point #	; access pointer you are using
     >
         dword buffer
bufsize = size SocketAddress + size ExtendedSACAddress + size dword
mau     = buffer of size MediumAndUnit "result"


Broken C-stub: SocketGetMediumAddress

SDK: ALL_GEOS:PUBLIC
C Routine:  SocketGetMediumAddress
Date Fixed: 10/15/97

The c-stub for SocketGetMediumAddress was calling the wrong routine
and thus the wrong data was coming back. You can work around this
bug by writing your own C-stub. The code below is a good start.

include geos.def
include geode.def
include resource.def
include ec.def
include assert.def

UseLib socket.def

SetGeosConvention

CApiCode	segment resource

MYGETMEDIUMADDRESS		proc	far	domain:fptr.char,
                        buffer:fptr.byte,
                        bufsize:fptr.word,
                        mau:fptr.MediumAndUnit
        uses	si,di,ds
        .enter
    ;
    ; Copy the parameters from the stack into registers
    ;
        movdw	dssi, bufsize
        Assert	fptr dssi
        mov	cx, ds:[si]
        push	ds,si
        movdw	dssi, domain
        movdw	esdi, buffer
        movdw	dxax, mau
    ;
    ; Call the assembly function
    ;
        call	SocketGetMediumAddress
    ;
    ; Return the result
    ;
        pop	ds,si
        mov	ds:[si], cx
        .leave
        ret
MYGETMEDIUMADDRESS	endp

CApiCode	ends

SetDefaultConvention


Using NT-based SDK under Windows '95

SDK: N9000C:PUBLIC
Q. Why doesn't the NT-based SDK work on Windows '95?

A. You might be able to compiler under Win '95, I haven't tried in
   a while. I think there is some problem between the command.com
   shell that Win '95 uses and the cmd.exe shell that NT uses. I
   believe part of the makefile depends on cmd.exe (but it has
   been a while since I have done this).

   The NT demo definitely won't work under '95. However, I have
   seen a normal DOS demo work in a window under NT. It mainly
   depends on the video card. Only a few allow this.

   I've never tried running Swat under '95. It is unlikely that
   Swat would be able to communicate with GEOS running '95. It
   definitely couldn't use the default communication mode (pipes),
   but it may be able to out one serial port and in the other.


Closing someone else's sockets (i.e. closing a domain).

SDK: ALL_GEOS:PUBLIC
Q. Is it possible to close down other people's sockets? I am
   trying this code but it fails to hangup the phone:

       MediumAndUnit theMedium;
       SocketError   se;
       char          tcpDomain[] = "TCPIP";
       word          bufsize = 100;

       se = SocketCheckMediumConnection( tcpDomain, buffer,
                                         &bufsize, &theMedium );
       theMedium.MU_medium.MET_id    = GMID_CELL_MODEM;
       theMedium.MU_medium.MET_manuf = MANUFACTURER_ID_GEOWORKS;
       theMedium.MU_unitType         = MUT_ANY;
       theMedium.MU_unit             = 0;
       se = SocketCloseDomainMedium( tcpDomain, &theMedium, TRUE );

A. Yes, it is possible to shut down the whole PPP Socket system,
   by passing TRUE as the third parameter to SocketCloseDomainMedium().
   In fact, this is exactly what the 'Hang Up' trigger in the main
   Internet Services view does. You must pass a valid MediumAndUnit
   structure in order for SocketCloseDomainMedium() to work. You can
   get this from SocketGetAddressMedium() given the SocketAddress.

   You can also be kept apprised of socket links that are created by
   using SysHookNotification() with SST_SOCKET as the first parameter.
   In the callback routine parameters, word1 will be the MediumUnitType,
   word2 will be the unit itself (MU_unit), and word3/word4 will be the
   MediumType.


Using 'ec ALL' in Swat causes HANDLE_FREE death.

SDK: ALL_GEOS:PUBLIC
If you turn on all the ec flags in Swat using "ec ALL", and then try
to quit an application using Ctrl-F4 or MSG_META_QUIT, you will get
a HANDLE_FREE death. This is logged as a bug and will be fixed someday.
As a workaround, you can use "ec ALL -app" instead, which will turn
on all the ec flags accept the "app" flag, which causes this crash.


Do not use TRUE for comparison in GOC

SDK: ALL_GEOS:PUBLIC
In geos.h, TRUE is defined as:

>>>>>
#define FALSE 0
#define TRUE (~0)           /* Use as a return value, *not* for comparisons */
<<<<<

This is different from the #define in .h files provided in most C
compilers out there. This means that in GOC you can do things like:

    Boolean	hasData;

    if ( hasData ) {
        ......
    }

but you cannot do things like:

    if ( hasData == TRUE ) {
        ......
    }

The reason is that C expressions that evaluate a condition generate
the value 1 if the condition is met. (This is described in the K&R
book and most compilers do it this way.) Therefore, if you have
something like this:

    Boolean greaterThan( int a, int b ) {
        return a > b;		/* returns +1 or 0 */
    }
    ......

    Boolean	fiveGtFour;

    fiveGtFour = greaterThan( 5, 4 );
    if ( greaterThan( 3, 2 ) == TRUE && fiveGtFour == TRUE ) {
        ......
    }

your code will not execute correctly. Rather, you should do

    if ( greaterThan( 3, 2 ) && fiveGtFour ) {
        ......
    }

There are quite a bit of existing code that uses TRUE for comparison,
yet still works. It happens to work because in some cases the
variable being compared was explicitly assigned to the constant
"TRUE". However, please do not use TRUE for comparison in the future.

Here is an explanation on why TRUE in GOC is defined as ~0 but not 1:
---------------------------------------------------------------------
I would guess it's because TRUE needs to match the geos.def
definition, in case people want to compare a return value
(for whatever reason) to it, rather than just using the
logical test in C. I think it's ~0 in assembly partly because
the "AND" operator is bitwise, not logical, so if one were to say:

if RANDOM_CONSTANT and TRUE

If RANDOM_CONSTANT were other than 1, you'd still want the
thing to evaluate true. I know some compilers use -1 for true,
rather than 1. not sure what the reasoning is.


Using F1-F4 keys in Telnet

SDK: N9000C:PUBLIC
Q. I want to use the function keys (F1 - F4) in the N9000 Telnet
   application. Is it possible to emulate those keys through the
   terminal?

A. Terminal and Telnet have special key list. It is a pop-up selectable
   list that is accessible from the trigger labelled "Key".  (This
   label appears after making the telnet/terminal connection.)

   There are several entries including PF1 - PF4.  PF1 - PF4 send out
   the following VT100 emulation ANSI mode auxiliary keypad codes:

   PF1	-> ESC O P
   PF2	-> ESC O Q
   PF3	-> ESC O R
   PF4	-> ESC O S

   There is no way for external developers to change the keycodes
   generated or add new function keys.


Why don't my instance field default values work?

SDK: ALL_GEOS:PUBLIC
Q. I'm trying to set some default values for instance data, in the
   class definition. However, the values don't seem to be assigned
   to the data.

   The instance data is a struct, declared as follows:

   @instance MetaComponentColor MCI_bgColor = {CF_NOT_SET, 0};

   CF_NOT_SET has a value of 0xff. However, when I check the instance
   data of a newly-instantiated object after META_INITIALIZE has been
   called, but before I've set MCI_bgColor, the data is set to all 0s.

A. The default values declared in the class definition will not get
   set in dynamically instantiated objects. You have to write the
   appropraite code to do it explicitly in your MSG_META_INITIALIZE.


Does register DS point dgroup in GOC methods?

SDK: ALL_GEOS:PUBLIC
Q. When a method written in GOC is called, does the system set the DS
   register to point at the dgroup of the geode owning the code resource?
   Or does the method have to take explicit steps to set ds=dgroup before
   acessing global vars, as exported library routines do?

A. Depends if your method is being called by a library or not. If so,
   the answer is yes, you have to setup DS. If you give a library a
   callback function, DS will be equal to the DS of the library when
   the function is called. So you have to setup the DS in callback
   functions just like a library must do.


How to convert FAX format from Nokia 9000 to PC.

SDK: N9000C:PUBLIC
The only way to convert a FAX from the Nokia 9000 format to a PC format
is to send the FAX to the PC via a telephone call.

The FAX format on the Nokia 9000 is proprietary and undocumented, so it
is unlikely that a conversion program will be written.


Maximum number of fields in a Foam DB record.

SDK: N9000C:PUBLIC
Q. It appears that I can't add more than 50 fields to a record in the
   FoamDB. Is this true?

A. Yes, FoamDB only supports up to 50 fields.


N9000 demo says 'unable to load UI library'.

SDK: N9000C:PUBLIC
Q. I've got a clean NT machine and I've installed the Nokia 9000
   software demo. When I try to run it, it says "unable to load the
   UI library (UI-03)".

   What setting does the demo require to make it work?

A. Set "files=80" in %SystemRoot%\system32\config.nt


How GenFileSelector sorts GEOS and DOS files.

SDK: ALL_GEOS:PUBLIC
The GenFileSelectorClass, by default, sorts files by their creation
date. Since DOS files do not have creation dates GEOS must hack them
to have very early dates, which forces DOS files to the end of the
selector listing. You can prevent this separation of GEOS and DOS
files by using the hint HINT_FILE_SELECTOR_ALWAYS_SORT_ALPHABETICALLY.
This will mingle the GEOS and DOS files and sort them in alphabetical
order.

By the way, after the files are sorted by creation date they are then
sorted by name. Some spui's sort them in reverse alphabetical order.


Defining a second process class messes up first one.

SDK: ALL_GEOS:PUBLIC
Q. I've defined a new process class in my application and now suddenly
   all the methods for my primary process class aren't working. Why is
   this happening?

A. In GOC programming there is no way to specify which process class is
   *the* process class for your application, other than by the order in
   which the process classes are defined (using @class/@endc). To make
   your primary process class work again you must be sure to define it
   after the other process classes. Here's an example:

   // this is for a secondary event thread
   @class MyThreadClass, ProcessClass;
   @endc;

   // this is my primary process class; it is defined
   // after the other process classes
   @class MyProcessClass, GenProcessClass;
   @endc;


Compressing files and buffers with the compress library.

SDK: ALL_GEOS:PUBLIC
If you want to compress a file or some block of data in memory, you
can use the routine CompressDecompress() (defined in compress.h).
This compression uses the PKWare compression library, version 1.02.

extern word
    _pascal CompressDecompress(CompLibFlags flags,
                   FileHandle sourceFileHandle,
                   void *sourceBuffer,
                   word sourceBufferSize,
                   FileHandle destFileHandle,
                   void *destBuffer);

The return value is the number of bytes written to the destination.

Here is a description of the flags you can set:

CLF_SOURCE_IS_BUFFER
  Set this bit if you are using *sourceBuffer instead of
  sourceFileHandle.
CLF_DEST_IS_BUFFER
  Set this bit if you are using *destBuffer instead of
  destFileHandle.
CLF_DECOMPRESS
  Set this if the source is compressed and you want to
  decompress it. If this bit is clear, the routine will
  perform compression.
CLF_MOSTLY_ASCII
  Set if the source is mostly ASCII characters.


ParaAttr hints: margins, bullets, border lines

SDK: ALL_GEOS:PUBLIC
Here are some random notes about ParaAttr:

----
VTPA_prependChars is not supported in the GEOS text objects.

----
Paragraph margins:
VTPA_leftMargin - is the position on the left side of the document
    where a text line begins. This is only for text that wrapped
    from the right margin.

VTPA_paraMargin - is the left margin position for text that
    follows a hard return.  This is used for indenting the
    first line of a paragraph.

VTPA_rightMargin - is the distance from the right side of the
    document to wrap text.

----
For setting VTPA_borderFlags, you should use the
VisTextParaBorderFlags which are defined in
CInclude\Objects\Text\tCommon.h.

Here is an example that draws a double-line sqare around the text
VTPA_borderFlags = (VTPBF_LEFT | VTPBF_TOP |
        VTPBF_RIGHT | VTPBF_BOTTOM |
        VTPBF_DRAW_INNER_LINES);

----
Bullet points

To add bullet points to your text object, so it looks like this

   *  Some long string of text
      that wraps
   *  Some other bullet point
      with more wrapped text

Set VTPA_paraMargin less than VTPA_leftMargin, then add a tab
character (ASCII code is 0x09) right after whatever the bullet
point character. This will tabulate the text out to the
VTPA_leftMargin.

For example, if you set VTPA_paraMargin=100 and VTPA_leftMargin=150
and then put text like '*', 0x09, "Some long string that wraps",
it should end up looking like the example.


I get ASSERTION_FAILED in VisTextHandleCharset

SDK: N9000C:PUBLIC
Q. I am getting an ASSERTION_FAILED error in Swat when I'm typing text
   into a VisLargeText object in my application. The backtrace seems
   to indicate that the error originated from VisTextHandleCharset.
   What could be going wrong?

A. What's happening is the text object is not handling the key releases.
   It is getting only the key presses and this causes a problem for
   the VisTextHandleCharset routine, which counts on there being a
   key release for every key press.

   Things to look for:

   - a GenView that has the attribute GVA_DONT_SEND_KBD_RELEASES set
   - you've superclassed MSG_META_KBD_CHAR and aren't calling the
     superclass for both CF_FIRST_PRESS and CF_RELEASE.


Push/pull support on the Nokia 9000 Communicator.

SDK: N9000C:PUBLIC
Q. Do you know, or can you find out, the level of HTML support offered
   by the Nokia 9000? Of particular interest is whether the server-push
   and client-pull Netscape-isms are supported.

A. The short answer to your question is that no, the Nokia 9000 does
   not support server push/client pull. Unfortunately, since the
   hardware and the application on the Nokia 9000 were developed by
   Nokia, and not Geoworks, we do not have much information about them.
   For such information, the Club Nokia page can be a great resource.
   I found the answer to your question at:

   http://www.club.nokia.com/communicator/library/0796/wwwbrowser.html


File extensions of SDK tools files.

SDK: ALL_GEOS:PUBLIC
  GEOS tools file extensions and what they mean:

(EC) means error-checking version
(NC) means non-error-checking version

_e.c	(EC) preprocessed .goc file (Unix/NT)
_e.rsc	(EC) lists resources in geode (Unix/NT)
_g.c	(NC) preprocessed .goc file (Unix/NT)
_g.rsc	(NC) lists resources in geode (Unix/NT)
.a	library file (Unix)
.c	C source code (Unix/DOS/NT)
.o	object files (Unix)
.ec	(EC) preprocessed .goc file (DOS)
.ecg	(EC) ?
.eobj	(EC) object code (Unix/NT)
.exe	compiled executable (Unix/DOS/NT)
.geo	GEOS executable file (Unix/DOS/NT)
.gobj	?
.goc	GOC source code (Unix/DOS/NT)
.grdef	?
.i	used by the PC tools for dependencies (DOS/NT)
.ldf	library defines (Unix/DOS/NT)
.mk	a makefile of some kind (Unix/DOS/NT)
.mod	file used by GreenHills tools (Unix)
.nc	(NC) preprocessed .goc file (DOS)
.obj	(NC) compiled object code (Unix/DOS/NT)
.rdef	ui resource file from the pre GOC GEOS days (Unix/NT)
.rsc	(NC) lists resources in geode (Unix/DOS/NT)
.sym	(NC) symbols file (Unix/DOS/NT)
.vm	localization file (Unix/DOS/NT)
ec.geo	(EC) GEOS executable file (Unix/DOS/NT)
ec.sym	(EC) symbols file (Unix/DOS/NT)


How to paste GString clipboard data.

SDK: ALL_GEOS:PUBLIC
Q. I am trying to get access to the GString data from the clipboard.
   Can you give a code example of how to do this?

A. Here is how it is done:

        #define GRAPHICS_FORMAT FormatIDFromManufacturerAndType(             MANUFACTURER_ID_GEOWORKS, CIF_GRAPHICS_STRING )

        /*
         * query   - return values for clipboard query
         * request - return values from clipboard request
         * gstate  - handle of gstate containing gstring; this
         *           is not a real gstate in that it is not
         *           attached to a window; don't attempt to
         *           draw to this gstate
         */
        ClipboardQueryArgs   query;
        ClipboardRequestArgs request;
        Handle               gstate;

        /*
         * Get the handle of the clipboard VM file.
         */
        ClipboardQueryItem( TIF_NORMAL, &query );

        /*
         * See if this clipboard has GString data in it.
         */
        if ( ( query.CQA_numFormats > 0 ) &&
             ClipboardTestItemFormat( query.CQA_header, GRAPHICS_FORMAT ) ) {
                ClipboardRequestItemFormat( GRAPHICS_FORMAT,
                                            query.CQA_header,
                                            &request );
                /*
                 * request.CRA_file   - file handle
                 * request.CRA_data   - start of data vm chain
                 * request.CRA_extra1 - H size
                 * request.CRA_extra2 - V size
                 */

                /*
                 * Copy the clipboard GString to a new block so
                 * we can perform work on it.
                 */
                gstate = GrLoadGString(
                    request.CRA_file,
                    GST_VMEM,
                    VMCHAIN_GET_VM_BLOCK( request.CRA_data ) );

                /* Do work on GString here. */

                /*
                 * After performing our work we can destroy the
                 * GString we grabbed.
                 */
                GrDestroyGString( newGString, NULL, GSKT_LEAVE_DATA );
        }
        ClipboardDoneWithItem( query.CQA_header );


Alternative Swat command to 'pclass'.

SDK: ALL_GEOS:PUBLIC
Q. Currently, if I want to find out the class of an object whose
   subclassed-method I am in, I do the following:

   => print oself
   @299: oself = 6950h:0030h
   => pclass ^l6950h:0030h
   FrameComponentClass
   =>

A. Try using "p optr oself" instead, that should do it.


How to get handle of geode in GOC without using GeodeFind.

SDK: ALL_GEOS:PUBLIC
Q. In GOC code, how do I get the handle of another geode? In assembly I
   can do

       mov      ax, handle ui           ; new onwer
       call     HandleModifyOwner

   How do I do this in GOC?

A. Try the following code:

        HandleModifyOwner( myHandle, MemOwner( MemPtrToHandle(
            (void*)&SomeClassOrFixedRoutineInTheOtherGeode ) ) );

   This way it doesn't have to lock/unlock all the coreblocks as when
   you're using GeodeFind().


Making modem data calls on the Nokia demo.

SDK: N9000C:PUBLIC
For modem data calls on the Nokia 9000i Communicator demo you should
use a Hayes Accura modem. The US Robotics Sportster will not work for
making modem data calls (i.e. calls made through the modem driver).


How to look at Swat stub variables.

SDK: ALL_GEOS:PUBLIC
Q. Is there any way to look at global variables defined in swat stub
   from within Swat debugger?

A. Sort of. You can look at the swat.map file in Tools/swat/Stub/NetWare
   to find where the thing is, then look at SwatSeg:whatever_offset. A
   more fun way is to use the dossym command (I think that's the name) to
   create a "stub" patient using the swat.sym file and SwatSeg:0 as the
   base address. Then I think you should be able to print things out,
   list stuff, etc.


Casting the return value from an @call.

SDK: ALL_GEOS:PUBLIC
Q. Error MYSOURCE.GOC 213: parse error, expecting ':'

      theAnswer = @call (int) (self::
          MSG_GEN_GUP_CALL_OBJECT_OF_CLASS( theMessage ) );

   I've tried various ways of casting the message but they all come up
   with errors (usually this one).

A. You need to move the "(int)" before the @call like this:

      theAnswer = (int) @call (self::
          MSG_GEN_GUP_CALL_OBJECT_OF_CLASS( theMessage ) );


Aligning text field with group's children.

SDK: N9000C:PUBLIC
Q. I want to have a single-line text field line up with the children of a
   GenBooleanGroup (and have it easily localizable). Here is a "picture"
   of the desired effect:

   GenBooleanGroup Moniker:
       Boolean 1 > Off
     Another One > Off
           Again > On
         Scanner > On
     Text Field: ___________________

   Instead, what happens now is the text field lines up with the group as
   a whole, looking like this:

   GenBooleanGroup Moniker:
       Boolean 1 > Off
     Another One > Off
           Again > On
         Scanner > On
   Text Field: ___________________

   Do you know how to accomplish the desired effect, and still allow
   for easy localization (i.e. putting the text field in an interaction
   and using HINT_INDENT_CHILDREN with a fixed pixel value isn't desirable).

A. Put HINT_CENTER_CHILDREN_ON_MONIKERS on the interaction surrounding
   the boolean group and text field. Then put HINT_ALIGN_WITH_CENTERED_-
   MONIKERS on the text object. Be sure to remove HINT_INDENT_CHILDREN
   from the boolean group, if you're using it.


I get a BLOCK_ALLOCATED_WITH_NO_FLAGS error. What does it mean?

SDK: ALL_GEOS:PUBLIC
Q. I tried to do a MemAlloc and I got an error in Swat:

   BLOCK_ALLOCATED_WITH_NO_FLAGS

   What does it mean?

A. A block was allocated that was neither fixed, discardable, nor
   swapable. This is bad, as it'll just sit on the heap, even if
   there is available swap space. You should call MemAlloc with
   either HF_FIXED, HF_DISCARDABLE, or HF_SWAPABLE.


Using 'pmake lib' doesn't create my .ldf file.

SDK: ALL_GEOS:PUBLIC
Q. I'm writing a library for the Nokia 9000 and I'm using the WinNT
   SDK. When I type "pmake lib" I don't get a .ldf file. What am I
   doing wrong? My source code is in c:\pcgeos\me\testlib.

A. You need to make sure your library source code is in a directory
   where the keyword "library" is in the path. The SDK tools rely
   on these pathnames to do the right thing. In your case, put your
   source code in a directory such as c:\pcgeos\me\library\testlib.


Underlined text cursor moves to end of field.

SDK: N9000C:PUBLIC
Q. Any suggestions how to define a GenTextClass object that has the
   cursor always at the start? Problem is that when a page becomes
   visible all is okay, but after I move up and down between the
   text objects, the cursor is set to the end of the fields.

A. This is caused by the UnderlinedVisTextClass whenever it loses the
   focus. It queues up a MSG_UVT_MOVE_TO_END_IF_NOT_FOCUSED so that the
   next time the object gets the focus the cursor will be at the end.

   To avoid this, simply define your own subclass of
   UnderlinedVisTextClass and intercept
   MSG_UVT_MOVE_TO_END_IF_NOT_FOCUSED to do nothing. If you're using
   UnderlinedGenTextClass, then be sure to have a line like this in
   your subclass declaration:

      @uses UnderlinedVisTextClass; // see GenTextClass for example

   This allows you to intercept UnderlinedVisTextClass messages even
   though you're really defining a subclass of UnderlinedGenTextClass.

   By the way, a simple GenText object does not exemplify this behavior.


How to create scrollbars without GenView.

SDK: ALL_GEOS:PUBLIC
Q. How do I make vertical and horizontal scrollbars? Maybe you
   could tell me what's wrong with this one. I tried all the
   normal values first without any visible success.

     @object GenValueClass HorizontalIndicator = {
         GVLI_value = { 1.0 };
         GVLI_maximum = { 10.0 };
         HINT_VALUE_DISPLAYS_RANGE = MakeWWFixed( 25.0 );
         HINT_VALUE_Y_SCROLLER;
     }

A. You're doing the right thing by using HINT_VALUE_Y_SCROLLER
   to create a vertical scrollbar. And the use of the hint
   HINT_VALUE_DISPLAYS_RANGE to set the size of the scroller is
   also good. However, the values you've set up in the GenValue
   are unacceptable and thus it doesn't draw itself. The range
   you've set in the hint is larger than the maximum range that
   is possible (your min is 0 and max is 10). Fix that and the
   scroller will work.

   Also, note that horizontal scrollbars are not supported on
   the Nokia 9000, so the hint HINT_VALUE_X_SCROLLBAR will not
   draw anything.


Colors that CVTPCX used for Nokia icons

SDK: ALL_GEOS:PUBLIC
When using the cvtpcx tool with the -N options, the PCX image can
only contain the following colors:

    pcx color:	  maps to:
    ----------    --------
    Black 	  Black
    Green	  Dark gray
    Violet	  Light dark gray
    Light gray	  Dark light gray
    Light Violet  Light gray
    Yellow	  Light gray
    White	  White
    Light Cyan	  used as mask

If the PCX image contains any of the following colors, cvtpcx will
return an error:

  Blue
  Cyan
  Red
  Brown
  Dark Gray
  Light Blue
  Light Green
  Light Red

Note:
 -N option specifies that the icon is in Nokia color map.


The discardable-dgroup flag in .gp files.

SDK: ALL_GEOS:PUBLIC
Q. Why use this flag? What are the trade-offs between using this
   flag and not using this flag?

A. This flag turns on error checking in glue to ensure that your
   geode has a discardable dgroup. If your geode does not have a
   discardable dgroup, it means that RAM is always reserved for your
   geodes' dgroup, even if the geode isn't currently loaded. This is
   bad, as the typical app's dgroup is over 2K, because of the stack.

Q. How does using this flag affect how you code your application?
   Does it mean that I can't do this?

    segmov	ds, dgroup, ax

   How do I get to my dgroup then?  ES no longer points to dgroup
   in methods.

A. You can still have handle relocations to your dgroup resource,
   and you can always do "resid dgroup", so you can do one of the
   following:

    GetResourceSegmentNS	dgroup,

    Which does:
        push	bx
        mov	bx, resid dgroup
        call	GeodeGetResourceHandle
        call	MemDerefDS
            or
        call	MemDerefES
        pop	bx

    Or you can do the shorter:

        mov	bx, handle dgroup
        call	MemDerefDS/MemDerefES

    I'm sticking with GetResourceSegmentNS...

   If C geodes need to load DS with dgroup (this is typically
   done for routines that are externally callable), they can call
   GeodeLoadDgroup.


How to make flashing note smaller.

SDK: N9000C:PUBLIC
Q. Is it possible to create a smaller flashing note than the one
   that's created by default? I'm able to make it bigger than the
   standard bubble size but not smaller. I tried with HINT_FIXED_SIZE
   but it doesn't seem to work.

A. The FlashingNoteClass will ignore any attempts to make it smaller
   than 270x183 (its minimum size). To make it smaller you will need
   to subclass FlashingNoteClass and intercept MSG_VIS_RECALC_SIZE.
   In the subclassed method you can do something like:

       return MAKE_SIZE_DWORD( 200, 160 );

   or something to that effect. This will force the note box to be
   that size. Watch out! If you make it too small and the elements
   inside the flashing note don't fit, you'll get a crash in the
   geometry manager (the particular error will depend on the objects
   in the note).


AccessPoint requirements for an IP address.

SDK: ALL_GEOS:PUBLIC
The mask setting must meet the same requirements as an IP address,
plus the following extra rule:

When viewed as a 32 bit binary numeral, it must match the regular
expression 1*0*0. That is to say, all the "1" bits must be contiguous
in the high bits of the mask, and all the "0" bits contiguous in the
low bits of the mask. Additionally, it can't be all 1s. We do allow
all 0s, although that is not a useful mask.

Examples:

00000000 00000000 00000000 00000000	0.0.0.0			valid
11111111 10000000 00000000 00000000	255.128.0.0		valid
11111111 11110000 00000000 00000000	255.240.0.0		valid
11111111 11111111 11111111 11111111	255.255.255.255		invalid
11111111 10100000 00000000 00000000	255.129.0.0		invalid
00000000 00000000 00000000 00111111	0.0.0.127		invalid
00000000 00001111 11111110 00000000	0.15.254.0		invalid


File selector filters and geode tokens.

SDK: ALL_GEOS:PUBLIC
Q. What is the right way to use a filter in a file selector object?
   The one I'm using doesn't work - it filters all files away.

A. The problem may be that the files in your directory do not have
   the creator GeodeToken you are specifying in your file selector.
   Only VM files have creator GeodeTokens. ASCII files do not have
   this.

   If the files you wish to filter are not VM files, you can use
   ATTR_GEN_FILE_SELECTOR_NAME_MASK with something like "*.txt"
   as the mask.


Getting focused object for objects not in focus path.

SDK: ALL_GEOS:PUBLIC
Q. Now I'd like to know which one of the FileSelectors (FFS1 or FFS2)
   is currently active. A function or message that returns optr to
   the active FileSelector would do fine. Or a Boolean value (are you
   or are you not active). But the best would be if I could send
   message encapsulated TO_APP_FOCUS (or something) and intercept it
   in the active FileSelector object.

   Keeping track of TAB presses or NAVIGATE_TO_NEXT_FIELD messages
   doesn't sound good.

   Since the source of the problem is that FileSelectors are not part
   of the focus path, I could add a new layer of GenViews and
   GenContents between TabObjectsHolder and those FileSelectors (and
   get rid of TabView and TabContent objects). This seems to work but
   sounds a bit heavy way to ask which FileSelector is active.

A. Since the FFileSelector gets converted into a view/content/items
   (unfortunately), the only way to get a known object in the focus
   hierarchy is by adding a GenView/GenContent between TabObjectsHolder
   and the FFileSelectorClass objects.

   Once you have a known object within the focus heirarchy, you can send
   MSG_META_GET_FOCUS_EXCL to the GenContent of the TabView. This will
   return an optr to the GenView that contains the FFileSelector that
   currently has the focus.

   So here is what your GenTree should look like
   TabApp (FoamSubApplicationClass)
       TabPrimary (GenPrimaryClass)
       TabView (TabViewClass->GenViewClass)  * monitors keypresses *
           TabContent (GenContentClass)
           TabObjectsHolder (GenInteractionClass)
              FFS1View (GenViewClass)
                   FFS1Content (GenContentClass)
                      FFS1 (FFileSelectorClass)
              FFS2View (GenViewClass)
                   FFS2Content (GenContentClass)
                      FFS2 (FFileSelectorClass)
       CloseTrigger (ComplexMonikerClass:GenTriggerClass)

   If you send MSG_META_GET_FOCUS_EXCL to TabObjectsHolder, it will
   return the optr of either FFS1View or FFS2View. You could optionally
   subclass the GenView for FFS1View and FFS2View so that they return
   the optr of FFS1 or FFS2 (respectively).

Q. Or is it somehow possible to add a GenInteraction object behind
   FileSelector so that the GenInteraction would be in the focus path?
   (e.g. TabObjectsHolder is not)

A. That would not work because a GenInteraction cannot be in the focus
   path unless it is a dialog or popup. Here is some information from
   Include\ui.def about which objects can be in the focus heirarchy:

   ;Focus nodes in Generic UI library: GenSystem
   ;				    GenField
   ;				    GenApplication
   ;				    GenPrimary
   ;				    GenDisplayControl
   ;				    GenDisplay
   ;				    GenView
   ;				    GenInteraction (Indep. displayable only)


Can't import text files to GeoWrite on NT demo.

SDK: ALL_GEOS:PUBLIC
Out of the box, the Nokia 9000i Communicator NT SDK 2.0 does not have
a working version of the ASCII.GEO file. This results in a TR-04 error
whenever the user tries to import ASCII text into a GeoWrite document.
A work-around is to use Text File Editor to copy the text file to the
clipboard and then paste it into GeoWrite.

Another fix is to get the correct version of ASCII.GEO and put it in
the SYSTEM\IMPEX directory. See the DevRel downloads page for this
file. The correct ascii.geo file is 1452 bytes in size while the one
on the SDK is 1576 bytes. Another difference is the release of the
one on the SDK is 3.0.3.434 while the working ascii.geo is release
2.0.40.1 (as viewed with the dumpgeo utility).


Running NC apps on EC demo and vis-versa.

SDK: ALL_GEOS:PUBLIC
Q. Can EC code compiled correctly with the EC compiler options be
   sent to an NC emulator?
   Can NC code compiled correctly with the NC emulator options be
   sent to an EC emulator?

A. Typically you run EC on EC and NC on NC. In reality, you can mix
   and match. On the NC emulator, the EC functions are just stubs
   so EC compiled apps can run, in general.

   Since NC compiled apps don't make calls to EC code, they can run
   on anywhere.

   Only problem is swat looks for apps of the same type as the emulator,
   so if you are running the NC emulator, and try to send foo.app, it
   will not look for fooec.app


Setting the mailbox name for OBEX messages

SDK: N9000C:PUBLIC
OBEX messages that are sent _from_ the Nokia 9000 using the mailbox
library get their NAME header from the OMTA_fileName field in the
ObexTDMailboxTransAddr (if none is supplied, the actual filename
containing the data is used). The OBEX TYPE field is taken from
the OMTA_dataType field (If none supplied, then
'application/octet-stream' is used).


Turning off keyclick sounds in demo.

SDK: N9000C:PUBLIC
Q. How can I turn off keyclick sounds in NT demo? If there is no UI
   for it, what is the INI setting?

A. [ui]
   keyClick = 0


How to receive OBEX transport address structure.

SDK: N9000C:PUBLIC
Q. I am trying to send some data through the mailbox library, via
   the OBEX transport data structure. The receiving side should get
   the sent file name from the message and I cannot find it. I can
   extract the temporary file name from the data but the name of the
   file I cannot get. Here is how I try to do it:

   When I send the file I fill in the info as follows:

       MailboxRegisterMessageArgs mrma;
       MailboxMessage             mmsg;
       MailboxTransAddr           mta;
       ObexTDMailboxTransAddr     obexMta;

       /* Some irrelevant data filling here */

       /* This should be found at the receiving side */
       strncpy( obexMta.OMTA_fileName,
                ptcFileName,
                sizeof( obexMta.OMTA_fileName ) );
       strncpy( obexMta.OMTA_dataType,
                (TCHAR*)LMemDeref( @ringingtones ),
                sizeof( obexMta.OMTA_dataType ) );
       obexMta.OMTA_userHeadersLength = 0;

       mta.MTA_transAddr = &obexMta;
       mta.MTA_transAddrLen = sizeof( ObexTDMailboxTransAddr );
       mta.MTA_userTransAddr = 0;
       mrma.MRA_transAddrs = &mta;
       mrma.MRA_numTransAddrs = 1;
       mrma.MRA_flags = 0;

       /* Send */
       MailboxRegisterMessage( &mrma, &mmsg );

   And in the receiving side I try to read the data:

       MailboxDataFormat      dataFormat;
       FileDDMaxAppRef        fddmarFileInfo;
       ObexTDMailboxTransAddr obexMta;

       /* This shows that we receive by OBEX */
       MailboxGetBodyFormat( msg, &dataFormat );

       /* Here we can read the temp file name */
       wSize = sizeof( fddmarFileInfo );
       error = MailboxGetBodyRef( msg, &fddmarFileInfo, &wSize );

       /* But this fails - structure shows only mess */
       wSize = sizeof( ObexTDMailboxTransAddr );
       MailboxGetTransAddr( msg, 0, &obexMta, &wSize );

A. You should check your error return codes. This is probably returning
   an error and garbage in obexMta, because the transport address
   attached to the message is actually larger than the basic
   ObexTDMailboxTransAddr, so MailboxGetTransAddr is failing.

   The right way to fetch a transport address, particularly from an OBEX
   message, which you should expect to contain arbitrary extra OBEX
   headers, is to do the following:

       wSize = 0;
       MailboxGetTransAddr( msg, 0, NULL, &wSize );
          /* Will fail, but wSize now contains real size of the address */

       obexMta =
       MailboxGetTransAddr( msg, 0, obexMta, &wSize ); /* Should succeed */


cvtpcx gives 'unmappable pixel value' error.

SDK: N9000C:PUBLIC
Q. I'm trying to use cvtpcx and I get this error:

   C:\Nokia\icon>cvtpcx -2 -t -N -G -w25 -h18 -oclock.goh -m3 clock.pcx
   Input parameters for clock.pcx:
        1 bits per pixel, 4 planes, 4 bytes per plane
        (0, 0) to (24, 17): width = 24, height = 17
        xRes = 150, yRes = 150
   **** Error: Unmappable pixel value: 1 ****

A. Looking at the source for cvtpcx:

------------------------------------------------------------
static const byte responderMap[] = {
    RC_BLACK,     	/* C_BLACK */
    0xff,     	/* C_BLUE */
    RC_DARK_GRAY,     	/* C_GREEN */
    0xff,     	/* C_CYAN */
    0xff,     	/* C_RED */
    RC_DARK_GRAY,     	/* C_VIOLET */
    0xff,     	/* C_BROWN */
    RC_LIGHT_GRAY,     	/* C_LIGHT_GRAY */
    0xff,     	/* C_DARK_GRAY */
    0xff,     	/* C_LIGHT_BLUE */
    0xff,     	/* C_LIGHT_GREEN  */
    0xff,     	/* C_LIGHT_CYAN - should be masked out */
    0xff,     	/* C_LIGHT_RED  */
    RC_LIGHT_GRAY,     	/* C_LIGHT_VIOLET  */
    RC_LIGHT_GRAY,     	/* C_YELLOW  */
    RC_WHITE     	/* C_WHITE  */
};

byte MapPixelToResponder( byte rawPixel ) {
    assert(rawPixel<16);
    if (rawPixel == maskout) {
    return(rawPixel);
    }
    if (responderMap[rawPixel] == 0xff) {
    fprintf(stderr,
        "**** Error: Unmappable pixel value: %d ****\n",
        (int) rawPixel);
    exit(1);
    }
    return(responderMap[rawPixel]);
}
------------------------------------------------------------

   It appears that any color that maps to 0xff above is illegal. This
   would imply that your pcx file has "invalid" pixel values for the
   N9000. Check your pcx file to make sure it doesn't have any blues
   in it, since that is the unmappable pixel value you're getting
   (1 = C_BLUE).

   The other solution is to not pass the -N flag. This produced an
   image that worked for me on the emulator.


How to handle installing apps or docs.

SDK: ALL_GEOS:PUBLIC
Q. How do you know if I'm installing software or document?
   At the moment appins gives "replace an existing document"
   for each and every GEOS file, which is not a driver, library
   or application, and every non-GEOS file. Is this correct?

A. There are many checks being done in the connect library
   to decide what is being installed and how to handle overwrite
   conflicts. All the checks rely on file type. Nothing depends
   on final location of installed file.

Case 1:
New Dos file overwriting existing Dos file -> ask user about
replacing existing software.

Case 2:
New dos file overwriting existing Geos file -> ask user about
replacing unrelated software.

Case 3:
New Geos file overwriting existing Dos file -> Dos name of
Geos file is changed so existing Dos file is not overwritten.
No note. If name cannot be changed, ask user about replacing
unrelated software.

Case 4:
New Geos file will overwrite Geos file with same Geos filename
and manufacturer ID ->

    If new file and existing file are of different types,
    user is asked about replacing unrelated software.
    No checks on file type.

    If new file GeosFileType is GFT_VM or GFT_DATA, user
    is asked about replacing existing document.

    If new file GeosFileType is GFT_EXECUTABLE, user
    is asked about replacing existing software.

    If the new file does not fit any of the above checks,
    user is asked about replacing unrelated software.

Case 5:
New Geos file will overwrite Geos file with same Geos filename,
different manufacturer ID -> ask user about replacing unrelated
software.

Case 6:
New Geos file will overwrite existing Geos file with different
Geos filename ->

    If GFT_VM or GFT_DATA, FileCopy or FileMove routines
    will assign a different Dos name to new Geos file.
    No note.

    Else, ask user about replacing unrelated software.


What does the PFIXED block flag mean in hwalk?

SDK: ALL_GEOS:PUBLIC
Q. I'm swatting a device running with XIP. When I do "hwalk" from Swat,
   I see some blocks with flags "PFIXED". What does it mean?

A. It means they were allocated as fixed blocks but couldn't fit in the
   space above the highest fixed block and below the lowest movable
   block. So GEOS tries to allocate them at the top of the heap with a
   very high lock count (254). Less than optimal, but it should leave a
   heap big enough to be usable. This is true in both non-XIP and XIP.
   Also, in XIP, all XIP fixed resources are also marked PFIXED.


Using FileCopy() on a GEOS file, DOS file already exists.

SDK: ALL_GEOS:PUBLIC
If you stick to using the FileCopy() routine, you'll never overwrite an
existing DOS file, no matter what the filenames are. There are basically
two cases for FileCopy() when used to copy a GEOS file to a directory
where a DOS file already exists of the same name:

1. The file copy will succeed and there'll be a file that is uniquely
   named in the destination directory. It might be the same DOS name it
   was before or it will be changed to avoid overwriting an existing
   DOS file.

2. The file names conflict and you'll get a ERROR_FILE_FORMAT_MISMATCH.
   This implies that the FileCreate() that is called by FileCopy() tried
   to open an existing file (in your case, the DOS file) and then checked
   the file format. It wasn't a GEOS file and thus it complains.

You could use FileCreateTempFile() to create a uniquely named file. The
DOS name of the GEOS file really makes no difference at all. You can
change it using DOS commands and it will not affect GEOS.


How to use FileParseStandardPath()

SDK: ALL_GEOS:PUBLIC
Q. When I call FileParseStandardPath(), it doesn't change the pointer
   to the path string and it returns SP_TOP. What am I doing wrong?

   TCHAR path[100] = "Document\\Own texts\\Calendar memos";
   TCHAR *pathPtr = &path;
   StandardPath sp = FileParseStandardPath( SP_TOP, &pathPtr );

A. Because GEOS runs on top of DOS, and DOS is case-insensitive, the
   path needs to be in all-caps in order for FileParseStandardPath()
   to work properly. Call LocalUpcaseString() on the path you have
   above and then call FileParseStandardPath().


How to make small dialog with triggers inside it.

SDK: N9000C:PUBLIC
Q. I want to make a dialog on the Nokia 9000 that is flush with
   the right side of the screen, such that the triggers are in
   the dialog itself, rather than drawn next to the dialog. How
   do I do this?

A. You'll need to make your dialog a GIV_POPUP dialog, instead
   of just a plain dialog. Second, you'll need to make the dialog
   not user initiable and display it with UserDoDialog() or
   MSG_GEN_INTERACTION_INITIATE.


How to copy text from a VisMonikerWithText.

SDK: ALL_GEOS:PUBLIC
Here's an example of how to copy the text out of a textual
VisMoniker, as well as how to copy the text from a text chunk.
Notice that when copying the text from the VisMoniker we must
add in the defined constant VMWT_text.

@start DataResource, data;
@visMoniker MyTextMoniker = "Blahblah";
@chunk TCHAR MyTextChunk = "blah blah";
@end DataResource;

@method TestProcessClass, MSG_TEST_PROCESS_TEST {
    TCHAR buffer[20];
    TCHAR *ptr;

    MemLock( OptrToHandle( @MyTextMoniker ) );
    ptr = LMemDeref( @MyTextMoniker );
    strcpy( buffer, ptr + VMWT_text );
    ptr = LMemDeref( @MyTextChunk );
    strcpy( buffer, ptr );
    MemUnlock( OptrToHandle( @MyTextMoniker ) );
}


Pressing 'send' in launched fax editor fails assertion.

SDK: N9000C:PUBLIC
Q. I'm writing an application that starts up the fax editor and then
   allows the user to send a FAX from there. However, when I press
   the "send" button, the system crashes and I see this in Swat:

Death due to ASSERTION_FAILED
addIt+48:            MOV     AX, 12 (000ch)
Execution died in patient mailbox:
addIt+48:            MOV     AX, 12 (000ch)
*** No explanation available ***
Interrupt 3: Breakpoint trap
Stopped in FatalError, GEOS system source file not available.

   The backtrace of that thread looks like this:

* 1: near FatalError(), bootBoot.asm:878
  2:  far AppFatalError(), bootBoot.asm:878
  3:  far MediaEnsureTransportInfo(), mediaTransport.asm:583
  5:  far MSCGenInteractionInitiate(), uiSendControl.asm:4176
  7: cspr *MySendControl{MailboxSendControlClass}26631(0000h 0004h 3b00h) (@1,
^^l6700h:0020h)
 10:  far VSCGenInteractionInitiate(), uiViewerSend.asm:902
 12: call *MySendControl{MySendCtrlClass}26631(0000h 0004h 3b00h) (@2,
^^l6700h:0020h)
 16:  far OLPopupActivate(), cwinPopup.asm:1875
 18: call *MySendControl{MySendCtrlClass}19461(0000h 0004h 3b00h) (@3,
^^l6700h:0020h)

   What could be going wrong?

A. In the MediaEnsureTransportInfo routine, it's checking that the
   transport/option/medium tuple is valid. However, the validity of
   that medium is not the cause of the problem. You need to attach a
   print control object to your fax send controller. Here's a code
   segment from the SDK_9000\FaxSend1 sample app:

@object ComplexMonikerClass FaxSendSendControl = {
    ComplexMoniker = FaxSendMailboxSendControlClass;
    CMI_topText = CMT_SEND;
    GCI_output = process;
    GII_visibility = GIV_POPUP;
    MSCI_defBodyType = MOT_SELECTION;
    HINT_SEEK_REPLY_BAR;
    HINT_SEEK_SLOT = 0;
    ATTR_GEN_INIT_FILE_CATEGORY = "fax";
    ATTR_MAILBOX_SEND_CONTROL_SEND_SELECTION;
    ATTR_MAILBOX_SEND_CONTROL_SINGLE_TRANSPORT = {
        { GMID_CELL_MODEM, MANUFACTURER_ID_GEOWORKS },
        { GMTID_FAX_SEND, MANUFACTURER_ID_GEOWORKS },
        0
    };
    ATTR_MAILBOX_SEND_CONTROL_TRANSPORT_HINT_OPTR = {
        { GMTID_FAX_SEND, MANUFACTURER_ID_GEOWORKS },
        0,
        @FaxSendPrintControl
    };
}

@object PrintControlClass FaxSendPrintControl = {
    GI_states = @default & ~GS_ENABLED;
    PCI_output = process;
    PCI_docNameOutput = process;
}

   Without the print control, the FAX send controller will crash.


Why does datacall close before timeout?

SDK: N9000C:PUBLIC
Q. I'm opening a socket to download web documents and the ppp
   connection keeps closing after only a couple of minutes.
   The Internet settings is set for 10 minute timeout. I'm
   calling SocketSetMediumBusy(..., TRUE) but that's not
   making a difference. What can I do?

A. Calling SocketSetMediumBusy() only prevents other apps who
   call SocketCloseDomainMedium() from succeeding. If the timeout
   is not abiding by the autodisconnect time and the app itself
   is not terminating the connection through some internal idle
   timeout, then the server might have its own timeout. This is
   easy to check if you have the ppp log file (there's another
   KB article on how to start ppp logging).

   You can set up whatever scheme you want for keeping the
   connection alive between accesses. Using a timer seems to be
   the smartest way. You should still call SocketSetMediumBusy()
   as other apps might still call SocketCloseDomainMedium()
   between your accesses. Note that SocketSetMediumBusy() does
   not override the autodisconnect timeout.


How does ifidn work in assembly?

SDK: ALL_GEOS:PUBLIC
Q. In GEOS assembly, how exactly does 'ifidn' act?

A. "ifidn" simply means "if identical". For example,

      ifidn HARDWARE_TYPE,

   evaluates to true if the macro "HARDWARE_TYPE" is defined to be
   "N9000C". It evaluates to false if HARDWARE_TYPE is defined to
   be something else. I think there'll be a compile-time error if
   HARDWARE_TYPE is not defined, but I'm not sure.


Getting the passive keyboard grab.

SDK: ALL_GEOS:PUBLIC
The keyboard messages MSG_META_PRE_PASSIVE_KBD_CHAR and
MSG_META_POST_PASSIVE_KBD_CHAR are not implemented in the system.
There is no API for getting either the pre-passive or post-passive
keyboard grab.