Category : Miscellaneous Language Source Code
Archive   : VPMTIPS.ZIP
Filename : VPMTIPS

Output of file : VPMTIPS contained in archive : VPMTIPS.ZIP
Copyright 1990 Digitalk, Inc. May be used freely under the same
terms and conditions as contained in the Digitalk License Statement.
This text and code is provided on an as-is basis, and all warrenties, either
express or implied, are disclaimed.
Smalltalk/V PM TIPS

- If you have received the upgrade from Smalltalk/V
PM 1.0 to version 1.1, don't forget to look at the new
information in the 'readme.vpm' file. New topics include:
starting up a standalone application, command line
arguments, changing a window's icon picture,
debugging DLLs and 'PMConstants' for OS/2 1.2.

- Compressing sources and/or changes does not reduce
image size.

- To find all methods that reference a global variable,
evaluate the following:

Smalltalk sendersOf: (Smalltalk
associationAt: #Global)

where 'Global' is the variable investigated.

- To find all methods that reference a class variable,
evaluate the following:

Smalltalk sendersOf:
(Association key: 'ClassVar')

where 'ClassVar' is the class variable investigated.

- Implementing a 'printOn:' method in key classes can
speed up and simplify debugging. Having this
method print something other than the name of the
class of the receiver will reduce the need to open
inspectors, and can provide a better formatted, more
usable view of the instance data of the object.

For example, let's say you're working on an
application which uses primarily 'MyClass', which
has three instance variables: 'bool', 'string' and
'collection' initialized to a 'Boolean', a 'String' and
an 'OrderedCollection', respectively. If you click on a
variable in the variable pane of a Debugger which
contains an instance of 'MyClass', the string
'a MyClass' is displayed in the contents pane. After
implementing the following method in 'MyClass':

printOn: aStream
bool printOn: aStream.
aStream cr.
string printOn: aStream.
aStream cr.
collection printOn: aStream

when you click on the variable, its contents is
displayed instead of the uninformative message
'a MyClass'. In this way, you do not need to open two
inspectors to see the true value of an object.

- Inspecting an application window. Have you
ever wanted to inspect your application window in its
current state? Here's some code that will add an
'Inspect Me' menu item to the System menu of every
Smalltalk/V PM window.

First add the following to the end of method
'buildMenuBar' in class 'ApplicationWindow':

menuWindow systemMenu
insertItem: 'Inspect Me'
selector: #inspect
accelKey: nil
accelBits: nil
after: 7.

Also change the reference to item 8 near the end of
method 'validate' in class 'TextWindow' to a 9.

- One of the most frequently asked questions is how
to make the runtime version of an application open
without the Transcript window being visible. Well,
here's one way to do it. We'll use 'Puzzle15' as an
example. First replace the last 6 lines in method
'startUp' in class 'NotificationManager' with:

Smalltalk isRunTime
ifTrue: [
self initialize.
"Put your opening expression here"
Puzzle15 new open]
ifFalse: [
previousScreenSize = Display extent
ifFalse: [
self initialize.
TextFont := ListFont := font.
ifTrue: [self resume]]

After 'self initialize' in the first 'ifTrue:' block, put
the expression to open your application.

Next, if you do not have a method 'close' in your
'ApplicationWindow' subclass, add this one:

Smalltalk isRunTime
ifTrue: [Smalltalk exit]
ifFalse: [^super close]

- If you want to call a DOS API that is not already in
the DosDLL class, you need to know the ordinal number
of the API since you cannot call by name. You can
determine the ordinal number of each API by using the
'lib.exe' program on 'API.LIB', included in the
Microsoft or IBM toolkit. A file containing this ('doscalls.lst')
is available in this library section.

- Smalltalk/V PM and OS/2 Versions. IBM's
OS/2 version 1.1 requires the Corrective Service Disk
(CSD) updates for Smalltalk/V PM. If you are noticing
strange characters in your dialog boxes, then you have
not installed the CSD. You can tell what version you
have by looking at the number on the screen that first
appears during booting. It should be 89039 or later (or
in extended edition, E9039.) You can upgrade by
obtaining the CSD disk from IBM. They are numbered

IBM's OS/2 1.2 and any version from Microsoft
don't need upgrades to run with Smalltalk/V PM.
They should work fine off the shelf.

- When you execute the runtime version of your
application 'v.exe' rather than 'vpm.exe' the
following classes are no longer available to your
application: 'ClassBrowser', 'ClassHierarchyBrowser',
'ClassReader', 'Compiler', 'Debugger', 'DiskBrowser',
'MethodBrowser' and 'NewSubclassDialog'.

- You can associate an integer value with an item
in a list box of a dialog box by using the method
'setValue:forItem:inListBox:' in class
'DialogBox'. Later query that value using the
'DialogBox' method 'queryValue:inListBox:'.


Here's a simple error handler for Smalltalk/V PM.
It follows the same model as those described in the
January 1988 and April 1988 issues of the newsletter
HOOPLA (no longer being published. The following
piece of code illustrates what it provides:

[1 // 0] ifError:
[:aString |
aString = 'divisor is zero'
ifTrue: [0]
ifFalse: [
self error: aString]]

Context objects can be sent the 'ifError:' message to
install an error handler and cause evaluation of the
block. If an error occurs during the evaluation of the
block, the error handling block is evaluated with the
error message string as the argument.

The one tricky part of installing the error handler is
that an instance variable must be added to class 'Process'.
The following code accomplishes this:

Process class compile:
^Array new'.
OrderedCollection subclass: #Process
'topFrame frameBias priority
sendFrame isUserIF debugger
name interruptFrame
classVariableNames: ''
poolDictionaries: ''.
Process class removeSelector:
Processor initialize.

First the 'allInstances' method is added to 'Process'
so the system will think there are no processes. Then the
instance variable 'errorHandler' is added to the end of
the list. The method 'allInstances' is removed from
class 'Process'. Finally, the last line eliminates all
processes and creates new ones of the new size. This
technique depends upon the existance of the 'initialize'
message. For example, this won't work for class
'TextPane' because there is no corresponding message.
This also will not work if you have your own processes

Now install the following methods by filing them in:

!Object methods !

error: aString
"Create a walkback window
describing an error condition
with the error message aString
in the window label."
CurrentProcess isErrorHandled
ifTrue: [
CurrentProcess errorHandler
value: aString].
Process queueWalkback: aString
makeUserIF: CurrentProcess
isUserIF resumable: false! !

!Process methods !

^errorHandler !

errorHandler: aBlock
errorHandler := aBlock !

^errorHandler notNil ! !

!Context methods !

ifError: aBlock
| errorBlock lastHandler |
lastHandler := CurrentProcess
errorBlock := [:aString |
CurrentProcess errorHandler:
^aBlock value: aString].
CurrentProcess errorHandler:
self value.
CurrentProcess errorHandler:
lastHandler ! !


When you change a class definition or want to
remove a class, you will get a walkback window if there
are instances of the class in the system. You must
remove them before proceeding.

If it is a window-related class, it is possible that there
are "ghost" windows left around from getting the
application to work (i.e. opening windows
unsuccessfully). You can test this by executing
the following with 'Show It':

| openWindows |
openWindows := 0.
(ApplicationWindow withAllSubclasses
collect: [ :class |
class allInstances size]) do:
[:s | openWindows :=
openWindows + s].

The answer should be the number of open windows.
If not, this could be your problem. Make sure you save
all of the information you want in the open windows,
then execute the following to close all open windows and
reinitialize the System Transcript:

Notifier reinitialize

If the instances you want to get rid of are not in a
window-related class, check the global variables in the
Smalltalk dictionary and see if any of them contain an
instance of the class. Do this by executing:

| dict |
dict := Dictionary new.
Smalltalk associationsDo: [ :assoc |
assoc value class ==
ifTrue: [dict add: assoc]].
dict inspect

Also think about Collections or class variables that
might contain instances.

If all else fails, try the following which changes all of
the instances to null strings (NOTE: This is dangerous
-- save your image first):

allInstances do: [:each |
each become: String new]


Sometimes it is necessary to move a class; for
instance, to make it a subclass of a new abstract class. Be
careful when moving classes around because the system
will blow up if you don't do it right and it can't find it!
This can be done with the following steps:

1. File the class out to a file.

2. Find all the methods which explicitly refer to the
class by name (for example, in creating new instances).
Do this by evaluate the following:

Smalltalk sendersOf: (Smalltalk
associationAt: #ClassName).

where ClassName is the name of the class being moved.
You will get a Method Browser window. Keep the window
containing the information because you will use it later.

3. Remove the class by evaluating this expression:

ClassName removeFromSystem.

There can be no subclasses or instances of the class. If
there are you must remove them before proceeding (see
previous tip on GETTING RID OF INSTANCES).

4. Change the name of the superclass in the class
definition message.

5. Re-install the class in the system.

6. Recompile all methods which refer to the moved
class, if any, contained in the window you saved in step 2.
Click on each method name in the Method Browser and
recompile the method shown in the Browser's text
pane by innocuously editing the text pane (for example,
put a space or remove a space somewhere) and saving it.
If you do not recompile these methods, they will use
the old class definition! Changes to the methods of the
moved class will not work with instances created by
unrecompiled methods.

This tip is courtesy of Professor Verschueren at the
Eindhoven University of Technology in The Netherlands.


This tip adds line filling to the Text Editor of
Smalltalk/V PM. Lines are broken only at word
boundaries and are as wide as possible without
exceeding the width of the pane. To use it:

- Select the block of text to be adjusted. The method
eliminates blank lines and existing line breaks, so the
selection should be made within a single paragraph.

- Select 'fill selection' from the Edit menu.

!String methods !

fill: anInteger font: aFont
"Answer a string with the text
content of the receiver divided
at word boundaries into lines of
width less than anInteger pixels
where aFont is used to determine
the width of words."
| blank answer pixels delta |
blank := aFont stringWidth: ' '.
answer := WriteStream on: String new.
pixels := 0.
self asArrayOfSubstrings do: [:aWord|
delta := aFont
stringWidth: aWord.
pixels + delta <= anInteger
ifTrue: [
answer nextPutAll: aWord;
nextPutAll: ' '; "one space"
pixels := pixels + delta +
ifFalse: [
answer cr; nextPutAll: aWord;
nextPutAll: ' '.
pixels := delta + blank]].
^answer contents! !

!Text Pane methods !

"Rearrange the selected text so
that each line fills the width of
the receiver."
(self selectedString
fill: self width
font: self font);
showSelection ! !

Finally in method 'editMenu' in class 'TextPane', add the
following menu item between the 'appendItem' for
'Print ~Selection' and '~Find/Replace...'.

appendItem: 'Fill Selection'
selector: #fill

This tip is modified from a version by Charles Rovira and
Morton Goldberg for Smalltalk/V Mac.


Jose Alsina has extended the Disk Browser so that the
sort switch which orders the directory's files (by name,
size or date) in the text pane also changes the order of
files in the file list pane. Just change the second
statement in method 'files:' in class 'DiskBrowser' from:

answer := SortedCollection new.


answer := OrderedCollection new.

This tip is courtesy of Jose Alsina, British Gas plc,


Many of you have asked how to change the icon that
appears when you minimize a window. Follow these

- Use the Icon Editor that comes with the OS/2 PM's
Developer's Kit (available from IBM or Microsoft) to
create an icon.

- Create a resource-only DLL containing your icon.
(Instructions for creating a resource-only DLL are
also in the PM Developer's Kit or refer to page 765 of
'Programming the OS/2 Presentation Manger' by
Charles Petzold for an example.) Copy the resulting
DLL to 'c:\OS2\DLL' or some other directory on your

- Copy the method
in class 'Window' to your subclass of
'ApplicationWindow'. In the middle of the method,
change 'hmod: 0' to:

hmod: (DynamicLinkLibrary open:

where your file containing the icon is called
'MyAppIcon.DLL'. If your icon's resource id is not 1,
also change the 'idResource:' argument in the
method to the proper value.

Now when you minimize your application window,
it should have your icon as its picture.


The windowing system of Smalltalk/V PM contains
a number of enhancements over earlier Smalltalk/V
windowing systems. Among these enhancements is the
event notification mechanism. Each Subpane class
maintains a set of events represented by symbols. The
owner (or model) of the Subpane specifies the events of
which it needs to be notified by sending the Subpane a
message like:

when: #getContents
perform: #textFor:

Given this, 'aTextPane' will effectively send the

owner textFor: self

each time the event 'getContents' occurs. Events are
triggered by sending the following message to a

event: aSymbol

The set of events a Subpane class can generate is
inherited by its subclasses and is extensible. To illustrate
this we will describe a subclass of 'TextPane' called
'EntryField'. File in EntryField's definition, one class
method and two instance methods:

TextPane subclass: #EntryField
instanceVariableNames: ''
classVariableNames: ''
'CharacterConstants PMConstants' !

!EntryField class methods !

"Answer the Set of events about
which EntryFields can notify
their owners."
^super supportedEvents
add: #enter;
yourself ! !

!EntryField methods!
"Private - Answer an Integer with
appropriate FCF_ bits in it."
^FcfBorder | FcfNobytealign
characterInput: aCharacter
"If aCharacter is a linefeed,
trigger the event #enter,
otherwise process normally."
^aCharacter = Lf
ifTrue: [self event: #enter]
ifFalse: [super
characterInput: aCharacter] ! !

An 'EntryField' behaves just like a 'TextPane', except
when it receives a linefeed as an input character the
event 'enter' is raised. Assuming the 'EntryField' has
been instructed to notify its owner of the event, as in:

when: #enter perform: #textFrom:

the owner of the 'EntryField' will effectively be sent
the message:

owner textFrom: self

An implementation of the method 'textFrom:' in the
owner class would probably extract the contents of the
EntryField (the argument to the message) and move
the input focus to the next EntryField by sending
'#setFocus' to that EntryField.

Class 'EntryField' as described here certainly has
room for improvement ( for example, by adding events
like 'tab', 'backtab', 'uparrow', 'downarrow', etc.), but this
simple version illustrates the extensibility of the event
notification mechanism.

  3 Responses to “Category : Miscellaneous Language Source Code
Archive   : VPMTIPS.ZIP
Filename : VPMTIPS

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: