/* wmh.c - window front-end to mh */
static char ident
[] = "@(#)$Id: wmh.c,v 1.4 1992/11/04 02:29:30 jromine Exp $";
Pass signals to client during execution
Figure out a way for the user to say how big the Scan/Display
windows should be, and where all the windows should be.
#define sigmask(s) (1 << ((s) - 1))
#define ALARM ((unsigned int) 10)
#define PAUSE ((unsigned int) 2)
#define abs(a) ((a) > 0 ? (a) : -(a))
#define SZ(a) (sizeof a / sizeof a[0])
static struct swit switches
[] = {
static int PEERpid
= NOTOK
;
static char *myprompt
= "(%s) ";
WINDOW
*windows
[NWIN
+ 1];
#define ERASE sg.sg_erase
#define WERASC ltc.t_werasc
static struct ltchars ltc
;
int ALRMser (), PIPEser (), SIGser ();
int ADJser (), REFser ();
extern char *sys_errlist
[];
invo_name
= r1bindex (argv
[0], '/');
if ((cp
= m_find (invo_name
)) != NULL
) {
ap
= brkstring (cp
= getcpy (cp
), " ", "\n");
ap
= copyip (ap
, arguments
);
(void) copyip (argv
+ 1, ap
);
switch (smatch (++cp
, switches
)) {
(void) sprintf (buffer
, "%s [switches for vmhproc]",
if (!(myprompt
= *argp
++) || *myprompt
== '-')
adios (NULLCP
, "missing argument to %s", argp
[-2]);
if (!(vmhproc
= *argp
++) || *vmhproc
== '-')
adios (NULLCP
, "missing argument to %s", argp
[-2]);
if (WINinit (nprog
) == NOTOK
) {
vec
[0] = r1bindex (vmhproc
, '/');
adios (vmhproc
, "unable to exec");
(void) PEERinit (vecp
, vec
);
(void) pLOOP (RC_QRY
, NULLCP
);
(void) sprintf (prompt
, myprompt
, invo_name
);
switch (WINgetstr (Command
, prompt
, buffer
)) {
done (0); /* NOTREACHED */
(void) pLOOP (RC_CMD
, buffer
);
static int PEERinit (vecp
, vec
)
(void) signal (SIGPIPE
, PIPEser
);
if (pipe (pfd0
) == NOTOK
|| pipe (pfd1
) == NOTOK
)
adios ("pipe", "unable to");
switch (PEERpid
= vfork ()) {
adios ("vfork", "unable to");/* NOTREACHED */
for (w
= windows
; *w
; w
++)
if ((*w
) -> w_fd
!= NOTOK
)
(void) close ((*w
) -> w_fd
);
vec
[vecp
++] = "-vmhread";
(void) sprintf (buf1
, "%d", pfd1
[0]);
vec
[vecp
++] = "-vmhwrite";
(void) sprintf (buf2
, "%d", pfd0
[1]);
(void) signal (SIGINT
, SIG_DFL
);
(void) signal (SIGQUIT
, SIG_DFL
);
(void) signal (SIGTERM
, SIG_DFL
);
vec
[0] = r1bindex (vmhproc
, '/');
_exit (-1); /* NOTREACHED */
(void) rcinit (pfd0
[0], pfd1
[1]);
register struct record
*rc
= &rcs
;
(void) sprintf (bp
, "%d %d", RC_VRSN
, numwins
);
for (w
= windows
; *w
; w
++) {
(void) sprintf (bp
, " %d", (*w
) -> w_height
);
switch (str2rc (RC_INI
, buffer
, rc
)) {
adios (NULLCP
, "%s", rc
-> rc_data
);
adios (NULLCP
, "pINI peer error");
adios (NULLCP
, "%s", rc
-> rc_data
);
adios (NULLCP
, "pINI protocol screw-up");
static int pLOOP (code
, str
)
register struct record
*rc
= &rcs
;
(void) str2peer (code
, str
);
if (sscanf (rc
-> rc_data
, "%d", &i
) != 1
(void) fmt2peer (RC_ERR
, "no such window \"%s\"",
if ((w
= windows
[i
- 1]) -> w_flags
& W_CMND
) {
(void) fmt2peer (RC_ERR
, "not a display window \"%s\"",
adorn (NULLCP
, "%s", rc
-> rc_data
);
adorn (NULLCP
, "pLOOP(%s) peer error",
code
== RC_QRY
? "QRY" : "CMD");
adorn (NULLCP
, "%s", rc
-> rc_data
);
i
= pidwait (PEERpid
, OK
);
adios (NULLCP
, "%s", rc
-> rc_data
);
adios (NULLCP
, "pLOOP(%s) protocol screw-up",
code
== RC_QRY
? "QRY" : "CMD");
TYPESIG (*hstat
) (), (*istat
) (), (*qstat
) (), (*tstat
) ();
register struct record
*rc
= &rcs
;
if (ChangeWindowDepth (dfd
, twd
, 0) == NOTOK
)
adios ("failed", "ChangeWindowDepth");
hstat
= signal (SIGHUP
, SIG_IGN
);
istat
= signal (SIGINT
, SIG_IGN
);
qstat
= signal (SIGQUIT
, SIG_IGN
);
tstat
= signal (SIGTERM
, SIG_IGN
);
(void) rc2rc (RC_ACK
, 0, NULLCP
, rc
);
(void) signal (SIGHUP
, hstat
);
(void) signal (SIGINT
, istat
);
(void) signal (SIGQUIT
, qstat
);
(void) signal (SIGTERM
, tstat
);
(void) rc2peer (RC_ACK
, 0, NULLCP
);
adorn (NULLCP
, "%s", rc
-> rc_data
);
adorn (NULLCP
, "pTTY peer error");
adios (NULLCP
, "%s", rc
-> rc_data
);
adios (NULLCP
, "pTTY protocol screw-up");
if ((i
= pWINaux (w
)) == OK
)
register struct line
*lp
,
register struct record
*rc
= &rcs
;
for (lp
= w
-> w_head
; lp
; lp
= mp
) {
w
-> w_head
= w
-> w_top
= w
-> w_bottom
= w
-> w_tail
= NULL
;
switch (rc2rc (RC_ACK
, 0, NULLCP
, rc
)) {
for (bp
= rc
-> rc_data
, n
= rc
-> rc_len
; n
-- > 0; )
(void) WINputc (w
, *bp
++);
(void) rc2peer (RC_ACK
, 0, NULLCP
);
(void) WINputc (w
, '\n');
adorn (NULLCP
, "%s", rc
-> rc_data
);
adorn (NULLCP
, "pWIN peer error");
adios (NULLCP
, "%s", rc
-> rc_data
);
adios (NULLCP
, "pWIN protocol screw-up");
(void) rc2peer (RC_FIN
, 0, NULLCP
);
switch (setjmp (PEERctx
)) {
(void) signal (SIGALRM
, ALRMser
);
status
= pidwait (PEERpid
, OK
);
(void) kill (PEERpid
, SIGKILL
);
/* should dynamically determine all this stuff from gconfig... */
#define MyX 20 /* anchored hpos */
#define MyY 40 /* .. vpos */
#define MyW 800 /* .. width */
#define MyH 500 /* .. height */
#define MyS 30 /* .. height for Status, about one line */
#define MySlop 45 /* slop */
#define EWIDTH 25 /* Width of vertical EBAR */
#define ESLOP 5 /* .. slop */
static int WINinit (nprog
) {
if (GetGraphicsConfig (fileno (stderr
), &gc
) == NOTOK
)
adios (NULLCP
, "not a window");
if ((dfd
= open ("/dev/ttyw0", 2)) == NOTOK
)
adios ("/dev/ttyw0", "unable to open");
if ((twd
= GetTopWindow (dfd
)) == NOTOK
)
adios ("failed", "GetTopWindow");
(void) BlockRefreshAdjust (1);
wx
= gc
.w
- (MyX
+ MyW
+ EWIDTH
+ ESLOP
);
Scan
= WINnew (wx
, wy
= MyY
, MyW
, wh
= MyH
* 2 / 3, "Scan", W_EBAR
);
Status
= WINnew (wx
, sy
= wy
, MyW
, wh
= MyS
, "Status", W_FAKE
);
Display
= WINnew (wx
, wy
, MyW
, MyH
, "Display", W_EBAR
);
Command
= WINnew (wx
, sy
, MyW
, MyS
, invo_name
, W_CMND
);
WINDOW
*WINnew (wx
, wy
, ww
, wh
, name
, flags
)
if ((w
= (WINDOW
*) calloc (1, sizeof *w
)) == NULL
)
adios (NULLCP
, "unable to allocate window");
if ((w
-> w_flags
= flags
) & W_FAKE
) {
if (w
-> w_flags
& W_EBAR
)
if ((w
-> w_fd
= OpenWindow (wx
, wy
, ww
, wh
, name
)) == NOTOK
)
adios ("failed", "OpenWindow");
if ((w
-> w_wd
= GetTopWindow (dfd
)) == NOTOK
)
adios ("failed", "GetTopWindow");
if (GetWindowState (w
-> w_fd
, &w
-> w_ws
) == NOTOK
)
adios ("failed", "GetWindowState");
if (SetLineDisc (w
-> w_fd
, TWSDISC
) == NOTOK
)
adios ("failed", "SetLineDisc");
SetBuf (w
-> w_fd
, 1024);
(void) SetAdjust (w
-> w_fd
, numwins
, ADJser
);
(void) SetRefresh (w
-> w_fd
, numwins
, REFser
);
SetAddressing (w
-> w_fd
, VT_ABSOLUTE
);
if (w
-> w_flags
& W_EBAR
) {
w
-> w_eb
= CreateElevatorBar (w
-> w_fd
, 0, 0, EWIDTH
,
w
-> w_ws
.height
, VT_Gray50
, 1, EB_VERTICAL
,
EB_ARROWS
, w
-> w_ebloc
= 0, w
-> w_ebsize
= EB_MAX
,
adios (NULLCP
, "CreateElevatorBar failed");
RefreshElevatorBar (w
-> w_eb
);
if ((w
-> w_cbase
= CharacterBaseline (w
-> w_ws
.font
)) <= 0)
if ((w
-> w_cheight
= CharacterHeight (w
-> w_ws
.font
)) <= 0)
w
-> w_height
= w
-> w_ws
.height
/ w
-> w_cheight
;
if ((w
-> w_cwidth
= CharacterWidth (w
-> w_ws
.font
, 'm')) <= 0)
w
-> w_width
= (w
-> w_ws
.width
- (w
-> w_eb
? (EWIDTH
+ ESLOP
) : 0))
static int WINgetstr (w
, prompt
, buffer
)
register struct vtseq
*vt
= &vts
;
adios (NULLCP
, "internal error--elevator bar found");
&& (w
-> w_head
= (struct line
*) calloc (1, sizeof *w
-> w_head
))
adios (NULLCP
, "unable to allocate line storage");
w
-> w_head
-> l_buf
= image
;
w
-> w_top
= w
-> w_bottom
= w
-> w_tail
= w
-> w_head
;
if (ChangeWindowDepth (dfd
, w
-> w_wd
, 0) == NOTOK
)
adios ("failed", "ChangeWindowDepth");
(void) strcpy (image
, prompt
);
bp
= ip
= image
+ strlen (image
);
switch (getvtseq (w
-> w_fd
, vt
)) {
DisplayStatus (w
-> w_fd
, "no hardkeys, please");
switch (c
= toascii (vt
-> u
.ascii
)) {
case '\f': /* refresh? */
(void) strcpy (buffer
, ip
);
adorn (NULLCP
, "Interrupt");
} while (isspace (*bp
) && bp
> ip
);
} while (!isspace (*bp
) && bp
> buffer
);
if (c
< ' ' || c
>= '\177')
switch (vt
-> u
.mouse
.buttons
& (VT_MOUSE_LEFT
| VT_MOUSE_MIDDLE
| VT_MOUSE_RIGHT
)) {
DisplayStatus (w
-> w_fd
, "use middle or right button");
#define WPOP "WMH\0Advance\0Burst\0Exit\0EOF\0"
SetPosition (w
-> w_fd
, vt
-> u
.mouse
.x
,
switch (DisplayPopUp (w
-> w_fd
, WPOP
)) {
(void) strcpy (buffer
, "advance");
(void) strcpy (buffer
, "burst");
(void) strcpy (buffer
, "exit");
default: /* failed or none taken */
adios (NULLCP
, "end-of-file on window");/* NOTREACHED */
DisplayStatus (w
-> w_fd
, "unknown VT sequence");
static int WINputc (w
, c
)
register struct line
*lp
;
if (WINputc (w
, 'M') == NOTOK
|| WINputc (w
, '-') == NOTOK
)
if (c
< ' ' || c
== '\177') {
if (WINputc (w
, '^') == NOTOK
)
for (i
= 8 - (w
-> w_bufpos
& 0x07); i
> 0; i
--)
if (WINputc (w
, ' ') == NOTOK
)
w
-> w_buffer
[w
-> w_bufpos
++] = c
;
w
-> w_buffer
[w
-> w_bufpos
] = NULL
;
if ((lp
= (struct line
*) calloc (1, sizeof *lp
)) == NULL
)
adios (NULLCP
, "unable to allocate line storage");
lp
-> l_no
= (w
-> w_tail
? w
-> w_tail
-> l_no
: 0) + 1;
lp
-> l_buf
= getcpy (w
-> w_buffer
);
for (cp
= lp
-> l_buf
+ strlen (lp
-> l_buf
) - 1; cp
>= lp
-> l_buf
; cp
--)
if (w
-> w_bottom
== NULL
)
w
-> w_tail
-> l_next
= lp
;
lp
-> l_prev
= w
-> w_tail
;
static bool cancel
[] = { 1 };
static struct choice mychoices
[] = { LABEL
, "cancel", VT_White
};
static struct question myquestions
[] = {
STRING
, "Line", SZ (mylineno
), (struct choice
*) 0,
TOGGLE
, "", SZ (mychoices
), mychoices
static struct menu mymenu
= { "Goto", SZ (myquestions
), myquestions
};
static int *myanswers
[] = { (int *) mylineno
, (int *) cancel
};
register struct vtseq
*vt
= &vts
;
if (w
-> w_fd
== NOTOK
) {
DisplayStatus (dfd
, w
-> w_top
-> l_buf
);
if (ChangeWindowDepth (dfd
, w
-> w_wd
, 0) == NOTOK
)
adios ("failed", "ChangeWindowDepth");
if (w
-> w_bottom
== w
-> w_tail
)
adios (NULLCP
, "internal error--no elevator bar");
for (clear
= refresh
= 0, forw
= 1;;) {
RemoveStatus (w
-> w_fd
);
switch (getvtseq (w
-> w_fd
, vt
)) {
DisplayStatus (w
-> w_fd
, "use the mouse");
switch (vt
-> u
.mouse
.buttons
& (VT_MOUSE_LEFT
| VT_MOUSE_MIDDLE
| VT_MOUSE_RIGHT
)) {
if ((pos
= vt
-> u
.mouse
.x
) < EWIDTH
) {
pos
= w
-> w_ebloc
= DoElevatorBar (w
-> w_eb
, pos
,
refresh
= WINgoto (w
, ((pos
* (w
-> w_tail
-> l_no
/ EB_MAX
) + w
-> w_head
-> l_no
);
#define WPOP "Paging\0Next\0Prev\0Left\0Right\0First\0Last\0Goto ...\0Exit\0"
SetPosition (w
-> w_fd
, vt
-> u
.mouse
.x
,
switch (DisplayPopUp (w
-> w_fd
, WPOP
)) {
if (w
-> w_bottom
== w
-> w_tail
)
refresh
= WINgoto (w
, w
-> w_bottom
-> l_no
+ 1 - PSLOP
);
if (w
-> w_top
== w
-> w_head
)
refresh
= WINgoto (w
, w
-> w_top
-> l_no
- w
-> w_height
+ PSLOP
);
DisplayStatus (w
-> w_fd
, "not yet");
refresh
= WINgoto (w
, w
-> w_head
-> l_no
);
refresh
= WINgoto (w
, w
-> w_tail
-> l_no
(void) sprintf (mylineno
, "%d",
if (PresentMenu (&mymenu
, myanswers
)
if (sscanf (mylineno
, "%d", &pos
) != 1) {
DisplayStatus (w
-> w_fd
, "bad format");
if (pos
< w
-> w_head
-> l_no
|| pos
> w
-> w_tail
-> l_no
) {
DisplayStatus (w
-> w_fd
, "no such line");
refresh
= WINgoto (w
, pos
);
default: /* failed or none taken */
if (w
-> w_bottom
== w
-> w_tail
)
adios (NULLCP
, "end-of-file on window");/* NOTREACHED */
DisplayStatus (w
-> w_fd
, "unknown VT sequence");
static int WINgoto (w
, n
)
register struct line
*lp
;
if (n
> (i
= w
-> w_tail
-> l_no
- w
-> w_height
+ 1))
if (n
< w
-> w_head
-> l_no
)
if ((i
= n
- (lp
= w
-> w_head
) -> l_no
)
> (j
= abs (n
- w
-> w_top
-> l_no
)))
if (i
> (j
= abs (w
-> w_tail
-> l_no
- n
)))
for (; lp
; lp
= lp
-> l_next
)
for (; lp
; lp
= lp
-> l_prev
)
static int ADJser (id
, ww
, wh
)
if (id
< 0 || id
>= numwins
)
adios (NULLCP
, "ADJser on bogus window (%d)", id
);
adios (NULLCP
, "ADJser on closed window (%d)", id
);
w
-> w_ws
.width
= w
-> w_ws
.tw
= ww
;
w
-> w_ws
.height
= w
-> w_ws
.th
= wh
;
DeleteElevatorBar (w
-> w_eb
);
w
-> w_eb
= CreateElevatorBar (w
-> w_fd
, 0, 0, EWIDTH
,
w
-> w_ws
.height
, VT_Gray50
, 1, EB_VERTICAL
,
EB_ARROWS
, w
-> w_ebloc
= 0, w
-> w_ebsize
= EB_MAX
,
adios (NULLCP
, "CreateElevatorBar failed");
static int REFser (id
, wx
, wy
, ww
, wh
)
if (id
< 0 || id
>= numwins
)
adios (NULLCP
, "REFser on bogus window (%d)", id
);
adios (NULLCP
, "REFser on closed window (%d)", id
);
if (GetWindowState (w
-> w_fd
, &w
-> w_ws
) == NOTOK
)
adios ("failed", "GetWindowState");
GetPermanentClipping (w
-> w_fd
, &cx
, &cy
, &cw
, &ch
);
SetPermanentClipping (w
-> w_fd
, wx
, wy
, ww
, wh
);
SetPermanentClipping (w
-> w_fd
, cx
, cy
, cw
, ch
);
static Redisplay (w
, doeb
)
register struct line
*lp
;
sx
= w
-> w_eb
? (EWIDTH
+ ESLOP
) : 0;
w
-> w_height
= w
-> w_ws
.height
/ w
-> w_cheight
;
w
-> w_width
= (w
-> w_ws
.width
- (w
-> w_eb
? (EWIDTH
+ ESLOP
) : 0))
SetPosition (w
-> w_fd
, sx
, 0);
SetColor (w
-> w_fd
, VT_White
);
PaintRectangleInterior (w
-> w_fd
, w
-> w_ws
.width
, w
-> w_ws
.height
);
SetColor (w
-> w_fd
, VT_Black
);
for (lp
= w
-> w_top
, y
= 0;
w
-> w_bottom
= lp
, lp
= lp
-> l_next
, y
++) {
SetPosition (w
-> w_fd
, sx
, y
* w
-> w_cheight
+ w
-> w_cbase
);
PaintString (w
-> w_fd
, VT_STREND
, lp
-> l_buf
);
if ((y
= EB_LOC (w
)) != w
-> w_ebloc
)
MoveElevator (w
-> w_eb
, w
-> w_ebloc
= y
);
if ((y
= EB_SIZE (w
)) != w
-> w_ebsize
)
SizeElevator (w
-> w_eb
, w
-> w_ebsize
= y
);
RefreshElevatorBar (w
-> w_eb
);
if ((i
= w
-> w_tail
-> l_no
- w
-> w_head
-> l_no
) <= 0)
return (((w
-> w_bottom
-> l_no
- w
-> w_top
-> l_no
) * EB_MAX
) / i
);
if ((i
= w
-> w_tail
-> l_no
- w
-> w_head
-> l_no
) <= 0)
return (((w
-> w_top
-> l_no
- w
-> w_head
-> l_no
) * EB_MAX
) / i
);
if (ioctl (fileno (stdin
), TIOCGETP
, (char *) &sg
) == NOTOK
)
adios ("failed", "ioctl TIOCGETP");
if (ioctl (fileno (stdin
), TIOCGETC
, (char *) &tc
) == NOTOK
)
adios ("failed", "ioctl TIOCGETC");
if (ioctl (fileno (stdin
), TIOCGLTC
, (char *) <c
) == NOTOK
)
adios ("failed", "ioctl TIOCGLTC");
(void) signal (SIGHUP
, SIGser
);
(void) signal (SIGINT
, SIGser
);
(void) signal (SIGQUIT
, SIGser
);
if ((pgrp
= getpgrp (0)) == NOTOK
)
adios ("process group", "unable to determine");
if (ioctl (fileno (stdin
), TIOCGPGRP
, (char *) &tpgrp
) == NOTOK
)
adios ("tty's process group", "unable to determine");
tstat
= signal (SIGTTIN
, SIG_DFL
);
(void) kill (0, SIGTTIN
);
(void) signal (SIGTTIN
, tstat
);
(void) signal (SIGTTIN
, SIG_IGN
);
(void) signal (SIGTTOU
, SIG_IGN
);
(void) signal (SIGTSTP
, SIG_IGN
);
(void) signal (SIGTTIN
, SIG_DFL
);
(void) signal (SIGTTOU
, SIG_DFL
);
(void) signal (SIGTSTP
, SIG_DFL
);
(void) signal (sig
, SIG_IGN
);
adios (NULLCP
, "lost peer");
(void) signal (sig
, SIG_IGN
);
static void adorn (what
, fmt
, a
, b
, c
, d
, e
, f
)
advise (what
, fmt
, a
, b
, c
, d
, e
, f
);
void advertise (what
, tail
, fmt
, a
, b
, c
, d
, e
, f
)
register struct iovec
*iov
= iob
;
iov
-> iov_len
= strlen (iov
-> iov_base
= invo_name
);
iov
-> iov_len
= strlen (iov
-> iov_base
= ": ");
(void) sprintf (buffer
, fmt
, a
, b
, c
, d
, e
, f
);
iov
-> iov_len
= strlen (iov
-> iov_base
= buffer
);
iov
-> iov_len
= strlen (iov
-> iov_base
= " ");
iov
-> iov_len
= strlen (iov
-> iov_base
= what
);
iov
-> iov_len
= strlen (iov
-> iov_base
= ": ");
if (eindex
> 0 && eindex
< sys_nerr
)
iov
-> iov_len
= strlen (iov
-> iov_base
= sys_errlist
[eindex
]);
(void) sprintf (err
, "Error %d", eindex
);
iov
-> iov_len
= strlen (iov
-> iov_base
= err
);
iov
-> iov_len
= strlen (iov
-> iov_base
= ", ");
iov
-> iov_len
= strlen (iov
-> iov_base
= tail
);
iov
-> iov_len
= strlen (iov
-> iov_base
= "\n");
(void) DisplayVector (iob
, iov
- iob
);
(void) writev (fileno (stderr
), iob
, iov
- iob
);
static DisplayVector (iov
, n
)
register struct iovec
*iov
;
for (i
= 0, cp
= NULL
; i
< n
; i
++, iov
++) {
(void) sprintf (buffer
, "%*.*s", iov
-> iov_len
, iov
-> iov_len
,