



	   ################################################
	   #                                              #
	   # ##   ## ###### ####### ##    ## ## ##     ## #
	   # ##   ## ##  ## ##      ###   ## ##  ##   ##  #
	   # ##   ## ##     ##      ####  ## ##   ## ##   #
	   # ##   ## ###### ######  ## ## ## ##    ###    #
	   # ##   ##     ## ##      ##  #### ##   ## ##   #
	   # ##   ## ##  ## ##      ##   ### ##  ##   ##  #
	   # ####### ###### ####### ##    ## ## ##     ## #
	   #                                              #
	   ################################################



	 The following paper was originally published in the
	   Proceedings of the Fourth Annual Tcl/Tk Workshop
		   Monterey, California, July 1996




	For more information about USENIX Association contact:

		   1. Phone:	510 528-8649
		   2. FAX:	510 548-5738
		   3. Email:	office@usenix.org
		   4. WWW URL:  http://www.usenix.org







Tcl/Tk as an OpenDoc Scripting Part
Jim Ingham
AT&T Bell Laboratories

I ) Introduction

The OpenDoc component document architecture promises to revolutionize how 
modern applications are deployed to users.  Backed by the Component 
Integration Laboratories (including Apple, IBM and Novell), it promises to 
cure the bloat of modern applications, which feel the need to provide every 
feature possible within one shell.  More important, OpenDoc provides unique 
opportunities for smaller developers, since they can concentrate on 
solutions in their particular area of expertise, without having to provide 
the whole environment within which their solutions can function.

The basic idea of OpenDoc is to cast the modules that comprise an ordinary 
application: text editors, spell checkers, picture editors, a differential 
equation solver, an FTP channel .  . ., as separate "parts" that can be 
embedded in arbitrary combinations into a document shell.  The document 
shell, provided by OpenDoc, controls the event loop and storage, arbitrates 
access to system resources like the menubar, mouse and keyboard, and 
provides a channel of communication among the parts for geometry management 
and data passing.

OpenDoc provides a rich language by which the parts communicate, but it 
does not come with many prebuilt features.  While the geometry arbitration 
mechanism is well defined, the developer is free to choose the particular 
model of geometry management according to his or her needs.  OpenDoc uses 
the Open Scripting Architecture (OSA) to facilitate data passing among the 
parts, but does not provide any particular scripting language.  Nor does it 
come with a toolkit for implementing ordinary GUI functions (buttons, 
listboxes, .  . .  ).

This situation provides an interesting opportunity for deploying Tcl/Tk in 
a new context, which has many attractive features.  If we could make Tk a 
"part" in the OpenDoc world, then the creators of OpenDoc content would get 
the ease of development and the rich widget set for their documents that 
has been such a boon in the X world.  At the same time, Tk developers would 
gain the ability to embed whatever parts are available in the OpenDoc world 
into their application, without having to build extensions for those parts.  
This kind of embedding could fill the role that the complex VBX's fill in 
the Visual Basic world.  Also, since OpenDoc is intended to be a 
cross-platform architecture, the 7.5/4.1 versions of Tcl/Tk are a natural 
choice for the scripting architecture/widget set.

In the rest of this paper, I will give an outline of how Tcl/Tk could be 
used as a tool in the OpenDoc environment, first providing a brief summary 
of OpenDoc.  Then I will sketch the enhancements that need to be made to 
Tcl/Tk in order fulfill this role.  There are several levels of OpenDoc 
incorporation, and while the tightest coupling would require some rather 
low-level changes to the Tk core, there is an intermediate level that could 
be done fairly surgically.
 
I have started the work in some of these areas, mostly at this point as an 
assay of the level of difficulty.  Although there is much work to be done, 
there do not seem to be any show-stopping difficulties, and results are 
promising enough to make the effort worthwhile.  This paper is really meant 
to be a call for an interest group.  I intend to show why this is an 
interesting project and sketch its parts, in the hope that I can find some 
other developers who are interested in cooperating in its implementation.  
Note that the following discussion is in the context of the MacOS port of 
Tcl/Tk.  There are also ports of OpenDoc to AIX and OS/2 currently 
available in Beta, with a Windows port due in the middle of the year, but I 
have no experience with these ports.

II) Summary of OpenDoc

The fundamental idea of the OpenDoc model is that the document, rather than 
the application, should be the central focus of attention.  The motivation 
is to give the content provider control over what elements go into their 
document: If I don't need pictures, then I don't need the picture editor 
most word processors now routinely include...  And if I need a picture 
editor, or some other special service embedded in a text document, I should 
be able to choose one made by someone whose primary interest it was to 
provide that function, rather than the knock-off required to meet some 
feature spec sheet.

