From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from cegelecproj.co.uk ([159.245.72.6]) by hawkwind.utcs.utoronto.ca with SMTP id <24107>; Fri, 28 Apr 1995 14:02:29 -0400 Received: from vampire.cegelecproj.co.uk (cerberus.cegelecproj.co.uk) by cegelecproj.co.uk (4.1/SMI-4.1) id AA03451; Fri, 28 Apr 95 18:50:19 BST Received: from spirit.cegelecproj.co.uk (spirit.limbo.cegelecproj.co.uk) by vampire.cegelecproj.co.uk (5.0/SMI-SVR4) id AA02331; Fri, 28 Apr 1995 18:50:02 +0000 Received: by spirit.cegelecproj.co.uk (5.0/SMI-SVR4) id AA01956; Fri, 28 Apr 1995 18:49:57 +0000 Date: Fri, 28 Apr 1995 14:49:57 -0400 From: Steve_Kilbane@cegelecproj.co.uk (Steve_Kilbane) Message-Id: <9504281749.AA01956@spirit.cegelecproj.co.uk> X-Planation: X-Faces images can be viewed with the XFaces program To: sam-fans@hawkwind.utcs.toronto.edu Subject: 9wm/9term cmdpipes X-Face: Iqsa(US9p?)Y^W+6Ff[Z]rM"uFE) lFDjag1e]\/#2 A while ago, I mentioned some hacks I'd done to 9term to add a command pipe, like sam's. Rich $alz commented that 9wm could do with something similar, and I couldn't resist. This is the result, including patches for both 9term and 9wm. There are probably bugs, but they work ok for me. :-) A README file is included. Steve PS Rich: I've made some improvements since I sent you the sample patches, so this lot is different. #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./9term.patch` then echo "writing ./9term.patch" cat > ./9term.patch << '\Rogue\Monster\' *** orig/9term/9term.c Fri Jun 3 09:35:39 1994 --- hacked/9term/9term.c Fri Apr 21 08:14:28 1995 *************** *** 16,36 **** #include "9term.h" int flushing; int suspended; Event e; ulong Erc; int highwater = 50000; int lowwater = 40000; int waterquantum; int beepmask; int ninewm; ! static char *items[] = { "cut", "paste", "snarf", "send", "scroll", 0 }; static Menu edit = {items}; enum { mCUT, mPASTE, mSNARF, mSEND, mSCROLL }; --- 16,48 ---- #include "9term.h" + #define PIPEDIRENV "NINETERMPIPE" + #define PIPEDIRDEF "/tmp/.9terms." + int flushing; int suspended; Event e; ulong Erc; + ulong Epipe; + static char *exname; + static int exlen; int highwater = 50000; int lowwater = 40000; int waterquantum; int beepmask; int ninewm; + static long mark0, mark1; + static int markset; ! void removeextern(void); ! static void pipeinput(Event *e); ! ! static char *items[] = { "cut", "paste", "snarf", "mark", "send", "scroll", 0 }; static Menu edit = {items}; enum { mCUT, mPASTE, mSNARF, + mMARK, mSEND, mSCROLL }; *************** *** 167,173 **** --- 179,273 ---- run(); } + /* + * create a named pipe for this 9term to accept commands on. + * This function is mainly copied from samterm... + */ + + static + void init_ninepipe(void) + { + #ifndef NOFIFO + char *ninepipedir; + char *disp; + char *user; + int fd; + int flags; + extern ulong windowid; + + if ((ninepipedir = getenv(PIPEDIRENV)) == 0) { + /* user hasn't specified a directory - make up a name */ + /* exname is PIPEDIR.user.display/wid or PIPEDIR.user/wid */ + user = getuser(); + disp = getenv("DISPLAY"); + + if (disp) { + exlen = strlen(PIPEDIRDEF) + strlen(user) + 1 + strlen(disp); + if ((exname = (char *)malloc(exlen + 20)) == 0) + return; + sprintf(exname, "%s%s.%s", PIPEDIRDEF, user, disp); + } else { + exlen = strlen(PIPEDIRDEF) + strlen(user); + if ((exname = (char *)malloc(exlen + 20)) == 0) + return; + sprintf(exname, "%s%s", PIPEDIRDEF, user); + } + } else { + /* use user's specified directory */ + exlen = strlen(ninepipedir); + if ((exname = (char *)malloc(exlen + 20)) == 0) + return; + strcpy(exname,ninepipedir); + } + + /* Create a directory for the pipes to exist in, if necessary. */ + (void)mkdir(exname,0700); + + /* add the next level - the pid */ + sprintf(exname+exlen,"/%d",windowid); + + /* Make the named pipe */ + if (mkfifo(exname, 0600) == -1) { + removeextern(); + return; + } + + fd = open(exname, O_RDONLY | O_NONBLOCK); + if (fd == -1) { + removeextern(); + return; + } + + /* + * Turn off no-delay and provide ourselves as a lingering + * writer so as not to get end of file on read. + */ + flags = fcntl(fd, F_GETFL, 0); + if (flags == -1 || fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1 + || open(exname, O_WRONLY) == -1) { + (void)close(fd); + removeextern(); + return; + } + + Epipe = estart(0, fd, 8192); + atexit(removeextern); + return; + #endif + } + + void + removeextern(void) + { + if (exname) { + (void)unlink(exname); + exname[exlen] = 0; + (void)rmdir(exname); + } + } + + /* * Register command output stream and handle events */ #define MAXMSG 128 *************** *** 179,184 **** --- 279,285 ---- ulong type; Erc = estart(0, comm_fd, MAXMSG + MAXFDATA); + init_ninepipe(); for (;;) { /* disable shell output when more than one buffer ahead */ /* *************** *** 204,210 **** } #endif shelloutput(Erc, &e); ! } } } --- 305,312 ---- } #endif shelloutput(Erc, &e); ! } else if (type == Epipe) ! pipeinput(&e); } } *************** *** 234,239 **** --- 336,371 ---- } /* + * Handle command pipe event + */ + + static void + pipeinput(Event *e) + { + Rune r; + char *c; + Text *t = text; + + /* XXX - should do something like: + if (e->n) + t->p0 = t->p1 = t->end; + or whatever, to make sure we're inserting at the end. */ + + if (e->n) + t->p0 = t->p1 = t->length; + for (c = (char *)e->data; e->n--; c++) { + chartorune(&r, c); + /* ignore eof or eol */ + if (r == eofchar || r == eolchar) + continue; + textinsert(t, &r, (&r)+1, t->p0); + textshow(t, t->p0, 1); + sendrunes(&r,1); + } + texthighlight(text,t->p0,t->p1, F & ~D); + } + + /* * Handle command output event */ static void *************** *** 398,403 **** --- 530,536 ---- static Rune nl[] = { '\n', 0 }; specialchars(slave_fd); + edit.item[mMARK] = markset?"select":"mark"; edit.item[mSCROLL] = text->scrolling?"noscroll":"scroll"; switch (menuhit(2, m, &edit)) { *************** *** 428,433 **** --- 561,582 ---- inputrune(text, text->snarfed, text->snarflen); if (text->snarfed[text->snarflen-1] != '\n') inputrune(text, nl, 1); + } + break; + case mMARK: /* save point, or select to point */ + if (markset) { + ulong m0, m1; + + m0 = (mark0 < text->p0)? mark0 : text->p0; + m1 = (mark1 > text->p1)? mark1 : text->p1; + markset = 0; + /* if (m0 < text->base || text->end < m0) + textset(text, _backnl(text, m0, 3)); */ + texthighlight(text,m0,m1, F & ~D); + } else { + mark0 = text->p0; + mark1 = text->p1; + markset = 1; } break; case mSCROLL: /* toggle scroll state */ *** orig/9term/display.c Thu Dec 15 14:48:28 1994 --- hacked/9term/display.c Wed Mar 29 12:42:36 1995 *************** *** 52,57 **** --- 52,58 ---- static void delwin(Widget, XEvent*, String*, Cardinal*); Text *text; /* the main and only text buffer */ + ulong windowid; /* too many X options */ static XrmOptionDescRec optable[] = { *************** *** 229,235 **** XSetErrorHandler(abort); #endif /* export window id to environment */ ! sprintf(id, "%d", XtWindow(_toplevel)); setenv("WINDOWID", id, 1); /* register mouse and keyboard events */ --- 230,237 ---- XSetErrorHandler(abort); #endif /* export window id to environment */ ! windowid = XtWindow(_toplevel); ! sprintf(id, "%d", windowid); setenv("WINDOWID", id, 1); /* register mouse and keyboard events */ \Rogue\Monster\ else echo "will not over write ./9term.patch" fi if `test ! -s ./9wm.patch` then echo "writing ./9wm.patch" cat > ./9wm.patch << '\Rogue\Monster\' *** orig/9wm/9wm.c Tue Mar 28 16:37:51 1995 --- hacked/9wm/9wm.c Tue Apr 18 14:45:52 1995 *************** *** 14,20 **** char *version[] = { ! "9wm version 1.1, Copyright (c) 1994 David Hogan", 0, }; Display *dpy; --- 14,22 ---- char *version[] = { ! "9wm version 1.1, Copyright (c) 1994 David Hogan", ! "cmdpipe extensions by Steve Kilbane", ! 0, }; Display *dpy; *************** *** 51,57 **** --- 53,61 ---- Atom _9wm_hold_mode; void usage(), sighandler(), getevent(); + static int do_select(); + char *fontlist[] = { "lucm.latin1.9", "blit", *************** *** 221,226 **** --- 225,232 ---- nofocus(); scanwins(); + init_ninepipe(); /* smk */ + for (;;) { getevent(&ev); *************** *** 443,448 **** --- 449,455 ---- e->value_mask |= CWBorderWidth; XConfigureWindow(dpy, e->window, e->value_mask, &wc); + wins_changed |= wm_configurereq; } void *************** *** 479,484 **** --- 486,492 ---- unhidec(c, 1); break; } + wins_changed |= wm_mapreq; } void *************** *** 506,511 **** --- 514,520 ---- } c->reparenting = 0; } + wins_changed |= wm_unmap; } void *************** *** 532,537 **** --- 541,547 ---- c->dy = e->height; c->border = e->border_width; } + wins_changed |= wm_newwindow; } void *************** *** 551,556 **** --- 561,567 ---- ignore_badwindow = 1; XSync(dpy, False); ignore_badwindow = 0; + wins_changed |= wm_destroy; } void *************** *** 657,662 **** --- 668,674 ---- if (c == current) cmapfocus(c); } + wins_changed |= wm_property; } void *************** *** 684,689 **** --- 696,702 ---- if (c != 0 && (c->parent == root || withdrawn(c))) rmclient(c); } + wins_changed |= wm_reparent; } #ifdef SHAPE *************** *** 698,703 **** --- 711,717 ---- return; setshape(c); + wins_changed |= wm_shape; } #endif *************** *** 728,755 **** XEvent *e; { int fd; - fd_set rfds; - struct timeval t; if (!signalled) { ! if (QLength(dpy) > 0) { ! XNextEvent(dpy, e); return; } fd = ConnectionNumber(dpy); ! FD_ZERO(&rfds); ! FD_SET(fd, &rfds); ! t.tv_sec = t.tv_usec = 0; ! if (select(fd+1, &rfds, NULL, NULL, &t) == 1) { ! XNextEvent(dpy, e); return; - } XFlush(dpy); ! FD_SET(fd, &rfds); ! if (select(fd+1, &rfds, NULL, NULL, NULL) == 1) { ! XNextEvent(dpy, e); return; - } if (errno != EINTR || !signalled) { perror("9wm: select failed"); exit(1); --- 742,761 ---- XEvent *e; { int fd; if (!signalled) { ! if (QLength(dpy) > 0) { /* if there are X events, handle them */ ! XNextEvent(dpy, e); /* may mean pipe never gets a look in */ return; } + if (wins_changed) + update_windows_list(); fd = ConnectionNumber(dpy); ! if (do_select(fd,e,0)) return; XFlush(dpy); ! if (do_select(fd,e,1)) return; if (errno != EINTR || !signalled) { perror("9wm: select failed"); exit(1); *************** *** 758,761 **** --- 764,801 ---- cleanup(); fprintf(stderr, "9wm: exiting on signal\n"); exit(1); + } + + static int + do_select(fd, e, i) + int fd; + XEvent *e; + int i; + { + int nfds, r; + fd_set rfds; + struct timeval t; + + for (;;) { /* stay here until we get an X event */ + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + if (ninepipefd != -1) { + FD_SET(ninepipefd, &rfds); + nfds = ninepipefd > fd? ninepipefd : fd; + } else { + nfds = fd; + } + t.tv_sec = t.tv_usec = 0; + if ((r = select(nfds+1, &rfds, NULL, NULL, i? NULL : &t)) < 1) { + return 0; + } + if (ninepipefd != -1 && FD_ISSET(ninepipefd,&rfds)) { + pipecmd(); + continue; + } + if (FD_ISSET(fd,&rfds)) { + XNextEvent(dpy, e); + return 1; + } + } } *** orig/9wm/client.c Tue Mar 28 16:37:53 1995 --- hacked/9wm/client.c Tue Apr 18 14:45:52 1995 *************** *** 68,73 **** --- 68,74 ---- } #endif + void active(c) Client *c; *************** *** 94,99 **** --- 95,101 ---- if (debug) dump_revert(); #endif + wins_changed |= wm_active; } void *************** *** 123,128 **** --- 125,131 ---- } XSetInputFocus(dpy, w, RevertToPointerRoot, timestamp()); cmapfocus(0); + wins_changed |= wm_nofocus; } Client * *** orig/9wm/dat.h Tue Mar 28 16:37:55 1995 --- hacked/9wm/dat.h Tue Apr 18 15:00:54 1995 *************** *** 115,117 **** --- 115,137 ---- /* error.c */ extern int ignore_badwindow; + + /* pipe.c - smk */ + extern int ninepipefd; + extern int wins_changed; + + #define wm_configurereq 0x1 + #define wm_mapreq 0x2 + #define wm_unmap 0x4 + #define wm_newwindow 0x8 + #define wm_destroy 0x10 + #define wm_property 0x20 + #define wm_reparent 0x40 + #define wm_shape 0x80 + #define wm_active 0x100 + #define wm_nofocus 0x200 + #define wm_hide 0x400 + #define wm_unhide 0x800 + #define wm_renamec 0x1000 + #define wm_creshape 0x2000 + #define wm_cmove 0x4000 *** orig/9wm/fns.h Tue Mar 28 16:37:55 1995 --- hacked/9wm/fns.h Tue Apr 18 14:15:42 1995 *************** *** 73,75 **** --- 73,81 ---- /* cursor.c */ void initcurs(); + + /* pipe.c - smk */ + void pipecmd(); + void init_ninepipe(); + void remove9pipe(); + void update_windows_list(); *** orig/9wm/manage.c Tue Mar 28 16:37:52 1995 --- hacked/9wm/manage.c Tue Apr 18 13:59:40 1995 *************** *** 88,94 **** /* Now do it!!! */ ! if (doreshape) { cmapfocus(0); if (!(fixsize ? drag(c) : sweep(c)) && c->is9term) { XDestroyWindow(dpy, c->window); --- 88,94 ---- /* Now do it!!! */ ! if (doreshape && (! dohide || ! fixsize)) { cmapfocus(0); if (!(fixsize ? drag(c) : sweep(c)) && c->is9term) { XDestroyWindow(dpy, c->window); *** orig/9wm/menu.c Tue Mar 28 16:37:52 1995 --- hacked/9wm/menu.c Tue Apr 18 15:10:18 1995 *************** *** 108,114 **** fprintf(stderr, "9wm: exec %s", shell); perror(" failed"); } ! execlp("9term", "9term", "-9wm", 0); execlp("xterm", "xterm", "-ut", 0); perror("9wm: exec 9term/xterm failed"); exit(1); --- 108,114 ---- fprintf(stderr, "9wm: exec %s", shell); perror(" failed"); } ! execlp("9term", "9term", "-unix", "-9wm", 0); execlp("xterm", "xterm", "-ut", 0); perror("9wm: exec 9term/xterm failed"); exit(1); *************** *** 186,191 **** --- 186,192 ---- b3items[B3FIXED+numhidden] = c->label; numhidden++; b3items[B3FIXED+numhidden] = 0; + wins_changed |= wm_hide; } void *************** *** 220,225 **** --- 221,227 ---- b3items[B3FIXED+i] = b3items[B3FIXED+i+1]; } b3items[B3FIXED+numhidden] = 0; + wins_changed |= wm_unhide; } void *************** *** 248,253 **** --- 250,256 ---- if (name == 0) name = "???"; c->label = name; + wins_changed |= wm_renamec; if (!hidden(c)) return; for (i = 0; i < numhidden; i++) \Rogue\Monster\ else echo "will not over write ./9wm.patch" fi if `test ! -s ./README` then echo "writing ./README" cat > ./README << '\Rogue\Monster\' This sharfile contains four files: README (this file) 9term.patch (cmdpipe support for 9term) 9wm.patch (first part of cmdpipe support for 9wm) pipe.c (second part) The 9term patch is against 1.6.3, while the 9wm patch is against 1.1. I've used these changes on Solaris 2.3 for quite a while now, and they seem stable as far as daily use goes. Mind you, they don't *much* use daily... incidentally, there's a bug in 9term 1.6.3 under solaris 2.3 - occasionally the cursor starts up in the wrong place (between two shell prompts), and input results in complaints about null characters. This is in the standard 9term release, and I haven't been able to track it down. 9term changes ============= Each 9term creates a pipe which can be used for input, in the manner of sam's pipe. The name of the pipe is given by $NINETERMPIPE, if set. If not, the pipes go into the directory /tmp/.9terms.$USER.$DISPLAY, if $DISPLAY is set, or /tmp/.9terms.$USER, if not. Within the directory, the pipe's name is $WINDOWID. The directory is created if required, and when 9term exits, the pipe is removed, and so is the directory, if empty. Text written to the pipe is inserted to 9term's window as though it had been typed by the user - it is sent to the shell, too. The cursor is moved to the end of the window first, if necessary. This patch also includes the mark/select toggle on the second menu: mark saves the current selection, and select selects all text between the saved and current selections, inclusive. Caveat: I don't bother to set $NINETERMPIPE, using the default pipe name. Therefore, I haven't actually got around to testing this bit of code. :-) Bug: Text set to the pipe is always sent straight to the shell, too. This means that if you've, say, typed "echo hello " so far, and you squirt "world\n" into the pipe, you'll get "world: no such file or directory", and then when you press return, you get "hello world" appear. This doesn't bother me too much, since I normally only send text to the pipe while I'm between commands anyway. 9wm changes =========== 9wm creates a file which contains the current state of the windows 9wm knows about. The name of the file is $NINEWINDOWS, or /tmp/.9wm-windows by default. Each line of the file contains wid s x y dx dy l where: wid is $WINDOWID s is the state of the window (n = normal, h = hidden) x y are the coords of the window's position dx dy are the window's dimensions l is the window's label The windows' details are added in the same order as the current window stack. Thus, the current window will always be the first line in the file, and so on. If a window's never been current, it'll be one of the last lines in the file. This file is updated whenever the details in it have changed. I've tried to catch all the cases, and have probably been a little eager - it can get updated an awful lot when some X events are going on, even though there's no visible change on the screen. However, 9wm is still a lot faster than olwm... 9wm also creates a pipe, name from $NINEPIPE, or /tmp/.9wm-pipe by default. This pipe is used for sending commands to 9wm itself. Commands are: none Just used for testing. reshape wid x y dx dy change position and size of window wid resize wid dx dy change size of window wid move wid x d change position of window wid front wid move window wid to the front, and make current hide wid hides window wid delete wid deletes window wid label wid str sets label of window wid to str This all seems to work on my system. I haven't tested the label command *too* much, and I suspect that there may be problems in the interaction between X's memory allocations and mine. I haven't seen any evidence of this, it's just that I've probably got it wrong somewhere. :-) Caveats: Again, I use the default names, so I haven't tested the $NINEWINDOWS/$NINEPIPE code. The update code for the windows file is a little eager. Label memory handling could be dodgy. What's the point? ================= I've used these changes, along with 9menu, for adding a few interesting things. Menu options for doing "front" and "back" commands are trivial, and since I use the es shell, other 9menus can repeat the last command or list my recent command history for occasional selection. The most extreme application is 9vwm, a virtual window manager for 9wm written in es. It mostly works, but since I don't have much of a tendency to have many windows anyway, there's no inclination to finish it off. But it was fun. Future directions ================= Sooner or later David Hogan's going to release 9wm 1.2, which has got some fairly extensive changes in it, so I'll have to upgrade to that. :-( I'm considering adding kill/unkill commands to 9wm, so that 9wm can be told of a list of daemons that are interested in being told when the windows file has changed (via a kill()). This might make it easier to write programs that follow manual changes to the window structure. It might be nice to have the windows file contain the arguments to the window, too. That way saving workspaces would be a doddle. It's probably a good idea for 9wm to have both "exit" and "exit!", or something similar - the latter is the current behaviour, while the former just complains to stderr if there are any windows currently hidden. It would probably have to ignore 9menu, though.... Steve Kilbane \Rogue\Monster\ else echo "will not over write ./README" fi if `test ! -s ./pipe.c` then echo "writing ./pipe.c" cat > ./pipe.c << '\Rogue\Monster\' /* Copyright (c) 1995 Steve Kilbane. See README for details */ #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" #include #include #define NINEWINDOWSDEF "/tmp/.9wm-windows" #define NINEWINDOWSENV "NINEWINDOWS" #define PCMDMAX 80 #define PIPENAMEENV "NINEPIPE" #define PIPENAMEDEF "/tmp/.9wm-pipe" typedef enum { pNone, pReshape, pResize, pMove, pHide, pFront, pDelete, pLabel, pError } PipeCmd; #define XY 1 #define DXY 2 #define STR 4 static struct cmdinfo { PipeCmd cmd; char *name; char *fmt; int nconvs; unsigned short flags; } names[] = { { pNone, "none", "", 0, 0 }, { pReshape, "reshape", "%lu%d%d%d%d", 5, (XY|DXY) }, { pResize, "resize", "%lu%d%d", 3, DXY }, { pMove, "move", "%lu%d%d", 3, XY }, { pFront, "front", "%lu", 1, 0 }, { pHide, "hide", "%lu", 1, 0 }, { pDelete, "delete", "%lu", 1, 0 }, { pLabel, "label", "%lu%*[ \t]%n", 1, STR }, { pNone, 0, 0, 0, 0 } }; static struct LabelStr { char *s; struct LabelStr *n; int f; } *labelstrs = NULL; static Client *findc(); static Client *setsize(); static PipeCmd parsepipecmd(); static PipeCmd parse(); static Client *freelabelstr(); static char *getlabelstr(); static void creshape(); static void cmove(); static char *pipename; static pid_t serverpid; int ninepipefd = -1; int wins_changed = 0; static struct { int i; char *s; } reasons[] = { { wm_configurereq, "configurereq" }, { wm_mapreq, "mapreq" }, { wm_unmap, "unmap" }, { wm_newwindow, "newwindow" }, { wm_destroy, "destroy" }, { wm_property, "property" }, { wm_reparent, "reparent" }, { wm_shape, "shape" }, { wm_active, "active" }, { wm_nofocus, "nofocus" }, { wm_hide, "hide" }, { wm_unhide, "unhide" }, { wm_renamec, "renamec" }, { wm_cmove, "cmove" }, { wm_creshape, "creshape" }, { 0, 0 } }; static void print_reason() { int x; fprintf(stderr,"9wm: reason"); for (x = 0; reasons[x].s ; x++) if (wins_changed & reasons[x].i) fprintf(stderr," %s",reasons[x].s); fprintf(stderr,"\n"); } static int write_window_line(c,fd) Client *c; int fd; { static char *buffer; static int maxlen; int len; char state; if (c->label == 0) return 0; len = 45 + strlen(c->label); if (len >= maxlen) { maxlen = len + 1; buffer = buffer? realloc(buffer,maxlen) : malloc(maxlen); if (buffer == 0) { maxlen = 0; return 1; } } state = hidden(c)? 'h' : 'n'; /* ignore withdrawn */ sprintf(buffer,"%lu %c %d %d %d %d %s\n",c->window,state,c->x,c->y,c->dx,c->dy,c->label); (void)write(fd,buffer,strlen(buffer)); return 0; } void update_windows_list(void) { static char *ninewindows, *ninewindowstmp; Client *c, *cc; int fd; /* print_reason(); */ wins_changed = 0; if (ninewindowstmp == 0) { if ((ninewindows = getenv(NINEWINDOWSENV)) == 0) ninewindows = NINEWINDOWSDEF; if ((ninewindowstmp = malloc(strlen(ninewindows)+5)) == 0) { fprintf(stderr,"9wm: cannot alloc tmpfile name for %s\n",ninewindows); return; } sprintf(ninewindowstmp,"%s.tmp",ninewindows); } if ((fd = creat(ninewindowstmp, 0744)) < 0) { fprintf(stderr,"9wm: cannot create '%s'\n",ninewindowstmp); return; } /* write clients that have been selected first, in active order */ for (c = current; c; c = c->revert) if (write_window_line(c,fd)) { close(fd); (void)unlink(ninewindowstmp); return; } /* now do those that have never been selected, in any order */ for (c = clients; c; c = c->next) { for (cc = current; cc; cc = cc->revert) if (cc == c) break; if (cc == 0) if (write_window_line(c,fd)) { close(fd); (void)unlink(ninewindowstmp); return; } } close(fd); (void)rename(ninewindowstmp,ninewindows); return; } void pipecmd() { static char data[PCMDMAX]; int x, y, dx, dy; int len; Window winid; char *text; Client *c; char *ptr; if ((len = read(ninepipefd,data,PCMDMAX)) < 1) return; ptr = data; for (;;) { switch (parsepipecmd(&ptr,&len,&winid,&x,&y,&dx,&dy,&text)) { case pNone: return; case pReshape: creshape(setsize(findc(winid),x,y,dx,dy,1,1)); break; case pResize: creshape(setsize(findc(winid),0,0,x,y,1,0)); break; case pMove: cmove(setsize(findc(winid),x,y,0,0,0,1)); break; case pHide: hide(findc(winid)); break; case pFront: c = findc(winid); if (c == 0) break; if (hidden(c)) unhidec(c,1); else { XMapRaised(dpy, c->parent); active(c); } break; case pDelete: delete(findc(winid),1); break; case pLabel: c = findc(winid); if (c == 0) break; renamec(freelabelstr(c),getlabelstr(text)); break; default: fprintf(stderr,"9wm: unparsed command: %s\n",text); return; } XFlush(dpy); } } static Client * findc(w) Window w; { Client *c; for (c = clients; c; c = c->next) if (c->window == w) return c; fprintf(stderr,"9wm: invalid window id %lu\n",w); return 0; } static Client * setsize(c,x,y,dx,dy,resizing,moving) Client *c; int x, y, dx, dy, resizing, moving; { if (c == 0) return 0; if (resizing) { if (dx < 0) dx = -dx; if (dy < 0) dy = -dy; /* following nicked from grab.c:sweepcalc() */ dx -= 2*BORDER; dy -= 2*BORDER; if (!c->is9term) { if (dx < c->min_dx) dx = c->min_dx; if (dy < c->min_dy) dy = c->min_dy; } if (dx < 4) dx = 4; if (dy < 4) dy = 4; if (c->size.flags & PResizeInc) { dx = c->min_dx + (dx-c->min_dx)/c->size.width_inc*c->size.width_inc; dy = c->min_dy + (dy-c->min_dy)/c->size.height_inc*c->size.height_inc; } if (c->size.flags & PMaxSize) { if (dx > c->size.max_width) dx = c->size.max_width; if (dy > c->size.max_height) dy = c->size.max_height; } /* end of nicked code */ c->dx = dx + 2*BORDER; c->dy = dy + 2*BORDER; } if (moving) { if (x < 0) x = 0; if (y < 0) y = 0; c->x = x; c->y = y; } return c; } /* * this function's fun. the event is pretty much going to be a character * at a time, but we don't know this. Therefore, we're called each time * with the new additions to the buffer, and we read until we get a * newline. At this point, we check the line length is ok, and then * start parsing. If we haven't got a newline yet, we return pNone once * we've saved the characters. If we find an error, we set *text to point * to the buffer, so that we can display it in the error message. */ static PipeCmd parsepipecmd(data, n, w, x, y, dx, dy, text) char **data; int *n; Window *w; int *x, *y, *dx, *dy; char **text; { static char buff[PCMDMAX]; static int len; char c; if (*n == 0) return pNone; *text = buff; while ((*n)--) { c = *(*data)++; if (c == '\n' || c == '\r') { if (len < PCMDMAX) { buff[len] = 0; len = 0; return parse(buff,w,x,y,dx,dy,text); } else { len = 0; return pError; } } buff[len++] = c; } return pNone; } static PipeCmd parse(buff, w, x, y, dx, dy, text) char *buff; Window *w; int *x, *y, *dx, *dy; char **text; { struct cmdinfo *p; char *str; unsigned int len; int r; for (p = names; p->name; p++) { len = strlen(p->name); if (strncmp(buff,p->name,len) == 0 && isspace(buff[len])) { break; } else { } } if (p->name == 0) { return pError; } str = buff + len + 1; if (p->flags & STR) r = sscanf(str,p->fmt,w,&len); else r = sscanf(str,p->fmt,w,x,y,dx,dy); if (r < p->nconvs) return pError; if (p->flags & STR) *text = str + len; return p->cmd; } /* * following is largely nicked from my hacks to 9term.c, which * in turn were swiped from samterm. */ void init_ninepipe() { #ifndef NOFIFO int fd; int flags; extern char *getenv(); serverpid = getpid(); if ((pipename = getenv(PIPENAMEENV)) == 0) pipename = PIPENAMEDEF; if (mkfifo(pipename, 0600) == -1) return; if ((fd = open(pipename, O_RDONLY | O_NONBLOCK)) < 0) { remove9pipe(); return; } flags = fcntl(fd, F_GETFL, 0); if (flags == -1 || fcntl(fd,F_SETFL, flags & ~O_NONBLOCK) == -1 || open(pipename, O_WRONLY) == -1) { (void)close(fd); remove9pipe(); return; } ninepipefd = fd; atexit(remove9pipe); return; #endif } void remove9pipe() { if (pipename && serverpid == getpid()) { (void)unlink(pipename); pipename = 0; } return; } static char * getlabelstr(s) char *s; { struct LabelStr *l; if (s == 0) return s; if ((l = (struct LabelStr *)malloc(sizeof(*l))) == 0) return s; l->n = labelstrs; labelstrs = l; if ((l->s = strdup(s)) == 0) l->s = s; l->f = (l->s == s); return l->s; } static Client * freelabelstr(c) Client *c; { char *s = c->label; struct LabelStr *l, **p = &labelstrs; while (*p && (*p)->s != s) p = &((*p)->n); if (*p) { l = *p; *p = l->n; if (l->f) (void)free(l->s); (void)free(l); } return c; } static void cmove(c) Client *c; { if (c == 0) return; active(c); XRaiseWindow(dpy, c->parent); XMoveWindow(dpy, c->parent, c->x-BORDER, c->y-BORDER); sendconfig(c); wins_changed |= wm_cmove; } static void creshape(c) Client *c; { if (c == 0) return; active(c); XRaiseWindow(dpy, c->parent); XMoveResizeWindow(dpy, c->parent, c->x-BORDER, c->y-BORDER, c->dx+2*(BORDER-1), c->dy+2*(BORDER-1)); XMoveResizeWindow(dpy, c->window, BORDER-1, BORDER-1, c->dx, c->dy); wins_changed |= wm_creshape; } \Rogue\Monster\ else echo "will not over write ./pipe.c" fi echo "Finished archive 1 of 1" exit