Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v09i058: Terminal emulator for X window system, Part05/07

4 views
Skip to first unread message

sources...@mirror.tmc.com

unread,
Apr 21, 1987, 2:20:26 PM4/21/87
to
Submitted by: edmoy%opal.Ber...@berkeley.edu
Mod.sources: Volume 9, Issue 58
Archive-name: xterm6.6b/Part05

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# main.c menu.c
if test -f main.c
then
echo shar: will not overwrite existing file "'main.c'"
else
echo 'x - main.c'
cat << \RAZZLE!DAZZLE > main.c
/*
* $Source: /u1/X/xterm/RCS/main.c,v $
* $Header: main.c,v 10.101 86/12/01 16:58:10 swick Rel $
*/

#include <X/mit-copyright.h>

/* Copyright Massachusetts Institute of Technology 1984, 1985 */

/* main.c */

#ifndef lint
static char sccs_id[] = "@(#)main.c\tX10/6.6B\t12/28/86";
#endif lint

#include <pwd.h>
#include <sgtty.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <sys/file.h>
#include <errno.h>
#include <signal.h>
#include <strings.h>
#include <setjmp.h>
#include <utmp.h>
#include <sys/param.h> /* for NOFILE */
#include <X/Xlib.h>
#include "scrollbar.h"
#include "ptyx.h"
#include "data.h"
#include "error.h"
#include "main.h"

int switchfb[] = {0, 2, 1, 3};

static int reapchild ();

static char *brdr_color;
static char **command_to_exec;
#ifdef TIOCCONS
static int Console;
#endif TIOCCONS
static struct sgttyb d_sg = {
0, 0, 0177, CKILL, EVENP|ODDP|ECHO|XTABS|CRMOD
};
static struct tchars d_tc = {
CINTR, CQUIT, CSTART,
CSTOP, CEOF, CBRK,
};
static struct ltchars d_ltc = {
CSUSP, CDSUSP, CRPRNT,
CFLUSH, CWERASE, CLNEXT
};
static int d_disipline = NTTYDISC;
static int d_lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
static char def_bold_font[] = DEFBOLDFONT;
static char def_font[] = DEFFONT;
static char def_title_font[] = DEFTITLEFONT;
static char def_icon_font[] = DEFICONFONT;
static char display[256];
static char etc_utmp[] = "/etc/utmp";
static char *get_ty;
static char *iconbitmap;
static int inhibit;
static int log_on;
static int login_shell;
static char passedPty[2]; /* name if pty if slave */
static int loginpty;
static char *tekiconbitmap;
static int tslot;
static char *xdef[] = {
"ActiveIcon", /* DEF_ACTIVEICON */
"AllowIconInput", /* DEF_ALLOWICONINPUT */
"AutoRaise", /* DEF_AUTORAISE */
"Background", /* DEF_BACKGROUND */
"BodyFont", /* DEF_BODYFONT */
"BoldFont", /* DEF_BOLDFONT */
"Border", /* DEF_BORDER */
"BorderWidth", /* DEF_BORDERWIDTH */
"C132", /* DEF_C132 */
"Curses", /* DEF_CURSES */
"Cursor", /* DEF_CURSOR */
"DeiconifyWarp", /* DEF_DEICONWARP */
"Foreground", /* DEF_FOREGROUND */
"IconBitmap", /* DEF_ICONBITMAP */
"IconFont", /* DEF_ICONFONT */
"IconStartup", /* DEF_ICONSTARTUP */
"InternalBorder", /* DEF_INTERNALBORDER */
"JumpScroll", /* DEF_JUMPSCROLL */
#ifdef KEYBD
"KeyBoard", /* DEF_KEYBOARD */
#endif KEYBD
"LogFile", /* DEF_LOGFILE */
"Logging", /* DEF_LOGGING */
"LogInhibit", /* DEF_LOGINHIBIT */
"LoginShell", /* DEF_LOGINSHELL */
"MarginBell", /* DEF_MARGINBELL */
"Mouse", /* DEF_MOUSE */
"NMarginBell", /* DEF_NMARGINBELL */
"PageOverlap", /* DEF_PAGEOVERLAP */
"PageScroll", /* DEF_PAGESCROLL */
"ReverseVideo", /* DEF_REVERSEVIDEO */
"ReverseWrap", /* DEF_REVERSEWRAP */
"SaveLines", /* DEF_SAVELINES */
"ScrollBar", /* DEF_SCROLLBAR */
"ScrollInput", /* DEF_SCROLLINPUT */
"ScrollKey", /* DEF_SCROLLKEY */
"SignalInhibit", /* DEF_SIGNALINHIBIT */
"StatusLine", /* DEF_STATUSLINE */
"StatusNormal", /* DEF_STATUSNORMAL */
"TekIconBitmap", /* DEF_TEKICONBITMAP */
"TekInhibit", /* DEF_TEKINHIBIT */
"TextUnderIcon", /* DEF_TEXTUNDERICON */
"TitleBar", /* DEF_TITLEBAR */
"TitleFont", /* DEF_TITLEFONT */
"VisualBell", /* DEF_VISUALBELL */
0,
};
#ifdef UTMP
static int added_utmp_entry;
#endif UTMP

