Commit Diff


commit - efc2b0c99e1a4f9d2be9e72785d566df903c66fb
commit + af78a4cd2b73800af86db8d999d80b1ef0e9bd75
blob - 7b1f73098d4880371ec4348f5a6c3277730c6370
blob + 7c6955065b2208d48858269988a4518fd806bc1b
--- NOTES
+++ NOTES
@@ -1,9 +1,5 @@
 This is a port of some Plan 9 libraries and programs to Unix.
 
-Some parts expect that the tree is installed in /usr/local/plan9.
-Most are position independent.  The few hard-coded references
-(there's one in sam) should really be fixed.
-
 * Obtaining the source
 
 Tarballs will be posted nightly (but only when there are updates!) at
@@ -19,18 +15,125 @@ See below.
 
 * Building
 
-To build, cd into src and run make; mk install.  This will place binaries
-in "bin".  At time of writing, the commands are sam, samterm, rc, and mk.
+First, you need to extract the tarball or check out the CVS tree
+(see below for CVS).  You should be able to install the tree anywhere
+-- tools check the environment variable $PLAN9 for the root of the
+tree.  Most of them assume /usr/local/plan9 if $PLAN9 is not set.
+
+To build and install, cd into the plan9/ directory and run "./INSTALL".
+This will first build "mk" and then use mk to build the rest of the
+system, installing libraries in plan9/lib/ and binaries in plan9/bin/.
 There are a few shell scripts already included in bin -- B, Bwait,
-and samsave.
+and samsave.  Arguably these directories should be broken up by
+architecture so that
 
-The "make" builds mk.  Mk builds the rest.
+* Writing programs
 
+The bin/ directory contains shell scripts 9a, 9c, 9l, and 9ar that mimic
+the Plan 9 tools pretty well, except in the object names: "9c x.c" produces
+x.o not x.9, and "9l x.o" produces "a.out" not "9.out" or "o.out".
+
+Mkfiles look substantially the same as in Plan 9, with slightly different
+names for the included rules. The most significant
+difference is that, since there is no autolinker, the Plan 9 libraries
+needed must be named explicitly.  The variable SHORTLIBS can
+be used to list them without giving paths, e.g.:
+
+	SHORTLIBS=thread bio 9
+
+The default is "SHORTLIBS=9".  (Libc is known as lib9; libregexp is
+known as libregexp9; the rest of the libraries retain their usual names.)
+
+Various function names (like open, accept, dup, malloc) are #defined in
+order to provide routines that mimic the Plan 9 interface better
+(for example, open handles the OCEXEC flag).  Lib9.h contains these
+definitions.  Function "foo" is #defined to "p9foo".  These definitions
+can cause problems in the rare case that other Unix headers are needed
+as well.  To avoid this, #define NOPLAN9DEFINES before including lib9.h,
+and then add the p9 prefix yourself for the renamed functions you wish to use.
+
+* 9P servers and "name spaces"
+
+A few Plan 9 programs, notably the plumber and acme, are heavily
+dependent on the use of 9P to interact with other programs.  Rather
+than rewrite them, they have been left alone.  Via the helper program 9pserve,
+they post a Unix domain socket with a well-known name (for example,
+"acme" or "plumb") in the directory /tmp/ns.$USER.$DISPLAY.
+Clients connect to that socket and interact via 9P.  9pserve takes
+care of muxing the various clients of that socket onto a single 9P
+conversation with the actual server, just like the kernel does on Plan 9.
+
+The choice of "namespace" directory is meant to provide a different
+name space for each X11 session a user has.  The environment variable
+$NAMESPACE overrides this.  The command "namespace" prints the
+current name space directory.
+
+In order to run normal Unix commands with their input or output
+connected to a 9P server, there is a new 9P request "openfd" whose
+response contains a real Unix file descriptor.  9pserve handles
+this request by sending a normal open to the real 9P server and
+sending back one side of a pipe.  Then 9pserver forks a thread to
+ferry bytes back and forth between its end of the pipe and the 9P
+conversation.  This works reasonably well, but has the drawback
+that reads are no longer "demand-driven" (the ferry thread issues
+the reads and fills the pipe regardless of whether the other end
+of the pipe is being read) and writes cannot return errors (writes
+to the pipe by the application will always succeed even though the
+write in the ferry thread might actually draw an interesting error).
+This doesn't cause too many problems in practice, but is worth
+keeping in mind.
+
+The command "9p" interacts with a given server to read or write
+a particular file.  Run "9p" for a usage message.
+
+* Plumbing
+
+There is a plumber.  It expects to find a plumbing rule file in
+$HOME/lib/plumbing.  $PLAN9/plumb/initial.plumbing is a
+good start.  
+
+Sam and acme interact with the plumber as they do on Plan 9. 
+(If there is no plumber, sam falls back to a named pipe
+as it always has on Unix.)  Unlike on Plan 9, there is a "web" 
+command whose purpose is to load files or URLs in a running
+web browser.  Right now, only Mozilla Firebird and Opera are
+supported, but it should be easy to add others to the script.
+The plumbing rules in $PLAN9/plumb/basic know to run "web"
+to handle URLs.
+
+Because sam and acme read from the plumber using file descriptors
+(and therefore the openfd hack described above), if the editor exits,
+this fact is not noted until the ferry thread tries to write the next
+plumbing message to the pipe.  At this point the ferry thread closes
+the corresponding plumber fid, but the plumber thinks the message
+has been sent -- the message is lost.  The message did serve a purpose --
+now the plumber knows there are no readers of the "edit" channel,
+so when it gets the next message it will start a new editor.  
+This situation doesn't happen often, but it is worth keeping in mind.
+
+Both acme and sam try to raise themselves when they get plumbing 
+messages.
+
+* Acme
+
+Acme works.  
+
+Programs executed with the middle button interact with acme by the
+"openfd" trick described above.  In a plain execution (as opposed
+to >prog or |prog), because of the delay introduced by the pipes,
+there is no guarantee that the command output will finish being
+displayed before the exit status notice is displayed.  This can be
+annoying.
+
+There is a "win" shell.  Of course, since we're on Unix, win can't
+tell when programs are reading from the tty, so proper input point
+management is right out the window.
+
 * Helping out
 
 If you'd like to help out, great!
 
-The TODO file contains our (somewhat long) to do list.
+The TODO file contains a small list.
 
 If you port this code to other architectures, please share your changes
 so others can benefit.  See PORTING for some notes.
blob - e09311a659bc301decc38657be1883fa5d5f6032
blob + 7ca8745fa4b87cb779d566edf0eeeb5ff8e220c1
--- TODO
+++ TODO
@@ -2,24 +2,6 @@
 	- bug with discovery of initial window size in certain cases
 	  (reported by Sean Dorward)
 
-* Plumber
-	- have named-pipe-based plumber from Caerwyn Jones
-	- 9term right-click plumbs
-	- plumb rules file runs B
-	- easy to hook up web browser:
-
-# urls to web browser
-type is text
-data matches '(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=]+([:.][a-zA-Z0-9_?,%#~&/\-+=]+)*'
-plumb to web
-plumb start /usr/rsc/bin/web $0
-
-	- want to change back to 9P-based plumber, need to build
-	  infrastructure first
-
-* Acme
-	- with 9P infrastructure, should "just work".
-
 * upas/fs+Mail
 	- with 9P infrastructure, should "just work".
 
blob - /dev/null
blob + 39615200bd24795c643ea3a347442900ef99c567 (mode 755)
--- /dev/null
+++ bin/web
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+plumb1()
+{
+	case $BROWSER in
+	# Other browsers here
+	# ...
+	*opera*)
+		$BROWSER -remote 'openURL('$i', new-page)'
+		;;
+	*firebird*)
+		$BROWSER -remote 'openURL('$i', new-window)'
+		;;
+	esac
+}
+
+if [ $# = 0 ]
+then
+	plumb1 about:blank
+else
+	for i
+	do
+		if [ -f "$i" ]
+		then
+			i=file://`pwd`/$i
+		fi
+		plumb1 $i
+	done
+fi
+
+case $BROWSER in
+*opera*)
+	$BROWSER -remote 'raise()'
+esac
+
blob - 918cc51b12f20057a0e9fc5d864ed3eb0217c8bd
blob + 23fd7adcac1c35c9faae3d44d39c2db45d6a0d82
--- plumb/basic
+++ plumb/basic
@@ -119,7 +119,10 @@ dst is postscript
 arg isfile $data
 plumb start gv $data
 