Each OpenDoc document is broken down into a number of "parts", each of 
which is controlled by its own "part editor".  A part editor could be a 
text or picture editing facility, a spell checking facility, a TCP/IP 
socket interface...  In a given document, there may be several parts that 
are controlled by the same part editor.  By implementation, the part 
editors are actually class definitions, derived from a base class provided 
by OpenDoc, and the parts are instances of their part editor class.  So 
although the parts owned by the same part editor share code, they are 
really independent entities, with their own data and state.

The user does not manipulate part editors directly.  Rather, the developer 
of the OpenDoc part also makes a "stationary" document for the part editor.  
This can be as simple as a template for one part, or that part with some 
state information included, or can be a whole conglomeration of parts.  The 
user opens the stationary document, which automatically makes a copy of 
itself for the user to edit.  The stationary documents also support a drag 
and drop mechanism.  So if you want to add a picture to a text document you 
are editing, you drag the stationary document for the picture part editor 
from the finder onto your text document, and drop it wherever you want the 
picture to go, then interact with the picture part to load in the desired 
image.  Thus you can make a complicated collections of parts, save it as a 
stationary document, and it becomes an atomic unit that you can later 
insert into another document.

Each part usually controls some screen area.  For instance, a text part 
would have some area in its document's window to display its contents.  
Each contiguous bit of screen area in a window that a part occupies is 
called a "frame".  Each part can have more than one frame, and the frames 
owned by a given part need not be in the same window.  So, for instance, if 
I wanted to put a long bit of text into a newsletter document, I could 
break the texts part up into a number of frames, and spread the frames 
throughout the newsletter.  There is no requirement that the frames be 
rectangular, though this has little implication for our purposes.

More importantly, the frames of a given part can be constructed in such a 
way as to contain other parts.  So one frame of a text part could contain a 
picture part; for instance to display an in-line image.  The containing 
frame (the text editor in our case) manages the geometry of the embedded 
part (the picture editor), but has no other responsibility for it.  OpenDoc 
forwards update requests to all the embedded parts, and each part has the 
responsibility for drawing itself.  Thus the coupling between an embedded 
part and its container is minimal.  The embedding can go on to any depth.

All user interaction is routed through the OpenDoc shell.  For each system 
service - the mouse, the keyboard, and other ports - there is an associated 
"focus".  Parts negotiate, through the OpenDoc shell, for the focus for a 
given input stream.  In general this is done by "activating" one part, 
which then requests the keyboard and mouse focus.  There are user-interface 
conventions for how the active part is displayed, and how the activation is 
switched from one part to another ( this is done by a single mouse click in 
the part to be activated, for instance).  Once a part gets the focus for a 
given input, the OpenDoc shell will route all such events to that part.

Finally, the OpenDoc shell provides the facility for one part to send 
scripting events to another part in the document, using Apples Open 
Scripting Architecture (OSA).  The OSA provides a well defined way for 
parts to publish their interface to other parts, and to OSA aware editors.  
To achieve this communication, the parts build up "Apple Events", which 
describe a set of steps to be taken using this interface, and pass them 
back and forth.  Any part that is OSA compliant, i.e.  that has this 
interface, can take part in these scripting exchanges.

II) Tcl/Tk in OpenDoc

Let's start with a scenario of how Tcl/Tk could be used in OpenDoc.  
Suppose I have written a 2-D differential equation solver, which I have 
incorporated as a Tcl extension so that I can script it.  Then I wrote a 
nice Tk front-end to control the simulation.  Now I need to display the 
data.  Since it is not entirely trivial to write a good 3-D data viewer, 
particularly one that can do convincing coloring and shading, rotations, 
etc, and perhaps produce a QuickTime movie of the results, I will look for 
a commercial package to do the task.

All this is possible in the context of ordinary applications, however, the 
presentation is fragmented.  I start up my Wish, do the simulation, and 
then start up the 3-D viewer, play with it a bit, then go back to the wish 
to redo the simulation.  I have to have a data file somewhere to store the 
input cards, and the results somewhere else, and my movies in a third 
file...

If both Tk and my 3-D viewer were OpenDoc parts, however, I could make up a 
single Document that contains as its parts, the Solver engine, the GUI and 
the viewer window, sort of a poor-man's Mathematica.  Later, if I wanted to 
run a series of simulations, I could add a spreadsheet part to store a 
table of test cases, write a Tcl script to get the columns one by one from 
the spreadsheet, run the simulation for each column, and write back some 
results to the spreadsheet.  I could even embed the QuickTime movies of the 
results as icons in the spreadsheet, if the spreadsheet was written to 
contain other parts in its cells.  Finally, my Tcl script could drive the 
spreadsheet to do some analysis of the results.