main (argc, argv)
int argc;
char **argv;
{
register Screen *screen = &term.screen;
register char *strind;
register int i, pty;
register char **cp;
short fnflag = 0; /* True iff -fn option used */
short fbflag = 0; /* True iff -fb option used */
int Xsocket, mode;
extern onalarm();
char *malloc();
char *basename();
int xerror(), xioerror();
#ifdef KEYBD
extern char *keyboardtype; /* used in XKeyBind.c */
char *getenv();
#endif KEYBD

xterm_name = (strcmp(*argv, "-") == 0) ? "xterm" : basename(*argv);

term.flags = WRAPAROUND | SMOOTHSCROLL | AUTOREPEAT;
screen->border = DEFBORDER;
screen->borderwidth = DEFBORDERWIDTH;
screen->reversestatus = TRUE;
screen->mappedVwin = &screen->fullVwin;
screen->mappedTwin = &screen->fullTwin;
f_b = def_bold_font;
f_n = def_font;
f_t = def_title_font;
f_i = def_icon_font;

display[0] = '\0';
#ifdef KEYBD
if((strind = getenv("KEYBD")) && *strind) {
if((keyboardtype = malloc(strlen(strind) + 1)) == NULL)
SysError(ERROR_KMALLOC);
strcpy(keyboardtype, strind);
}
#endif KEYBD

/*
* go get options out of default file
*/
for(i = 0, cp = xdef ; *cp ; i++, cp++) {
if(!(strind = XGetDefault(xterm_name, *cp)))
continue;
switch(i) {
case DEF_ACTIVEICON:
if (strcmp (strind, "on") == 0)
screen->active_icon = TRUE;
continue;
case DEF_ALLOWICONINPUT:
if (strcmp (strind, "on") == 0)
term.flags |= ICONINPUT;
continue;
case DEF_AUTORAISE:
if (strcmp (strind, "on") == 0)
screen->autoraise = TRUE;
continue;
case DEF_BACKGROUND:
back_color = strind;
continue;
case DEF_BODYFONT:
f_n = strind;
fnflag = TRUE;
continue;
case DEF_BOLDFONT:
f_b = strind;
fbflag = TRUE;
continue;
case DEF_BORDER:
brdr_color = strind;
continue;
case DEF_BORDERWIDTH:
screen->borderwidth = atoi (strind);
continue;
case DEF_C132:
if (strcmp (strind, "on") == 0)
screen->c132 = TRUE;
continue;
case DEF_CURSES:
if (strcmp (strind, "on") == 0)
screen->curses = TRUE;
continue;
case DEF_CURSOR:
curs_color = strind;
continue;
case DEF_DEICONWARP:
if (strcmp (strind, "on") == 0)
screen->deiconwarp = TRUE;
continue;
case DEF_FOREGROUND:
fore_color = strind;
continue;
case DEF_ICONBITMAP:
iconbitmap = strind;
continue;
case DEF_ICONFONT:
f_i = strind;
continue;
case DEF_ICONSTARTUP:
if (strcmp (strind, "on") == 0)
screen->icon_show = -1;
continue;
case DEF_INTERNALBORDER:
screen->border = atoi (strind);
continue;
case DEF_JUMPSCROLL:
if (strcmp (strind, "on") == 0) {
screen->jumpscroll = TRUE;
term.flags &= ~SMOOTHSCROLL;
}
continue;
#ifdef KEYBD
case DEF_KEYBOARD:
if(keyboardtype)
free(keyboardtype);
keyboardtype = strind;
continue;
#endif KEYBD
case DEF_LOGFILE:
if(screen->logfile = malloc(strlen(strind) + 1))
strcpy(screen->logfile, strind);
continue;
case DEF_LOGGING:
if (strcmp (strind, "on") == 0)
log_on = TRUE;
continue;
case DEF_LOGINHIBIT:
if (strcmp (strind, "on") == 0)
inhibit |= I_LOG;
continue;
case DEF_LOGINSHELL:
if (strcmp (strind, "on") == 0)
login_shell = TRUE;
continue;
case DEF_MARGINBELL:
if (strcmp (strind, "on") == 0)
screen->marginbell = TRUE;
continue;
case DEF_MOUSE:
mous_color = strind;
continue;
case DEF_NMARGINBELL:
n_marginbell = atoi (strind);
continue;
case DEF_PAGEOVERLAP:
if((screen->pageoverlap = atoi (strind) - 1) < 0)
screen->pageoverlap = -1;
continue;
case DEF_PAGESCROLL:
if (strcmp (strind, "on") == 0)
screen->pagemode = TRUE;
continue;
case DEF_REVERSEVIDEO:
if (strcmp (strind, "on") == 0)
re_verse = TRUE;
continue;
case DEF_REVERSEWRAP:
if (strcmp (strind, "on") == 0)
term.flags |= REVERSEWRAP;
continue;
case DEF_SAVELINES:
save_lines = atoi (strind);
continue;
case DEF_SCROLLBAR:
if (strcmp (strind, "on") == 0)
screen->scrollbar = SCROLLBARWIDTH;
continue;
case DEF_SCROLLINPUT:
if (strcmp (strind, "on") == 0)
screen->scrollinput = TRUE;
continue;
case DEF_SCROLLKEY:
if (strcmp (strind, "on") == 0)
screen->scrollkey = TRUE;
continue;
case DEF_SIGNALINHIBIT:
if (strcmp (strind, "on") == 0)
inhibit |= I_SIGNAL;
continue;
case DEF_STATUSLINE:
if (strcmp (strind, "on") == 0)
screen->statusline = TRUE;
continue;
case DEF_STATUSNORMAL:
screen->reversestatus = (strcmp (strind, "on") != 0);
continue;
case DEF_TEKICONBITMAP:
tekiconbitmap = strind;
continue;
case DEF_TEKINHIBIT:
if (strcmp (strind, "on") == 0)
inhibit |= I_TEK;
continue;
case DEF_TEXTUNDERICON:
if (strcmp (strind, "on") == 0)
screen->textundericon = TRUE;
continue;
case DEF_TITLEBAR:
if (strcmp (strind, "on") == 0)
screen->fullVwin.titlebar = TRUE;
continue;
case DEF_TITLEFONT:
f_t = strind;
continue;
case DEF_VISUALBELL:
if (strcmp (strind, "on") == 0)
screen->visualbell = TRUE;
continue;
}
}

/* parse command line */

for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
if (**argv == '=') {
geo_metry = *argv;
continue;
}

if (**argv == '%') {
T_geometry = *argv;
*T_geometry = '=';
continue;
}

if (**argv == '#') {
icon_geom = *argv;
*icon_geom = '=';
continue;
}

if((strind = index (*argv, ':')) != NULL) {
strncpy(display, *argv, sizeof(display));
continue;
}

if(!(i = (**argv == '-')) && **argv != '+') Syntax ();

switch(argument(&(*argv)[1])) {
case ARG_132:
screen->c132 = i;
continue;
#ifdef TIOCCONS
case ARG__C:
Console = i;
continue;
#endif TIOCCONS
case ARG__L:
{
char tt[32];

L_flag = 1;
get_ty = argv[--argc];
strcpy(tt,"/dev/");
strcat(tt, get_ty);
tt[5] = 'p';
loginpty = open( tt, O_RDWR, 0 );
dup2( loginpty, 4 );
close( loginpty );
loginpty = 4;
tt[5] = 't';
chown(tt, 0, 0);
chmod(tt, 0622);
if (open(tt, O_RDWR) < 0) {
consolepr("open failed\n");
}
signal(SIGHUP, SIG_IGN);
vhangup();
setpgrp(0,0);
signal(SIGHUP, SIG_DFL);
(void) close(0);
open(tt, O_RDWR, 0);
dup2(0, 1);
dup2(0, 2);
continue;
}
case ARG__S:
if(i) {
if (--argc <= 0) Syntax ();
sscanf(*++argv, "%c%c%d", passedPty, passedPty+1,
&am_slave);
if (am_slave <= 0) Syntax();
} else
am_slave = 0;
continue;
case ARG_AI:
screen->active_icon = i;
continue;
case ARG_AR:
screen->autoraise = i;
continue;
case ARG_B:
if(i) {
if (--argc <= 0) Syntax ();
screen->border = atoi (*++argv);
} else
screen->border = DEFBORDER;
continue;
case ARG_BD:
if(i) {
if (--argc <= 0) Syntax ();
brdr_color = *++argv;
} else
brdr_color = NULL;
continue;
case ARG_BG:
if(i) {
if (--argc <= 0) Syntax ();
back_color = *++argv;
} else
back_color = NULL;
continue;
case ARG_BW:
if(i) {
if (--argc <= 0) Syntax ();
screen->borderwidth = atoi (*++argv);
} else
screen->borderwidth = DEFBORDERWIDTH;
continue;
case ARG_CR:
if(i) {
if (--argc <= 0) Syntax ();
curs_color = *++argv;
} else
curs_color = NULL;
continue;
case ARG_CU:
screen->curses = i;
continue;
#ifdef DEBUG
case ARG_D:
debug = i;
continue;
#endif DEBUG
case ARG_DW:
screen->deiconwarp = i;
continue;
case ARG_E:
if(!i) Syntax();
if (argc <= 1) Syntax ();
command_to_exec = ++argv;
break;
case ARG_FB:
if(fbflag = i) {
if (--argc <= 0) Syntax ();
f_b = *++argv;
fbflag = TRUE;
} else {
f_b = def_bold_font;
fbflag = FALSE;
}
continue;
case ARG_FG:
if(i) {
if (--argc <= 0) Syntax ();
fore_color = *++argv;
} else
fore_color = NULL;
continue;
case ARG_FI:
if (i) {
if (--argc <= 0) Syntax();
f_i = *++argv;
} else
f_i = def_icon_font;
continue;
case ARG_FN:
if(fnflag = i) {
if (--argc <= 0) Syntax ();
f_n = *++argv;
fnflag = TRUE;
} else {
f_n = def_font;
fnflag = FALSE;
}
continue;
case ARG_FT:
if(i) {
if (--argc <= 0) Syntax ();
f_t = *++argv;
} else
f_t = def_title_font;
continue;
case ARG_I:
screen->icon_show = i ? -1 : 0;
continue;
case ARG_IB:
if(i) {
if (--argc <= 0) Syntax ();
iconbitmap = *++argv;
} else
iconbitmap = NULL;
continue;
case ARG_IT:
if(i) {
if (--argc <= 0) Syntax ();
tekiconbitmap = *++argv;
} else
tekiconbitmap = NULL;
continue;
case ARG_J:
if(screen->jumpscroll = i)
term.flags &= ~SMOOTHSCROLL;
else
term.flags |= SMOOTHSCROLL;
continue;
#ifdef KEYBD
case ARG_K:
if(i) {
if (--argc <= 0) Syntax ();
keyboardtype = *++argv;
} else
keyboardtype = NULL;
continue;
#endif KEYBD
case ARG_L:
log_on = i;
continue;
case ARG_LF:
if(screen->logfile)
free(screen->logfile);
if(i) {
if (--argc <= 0) Syntax ();
if(screen->logfile = malloc(strlen(*++argv) + 1))
strcpy(screen->logfile, *argv);
} else
screen->logfile = NULL;
continue;
case ARG_LS:
login_shell = i;
continue;
case ARG_MB:
screen->marginbell = i;
continue;
case ARG_MS:
if(i) {
if (--argc <= 0) Syntax ();
mous_color = *++argv;
} else
mous_color = NULL;
continue;
case ARG_N:
if(i) {
if (--argc <= 0) Syntax ();
win_name = *++argv;
} else
win_name = NULL;
continue;
case ARG_NB:
if(i) {
if (--argc <= 0) Syntax ();
n_marginbell = atoi (*++argv);
} else
n_marginbell = N_MARGINBELL;
continue;
case ARG_PO:
if(i) {
if (--argc <= 0) Syntax ();
if((screen->pageoverlap = atoi (*++argv) - 1) < 0)
screen->pageoverlap = -1;
} else
screen->pageoverlap = 0;
continue;
case ARG_PS:
screen->pagemode = i;
continue;
case ARG_RV:
re_verse = i;
continue;
case ARG_RW:
if(i)
term.flags |= REVERSEWRAP;
else
term.flags &= ~REVERSEWRAP;
continue;
case ARG_S:
screen->multiscroll = i;
continue;
case ARG_SB:
screen->scrollbar = i ? SCROLLBARWIDTH : 0;
continue;
case ARG_SI:
screen->scrollinput = i;
continue;
case ARG_SK:
screen->scrollkey = i;
continue;
case ARG_SL:
if(i) {
if (--argc <= 0) Syntax ();
save_lines = atoi (*++argv);
} else
save_lines = SAVELINES;
continue;
case ARG_SN:
screen->reversestatus = !i;
continue;
case ARG_ST:
screen->statusline = i;
continue;
case ARG_T:
screen->TekEmu = i;
continue;
case ARG_TB:
screen->fullVwin.titlebar = i;
continue;
case ARG_TI:
screen->textundericon = i;
continue;
case ARG_VB:
screen->visualbell = i;
continue;
default:
Syntax ();
}
break;
}

term.initflags = term.flags;