-type	is	text
-data	matches	'Local (.*)'
-plumb	to	none
-plumb	start	rc -c $1
+# urls to internet explorer on another machine
+type is text
+data matches '(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=@]+([:.][@a-zA-Z0-9_?,%#~&/\-+=]+)*'
+plumb to web
+plumb start /usr/rsc/bin/web $0
+# plumb start winstart iexplore -new $0
+
blob - cfee0013b4a7b8b9bca1152733fb20d01d380ed2
blob + 41a0a2f7c168a7ff8316e9626766bcb8e8189cb6
--- src/cmd/9term/9term.c
+++ src/cmd/9term/9term.c
@@ -147,7 +147,7 @@ hostproc(void *arg)
 	i = 0;
 	for(;;){
 		i = 1-i;	/* toggle */
-		n = read(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
+		n = threadread(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
 		if(n <= 0){
 			if(n < 0)
 				fprint(2, "9term: host read error: %r\n");
@@ -163,7 +163,7 @@ void
 hoststart(void)
 {
 	hostc = chancreate(sizeof(int), 0);
-	proccreate(hostproc, hostc, 32*1024);
+	threadcreate(hostproc, hostc, 32*1024);
 }
 
 void
blob - ca7eba424903b06e6a50574a028838efc5c2f241
blob + 6b2592883429f687f6eaaca88721ddc53cb15da2
--- src/cmd/acme/look.c
+++ src/cmd/acme/look.c
@@ -196,6 +196,7 @@ plumblook(Plumbmsg *m)
 	openfile(nil, &e);
 	free(e.name);
 	free(e.u.at);
+	drawtopwindow();
 }
 
 void
@@ -234,6 +235,7 @@ plumbshow(Plumbmsg *m)
 	winsettag(w);
 	textscrdraw(&w->body);
 	textsetselect(&w->tag, w->tag.file->b.nc, w->tag.file->b.nc);
+	drawtopwindow();
 }
 
 int
blob - 0bffad3d736f24f73c9833132cdf4d6b82ea28c7
blob + 2052843178e152eded81f007ba8739be92fea78c
--- src/cmd/samterm/mesg.c
+++ src/cmd/samterm/mesg.c
@@ -25,7 +25,7 @@ long	invlong(int);
 void	hsetdot(int, long, long);
 void	hmoveto(int, long);
 void	hsetsnarf(int);
-/* void	hplumb(int); */
+void	hplumb(int);
 void	clrlock(void);
 int	snarfswap(char*, int, char**);
 
@@ -296,11 +296,9 @@ inmesg(Hmesg type, int count)
 		threadexitsall(nil);
 		break;
 
-/*
 	case Hplumb:
 		hplumb(m);
 		break;
-*/
 	}
 }
 