All this would be within a single document, so I can hand it off to a 
colleague to use, without having to give complicated instructions on its 
use (for instance describing the naming convention that links the input and 
output data sets).  Furthermore, I can make copies of the document, each 
containing a separate test sequence, and each copy is self-contained, with 
all its data and results in one place.

This picture relies on two separate facilities: the intercommunication of 
the parts which makes joint operations possible, and the common shell by 
which a single environment can be constructed around all these functions, 
some of which I control (the Tcl/Tk and solver engine), and some of which I 
don't even have libraries for (the spreadsheet and 3-D viewer).  I will 
discuss in the next section what needs to be done to provide these two 
facilities.

The advantage of this integration goes in two directions.  Tk brings to the 
OpenDoc world an extensible (I could incorporate my 2-D solver) scripting 
language, with a well-designed widget set.  In return, Tcl/Tk applications 
will gain access, in a particularly seamless and attractive way, to custom 
facilities that are not available as libraries for incorporation into the 
Tcl shell.

The whole discussion is speculative at present, since there are no quality 
applications currently available as OpenDoc parts.  But this will likely 
change in the near future; OpenDoc won Best Technological Achievement of 
1995 at Comdex this year, and has been consistently rated superior to the 
only real competitor, MicroSoft's OLE. There is an impressive list of 
commercial developers committed to writing OpenDoc parts (see 
http://www.cilabs.org for details).  And at the same time, Tcl/Tk has an 
opportunity to make a contribution to this development precisely because 
there are no well established competitors.

III) Changes to Tcl/Tk 

This section falls under two heads, OpenDoc compliance, and OSA compliance.  
It is worth pointing out that these two are really independent.  In fact, 
the OSA compliance should really be implemented regardless of whether the 
OpenDoc work is attempted at all.  It is the logical way to implement send 
and perhaps exec on the Mac.  Both the Tcl-based Mac Editor Alpha and the 
Mac implementation of Perl offer Apple Event support.  In the case of 
Alpha, this has made it a very powerful plug-in editor for the major Mac 
development environments.  Without some kind of Apple Event support, Tcl/Tk 
will be a mute and isolated participant in the MacOS world.

A) OpenDoc:

There are two levels of OpenDoc incorporation offered by the Apple OpenDoc 
development group.  One is to make Tcl/Tk a full fledged OpenDoc part, 
capable of being embedded in other parts, and of containing embedded parts.  
This is called a container part, in OpenDoc terminology.  This is obviously 
the best way, since it would allow us to embed Tk controls in any other 
document, and to embed viewers, spreadsheets or whatever parts we wish 
within the Tk layout of our application.  However, it also takes the most 
work, some of which is not entirely trivial.

The second is to make Tcl/Tk be an embeddable part, but not a containing 
part.  This would allow us to put Tk controls and display widgets into a 
document alongside other parts, and use the Tcl interpreter to run our own 
extensions, and communicate with the other parts.  However, we would not, 
for example, be able to embed the 3-D viewer into a Tk text widget, or use 
the Tk scrollbar widget to drive a non-Tk part.

i) Necessary Enhancements:

The full OpenDoc support requires changes or enhancements in four major 
areas, the event loop, windows, part activation, and part storage.  The 
following is a bare sketch of each of these four areas.

The Event Loop:

In any compound architecture like OpenDoc, the shell has to control the 
event loop.  In order to switch control between the various parts, and also 
allow the parts to share idle time, there has to be a central router.  The 
way this is implemented in OpenDoc is that each part has a HandleEvent 
method that gets called by the document shell.  The document shell takes 
each event off the event queue, determines which part should respond to 
that event, and dispatches the event to that parts HandleEvent method.  
The Tk event loop would have to be replaced by an event handler, which can 
do what it wishes with the events in Tks internal event queue, but cannot 
poll for system events.

This is not too difficult to implement.  The current model in Mac Tk is 
that each time through the event loop, the top of Tcls internal event 
queue is serviced.  If there was an event in the queue, it is handled and 
the event loop is restarted.  If the queue is empty, then the various event 
sources (file events, as well as UI events,...)  are all polled for events.  
The new events are not processed at this time, but just added to Tcls 
internal queue.  Then the top event in the queue is serviced.  In OpenDoc, 
the handler would just put the event that woke it up onto the queue, then 
service the top event.  The polling for file events, etc..  would be done 
when the handler was invoked for an idle event.  It is yet to be seen 
whether this will cause performance problems, but it is the model for all 
the OpenDoc applications, and none of the currently available parts seem at 
all sluggish, so it should not be a problem.