if (fnflag && !fbflag) f_b = NULL;
if (!fnflag && fbflag) f_n = f_b;
if(!win_name) {
if(get_ty) {
char b[256];

gethostname(b, sizeof(b) - 1);
b[sizeof(b) - 1] = 0;
if(strind = index(b, '.')) /* remove domain */
*strind = 0;
win_name = malloc(strlen(b) + 8);
strcpy(win_name, "login(");
strcat(win_name, b);
strcat(win_name, ")");
} else
win_name = (am_slave ? "xterm slave" :
(command_to_exec ? basename(command_to_exec[0]) :
xterm_name));
}
if(inhibit & I_TEK)
screen->TekEmu = FALSE;

/* set up stderr properly */
i = -1;
#ifdef DEBUG
if(debug)
i = open ("xterm.debug.log", O_WRONLY | O_CREAT | O_TRUNC,
0666);
else
#endif DEBUG
if(get_ty)
i = open("/dev/console", O_WRONLY);
if(i >= 0)
fileno(stderr) = i;
if(fileno(stderr) != (NOFILE - 1)) {
dup2(fileno(stderr), (NOFILE - 1));
if(fileno(stderr) >= 3)
close(fileno(stderr));
fileno(stderr) = (NOFILE - 1);
}

signal (SIGCHLD, reapchild);
signal (SIGHUP, SIG_IGN);
signal(SIGALRM, onalarm);

/* open a terminal for client */
get_terminal ();
spawn ();

Xsocket = screen->display->fd;
pty = screen->respond;

if (am_slave) { /* Write window id so master end can read and use */
write(pty, screen->TekEmu ? (char *)&TWindow(screen) :
(char *)&VWindow(screen), sizeof(Window));
write(pty, "\n", 1);
}

if(log_on) {
log_on = FALSE;
StartLog(screen);
}
screen->inhibit = inhibit;
mode = 1;
if (ioctl (pty, FIONBIO, &mode) == -1) SysError (ERROR_FIONBIO);

pty_mask = 1 << pty;
X_mask = 1 << Xsocket;
Select_mask = pty_mask | X_mask;
max_plus1 = (pty < Xsocket) ? (1 + Xsocket) : (1 + pty);

#ifdef DEBUG
if (debug) printf ("debugging on\n");
#endif DEBUG
XErrorHandler(xerror);
XIOErrorHandler(xioerror);
for( ; ; )
if(screen->TekEmu)
TekRun();
else
VTRun();
}

char *basename(name)
char *name;
{
register char *cp;
char *rindex();

return((cp = rindex(name, '/')) ? cp + 1 : name);
}

static struct argstr {
char *arg;
int val;
} arg[] = {
{"132", ARG_132},
#ifdef TIOCCONS
{"C", ARG__C},
#endif TIOCCONS
{"L", ARG__L},
{"S", ARG__S},
{"ai", ARG_AI},
{"ar", ARG_AR},
{"b", ARG_B},
{"bd", ARG_BD},
{"bg", ARG_BG},
{"bw", ARG_BW},
{"cr", ARG_CR},
{"cu", ARG_CU},
#ifdef DEBUG
{"d", ARG_D},
#endif DEBUG
{"dw", ARG_DW},
{"e", ARG_E},
{"fb", ARG_FB},
{"fg", ARG_FG},
{"fi", ARG_FI},
{"fn", ARG_FN},
{"ft", ARG_FT},
{"i", ARG_I},
{"ib", ARG_IB},
{"it", ARG_IT},
{"j", ARG_J},
#ifdef KEYBD
{"k", ARG_K},
#endif KEYBD
{"l", ARG_L},
{"lf", ARG_LF},
{"ls", ARG_LS},
{"mb", ARG_MB},
{"ms", ARG_MS},
{"n", ARG_N},
{"nb", ARG_NB},
{"po", ARG_PO},
{"ps", ARG_PS},
{"r", ARG_RV},
{"rv", ARG_RV},
{"rw", ARG_RW},
{"s", ARG_S},
{"sb", ARG_SB},
{"si", ARG_SI},
{"sk", ARG_SK},
{"sl", ARG_SL},
{"sn", ARG_SN},
{"st", ARG_ST},
{"t", ARG_T},
{"tb", ARG_TB},
{"ti", ARG_TI},
{"vb", ARG_VB},
{"w", ARG_BW},
};

argument(s)
register char *s;
{
register int i, low, high, com;

low = 0;
high = sizeof(arg) / sizeof(struct argstr) - 1;
while(low <= high) {/* use binary search, arg in lexigraphic order */
i = (low + high) / 2;
if ((com = strcmp(s, arg[i].arg)) == 0)
return(arg[i].val);
if(com > 0)
low = i + 1;
else
high = i - 1;
}
return(-1);
}

static char *ustring[] = {
"Usage: xterm [-132] [-ai] [-ar] [-b margin_width] [-bd border_color] \\\n",
#ifdef ARG__C
" [-bg backgrnd_color] [-bw border_width] [-C] [-cr cursor_color] [-cu] \\\n",
#else ARG__C
" [-bg backgrnd_color] [-bw border_width] [-cr cursor_color] [-cu] \\\n",
#endif ARG__C
" [-dw] [-fb bold_font] [-fg foregrnd_color] [-fi icon_font] [-fn norm_font] \\\n",
" [-ft title_font] [-i] [-ib iconbitmap] [-it tekiconbitmap] [-j] \\\n",
#ifdef ARG_K
" [-k keybd] [-l] [-lf logfile] [-ls] [-mb] [-ms mouse_color] \\\n",
#else ARG_K
" [-l] [-lf logfile] [-ls] [-mb] [-ms mouse_color] \\\n",
#endif ARG_K
" [-n name] [-nb bell_margin] [-po] [-ps] [-rv] [-rw] [-s] \\\n",
" [-sb] [-si] [-sk] [-sl save_lines] [-sn] [-st] [-t] [-tb] \\\n",
" [-ti] [-vb] [=[width]x[height][[+-]xoff[[+-]yoff]]] \\\n",
" [%[width]x[height][[+-]xoff[[+-]yoff]]] [#[+-]xoff[[+-]yoff]] \\\n",
" [-e command_to_exec]\n\n",
"Fonts must be of fixed width and of same size;\n",
"If only one font is specified, it will be used for normal and bold text\n",
"The -132 option allows 80 <-> 132 column escape sequences\n",
"The -ai option turns on miniature (active) icons\n",
"The -ar option turns auto raise window mode on\n",
#ifdef ARG__C
"The -C option forces output to /dev/console to appear in this window\n",
#endif ARG__C
"The -cu option turns a curses bug fix on\n",
"The -dw option warps the mouse on deiconify\n",
"The -i option enables icon startup\n",
"The -j option enables jump scroll\n",
"The -l option enables logging\n",
"The -ls option makes the shell a login shell\n",
"The -mb option turns the margin bell on\n",
"The -ps option turns page scroll on\n",
"The -rv option turns reverse video on\n",
"The -rw option turns reverse wraparound on\n",
"The -s option enables asynchronous scrolling\n",
"The -sb option enables the scrollbar\n",
"The -si option enables re-positioning the scrollbar at the bottom on input\n",
"The -sk option causes the scrollbar to position at the bottom on a key\n",
"The -sn option makes the status line normal video \n",
"The -st option enables the status line\n",
"The -t option starts Tektronix mode\n",
"The -tb option enables the titlebar\n",
"The -ti option places the window name under the icon\n",
"The -vb option enables visual bell\n",
0
};

Syntax ()
{
register char **us = ustring;

while (*us) fputs(*us++, stderr);
exit (1);
}

get_pty (pty, tty)
/*
opens a pty, storing fildes in pty and tty.
*/
int *pty, *tty;
{
int devindex, letter = 0;

while (letter < 4) {
ttydev [8] = ptydev [8] = "pqrs" [letter++];
devindex = 0;

while (devindex < 16) {
ttydev [9] = ptydev [9] = "0123456789abcdef" [devindex++];
if ((*pty = open (ptydev, O_RDWR)) < 0)
continue;
if ((*tty = open (ttydev, O_RDWR)) < 0) {
close(*pty);
continue;
}
return;
}
}

fprintf (stderr, "%s: Not enough available pty's\n", xterm_name);
exit (ERROR_PTYS);
}