@@ -668,7 +666,6 @@ hsetsnarf(int nc)
 	setcursor(mousectl, cursor);
 }
 
-/*
 void
 hplumb(int nc)
 {
@@ -687,7 +684,6 @@ hplumb(int nc)
 	}
 	free(s);
 }
-*/
 
 void
 hgrow(int m, long a, long new, int req)
blob - 67997f399810e74d249eb9de12326bd5d0c676c4
blob + facc78d2ee0236bbe30f949a5365a1222c4bdf9b
--- src/cmd/samterm/mkfile
+++ src/cmd/samterm/mkfile
@@ -23,6 +23,6 @@ HFILES=\
 
 CFLAGS=$CFLAGS -I../sam
 LDFLAGS=$LDFLAGS -L$X11/lib -lX11 -lm
-SHORTLIB=frame draw thread regexp9 bio 9
+SHORTLIB=frame draw plumb fs mux thread regexp9 bio 9
 
 <$PLAN9/src/mkone
blob - 60ef5c0ec33d61fd29aeb7e1eaf2abec34c87e99
blob + 7c4ed39b86faba29c867d48a6837407cdf9435d7
--- src/cmd/samterm/plan9.c
+++ src/cmd/samterm/plan9.c
@@ -10,6 +10,7 @@
 #include <cursor.h>
 #include <keyboard.h>
 #include <frame.h>
