Grok the Web

A Programmer's Guide to the New Software Development Paradigm

by Andrew Schulman


Chapter 7

Web Browser as Display Engine

Last revised: April 29, 1997


Full GUI via printf!!

Suddenly dialog box programming (and user-interface programming more generally), which was supposed to be hard, is easy. Besides <FORM> and <INPUT>, another wonderful example is <TABLE>. You construct the HTML, and the web browser does all the work. The point, this chapter shows, is that what we call a web browser is really a *display engine*, an all-purpose application. (X-Windows and NeWs were great ideas; this is a workable implementation of the basic idea of separating an app from its UI.) You drive this display engine using a text file. This text file is written in HTML. (Text rather than binary means: no priesthood. This has both benefits and problems. In HTML, app drives the display engine at about the "right" level; contrast for example the lower-level X protocol or PostScript.)

I'm going to discuss my "local CGI" idea in this chapter: why require that a network sit between a CGI program and the web browser? Given that a CGI program can produce nice-looking UI, without getting involved in the micro-details of UI, why not make this same mechanism available on a single machine? The chapter probably needs to discuss Microsoft's "Trident" ("Dynamic HTML") here too.

(See email from Xavier on importance of trying out locally. Try to get http://localhost to work with WebSite, use WebSite as Local CGI "engine", at least as prototype.)

(This chapter is based on keynote presentation I gave at WinDev, and talks I gave at BCS Windows SIG and SD96. Need to dig out notes and slides for those: try to reuse. Also, some of Jon Udell's Byte articles discuss this same point. Quote Jon in this chapter.)

In previous chapters, we've seen plenty of forms. We know these are HTML interfaces to CGI, and we've discussed tremendous implications of this. But one thing we didn't really comment on: how the form itself is displayed.

If you're a Windows or Mac or X developer, you might know what I'm getting at here. These forms look like dialog boxes: they have pushbuttons, edit fields, drop-down lists, radio buttons, and so on. Dialog boxes are difficult for developers to write. (Give example from a Windows programming book, even show some of the code to give an idea, then "if you didn't understand much of this, good, that's the whole point.")

Yet, here we have these very same forms, displayed by Netscape or MSIE or whatever. How the heck *did* the web browser display this form? Windows developers in particular are used to thinking of forms and dialog boxes as something you hard-wire into a program, using the hated "resource compiler." Obviously, the forms we've seen aren't wired into Netscape or MSIE, since they're all very specific to the particular web site -- a web site which might not even have existed when the web browser was built.

Clearly, the form "comes from" the HTML page. Well, that's obvious in a way, but please think about it some more until it seems *less* obvious: dialog boxes are hard, dialog boxes are hard-wired into a program, dialog boxes are built with the resource compiler. Yet these dialog boxes were obviously constructed "on the fly," based on the contents of an HTML page. Change the HTML page, and the form changes.

WOW! Suddenly dialog box programming, user-interface programming really, which was supposed to be hard, is easy.

<FORM>
<INPUT TYPE=text SIZE=40 name=1> 
<INPUT TYPE=radio NAME=x VALUE=1> Foo 
<INPUT TYPE=radio NAME=y VALUE=1> Bar
<INPUT TYPE=radio NAME=z VALUE=1> Baz
<INPUT TYPE=submit VALUE="Click here!">
</FORM>
The point is that what we call a web browser is really a *display engine*, an all-purpose application. You drive this display engine using a text file. This text file is written in HTML.

Idea that HTML forms too primitive, ugly: note flexibility of HTML UI, because INPUT TYPE=IMAGE (and TABLE to put border around image: see imagform.html; though BOX alias would be nice rather than one- column table hack) and ability to wrap HREF around IMG. Good example: www.lycos.com?

Nice simple example: flip gifs at zdnet (uses JS).

Also "Project Cool" with JS tutorial: http://www.projectcool.com/loindex.html, with explanation at http://www.projectcool.com/happynewyear/ ("How do you do that?!", emphasizes no plug-ins, etc., but do need JS).

Better examples than Project Cool, though!

Another great example besides forms: tables. Do an HTML table, and the web browser (display engine) is responsible for figuring out all column widths. Yes, you lose some control. But that control only needed for maybe 5% or less of tasks. Why penalize what is done 95% of time for what you might need maybe 5% of the time? Yet that has been basic Microsoft approach to software development: find the most complicated task you do most rarely, and make that the model for what you do the rest of the time. This is what passes for thinking ahead.

Benefits to text rather than binary: no priesthood.

Problem of text rather than binary: no priesthood. Similar to point made earlier, suddenly what required $200/hr consultant now done by kid making $30k/yr who doesn't even know he or she is programming. We know how to make money from complexity; a big problem of web is, can we make money from simplicity?

CGI programs generate HTML, i.e., CGI programs are programs that output text to drive the display engine. All the complexity of actually interacting with user, micro-managing mouse moves and hit detection, etc., is done by the web browser -- the programming is done once in a display engine, rather than being scattered through several million apps. This doesn't work for highly interactive apps (Doom, Quake, etc.), but even here note that Microsoft is talking about "Dynamic HTML."

Now, if you think about how many separate apps you have on your hard disk, how much redundancy there is between them (how many put up dialog boxes, etc.), you see the potential here: put a display engine in the operating system, have apps just output HTML. I call this Local CGI; it doesn't exist. How difficult would it be to cobble together a demo of it, maybe using http://localhost?

Maybe do Local CGI via sockets, as RPC. Other localhost addresses available, besides 127.0.0.1? Use registry: each service has name, filename, and IP address. If no IP address, client uses filename to launch. Functions get input on socket read, produce output on socket write. In other words, they're not CGI apps, but mini web servers. ("Local CGI" name no good anyway: "Web RPC"?; using HTTP, but not necessarily transferring HTML: make new MIME type for use by Web RPC clients: data/wrpc? If client can only accept HTML, then can send that.) Should use HTTP (port 80; need sample HTTP server anyway), so clients not aware of "local CGI" can use too. Can just add addresses other than 127.0.0.1 to hosts.sam file (hosts.sam? Maybe WebSite was looking for filename hosts??). Actually, all servers seem to take over not only 127.0.0.1 but all 127.0.0.xxx? Note sockets option: SO_USELOOPBACK ("bypass hardware when possible").

Names instead of "local CGI": point is that apps use HTML and web browser for their UI. Web browser is stdout/stdin, and HTML is ASCII. So some name that plays off this: htmlio? htmlui? Same basic goal as WinIO.

Jon Udell, Byte: a web application "reads and writes text just like a console app does. But the text it writes -- HTML -- describes how to render text and graphics [and forms and ...] on a bit-mapped screen. A web application is, from this perspective, something like a PostScript driver." (In fact, a "web browser" is really a general purpose display engine, CGI apps are programs that output the HTML to drive this "display engine," and local CGI if it existed would let the CGI app reside on the same machine as the display engine, without the web in between: need to split up monolithic Windows apps into client/server compontents.)

WWW6 paper on turning command-line apps into web GUI, with Java: http://www6.nttlabs.com/HyperNews/get/PAPER41.html; see also http://www.cs.vt.edu/~chitra/javamatic.html; their Unix demo at http://ash.cs.vt.edu:10000/UNIX/UNIX.html seems to take forever to load (applets?)

From Dale's report on WWW6, interesting point about web browser as display engine; this was part of Viola: "Kevin Hughes (EIT, now Verifone) and Mark Weber organized a Web History exhibit and a History Day track at the conference. It featured Tim Berners-Lee's Next Workstation running the first Web browser and a number of other notable 'firsts.' Viola was on display and pegged as the first to have employ the model of applets. I met with Pei Wei and talked to him about Viola. He pointed out, correctly I think, that Viola not only had the idea of applets as interpreted scripts, but it also had plug-ins, in which an external binary uses the browser as a display engine. (Do you remember the wire-frame airplane model? -- that was a separate program displaying its results in a Viola window.)" First edition of Krol based on Viola!

Problem with current plug-ins, applets using browser window as display engine: no access to HTML, just get a piece of screen real estate. Was Viola like this too?

To do local CGI, use DDE interface? See http://home.netscape.com/newsref/std/ddeapi.html, http://www.wptc.com/links2learning/www/html/tableofcontents.html. Spyglass SDI (http://www.spyglass.com:4040/newtechnology/integration/iapi.htm, can also use AppleEvents; ever did planned TCP/IP implementation?; see also earlier? CCI: http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/CCI/cci-spec.html, including sample apps). Use DDEML (see http://www.bigcreek.com/ddedemys.html)! DDEML functions for Win32 in USER32. Article on controlling Netscape from VB: http://www.program.com/ask2bits/. WebReview "auditorials" using RealAudio is good example of external app that controls browser (URLs stream in as part of audio; e.g., XXX).

// lcgi.c -- use DDE interface to web browser
// ShellExecute will look up ddeexec command strings in registry (Ron P., pp. 340-342, 372-3)
// Netscape has Netscape/WWW_OpenURL
// MSIE has IExplore/WWW_OpenURL
// could add additional verbs to registry, from Netscape DDE spec
// Started to use DDEML, but let shell do all work
// see my old cmd.c for ShellExecuteEx

// TODO: convert cgitest4.c (window browser) to Local-CGI
// Oops, have to force Netscape to *run* Local-CGI app; in this test, I'm just
//		running lcgi.exe from command line
// Any way for DDEML app to receive messages from browser? If so, then have equivalent
//      of "Fast-CGI" without app launch each time???

#include <stdlib.h>
#include <stdio.h>
#include "windows.h"	/* includes shellapi.h */

// extension is crucial: shell will use this to find DDE server, or to launch app
// See lcgi.reg for ddeexec registry settings for ".lcgi"
// If use ".lcgi" extension, must tell Netscape this is text/html
// If use ".html" extension, must enter Netscape dde into registry!
//		[HKEY_CLASSES_ROOT\NetscapeMarkup\shell\open\ddeexec]
// Better to use ".html" extension, and just before ShellExecute call, ensure
//		that proper entries are in registry

#if 0
[HKEY_CLASSES_ROOT\NetscapeMarkup\shell\Open\ddeexec]
@="%1"

[HKEY_CLASSES_ROOT\NetscapeMarkup\shell\Open\ddeexec\application]
@="NETSCAPE"

[HKEY_CLASSES_ROOT\NetscapeMarkup\shell\Open\ddeexec\topic]
@="WWW_OpenURL"
#endif

#define LCGI_OUTPUT "Local CGI Output.html"

void msg(const char *s) { MessageBox(0, s, "LCGI", MB_OK); }

void fail(const char *s) { msg(s); exit(1); }
 
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{
	char buf[128];
	FILE *f;

	// msg(lpszCmdLine);

	{
		FILE *f = fopen(LCGI_OUTPUT, "w");
		fprintf(f, "<HTML><HEAD><TITLE>LCGI Test #%u</TITLE></HEAD><BODY>\n", 1);
		fprintf(f, "<H1>This is LCGI Test #%u</H1>\n", 1);
		if (lpszCmdLine && *lpszCmdLine)
			fprintf(f, "<H2>%s</H2>\n", lpszCmdLine);
		fprintf(f, "Time: %lu<BR>\n", GetTickCount());
		fprintf(f, "Windows version: %0X<BR>\n", GetVersion());
		GetModuleFileName(hInstance, buf, 128);
		fprintf(f, "Module filename: %s<BR>\n", buf);
		// TODO: insert sample links back to here!
		fprintf(f, "</BODY></HTML>");
		fclose(f);
	}

	ShellExecute(0, 0, LCGI_OUTPUT, 0, 0, SW_NORMAL);
	
}
</PRE>