get_terminal ()
/*
* sets up X and initializes the terminal structure except for term.buf.fildes.
*/
{
register Screen *screen = &term.screen;
register int try;
Color cdef;
char *malloc();

for (try = 10 ; ; ) {
if (screen->display = XOpenDisplay(display))
break;
if (!get_ty) {
fprintf(stderr, "%s: No such display server %s\n", xterm_name,
XDisplayName(display));
exit(ERROR_NOX);
}
if (--try <= 0) {
fprintf (stderr, "%s: Can't connect to display server %s\n",
xterm_name, XDisplayName(display));
exit (ERROR_NOX2);
}
sleep (5);
}

if(re_verse) {
B_Pixel = WhitePixel;
B_Pixmap = WhitePixmap;
W_Pixel = BlackPixel;
W_Pixmap = BlackPixmap;
} else {
B_Pixel = BlackPixel;
B_Pixmap = BlackPixmap;
W_Pixel = WhitePixel;
W_Pixmap = WhitePixmap;
}

if (brdr_color && DisplayCells() > 2 &&
XParseColor(brdr_color, &cdef) && XGetHardwareColor(&cdef)) {
if(!(screen->bordertile = XMakeTile(cdef.pixel)))
Error(ERROR_BORDER);
} else
screen->bordertile = B_Pixmap;
screen->graybordertile = make_gray();

screen->foreground = B_Pixel;
screen->background = W_Pixel;
screen->cursorcolor = B_Pixel;
screen->mousecolor = B_Pixel;

if (DisplayCells() > 2 && (fore_color || back_color ||
curs_color)) {
if (fore_color && XParseColor(fore_color, &cdef) &&
XGetHardwareColor(&cdef)) {
screen->foreground = cdef.pixel;
screen->color |= C_FOREGROUND;
}
if (back_color && XParseColor(back_color, &cdef) &&
XGetHardwareColor(&cdef)) {
screen->background = cdef.pixel;
screen->color |= C_BACKGROUND;
}
if (curs_color && XParseColor(curs_color, &cdef) &&
XGetHardwareColor(&cdef)) {
screen->cursorcolor = cdef.pixel;
screen->color |= C_CURSOR;
} else
screen->cursorcolor = screen->foreground;
}

if (mous_color && DisplayCells() > 2 &&
XParseColor(mous_color, &cdef) && XGetHardwareColor(&cdef)) {
screen->mousecolor = cdef.pixel;
screen->color |= C_MOUSE;
} else
screen->mousecolor = screen->cursorcolor;

if(screen->color & C_BACKGROUND) {
if(!(screen->bgndtile = XMakeTile(screen->background)))
Error(ERROR_BACK);
} else
screen->bgndtile = W_Pixmap;
screen->arrow = make_arrow(screen->mousecolor, screen->background,
GXcopy);

XAutoRepeatOn();
if((screen->titlefont = XOpenFont(f_t)) == NULL) {
fprintf(stderr, "%s: Can't get title font %s\n", xterm_name,
f_t);
exit(ERROR_TITLEFONT);
}
screen->title_n_size= XQueryWidth("m", screen->titlefont->id);
screen->titleheight = screen->titlefont->height + 2 * TITLEPAD + 1;
if(screen->fullVwin.titlebar)
screen->fullVwin.titlebar =
screen->fullTwin.titlebar = screen->titleheight;
IconInit(screen, iconbitmap, tekiconbitmap);
}

static char *tekterm[] = {
"tek4015",
"tek4014",
"tek4013",
"tek4010",
"dumb",
0
};

static char *vtterm[] = {
"xterms",
"xterm",
"vt102",
"vt100",
"ansi",
"dumb",
0
};

spawn ()
/*
* Inits pty and tty and forks a login process.
* Does not close fd Xsocket.
* If getty, execs getty rather than csh and uses std fd's rather
* than opening a pty/tty pair.
* If slave, the pty named in passedPty is already open for use
*/
{
register Screen *screen = &term.screen;
int Xsocket = screen->display->fd;
int index1, tty = -1;
int discipline;
unsigned lmode;
struct tchars tc;
struct ltchars ltc;
struct sgttyb sg;

char termcap [1024];
char newtc [1024];
char *ptr, *shname;
int i, no_dev_tty = FALSE;
char **envnew; /* new environment */
char buf[32];
char *TermName = NULL;
int ldisc = 0;
#ifdef sun
#ifdef TIOCSSIZE
struct ttysize ts;
#endif TIOCSSIZE
#else sun
#ifdef TIOCSWINSZ
struct winsize ws;
#endif TIOCSWINSZ
#endif sun
struct passwd *pw = NULL;
#ifdef UTMP
struct utmp utmp;
#endif UTMP
extern int Exit();
struct passwd *getpwuid();
char *getenv();
char *index (), *rindex (), *strindex ();

screen->uid = getuid();
screen->gid = getgid();

#ifdef UTMP
added_utmp_entry = FALSE;
#endif UTMP
/* so that TIOCSWINSZ || TIOCSIZE doesn't block */
signal(SIGTTOU,SIG_IGN);
if(!(screen->TekEmu ? TekInit() : VTInit()))
exit(ERROR_INIT);

if(screen->TekEmu) {
envnew = tekterm;
ptr = newtc;
} else {
/*
* Special case of a 80x24 window, use "xterms"
*/
envnew = (screen->max_col == 79 && screen->max_row ==
23) ? vtterm : &vtterm[1];
ptr = termcap;
}
while(*envnew) {
if(tgetent(ptr, *envnew) == 1) {
TermName = *envnew;
if(!screen->TekEmu)
resize(screen, TermName, termcap, newtc);
break;
}
envnew++;
}

if (get_ty) {
screen->respond = loginpty;
if((tslot = ttyslot()) <= 0)
SysError(ERROR_TSLOT);
#ifdef TIOCCONS
if (Console) {
int on = 1;
if (ioctl (0, TIOCCONS, &on) == -1)
SysError(ERROR_TIOCCONS);
}
#endif TIOCCONS
} else if (am_slave) {
screen->respond = am_slave;
ptydev[8] = ttydev[8] = passedPty[0];
ptydev[9] = ttydev[9] = passedPty[1];
if((tslot = ttyslot()) <= 0)
SysError(ERROR_TSLOT2);
setgid (screen->gid);
setuid (screen->uid);
} else {
if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0) {
if (errno != ENXIO) SysError(ERROR_OPDEVTTY);
else {
no_dev_tty = TRUE;
sg = d_sg;
tc = d_tc;
discipline = d_disipline;
ltc = d_ltc;
lmode = d_lmode;
}
} else {
/* get a copy of the current terminal's state */

if(ioctl(tty, TIOCGETP, &sg) == -1)
SysError (ERROR_TIOCGETP);
if(ioctl(tty, TIOCGETC, &tc) == -1)
SysError (ERROR_TIOCGETC);
if(ioctl(tty, TIOCGETD, &discipline) == -1)
SysError (ERROR_TIOCGETD);
if(ioctl(tty, TIOCGLTC, &ltc) == -1)
SysError (ERROR_TIOCGLTC);
if(ioctl(tty, TIOCLGET, &lmode) == -1)
SysError (ERROR_TIOCLGET);
close (tty);

/* close all std file descriptors */
for (index1 = 0; index1 < 3; index1++)
close (index1);
if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0)
SysError (ERROR_OPDEVTTY2);

if (ioctl (tty, TIOCNOTTY, 0) == -1)
SysError (ERROR_NOTTY);
close (tty);
}

get_pty (&screen->respond, &tty);

if (screen->respond != Xsocket + 1) {
dup2 (screen->respond, Xsocket + 1);
close (screen->respond);
screen->respond = Xsocket + 1;
}

/* change ownership of tty to real group and user id */
chown (ttydev, screen->uid, screen->gid);

/* change protection of tty */
chmod (ttydev, 0622);

if (tty != Xsocket + 2) {
dup2 (tty, Xsocket + 2);
close (tty);
tty = Xsocket + 2;
}

/* set the new terminal's state to be the old one's
with minor modifications for efficiency */

sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
sg.sg_flags |= ECHO | CRMOD;
/* make sure speed is set on pty so that editors work right*/
sg.sg_ispeed = B9600;
sg.sg_ospeed = B9600;
/* reset t_brkc to default value */
tc.t_brkc = -1;

if (ioctl (tty, TIOCSETP, &sg) == -1)
SysError (ERROR_TIOCSETP);
if (ioctl (tty, TIOCSETC, &tc) == -1)
SysError (ERROR_TIOCSETC);
if (ioctl (tty, TIOCSETD, &discipline) == -1)
SysError (ERROR_TIOCSETD);
if (ioctl (tty, TIOCSLTC, &ltc) == -1)
SysError (ERROR_TIOCSLTC);
if (ioctl (tty, TIOCLSET, &lmode) == -1)
SysError (ERROR_TIOCLSET);
#ifdef TIOCCONS
if (Console) {
int on = 1;
if (ioctl (tty, TIOCCONS, &on) == -1)
SysError(ERROR_TIOCCONS);
}
#endif TIOCCONS

close (open ("/dev/null", O_RDWR, 0));

for (index1 = 0; index1 < 3; index1++)
dup2 (tty, index1);
if((tslot = ttyslot()) <= 0)
SysError(ERROR_TSLOT3);
#ifdef UTMP
if((pw = getpwuid(screen->uid)) &&
(i = open(etc_utmp, O_WRONLY)) >= 0) {
bzero((char *)&utmp, sizeof(struct utmp));
(void) strcpy(utmp.ut_line, &ttydev[5]);
(void) strcpy(utmp.ut_name, pw->pw_name);
(void) strcpy(utmp.ut_host, DisplayName());
time(&utmp.ut_time);
lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
write(i, (char *)&utmp, sizeof(struct utmp));
close(i);
added_utmp_entry = TRUE;
}
#endif UTMP
}

#ifdef sun
#ifdef TIOCSSIZE
/* tell tty how big window is */
if(screen->TekEmu) {
ts.ts_lines = 38;
ts.ts_cols = 81;
} else {
ts.ts_lines = screen->max_row + 1;
ts.ts_cols = screen->max_col + 1;
}
ioctl (screen->respond, TIOCSSIZE, &ts);
#endif TIOCSSIZE
#else sun
#ifdef TIOCSWINSZ
/* tell tty how big window is */
if(screen->TekEmu) {
ws.ws_row = 38;
ws.ws_col = 81;
ws.ws_xpixel = TFullWidth(screen);
ws.ws_ypixel = TFullHeight(screen);
} else {
ws.ws_row = screen->max_row + 1;
ws.ws_col = screen->max_col + 1;
ws.ws_xpixel = FullWidth(screen);
ws.ws_ypixel = FullHeight(screen);
}
ioctl (screen->respond, TIOCSWINSZ, &ws);
#endif TIOCSWINSZ
#endif sun

