=== Top of the Swiki === Attachments ===
Nebraska
Nebraska is a toolkit for building remote interactions with Morphic in Squeak. It is modelled somewhat after Kansas, although as yet it's a much simpler system. There is a shared world on some server on a network, and other people can connect to that world from afar. Whenever the shared world tries to draw to its screen, it sends drawing commands across the network. Whenever a user tries to perform a mouse or keyboard interaction, those interactions are forwarded to the server where a RemoteControlledHand acts on their behalf.
The status is that you can do useful things and even develop code remotely. The performance is reasonable over a local T1 connection (I haven't actually tested it otherwise....) However, some things don't work. Many things still draw to the server's world instead of the shared world. And I haven't even touched 3D.
It's being worked on by Lex Spoon. It's being integrated with Squeak Central new collaborative system under the name "Midwest Telemorphic" by Bob Arning -- stay tuned!
Getting the Code
Load the following code, in order:
WARNING: the last changeset changes around some system code, so you may not want to load it into your main image.
Trying it out
To start a server, execute the following code:
| server |server := NebraskaServer new.
server startListeningOnPort: 9091.
(NebraskaServerMorph new server: server) openInWorld.
Feel free to run it on another port than port 9091.
To start a client, run the following in another image:
NetworkTerminalMorph openAndConnectTo: 'servername' port: 9091
Fill in your server's hostname for 'servername'. At this point, everything should be working!
NOTE: if you want to have a local view of the server, you shouldn't use the TCP connections. The problem is that the server will occasionally do a #flush, and it won't work due to single threading. The better solution is to use a LoopBackStringSocket instead of a regular StringSocket, but there is no handy method for that right now....
Small Tweaks
Accessing the Shared World Progammatically
You can access the shared world with Smalltalk code on the server. Just do "server sharedWorld". For example, you can use this to add some morph you want to edit to the world:
| server |server := NebraskaServer new.
server startListeningOnPort: 9091.
server sharedWorld addMorph: (some morph).
(NebraskaServerMorph new server: server) openInWorld.
Changing the Size of the Shared World
The proper way to change the size of the shared world is as follows:
server extent: 600@400 depth: 32
The server will broadcast the change to all connected clients.
Architecture
The basic system provided here isn't the only possible scenario this toolkit can be used for. For example, you may wish to make Nebraska the main UI for the system and allow project switches inside of the shared world. You may wish to make a client image which automatically connects to some server. There are lots of possibilities for the components herein.
StringSocket
StringSocket's are wrappers around regular sockets that allow sending arrays of strings. I have found this more convenient that dealing with raw binary streams. The encoders and decoders use StringSocket's instead of talking to Socket's directly.
CanvasEncoder/CanvasDecoder
CanvasEncoder accepts canvas commands, encodes them into string arrays and forwards them over an underlying string socket. CanvasDecoder does the opposite, decoding string arrays and drawing onto an actual canvas.
There are two commands other than drawing commands that CanvasEncoder/Decoders work with. First, they handle screen resizes. Second, they handle "force to screen" commands.
RemoteCanvas
A RemoteCanvas wraps a CanvasEncoder, and has a clipping rectangle and a transformation associated with it. Whenever you draw to a RemoteCanvas, it will first establish the clipping rectangle and transformation, and only then will it forward the actual drawing commands. The purpose of RemoteCanvas, instead of just having CanvasEncoder, is to allow multiple clipping rectangles and transformations to be live at the same time. However, clip rectangles and transformations don't work perfectly at the moment, so this part of the system might change....
MorphicEventEncoder/Decoder
These classes encode and decode MorphicEvents, similar to CanvasEncoder/Decoder.
RemoteControlledHandMorph
This is similar to RemoteHandMorph. It accepts events from a MorphicEventDecoder, and acts on those events.
NetworkTerminalMorph
A NetworkTerminalMorph is a simple morph which accepts drawing commands from a CanvasDecoder, and which forwards all events sent to it to a MorphicEventEncoder.
NebraskaPasteUpMorph
NebraskaPasteUpMorph is a variant of PasteUpMorph which has an additional set of remote canvases. The most notable difference from a regular PasteUpMorph is that #assuredCanvas builds a canvas out of these remote canvases, instead of building a FormCanvas on the Display.
NebraskaServer and NebraskaServerMorph
These are the heart of the server setup described above. The server does basic things like accepting new connections and updating the underlying NebraskaPasteUpMorph whenever the set of clients changes. The ServerMorph at this time mostly just step's the server periodically.
Other Kinds of Canvases
There are several kinds of canvases floating around in the system that others might find useful. There are:
- MultiCanvas: forwards canvas commands to multiple underlying canvases
- CachingCanvas: maintains a cache of the screen in a local Form, so that contentsOfArea: can be quick even if the main canvas is a remote one.
- NullCanvas: does nothing. great for benchmarking.
- ClippingCanvas: wraps a canvas and clips the underlying canvas. This is just around so that I don't have to give a clipping rectangle to all of the above kinds of canvases.
- PluggableCanvas is an abstract superclass of several of the above. It's useful when all canvas commands should be modified in a uniform way. (eg, all canvas commands should be executed by doing a clip, and then running the original command)