+#include <plumb.h>
 #include "flayer.h"
 #include "samterm.h"
 
@@ -170,20 +171,15 @@ extstart(void)
 	atexit(removeextern);
 }
 
-#if 0
 int
-plumbformat(int i)
+plumbformat(Plumbmsg *m, int i)
 {
-	Plumbmsg *m;
 	char *addr, *data, *act;
 	int n;
 
 	data = (char*)plumbbuf[i].data;
-	m = plumbunpack(data, plumbbuf[i].n);
-	if(m == nil)
-		return 0;
 	n = m->ndata;
-	if(n == 0){
+	if(n == 0 || 2+n+2 >= READBUFSIZE){
 		plumbfree(m);
 		return 0;
 	}
@@ -219,8 +215,9 @@ void
 plumbproc(void *argv)
 {
 	Channel *c;
-	int i, n, which, *fdp;
+	int i, *fdp;
 	void **arg;
+	Plumbmsg *m;
 
 	arg = argv;
 	c = arg[0];
@@ -229,16 +226,14 @@ plumbproc(void *argv)
 	i = 0;
 	threadfdnoblock(*fdp);
 	for(;;){
-		i = 1-i;	/* toggle */
-		n = threadread(*fdp, plumbbuf[i].data, READBUFSIZE);
-		if(n <= 0){
+		m = threadplumbrecv(*fdp);
+		if(m == nil){
 			fprint(2, "samterm: plumb read error: %r\n");
 			threadexits("plumb");	/* not a fatal error */
 		}
-		plumbbuf[i].n = n;
-		if(plumbformat(i)){
-			which = i;
-			send(c, &which);
+		if(plumbformat(m, i)){
+			send(c, &i);
+			i = 1-i;	/* toggle */
 		}
 	}
 }
@@ -258,19 +253,12 @@ plumbstart(void)
 		close(fd);
 		return -1;
 	}
-	arg[0] =plumbc;
+	arg[0] = plumbc;
 	arg[1] = &fd;
 	threadcreate(plumbproc, arg, STACK);
 	return 1;
 }
-#endif
 
-int
-plumbstart(void)
-{
-	return -1;
-}
-
 void
 hostproc(void *arg)
 {
blob - fb6a91449fbfb31e090eb0b1dfd2eda2d6dac777
blob + 1283f430f09ef8b88ea7845511598eeb88f288d4
--- src/libdraw/x11-init.c
+++ src/libdraw/x11-init.c
@@ -124,6 +124,8 @@ xerror(XDisplay *d, XErrorEvent *e)
 {
 	char buf[200];
 
+	if(e->request_code == 42) /* XSetInputFocus */
+		return 0;
 	print("X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
 		e->error_code, e->request_code, e->minor_code, d);
 	XGetErrorText(d, e->error_code, buf, sizeof buf);
blob - ac4aa40c5021c75e2150273603d00b6cf7fac716
blob + e27202f544b48e934cb16249117bc3a2bd90c138
--- src/libdraw/x11-wsys.c
+++ src/libdraw/x11-wsys.c
@@ -8,7 +8,10 @@
 void
 drawtopwindow(void)
 {
-	XRaiseWindow(_x.display, _x.drawable);
+	XMapRaised(_x.display, _x.drawable);
 	XFlush(_x.display);
+	XSetInputFocus(_x.display, _x.drawable, RevertToPointerRoot,
+		CurrentTime);
+	XFlush(_x.display);
 }