if (!am_slave) {
if ((screen->pid = fork ()) == -1)
SysError (ERROR_FORK);

if (screen->pid == 0) {
extern char **environ;
int pgrp = getpid();
char shell_name[64];

close (Xsocket);
close (screen->respond);
if(fileno(stderr) >= 3)
close (fileno(stderr));

if (tty >= 0) close (tty);

signal (SIGCHLD, SIG_DFL);
signal (SIGHUP, SIG_IGN);

/* copy the environment before Setenving */
for (i = 0 ; environ [i] != NULL ; i++) ;
/*
* The `4' is the number of Setenv() calls which may add
* a new entry to the environment. The `1' is for the
* NULL terminating entry.
*/
envnew = (char **) calloc (i + (4 + 1), sizeof(char *));
bcopy((char *)environ, (char *)envnew, i * sizeof(char *));
environ = envnew;
Setenv ("TERM=", TermName);
if(!TermName)
*newtc = 0;
Setenv ("TERMCAP=", newtc);
sprintf(buf, "%d", screen->TekEmu ? (int)TWindow(screen) :
(int)VWindow(screen));
Setenv ("WINDOWID=", buf);
/* put the display into the environment of the shell*/
if (display[0] != '\0')
Setenv ("DISPLAY=", screen->display->displayname);

signal(SIGTERM, SIG_DFL);
ioctl(0, TIOCSPGRP, &pgrp);
setpgrp (0, 0);
close(open(ttyname(0), O_WRONLY, 0));
setpgrp (0, pgrp);

setgid (screen->gid);
setuid (screen->uid);

if (command_to_exec) {
execvp(*command_to_exec, command_to_exec);
/* print error message on screen */
fprintf(stderr, "%s: Can't execvp %s\n", xterm_name,
*command_to_exec);
}
signal(SIGHUP, SIG_IGN);
if (get_ty) {
ioctl (0, TIOCNOTTY, 0);
execl ("/etc/getty", "+", "Xwindow", get_ty, 0);
}
signal(SIGHUP, SIG_DFL);

#ifdef UTMP
if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) ||
*(ptr = pw->pw_shell) == 0))
#else UTMP
if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
((pw = getpwuid(screen->uid)) == NULL ||
*(ptr = pw->pw_shell) == 0))
#endif UTMP
ptr = "/bin/sh";
if(shname = rindex(ptr, '/'))
shname++;
else
shname = ptr;
i = strlen(shname) - 3;
ldisc = (strcmp("csh", shname + i) == 0 ||
strcmp("ksh", shname + i) == 0) ? NTTYDISC : 0;
ioctl(0, TIOCSETD, &ldisc);
if(login_shell)
strcpy(shell_name, "-");
else
*shell_name = 0;
strcat(shell_name, shname);
execl (ptr, shell_name, 0);
fprintf (stderr, "%s: Could not exec %s!\n", xterm_name, ptr);
sleep(5);
exit(ERROR_EXEC);
}
}

if(tty >= 0) close (tty);
signal(SIGHUP,SIG_IGN);

if (!no_dev_tty) {
if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0)
SysError(ERROR_OPDEVTTY3);
for (index1 = 0; index1 < 3; index1++)
dup2 (tty, index1);
if (tty > 2) close (tty);
}

signal(SIGINT, Exit);
signal(SIGQUIT, Exit);
signal(SIGTERM, Exit);
}

Exit(n)
int n;
{
register Screen *screen = &term.screen;
#ifdef UTMP
register int i;
struct utmp utmp;

if(added_utmp_entry && (i = open(etc_utmp, O_WRONLY)) >= 0) {
bzero((char *)&utmp, sizeof(struct utmp));
lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
write(i, (char *)&utmp, sizeof(struct utmp));
close(i);
}
#endif UTMP
if(screen->logging)
CloseLog(screen);

if(!get_ty && !am_slave) {
/* restore ownership of tty */
chown (ttydev, 0, 0);

/* restore modes of tty */
chmod (ttydev, 0666);
}
exit(n);
}

resize(screen, TermName, oldtc, newtc)
Screen *screen;
char *TermName;
register char *oldtc, *newtc;
{
register char *ptr1, *ptr2;
register int i;
register int li_first = 0;
register char *temp;
char *index(), *strindex();

if ((ptr1 = strindex (oldtc, "co#")) == NULL){
fprintf(stderr, "%s: Can't find co# in termcap string %s\n",
xterm_name, TermName);
exit (ERROR_NOCO);
}
if ((ptr2 = strindex (oldtc, "li#")) == NULL){
fprintf(stderr, "%s: Can't find li# in termcap string %s\n",
xterm_name, TermName);
exit (ERROR_NOLI);
}
if(ptr1 > ptr2) {
li_first++;
temp = ptr1;
ptr1 = ptr2;
ptr2 = temp;
}
ptr1 += 3;
ptr2 += 3;
strncpy (newtc, oldtc, i = ptr1 - oldtc);
newtc += i;
sprintf (newtc, "%d", li_first ? screen->max_row + 1 :
screen->max_col + 1);
newtc += strlen(newtc);
ptr1 = index (ptr1, ':');
strncpy (newtc, ptr1, i = ptr2 - ptr1);
newtc += i;
sprintf (newtc, "%d", li_first ? screen->max_col + 1 :
screen->max_row + 1);
ptr2 = index (ptr2, ':');
strcat (newtc, ptr2);
}

static reapchild ()
{
union wait status;
register int pid;

#ifdef DEBUG
if (debug) fputs ("Exiting\n", stderr);
#endif DEBUG
pid = wait3 (&status, WNOHANG, NULL);
if (!pid) return;
if (pid != term.screen.pid) return;

Cleanup(0);
}

consolepr(string)
char *string;
{
extern int errno;
extern char *sys_errlist[];
int oerrno;
int f;

oerrno = errno;
f = open("/dev/console",O_WRONLY);
write(f, "xterm: ", 7);
write(f, string, strlen(string));
write(f, ": ", 2);
write(f, sys_errlist[oerrno],strlen(sys_errlist[oerrno]));
write(f, "\n", 1);
close(f);
if ((f = open("/dev/tty", 2)) >= 0) {
ioctl(f, TIOCNOTTY, 0);
close(f);
}
}

checklogin()
{
register int i, j;
register struct passwd *pw;
struct utmp utmp;

if((i = open(etc_utmp, O_RDONLY)) < 0)
return(FALSE);
lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
j = read(i, (char *)&utmp, sizeof(utmp));
close(i);
if(j != sizeof(utmp) || strcmp(get_ty, utmp.ut_line) != 0 ||
!*utmp.ut_name || (pw = getpwnam(utmp.ut_name)) == NULL)
return(FALSE);
chdir(pw->pw_dir);
setgid(pw->pw_gid);
setuid(pw->pw_uid);
L_flag = 0;
return(TRUE);
}
RAZZLE!DAZZLE
fi # End main.c
if test -f menu.c
then
echo shar: will not overwrite existing file "'menu.c'"
else
echo 'x - menu.c'
cat << \RAZZLE!DAZZLE > menu.c
/*
* $Source: /u1/X/xterm/RCS/menu.c,v $
* $Header: menu.c,v 10.101 86/12/01 17:52:43 swick Rel $
*/

#ifdef MODEMENU
#include "X/Xlib.h"
#include "menu.h"

#ifndef lint
static char sccs_id[] = "@(#)menu.c\tX10/6.6B\t12/26/86";
#endif lint

#define FALSE 0
#define TRUE 1
#define InvertPlane 1
#define SetStateFlags(item) item->itemFlags = (item->itemFlags &\
~(itemStateMask | itemChanged)) |\
((item->itemFlags & itemSetMask) >>\
itemSetMaskShift)


static short Check_MarkBits[] = {
0x0100, 0x0180, 0x00c0, 0x0060,
0x0031, 0x001b, 0x000e, 0x0004
};
static short Check_GrayBits[] = {
0x0100, 0x0080, 0x0040, 0x0020,
0x0011, 0x000a, 0x0004, 0x0000
};
static short Default_CursorBits[] = {
0x0000, 0x0002, 0x0006, 0x000e,
0x001e, 0x003e, 0x007e, 0x00fe,
0x01fe, 0x003e, 0x0036, 0x0062,
0x0060, 0x00c0, 0x00c0, 0x0000
};
static short Default_GrayBits[] = {
0xaaaa, 0x5555, 0xaaaa, 0x5555,
0xaaaa, 0x5555, 0xaaaa, 0x5555,
0xaaaa, 0x5555, 0xaaaa, 0x5555,
0xaaaa, 0x5555, 0xaaaa, 0x5555,
};
static short Default_MaskBits[] = {
0x0003, 0x0007, 0x000f, 0x001f,
0x003f, 0x007f, 0x00ff, 0x01ff,
0x03ff, 0x07ff, 0x007f, 0x00f7,
0x00f3, 0x01e1, 0x01e0, 0x01c0
};
static char def_menu_font[] = "vtsingle";