Windows:

One major change in Tk required by OpenDoc is that the main window of the 
application may not be a top level window.  After all, we want to be able 
to embed a Tk layout into a document.  This does not seem a very hard 
problem, however.  We can just make an ODToplevel widget, which is just 
like a TopLevel, except that its window manager is the OpenDoc shell rather 
than the MacOS window manager.  Tk would draw all its component widgets 
into this ODToplevel just as it would into an ordinary toplevel.  Then it 
passes its final geometry request to its containing part.  There is some 
work to be done to implement the wm and winfo commands for these 
ODToplevels, but OpenDoc possesses a full set of calls to get geometry 
information, and arbitrate for new geometry, so the groundwork is well 
laid.

One requirement for the ODToplevel, and ordinary Toplevels, is that they 
must be registered with OpenDoc.  This is so OpenDoc can do event routing, 
and dispatch update requests.  This registration is accomplished by a 
fairly simple call, though we have to get access to our parts object to 
make it.  Thus windows in OpenDoc Tk need to have a part pointer added to 
their data storage.  This can just be a ClientData pointer hung off the 
window structure, so it is not too intrusive.

If we want to implement Tk as a containing part, we will also have to 
provide an ODFrame widget.  This will be the containing frame for an 
embedded OpenDoc part.  Each OpenDoc part is responsible for informing its 
containing part of its geometry requirements, so the ODFrame has all the 
information it needs to negotiate for position within the rest of the Tk 
layout.  Further, each OpenDoc part has the responsibility to draw itself, 
so we dont need to do any work to present the contained part.  There are 
some User Interface guidelines to indicate which part is the active one in 
the document, so the ODFrame widget would need some custom border drawing 
routines to conform to these.  Since OpenDoc does all the event passing, 
the ODFrames responsibilities to its contained part are limited to 
activating it when the frame is clicked in, and redrawing the borders in 
accordance with the UI Guidelines when the contained part becomes inactive.

Part Activation:

When the Tk part is activated (for instance, when it is clicked in, or when 
it is first created) OpenDoc requires a number of setup routines be run.  
The part has to request focus for the events it is interested in (mouse 
events, keyboard events, as well as other system functions, like 
communications ports).  However, this Focus negotiation is separate from 
the Tk focus commands, just as the window manager focus in X is separate 
from Tk.  Basically, all that is required is that when the Tk part becomes 
active, it must request the keyboard and mouse focus, done through fairly 
simple library call.  Again, when the part is deactivated, there is a 
protocol that must be followed to resign the foci which the newly activated 
part requests.

The UI requirements for displaying the active part (there is a little 
double line border in the current implementation) must be implemented.  
This frame would just be a special -relief option for the ODToplevel.

The general UI standard for OpenDoc is that a part withdraw its floating 
palettes when it becomes inactive, and redraws them when it is reactivated.  
This would also have to be implemented.

Part Storage:

Each part is responsible for reading itself in from storage, and writing 
itself out to storage.  This is so the document can be saved and restored 
to this state later.  In Tk, this is relatively easy, since the Tcl/Tk 
architecture allows you to query out the state of the interpreter.  You 
know what all the global variables are, and you can just run the Tk tree to 
find out all the widgets, their contents and their positions.  You also 
need to track the proc definitions, and what files are open, what fileevent 
handlers have been registered, etc.  The state of the application can be 
"pickled" as this set of Tcl/Tk commands.  Doing this quickly and 
efficiently may take a little work, but all the facilities are already 
available in Tk.  Of course, any extensions that you add to Tcl will have 
to have this ability to pickle themselves as well, if they are to coexist 
in OpenDoc.

B) Open Scripting Architecture:

This is the generic language by which parts (and applications under MacOS) 
communicate with each other.  The idea is that each application specifies 
the objects and operations that it wants to export to the world.  For 
instance a generic application has objects like documents and windows; and 
a word processor has, in addition, paragraphs, lines and words of text.  
There is a "Required suite" of operations that a generic application must 
perform: open print, quit and run.  Then our word processor will add 
natural functions like get, set, delete and save, whic can act on any of 
the basic objects.  Each of these objects are specified by a four-letter 
code in a program resource, which identifies the object or function, and by 
some "Human readable" information on the object.  These codes are linked to 
a handlers within the application at startup.

