A Smalltalk System for the Nokia 9110 Communicator

This is a README.HTML file for the development beta 0.8 release of Pocket Smalltalk for the Nokia Communicator 9110, released on 14th March 2000. It's been a long time since the last release, but this one should not be too far from a practically usable system.

The text is both for people who know Smalltalk and do not know GEOS or the Nokia Communicator and for people who know GEOS and the Communicator and do not know Smalltalk. For those who do not know any of these worlds it may be difficult to understand and I would recommend to start with some introductory text on Smalltalk programming (see references near the end of this document) and to come back here after having a basic idea about what Smalltalk is and how the Smalltalk object system works.
 

Contents

 The goals and basic history of this project
 The overview of Pocket Smalltalk for Nokia Communicator
 Installation instructions for Pocket Smalltalk
 Differences from the PalmOS version
 How Pocket Smalltalk interacts with the GEOS system
 Further documentation
 Support and future development
 Changes since previous releases
 

The goals and basic history of this project

The  Nokia Communicator is a pocket device combining a GSM 900 mobile phone (not dual band 1800/900 MHz as most newer GSM phones, but there is also a different US version for the US PCS standard) with an integrated PDA in one convenient package. The integration has some unique advantages, as the PDA has a complete access of the phone functions, such as contact list, list of all calls made, data communications over the GSM network, full Internet functions (WWW, FTP, Telnet, e-mail) and others. Besides the GSM functions, the Communicator can talk to the outside world via a built-in EIA-232 port and IRDA interface. The device is powered by an AMD Elan SC 450 single chip computer based on the 80386 processor, has 2 MB of working RAM, 2 MB of Flash RAM for data storage (flash disk) and can be extended with a MMC card (4 to 32 MB at the moment) expanding the file storage (not the built-in RAM). The operating system is GEOS, an old rival of Windows 2.0 which has been used for some early PDAs both with keyboard and pen oriented input. The Nokia Communicator 9110 has a non-touch-sensitive 640x240 display with 16 grey levels and a backlight, a "standard" keyboard and 7 special control keys (4 at the right side of the display, which are used for controlling most of the applications and 3 special keys at the left: the backlight key, ZOOM key and MENU key; only the MENU key is reasonably programmable, the backlight key and ZOOM key have system level functions).

Although the device has excellent possibilities and the built-in applications (plus some extras available from Nokia) are not that bad, the success so far with techie type folks has been limited due to the lack of any decent way to write own applications for the device. Nokia supplies a "Software Development Kit" (SDK for short), which contains the tools and documentation required to write native GEOS applications for the Communicator. There are several problems with the SDK for an average programmer: first, there is a huge amount of information one has to digest before writing the first usable program; and second, the GEOS system has severe limitations due to the fact that it uses the Real mode of the 80386 processor (i.e.. runs like the old IBM PC XT in 16 bit segmented memory, rather than the 32 bit flat memory model used in operating systems on current PCs).

After trying to write some simple programs for the Communicator using the SDK, I have tried to find some environment which would help to develop complex applications with full UI compatible with the built-in applications, but with higher level language and constructs than the GOC language used in the SDK. The main objectives were to have a completely transparent memory management, graphical environment for program editing and other functions. The only alternatives to GOC for the Communicator were FreeBAS 9K by Conrad Davies (a simple variant of the BASIC language, the environment enables to write programs directly on the device) and PFORTH (an unfinished port of the FORTH language). None of these had the possibility to build the UI compatible with built-in applications and to have the power similar to the SDK. Nokia has also introduced a "Nokia 9000/9110 Development Environment", which is a GUI shell around the SDK with some limited possibilities to generate GOC code for common tasks (this tool has been known in the Communicator programming community as "Blank Screen Generator"), but the only really useful functions were syntax coloring and better access to the documentation files.

After I have failed to find something useful, I have decided to try to port some existing environment to the Nokia Communicator. The source of inspiration was mainly PalmOS, which is gaining popularity and has a lot of available software. The older models of PalmOS devices have similar architecture (16 bit rather than 32 bit, very limited RAM), so porting from PalmOS to GEOS should be much simpler than, say, porting from Windows CE or EPOC32, which are both 32 bit operating systems with flat memory models. Another source of inspiration were old MS-DOS development tools from times when DOS was 16 bit and used to run "well" in 640 KB of RAM. The hot candidates for porting were:

So, in September 1999 I have thrown away my attempts to port TCL and LUA from DOS to GEOS and decided to work on Pocket Smalltalk.

Smalltalk is the oldest (and some people say purest and others say the best) object oriented programming language developed in late seventies and released to public in 1980 as Smalltalk 80 (yes, people were calling versions by the release year even before Windows 95, Algol was probably the first in late fifties). Smalltalk, besides being an elegant and easy to use Object Oriented programming language, is usually a complete programming/runtime environment, which was the first to use bitmapped graphics, a mouse as a pointing device and overlapping windows on the screen. Everything else (Apple, X11, Windows) is based on the ideas and experience of the original Xerox team behind Smalltalk.

Pocket Smalltalk has been written by Andrew Brault (at least all source files contain Andrew's and no other copyright) and is being maintained by Eric Arsenau. It has been written from scratch for the Palm Pilot (before it was called PalmOS or Palm Computing platform), uses the Smalltalk language, but quite a different compilation/runtime model as compared with other Smalltalk implementations. Pocket Smalltalk was released with full sources and a liberal license derived from the license of the popular web server Apache (please read the file LICENSE.TXT). I have decided to port this system to the Nokia Communicator.

It took me over 6 months (about 2 evenings per week, one or two full days in a month over weekends, about three full days in bed while sick at home) to get to a system which could be used for writing real life applications. The Virtual Machine (VM, what interprets the Smalltalk bytecodes on the Nokia Communicator) has changed very little over this time, except some glue code between Smalltalk and GEOS. The IDE (Integrated Development Environment, the application running on a PC and producing a binary file to be run by the VM on the Communicator) has changed only due to some enhancements and bug fixes. What has changed the most is the glue from Smalltalk to GEOS and the set of predefined files in Smalltalk with definitions of the GEOS system interfaces. With these, you can do (nearly) everything as in the GOC/SDK, and even the existing limitations are slowly being removed.

I owe much credits to Andrew Wilson from Magna Praeda, who answers all my crazy questions about GEOS internals and has been my valuable source of information and advice. Without his help, the GEOS port would never become a reality. Other people such as Marcus Groeber have provided sources to their GEOS programs to give me some background information how a real life GEOS application for the Nokia Communicator should look.

So, to summarize the (now nearly 100% achieved) goals of the Pocket Smalltalk for Nokia Communicator (PST9110 for short):

The overview of Pocket Smalltalk for Nokia Communicator

The Pocket Smalltalk for the Nokia Communicator programming system consists of the following parts:

Installation instructions for Pocket Smalltalk

Installing the demo application

Installing on the real 9110 device

Use the PC Suite or NSERVER on the PC (+ the install/remove software application in the System launcher on the 9110) and install the demo files (one goes to WORLD\EXTRAPPS, the other to DOCUMENT) using the provided pst.ins file. The description will be "Pocket Smalltalk 0.8 Virt. machine and Image". For your applications, you can use the vm.ins (Image only) installation script, which installs only the PSTVM.VM file with compiled bytecodes.

To run the demo application, go to Extra launcher, start EC Pocket Smalltalk (the EC means Error Checking), press the RUN trigger, see what happens, CLOSE the application.

This version of the demo application does several things:

  1. Calls a function in the eci.geo library called EciGetImei (gets a string with the IMEI of the phone - more or less an unique serial number of the phone), converts the result to Smalltalk string, displays the result (Basic test for GEOS API interface to a library which is not normally in memory).
  2. Creates a dynamic UI dialog box which enables you to edit some text, the dialog is closed when OK is pressed, the resulting text is displayed.
  3. Creates a dynamic UI dialog box with GenBooleanGroup (a set of on/off switches), waits for the user to make some changes and displays the result once OK is pressed. The result is a word with individual bits on and off for the individual GenBoolean items.
  4. Creates a more complex UI dialog box with two GenItemGroups, lets the user to make a selection and displays the result after the Close trigger is pressed (the result is an OrderedCollection of two positions in the two lists, with the topmost position as 0). This demo uses a GEOS class defined in Pocket Smalltalk and uses a GEOS method in Smalltalk (this is necessary to synchronize the UI and the main PST application using a GEOS semaphore).
  5. Displays a window to enter a Smalltalk expression using integers and + and - operators, parses and compiles this expression into Pocket Smalltalk instructions and interprets these instruction with an interpreter written in Pocket Smalltalk (there is no link to the underlying Pocket Smalltalk system, it's a quick and dirty port of a part of the IDE from Dolphin to Pocket Smalltalk). The resulting instructions and the result are displayed. To close the window, enter any expression which evaluates to the integer 0 (such as literal 0). This test shows that Pocket Smalltalk can process even larger applications, as only this part has about 11,000 lines of Pocket Smalltalk code.
You can run the test many times just by pressing Run. The output is scrolled once the screen is filled and you can use the up and down arrow keys to scroll with the window.

Installing the demo on the 9110 emulator

If you do not have the Nokia SDK and the emulator contained there, you can download a free 9110 emulator from http://www.forum.nokia.com/developers/comfriendly/comfriendly.html. Both the emulators work only on Windows NT or Windows 2000, they do not work under Windows 95 and 98, sorry. I have no experience with the older emulator of the Nokia 9000 Communicator, which should run in DOS/Windows 95/Windows 98. The demo uses a 9110 specific eci.geo library, so it would not run in the Nokia 9000 Communicator emulator without taking out the first step of the demo.

If using the SDK emulator, please use the Error Checking version (EC). This is slower, but performs a lot of checks on all GEOS system calls, so any problems encountered should be reported in SWAT (a GEOS debugger available with the SDK). To see the errors reported, you should always start SWAT after starting the emulator and keep it sitting in the background. If any problem is detected by the EC functions, it is (sometimes) reported with explanations and context in SWAT and you can use SWAT commands to explore the reasons even deeper. For the standalone emulator, only the non error checking (NC) version is available, so replace .EC to .NC in the following path names.

To install the Virtual Machine, copy the file pstec.geo to a directory called WORLD\EXTRAPPS in the SP_TOP of the emulator (this would be something like C:\PCGEOS\yourname\N9110V10.EC\WORLD\EXTRAPPS in the 9110 SDK emulator and emulator\WORLD\EXTRAPPS in the free emulator). Then copy the file pstvm.vm to DOCUMENT (i.e.. C:\PCGEOS\yourname\N9110V10.EC\DOCUMENT or emulator\DOCUMENT).

Once installed, you can run the emulator, go to Extra Launcher (CTRL-F12 on my keyboard) and to start the Pocket Smalltalk demo as in previous section.

Installation of the IDE (Development Environment)

You need Dolphin Smalltalk 98 version 2.1 to install the IDE (you can get it freely from http://www.object-arts.com/Downloads/2.1/Downloads.htm). After you install and start Dolphin Smalltalk, go to Dolphin Package Browser (Tools Menu), choose Package, Install and load the file pstgeos.pac file into Dolphin. Choose the PSTGEOS in Package Browser, display Package Comment (bottom half of window) and select the text:
        Q initGeosSystem.
        QLauncher show.
With this text selected, type CTRL-E (Execute) and a new window will open (Pocket Smalltalk Launcher). Now you can close the Package Browser window and in the Dolphin System Transcript Save the Image (either with a toolbar button or from the File menu). After you run Dolphin Smalltalk next time, you will get a Pocket Smalltalk Launcher window immediately. Do not save the Image while closing Dolphin Smalltalk, unless you have made some changes to the IDE classes or want to save your environment as it is and return to the same state later.

All further work will be done in the various Pocket Smalltalk windows. All these windows are launched from the Pocket Smalltalk Launcher.

Compiling the demo application from sources in PST IDE, generating compiled bytecodes

Now go to Pocket Smalltalk Launcher and select Tools, Package Browser. A new window opens, choose Package, Install Package. You have to install various system packages first, before you can install the files for the actual demo. All packages are installed in a same way. The difference is that it is better to mark the system packages as Don't save with project, so that you do not overwrite system files by accident. On the other hand, if you are not careful, you might lose your changes. All the changes you make in the IDE are saved to a file called pocketst.chg, which is in the directory with the Dolphin image. If you lose something, you should be able to find it in this file (as opposed to other Smalltalk systems, Pocket Smalltalk does not include tools for browsing the change file).

For any Nokia Communicator application in Pocket Smalltalk, you will have to include the following system packages before you start to make any changes. Please note that some of the longer files parse and compile a long time (up to a minute on my notebook), the usual Windows hourglass cursor is displayed during this time. So, to prepare for the demo application, you have to include the following packages and you should mark all of them as Don't save with project:

It is a good idea to save the project now, making it a start to all future projects so that you do not have to include all the files manually one by one. The projects are saved into project files (*.prj), which are nothing more than a list of packages and their attributes. All the changes done to classes in packages not marked as Don't save with project are saved to the individual .st files. You can call the empty project as base.prj and when starting a new project, you can open the base.prj project, add/create your packages and save your projects under different names. You can also make a Dolphin image file with the base.prj project open and start from that image rather than from an image with just an empty launcher (you can have several Dolphin images and start them individually by double-clicking on them in the Dolphin program directory). It is much faster to load a Dolphin image with a Pocket Smalltalk project than to parse the .st files using Open Project in Pocket Smalltalk Launcher. The current Pocket Smalltalk parser/compiler is quite slow and memory hungry, you need at least 64 MB or RAM for any decent performance. I will try to fix this with Eric Arsenau so that the parsing/compiling is faster and takes less memory. This has no impact on the speed/memory footprint of the compiled Pocket Smalltalk programs, it's just a problem of the IDE implementation.

Now we need to include the files which are specific to our Pocket Smalltalk for Nokia Communicator demo. As you will probably change these, you should not mark them as Don't save with project and you should make the last file marked as Default (which means that all new Smalltalk classes will go into this package). Please note that the Default package information is not saved with the project, so that you have to mark some package as Default or to check all classes and Constants for Uncommitted before saving the project, or you will lose your changes. The demo application specific files are these:

Now you have all the system and demo classes compiled and you can browse them. To work with the source, launch a separate Pocket Smalltalk Class Browser window (from the Pocket Smalltalk Launcher Tools menu). As there are lots of classes, it is not obvious what is the system stuff and what is specific to the demo. In general, everything under the Geos class is something linking the Smalltalk and GEOS worlds together. Besides pure GEOS definitions, it contains also the glue code to link Smalltalk and GEOS objects together, some helper methods to make creating and modifying easier in Smalltalk and there are also the methods for the UI demo dialogs (they are at the class side of the class GeosMetaObject).

When the Pocket Smalltalk application is started, the interpreted first executes the method basicStart in the class side of Smalltalk class. As you can see, basicStart does some system initialization and starts Smalltalk class>>start, which does the real work. The definition of start contains simple invocations of the individual demo steps one by one, always displaying the result into the console window using Geos class>>showText:.

The hierarchy of classes under the class called Q is the Pocket Smalltalk parser/compiler/interpreter and these classes are similar (or even the same) as those under Q in the Dolphin PST IDE. Please note that if you comment out the last step in Smalltalk class>>start, the resulting compiled bytecodes will not include anything from the Q class hierarchy, as these will be left out by the optimizer (unless you turn optimization off).

All classes under Meta are GEOS classes and the Smalltalk objects are simply links to underlying GEOS objects and Smalltalk methods are either glue methods (on the class side of GEOS classes), or map GEOS instance variables, vardata and messages to Smalltalk methods (these are on the instance side of GEOS classes). There are some Smalltalk helper methods, which were defined manually (remember all the geos/*.st files were generated automatically with the classes.pl PERL script) and there is one GEOS class defined in Smalltalk in the demo - it is GenInteractionSmalltalk, which overrides the GEOS system MSG_GEN_GUP_INTERACTION_COMMAND, which is available in Smalltalk as #gupInteractionCommand:.

Now you should save the demo project under a different name (say, demo.prj). You can also save the Dolphin Image file so that you can continue any time from where you have left off. To generate the compiled bytecode file, use System, Generate Code (it will ask you for the name of the *.vm file; the current pstec.geo application can handle only the pstvm.vm file, so you have to name the file with this name or to rename it later to be used).

To install a new PST Image, install that either to the Communicator (using the VM.INS script; say yes to the question to replace an existing document file) or to the emulator.

The supplied demo pstvm.vm file is with debug info (names of classes and symbols for error messages) and with optimizations on - so it has about 67 KB. If you turn off optimizations, the pstvm.vm will increase in size several times (515 KB). Turning off debugging and keeping optimizations on reduces the size to 51 KB for the whole demo (remember it is over 10 thousand lines of Smalltalk code).

Enhancing the Demo application

Not written yet, sorry!

Working with PST Virtual Machine sources

You do not need the Virtual Machine sources to create your applications in Pocket Smalltalk - provided the existing Virtual Machine can do what you need in terms of primitive methods and other ways to interact with the target system. The current version of the Virtual Machine is powerful enough so that all real work can be done in Pocket Smalltalk.

You need a CD called Nokia 9110 SDK - you need to register at http://www.forum.nokia.com/developers/communicators/geossdk/9110sdk_request.html and Nokia will send you the CD free of charge (it took over a month in my case, so be patient). The SDK works only on Windows NT or Windows 2000, so you're lost if you have Windows 95 or 98.

To compile the sources, you need the Borland C/C++ compiler version 4.5x (I have 4.52, which was given to me by someone who had this for a long time and had no use for it any more). The 4.x is apparently shipped with the newer versions of the same product (such as 5.x) and is bundled with certain C/C++ textbooks widely available. The Borland C 4.x is not available from normal software retailers any more. You need only the MS-DOS real mode parts of the environment for the Nokia SDK development, you do not need to install any Windows or database or other optional components, these are of no use for Nokia Communicator development.

Once you have installed Borland C and the Nokia SDK (you need about 500 MB of free disk space for these two CDs!), you can copy the PST directory to your GEOS development branch, go to PST and to make a new version you can execute "mkmf" (make makefile) and then executing "pmake" will build a new version of the PST Virtual Machine. If you change existing files, executing pmake would do the rebuild, if you introduce new files, you need to re-run mkmf (the Makefile is created automatically, you do not need to manually list the files anywhere).

Main differences from the PalmOS version (a chapter for those who are familiar with the PalmOS version of Pocket Smalltalk)

Resources

The PalmOS version of Pocket Smalltalk is dependent on PalmOS resource files, which contain the PST Virtual Machine resource, UI resources and possibly other data. The Nokia Communicator version uses a separate file for the Virtual Machine (PST Virtual Machine Geode application) and the UI is built dynamically with the Pocket Smalltalk program, rather than being statically defined at compile time. For that reason, the Resource related functions in the Constants browser tool are not relevant to the Nokia Communicator.

SYSTRAPs and other system API

All the system API in PalmOS is done via the SYSTRAP mechanism and the set of available SYSTRAPs is limited at the time the IDE is built. PST for PalmOS is providing support for lots of SYSTRAPs (all?) and the PalmOS PST Virtual Machine provides instruction for SYSTRAP interface. There are wrapper Smalltalk methods to a lot of SYSTRAPs useful for Pocket Smalltalk programs for PalmOS.

The GEOS API is different to that of PalmOS in many respects - the SYSTRAPs use single entry point to call all the functions which are assigned mnemonic names, but the actual call uses a 16 bit number to identify the entry point. The programming model in PalmOS is for plain C language. In GEOS, the system API is spread over a number of dynamically loaded libraries and the actual interface is via a function call directly to the entry point of the library (identified with library name and ordinal number of the entry). GEOS uses both Pascal and C calling conventions, which complicates things even further, as the Smalltalk glue code needs to know whether to use the C or Pascal calling convention. The aspect which complicates the link between Smalltalk and GEOS the most is the fact, that the GEOS system itself is object oriented, has its own class system, objects and messages. The GEOS system of classes and methods is more complicated than the Smalltalk one in at least two aspects: first, the GEOS classes can have multiple inheritance, that is a class can have more than one class as its superclasses (in GEOS speak this is called a variant class); second, the object instances can have fixed instance variables, but can also have optional data attached to them, which are called vardata in GEOS speak. For a system with most of the power of GOC we have to map the variant classes mechanism and the vardata to the straightforward Smalltalk object model.

Most of the complexity to learn to use Pocket Smalltalk for the Nokia Communicator is in the fact that one has to learn at least some basics about the GEOS object model, understand what the various GEOS UI classes do and which methods should be used for which function and which methods are called by the operating system and the application has to override them in application specific classes to handle some system events. For the functionality to handle GEOS system events in Smalltalk it is necessary to be able to create new GEOS classes in Smalltalk and with user written methods in the Smalltalk language.

Application framework

The PST for PalmOS provides classes for the PST application framework, which takes care of handling PalmOS events, mapping them to calls to PST methods etc. etc. As the GEOS system already uses an object oriented model for handling system events, the amount of Smalltalk glue code required to process system events in Smalltalk is much lower than in PalmOS, but where the PalmOS handler can be more or less universal for all PST applications, the object oriented handlers for various GEOS UI classes has to be unique for each application and has to use GEOS classes defined in Smalltalk and with Smalltalk language methods.

The PalmOS program is started at one starting point when launched and executes until finished (or in infinite loop). The GEOS program on the other hand does some initialization at start-up and then is event driven by the operating system itself, rather than some get-event/process-event loop (this loop is part of the GEOS kernel, rather than being part of every application). This means that a typical Pocket Smalltalk application would build most of the UI and other GEOS objects at start-up and then simply pass control back to GEOS kernel. As the user controls the UI, the GEOS kernel calls user written methods (in Smalltalk), which once finished pass again control back to GEOS. So in PalmOS, the Virtual Machine loop is started once and executes until the program finishes or crashes, but in GEOS the Virtual Machine is called many times (sometimes even at nested levels) and after executing some methods passes control back to GEOS. It is obviously possible to write start-to-finish programs in Pocket Smalltalk, but it is rather difficult to provide more than very basic UI for these non-event-driven programs.

Graphics, UI, ...

The graphical and UI model for GEOS and PalmOS is quite different. Both versions of the Pocket Smalltalk system can access most functionality of the underlying operating system and libraries, but the details are completely different, so porting applications from one platform to the other is by far not trivial, at least for the graphics and UI parts. The part which is called Model in Smalltalk terms (MVC - Model View Controller) can be ported without any changes, but the interactive parts need to be written again from scratch.

How Pocket Smalltalk interacts with the GEOS system

Understanding Smalltalk primitives

The most common and "Smalltalk native" way to perform tasks which are not possible or efficient in Smalltalk is to use the "primitive" methods. These methods are written in C and are part of the Virtual Machine. A typical example of a primitive method is the Integer>>#+ method for adding two integer numbers and returning the resulting sum. Most of the primitive methods in Pocket Smalltalk are not GEOS specific and implement basic operations for typical Smalltalk classes such as numbers, collections, streams and so on.

For linking of Smalltalk to GEOS there are some system primitives, which provide access to various things in GEOS or to components of the Virtual Machine. For instance the Geos>>geosClass:number: primitive returns a CPointer object to the GEOS internal data structure (ClassStruct) used to describe GEOS classes, based on library entry number and library number (GEOS classes are exported from libraries in a similar way to functions through numbered library entries). All the GEOS specific primitives are defined as class methods of the Geos class.

Calling GEOS C API functions

Pocket Smalltalk for Nokia Communicator can call all entries in all GEOS shared libraries. The Nokia 9110 Communicator is shipped with 95 shared libraries, but the GEOS SDK does not provide the required *.LDF and *.h/*.goh files for the RSA Data Security crypto libraries bsafe.geo, crypto.geo and ssl.geo (they are used by the built-in WWW browser in HTTPS connections), the emulator of the floating coprocessor int8087.geo and intx87.geo, the libraries linking the phone functions with GEOS ota.geo, rbus.geo and vp.geo, the Nokia Communicator specific UI library rudy.geo and libraries with other functions called impex.geo, smbcard.geo and ssmeta.geo (I have no idea what these libraries do). So, there are 83 libraries with available *.ldf files, which can be called from Pocket Smalltalk. These libraries are described in a file called n9110PST.plt, which is a hand edited version of the SDK file \pcgeos\n9110v10\installed\include\n9110v10.plt and the differences are in taking out libraries without available *.ldf files and changing the order of the libraries for compatibility with older versions of Pocket Smalltalk (which had hard coded definitions of the first few libraries, namely geos.geo, ansic.geo, eci.geo, ui.geo and foam.geo). The order of libraries in the file n9110PST.geo gives the libraries their internal Pocket Smalltalk numbers (the libraries are accessed by file names in GEOS), which are used for all reference to the individual libraries. The mapping of names to numbers is done by Pocket Smalltalk constants with names ##geosLIBnn (where nn is the number of the library), the value of the constant is the library file name (without the EC and .geo suffixes, but including the GEOS folder name starting from the SP_TOP system - the system libraries are in the SYSTEM folder).

The library entries can be functions with three different calling conventions: Assembly (the parameters and results are passed in processor registers), C (parameters are passed on the stack in reverse order from right to left and removing the parameters is the responsibility of the caller) and Pascal (parameters are passed on the stack in normal order from left to right and are removed from the stack within the called function), global variables and classes. For the C API, only the C and Pascal calling convention functions can be used from Pocket Smalltalk. Most functions are available with both Pascal and Assembly calling conventions and the Assembly calling convention functions cannot be used from C/GOC, so you do not use anything without the possibility to call Assembly calling convention functions.

The Perl script classes.pl generates Smalltalk definitions for all C and Pascal entries in all GEOS libraries as helper methods on the class side of the Geos class. The implementation of the method is to use the "GEOS" instruction of the Pocket Smalltalk Virtual Machine (the idea is based on the PalmOS Pocket Smalltalk SYSTRAP instruction), which has normal Smalltalk syntax of a message with a special receiver GEOS and the first keyword specifying the type of GEOS call (GEOS method, function). For API calls, the first message keyword has to be call:. All other keywords are with: only to separate the arguments from each other.

The last parameter to GEOS call: is a Smalltalk ByteArray constant (using #[v1 v2 ...] syntax) with library number in the first byte (and a flag whether C or Pascal calling convention should be used in the topmost bit, so you can use up to 128 shared libraries in one Pocket Smalltalk application), the entry number in the next two bytes (in the network byte order, so more significant byte first), followed by one byte for each parameter specifying the type of the parameter and followed by the last byte which specifies the type of the return value from the API function call.

The codes for types of parameters are as follows:

0    void - used only for return type when the function does not return any value

1    word - 16 bit unsigned integer, also used for unsigned 8 bit values
2    dword - 32 bit signed integer
3    CPointer - a 32 bit pointer passed as CPointer instance or as ByteArray instance, when used as result a new CPointer object is created
4    short - 16 bit signed integer, also used for signed 8 bit values
5    double - an 8 byte IEEE double floating point value
There is an unhandled code for C structures which are passed on the stack (rather than being referenced by a pointer, which is OK) which takes 2 bytes per structure, but these calls will always fail in the current version of Pocket Smalltalk. There are very few GEOS library functions taking structures as their arguments on the stack, rather than being passed a pointer to the structure.

Another limitation is that you cannot write callback functions in Pocket Smalltalk and pass them as arguments to certain system functions. So API calls requiring a callback functions cannot be used in Pocket Smalltalk. You would have to code the callback (including the API call to use it) in C or GOC and interface this code to Smalltalk as a primitive or to put your code into a separate shared library and call it using Geos call: from Smalltalk.

Let's use the memcpy function for copying a block of memory as an example. This function is provided by the ansic.geo library and is exported as entry number 44 and uses the Pascal calling convention (you can find this with the printobj.exe tool provided with the Nokia SDK the ansic.ldf file). The definition in the SDK ansi/string.h file is as follows:

void * pascal memcpy(void *__dest, const void *__src, size_t n)
That is, the function returns a pointer and takes two pointers and an unsigned 16 bit integer as its arguments. The Pocket Smalltalk definition generated by the classes.pl script is as follows:
memcpy: __dest with: __src with: __n
        "void *pascal memcpy (void *__dest, const void *__src, size_t __n) in ansi/string.h"
        ^GEOS call: __dest with: __src with: __n with: #[1 0 44 3 3 1 3]
So, the Smalltalk helper method to access the memcpy function from the ansic.geo library has the selector memcpy:with:with: (the first keyword is always the name of the function as in C, all parameters are separated with with: keywords), the names of Smalltalk parameters are taken from the C definition, the C definition is repeated as a comment and the link to the actual library is via the GEOS instruction with the call: selector, all parameters are passed to the GEOS instruction plus the extra parameter defines in a ByteArray that the memcpy function is exported from library number 1, has Pascal calling convention (highest bit of the first byte is zero), is entry number 44 (second and third byte), takes two pointers (3) and one unsigned 16 bit integer (1) as parameters and returns a pointer (3). The value returned from the GEOS instruction is returned as the result of the Smalltalk helper method. To use the Smalltalk method, say we have a Smalltalk String object and a CPointer and want to copy the content of the string to the pointer. To make a usable C string, we have to supply the trailing null byte after the content of the string. We simply do:
    Geos memcpy: aCPointer with: aString with: aString size.
    aCPointer byteAt: aString size put: 0.
In our example, we throw away the return value from the function, which is the usual way to use the memcpy function in C.

The GEOS instruction is defined in the Pocket Smalltalk Virtual Machine source file vm.c and you can understand the handling by reading the C source code there. In short, the instruction is followed by a byte with the number of parameters really passed to the instruction (including the spec argument), which is checked against the length of the spec ByteArray for the correct number of parameters. The calling convention, library number and entry number are extracted from the spec argument, all parameters are checked against the spec and converted to C integers or pointers from Smalltalk integer or pointer representation (integers are objects in Smalltalk and therefore are not simply words or doublewords), pushed into a parameter array in a correct order depending on the calling conventions, the actual library entry address is obtained and the function is called via a pointer to function (there is some extra trickery in GEOS for function calls over a pointer, as function pointers do not point to actual functions, but need to be converted to real addresses first). The helper functions are in the file pstgeos.goc. Finally, the returned value is converted to the appropriate Smalltalk object and the execution is finished, returning control back to the main Virtual Machine interpret loop.

Using GEOS #defines and enums

GEOS uses a lot of C enumerated types and has an 8 bit enumerated type, where the constants have to be manually defined using #define construct of the C preprocessor. For using C functions and types, you need to have the access to the values of the individual constants, as the Nokia SDK documentation does not tell you the values, only the names of the values. That is why all enumerated types are converted together with all #defines defining numeric values into Pocket Smalltalk constants.

Pocket Smalltalk constants are very similar to C #defines, as they are resolved to actual values at compile time and for the Virtual Machine it is irrelevant if the source did say 123 or ##const when ##const is defined as 123. The underscores and capitalization of all enums and #defines is preserved from C, so you can use any constant available to a C program as ##constant. As opposed to C API definitions and GEOS classes, which use individual *.st packages for each library, the file enums.st contains definitions for all the available .h and .goh header files in the whole SDK and therefore for all the libraries. These constants take memory in the IDE, but do not have any overhead at run time, so do not hesitate to use them.

Please note that in C, the C compiler can evaluate constant expressions at compile time, which is something Pocket Smalltalk cannot do (Dolphin Smalltalk has a syntax ##(expression) which is evaluated at compile time, but Pocket Smalltalk does not have this functionality at the moment), so if you write in C something like (GIA_NOT_USER_INITIATABLE|GIA_MODAL), which is evaluated at compile time to a single numerical value (0xa0), but in Pocket Smalltalk you have to write (##GIA_NOT_USER_INITIATABLE bitOr: ##GIA_MODAL), which is evaluated at runtime on the device as (16r80 bitOr: 16r20).

You can browse the enum and #define constants in the Constant browser, under the Geos enums and define constants category (in alphabetical order). There is no way to include a comment with constant definitions, so the information which constant belongs to which type is not available in the Pocket Smalltalk IDE, but you can rely on the naming scheme used in GEOS to prefix the constant with the abbreviated name of the type (GIA for GenInteractionAttrs in our example above).

Using GEOS C structures and unions in Pocket Smalltalk

Besides numbers and pointers, C (and GOC) use arrays, structures and unions to represent the data in the applications and system interfaces. The Smalltalk object instances are very similar to C structures in principles, but there is no easy mapping of C structures to Smalltalk. With the large number of structures and unions defined in various GEOS libraries and used as parameters to API calls and GEOS object messages (there are 937 structure and union definitions translated to Pocket Smalltalk from the Nokia SDK files to a file called structs.st), it is necessary to make the access of the GEOS structures simpler in Pocket Smalltalk.

The Pocket Smalltalk defines a class CStructure, which contains some basic methods to access various fields of the structures, which are referenced by a pointer to the structure. The fields have to be either bytes, words (2 bytes) or dwords (4 bytes) and only numeric values can be extracted or stored in the structure fields. To access a field in the structure, you need to know its offset from the start of the structure and the length of the data type of the field. The CStructure class is not meant to be used directly, but it is meant to be used as a superclass to classes defining different structures. The structs.st files provides definitions to all GEOS system structures and unions.

The GEOS structures and unions are placed one extra level of subclassing deeper, under a class called GCS (short for GeosCStructure), so that user defined CStructures can be easily separated from system structures (remember, there are 937 definitions and 937 subclasses of the GCS class). Due to name conflicts with Smalltalk classes (Rectangle, ...), the GEOS structures and unions are prefixed with GCS followed by their original C name (so that C Rectangle becomes GCSRectangle).

The Pocket Smalltalk definition of each GEOS structure or union contains one class side method called sizeInBytes, which returns the size of the data in the structure or union and in the instance side contains Smalltalk access methods to access and change all structure fields in a way similar to access methods to access named instance variables of Smalltalk objects. So for a C structure Rectangle defined in C as:

/* standard structure for a rectangle */

typedef struct {
    sword       R_left;
    sword       R_top;
    sword       R_right;
    sword       R_bottom;
} Rectangle;
the Pocket Smalltalk definition would define the class GCSRectangle with a class side method GCSRectangle class>>sizeInBytes returning 8 (four words of 2 bytes each) and the access methods GCSRectangle>>R_left, GCSRectangle>>R_left: and so on. The access methods call the CPointer>>wordAt: and CPointer>>wordAt:put: methods to actually access the fields within the structure. The offsets and sizes of data types are computed statically while translating from .h and .goh files into Pocket Smalltalk definitions. So the definitions of the access methods for the R_right field are as follows:
rRight
    "sword R_right"
    ^pointer wordAt: 4

rRight: value
    "sword R_right"
    pointer wordAt: 4 put: value
Please note that the C names of structure fields are converted to Smalltalk conventions, that is words are separated with capitalization rather than underscores and instance names/methods start with a lowercase letter. This rule is applied to most names with different conventions in Smalltalk and C or GOC.

The problem are fields which are either arrays or nested structures or unions, as the access methods cannot simply be expressed in terms of methods like wordAt: and wordAt:put:. The current version of the classes.pl program does not try to generate something clever like using memcpy or other functions, as the representation in Smalltalk would be a problem. So to give you the information about the fields existence, the generated access method has only the comment with the C definition of the field, but does not do anything to access or modify the data in the field. The comment includes besides the C definition two numbers, the first is the offset of the start of the field within the structure or union and the second is the size of the field in bytes. You can use this informatio to write your real accessors for the field. Please note that from the all structures and unions, only a few contain nested arrays, structures and unions.

Another problem with converted defintions which need to be manually modified is with structures having arrays as their last field, where the array can have any size for a particular instance of the structure, but the structure definition contains a fixed size array field with only one item in the array (i.e.. char text[1]). As classes.pl things this field is exactly one byte long, it generates the access methods as for a charfield (using byteAt: and byteAt:put:).

There are other subtle problems and limitations with the converted definitions, but listing them all here would take too much time, but as a general rule everything consisting of bytes, words or dwords should work fine, everything else needs manual checking or redefinition of the accessor methods. So far I have not found any bug in my algorithm to compute the offsets and field sizes (and the size of the structure), but as classes.pl does no do a complete C/GOC parsing, but is based only on simple regular expressions, there may be structures or unions with incorrectly computed sizes or field offsets. Please let me know if you find any irregularities of this kind.

Working with GEOS objects in Smalltalk, building UI Generic Trees

For those readers not familiar with the GEOS object system I would recommend to read the part called GEOS Programming before continuing with reading this part of this document. The part is on the SDK CD-ROM in pcgeos\techdocs\Programming\GOCLanguage\index.htm.

The GEOS object system is strongly influenced by Smalltalk (remember: Smalltalk was the original OO language) and other newer object oriented programming languages, but certain aspects of the GEOS class system are quite different from what is used in Smalltalk. The GEOS object system was designed with Assembly programming in mind and extended to GOC, which is an extension to the C language influenced by the language Objective C (not C++, another object oriented extension to the C language). There is therefore no direct mapping of the GEOS objects to Smalltalk objects and the object-oriented features of both systems. The resulting implementation of the mapping is therefore inevitably a compromise between power, memory consumption and speed of execution.

In Smalltalk, all data are objects, even numbers, characters and strings. In GEOS (and C++ and Java, to name some recently popular OO languages), there are "primitive types" such as numbers, which are not objects, and then there are objects, which contain data in C struct-like instances and methods, which act on the data. Most UI objects in GEOS are statically created at compile time and new objects are rarely created in runtime in a typical GEOS application. In Smalltalk, most objects are created in runtime and most operations even on simple values create new temporary objects, which are later reclaimed by the Garbage Collector.

In Pocket Smalltalk, the GEOS objects are typically created in runtime, so the UI is built from scratch after the application starts and does not exist already built in the application geode which is the case with most GEOS applications. For this reason, programming the UI and working with objects in Pocket Smalltalk is different from the usual ways to deal with objects in GEOS. But Pocket Smalltalk provides most of the glue necessary to handle creation and destruction of UI objects in runtime, so you may ignore most of the warnings in the GEOS SDK documentation discouraging anybody to try to create objects dynamically in runtime. In Pocket Smalltalk, that is the only way to work with GEOS objects.

The top of the hierarchy of classes in Smalltalk is called Object and all Smalltalk classes are subclasses of the Object class (well, in Pocket Smalltalk you can have other root classes besides Object, but we can ignore this for discussing GEOS objects). The top of the GEOS object hierarchy is the class called MetaClass (the word Class is always the part of the class name in GOC) and all GEOS classes are subclasses of MetaClass.

For each GEOS class, the classes.pl program generates a helper Smalltalk class, which enables processing of GEOS objects of that class in Smalltalk. The top of the helper classes is the Smalltalk class GeosMetaObject and all Smalltalk helper classes for GEOS classes are subclasses of the Smalltalk class GeosMetaObject. The Smalltalk helper classes for GEOS classes are called after the GEOS classes, but without the trailing word Class. At the moment, there does not seem to be any name clash among Smalltalk and GEOS class names. So under GeosMetaObject class there is a single subclass called Meta, which is the Smalltalk helper class for GEOS MetaClass. All other subclasses of the MetaClass have their helper Smalltalk classes below Meta.
 

Creating GEOS objects in Pocket Smalltalk

Each GEOS object which is handled from a Pocket Smalltalk program has a helper Smalltalk object, which is an instance of the Smalltalk helper class for the GEOS system class. The helper Smalltalk objects have a single instance variable, which contains a GEOS object pointer (optr) to the underlying GEOS object instance. GEOS object pointers are 32 bit numbers and are handled as instances of the class LongInteger. So the memory overhead for the Smalltalk helper object is 3 words for the Smalltalk object header plus one word for the optr instance variable (8 bytes in total) and another 3 words for the LongInteger Smalltalk object header plus 4 bytes of the LongInteger value (10 bytes), making the total overhead equal to 18 bytes. As these are actually two Smalltalk objects, they consume two slots in the Pocket Smalltalk object table (you can set the size of the object table in the Constants browser in the category System Properties). The overhead for objects which are instances of GEOS variant classes (see the chapter about multiple inheritance) is larger by 1 word in the helper obejct and one more helper object and one more helper object, which takes 4 words. This means there are 10 more bytes of overhead for each variant class instance.

Please note that while working with Smalltalk helper objects there may be created some temporary objects (such as objects of classes CPointer, CStructure and LongInteger), which will be reclaimed by the Smalltalk Garbage Collector when not needed any more.

The clases.pl program generates enough information for all Smalltalk helper classes for system GEOS classes so that combined with predefined methods in the Smalltalk class GeosMetaObject you can create new GEOS objects including the Smalltalk helper objects by simply sending new to the Smalltalk helper class. The result can be used in a cascaded message send in Smalltalk to further set the new object to the required state.

GEOS objects are not created in one common object memory as in Smalltalk, but are created in so called Object Memory Blocks. Each object memory block in GEOS is owned by one GEOS thread and all objects in that object memory block belong to that thread. While dynamically creating (instantiating) GEOS objects, the system call has to specify in which object memory block should the new object created. In order to be able to use a simple new class message for creating new objects, the Smalltalk helper classes store the object memory block handle for all newly created objects in a class variable ObjBlock in the GeosMetaObject class. A new object block is created and a handle to this block is assigned to the ObjBlock variable in the newObjBlock method. If you need to create more than one object block or to create GEOS objects belonging to other than the UI thread, you need to assign the ObjBlock class variable a different value.

Working with GEOS instance variables

In GEOS, the class system is based on C structures and the fields of these structures are called instance variables as in Smalltalk. As GEOS instances are structures, they can be accessed in GOC both using accessor methods as in Smalltalk and through direct access to object instance fields using a pointer (which is similar to using the object instance variables in Smalltalk). The GOC syntax for creating static objects at compile time resembles the C syntax for assigning values to C structure fields. If instance variables need to be accessed or changed in runtime in GEOS, there is a way to create a pointer to the object and to access the fields of the structure over that pointer. As there are instance variables which cannot be accessed or assigned to using GEOS messages sent to the GEOS object, the classes.pl program generates helper methods for all instance variables of all GEOS classes, which are similar to the helper methods to access struct or union fields. The implementation of the underlying wordAt: and wordAt:put: type of methods is different for GEOS classes than for GEOS structures, the usage from Smalltalk is the same and the limitiations are also indentical to those for the structures/unions. The names of instance variables are changed to Smalltalk conventions by the same rule as are structure fields.

The GEOS accessor methods should be more efficient than the Smalltalk generated accessor methods for instance variables, so unless you want to achieve maximum similarity with the static GOC object definitions, using GEOS messages to set object instance variables should be faster.

Working with GEOS objects vardata

In GEOS, the class system is based on C structures and the fields of these structures are called instance variables as in Smalltalk. Besides fixed instance variables, GEOS knows other instance data called vardata (for variable data), which are optional tagged values attached to instances besides the static instance variables. The vardata are either valueless, which serve as boolean properties (the property is given to the object by including the tag with no value for the vardata), or contain a value which can be of any C type. The vardata can be added to the object statically when the object is statically built at compile time (GOC/C), or to be added or removed dynamically to any existing object. The vardata presence can be tested and the values of the vardata can be accessed and changed. In Pocket Smalltalk, there are no static objects, so there are no static vardata, all vardata have to be added dynamically to objects. For GUI objects, the number of vardata items can be quite large, so there are helper methods to add simple valueless vardata and vardata with simple or even more complex values.

The vardata tags are 16 bit integers in GEOS, which have a similar hierarchical system as GEOS message numbers (the message numbers are described in GEOS SDK documentation, the vardata numbering is not explained anywhere). If the vardata item has a value, the value is included after the tag, including the length of the value. This enables to store variable length vardata such as strings to GEOS objects. There are both C style API functions for working with vardata (taking GEOS objects as arguments) and object oriented messages which change or query the vardata when sent to any GEOS object.

In Pocket Smalltalk there are several helpers for each GOC vardata definition. First, there is a Pocket Smalltalk constant with a name derived from the name of the vardata tag (translating names such as ATTR_GEN_HELP_FILE to ##attrGenHelpFile) and the value equal to the vardata tag value (the GOC compiler translates the vardata tags to C #defines, so the vardata tag names are treated as numbers in C). You can use the constant as a parameter to C API functions like ObjVarAddData or to GEOS methods such as MSG_META_ADD_VAR_DATA.

For valueless (void) vardata items which contain only the tag and can be tested for presence or absence in any object, classes.pl creates a helper method with the same name as the vardata tag (in Smalltalk conventions), which adds the vardata item to the receiver GEOS object. Using these methods and cascaded Smalltalk messages, the actual syntax to add various vardata to a certain UI object is nearly identical to that of GOC while defining static objects. So, if one would write in GOC:

@object ComplexMonikerClass AboutBox = {
    ...
    CMI_fontSize = FOAM_NORMAL_FONT_SIZE; /* assign instance variable */
    ...
    HINT_DRAW_IN_BOX;
    HINT_DRAW_SHADOW;
    HINT_PLACE_MONIKER_TO_LEFT;
    ...
}
the equivalent dynamic object creation in Pocket Smalltalk would be:
aboutBox := ComplexMoniker new
    ...
    cmiFontSize: ##FOAM_NORMAL_FONT_SIZE; "assign instance variable using PST accessor method"
    ...
    hintDrawInBox;
    hintDrawShadow;
    hintPlaceMonikerToLeft;
    ... .
For vardata values, there are two generated helper methods. One is the same as for the valueless which simply creates the vardata, but leaves the value equal to all zeros - this method actually returns a CPointer to the vardata value, so the value can be set with other methods. The other generated method uses a keyword message with one parameter (the name is the same as in the first case but the added colon at the end), which creates the vardata and immediately assignes the passed value to the vardata item. For simple values (byte, word, dword), the usual wordAt:put: type of access is used, for structures and unions the passed value is not a value as such, but rather a Smalltalk block (a piece of Smalltalk code used as data and executed on demand), which is passed as parameter the correct GCS (GeosCStructure) to the actual vardata item. The block can contain code to set the individual items such as structure fields of the complex value. As an example, consider the following GOC code:
@object SomeClass SomeObject = {
    ...
    HINT_FIXED_SIZE = {
        SST_PIXELS | FOAM_DEFAULT_COMPONENT_WIDTH,
        0,
        0
    };
    ...
}
with the equivalent Pocket Smalltalk code:
someObject := Some new
    ...
    hintFixedSize: [:csha | csha cshaWidth: (##SST_PIXELS bitOr: ##FOAM_DEFAULT_COMPONENT_WIDTH)];
    ... .
In the above example, the remaining fields of the structure are left as zero without explicitly assigning them a value.

To check for vardata presence, accessing or changing existing vardata values, you have to use the normal GEOS means for dynamic vardata handling, there are no automatically helper methods for those purposes. The goal of the Smalltalk helper methods is to create a syntax similar to that used while defining static GEOS objects in GOC.
 

Calling GEOS methods from Pocket Smalltalk

The GEOS objects besides storing data can react to messages implemented in GOC or Assembly methods. Most of the system functionality is available as methods of GEOS system classes. There are two different calling conventions for GEOS methods: GOC (on stack) and Assembly (in registers or on stack) and GEOS provides internal conversions, so methods written in Assembly can be called from GOC and the GOC methods can be called from Assembly with parameters in registers. The .goh header files contain definitions of GEOS system methods written in Assembly including the information which parameter goes into which register and the GOC compiler translates message sends to calls to CObjMessage with one parameter encoding the arrangement of parameters. As there is no GOC preprocessor in Pocket Smalltalk, the classes.pl program generates helper methods for all GEOS messages, including the information required to pass parameters to system methods in Assembly (most of the methods for most of the UI classes). Except this parameter and the fact that GEOS messages use 16 bit integer selectors and need a receiver, the handling of the Smalltalk helper method is similar to that of C API, using the GEOS instruction with the messageOn: keyword. There is one more level of message sends at the Smalltalk helper code level for memory conservation, so all helper methods in Smalltalk use methods in the class GeosMetaObject, which invoke the GEOS instruction of the Virtual Machine.

As some objects store message selectors, the constants used to represent messages in GOC are defined as Pocket Smalltalk constants as well so that the message number can be referenced anywhere in the Pocket Smalltalk program. As in GOC all the messages are processed in a flat name space with other constants and names, the names of messages (the selectors to use the Smalltalk terminology) have the prefix MSG_CLASS_what, and the MSG_CLASS_ prefix is dropped while converting the name to Smalltalk conventions, so that MSG_META_ADD_VAR_DATA would be ##addVarData in Smalltalk and the helper method in class Meta would be addVarData.

The GEOS applications can be multithreaded and each GEOS object instance is stored in one of the object memory blocks. Object memory blocks are owned by individual threads and messages in GEOS are always processed by the thread which owns the object memory block, not the thread which has invoked the message send. Besides calling messages, GEOS can send messages which means the message is stored in a queue and can be processed later, while the sending thread continues immediately (in Smalltalk terminology, there are no message calls and the GEOS call mechanism is called a message send, but there is no queue and all Smalltalk sends are processed sychronously). Each GEOS message send or call can have some extra parameters and message sends can be "recorded" and actually sent later (saved message sends are called events). In Pocket Smalltalk, these functions are not possible at the moment, but implementing them is quite easy and will be done in a short time. But looking at the sample applications in the Nokia SDK, most applications do not use these features and most tasks can be achieved with message calls, which is what Pocket Smalltalk supports at the moment.
 

Multiple inheritance in GEOS classes: master and variant classes

In Smalltalk the hierarchy of classes forms a simple tree, that is each Smalltalk class has exactly one superclass and there is a class Object which has all other classes as direct or indirect subclasses. The subclasses inherit from their superclasses all the instance variables (and the subclass can define more instance variables, but not less) and inherit also all the methods unless the subclass overrides them with its own definitions (and the subclass can obviously define new methods, not known to the subclasses).

In GEOS, besides "normal" classes, there are master classes, which have different internal organisation of the instance variables, but bring no new expressive power to the object model. Master classes enable to save memory, as they break the object instance into several parts (master levels) and only some parts of the object can be installed, while the remaining parts may stay empty. GEOS is able to create the missing master parts more or less automatically. In Smalltalk, if you access the object only by GEOS messages (sent via Smalltalk helper methods), you do not need to worry about which master part is initialized and which is not. If you want to acces the object instance variables below the topmost master level, you should call the initNextLevel method on the Smalltalk helper object to make sure the next master level is initialized (such as accessing the GenXXX level instance variables in an object of class ComplexMoniker. If you need to initialize some master levels below the topmost two levels, you will have to write a helper method yourself.

But there are also variant classes (all variant classes have to be master classes as well, but this is more an implementation issue), which enable to change the strict subclass/superclass relationship and enables for a class to inherit from a whole group of superclasses. The main use of this multiple inheritance in GEOS is in separation of an abstract UI (Generic in GEOS terms) and its visual representation (Specific UI in GEOS terms). All UI in GEOS is described using so called Generic objects (all generic classes are subclasses of the class Gen) and the Generic objects do not contain any information about the visual representation of the user interface elements. The visual representation is described in Visual objects (all visual classes are subclasses of the class Vis), but Gen is a subclass of the class Vis and for each GenXXX class there is some corresponding VisXXX class. But the VisXXX classes are subclasses of Vis, as is the Gen class, so Gen and its subclasses cannot inherit from VisXXX classes under the normal class inheritance model. But Gen is a master and variant subclass of Vis, which means that each instance of Gen or its subclasses will be a subclass of one of the subclasses of Vis. So for a particular object instance the inheritance is straightforward, but for a class, it can inherit from any subclass of the superclass of the variant class. In practice, object instances of subclasses of Gen can have different instance variables, depending on which of the Vis subclasses is the superclass of the object, and respons to a different set of messages with potentially different behaviour, again depending on the acutal superclass.

The selection of the actual superclass (ie. which VisXXX class will be the superclass of a particular GenXXX instance) is either automatic (the system knows which classes belong to each other and fills in the link in runtime when needed, this is the case with most Generic objects), or manual, that is the object has to specify its superclass before being fully usable (this is the case of the Nokia Communicator UI class ComplexMoniker). If the class is filled in manually, it is performed by assigning an instance variable with the same name as the variant class a value, which is a pointer to the ClassStruct of the actual superclass of the variant class.

The GEOS object system uses a very efficient way to handle variant classes, both for data storage and for lookup of methods for messages, and uses smart tricks to magically create the automatic links just in time when the first message is sent which needs to cross the boundary of the variant class.

As this system is more powerful than the simple Smalltalk model of class inheritance, it is not trivial to model it using the helper Smalltalk classes. As all the helpers in Smalltalk are methods (accessors, vardata creation, messages), it is sufficient to be able to change the Smalltalk message lookup algorithm so that the helper methods in Smalltalk helper classes are being looked up in the same way as in GEOS. If we relax our requirements that the lookup has to be exactly the same, there is a relatively easy way to map the GEOS functionality to that of Smalltalk helper classes. If we make the Gen helper class a simple subclass of the Vis helper class, then any object of any subclass of Gen can handle all messages properly, except those defined in other subclasses of Vis. The Smalltalk message lookup for messages defined in Vis classes therefore fails. In Smalltalk if a message is not understood by any superclass of the class of the object, the object is sent doesNotUnderstand: message with the original message including arguments as its parameter. This message is normally handled in Object, which produces some error and starts a debugger or does some other action. But as doesNotUnderstand: is a normal Smalltalk method, any class can provide its own definition and override the behaviour defined in Object. So for all the GEOS variant classes, we define doesNotUnderstand: in such a way that if the message is not understood through the normal inheritance, we resend it through the actual superclass, but with the same underlying GEOS object. As we cannot change the class temporarily (we can change classes permanently in Smalltalk, but it is not a good idea to do this for multiple inheritance), we have to keep the information about the superclass within the Smalltalk helper object and to create a temporary Smalltalk helper object of the actual superclass (but with the same GEOS object referenced by optr) and send the message to the temporary object.

This mapping can be broken deliberately, but it does not seem to be broken within the existing GEOS system classes. As the Smalltalk methods do not do any real work, but merely exist to map the Smalltalk message sends to GEOS message numbers (which are hierarchical depending on where the class is in the class inheritance tree) and other information required to translate the call to a proper GEOS message call, the doesNotUnderstand: trick should handle all the existing classes in GEOS. After the information is looked up in Smalltalk, the GEOS message is sent using the GEOS method lookup rules to the original GEOS object (which means that there are two very similar message lookups, one using Smalltalk selectors in Smalltalk Virtual Machine and one using message numbers in GEOS kernel).

The only restriction on using GEOS variant classes through the Smalltalk helper classes is in the fact that the Smalltalk helper classes cannot automatically infer the correct actual superclass, so for objects which need to handle messages for superclasses outside the direct line of ancestors you have to define the superclass manually even in cases which are handled automatically by GEOS. The only example I could find so far where this is necessary is with the GenText class, as you will usually need to use not only the MSG_GEN_TEXT_xxx messages, but also the MSG_VIS_TEXT_xxx messages as well and therefore you have to link all instances of the GenText Smalltalk helper class to the VisText actual Smalltalk helper superclass. Besides the link at the GEOS object level, the Smalltalk helper classes for GEOS variant classes define link to the actual superclass. As filling in the actual superclass at the GEOS level for Gen objects breaks their functionality (except the ComplexMoniker class, where the link to the underlying Gen class has to be both at the Smalltalk helper level and the GEOS object level), there are two ways to make the link in Smalltalk helper classes: to set only the Smalltalk helper link and to transfer the Smalltalk helper link to the underlying GEOS object with a setVariant message.

To illustrate this rather abstract discussion, we can use the following example. While creating an instance of the GenText class, we set the link to the VisText superclass at the Smalltalk helper level, but leave the GEOS system to fill in this link automatically. The actual code is as follows:

Gen>>gen:
gen: aClass
    "create another helper Smalltalk object with the same optr, but belonging to the actual superclass"
    gen := aClass basicNew optr: optr

Gen>>setVariant
setVariant
    "propagate the link to the actual superclass to the GEOS object level"
    self dwordAt: 0 put: gen class classPtr asInteger

Gen>>doesNotUnderstand:
doesNotUnderstand: aMessage
    "if the message cannot be handled in the straight inheritance, send it using a different helper class"
    ^gen perform: aMessage selector withArguments: aMessage arguments

... example use ...
    aText := GenText new
        gen: VisText;
        gtxiText: ...

    result := aText textGetAll. "this is a VisText message, which needs the gen helper method"
Please see the Pocket Smalltalk demo application use of different ComplexMoniker superclasses as an example of propagating the actual superclass to the GEOS level.

Generic classes and building Generic trees in Pocket Smalltalk

The GEOS UI objects are organized in a form of trees to model the hierarchical relationships between UI objects. The GEOS UI objects are linked into trees using object instance variables which point to the first child and to next neighbour within the level of hierarchy. Besides these "downward" links, there are links back to parents, which are used in the neighbour field instead of the nil value used in other environments. This saves memory and enables to find both the children and the parents quickly, at the const of minor complications to find where the hierarchy starts and where it finishes (one has to traverse the cycle and find the top to find out what is "up" and what is "down".

While defining UI objects statically in GOC, the programmer can desribe the tree-like relations by specifying the full list of children at the parent level. The syntax for listing the children is as follows:

    GI_comp = @child1, @child2, @child3;
The GOC compiler generates all the necessary child, neighbour and parent links automatically. This can be used only for statically defined objects. For dynamically created objects, one has to use GEOS messages defined in the class which contains the instance variables for the linking. In GEOS there are two tree-like hierarchies, one is for Vis objects (linking the visual representations of the UI) and one is for Gen objects, linking the logical relations between the UI objects. As the Vis objects are rarely manipulated directly (remember, every Gen class is a superclass of some Vis class), the application programmer usually needs to worry only about the Gen objects and their relationships. The messages to manipulate the tree-like relations of Gen objects are defined in the class Gen which is inherited by all Gen subclasses.

While creating the trees to describe UI objects in Smalltalk, for simple applications you will need to add items to their parents one by one to create the tree for dialog windows and then you will need to be able to destroy the whole branch of the tree when you are finished with the dialog. You will not need any other functionality for simple applications.

Adding Gen objects to other Gen objects is done by the GEOS message MSG_GEN_ADD_CHILD (with an automatically created Smalltalk helper method addChild:with:). All Gen objects have a state information and can be enabled or disabled and usable or not usable. To attach a Gen object to a generic tree, the object has to be set to non-usable. But to use it, it has to be set to usable. For this reason, Pokcet Smalltalk defines a helper method called addUsable:, which does the two usual steps together - attaches the object to a specified generic tree and sets the usable flag (the enabled flag should be set while creating the object). The typical scenario for building the generic tree is to use the Smalltalk cascaded messages syntax to create and setup the object and to attach the children one by one in another embedded cascaded message send. As opposed to GOC where you need to name all the objects at all levels in order to be able to describe the relations, in Pocket Smalltalk you need to define local variables and to assign references to UI objects only for those objects which need to be manipulated directly later (as for retrieving the current value from UI objects), purely organizational and descriptive UI objects do not need to be named. Pocket Smalltalk supports a syntax where you can make an assignment in the middle of a hierarchy cascaded message sends, so you can build the whole tree including creation of the required references in local variables in one large hierarchical message send. You can see an example of the programming style in the gdemo.st dialogs and to compare them with the GOC definitions in the settings sample Nokia SDK application.

The top of the GEOS generic tree for an application needs to be referred to in the application object, so that the system can launch a separate UI thread and to start to process the generic objects in this thread. The top of the generic tree is an instance of the GenPrimary class and the instance is created in the Pocket Smalltalk Virtual Machine application. In order to link your dunamically created generic objects to the application's generic tree, you need the optr to the instance of the GenPrimary class. There is a Smalltalk primitive method which returns the optr to the instance of GenPrimary. This method is called in GeosMetaObject class>>newObjBlock and saved in a class variable PSTPrimary for further reference. You can therefore send the addUsable: message to PSTPrimary in order to attach your GenInteraction instances for dialog windows to the existing generic trees.

Defining GEOS classes in Smalltalk, writing GEOS methods in Smalltalk

The functionality to create GEOS objects and call GEOS methods is not enough for all functionality of GEOS applications. Besides application-generated messages, the system generates messages for various UI objects (such as key presses) and the applications can define their own subclasses of GEOS system classes and can provide their own functionality for the system generated messages. This is the same approach as Smalltalk was using for handling of UI in the MVC (Model View Controller) architecture, but in Smalltalk the programmer had always access to the sources of the underlying system classes, so it was easier to write the application specific methods processing system messages by copying the code from the system class and making only small changes. In GEOS, the system classes are "black boxes" and the only way to learn how to process system messages is to believe in the documentation and by trial and error.

To be able to create real life applications, the Pocket Smalltalk system has to be able to create GEOS subclasses of GEOS system classes and to defined methods in Smalltalk for these new classes for system generated messages. Also, many UI components communicate with each other by sending user defined messages to each other, so there has to be the possibility to define new messages and to write methods in Smalltalk to handle them.

The classes.pl program generates Smalltalk glue code, which creates a Smalltalk class for each existing GEOS class, so that GEOS objects are represented in Pocket Smalltalk as Smalltalk objects with a single instance variable, which contains a link (in GEOS lingo these are called OPTRs - Object Pointers) to the underlying GEOS object. The GEOS classes exist in GEOS before any Smalltalk application is started. Application specific classes which are subclasses of system classes are defined in GOC and created statically at compile time (i.e.. the GOC compiler builds the ClassStruct data structure for the class and the class itself usually does not change while the application runs). In Pocket Smalltalk, you can easily define a Smalltalk subclass of the Smalltalk (helper) class for the GEOS system class, but you cannot statically create the GEOS data structures for the new GEOS class. So for Smalltalk defined GEOS classes, you have to dynamically build the class during the application initialization time and only once the GEOS class for the Smalltalk class is defined, you can start to make and use objects of this new GEOS class (in GEOS or Smalltalk).

The required ClassStruct (which has other arrays and structures immediately following the basic ClassStrcuct) is built using a helper Smalltalk method GeosMetaObject class>>initializeSubclassHandling:, which takes an Array of Associations, which map GEOS message numbers (as Smalltalk constants, i.e.. something like ##kbdChar) to Smalltalk message selectors (as Smalltalk symbols, i.e.. something like #kbdChar:with:with:). The Smalltalk instances of Smalltalk objects point to the underlying GEOS obejcts, but for system classes there is no need to have the opposite link from the GEOS object to the glue object in Smalltalk. For GEOS classes defined in Smalltalk, such a link is required, so that the Virtual Machine function knows which Smalltalk object should be sent the Smalltalk message equivalent to the GEOS system message. For this reason, the Smalltalk defined subclasses of GEOS classes always have to have at least one more instance variable, which contains a 16 bit object pointer pointing to the Smalltalk object instance for the underlying GEOS object (i.e.. the Smalltalk object points to the GEOS one and vice versa). This instance variable has to be the last word of the GEOS object instance. The GeosMetaObject class>>new method fills in this instance variable automatically for each new object created, so its existence is mostly hidden from the Smalltalk programmer. The only place where its existence is important is the fact that each Smalltalk defined subclass of GEOS system class has to define two more class side methods for the Smalltalk class: SomeClass class>>isInSmalltalk which has to return true to tell the new method to fill in the reverse pointer (this method is defined at GeosMetaObject class>>isInSmalltalk as returning false, from where it is inherited in all GEOS system classes, and the classes defined in Smalltalk have to override this) and SomeClass class>>instanceSize, which has to define the instance size (for this master level) for the new subclass. Unless you want to include some more instance variables, this will be always the size of the GEOS system superclass instance plus 2 bytes for the backpointer with the Smalltalk object pointer. So, for nearly all Smalltalk defined classes, you should use the definition: ^self superclass instanceSize + 2 (please note that this has to be written this way and not ^super ..., which would try to fetch the instance size from the yet undefined ClassStruct structure for the class just being defined). To make things easier, there is a helper method GeosMetaObject class>>superInstanceSizePlus2, so that you can define SomeClass class>>instanceSize simply as ^self superInstanceSizePlus2.

GEOS system generated messages never return any value, so there is no transfer of the return value from Smalltalk back to GEOS (if someone finds an example where this is not true, I will fix this easily). The Virtual Machine level function which translates GEOS messages to Smalltalk messages can handle at this moment only messages with 0 to 3 word (16 bit) arguments passed in the CX, DX and BP registers. This handles nearly all system generated messages and with a bit of effort handles also messages with one 32 bit argument and possibly one more 16 bit argument, by combining the values in 16 bit registers together. The reason is that this can be coded in C, anything better needs to be coded in Assembly, which will take some more time for me to write and debug (plus to understand the kernel code wich actually passes the message to the message handler). The C language handler function passes 0 to 3 arguments to the Smalltalk method as integers from the CX, DX and BP registers (well, they are actually on stack, but the important part is how they are defined in the GOC files for which registers), based on the number of arguments of the Smalltalk method (the first argument would be the CX, the second DX and the third BP). In most cases, the only thing you need to do is to have a look at the GEOS definition of the message in the Smalltalk glue method (which contains a copy of the GEOS GOC message definition as a comment), find out how many parameters there are and to write a Smalltalk method for this message.

For the moment, the main limitation is in the fact that the C handler for system messages always calls the system superclass handler after the Smalltalk language handler and with the same parameters as the original system generated message. This means you can react with your own functionality to system generated messages, but you cannot prevent the system from doing the default action or to change the behaviour with passing different parameters and you cannot change the order that the Smalltalk code is executed first and the default processing is done afterwards. In the next version of Pocket Smalltalk you will have to call the default processing yourself as you would do in GOC, but at the moment this is not possible and it is not worth of delaying the realease of this version of Pocket Smalltalk.

Some known bugs, problems and limitations of the Smalltalk/GEOS interaction (a summary)

Most of the following problems/restrictions will be dealt with in the next version or at some later stage. None of the limitations is principal, i.e.. they can be removed with some effort.

List of files in the distribution and what they do

Further Documentation

To understand Pocket Smalltalk beyond the PalmOS specific tutorial and this document, you need at least four sets of documentation:
  1. some books about the Smalltalk language if you are new to the language. You might find various tutorials on the Smalltalk language useful, you can start at www.smalltalk.org and follow many of the links from there. There is also an ANSI standard for the Smalltalk language - the actual Pocket Smalltalk language is nearly 100% following the ANSI draft standard, but the class library is very different from the ANSI one, so you can safely skip most of the standard. The ANSI draft standard for Smalltalk is available in Word for Windows format at http://www.ibm.com/software/ad/smalltalk/downloads/ansistan.doc
  2. the 9110 SDK documentation (included on the SDK CD in HTML format) - you need this to understand/change the Virtual Machine sources and to use the GEOS classes and API accessible from Pocket Smalltalk. Without this documentation you can hardly do anything useful with Pocket Smalltalk for the Nokia Communicator.
  3. the Dolphin Smalltalk documentation (included in the Dolphin distribution) - you only need this to understand/change the IDE Development environment. The IDE would be ported to some more portable version of the Smalltalk language eventually (Squeak is the hot candidate, as that runs on a large number of platforms and is completely available in the source code with a liberal license from Disney and Apple).
  4. the Pocket Smalltalk documentation - there is a local copy of most of the documentation files within the PST9110 distribution. Other documents are available on www.pocketsmalltalk.com, although only the PalmOS version is described. All information about the 9110 port is available at www.i.cz/PeN/pst9110.html.

Support and further development

The 9110 port has been done by Petr Novak (Petr.Novak@i.cz). The WWW site for the 9110 port is at www.i.cz/PeN/pst9110.html - including the download. The process to synchronize the 9110 port with PalmOS and potentially other platforms is not in place yet. You can email me or to use the PST discussion forum - please - note that I am working on Pocket Smalltalk 9110 only in my private spare time as a hobby and I have a baby-daughter and a full time job as priorities, so the response times might be slow.

The plans for the future

  1. test other possibilities of memory management under GEOS (at the moment the PST memory is a mixture of GEOS Virtual Memory files with most of the VM file locked and with locked memory blocks allocated using malloc - this is not a good model for GEOS but was the simplest to get the thing working in a short time)
  2. build wrapper Smalltalk methods around most useful library calls and Geos classes. This would greatly enhance the usability of the whole system providing clean and simple interface even to complex tasks (like sending SMS messages).
  3. provide excellent documentation to the whole environment (any volunteers? the new PST tutorial by Joey Gibson is a great start)
  4. write real life examples, demos and tutorials. In my opinion, the weakest aspect of the PalmOS Pocket Smalltalk is the lack of good examples available in the source code and the 9110 should take a lead in this respect (again, any volunteers?).
  5. port the IDE Development environment to Squeak so that the development can be done on any platforms (Eric Arsenau may or may not be working on this as well)
  6. consider the benefits of creating a limited Development Environment running on the 9110 itself (written in Pocket Smalltalk, obviously) - is the keyboard and screen good enough so that anybody would like to use this for anything else than debugging? The PSTPST demo shows this is indeed possible (although slow and taking too much memory at the moment)
  7. Change the format of the Pocket Smalltalk code files to be .GEO application rather than .VM (virtual memory file), move the PST VM (pstec.geo) to a shared library. This will enable to have multiple applications in PST and to have a full control of the UI from the moment the application starts.
  8. support of ##(expression) constant expressions evaluated at compile time within the IDE
  9. multiple threads in Pocket Smalltalk, including thread synchronisation
  10. speed up the compilation from Smalltalk to make files load faster, decrease the memory requirements so that the system is practically usable with 32 MB of RAM even for larger projects

Changes from the previos relases

0.5 to 0.8 (2000-03-13)

  1. Pocket Smalltalk can call all Geos methods and library functions. Geos classes can be defined including methods in Smalltalk (there are some limitations, though).
  2. Got rid of SYSTRAPs in favour of GEOS with different functionality (less tests in compile time, but possibility to define the system interface from .st files at runtime rather than having it hardwired to the IDE).
  3. Fixed some bugs in both the IDE and the VM which crashed some test programs.
  4. A more complete example behaving like a real life application.

0.4 to 0.5 (2000-01-24)

  1. GEOS classes and methods, but using manual definitions. The dynamic dialog written completely in Pocket Smalltalk.
  2. Fixed some problems in the IDE, namely the need to initialize the table of SYSTRAPs and the bug in optimizer to be able to produce optimized .VM files.
  3. more files included for people who would like to share everything I have on the Pocket Smalltalk 9110 available at the moment, including stuff which is completely broken and does not do anything useful yet.

0.3 to 0.4 (1999-11-23)

  1. New stuff! The UI can do some input and my GEOS UI finally seems to behave as expected.
  2. converted this readme into HTML for better readability
  3. Reworked the SYSTRAP (actually GEOS Library Call) mechanism
  4. Fixed some bugs, mainly intermixed files in the 0.3 distribution
  5. Tried to handle both signed and unsigned int16 in SYSTRAP, some limited floating point support in SYSTRAP

0.2 to 0.3 (1999-11-09)

  1. fixed a problem with library names in error-checking and non-error-checking versions (now both libraries are tried before an error is reported)
  2. fixed a problem in the .INS script
  3. fixed a problem in math.c with integer unequal method (primitive 84)
  4. the gtest.st has now some primitive CPointer methods, the getImei example is yet improved into something people really might use one day (see the Smalltalk class>>getImei source to see what I mean).
  5. replaced the floating-point demo with something which works (the bug is still there!!!)
  6. no real new functionality, sorry, this is mainly a bug-fixing release

0.2 (1999-10-28)

  1. first public version