Pixmap Gray_Tile;
Menu Menu_Default;
Cursor Menu_DefaultCursor;
char *Menu_DefaultFont;
FontInfo *Menu_DefaultFontInfo;

/*
* AddMenuItem() adds a menu item to an existing menu, at the end of the
* list, which are number sequentially from zero. The menuitem index is
* return, or -1 if failed.
*/

AddMenuItem(menu, text)
register Menu *menu;
register char *text;
{
register MenuItem *menuitem, **next;
register int i;
extern char *malloc();

if(!menu || !text || (menuitem = (MenuItem *)malloc(sizeof(MenuItem)))
== (MenuItem *)0)
return(-1);
bzero((char *)menuitem, sizeof(MenuItem));
menuitem->itemText = text;
menuitem->itemTextLength = strlen(text);
for(i = 0, next = &menu->menuItems ; *next ; i++)
next = &(*next)->nextItem;
*next = menuitem;
menu->menuFlags |= menuChanged;
return(i);
}

/*
* DisposeItem() releases the memory allocated for the given indexed
* menuitem. Nonzero is returned if an item was actual disposed of.
*/
DisposeItem(menu, i)
register Menu *menu;
register int i;
{
register MenuItem **next, **last, *menuitem;

if(!menu || i < 0)
return(0);
next = &menu->menuItems;
do {
if(!*next)
return(0);
last = next;
next = &(*next)->nextItem;
} while(i-- > 0);
menuitem = *last;
*last = *next;
free(menuitem);
return(1);
}

/*
* DisposeMenu() releases the memory allocated for the given menu.
*/
DisposeMenu(menu)
register Menu *menu;
{
static Unmap_Menu();

if(!menu)
return;
if(menu->menuFlags & menuMapped)
Unmap_Menu(menu);
while(DisposeItem(menu, 0));
if(menu->menuWindow)
XDestroyWindow(menu->menuWindow);
if(menu->menuSaved)
XFreePixmap(menu->menuSaved);
free(menu);
}

InitMenu(name)
register char *name;
{
register char *cp;
register Bitmap bit;

/*
* If the gray tile hasn't been set up, do it now.
*/
if(!Gray_Tile) {
if(!(bit = XStoreBitmap(grayWidth, grayHeight,
Default_GrayBits)))
return;
Gray_Tile = XMakePixmap(bit, WhitePixel, BlackPixel);
XFreeBitmap(bit);
}
Menu_Default.menuFlags = menuChanged;
if((cp = XGetDefault(name, "MenuFreeze")) && strcmp(cp, "on") == 0)
Menu_Default.menuFlags |= menuFreeze;
if((cp = XGetDefault(name, "MenuSave")) && strcmp(cp, "on") == 0)
Menu_Default.menuFlags |= menuSaveMenu;
Menu_Default.menuInitialItem = -1;
Menu_Default.menuBorderWidth = (cp = XGetDefault(name, "MenuBorder")) ?
atoi(cp) : 2;
Menu_Default.menuItemPad = (cp = XGetDefault(name, "MenuPad")) ?
atoi(cp) : 3;
Menu_DefaultFont = (cp = XGetDefault(name, "MenuFont")) ? cp :
def_menu_font;
};

/*
* ItemFlags returns the state of item "n" of the menu.
*/
ItemFlags(menu, n)
register Menu *menu;
register int n;
{
register MenuItem *item;

if(!menu || !menu->menuItems || n < 0)
return(-1);
for(item = menu->menuItems ; n > 0 ; n--)
if(!(item = item->nextItem))
return(0);
return((item->itemFlags & itemSetMask) >> itemSetMaskShift);
}

/*
* ItemText changes the text of item "n" of the menu.
*/
ItemText(menu, n, text)
register Menu *menu;
register int n;
char *text;
{
register MenuItem *item;

if(!menu || !menu->menuItems || n < 0 || !text)
return(0);
for(item = menu->menuItems ; n > 0 ; n--)
if(!(item = item->nextItem))
return(0);
item->itemText = text;
menu->menuFlags |= menuChanged;
return(1);
}

/*
* NewMenu() returns a pointer to an initialized new Menu structure, or NULL
* if failed.
*
* The Menu structure _menuDefault contains the default menu settings.
*/
Menu *NewMenu(name, reverse)
char *name;
int reverse;
{
register Menu *menu;
register int fg, bg;
extern char *malloc();

/*
* If the GrayTile hasn't been defined, InitMenu() was never
* run, so exit.
*/
if(!Gray_Tile)
return((Menu *)0);
/*
* Allocate the memory for the menu structure.
*/
if((menu = (Menu *)malloc(sizeof(Menu))) == (Menu *)0)
return((Menu *)0);
/*
* Initialize to default values.
*/
*menu = Menu_Default;
/*
* If the menu font hasn't yet been gotten, go get it.
*/
if(!menu->menuFontInfo) {
if(!Menu_DefaultFontInfo && !(Menu_DefaultFontInfo =
XOpenFont(Menu_DefaultFont)))
return((Menu *)0);
menu->menuFontInfo = Menu_DefaultFontInfo;
}
/*
* If the menu cursor hasn't been given, make a default one.
*/
if(!menu->menuCursor) {
if(!Menu_DefaultCursor) {
if(reverse) {
fg = WhitePixel;
bg = BlackPixel;
} else {
fg = BlackPixel;
bg = WhitePixel;
}
if(!(Menu_DefaultCursor =
XCreateCursor(defaultCursorWidth, defaultCursorHeight,
Default_CursorBits, Default_MaskBits, defaultCursorX,
defaultCursorY, fg, bg, GXcopy)))
return((Menu *)0);
}
menu->menuCursor = Menu_DefaultCursor;
}
/*
* Initialze the default background and border pixmaps and foreground
* and background colors (black and white).
*/
if(reverse) {
menu->menuBgTile = BlackPixmap;
menu->menuFgColor = WhitePixel;
menu->menuBgColor = BlackPixel;
} else {
menu->menuBgTile = WhitePixmap;
menu->menuFgColor = BlackPixel;
menu->menuBgColor = WhitePixel;
}
/*
* Set the menu title. If name is NULL or is an empty string, no
* title will be displayed.
*/
if(name && *name) {
menu->menuTitleLength = strlen(menu->menuTitle = name);
menu->menuTitleWidth = XStringWidth(name, menu->menuFontInfo,
0, 0);
menu->menuItemTop = menu->menuFontInfo->height + 2 *
menu->menuItemPad + 1;
} else
menu->menuTitleLength = menu->menuTitleWidth =
menu->menuItemTop = 0;
return(menu);
}

/*
* SetItemCheck sets the check state of item "n" of the menu to "state".
*/
SetItemCheck(menu, n, state)
register Menu *menu;
register int n;
int state;
{
register MenuItem *item;

if(!menu || !menu->menuItems || n < 0)
return(0);
for(item = menu->menuItems ; n > 0 ; n--)
if(!(item = item->nextItem))
return(0);
if(state)
item->itemFlags |= itemSetChecked;
else
item->itemFlags &= ~itemSetChecked;
if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
(item->itemFlags & itemStateMask)) {
item->itemFlags |= itemChanged;
menu->menuFlags |= menuItemChanged;
} else
item->itemFlags &= ~itemChanged;
return(1);
}

/*
* SetItemDisable sets the disable state of item "n" of the menu to "state".
*/
SetItemDisable(menu, n, state)
register Menu *menu;
register int n;
int state;
{
register MenuItem *item;

if(!menu || !menu->menuItems || n < 0)
return(0);
for(item = menu->menuItems ; n > 0 ; n--)
if(!(item = item->nextItem))
return(0);
if(state)
item->itemFlags |= itemSetDisabled;
else
item->itemFlags &= ~itemSetDisabled;
if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
(item->itemFlags & itemStateMask)) {
item->itemFlags |= itemChanged;
menu->menuFlags |= menuItemChanged;
} else
item->itemFlags &= ~itemChanged;
return(1);
}

