As it turns out, the web eventually came around to using NeWS's extensible client/server architecture, once they rediscovered it 20 years later and called it "Ajax". (2005 [1] - 1985 [2] = 20)
Hi Jim! As it turns out, AJAX is immensely popular in Amsterdam, because it's the name of the local soccer team [1]. But they pronounce AJAX like "ah yax", and JavaScript like "ya va schkript"! ;)
Less important and less popular there was also MGR, which treated windowing more like a terminal session, and so was more Unix-philosophy than most. It was neat, and because of its smaller profile it got ported to a lot of systems (Atari ST, etc.) that struggled under the full X11 system
Other than using PostScript for 2D rendering I don't think NeWS and Display Postscript had much in common.
In NeWS you could write your client applications completely in PostScript (or something compiled down to PostScript) and it had its own object-oriented, multi-threaded environment with event handling etc.
NeWS was more of a predecessor for Java than NeXT.
It's no coincidence that NeWS and Java were both designed and written by James Gosling.
It could be said that Java rose out of the ashes of NeWS.
Although I wouldn't go as far as to say that NeWS rose out of the ashes of Gosling/UniPress/EvilSoftwareHoarder Emacs and Mocklisp. But Gnu Emacs did! ;)
However, at UniPress we did develop a nice NeWS display driver for Emacs that worked efficiently over a slow network connection, providing local interactivity like text selection feedback, control panels, pie menus, multiple tabbed windows, etc.
Here's the PostScript source code of the UniPress Emacs 2.20 NeWS display driver [1], and a screen snapshot [2] of Emacs as an authoring tool for the NeWS version of the HyperTIES hypermedia system (plus a diagram of HyperTIES extensible client/server architecture).
Here's the source code for the classic PizzaTool demo (BTW, I've just looked on Google Maps, and I think that Tony & Alba's pizza place in Mountain View no longer exists):
I actually worked on a project that used NeWS (actually HyperNeWS) as a front end for a Lisp based AI system written in Common Lisp.
HyperNeWS could do some neat things - e.g. you could draw a shape (any shape!) in the graphical editor and paste it as the shape of a window, all without writing any code.
Edit: changed "uses" to "used" - was quite a long time ago!
I really miss HyperNeWS [1], which I worked on with Arthur van Hoff at the Turing Institute, and I used it to port SimCity to NeWS on Unix [2].
Arthur van Hoff (who developed HyperNeWS and other stuff like Java [3]) and I are working together again, this time at his 360° VR video camera company, JauntVR [4]! I'm developing a secret project called HyperJaunt, that I can't say anything about yet, but you can guess by the name that I'm pretty excited about it! ;)
We are looking for a lead software engineer with leadership experience in Amsterdam! [5]
The Role:
This is a highly challenging and highly technical role offering the chance to define the early days of a new industry. Candidate would have to know or be willing to learn mobile 3D graphics programming (OpenGL/GLSL/Unity) with focus on interactivity, network optimization and performance tuning. Candidate should have strong leadership skills. While we are looking for prior experience as a good indicator of future success, our main criteria includes passion for VR, intelligence, creativity and strong work ethics.
Postscript isn't a complex language. It's probably quite straightforward to translate it into Javascript and run it locally on a web browser, rendering into a canvas. With a websocket connection to the backend, it'd be possible to recreate NeWS and use it for traditional client/server Unix apps, but with an ordinary web browser instead of an X server.
I don't know whether this would be useful, mind, other than being a cool hack (which has value all of its own)... but it would be a very cool hack.
Omar Rizwan has been developing a project called "dewdrop" [1] [2] to re-implement NeWS in the web browser, using canvas to render the graphics.
It's based on the WPS PostScript interpreter [3], which he's rewritten and extended in TypeScript.
He says: "It's _very_ incomplete (not many events, multi-canvas support unclear, no GUI toolkit, no network stuff), but a surprising amount of the core stuff is in, I think (cooperative multitasking including timer events, OOP, graphics).
Thinking about where to go from here -- could start the GUI toolkit, or server/client stuff..."
A few years ago I started writing my own "SunDew" [4] [5] NeWS interpreter in JavaScript. It's not complete and doesn't have any graphics, but I've written some comments and stubbed out some classes that specify all the various NeWS data types and operators that would have to be supported.
But now that I have seen how much cleaner Omar's code is written in TypeScript, and how it elegantly takes advantage of TypeScript's asynchronous programming to implement NeWS light weight processes, I think it would be better to build on top of what he's done instead. But my code and the comments in it could at least help serve as a spec for the various types of NeWS objects and operators that are required.
There's still a lot of work to do, but it's certainly possible and would be really cool!
There are some nuances that need to be worked out where NeWS doesn't quite match up with JavaScript or standard PostScript.
Strings, arrays and dictionaries are references to shared object bodies, and arrays and strings of different lengths can share memory with sub-intervals.
References to shared object bodies on the stack and in other objects contain their own permission bits independent of the object body, so you can have read-only access from one reference, and writable or executable access from another reference.
And of course NeWS has magic dictionaries, which is a way of calling native code when you access dictionaries, which NeWS uses to implement fonts, canvases, processes, etc. [6]
There are also a lot of undocumented nuances in NeWS that would have to be reverse engineered or figured out by looking at the original source code.
I worked in Edinburgh and visited the Turing Institute a few times - I did meet Arthur a few times though I think we mainly spoke to some other chap (Danny?).
When Arthur moved to work for Sun I remember begging a copy of Java from him early in '95.
No, NeWS was around before NeXT, and it was developed independently by James Gosling.
NeXT's Display PostScript architecture was not concerned with networking, extensibility, providing local interactivity, or reducing client/server communication by downloading code, which is what the modern term "Ajax" refers to.
Here is one of Gosling's earlier papers about NeWS (originally called "SunDew"), published in 1985 at an Alvey Workshop, and the next year in an excellent Springer Verlag book called "Methodology of Window Management" that is now available online for free. [1]
Chapter 5: SunDew - A Distributed and Extensible Window System, by James Gosling [2]
Another interesting chapter is Warren Teitelman's "Ten Years of Window Systems - A Retrospective View". [3]
Also, the Architecture Working Group Discussion [4] and Final Report [5], and the API Task Group [6] have a treasure trove of interesting and prescient discussion between some amazing people.
F R A Hopgood, D A Duce, E V C Fielding, K Robinson, A S Williams
29 April 1985
This is the Proceedings of the Alvey Workshop at Cosener's House, Abingdon that took place from 29 April 1985 until 1 May 1985. It was input into the planning for the MMI part of the Alvey Programme.
The Proceedings were later published by Springer-Verlag in 1986.
5. SunDew - A Distributed and Extensible Window System
James Gosling
SunDew is a distributed, extensible window system that is currently being developed at SUN. It has arisen out of an effort to step back and examine various window system issues without the usual product development constraints. It should really be viewed as speculative research into the right way to build a window system. We started out by looking at a number of window systems and clients of window systems, and came up with a set of goals. From those goals, and a little bit of inspiration, we came up with a design.
GOALS
A clean programmer interface: simple things should be simple to do, and hard things, such as changing the shape of the cursor, should not require taking pliers to the internals of the beast. There should be a smooth slope from what is needed to do easy things, up to what is needed to do hard things. This implies a conceptual organization of coordinated, independent components that can be layered. This also enables being able to improve or replace various parts of the system with minimal impact on the other components or clients.
Similarly, the program interface probably should be procedural, rather than simply exposing a data structure that the client then interrogates or modifies. This is important for portability, as well as hiding implementation details, thereby making it easier for subsequent changes or enhancements not to render existing code incompatible. [...]
DESIGN SKETCH
The work on a language called PostScript [1] by John Warnock and Charles Geschke at Adobe Systems provided a key inspiration for a path to a solution that meets these goals. PostScript is a Forth-like language, but has data types such as integers, reals, canvases, dictionaries and arrays.
Inter process communication is usually accomplished by sending messages from one process to another via some communication medium. They usually contain a stream of commands and parameters. One can view these streams of commands as a program in a very simple language. What happens if this simple language is extended to being Turing-equivalent? Now, programs do not communicate by sending messages back and forth, they communicate by sending programs which are elaborated by the receiver. This has interesting implications on data compression, performance and flexibility.
What Warnock and Geschke were trying to do was communicate with a printer. They transmit programs in the PostScript language to the printer which are elaborated by a processor in the printer, and this elaboration causes an image to appear on the page. The ability to define a function allows the extension and alteration of the capabilities of the printer.
This idea has very powerful implications within the context of window systems: it provides a graceful way to make the system much more flexible, and it provides some interesting solutions to performance and synchronization problems. SunDew contains a complete implementation of PostScript. The messages that client programs send to SunDew are really PostScript programs. [...]
4. Ten Years of Window Systems - A Retrospective View
Warren Teitelman
4.1 INTRODUCTION
Both James Gosling and I currently work for SUN and the reason for my wanting to talk before he does is that I am talking about the past and James is talking about the future. I have been connected with eight window systems as a user, or as an implementer, or by being in the same building! I have been asked to give a historical view and my talk looks at window systems over ten years and features: the Smalltalk, DLisp (Interlisp), Interlisp-D, Tajo (Mesa Development Environment), Docs (Cedar), Viewers (Cedar), SunWindows and SunDew systems.
The talk focuses on key ideas, where they came from, how they are connected and how they evolved. Firstly, I make the disclaimer that these are my personal recollections and there are bound to be some mistakes although I did spend some time talking to people on the telephone about when things did happen. [...]
The membership of the Architecture Working Group was as follows:
George Coulouris (Chairman).
James Gosling.
Alistair Kilgour.
David Small.
Dominic Sweetman.
Tony Williams.
Neil Wiseman.
[...] The possibility of allowing the client process to download a procedure to be executed in response to a specific class of input events was discussed, and felt to be desirable in principle. However, more work was needed to establish the practicality in general of programmable window managers. The success of Jim Gosling's SunDew project would be an indicator, but it was felt that it would be fruitful to initiate a UK investigation into this issue. John Butler pointed out in discussion that in the Microsoft MS- Windows system an input event received by a client process could be sent back to the window manager for interpretation by one of a set of translation routines. [...]
[...] There was a strong feeling that, at this stage in their development, window managers need to be very flexible. The downloading-of-procedures idea in James Gosling's work was seen as a nice way to achieve this. In this context protection issues were seen to be important. There need to be some limits on loading arbitrary code, especially since the window manager has in some sense the status of an operating system in that it must be reliable and not crash. One idea for achieving protection was through the use of applicative languages which are by their nature side-effect free. [...]
21.4 DISCUSSION
Teitelman:
Referring to point (3) in your list, can you characterize the conditions under which a window manager would refuse requests from a client? It feels so soft that the user might feel uneasy. Is the window manager surly? Is it the intention that requests are honoured most of the time, and that failure is rare?
Gosling:
Yes, but failure should be handled gracefully.
Bono:
I think that there are two situations which arise from the same mechanism. The first is occasional failure such as a disk crash. The program environment should be robust enough to deal with it. The other situation is where device independence is written into the system. What happens if a colour device is used to run the program today, where a black and white device was used yesterday? This may show up in the same mechanism, so you cannot say that it is rare.
Gosling:
When an application makes a request, it should nearly always be satisfied. The application program can inspect the result to see if it is satisfied exactly. If it asks for pink and it doesn't get it, it should be able to find out what it did get. Only then should the application deal with the complex recovery strategy that it may need. We need some sort of strategy specification. What sort of strategy should we use to select a font or colour if there is no exact match? What feature is more important in matching a 10 point Roman font, its size or its typeface? At CMU, if you point at a thing and want 14 point Roman you may get 14 point Cyrillic, which is not very useful.
On point (7), are you implying a dynamic strategy, or one determined at system configuration?
Gosling:
Harold (Thimbleby) is all for downline loading this. In reality this is not usually very easy. GKS adopts a compromise - an integer is used to select a predefined procedure. As you may only have 32 bits, this does not give you many Turing machines. Something of that flavour would not be a bad idea.
Cook:
Justify synchrony in point (2).
Gosling:
This is mostly a matter of complexity of program. Not many languages handle asynchrony very well. If we have Cedar or Mesa then this is possible.
Teitelman:
How we do it in Cedar is that the application is given the opportunity to take action. In Mesa we require that the application catches the signal and takes any action. In the absence of the application program intervening, something sensible should be done, but it may impose a little bit more of a burden on the implementer.
Gosling:
In Unix software there is no synchronization around data objects. In Cedar/Mesa there are monitors which continue while the mainline code is running; there are no notions of interrupt routines.
Teitelman:
This is a single address space system. We are unlikely to see this in Unix systems.
Newman:
How realistic is it to design an interface using your criteria?
Gosling:
Bits and pieces already appear all over the place. The CMU system deals with most of this OK, but is poor on symmetry. The SUN system is good for symmetry, but not for synchrony. It is terrible on hints, and has problems with redraw requests. There is no intrinsic reason why we can't deal with all of these though. The problem is dealing with them all at the same time.
Williams:
A point that I read in the SunWindows manual was that once a client has done a 'create window' then the process will probably get a signal to redraw its windows for the first time.
Gosling:
Right, but it's a case of maybe rather than will. Some programs may redraw and redraw again if multiple events aren't handled very well, and give screen flicker.
Hopgood:
Do you have a view on the level of interface to the window manager?
Gosling:
Clients don't want to talk to the window manager at all, but should talk to something fairly abstract. Do you want to talk about this as the window manager as well? The window manager shouldn't implement scroll bars, or buttons or dialogues, we need another name for the thing which handles the higher level operations.
You can't do opengl efficiently over the network. At least xorg can't. Most applications uses opengl these days.
For me, I've been using Linux fulltime for the last 15 years and I have never, not even once, had the need to connect to a remote X11 server. ssh has always been enough for me.
I think it is likely that your lack of need for running applications remotely largely reflects another change: the rise of the web. We run fewer native applications than we used to, for better and for worse. I run mostly a browser and a terminal. The browser has taken much of the role X11 had, and things like VNC have taken most of the rest.
They just added another layer, flipped the words "server" and "client" around, and added more hardware.
Now you run the web browser client on top of the local window system server, through shared memory, without using the network. And both the browser and GPU are locally programmable!
And then the local web browser client accesses remote web servers over the network, instead of ever using X11's networking ability.
One way of looking at it in the X11 sense is that a remote app running in the web server acts as a client of the local window server's display and GPU hardware, by downloading JavaScript code to run in the web browser (acting as a programmable middleman near the display), and also shader code to run in the window server's GPU.
Trying to pigeonhole practices like distributed network and GPU programming into simplistic dichotomies like "client/server," or partition user interface programming into holy trinities like "model/view/controller," just oversimplifies reality and unnecessarily limits designs.
XFree86 had problems with OpenGL over network (to the extent of "it does not work at all" for any reasonable definition of "work"). Since the X.org fork this got mostly fixed and the related infrastructure (DRI, AIGLX, GLX_EXT_texture_from_pixmap, ...) is used extensively by other parts of the X server (for example to implement XVideo or Render in terms of OpenGL).
On the other hand, typical applications (ie. games) usually expect that the channel to GPU has quite large bandwidth and no meaningful latency, which simply isn't true for any kind of network connection.
Now 'most' is a relative term, but I do not think that's true at all. There are very few applications that use OpenGL. Obviously games are an exception, but if you count in all GUIs I would say mostly target X11 (via Gnome or KDE).
GNOME and KDE can also use opengl for some tasks if it is available. But right, most applications doesn't directly use opengl. I believe if it weren't such a pita to integrate opengl in desktop appliations (thanks to X11's bad design), many more applications would be using it.
To give you an example, think about desktop effects. On Windows, several applications such as Explorer makes parts of their windows semi-transparent. It's a nice simple effect that is impossible (without tons of hackery) to replicate using X11.
I don't think that this qualifies as "tons of hackery" given the fact that other contemporary UI systems with truly transparent windows implement it in same way (IIRC in pre-Vista Windows truly transparent windows are supported on the OS level but the implementation involves hacks with backing buffer and synthesized expose events).
Hm right. That is indeed possible because the client asks xorg for a surface with an alpha channel. What I don't think clients can do is doing the transparency effects themselves. Because that involves using opengl and doesn't work (very well) in a networked context.
Clients doing transparency themselves is the hackish solution to this problems because it involves the client sohehow knowing what it paints over.
And in all this has nothing to do with OpenGL except that GLX_EXT_texture_from_pixmap is particularly efficient way to implement it on OpenGL supporting hardware. For simple transparency, the compositor can do the blending completely in software (which involves getting the drawables to the client and back), do it via XRender (which may get translated into OpenGL by AIGLX-supporting server) or by calling OpenGL directly. For compositor that only cares about transparency XRender is probably better API, for 3D-ish effects (as in Xgl or Sun's Looking Glass) OpenGL makes more sense.
At Sun we experimented with implementing an X11 window manager in NeWS. We didn't have transparency at the time (1992), but we did support shaped windows!
The NeWS window manager supported cool stuff (for both X11 and NeWS windows!) like rooms, virtual scrolling desktops, tabbed windows, pie menus, was easily extensible and deeply customisable in PostScript, and ran locally in the window server so it could respond instantly to input events, lock the input queue and provide feedback and manipulate windows immediately without causing any context switches or dealing with asynchronous locking, unlocking and event handling. You'd never lose a keystroke or click when switching between applications, for example.
I touched on some of those ideas in this ancient window manager flamey-poo:
And here's how I think you should design a programmable "window manager" these days -- but it would be much more than just a window manager! It would be great for integrating legacy desktop and mobile applications into VR, for example!
Don asks Peter Korn:
Hey I would love to bounce an idea off of you! I didn't realize how much work you've done in accessibility.
There is a window manager for the Mac called Slate, that is extensible in JavaScript -- it makes a hidden WebView and uses its JS interpreter by extending it with some interfaces to the app to do window management, using the Mac Accessibility API.
So I wanted to make pie menus for it, and thought of a good approach: make the hidden WebView not so hidden, but in the topmost layer of windows, covering all the screens, with a transparent background, that shows the desktop through anywhere you don't draw html.
Then just make pie menus with JavaScript, which I've done. Works like a charm!
THEN the next step I would like to do is this:
aQuery -- like jQuery, but for selecting, querying and manipulating Mac app user interfaces via the Accessibility framework and protocols.
So you can write jQuery-like selectors that search for and select Accessibility objects, and then it provides a convenient high level API for doing all kinds of stuff with them. So you can write higher level plugin widgets with aQuery that use HTML with jQuery, or even other types of user interfaces like voice recognition/synthesis, video tracking, augmented reality, web services, etc!
For example, I want to click on a window and it will dynamically configure jQuery Pie Menus with the commands in the menu of a live Mac app. Or make a hypercard-like user interface builder that lets people drag buttons or commands out of Mac apps into their own stacks, and make special purpose simplified guis for controlling and integrating Mac apps.
Does that sound crazy? I think it just might work! Implement the aQuery "selector engine" and heavy lifting in Objective C so that it runs really fast, and presents a nice high level useful interface to JavaScript.
Here is an issue I opened about it on the Slate github page, describing what I've done, but I haven't written up the "aQuery" idea yet. That's the next step!
That's the FORTH source code from 1987 of a programmable multi threaded X10 window manager that lets you throw windows around so they bounce off of the edge of the screen!
Maybe you used Synergy to share a mouse and a keyboard over multiple machines. It's a use case that partly overlaps with running remote desktop applications on your display. Or VNC.
Plan 9 did it in an interesting way. You draw to the screen by writing to files under /dev. On Plan 9, all file operations take place over 9P, a networked file protocol. So if you are connecting to a remote machine and want to run a graphical program, you mount your local /dev/draw files on the remote end (this is actually taken care of automatically by cpu(1)) and just run the program. Its graphical functions access your local machine's /dev/draw and it all Just Works. Hard to explain but very neat when you use it.
Plan 9's "everything is a file" philosophy never worked for me, because it's far too low level, and I don't believe Unix's file I/O API itself is very pleasant: open, read, write, ioctl and select (gag).
I'd much rather have a real API with rich app-specific functional or event interfaces to call, and to be able to pass actual typed parameters instead just a stream of bytes, including structured data like json, s-expressions or PostScript data, or even (gasp) Turing complete programs, like PostScript code!
NeFS, as defined in 1990 in the infamous NFS3 proposal aka "Network extensible File System Protocol Specification" did just that, and it was actually a great idea too early for its time. So it went over like a lead balloon, and was never actually adopted.
NeFS should not have been framed as a successor to NFS, because it required a revolution in how programs interacted with the file system. And of course there are the security and stability implications of running downloaded code in the kernel, which hadn't been properly addressed. ;)
Take for example (shown below) the act of copying a file to a backup file in the same directory.
With traditional NFS, the server would have to send each block of the file to the client, which would then send it back to the server, which would then write it to disk. That required a lot of network traffic, as well as many context switches between user and kernel space on both the client and the server (at a time in history where they were extremely expensive).
Instead, the client could just send a simple PostScript program to the server (or call one that was loaded from a library or sent previously -- see the example below), which copied the file in the kernel of the server, without sending it over the network, or requiring any context switches on either the client or server.
That's several orders of magnitude more efficient in terms of both CPU and network usage, and just the simplest and easiest to explain example possible of what you could do.
Just imagine how much more efficient, powerful and tightly integrated together other utilities like "find" and "grep" could be, tightly woven together procedurally in the kernel instead of communicating with a stream of bytes over a pipe!
The Network Extensible File System protocol(NeFS) provides transparent remote access to shared
file systems over networks. The NeFS protocol is designed to be machine, operating system,
network architecture, and transport protocol independent. This document is the draft specification
for the protocol. It will remain in draft form during a period of public review. Italicized comments
in the document are intended to present the rationale behind elements of the design and to raise
questions where there are doubts. Comments and suggestions on this draft specification are most
welcome.
1.1 The Network File System
The Network File System (NFS™*) has become a de facto standard distributed file system. Since
it was first made generally available in 1985 it has been licensed by more than 120 companies. If
the NFS protocol has been so successful why does there need to be NeFS ? Because the NFS protocol
has deficiencies and limitations that become more apparent and troublesome as it grows older.
1. Size limitations. The NFS version 2 protocol limits filehandles to 32 bytes, file sizes to the
magnitude of a signed 32 bit integer, timestamp accuracy to 1 second. These and other limits
need to be extended to cope with current and future demands.
2. Non-idempotent procedures. A significant number of the NFS procedures are not idempotent.
In certain circumstances these procedures can fail unexpectedly if retried by the client. It is not
always clear how the client should recover from such a failure.
3. Unix®† bias. The NFS protocol was designed and first implemented in a Unix environment.
This bias is reflected in the protocol: there is no support for record-oriented files, file versions
or non-Unix file attributes. This bias must be removed if NFS is to be truly machine and
operating system independent.
4. No access procedure. Numerous security problems and program anomalies are attributable to
the fact that clients have no facility to ask a server whether they have permission to carry out
certain operations.
5. No facility to support atomic filesystem operations. For instance the POSIX O_EXCL flag
makes a requirement for exclusive file creation. This cannot be guaranteed to work via the NFS
protocol without the support of an auxiliary locking service. Similarly there is no way for a
client to guarantee that data written to a file is appended to the current end of the file.
6. Performance. The NFS version 2 protocol provides a fixed set of operations between client and
server. While a degree of client caching can significantly reduce the amount of client-server
interaction, a level of interaction is required just to maintain cache consistency and there yet
remain many examples of high client-server interaction that cannot be reduced by caching. The
problem becomes more acute when a client’s set of filesystem operations does not map cleanly
into the set of NFS procedures.
1.2 The Network Extensible File System
NeFS addresses the problems just described. Although a draft specification for a revised version of
the NFS protocol has addressed many of the deficiencies of NFS version 2, it has not made non-Unix
implementations easier, not does it provide opportunities for performance improvements. Indeed,
the extra complexity introduced by modifications to the NFS protocol makes all implementations
more difficult. A revised NFS protocol does not appear to be an attractive alternative to the existing
protocol.
Although it has features in common with NFS, NeFS is a radical departure from NFS. The NFS
protocol is built according to a Remote Procedure Call model (RPC) where filesystem operations
are mapped across the network as remote procedure calls. The NeFS protocol abandons this model
in favor of an interpretive model in which the filesystem operations become operators in an
interpreted language. Clients send their requests to the server as programs to be interpreted.
Execution of the request by the server’s interpreter results in the filesystem operations being invoked
and results returned to the client. Using the interpretive model, filesystem operations can be defined
more simply. Clients can build arbitrarily complex requests from these simple operations.
[...]
Example: Copy a File
Make a copy of file (foo) called (bar). Both files exist in the same directory dfh. The request
starts by looking up the filehandle for the file to be copied and creates a filehandle for the copy.
The loop operator executes a procedure that copies the file using 1K reads and writes. It
maintains a running count of the number of bytes yet to be copied.
% Copy a file
%
dfh (foo) lookup /foofh exch def % get filehandle for (foo)
dfh (bar) create /barfh exch def % create filehandle for (bar)
/bytes foofh getattr /fsize get def % get size of (foo) so we know how much to copy
/offset 0 def % initialize offset for (bar)
{
/data foofh offset 1024 read def % read up to 1K from (foo)
barfh offset data write % write up to 1K to (bar)
/bytes bytes 1024 sub def % decrement byte count by 1024
bytes 0 le { exit } if % if it’s < 0 then we’re done
/offset offset 1024 add def % increment offset by 1024
}
loop
barfh getattr 1 encodereply sendreply % return the attributes of the new file to client.
I don't have numbers but in general I'd call it no less usable than X forwarding over ssh. For a long time I used to connect to a Japanese Plan 9 server using drawterm (a Windows/Linux application which essentially emulates the /dev/draw infrastructure) and it was pretty decent considering the latency--I used it to read email, follow IRC, and write code. Over a LAN, it's so fast as to be indistinguishable from something running on your local machine.