To pass an instruction to another part or application, you construct an 
Apple Event, which is just a data structure describing the operation and 
the objects it acts upon using these codes.  It is a nested structure, so 
that objects can be specified as the result of operations, and thus quite 
complicated instructions can be built up.  Then you pass this Apple Event 
to the Apple Event Manager, which routes it to the other application or 
part.  That part receives the instruction as an entry in its event queue, 
(of type kHighLevelEvent) and responds the event, parsing up into its 
parts, and calling out the handlers associated with the codes, and finally 
returning a reply Apple event if the incoming instruction requested a 
result.

Our job, however, is simpler than the above discussion makes it sound.  We 
do not need to provide an OSA interface to the objects within Tk, since it 
already has its own scripting language.  If another part wants to get at a 
widget in a Tk layout, they can just send a bit of Tcl code.  All we need 
is 1) to be able to accept a Tcl script from another application, and 
respond to it, and 2) some facility to build up an Apple Event and dispatch 
it to another application.  This capability already exists in the Tcl-based 
Mac Editor Alpha.  There is a doScript Apple Event handler, and a Tcl 
extension that allows you to build up arbitrary Apple Events from their 
codes, and send them.  Although the Alpha code is not in the public domain, 
so we cannot use it directly, the Apple Event builder is a simple wrapping 
of a library (AEGizmos) provided by Apple, and in the public domain, so 
this functionality is easy to replicate.  Adding the single Apple Event 
handler (doScript) is quite straightforward.

Of course, this is a very low-level solution, and probably not how you 
would really use the inter-part communication.  In keeping with the Tcl 
philosophy, you would identify a part you were interested in communicating 
with, and then extend the basic Apple Event builder to provide a higher 
level of abstraction appropriate to that part.  There is a Core suite of 
Apple Events that all applications are expected to support (when the events 
and objects make sense for the application), and it would be worth the 
effort, at least, to wrap the process of building these events.

One example of the use of this Apple Event builder is to implement send for 
Tk on the Mac.  After all, send is no more than the doScript Apple event 
with the script as its data, sent between two Wish applications.  Another 
use for the Apple Event builder, is to implement exec.  There is no concept 
of "Command line arguments" on the Mac, so you cant really make an exact 
parallel to the Unix exec.  The equivalent is to send a run Apple event to 
the application, and the extra initialization data can be provided in the 
Apple Event.  So the implementation of this inter-part communication would 
close two open items in the Mac Port of Tk.

IV) Conclusions:

First of all, I hope I have communicated some of the promise of the 
"document centered" User Interface philosophy.  It allows the user to 
tailor "mini-applications", which contain the specific functionality they 
need.  Moreover, each copy of the document contains both the description of 
the "application" that the user has assembled, and its state when he or she 
last left it.  So, once constructed, the document can be replicated, 
reused, edited, and embedded as an atomic element in another document.  It 
transfers many of the "application designer" functions to the user of the 
application, and offers a flexibility and level of control that is quite 
promising.

However, at this stage the OpenDoc world is lacking a good solid toolkit.  
This, by the way, is not some oversight on the part of the OpenDoc 
development group.  The idea was to create an open architecture that 
developers could tailor to their own needs, rather than forcing a whole 
package down everyones throats.  This situation offers great 
possibilities, however, for someone who can deploy a solid toolkit in 
OpenDoc.  There are several reasons to think Tcl/Tk would fill this role 
elegantly.  Its extensibility would be a great asset, just as it is for 
stand-alone applications.  The widget set has proved popular because it is 
easy to use, and yet very flexible.  Currently OpenDoc only has a solid 
implementation under MacOS. However, as it is deployed to more platforms, 
we can repeat the steps we took to embed Tcl/Tk into MacOS OpenDoc, with 
the confidence that the engine is well tested on those platforms.  This 
would not be true of any widget set that was developed first of all on the 
Mac.

I will conclude by laying out a proposal for the incorporation of Tcl/Tk 
into OpenDoc.  First of all, we need to refit the event loop part of Tcl, 
converting it into a handler based architecture.  Substantial progress has 
been made in this area already.  Then, we should implement the scripting 
engine into MacTk, and port that to OpenDoc.  This is of sufficient utility 
to MacTk in general, that it should be done as soon as possible.  The next 
step is to embed Tk.  The simplest way to do this is to start by allowing 
only separate, Tk-controlled toplevels.  These only need to be registered 
with OpenDoc, so they receive events, other than that they do not differ 
from their Wish counterparts.  This has also been done.  Then we need to 
write an ODTopLevel widget, and finally the ODFrame widget.  I have not 
made any progress on these items yet; they are fairly independent, and 
would make interesting projects for anyone interested.