/*
* TrackMenu does most of the work of displaying the menu and tracking the
* mouse.
*/
TrackMenu(menu, event)
register Menu *menu;
register XButtonPressedEvent *event;
{
register MenuItem *item;
register int i, button;
register MenuItem *hilited_item = (MenuItem *)0;
register int drawn;
XButtonReleasedEvent ev;
register int changed;
int y, n, hilited_y, hilited_n, in_window;
static MenuItem *Mouse_InItem(), *Y_InItem();
static Unmap_Menu();

/*
* Check that things are reasonable.
*/
if(!menu || !event || !menu->menuItems || event->type != ButtonPressed)
return(-1);
/*
* Set the changed flag and clear the menu changed flags.
*/
changed = menu->menuFlags & (menuChanged | menuItemChanged);
/*
* If the entire menu has changed, throw away any saved pixmap and
* then call RecalcMenu().
*/
if(changed & menuChanged) {
if(menu->menuSaved)
XFreePixmap(menu->menuSaved);
menu->menuSaved = (Pixmap)0;
if(!Recalc_Menu(menu))
return(-1);
changed &= ~menuItemChanged;
}
/*
* Now if the window was never created, go ahead and make it. Otherwise
* if the menu has changed, resize the window.
*/
if(!menu->menuWindow) {
if((menu->menuWindow = XCreateWindow(RootWindow, 0, 0,
menu->menuWidth, menu->menuHeight, menu->menuBorderWidth,
Gray_Tile, menu->menuBgTile)) == (Window)0)
return(-1);
XDefineCursor(menu->menuWindow, menu->menuCursor);
XSelectInput(menu->menuWindow, ExposeWindow | EnterWindow |
LeaveWindow | MouseMoved | ButtonReleased);
} else if(changed & menuChanged)
XChangeWindow(menu->menuWindow, menu->menuWidth,
menu->menuHeight);
/*
* Figure out where the menu is supposed to go, from the initial button
* press, and move the window there. Then map the menu.
*/
if(!Move_Menu(menu, event) || !Map_Menu(menu))
return(-1);
/*
* Try to grab the mouse, over a period of 10 seconds.
*/
for(i = 10 ; ; ) {
if(XGrabMouse(menu->menuWindow, menu->menuCursor,
ButtonReleased | EnterWindow | LeaveWindow | MouseMoved))
break;
if(--i <= 0) {
Unmap_Menu(menu);
return(-1);
}
sleep(1);
}
/*
* Save away the button that was pressed and use it to match a
* corresponding ButtonReleased event.
*/
button = event->detail & 03;
/*
* Now process events for the menu window.
*/
drawn = 0;
for( ; ; ) {
XNextEvent(&ev);
if(ev.type != ButtonReleased && ev.window != menu->menuWindow) {
if(menu->menuEventHandler)
(*menu->menuEventHandler)(&ev);
continue;
}
switch(ev.type) {
case ExposeWindow:
/*
* If we have a saved pixmap, display it. Otherwise
* redraw the menu and save it away.
*/
if(menu->menuSaved) {
XPixmapPut(menu->menuWindow, 0, 0, 0, 0,
menu->menuWidth, menu->menuHeight,
menu->menuSaved, GXcopy, AllPlanes);
/*
* If the menuItemChanged flag is still set,
* then we need to redraw certain menu items.
* ("i" is the vertical position of the top
* of the current item.)
*/
if(changed & menuItemChanged) {
i = menu->menuItemTop;
for(item = menu->menuItems ; item ;
item = item->nextItem) {
if(item->itemFlags &
itemChanged)
Modify_Item(menu, item,
i);
i += item->itemHeight;
}
}
} else
Draw_Menu(menu);
/*
* If the menu has changed in any way and we want to
* save the menu, throw away any existing save menu
* image and make a new one.
*/
XFlush();
if(changed && (menu->menuFlags & menuSaveMenu)) {
if(menu->menuSaved)
XFreePixmap(menu->menuSaved);
menu->menuSaved = XPixmapSave(menu->menuWindow,
0, 0, menu->menuWidth, menu->menuHeight);
}
/*
* See which item the cursor may currently be in. If
* it is in a non-disabled item, hilite it.
*/
if(hilited_item = Mouse_InItem(menu, &hilited_y,
&hilited_n, &in_window))
XPixFill(menu->menuWindow, 0, hilited_y,
menu->menuWidth, hilited_item->itemHeight,
BlackPixmap, (Bitmap)0, GXinvert, InvertPlane);
drawn++;
break;
case EnterWindow:
in_window = TRUE;
/* drop through */
case MouseMoved:
if(!drawn || !in_window)
break;
/*
* See which item the cursor may currently be in. If
* the item has changed, unhilite the old one and
* then hilited the new one.
*/
y = ((XEnterWindowEvent *)&ev)->y;
if((item = Y_InItem(menu, &y, &n)) != hilited_item) {
if(hilited_item)
XPixFill(menu->menuWindow, 0,
hilited_y, menu->menuWidth,
hilited_item->itemHeight, BlackPixmap,
(Bitmap)0, GXinvert, InvertPlane);
if(hilited_item = item) {
XPixFill(menu->menuWindow, 0,
hilited_y = y, menu->menuWidth,
item->itemHeight, BlackPixmap,
(Bitmap)0, GXinvert, InvertPlane);
hilited_n = n;
}
}
break;
case LeaveWindow:
if(!drawn)
break;
/*
* Unhilite any window that is currently hilited.
*/
if(hilited_item) {
XPixFill(menu->menuWindow, 0, hilited_y,
menu->menuWidth, hilited_item->itemHeight,
BlackPixmap, (Bitmap)0, GXinvert, InvertPlane);
hilited_item = (MenuItem *)0;
}
in_window = FALSE;
break;
case ButtonReleased:
/*
* If the correct button was released, ungrab the mouse
* and return the index number of any selected menu
* item.
*/
if((ev.detail & 0x3) == button) {
if(in_window) {
y = ((XButtonReleasedEvent *)&ev)->y;
if((item = Y_InItem(menu, &y, &n)) !=
hilited_item) {
if(hilited_item)
XPixFill(menu->menuWindow, 0,
hilited_y, menu->menuWidth,
hilited_item->itemHeight,
BlackPixmap, (Bitmap)0,
GXinvert, InvertPlane);
if(hilited_item = item) {
XPixFill(menu->menuWindow, 0,
hilited_y = y, menu->menuWidth,
hilited_item->itemHeight,
BlackPixmap, (Bitmap)0,
GXinvert, InvertPlane);
hilited_n = n;
}
}
}
XUngrabMouse();
menu->menuFlags &= ~(menuChanged |
menuItemChanged);
Unmap_Menu(menu);
XFlush();
if(hilited_item)
return(menu->menuInitialItem =
hilited_n);
return(-1);
}
break;
}
}
}

/*
* Recalculate all of the various menu and item variables.
*/
static Recalc_Menu(menu)
register Menu *menu;
{
register MenuItem *item;
register int max, i, height, fontheight;

/*
* We must have already gotten the menu font.
*/
if(!menu->menuFontInfo)
return(0);
/*
* Initialize the various max width variables.
*/
fontheight = menu->menuFontInfo->height;
height = menu->menuItemTop;
menu->menuMaxTextWidth = menu->menuTitleWidth;
/*
* The item height is the maximum of the font height and the
* checkbox height.
*/
max = fontheight;
if(checkMarkHeight > max)
max = checkMarkHeight;
/*
* Go through the menu item list.
*/
for(item = menu->menuItems ; item ; item = item->nextItem) {
/*
* If the item text is a single dash, we assume this is
* a line separator and treat it special.
*/
if(strcmp(item->itemText, "-") == 0)
height += (item->itemHeight = lineSeparatorHeight);
else {
height += (item->itemHeight = max);
/*
* Check the text width with the max value stored in
* menu.
*/
if((item->itemTextWidth = XStringWidth(item->itemText,
menu->menuFontInfo, 0, 0)) > menu->menuMaxTextWidth)
menu->menuMaxTextWidth = item->itemTextWidth;
}
/*
* If the itemChanged flag is set, set the state bits.
*/
if(item->itemFlags & itemChanged) {
item->itemFlags = (item->itemFlags & ~itemStateMask) |
((item->itemFlags & itemSetMask) >> itemSetMaskShift);
item->itemFlags &= ~itemChanged;
}
}
/*
* Set the menu height and then set the menu width.
*/
menu->menuHeight = height;
menu->menuWidth = 3 * menu->menuItemPad + menu->menuMaxTextWidth +
checkMarkWidth;
return(1);
}

/*
* Figure out where to popup the menu, relative to the where the button was
* pressed.
*/
static Move_Menu(menu, ev)
register Menu *menu;
XButtonPressedEvent *ev;
{
register MenuItem *item;
register int n, x, y;
int ev_x, ev_y;
int total_width;
Window subw;

/*
* Get the coordinates of the mouse when the button was pressed.
*/
XInterpretLocator(RootWindow, &ev_x, &ev_y, &subw, ev->location);
/*
* Try to popup the menu so that the cursor is centered within the
* width of the menu, but compensate if that would run it outside
* the display area.
*/
total_width = menu->menuWidth + 2 * menu->menuBorderWidth;
if((x = ev_x - total_width / 2) < 0)
x = 0;
else if(x + total_width > DisplayWidth())
x = DisplayWidth() - total_width;
#ifdef DROPMENUS
y = 0;
#else DROPMENUS
/*
* If we have an inital item, try to popup the menu centered
* vertically within this item.
*/
if(menu->menuInitialItem >= 0) {
/*
* Look through the item list. "y" is the vertical position
* of the top of the current item and "n" is the item number.
*/
y = menu->menuItemTop + menu->menuBorderWidth;
for(n = 0, item = menu->menuItems ; ; n++) {
/*
* On finding the intial item, center within this item.
*/
if(n == menu->menuInitialItem) {
y += item->itemHeight / 2;
break;
}
y += item->itemHeight;
/*
* If we run out of items, turn off the initial item
* and treat this as if no initial item.
*/
if(!(item = item->nextItem)) {
menu->menuInitialItem = -1;
goto noInitial;
}
}
/*
* If no initial item, try to popup the menu centered in the item
* nearest the center of the menu.
*/
} else {
noInitial:
/*
* Look through the item list. "y" is the vertical position
* of the top of the current item and "n" is the vertical
* position of the center of the menu.
*/
y = menu->menuItemTop + menu->menuBorderWidth;
for(n = menu->menuHeight / 2, item = menu->menuItems ; item ;
item = item->nextItem)
/*
* If the center of the menu is in this item, we
* center within this item.
*/
if((y += item->itemHeight) > n) {
y -= item->itemHeight / 2;
break;
}
}
#endif DROPMENU
/*
* If the menu extends above outside of the display, warp
* the mouse vertically so the menu will all show up.
*/
if((y = ev_y - y) < 0) {
XWarpMouse(RootWindow, ev_x, ev_y - y);
y = 0;
} else if((n = y + menu->menuHeight + 2 * menu->menuBorderWidth
- DisplayHeight()) > 0) {
XWarpMouse(RootWindow, ev_x, ev_y - n);
y -= n;
}
XMoveWindow(menu->menuWindow, x, y);
/*
* If we are in freeze mode, save what will be the coordinates of
* the save image.
*/
if(menu->menuFlags & menuFreeze) {
menu->menuSavedImageX = x;
menu->menuSavedImageY = y;
}
return(1);
}

/*
* Map the menu window.
*/
static Map_Menu(menu)
register Menu *menu;
{
register int i;

/*
* If we are in freeze mode, save the pixmap underneath where the menu
* will be (including the border).
*/
if(menu->menuFlags & menuFreeze) {
XGrabServer();
i = 2 * menu->menuBorderWidth;
if((menu->menuSavedImage = XPixmapSave(RootWindow,
menu->menuSavedImageX, menu->menuSavedImageY, menu->menuWidth
+ i, menu->menuHeight + i)) == (Pixmap)0)
return(0);
}
/*
* Actually map the window.
*/
XMapWindow(menu->menuWindow);
menu->menuFlags |= menuMapped;
return(1);
}

/*
* Draw the entire menu in the blank window.
*/
static Draw_Menu(menu)
register Menu *menu;
{
register MenuItem *item;
register int top = menu->menuItemTop;
register int x = menu->menuItemPad;
register int y, dim;

/*
* If we have a menu title, draw it first, centered and hilited.
*/
if(menu->menuTitleLength) {
XPixSet(menu->menuWindow, 0, 0, menu->menuWidth,
top - 1, menu->menuFgColor);
XText(menu->menuWindow, (menu->menuWidth -
menu->menuTitleWidth) / 2, menu->menuItemPad, menu->menuTitle,
menu->menuTitleLength, menu->menuFontInfo->id,
menu->menuBgColor, menu->menuFgColor);
}
/*
* For each item in the list, first draw any check mark and then
* draw the rest of it.
*/
for(item = menu->menuItems ; item ; item = item->nextItem) {
SetStateFlags(item);
dim = (item->itemFlags & itemDisabled);
/*
* Draw the check mark, possibly dimmed, wherever is necessary.
*/
if(item->itemFlags & itemChecked) {
XBitmapBitsPut(menu->menuWindow, x, y = top +
(item->itemHeight - checkMarkHeight) / 2,
checkMarkWidth, checkMarkHeight, dim ? Check_GrayBits :
Check_MarkBits, menu->menuFgColor, menu->menuBgColor,
(Bitmap)0, GXcopy, AllPlanes);
}
/*
* Draw the item, possibly dimmed.
*/
Draw_Item(menu, item, top, dim);
top += item->itemHeight;
}
}

/*
* Modify the item at vertical position y. This routine is table driven and
* the state and set bits are each 2 bits long, contiguous, the least
* significant bits in the flag word and with the state bits in bits 0 & 1.
*/

#define drawCheck 0x10
#define removeCheck 0x08
#define dimCheck 0x04
#define drawItem 0x02
#define dimItem 0x01

static char Modify_Table[] = {
0x00, 0x02, 0x08, 0x0a, 0x01, 0x00, 0x09, 0x08,
0x10, 0x12, 0x00, 0x12, 0x15, 0x14, 0x05, 0x00
};

static Modify_Item(menu, item, top)
register Menu *menu;
register MenuItem *item;
int top;
{
register int x = menu->menuItemPad;
register int y;
register int center = top + item->itemHeight / 2;
register int func = Modify_Table[item->itemFlags &
(itemStateMask | itemSetMask)];

/*
* If we really won't be making a change, return.
*/
if(func == 0)
return;
/*
* Draw the check mark if needed, possibly dimmed.
*/
y = center - (checkMarkHeight / 2);
if(func & (drawCheck | dimCheck))
XBitmapBitsPut(menu->menuWindow, x, y, checkMarkWidth,
checkMarkHeight, (func & dimCheck) ? Check_GrayBits :
Check_MarkBits, menu->menuFgColor, menu->menuBgColor,
(Bitmap)0, GXcopy, AllPlanes);
/*
* Remove the check mark if needed.
*/
if(func & removeCheck)
XTileSet(menu->menuWindow, x, y, checkMarkWidth,
checkMarkHeight, menu->menuBgTile);
/*
* Call Draw_Item if we need to draw or dim the item.
*/
if((x = func & dimItem) || (func & drawItem))
Draw_Item(menu, item, top, x);
/*
* Update state flags.
*/
SetStateFlags(item);
}

/*
* Draw the item (less check mark) at vertical position y.
* Dim the item if "dim" is set.
*/
static Draw_Item(menu, item, y, dim)
register Menu *menu;
register MenuItem *item;
register int y;
int dim;
{
register int x = 2 * menu->menuItemPad + checkMarkWidth;
register int center = y + item->itemHeight / 2;

/*
* If the item text is a single dash, draw a separating line.
*/
if(strcmp(item->itemText, "-") == 0) {
XLine(menu->menuWindow, 0, center, menu->menuWidth, center,
1, 1, menu->menuFgColor, GXcopy, AllPlanes);
return;
}
/*
* Draw and/or dim the text, centered vertically.
*/
y = center - (menu->menuFontInfo->height / 2);
if(dim) {
XTileSet(menu->menuWindow, x, y, item->itemTextWidth,
menu->menuFontInfo->height, Gray_Tile);
XTextPad(menu->menuWindow, x, y, item->itemText,
item->itemTextLength, menu->menuFontInfo->id, 0, 0,
menu->menuFgColor, menu->menuBgColor, menu->menuFgColor ?
GXand : GXor, AllPlanes);
} else
XText(menu->menuWindow, x, y, item->itemText,
item->itemTextLength, menu->menuFontInfo->id,
menu->menuFgColor, menu->menuBgColor);
}

/*
* Determine which enabled menu item the mouse is currently in. Return the
* top position of this item and its item number. Set inwindow to whether
* we are or not.
*/
static MenuItem *Mouse_InItem(menu, top, n, inwindow)
register Menu *menu;
int *top, *n, *inwindow;
{
int x, y;
Window subw;
static MenuItem *Y_InItem();

/*
* Find out where the mouse is. If its not in the menu window,
* return NULL.
*/
XQueryMouse(RootWindow, &x, &y, &subw);
if(subw != menu->menuWindow) {
*inwindow = FALSE;
return((MenuItem *)0);
}
*inwindow = TRUE;
/*
* Now get the coordinates relative to the menu window.
*/
XInterpretLocator(menu->menuWindow, &x, &y, &subw, (x << 16) | y);
/*
* Call Y_InItem().
*/
*top = y;
return(Y_InItem(menu, top, n));
}

/*
* Return which enabled item the locator is in. Also return the
* top position of this item and its item number. Initial y passed
* in top.
*/
static MenuItem *Y_InItem(menu, top, n)
register Menu *menu;
int *top, *n;
{
register MenuItem *item;
register int t, i;
register int y = *top;
Window subw;

/*
* Go through the item list. "t" is the vertical position of the
* current item and "i" is its item number.
*/
t = menu->menuItemTop;
/*
* If the mouse is before the first item, return.
*/
if(y < t)
return((MenuItem *)0);
for(i = 0, item = menu->menuItems ; item ; i++, item = item->nextItem) {
/*
* If the y coordinate is within this menu item, then return.
* But don't return disable items.
*/
if(t + item->itemHeight > y) {
if(item->itemFlags & itemDisabled)
return((MenuItem *)0);
*top = t;
*n = i;
return(item);
}
t += item->itemHeight;
}
/*
* Should never get here.
*/
return((MenuItem *)0);
}

/*
* Unmap_Menu() unmaps a menu, if it is currently mapped.
*/
static Unmap_Menu(menu)
register Menu *menu;
{
register int i;

if(!menu || !(menu->menuFlags & menuMapped))
return;
if(menu->menuFlags & menuFreeze) {
XUnmapTransparent(menu->menuWindow);
i = 2 * menu->menuBorderWidth;
XPixmapPut(RootWindow, 0, 0, menu->menuSavedImageX,
menu->menuSavedImageY, menu->menuWidth + i,
menu->menuHeight + i, menu->menuSavedImage,
GXcopy, AllPlanes);
XFreePixmap(menu->menuSavedImage);
XUngrabServer();
} else
XUnmapWindow(menu->menuWindow);
menu->menuFlags &= ~menuMapped;
}
#endif MODEMENU
RAZZLE!DAZZLE
fi # End menu.c
echo '***** End of' xterm 6.6B - Part 5 of 7 '*****'
exit

0 new messages