1 /*--------------------------------*-C-*---------------------------------*
2  * File:	command.c
3  *----------------------------------------------------------------------*
4  * Copyright (C) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *----------------------------------------------------------------------*/
20 /*----------------------------------------------------------------------*
21  * Originally written:
22  *    1992      John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
23  * Modifications:
24  *    1994      Robert Nation <nation@rocket.sanders.lockheed.com>
25  *              - extensive modifications
26  *    1995      Garrett D'Amore <garrett@netcom.com>
27  *              - vt100 printing
28  *    1995      Steven Hirsch <hirsch@emba.uvm.edu>
29  *              - X11 mouse report mode and support for DEC "private mode"
30  *                save/restore functions.
31  *    1995      Jakub Jelinek <jj@gnu.ai.mit.edu>
32  *              - key-related changes to handle Shift+function keys properly.
33  *    1997      MJ Olesen <olesen@me.queensu.ca>
34  *              - extensive modifications
35  *    1997      Raul Garcia Garcia <rgg@tid.es>
36  *              - modification and cleanups for Solaris 2.x and Linux 1.2.x
37  *    1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
38  *    1998      Geoff Wing <gcw@pobox.com>
39  *    1998	Alfredo K. Kojima <kojima@windowmaker.org>
40  *    1999      Rafal Wierzbicki <rafal@mcss.mcmaster.ca>
41  *              - support for Unix98 ptys with linux-2.2.x and glibc-2.1
42  *    2002      Alexis <materm@tuxfamily.org>
43  *              - modifications for multi-terms support
44  *----------------------------------------------------------------------*/
45 
46 
47 /*
48  * $Id: command.c,v 1.18 2004/08/15 16:08:07 alexis Exp $
49  */
50 
51 //#include "../config.h"
52 
53 
54 #include "rxvt.h"		/* NECESSARY */
55 
56 #ifdef DEBUG
57 #define DEBUG_CMD_ALEXIS 1
58 #define DEBUG_CMD 0
59 #define DEBUG_TTYMODE 1
60 #else
61 #define DEBUG_CMD_ALEXIS 0
62 #endif
63 
64 
65 #if DEBUG_CMD_ALEXIS
66 #define DCMD_ALEXIS(d,x) if(d <= DEBUG_CMD_ALEXIS) fprintf x
67 #else
68 #define DCMD_ALEXIS(d,x)
69 #endif
70 
71 
72 
73 #define TT_PRINTF_LIMIT		1024
74 
75 #if defined(OFFIX_DND) || defined(TRANSPARENT)
76 # include <X11/Xatom.h>
77 #endif
78 #ifdef OFFIX_DND
79 # define DndFile	2
80 # define DndDir		5
81 # define DndLink	7
82 #endif
83 
84 #if defined __GLIBC__ && __GLIBC__ >= 2
85 #  if defined __GLIBC_MINOR__ && __GLIBC_MINOR__ >= 1
86 #    define __lnx21__ 1
87 #  endif
88 #endif
89 
90 #include <X11/keysym.h>
91 #ifndef NO_XLOCALE
92 # if (XtSpecificationRelease < 6)
93 #  define NO_XLOCALE
94 # else
95 #  define X_LOCALE
96 #  include <X11/Xlocale.h>
97 # endif
98 #endif				/* NO_XLOCALE */
99 
100 #ifdef TTY_GID_SUPPORT
101 # include <grp.h>
102 #endif
103 
104 #if defined (__svr4__) || defined (__lnx21__)
105 # include <sys/resource.h>	/* for struct rlimit */
106 # include <sys/stropts.h>	/* for I_PUSH */
107 # define _NEW_TTY_CTRL		/* to get proper defines in <termios.h> */
108 #endif
109 
110 static unsigned int ModMetaMask, ModNumLockMask;
111 
112 /* pasting */
113 static char    *v_buffer;	/* pointer to physical buffer */
114 static char    *v_bufstr = NULL;	/* beginning of area to write */
115 static char    *v_bufptr;	/* end of area to write */
116 static char    *v_bufend;	/* end of physical buffer */
117 
118 void            get_ourmods(void);
119 int             pixmap_error_handler(Display * dpy, XErrorEvent * error);
120 
121 /* terminal mode defines:
122  *
123  * use the fastest baud-rate
124  */
125 #ifdef B38400
126 # define BAUDRATE	B38400
127 #else
128 # ifdef B19200
129 #  define BAUDRATE	B19200
130 # else
131 #  define BAUDRATE	B9600
132 # endif
133 #endif
134 
135 /* Disable special character functions */
136 #ifdef _POSIX_VDISABLE
137 # define VDISABLE	_POSIX_VDISABLE
138 #else
139 # define VDISABLE	255
140 #endif
141 
142 /*----------------------------------------------------------------------*
143  * system default characters if defined and reasonable
144  */
145 #ifndef CINTR
146 # define CINTR		'\003'	/* ^C */
147 #endif
148 #ifndef CQUIT
149 # define CQUIT		'\034'	/* ^\ */
150 #endif
151 #ifndef CERASE
152 # ifdef linux
153 #  define CERASE	'\177'	/* ^? */
154 # else
155 #  define CERASE	'\010'	/* ^H */
156 # endif
157 #endif
158 #ifndef CKILL
159 # define CKILL		'\025'	/* ^U */
160 #endif
161 #ifndef CEOF
162 # define CEOF		'\004'	/* ^D */
163 #endif
164 #ifndef CSTART
165 # define CSTART		'\021'	/* ^Q */
166 #endif
167 #ifndef CSTOP
168 # define CSTOP		'\023'	/* ^S */
169 #endif
170 #ifndef CSUSP
171 # define CSUSP		'\032'	/* ^Z */
172 #endif
173 #ifndef CDSUSP
174 # define CDSUSP		'\031'	/* ^Y */
175 #endif
176 #ifndef CRPRNT
177 # define CRPRNT		'\022'	/* ^R */
178 #endif
179 #ifndef CFLUSH
180 # define CFLUSH		'\017'	/* ^O */
181 #endif
182 #ifndef CWERASE
183 # define CWERASE	'\027'	/* ^W */
184 #endif
185 #ifndef CLNEXT
186 # define CLNEXT		'\026'	/* ^V */
187 #endif
188 
189 #ifndef VDISCRD
190 # ifdef VDISCARD
191 #  define VDISCRD	VDISCARD
192 # endif
193 #endif
194 
195 #ifndef VWERASE
196 # ifdef VWERASE
197 #  define VWERSE	VWERASE
198 # endif
199 #endif
200 
201 
202 /* defines
203  */
204 
205 #define KBUFSZ		8	/* size of keyboard mapping buffer */
206 #define STRING_MAX	512	/* max string size for process_xterm_seq() */
207 #define ESC_ARGS	32	/* max # of args for esc sequences */
208 
209 /* a large REFRESH_PERIOD causes problems with `cat' */
210 #define REFRESH_PERIOD		1
211 
212 #ifndef REFRESH_PERIOD
213 # define REFRESH_PERIOD		10
214 #endif
215 
216 #ifndef MULTICLICK_TIME
217 # define MULTICLICK_TIME	500
218 #endif
219 #ifndef SCROLLBAR_INITIAL_DELAY
220 # ifdef NEXT_SCROLLER
221 #  define SCROLLBAR_INITIAL_DELAY	20
222 # else
223 #  define SCROLLBAR_INITIAL_DELAY	40
224 # endif
225 #endif
226 #ifndef SCROLLBAR_CONTINUOUS_DELAY
227 # define SCROLLBAR_CONTINUOUS_DELAY	2
228 #endif
229 
230 /* time factor to slow down a `jumpy' mouse
231  */
232 #define MOUSE_THRESHOLD		50
233 #define CONSOLE		"/dev/console"	/* console device */
234 
235 /*
236  * key-strings: if only these keys were standardized <sigh>
237  */
238 #ifdef LINUX_KEYS
239 # define KS_HOME	"\033[1~"	/* Home == Find */
240 # define KS_END		"\033[4~"	/* End == Select */
241 #else
242 //# define KS_HOME	"\001" /* these is the C^a shell sequence */
243 //# define KS_END	"\005"   /* these is the C^e shell sequence */
244 # define KS_HOME	"\033[7~"	/* Home */
245 # define KS_END		"\033[8~"	/* End */
246 #endif
247 
248 /*
249  * ESC-Z processing:
250  *
251  * By stealing a sequence to which other xterms respond, and sending the
252  * same number of characters, but having a distinguishable sequence,
253  * we can avoid having a timeout (when not under an rxvt) for every login
254  * shell to auto-set its DISPLAY.
255  *
256  * This particular sequence is even explicitly stated as obsolete since
257  * about 1985, so only very old software is likely to be confused, a
258  * confusion which can likely be remedied through termcap or TERM. Frankly,
259  * I doubt anyone will even notice.  We provide a #ifdef just in case they
260  * don't care about auto-display setting.  Just in case the ancient
261  * software in question is broken enough to be case insensitive to the 'c'
262  * character in the answerback string, we make the distinguishing
263  * characteristic be capitalization of that character. The length of the
264  * two strings should be the same so that identical read(2) calls may be
265  * used.
266  */
267 #define VT100_ANS	"\033[?1;2c"	/* vt100 answerback */
268 #ifndef ESCZ_ANSWER
269 # define ESCZ_ANSWER	VT100_ANS	/* obsolete ANSI ESC[c */
270 #endif
271 
272 
273 /* local variables
274  */
275 //static char    *ptydev = NULL, *ttydev = NULL;	/* pty/tty name */
276 //static int      cmd_fd = -1;	/* file descriptor connected to the command */
277 //static pid_t    cmd_pid = -1;	/* process id if child */
278 static int      Xfd = -1;	/* file descriptor of X server connection */
279 static unsigned int num_fds = 0;	/* number of file descriptors being used */
280 //static struct stat ttyfd_stat;	/* original status of the tty we will use */
281 
282 /* multi-aterm vars
283  */
284 static char *ptydevs[MAX_PAGES],*ttydevs[MAX_PAGES];
285 static int cmd_fds[MAX_PAGES]; // liste des descripteurs pour les shells
286 static pid_t cmd_pids[MAX_PAGES];
287 static struct stat ttyfd_stats[MAX_PAGES];
288 static int fd_read; // descripteur sur lequel on a lu qqchose
289 int current_page;
290 
291 /* index of a vt that just died, -1 otherwise
292  set in f_Child_signal
293  */
294 static int vt_died;
295 
296 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
297 static int      scroll_arrow_delay;
298 #endif
299 
300 #ifdef META8_OPTION
301 static unsigned char meta_char = 033;	/* Alt-key prefix */
302 #endif
303 static unsigned int ModXMask = Mod1Mask;
304 
305 /* DEC private modes */
306 #define PrivMode_132		(1LU<<0)
307 #define PrivMode_132OK		(1LU<<1)
308 #define PrivMode_rVideo		(1LU<<2)
309 #define PrivMode_relOrigin	(1LU<<3)
310 #define PrivMode_Screen		(1LU<<4)
311 #define PrivMode_Autowrap	(1LU<<5)
312 #define PrivMode_aplCUR		(1LU<<6)
313 #define PrivMode_aplKP		(1LU<<7)
314 #define PrivMode_HaveBackSpace	(1LU<<8)
315 #define PrivMode_BackSpace	(1LU<<9)
316 #define PrivMode_ShiftKeys	(1LU<<10)
317 #define PrivMode_VisibleCursor	(1LU<<11)
318 #define PrivMode_MouseX10	(1LU<<12)
319 #define PrivMode_MouseX11	(1LU<<13)
320 #define PrivMode_scrollBar	(1LU<<14)
321 #define PrivMode_menuBar	(1LU<<15)
322 #define PrivMode_TtyOutputInh	(1LU<<16)
323 #define PrivMode_Keypress	(1LU<<17)
324 /* too annoying to implement X11 highlight tracking */
325 /* #define PrivMode_MouseX11Track       (1LU<<18) */
326 
327 #define PrivMode_mouse_report	(PrivMode_MouseX10|PrivMode_MouseX11)
328 #define PrivMode(test,bit)	do {					\
329     if (test) PrivateModes |= (bit); else PrivateModes &= ~(bit);} while (0)
330 
331 #define PrivMode_Default						 \
332 (PrivMode_Autowrap|PrivMode_aplKP|PrivMode_ShiftKeys|PrivMode_VisibleCursor)
333 
334 static unsigned long PrivateModes = PrivMode_Default;
335 static unsigned long SavedModes = PrivMode_Default;
336 
337 #undef PrivMode_Default
338 
339 static int refresh_count = 0, refresh_limit = 1;
340 static int refresh_type = SLOW_REFRESH;
341 
342 static Atom     wmDeleteWindow;
343 
344 /* OffiX Dnd (drag 'n' drop) support */
345 #ifdef OFFIX_DND
346 static Atom     DndProtocol, DndSelection;
347 #endif				/* OFFIX_DND */
348 
349 #ifndef NO_XLOCALE
350 static char    *rs_inputMethod = "";	/* XtNinputMethod */
351 static char    *rs_preeditType = NULL;	/* XtNpreeditType */
352 static XIC      Input_Context;	/* input context */
353 #endif				/* NO_XLOCALE */
354 
355 /* command input buffering */
356 #ifndef BUFSIZ
357 # define BUFSIZ		4096
358 #endif
359 static unsigned char cmdbuf_base[BUFSIZ], *cmdbuf_ptr, *cmdbuf_endp;
360 
361 
362 /* substitute system functions
363  */
364 #ifndef _POSIX_VERSION
365 # if defined (__svr4__) || defined (__lnx21__)
getdtablesize(void)366 int getdtablesize(void)
367 {
368 	struct rlimit   rlim;
369 
370 	getrlimit(RLIMIT_NOFILE, &rlim);
371 	return rlim.rlim_cur;
372 }
373 # endif
374 #endif
375 
376 /* take care of suid/sgid super-user (root) privileges
377  */
f_privileges(int page,int mode)378 void f_privileges(int page,int mode) {
379 #ifdef HAVE_SETEUID
380 	static uid_t    euid;
381 	static gid_t    egid;
382 
383 	switch (mode)
384 	{
385 	case IGNORE:
386 	    /*
387 	     * change effective uid/gid - not real uid/gid - so we can switch
388 	     * back to root later, as required
389 	     */
390 		seteuid(getuid());
391 		setegid(getgid());
392 		break;
393 
394 	case SAVE:
395 		euid = geteuid();
396 		egid = getegid();
397 		break;
398 
399 	case RESTORE:
400 		seteuid(euid);
401 		setegid(egid);
402 		break;
403 	}
404 #else
405 # ifndef __CYGWIN32__
406 	switch (mode)
407 	{
408 	case IGNORE:
409 		setuid(getuid());
410 		setgid(getgid());
411 		break;
412 
413 	case SAVE:
414 		break;
415 	case RESTORE:
416 		break;
417 	}
418 # endif
419 #endif
420 }
421 
print_winsize()422 void print_winsize() {
423   struct winsize ws;
424 
425   ioctl(cmd_fds[TermWin.active_page], TIOCGWINSZ, &ws);
426   fprintf(stderr,"dimension du terminal: %dx%d\n",ws.ws_col,ws.ws_row);
427   fprintf(stderr,"dimension du screen: %dx%d\n",TermWin.ncol,TermWin.nrow);
428 }
429 
f_update_resources(int unused)430 void f_update_resources(int unused) {
431   f_RenderPixmap(TermWin.active_page,1);
432   TermWin.vts[TermWin.active_page].bg.Shading.shading = 80;
433   f_scr_touch(TermWin.active_page);
434   //print_info_screen();
435   print_winsize();
436 	signal(SIGCHLD, f_Child_signal);
437   signal(SIGUSR1, f_update_resources);
438 }
439 
440 
441 
442 /* signal handling, exit handler
443  *
444  * Catch a SIGCHLD signal and exit if the direct child has died
445  */
f_Child_signal(int unused)446 RETSIGTYPE f_Child_signal(int unused)
447 {
448 	int pid, save_errno = errno;
449   int i=0,l;
450   char buff[1024];
451 
452   pid = waitpid(-1,NULL,WNOHANG);
453   if( pid != -1 ) {
454     for(i=0; i <= TermWin.last_page && pid != cmd_pids[i]; i++);
455 
456     if( i <= TermWin.last_page ) {
457       vt_died=i;
458     } else {
459       DCMD_ALEXIS(1,(stderr,"no pid find in cmd_pids for child %d\n",pid));
460       errno = save_errno;
461     }
462   }
463 
464 	signal(SIGCHLD, f_Child_signal);
465   signal(SIGUSR1, f_update_resources);
466 }
467 
468 
469 /*
470  * Catch a fatal signal and tidy up before quitting
471  */
Exit_signal(int sig)472 RETSIGTYPE Exit_signal(int sig)
473 {
474 #ifdef DEBUG_CMD
475 	print_error("signal %d", sig);
476 #endif
477 	signal(sig, SIG_DFL);
478 
479 #ifdef UTMP_SUPPORT
480 	f_privileges(0,RESTORE);
481 	cleanutent();
482 	f_privileges(0,IGNORE);
483 #endif
484 
485 	kill(getpid(), sig);
486 }
487 
488 /*
489  * Exit gracefully, clearing the utmp entry and restoring tty attributes
490  * TODO: this should free up any known resources if we can
491  */
f_clean_exit(void)492 void f_clean_exit(void)
493 {
494   int i;
495 #ifdef DEBUG_CMD
496 /*	fprintf(stderr, "Restoring \"%s\" to mode %03o, uid %d, gid %d\n",
497 		ttydev, ttyfd_stat.st_mode, ttyfd_stat.st_uid,ttyfd_stat.st_gid);*/
498 #endif
499   f_privileges(i,RESTORE);
500   for(i=0; i < TermWin.last_page; i++) {
501     f_scr_release(i,0);
502   }
503   /* and clean the last screen and drawn & co */
504   f_scr_release(TermWin.last_page,1);
505 #ifndef __CYGWIN32__
506   for(i=0; i <= TermWin.last_page; i++) {
507     chmod(ttydevs[i], ttyfd_stats[i].st_mode);
508     chown(ttydevs[i], ttyfd_stats[i].st_uid, ttyfd_stats[i].st_gid);
509   }
510 #endif
511 #ifdef UTMP_SUPPORT
512 	cleanutent();
513 #endif
514 //  for(i=0; i <= TermWin.last_page; i++) {
515     f_privileges(0,IGNORE);
516 //  }
517 }
518 
519 
520 /* Acquire a pseudo-teletype from the system.
521  *
522  * On failure, returns -1.
523  * On success, returns the file descriptor.
524  *
525  * If successful, ttydev and ptydev point to the names of the
526  * master and slave parts
527  */
528 
f_get_pty(int page)529 int f_get_pty(int page) {
530 	int             fd = -1;
531 
532 #if defined (__sgi)
533 	ptydevs[page] = ttydevs[page] = _getpty(&fd, O_RDWR | O_NDELAY, 0622, 0);
534 	if (ptydevs[page] == NULL)
535 		goto Failed;
536 #elif defined (__svr4__) || defined(__CYGWIN32__) || defined(__lnx21__)
537 	{
538 		extern char    *ptsname();
539     DCMD_ALEXIS(1,(stderr,"__CYGWIN32__ case for getting pty\n"));
540 
541     /* open the STREAMS, clone device /dev/ptmx (master pty) */
542 #ifdef HAVE_GETPT
543     if ((fd = getpt()) < 0)
544     {
545 #else
546     if ((fd = open("/dev/ptmx", O_RDWR)) < 0)
547     {
548 #endif
549       goto Failed;
550     } else {
551       grantpt(fd);	/* change slave permissions */
552       unlockpt(fd);	/* unlock slave */
553       ptydevs[page] = ttydevs[page] = ptsname(fd);	/* get slave's name */
554       //printf("pseudo terminal maitre: %s\n",ttyname(fd)); -> /dev/ptmx
555       DCMD_ALEXIS(1,(stderr,"pty %s, tty %s\n",ptydevs[page],ttydevs[page]));
556     }
557   }
558 #elif defined (_AIX)
559 	if ((fd = open("/dev/ptc", O_RDWR)) < 0)
560 		goto Failed;
561 	else
562 		ptydevs[page] = ttydevs[page] = ttyname(fd);
563 #elif defined(ALL_NUMERIC_PTYS)	/* SCO OSr5 */
564 	static char     pty_name[] = "/dev/ptyp??\0\0\0";
565 	static char     tty_name[] = "/dev/ttyp??\0\0\0";
566 	int             len = strlen(tty_name);
567 	char           *c1, *c2;
568 	int             idx;
569 
570   DCMD_ALEXIS(1,(stderr,"ALL_NUMERIC_PTYS case for getting pty\n"));
571   ptydevs[page] = pty_name;
572   ttydevs[page] = tty_name;
573 
574   for (idx = 0; idx < 256; idx++)
575 	{
576 		sprintf(ptydevs[page], "%s%d", "/dev/ptyp", idx);
577 		sprintf(ttydevs[page], "%s%d", "/dev/ttyp", idx);
578 
579 		if (access(ttydevs[page], F_OK) < 0)
580 		{
581 			idx = 256;
582 			break;
583 		}
584 		if ((fd = open(ptydevs[page], O_RDWR)) >= 0)
585 		{
586 			if (access(ttydevs[page], R_OK | W_OK) == 0)
587 				goto Found;
588 			close(fd); /* i_f */
589 		}
590 	}
591 	goto Failed;
592 #else
593   /* FreeBSD uses this one */
594 	static char     pty_name[] = "/dev/pty??";
595 	static char     tty_name[] = "/dev/tty??";
596 	int             len = strlen(tty_name);
597 	char           *c1, *c2;
598 
599   DCMD_ALEXIS(1,(stderr, "default case for getting pty\n"));
600 	ptydevs[page] = pty_name;
601 	ttydevs[page] = tty_name;
602 
603 # define PTYCHAR1	"pqrstuvwxyz"
604 # define PTYCHAR2	"0123456789abcdef"
605 	for (c1 = PTYCHAR1; *c1; c1++)
606 	{
607 		ptydevs[page][len - 2] = ttydevs[page][len - 2] = *c1;
608 		for (c2 = PTYCHAR2; *c2; c2++)
609 		{
610 			ptydevs[page][len - 1] = ttydevs[page][len - 1] = *c2;
611 			if ((fd = open(ptydevs[page], O_RDWR)) >= 0)
612 			{
613 				if (access(ttydevs[page], R_OK | W_OK) == 0)
614 					goto Found;
615 				close(fd);
616 			}
617 		}
618 	}
619 	goto Failed;
620 #endif
621 
622       Found:
623 	fcntl(fd, F_SETFL, O_NDELAY);
624 	return fd;
625 
626       Failed:
627 	print_error("can't open pseudo-tty");
628 	return -1;
629 }
630 
631 
632 /* establish a controlling teletype for new session
633  *
634  * On some systems this can be done with ioctl() but on others we
635  * need to re-open the slave tty.
636  */
637 int f_get_tty(int page)
638 {
639 	int             fd;
640 	pid_t           pid;
641 
642 /*
643  * setsid() [or setpgrp] must be before open of the terminal,
644  * otherwise there is no controlling terminal (Solaris 2.4, HP-UX 9)
645  */
646 #ifndef ultrix
647 # ifdef NO_SETSID
648 	pid = setpgrp(0, 0);
649 # else
650 	pid = setsid();
651 # endif
652 	if (pid < 0)
653 		perror(rs_name);
654 # ifdef DEBUG_TTYMODE
655 	print_error("(%s: line %d): PID = %d\n", __FILE__, __LINE__, pid);
656 # endif
657 #endif				/* ultrix */
658 
659 	if ((fd = open(ttydevs[page], O_RDWR)) < 0)
660 	{
661 		print_error("can't open slave tty %s", ttydevs[page]);
662 		exit(EXIT_FAILURE);
663 	}
664 #if defined (__svr4__) || defined (__lnx21__)
665 /*
666  * Push STREAMS modules:
667  *    ptem: pseudo-terminal hardware emulation module.
668  *    ldterm: standard terminal line discipline.
669  *    ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
670  */
671 	ioctl(fd, I_PUSH, "ptem");
672 	ioctl(fd, I_PUSH, "ldterm");
673 	ioctl(fd, I_PUSH, "ttcompat");
674 #else				/* __svr4__ */
675 	{
676 	    /* change ownership of tty to real uid and real group */
677 		unsigned int    mode = 0622;
678 		gid_t           gid = getgid();
679 
680 # ifdef TTY_GID_SUPPORT
681 		{
682 			struct group   *gr = getgrnam("tty");
683 
684 			if (gr)
685 			{
686 			    /* change ownership of tty to real uid, "tty" gid */
687 				gid = gr->gr_gid;
688 				mode = 0620;
689 			}
690 		}
691 # endif				/* TTY_GID_SUPPORT */
692 		f_privileges(page,RESTORE);
693 # ifndef __CYGWIN32__
694 		fchown(fd, getuid(), gid);	/* fail silently */
695 		fchmod(fd, mode);
696 # endif
697 		f_privileges(page,IGNORE);
698 	}
699 #endif				/* __svr4__ */
700 
701 /*
702  * Close all file descriptors.  If only stdin/out/err are closed,
703  * child processes remain alive upon deletion of the window.
704  */
705 	{
706 		int             i;
707 
708 		for (i = 0; i < num_fds; i++)
709 			if (i != fd)
710 				close(i);
711 	}
712 
713 /* Reopen stdin, stdout and stderr over the tty file descriptor */
714 	dup(fd);		/* 0: stdin */
715 	dup(fd);		/* 1: stdout */
716 	dup(fd);		/* 2: stderr */
717 
718 	if (fd > 2)
719 		close(fd);
720 
721 #ifdef ultrix
722 	if ((fd = open("/dev/tty", O_RDONLY)) >= 0)
723 	{
724 		ioctl(fd, TIOCNOTTY, 0);
725 		close(fd);
726 	} else
727 	{
728 		pid = setpgrp(0, 0);
729 		if (pid < 0)
730 			perror(rs_name);
731 	}
732 
733 /* no error, we could run with no tty to begin with */
734 #else				/* ultrix */
735 # ifdef TIOCSCTTY
736 	ioctl(0, TIOCSCTTY, 0);
737 # endif
738 
739 /* set process group */
740 # if defined (_POSIX_VERSION) || defined (__svr4__)
741 	tcsetpgrp(0, pid);
742 # elif defined (TIOCSPGRP)
743 	ioctl(0, TIOCSPGRP, &pid);
744 # endif
745 
746 /* svr4 problems: reports no tty, no job control */
747 /* # if !defined (__svr4__) && defined (TIOCSPGRP) */
748 
749 	close(open(ttydevs[page], O_RDWR, 0));
750 /* # endif */
751 #endif				/* ultrix */
752 
753 	f_privileges(page,IGNORE);
754 
755 	return fd;
756 }
757 
758 
759 /* debug_ttymode() */
760 #ifdef DEBUG_TTYMODE
761 void debug_ttymode(ttymode_t * ttymode)
762 {
763 # ifdef HAVE_TERMIOS_H
764 /* c_iflag bits */
765 	DCMD_ALEXIS(1,(stderr, "Input flags\n"));
766 
767 /* cpp token stringize doesn't work on all machines <sigh> */
768 #  define FOO(flag,name)		\
769     if ((ttymode->c_iflag) & flag)	\
770 	fprintf (stderr, "%s ", name)
771 
772 /* c_iflag bits */
773 	FOO(IGNBRK, "IGNBRK");
774 	FOO(BRKINT, "BRKINT");
775 	FOO(IGNPAR, "IGNPAR");
776 	FOO(PARMRK, "PARMRK");
777 	FOO(INPCK, "INPCK");
778 	FOO(ISTRIP, "ISTRIP");
779 	FOO(INLCR, "INLCR");
780 	FOO(IGNCR, "IGNCR");
781 	FOO(ICRNL, "ICRNL");
782 	FOO(IXON, "IXON");
783 	FOO(IXOFF, "IXOFF");
784 #  ifdef IUCLC
785 	FOO(IUCLC, "IUCLC");
786 #  endif
787 #  ifdef IXANY
788 	FOO(IXANY, "IXANY");
789 #  endif
790 #  ifdef IMAXBEL
791 	FOO(IMAXBEL, "IMAXBEL");
792 #  endif
793 	fprintf(stderr, "\n\n");
794 
795 #  undef FOO
796 #  define FOO(entry, name) \
797     fprintf (stderr, "%s = %#3o\n", name, ttymode->c_cc [entry])
798 
799 	FOO(VINTR, "VINTR");
800 	FOO(VQUIT, "VQUIT");
801 	FOO(VERASE, "VERASE");
802 	FOO(VKILL, "VKILL");
803 	FOO(VEOF, "VEOF");
804 	FOO(VEOL, "VEOL");
805 #  ifdef VEOL2
806 	FOO(VEOL2, "VEOL2");
807 #  endif
808 #  ifdef VSWTC
809 	FOO(VSWTC, "VSWTC");
810 #  endif
811 #  ifdef VSWTCH
812 	FOO(VSWTCH, "VSWTCH");
813 #  endif
814 	FOO(VSTART, "VSTART");
815 	FOO(VSTOP, "VSTOP");
816 	FOO(VSUSP, "VSUSP");
817 #  ifdef VDSUSP
818 	FOO(VDSUSP, "VDSUSP");
819 #  endif
820 #  ifdef VREPRINT
821 	FOO(VREPRINT, "VREPRINT");
822 #  endif
823 #  ifdef VDISCRD
824 	FOO(VDISCRD, "VDISCRD");
825 #  endif
826 #  ifdef VWERSE
827 	FOO(VWERSE, "VWERSE");
828 #  endif
829 #  ifdef VLNEXT
830 	FOO(VLNEXT, "VLNEXT");
831 #  endif
832 	fprintf(stderr, "\n\n");
833 #  undef FOO
834 # endif				/* HAVE_TERMIOS_H */
835 }
836 #endif				/* DEBUG_TTYMODE */
837 
838 /* get_ttymode()
839  */
840 void get_ttymode(ttymode_t * tio)
841 {
842 #ifdef HAVE_TERMIOS_H
843 /*
844  * standard System V termios interface
845  */
846 	if (GET_TERMIOS(0, tio) < 0)
847 	{
848 	    /* return error - use system defaults */
849 		tio->c_cc[VINTR] = CINTR;
850 		tio->c_cc[VQUIT] = CQUIT;
851 		tio->c_cc[VERASE] = CERASE;
852 		tio->c_cc[VKILL] = CKILL;
853 		tio->c_cc[VSTART] = CSTART;
854 		tio->c_cc[VSTOP] = CSTOP;
855 		tio->c_cc[VSUSP] = CSUSP;
856 # ifdef VDSUSP
857 		tio->c_cc[VDSUSP] = CDSUSP;
858 # endif
859 # ifdef VREPRINT
860 		tio->c_cc[VREPRINT] = CRPRNT;
861 # endif
862 # ifdef VDISCRD
863 		tio->c_cc[VDISCRD] = CFLUSH;
864 # endif
865 # ifdef VWERSE
866 		tio->c_cc[VWERSE] = CWERASE;
867 # endif
868 # ifdef VLNEXT
869 		tio->c_cc[VLNEXT] = CLNEXT;
870 # endif
871 	}
872 	tio->c_cc[VEOF] = CEOF;
873 	tio->c_cc[VEOL] = VDISABLE;
874 # ifdef VEOL2
875 	tio->c_cc[VEOL2] = VDISABLE;
876 # endif
877 # ifdef VSWTC
878 	tio->c_cc[VSWTC] = VDISABLE;
879 # endif
880 # ifdef VSWTCH
881 	tio->c_cc[VSWTCH] = VDISABLE;
882 # endif
883 # if VMIN != VEOF
884 	tio->c_cc[VMIN] = 1;
885 # endif
886 # if VTIME != VEOL
887 	tio->c_cc[VTIME] = 0;
888 # endif
889 
890 /* input modes */
891 	tio->c_iflag = (BRKINT | IGNPAR | ICRNL | IXON
892 # ifdef IMAXBEL
893 			| IMAXBEL
894 # endif
895 	    );
896 
897 /* output modes */
898 	tio->c_oflag = (OPOST | ONLCR);
899 
900 /* control modes */
901 	tio->c_cflag = (CS8 | CREAD);
902 
903 /* line discipline modes */
904 	tio->c_lflag = (ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK
905 # if defined (ECHOCTL) && defined (ECHOKE)
906 			| ECHOCTL | ECHOKE
907 # endif
908 	    );
909 
910 #if 0
911 /*
912  * guess an appropriate value for Backspace
913  */
914 # ifdef FORCE_BACKSPACE
915 	PrivMode(1, PrivMode_BackSpace);
916 # elif defined (FORCE_DELETE)
917 	PrivMode(0, PrivMode_BackSpace);
918 # else
919 	PrivMode((tio->c_cc[VERASE] == '\b'), PrivMode_BackSpace);
920 # endif
921 #endif				/* if 0 */
922 
923 #else				/* HAVE_TERMIOS_H */
924 
925 /*
926  * sgtty interface
927  */
928 
929 /* get parameters -- gtty */
930 	if (ioctl(0, TIOCGETP, &(tio->sg)) < 0)
931 	{
932 		tio->sg.sg_erase = CERASE;	/* ^H */
933 		tio->sg.sg_kill = CKILL;	/* ^U */
934 	}
935 	tio->sg.sg_flags = (CRMOD | ECHO | EVENP | ODDP);
936 
937 /* get special characters */
938 	if (ioctl(0, TIOCGETC, &(tio->tc)) < 0)
939 	{
940 		tio->tc.t_intrc = CINTR;	/* ^C */
941 		tio->tc.t_quitc = CQUIT;	/* ^\ */
942 		tio->tc.t_startc = CSTART;	/* ^Q */
943 		tio->tc.t_stopc = CSTOP;	/* ^S */
944 		tio->tc.t_eofc = CEOF;	/* ^D */
945 		tio->tc.t_brkc = -1;
946 	}
947 /* get local special chars */
948 	if (ioctl(0, TIOCGLTC, &(tio->lc)) < 0)
949 	{
950 		tio->lc.t_suspc = CSUSP;	/* ^Z */
951 		tio->lc.t_dsuspc = CDSUSP;	/* ^Y */
952 		tio->lc.t_rprntc = CRPRNT;	/* ^R */
953 		tio->lc.t_flushc = CFLUSH;	/* ^O */
954 		tio->lc.t_werasc = CWERASE;	/* ^W */
955 		tio->lc.t_lnextc = CLNEXT;	/* ^V */
956 	}
957 /* get line discipline */
958 	ioctl(0, TIOCGETD, &(tio->line));
959 # ifdef NTTYDISC
960 	tio->line = NTTYDISC;
961 # endif				/* NTTYDISC */
962 	tio->local = (LCRTBS | LCRTERA | LCTLECH | LPASS8 | LCRTKIL);
963 
964 /*
965  * guess an appropriate value for Backspace
966  */
967 #if 0
968 # ifdef FORCE_BACKSPACE
969 	PrivMode(1, PrivMode_BackSpace);
970 # elif defined (FORCE_DELETE)
971 	PrivMode(0, PrivMode_BackSpace);
972 # else
973 	PrivMode((tio->sg.sg_erase == '\b'), PrivMode_BackSpace);
974 # endif
975 #endif				/* if 0 */
976 
977 #endif				/* HAVE_TERMIOS_H */
978 }
979 
980 
981 /* run_command()
982  *
983  * Run the command in a subprocess and return a file descriptor for the
984  * master end of the pseudo-teletype pair with the command talking to
985  * the slave.
986  */
987 
988 int f_run_command(int page,char *argv[])
989 {
990 	ttymode_t tio; /* same as termios */
991 	int       ptyfd;
992 
993 	ptyfd = f_get_pty(page);
994 
995   DCMD_ALEXIS(1,(stderr,"ptyfd = %d\n",ptyfd));
996 	if (ptyfd < 0)
997 		return -1;
998 
999 /* store original tty status for restoration clean_exit() -- rgg 04/12/95 */
1000 	lstat(ttydevs[page], &ttyfd_stats[page]);
1001 #ifdef DEBUG_CMD
1002 	DCMD_ALEXIS(1,(stderr,
1003 		"Original settings of %s are mode %o, uid %d, gid %d\n",
1004 		ttydevs[page], ttyfd_stats[page].st_mode, ttyfd_stats[page].st_uid,
1005 		ttyfd_stats[page].st_gid));
1006 #endif
1007 
1008 /*
1009  * get tty settings before fork()
1010  * and make a reasonable guess at the value for BackSpace
1011  */
1012 	get_ttymode(&tio);
1013 
1014   f_scr_reset(page);
1015   tt_winsize(ptyfd);
1016   f_scr_clear(page);
1017   f_scr_touch(page);
1018 
1019 #if 0
1020 /* add Backspace value */
1021 	SavedModes |= (PrivateModes & PrivMode_BackSpace);
1022 #endif
1023 
1024 /* add value for scrollBar */
1025 	if (scrollbar_visible())
1026 	{
1027 		PrivateModes |= PrivMode_scrollBar;
1028 		SavedModes |= PrivMode_scrollBar;
1029 	}
1030 	if (menubar_visible())
1031 	{
1032 		PrivateModes |= PrivMode_menuBar;
1033 		SavedModes |= PrivMode_menuBar;
1034 	}
1035 #ifdef DEBUG_TTYMODE
1036 	debug_ttymode(&tio);
1037 #endif
1038 
1039 /* spin off the command interpreter */
1040 	signal(SIGHUP, Exit_signal);
1041 #ifndef __svr4__
1042 	signal(SIGINT, Exit_signal);
1043 #endif
1044 	signal(SIGQUIT, Exit_signal);
1045 	signal(SIGTERM, Exit_signal);
1046 	signal(SIGCHLD, f_Child_signal);
1047   signal(SIGUSR1, f_update_resources);
1048 
1049 /* need to trap SIGURG for SVR4 (Unixware) rlogin */
1050 /* signal (SIGURG, SIG_DFL); */
1051 
1052 
1053 	cmd_pids[page] = fork();
1054 	if (cmd_pids[page] < 0)
1055 	{
1056 		print_error("can't fork");
1057 		return -1;
1058 	}
1059 	if (cmd_pids[page] == 0)
1060 	{			/* child */
1061 	    /* signal (SIGHUP, Exit_signal); */
1062 	    /* signal (SIGINT, Exit_signal); */
1063 #ifdef HAVE_UNSETENV
1064 	    /* avoid passing old settings and confusing term size */
1065 		unsetenv("LINES");
1066 		unsetenv("COLUMNS");
1067 	    /* avoid passing termcap since terminfo should be okay */
1068 		unsetenv("TERMCAP");
1069 #endif				/* HAVE_UNSETENV */
1070 	    /* establish a controlling teletype for the new session */
1071 		f_get_tty(page);
1072 
1073 	    /* initialize terminal attributes */
1074 		SET_TTYMODE(0, &tio);
1075 
1076 	    /* become virtual console, fail silently */
1077 		if (Options & Opt_console)
1078 		{
1079 #ifdef TIOCCONS
1080 			unsigned int    on = 1;
1081 
1082 			ioctl(0, TIOCCONS, &on);
1083 #elif defined (SRIOCSREDIR)
1084 			int fd = open(CONSOLE, O_WRONLY);
1085 
1086 			if (fd < 0 || ioctl(fd, SRIOCSREDIR, 0) < 0)
1087 			{
1088 				if (fd >= 0)
1089 					close(fd);
1090 			}
1091 #endif				/* SRIOCSREDIR */
1092 		}
1093 		tt_winsize(0);	/* set window size */
1094 
1095     /* reset signals and spin off the command interpreter */
1096 		signal(SIGINT, SIG_DFL);
1097 		signal(SIGQUIT, SIG_DFL);
1098 		signal(SIGCHLD, SIG_DFL);
1099     /*
1100      * mimick login's behavior by disabling the job control signals
1101      * a shell that wants them can turn them back on
1102      */
1103 #ifdef SIGTSTP
1104 		signal(SIGTSTP, SIG_IGN);
1105 		signal(SIGTTIN, SIG_IGN);
1106 		signal(SIGTTOU, SIG_IGN);
1107 #endif				/* SIGTSTP */
1108 
1109 	    /* command interpreter path */
1110 		if (argv != NULL)
1111 		{
1112 #ifdef DEBUG_CMD
1113 			int i;
1114 
1115 			for (i = 0; argv[i]; i++)
1116 				DCMD_ALEXIS(1,(stderr, "argv [%d] = %s\n", i,argv[i]));
1117 #endif
1118 			execvp(argv[0], argv);
1119 			print_error("can't execute \"%s\"", argv[0]);
1120 		} else
1121 		{
1122 			const char     *argv0, *shell;
1123 
1124 			if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1125 				shell = "/bin/sh";
1126 
1127 			argv0 = my_basename(shell);
1128 			if (Options & Opt_loginShell)
1129 			{
1130 				char *p = MALLOC((strlen(argv0) + 2) * sizeof(char));
1131 
1132 				p[0] = '-';
1133 				STRCPY(&p[1], argv0);
1134 				argv0 = p;
1135 			}
1136 			execlp(shell, argv0, NULL);
1137 			print_error("can't execute \"%s\"", shell);
1138     }
1139     exit(EXIT_FAILURE);
1140   }
1141 
1142   return ptyfd;
1143 }
1144 
1145 
1146 /*
1147  * Probe the modifier keymap to get the Meta (Alt) and Num_Lock settings
1148  */
1149 void f_get_ourmods(int page)
1150 {
1151 	int             i, j, k;
1152 	int             got_meta, got_numlock;
1153 	XModifierKeymap *map;
1154 	KeyCode        *kc;
1155 	unsigned int modmasks[] = { Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask };
1156 
1157 	got_meta = got_numlock = 0;
1158 	map = XGetModifierMapping(Xdisplay);
1159 	kc = map->modifiermap;
1160 	for (i = 3; i < 8; i++)
1161 	{
1162 		k = i * map->max_keypermod;
1163 		for (j = 0; j < map->max_keypermod; j++, k++)
1164 		{
1165 			if (kc[k] == 0)
1166 				break;
1167 			switch (XKeycodeToKeysym(Xdisplay, kc[k], 0))
1168 			{
1169 			case XK_Num_Lock:
1170 				if (!got_numlock)
1171 				{
1172 					ModNumLockMask = modmasks[i - 3];
1173 					got_numlock = 1;
1174 				}
1175 				break;
1176 			case XK_Meta_L:
1177 			case XK_Meta_R:
1178 			case XK_Alt_L:
1179 			case XK_Alt_R:
1180 				if (!got_meta)
1181 				{
1182 					ModMetaMask = modmasks[i - 3];
1183 					got_meta = 1;
1184 				}
1185 				break;
1186 			}
1187 		}
1188 		if (got_meta && got_numlock)
1189 			break;
1190 	}
1191 	XFreeModifiermap(map);
1192 }
1193 
1194 /* init_command()
1195  */
1196 void init_command(char *argv[])
1197 {
1198 /*
1199  * Initialize the command connection.
1200  * This should be called after the X server connection is established
1201  * and the top window is created.
1202  */
1203 
1204 /* Enable delete window protocol */
1205 	wmDeleteWindow = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", False);
1206 	XSetWMProtocols(Xdisplay, TermWin.parent, &wmDeleteWindow, 1);
1207 
1208 #ifdef OFFIX_DND
1209 /* Enable OffiX Dnd (drag 'n' drop) protocol */
1210 	DndProtocol = XInternAtom(Xdisplay, "DndProtocol", False);
1211 	DndSelection = XInternAtom(Xdisplay, "DndSelection", False);
1212 #endif				/* OFFIX_DND */
1213 
1214 	init_xlocale();
1215 
1216 /* get number of available file descriptors */
1217 #ifdef _POSIX_VERSION
1218 	num_fds = sysconf(_SC_OPEN_MAX);
1219 #else
1220 	num_fds = getdtablesize();
1221 #endif
1222 
1223 #ifdef META8_OPTION
1224 	meta_char = (Options & Opt_meta8 ? 0x80 : 033);
1225 	if (rs_modifier
1226 	    && strlen(rs_modifier) == 4
1227 	    && toupper(*rs_modifier) == 'M'
1228 	    && toupper(rs_modifier[1]) == 'O'
1229 	    && toupper(rs_modifier[2]) == 'D')
1230 		switch (rs_modifier[3])
1231 		{
1232 		case '2':
1233 			ModXMask = Mod2Mask;
1234 			break;
1235 		case '3':
1236 			ModXMask = Mod3Mask;
1237 			break;
1238 		case '4':
1239 			ModXMask = Mod4Mask;
1240 			break;
1241 		case '5':
1242 			ModXMask = Mod5Mask;
1243 			break;
1244 		default:
1245 			ModXMask = Mod1Mask;
1246 		}
1247 #endif
1248 	f_get_ourmods(0);
1249 	if (Options & Opt_scrollTtyOutputInh)
1250 		PrivateModes |= PrivMode_TtyOutputInh;
1251 	if (Options & Opt_scrollKeypress)
1252 		PrivateModes |= PrivMode_Keypress;
1253 #ifndef NO_BACKSPACE_KEY
1254 	if (strcmp(rs_backspace_key, "DEC") == 0)
1255 		PrivateModes |= PrivMode_HaveBackSpace;
1256 #endif
1257 
1258 #ifdef GREEK_SUPPORT
1259 	greek_init();
1260 #endif
1261 
1262 	Xfd = XConnectionNumber(Xdisplay);
1263 	cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
1264 
1265   vt_died = -1;
1266 
1267 /* install exit handler for cleanup */
1268 #ifdef HAVE_ATEXIT
1269   //atexit(f_clean_exit);
1270 #else
1271 # if defined (__sun__)
1272   //on_exit(f_clean_exit, NULL);	/* non-ANSI exit handler */
1273 # else
1274 # ifdef UTMP_SUPPORT
1275   print_error("no atexit(), UTMP entries can't be cleaned");
1276 #  endif
1277 # endif
1278 #endif
1279 
1280 }
1281 
1282 void f_launch_command(int page,char *argv[]) {
1283 	if ((cmd_fds[page] = f_run_command(page,argv)) < 0)
1284 	{
1285 		print_error("aborting");
1286 		exit(EXIT_FAILURE);
1287   }
1288 #if DEBUG_CMD_ALEXIS
1289   else {
1290     int i;
1291     for(i=0; i <= TermWin.last_page; i++) {
1292       DCMD_ALEXIS(1,(stderr,"cmd_pids[%d] = %d\n",i,cmd_pids[i]));
1293     }
1294   }
1295 #endif
1296 
1297 }
1298 
1299 // restore les privileges, enleve le descripteur et le pid
1300 void pat_destroy_command(int page) {
1301   int i;
1302 
1303   /*
1304    *
1305    */
1306   for(i=page; i < TermWin.last_page; i++) {
1307     cmd_pids[i] = cmd_pids[i+1];
1308     cmd_fds[i] = cmd_fds[i+1];
1309     ptydevs[i] = ptydevs[i+1];
1310     ttydevs[i] = ttydevs[i+1];
1311     ttyfd_stats[i] = ttyfd_stats[i+1];
1312   }
1313 }
1314 
1315 
1316 /* Xlocale
1317  *
1318  * This is more or less stolen straight from XFree86 xterm.
1319  * This should support all European type languages.
1320  */
1321 void init_xlocale(void)
1322 {
1323 #ifndef NO_XLOCALE
1324 	char           *p, *s, buf[32], tmp[1024];
1325 	XIM             xim = NULL;
1326 	XIMStyle        input_style = 0;
1327 	XIMStyles      *xim_styles = NULL;
1328 	int             found;
1329 
1330 	Input_Context = NULL;
1331 
1332 # ifndef NO_SETLOCALE
1333     /* setlocale(LC_CTYPE, ""); */ // XXX: should we do this?
1334 # endif
1335 	if (rs_inputMethod == NULL || !*rs_inputMethod)
1336 	{
1337 		if ((p = XSetLocaleModifiers("")) != NULL && *p)
1338 			xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
1339 	} else
1340 	{
1341 		STRCPY(tmp, rs_inputMethod);
1342 		for (s = tmp; *s; s++)
1343 		{
1344 			char           *end, *next_s;
1345 
1346 			for (; *s && isspace(*s); s++)
1347 			    /* */ ;
1348 			if (!*s)
1349 				break;
1350 			for (end = s; (*end && (*end != ',')); end++)
1351 			    /* */ ;
1352 			for (next_s = end--; ((end >= s) && isspace(*end));
1353 			     end--)
1354 			    /* */ ;
1355 			*++end = '\0';
1356 			if (*s)
1357 			{
1358 				STRCPY(buf, "@im=");
1359 				strcat(buf, s);
1360 				if ((p = XSetLocaleModifiers(buf)) != NULL && *p && (xim =
1361 					XOpenIM(Xdisplay, NULL, NULL,
1362 						NULL)) != NULL)
1363 					break;
1364 			}
1365 			if (!*(s = next_s))
1366 				break;
1367 		}
1368 	}
1369 
1370 	if (xim == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL && *p)
1371 		xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
1372 
1373 	if (xim == NULL)
1374 	{
1375 		print_error("Failed to open input method");
1376 		return;
1377 	}
1378 	if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles)
1379 	{
1380 		print_error("input method doesn't support any style");
1381 		XCloseIM(xim);
1382 		return;
1383 	}
1384 	STRCPY(tmp, (rs_preeditType ? rs_preeditType : "Root"));
1385 	for (found = 0, s = tmp; *s && !found;)
1386 	{
1387 		unsigned short  i;
1388 		char           *end, *next_s;
1389 
1390 		for (; *s && isspace(*s); s++)
1391 		    /* */ ;
1392 		if (!*s)
1393 			break;
1394 		for (end = s; (*end && (*end != ',')); end++)
1395 		    /* */ ;
1396 		for (next_s = end--; ((end >= s) && isspace(*end));)
1397 			*end-- = 0;
1398 
1399 		if (!strcmp(s, "OverTheSpot"))
1400 			input_style = (XIMPreeditPosition | XIMStatusArea);
1401 		else if (!strcmp(s, "OffTheSpot"))
1402 			input_style = (XIMPreeditArea | XIMStatusArea);
1403 		else if (!strcmp(s, "Root"))
1404 			input_style = (XIMPreeditNothing | XIMStatusNothing);
1405 
1406 		for (i = 0; i < xim_styles->count_styles; i++)
1407 			if (input_style == xim_styles->supported_styles[i])
1408 			{
1409 				found = 1;
1410 				break;
1411 			}
1412 		s = next_s;
1413 	}
1414 	XFree(xim_styles);
1415 
1416 	if (found == 0)
1417 	{
1418 		print_error("input method doesn't support my preedit type");
1419 		XCloseIM(xim);
1420 		return;
1421 	}
1422 /*
1423  * This program only understands the Root preedit_style yet
1424  * Then misc.preedit_type should default to:
1425  *          "OverTheSpot,OffTheSpot,Root"
1426  *  /MaF
1427  */
1428 	if (input_style != (XIMPreeditNothing | XIMStatusNothing))
1429 	{
1430 		print_error
1431 		    ("This program only supports the \"Root\" preedit type");
1432 		XCloseIM(xim);
1433 		return;
1434 	}
1435 	Input_Context = XCreateIC(xim, XNInputStyle, input_style,
1436 				  XNClientWindow, TermWin.parent,
1437 				  XNFocusWindow, TermWin.parent, NULL);
1438 //  printf("Input_Context created\n");
1439 	if (Input_Context == NULL)
1440 	{
1441 		print_error("Failed to create input context");
1442 		XCloseIM(xim);
1443 	}
1444 #endif				/* NO_XLOCALE */
1445 }
1446 
1447 
1448 /* window resizing
1449  *
1450  * Tell the teletype handler what size the window is.
1451  * Called after a window size change.
1452  */
1453 void tt_winsize(int fd)
1454 {
1455 	struct winsize  ws;
1456 
1457 	if (fd < 0)
1458 		return;
1459 
1460 	ws.ws_col = (unsigned short)TermWin.ncol;
1461 	ws.ws_row = (unsigned short)TermWin.nrow;
1462 #ifndef __CYGWIN32__
1463 	ws.ws_xpixel = ws.ws_ypixel = 0;
1464 #endif
1465 	ioctl(fd, TIOCSWINSZ, &ws);
1466 }
1467 
1468 void f_tt_resize(int page)
1469 {
1470   tt_winsize(cmd_fds[page]);
1471 }
1472 
1473 
1474 /* Convert the keypress event into a string
1475  */
1476 
1477 void f_lookup_key(XEvent * ev) {
1478 
1479 	static int      numlock_state = 0;
1480 
1481 #if defined(DEBUG_CMD) && defined(DEBUG_CMD_ALEXIS)
1482 	static int      debug_key = 1;	/* accessible by a debugger only */
1483 #endif
1484 #ifdef GREEK_SUPPORT
1485 	static short    greek_mode = 0;
1486 #endif
1487 	static XComposeStatus compose = { NULL, 0 };
1488 	static unsigned char kbuf[KBUFSZ];
1489 	int             ctrl, meta, shft, len;
1490 	KeySym          keysym;
1491 
1492 /*
1493  * use Num_Lock to toggle Keypad on/off.  If Num_Lock is off, allow an
1494  * escape sequence to toggle the Keypad.
1495  *
1496  * Always permit `shift' to override the current setting
1497  */
1498 	shft = (ev->xkey.state & ShiftMask);
1499 	ctrl = (ev->xkey.state & ControlMask);
1500 	meta = (ev->xkey.state & ModXMask);
1501 
1502 	if (numlock_state || (ev->xkey.state & ModNumLockMask))
1503 	{
1504 		numlock_state = (ev->xkey.state & ModNumLockMask);	/* numlock toggle */
1505 		PrivMode((!numlock_state), PrivMode_aplKP);
1506 	}
1507 #ifndef NO_XLOCALE
1508 	if (!XFilterEvent(ev, *(&ev->xkey.window)))
1509 	{
1510 		if (Input_Context != NULL)
1511 		{
1512 			Status          status_return;
1513 
1514 			len = XmbLookupString(Input_Context, &ev->xkey, kbuf,
1515 					      sizeof(kbuf), &keysym,&status_return);
1516 		} else
1517 		{
1518 			len = XLookupString(&ev->xkey, kbuf,sizeof(kbuf), &keysym, &compose);
1519 		}
1520 	} else
1521 		len = 0;
1522 #else				/* NO_XLOCALE */
1523 	len = XLookupString(&ev->xkey, (char *)kbuf, sizeof(kbuf), &keysym, &compose);
1524 /*
1525  * have unmapped Latin[2-4] entries -> Latin1
1526  * good for installations  with correct fonts, but without XLOCAL
1527  */
1528 	if (!len && (keysym >= 0x0100) && (keysym < 0x0400))
1529 	{
1530 		len = 1;
1531 		kbuf[0] = (keysym & 0xFF);
1532 	}
1533 #endif				/* NO_XLOCALE */
1534 
1535 	if (len && (Options & Opt_scrollKeypress))
1536 		TermWin.vts[TermWin.active_page].view_start = 0;
1537 
1538 /* for some backwards compatibility */
1539 #if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
1540 # ifdef HOTKEY_CTRL
1541 #  define HOTKEY	ctrl
1542 # else
1543 #  ifdef HOTKEY_META
1544 #   define HOTKEY	meta
1545 #  endif
1546 # endif
1547 	if (HOTKEY)
1548 	{
1549 		if (keysym == ks_bigfont)
1550 		{
1551 			change_font(0, FONT_UP);
1552 			return;
1553 		} else if (keysym == ks_smallfont)
1554 		{
1555 			change_font(0, FONT_DN);
1556 			return;
1557 		}
1558 	}
1559 # undef HOTKEY
1560 #endif
1561 
1562   /* to add a new terminal, press Ctrl n
1563    */
1564   if( ctrl && !shft && meta) {
1565     if(keysym == XK_n) {
1566       append_page(0);
1567       return;
1568     }
1569   }
1570 
1571 	if (shft)
1572 	{
1573 	    /* Shift + F1 - F10 generates F11 - F20 */
1574 		if (keysym >= XK_F1 && keysym <= XK_F10)
1575 		{
1576 			keysym += (XK_F11 - XK_F1);
1577 			shft = 0;	/* turn off Shift */
1578 		} else if (!ctrl && !meta && (PrivateModes & PrivMode_ShiftKeys))
1579 		{
1580 			int             lnsppg = TermWin.nrow * 4 / 5;
1581 
1582 #ifdef PAGING_CONTEXT_LINES
1583 			lnsppg = TermWin.nrow - PAGING_CONTEXT_LINES;
1584 #endif
1585 
1586 			switch (keysym)
1587 			{
1588 			    /* normal XTerm key bindings */
1589 			case XK_Prior:	/* Shift+Prior = scroll back */
1590 				if (TermWin.vts[TermWin.active_page].saveLines)
1591 				{
1592 					f_scr_page(TermWin.active_page,UP, lnsppg);
1593 					return;
1594 				}
1595 				break;
1596 
1597 			case XK_Up:	/* Shift+XK_Up = scroll up one line */
1598 				if (TermWin.vts[TermWin.active_page].saveLines)
1599 				{
1600 					f_scr_page(TermWin.active_page,UP, 1);
1601 					return;
1602 				}
1603 				break;
1604 
1605 			case XK_Down:	/* Shift+XK_Down = scroll down one line */
1606 				if (TermWin.vts[TermWin.active_page].saveLines)
1607 				{
1608 					f_scr_page(TermWin.active_page,DN, 1);
1609 					return;
1610 				}
1611 				break;
1612 
1613 			case XK_Next:	/* Shift+Next = scroll forward */
1614 				if (TermWin.vts[TermWin.active_page].saveLines)
1615 				{
1616 					f_scr_page(TermWin.active_page,DN, lnsppg);
1617 					return;
1618 				}
1619 				break;
1620 
1621 			case XK_Insert:	/* Shift+Insert = paste mouse selection */
1622 				f_selection_request(TermWin.active_page,ev->xkey.time, ev->xkey.x,ev->xkey.y);
1623 				return;
1624 				break;
1625 
1626 			    /* rxvt extras */
1627 			case XK_KP_Add:	/* Shift+KP_Add = bigger font */
1628 				change_font(0, FONT_UP);
1629 				return;
1630 				break;
1631 
1632 			case XK_KP_Subtract:	/* Shift+KP_Subtract = smaller font */
1633 				change_font(0, FONT_DN);
1634 				return;
1635 				break;
1636 
1637       case XK_Left:	/* Shift+Left = activate prev tab */
1638         DCMD_ALEXIS(1,(stderr,"go on previous vt (%d)\n",
1639           TermWin.active_page == 0 ? TermWin.last_page : TermWin.active_page-1));
1640         if( TermWin.active_page == 0 ) {
1641           page_right_shift(TermWin.last_page);
1642         } else {
1643           if(TermWin.active_page == TermWin.left_page)
1644             page_left_shift(TermWin.left_page-1);
1645         }
1646 				activate_page_num(TermWin.active_page == 0 ? TermWin.last_page : TermWin.active_page-1);
1647 				return;
1648 				break;
1649 
1650       case XK_Right:	/* Shift+Right= activate next tab */
1651         DCMD_ALEXIS(1,(stderr,"go on next vt(%d)\n",
1652           TermWin.active_page == TermWin.last_page ? 0 : TermWin.active_page+1));
1653         if( TermWin.active_page == TermWin.last_page ) {
1654           page_left_shift(0);
1655         } else {
1656           if(TermWin.active_page == TermWin.right_page)
1657             page_right_shift(TermWin.right_page+1);
1658         }
1659 				activate_page_num(TermWin.active_page == TermWin.last_page ? 0 : TermWin.active_page+1);
1660 				return;
1661 				break;
1662 
1663 			}
1664 		}
1665 	} //if (shft)
1666 #ifdef UNSHIFTED_SCROLLKEYS
1667 	else if (!ctrl && !meta)
1668 	{
1669 		switch (keysym)
1670 		{
1671 		case XK_Prior:
1672 			if (TermWin.vts[TermWin.active_page].saveLines)
1673 			{
1674 				f_scr_page(TermWin.active_page,UP, TermWin.nrow * 4 / 5);
1675         scrollbar_show(1);
1676 				return;
1677 			}
1678 			break;
1679 
1680 		case XK_Next:
1681 			if (TermWin.vts[TermWin.active_page].saveLines)
1682 			{
1683 				f_scr_page(TermWin.active_page,DN, TermWin.nrow * 4 / 5);
1684         scrollbar_show(1);
1685 				return;
1686 			}
1687 			break;
1688 		}
1689 	}
1690 #endif
1691 
1692 	switch (keysym)
1693 	{
1694 	case XK_Print:
1695 #ifdef PRINTPIPE
1696 		scr_printscreen(ctrl | shft);
1697 		return;
1698 #endif
1699 		break;
1700 
1701 	case XK_Mode_switch:
1702 #ifdef GREEK_SUPPORT
1703 		greek_mode = !greek_mode;
1704 		if (greek_mode)
1705 		{
1706 			f_xterm_seq(TermWin.active_page,
1707         XTerm_title,(greek_getmode() == GREEK_ELOT928 ? "[Greek: iso]" :"[Greek: ibm]"));
1708 			greek_reset();
1709 		} else
1710 			f_xterm_seq(TermWin.active_page,XTerm_title, APL_NAME "-" VERSION);
1711 		return;
1712 #endif
1713 		break;
1714 	}
1715 
1716 	if (keysym >= 0xFF00 && keysym <= 0xFFFF)
1717 	{
1718 #ifdef KEYSYM_RESOURCE
1719 		if (!(shft | ctrl) && KeySym_map[keysym - 0xFF00] != NULL)
1720 		{
1721 			const unsigned char *kbuf;
1722 			unsigned int    len;
1723 
1724 			kbuf = (KeySym_map[keysym - 0xFF00]);
1725 			len = *kbuf++;
1726 
1727 		    /* escape prefix */
1728 			if (meta
1729 # ifdef META8_OPTION
1730 			    && (meta_char == 033)
1731 # endif
1732 			    )
1733 			{
1734 				const unsigned char ch = '\033';
1735 
1736 				f_tt_write(TermWin.active_page,&ch, 1);
1737 			}
1738 			f_tt_write(TermWin.active_page,kbuf, len);
1739 			return;
1740 		} else
1741 #endif
1742 			switch (keysym)
1743 			{
1744 #ifndef NO_BACKSPACE_KEY
1745 			case XK_BackSpace:
1746 				if (PrivateModes & PrivMode_HaveBackSpace)
1747 				{
1748 					len = 1;
1749 					kbuf[0] =(((PrivateModes & PrivMode_BackSpace) ? !(shft | ctrl) : (shft | ctrl)) ? '\b' :'\177');
1750 				} else
1751 					len = strlen(STRCPY(kbuf, rs_backspace_key));
1752 				break;
1753 #endif
1754 #ifndef NO_DELETE_KEY
1755 			case XK_Delete:
1756 				len = strlen(STRCPY(kbuf, rs_delete_key));
1757 				break;
1758 #endif
1759 			case XK_Tab:
1760 				if (shft)
1761 				{
1762 					len = 3;
1763 					STRCPY(kbuf, "\033[Z");
1764 				}
1765 				break;
1766 
1767 #ifdef XK_KP_Home
1768 			case XK_KP_Home:
1769 			    /* allow shift to override */
1770 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1771 				{
1772 					len = 3;
1773 					STRCPY(kbuf, "\033Ow");
1774 					break;
1775 				}
1776 			    /* -> else FALL THROUGH */
1777 #endif
1778 			case XK_Home:
1779 				len = strlen(STRCPY(kbuf, KS_HOME));
1780         DCMD_ALEXIS(1,(stderr,"HOME\n"));
1781 
1782 				break;
1783 
1784 #ifdef XK_KP_Left
1785 			case XK_KP_Left:	/* \033Ot or standard */
1786 			case XK_KP_Up:	/* \033Ox or standard */
1787 			case XK_KP_Right:	/* \033Ov or standard */
1788 			case XK_KP_Down:	/* \033Or or standard */
1789 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1790 				{
1791 					len = 3;
1792 					STRCPY(kbuf, "\033OZ");
1793 					kbuf[2] = ("txvr"[keysym - XK_KP_Left]);
1794 					break;
1795 				} else
1796 				{
1797 				    /* translate to std. cursor key */
1798 					keysym = XK_Left + (keysym - XK_KP_Left);
1799 				}
1800 			    /* FALL THROUGH */
1801 #endif
1802 			case XK_Left:	/* "\033[D" */
1803 			case XK_Up:	/* "\033[A" */
1804 			case XK_Right:	/* "\033[C" */
1805 			case XK_Down:	/* "\033[B" */
1806 				len = 3;
1807 				STRCPY(kbuf, "\033[@");
1808 				kbuf[2] = ("DACB"[keysym - XK_Left]);
1809 			    /* do Shift first */
1810 				if (shft)
1811 				{
1812 					kbuf[2] = ("dacb"[keysym - XK_Left]);
1813 				} else if (ctrl)
1814 				{
1815 					kbuf[1] = 'O';
1816 					kbuf[2] = ("dacb"[keysym - XK_Left]);
1817 				} else if (PrivateModes & PrivMode_aplCUR)
1818 				{
1819 					kbuf[1] = 'O';
1820 				}
1821 				break;
1822 
1823 #ifndef UNSHIFTED_SCROLLKEYS
1824 # ifdef XK_KP_Prior
1825 			case XK_KP_Prior:
1826 			    /* allow shift to override */
1827 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1828 				{
1829 					len = 3;
1830 					STRCPY(kbuf, "\033Oy");
1831 					break;
1832 				}
1833 			    /* -> else FALL THROUGH */
1834 # endif
1835 			case XK_Prior:
1836 				len = 4;
1837 				STRCPY(kbuf, "\033[5~");
1838 				break;
1839 # ifdef XK_KP_Next
1840 			case XK_KP_Next:
1841 			    /* allow shift to override */
1842 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1843 				{
1844 					len = 3;
1845 					STRCPY(kbuf, "\033Os");
1846 					break;
1847 				}
1848 			    /* -> else FALL THROUGH */
1849 # endif
1850 			case XK_Next:
1851 				len = 4;
1852 				STRCPY(kbuf, "\033[6~");
1853 				break;
1854 #endif
1855 #ifdef XK_KP_End
1856 			case XK_KP_End:
1857 			    /* allow shift to override */
1858 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1859 				{
1860 					len = 3;
1861 					STRCPY(kbuf, "\033Oq");
1862 					break;
1863 				}
1864 			    /* -> else FALL THROUGH */
1865 #endif
1866 			case XK_End:
1867 				len = strlen(STRCPY(kbuf, KS_END));
1868         DCMD_ALEXIS(1,(stderr,"END\n"));
1869 				break;
1870 
1871 			case XK_Select:
1872 				len = 4;
1873 				STRCPY(kbuf, "\033[4~");
1874 				break;
1875 #ifdef DXK_Remove		/* support for DEC remove like key */
1876 			case DXK_Remove:	/* drop */
1877 #endif
1878 			case XK_Execute:
1879 				len = 4;
1880 				STRCPY(kbuf, "\033[3~");
1881 				break;
1882 			case XK_Insert:
1883 				len = 4;
1884 				STRCPY(kbuf, "\033[2~");
1885 				break;
1886 
1887 			case XK_Menu:
1888 				len = 5;
1889 				STRCPY(kbuf, "\033[29~");
1890 				break;
1891 			case XK_Find:
1892 				len = 4;
1893 				STRCPY(kbuf, "\033[1~");
1894 				break;
1895 			case XK_Help:
1896 				len = 5;
1897 				STRCPY(kbuf, "\033[28~");
1898 				break;
1899 
1900 			case XK_KP_Enter:
1901 			    /* allow shift to override */
1902 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1903 				{
1904 					len = 3;
1905 					STRCPY(kbuf, "\033OM");
1906 				} else
1907 				{
1908 					len = 1;
1909 					kbuf[0] = '\r';
1910 				}
1911 				break;
1912 
1913 #ifdef XK_KP_Begin
1914 			case XK_KP_Begin:
1915 				len = 3;
1916 				STRCPY(kbuf, "\033Ou");
1917 				break;
1918 
1919 			case XK_KP_Insert:
1920 				len = 3;
1921 				STRCPY(kbuf, "\033Op");
1922 				break;
1923 
1924 			case XK_KP_Delete:
1925 				len = 3;
1926 				STRCPY(kbuf, "\033On");
1927 				break;
1928 #endif
1929 
1930 			case XK_KP_F1:	/* "\033OP" */
1931 			case XK_KP_F2:	/* "\033OQ" */
1932 			case XK_KP_F3:	/* "\033OR" */
1933 			case XK_KP_F4:	/* "\033OS" */
1934 				len = 3;
1935 				STRCPY(kbuf, "\033OP");
1936 				kbuf[2] += (keysym - XK_KP_F1);
1937 				break;
1938 
1939 			case XK_KP_Multiply:	/* "\033Oj" : "*" */
1940 			case XK_KP_Add:	/* "\033Ok" : "+" */
1941 			case XK_KP_Separator:	/* "\033Ol" : "," */
1942 			case XK_KP_Subtract:	/* "\033Om" : "-" */
1943 			case XK_KP_Decimal:	/* "\033On" : "." */
1944 			case XK_KP_Divide:	/* "\033Oo" : "/" */
1945 			case XK_KP_0:	/* "\033Op" : "0" */
1946 			case XK_KP_1:	/* "\033Oq" : "1" */
1947 			case XK_KP_2:	/* "\033Or" : "2" */
1948 			case XK_KP_3:	/* "\033Os" : "3" */
1949 			case XK_KP_4:	/* "\033Ot" : "4" */
1950 			case XK_KP_5:	/* "\033Ou" : "5" */
1951 			case XK_KP_6:	/* "\033Ov" : "6" */
1952 			case XK_KP_7:	/* "\033Ow" : "7" */
1953 			case XK_KP_8:	/* "\033Ox" : "8" */
1954 			case XK_KP_9:	/* "\033Oy" : "9" */
1955 			    /* allow shift to override */
1956 				if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
1957 				{
1958 					len = 3;
1959 					STRCPY(kbuf, "\033Oj");
1960 					kbuf[2] += (keysym - XK_KP_Multiply);
1961 				} else
1962 				{
1963 					len = 1;
1964 					kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
1965 				}
1966 				break;
1967 
1968 #define FKEY(n, fkey)							\
1969     len = 5;								\
1970     sprintf((char *) kbuf,"\033[%02d~", (int)((n) + (keysym - fkey)))
1971 
1972 			case XK_F1:	/* "\033[11~" */
1973 			case XK_F2:	/* "\033[12~" */
1974 			case XK_F3:	/* "\033[13~" */
1975 			case XK_F4:	/* "\033[14~" */
1976 			case XK_F5:	/* "\033[15~" */
1977 				FKEY(11, XK_F1);
1978 				break;
1979 
1980 			case XK_F6:	/* "\033[17~" */
1981 			case XK_F7:	/* "\033[18~" */
1982 			case XK_F8:	/* "\033[19~" */
1983 			case XK_F9:	/* "\033[20~" */
1984 			case XK_F10:	/* "\033[21~" */
1985 				FKEY(17, XK_F6);
1986 				break;
1987 
1988 			case XK_F11:	/* "\033[23~" */
1989 			case XK_F12:	/* "\033[24~" */
1990 			case XK_F13:	/* "\033[25~" */
1991 			case XK_F14:	/* "\033[26~" */
1992 				FKEY(23, XK_F11);
1993 				break;
1994 
1995 			case XK_F15:	/* "\033[28~" */
1996 			case XK_F16:	/* "\033[29~" */
1997 				FKEY(28, XK_F15);
1998 				break;
1999 
2000 			case XK_F17:	/* "\033[31~" */
2001 			case XK_F18:	/* "\033[32~" */
2002 			case XK_F19:	/* "\033[33~" */
2003 			case XK_F20:	/* "\033[34~" */
2004 			case XK_F21:	/* "\033[35~" */
2005 			case XK_F22:	/* "\033[36~" */
2006 			case XK_F23:	/* "\033[37~" */
2007 			case XK_F24:	/* "\033[38~" */
2008 			case XK_F25:	/* "\033[39~" */
2009 			case XK_F26:	/* "\033[40~" */
2010 			case XK_F27:	/* "\033[41~" */
2011 			case XK_F28:	/* "\033[42~" */
2012 			case XK_F29:	/* "\033[43~" */
2013 			case XK_F30:	/* "\033[44~" */
2014 			case XK_F31:	/* "\033[45~" */
2015 			case XK_F32:	/* "\033[46~" */
2016 			case XK_F33:	/* "\033[47~" */
2017 			case XK_F34:	/* "\033[48~" */
2018 			case XK_F35:	/* "\033[49~" */
2019 				FKEY(31, XK_F17);
2020 				break;
2021 #undef FKEY
2022 			}
2023 	    /*
2024 	     * Pass meta for all function keys, if 'meta' option set
2025 	     */
2026 #ifdef META8_OPTION
2027 		if (meta && (meta_char == 0x80) && len > 0)
2028 		{
2029 			kbuf[len - 1] |= 0x80;
2030 		}
2031 #endif
2032 	} else if (ctrl && keysym == XK_minus)
2033 	{
2034 		len = 1;
2035 		kbuf[0] = '\037';	/* Ctrl-Minus generates ^_ (31) */
2036 	} else
2037 	{
2038 #ifdef META8_OPTION
2039 	    /* set 8-bit on */
2040 		if (meta && (meta_char == 0x80))
2041 		{
2042 			unsigned char  *ch;
2043 
2044 			for (ch = kbuf; ch < kbuf + len; ch++)
2045 				*ch |= 0x80;
2046 			meta = 0;
2047 		}
2048 #endif
2049 #ifdef GREEK_SUPPORT
2050 		if (greek_mode)
2051 			len = greek_xlat(kbuf, len);
2052 #endif
2053 	    /* nil */ ;
2054 	}
2055 
2056 	if (len <= 0) {
2057 		return;		/* not mapped */
2058   }
2059 
2060 /*
2061  * these modifications only affect the static keybuffer
2062  * pass Shift/Control indicators for function keys ending with `~'
2063  *
2064  * eg,
2065  *   Prior = "ESC[5~"
2066  *   Shift+Prior = "ESC[5~"
2067  *   Ctrl+Prior = "ESC[5^"
2068  *   Ctrl+Shift+Prior = "ESC[5@"
2069  * Meta adds an Escape prefix (with META8_OPTION, if meta == <escape>).
2070  */
2071 	if (kbuf[0] == '\033' && kbuf[1] == '[' && kbuf[len - 1] == '~')
2072 		kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
2073 
2074 /* escape prefix */
2075 	if (meta
2076 #ifdef META8_OPTION
2077 	    && (meta_char == 033)
2078 #endif
2079 	    )
2080 	{
2081 		const unsigned char ch = '\033';
2082 
2083     DCMD_ALEXIS(1,(stderr,"Writing to terminal %d\n",TermWin.active_page));
2084 		f_tt_write(TermWin.active_page,&ch, 1);
2085 	}
2086 #if DEBUG_CMD && DEBUG_CMD_ALEXIS
2087 	if (debug_key)
2088 	{			/* Display keyboard buffer contents */
2089 		char           *p;
2090 		int             i;
2091 
2092 		fprintf(stderr, "key 0x%04X [%d]: `", (unsigned int)keysym,len);
2093 		for (i = 0, p = kbuf; i < len; i++, p++)
2094 			fprintf(stderr,(*p >= ' ' && *p < '\177' ? "%c" : "\\%03o"), *p);
2095 		fprintf(stderr, "'\n");
2096 	}
2097 #endif				/* DEBUG_CMD */
2098 	f_tt_write(TermWin.active_page,kbuf, len);
2099 }
2100 
2101 /*}}} */
2102 
2103 #if (MENUBAR_MAX)
2104 /* cmd_write(), cmd_getc() */
2105 /* attempt to `write' COUNT to the input buffer */
2106 
2107 unsigned int
2108 cmd_write(const unsigned char *str, unsigned int count)
2109 {
2110 	int             n;
2111 
2112 	n = (count - (cmdbuf_ptr - cmdbuf_base));
2113 /* need to insert more chars that space available in the front */
2114 	if (n > 0)
2115 	{
2116 	    /* try and get more space from the end */
2117 		unsigned char  *src, *dst;
2118 
2119 		dst = (cmdbuf_base + sizeof(cmdbuf_base) - 1);	/* max pointer */
2120 
2121 		if ((cmdbuf_ptr + n) > dst)
2122 			n = (dst - cmdbuf_ptr);	/* max # chars to insert */
2123 
2124 		if ((cmdbuf_endp + n) > dst)
2125 			cmdbuf_endp = (dst - n);	/* truncate end if needed */
2126 
2127 	    /* equiv: memmove ((cmdbuf_ptr+n), cmdbuf_ptr, n); */
2128 		src = cmdbuf_endp;
2129 		dst = src + n;
2130 	    /* FIXME: anything special to avoid possible pointer wrap? */
2131 		while (src >= cmdbuf_ptr)
2132 			*dst-- = *src--;
2133 
2134 	    /* done */
2135 		cmdbuf_ptr += n;
2136 		cmdbuf_endp += n;
2137 	}
2138 	while (count-- && cmdbuf_ptr > cmdbuf_base)
2139 	{
2140 	    /* sneak one in */
2141 		cmdbuf_ptr--;
2142 		*cmdbuf_ptr = str[count];
2143 	}
2144 
2145 	return 0;
2146 }
2147 #endif				/* MENUBAR_MAX */
2148 /* cmd_getc() - Return next input character */
2149 /*
2150  * Return the next input character after first passing any keyboard input
2151  * to the command.
2152  */
2153 /* PROTO */
2154 unsigned char
2155 f_cmd_getc(void)
2156 {
2157 #define TIMEOUT_USEC	5000
2158 	static short    refreshed = 0;
2159 	fd_set          readfds;
2160 	int             retval;
2161   int i;
2162 
2163 #ifdef __CYGWIN32__
2164 	struct timeval  value;
2165 #else
2166 	struct itimerval value;
2167 #endif
2168 
2169 /* If there have been a lot of new lines, then update the screen
2170  * What the heck I'll cheat and only refresh less than every page-full.
2171  * the number of pages between refreshes is refresh_limit, which
2172  * is incremented here because we must be doing flat-out scrolling.
2173  *
2174  * refreshing should be correct for small scrolls, because of the
2175  * time-out */
2176 	if (refresh_count >= (refresh_limit * (TermWin.nrow - 1)) )
2177 	{
2178 		if (refresh_limit < REFRESH_PERIOD)
2179 			refresh_limit++;
2180 		refresh_count = 0;
2181 		refreshed = 1;
2182 		f_scr_refresh(TermWin.active_page,refresh_type);
2183 	}
2184 /* characters already read in */
2185 	if (cmdbuf_ptr < cmdbuf_endp)
2186 		goto Return_Char;
2187 
2188   /* check if we should destroy a vt
2189   */
2190   if( vt_died >= 0 ) {
2191     char buff[1024];
2192     DCMD_ALEXIS(1,(stderr,"child %d died\n",cmd_pids[vt_died]));
2193 
2194     // read last char of the descriptor
2195     while( read(cmd_fds[vt_died], buff, 1024) > 0);
2196     // now, destroy associated struct to this vt
2197     remove_page(vt_died);
2198     vt_died=-1;
2199   }
2200 
2201 	for (;;)
2202 	{
2203 		if (v_bufstr < v_bufptr)	/* output any pending chars */
2204 			f_tt_write(TermWin.active_page,NULL, 0);
2205 		while (XPending(Xdisplay))
2206 		{		/* process pending X events */
2207 			XEvent          ev;
2208 			refreshed = 0;
2209 			XNextEvent(Xdisplay, &ev);
2210 			process_x_event(&ev);
2211 
2212 
2213 		    /* in case button actions pushed chars to cmdbuf */
2214 			if (cmdbuf_ptr < cmdbuf_endp)
2215 				goto Return_Char;
2216 		}
2217 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2218 		if (scrollbar_isUp())
2219 		{
2220 			if (!scroll_arrow_delay-- && f_scr_page(TermWin.active_page,UP, 1))
2221 			{
2222 				scroll_arrow_delay =  SCROLLBAR_CONTINUOUS_DELAY;
2223 				refreshed = 0;
2224 				refresh_type |= SMOOTH_REFRESH;
2225 			}
2226 		} else if (scrollbar_isDn())
2227 		{
2228 			if (!scroll_arrow_delay-- && f_scr_page(TermWin.active_page,DN, 1))
2229 			{
2230 				scroll_arrow_delay = SCROLLBAR_CONTINUOUS_DELAY;
2231 				refreshed = 0;
2232 				refresh_type |= SMOOTH_REFRESH;
2233 			}
2234 		}
2235 #endif				/* NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING */
2236 
2237 	    /* Nothing to do! */
2238 		FD_ZERO(&readfds);
2239     for(i=0; i <= TermWin.last_page; i++) {
2240       FD_SET(cmd_fds[i], &readfds);
2241     }
2242 		FD_SET(Xfd, &readfds);
2243 #ifdef __CYGWIN32__
2244 		value.tv_usec = TIMEOUT_USEC;
2245 		value.tv_sec = 0;
2246 #else
2247 		value.it_value.tv_usec = TIMEOUT_USEC;
2248 		value.it_value.tv_sec = 0;
2249 #endif
2250 
2251 		retval = select(num_fds, &readfds, NULL, NULL, ((refreshed
2252 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2253 	&& !(scrollbar_isUpDn())
2254 #endif
2255 #ifdef __CYGWIN32__
2256 								)? NULL :	&value));
2257 #else
2258 								)? NULL :	&value.it_value));
2259 #endif
2260 
2261 	    /* See if we can read from the application */
2262     for(i=0; i <= TermWin.last_page && !FD_ISSET(cmd_fds[i],&readfds); i++);
2263 
2264     fd_read = i;
2265 
2266 		if (i <= TermWin.last_page )
2267 //    if (FD_ISSET(cmd_fds[0], &readfds))
2268 		{
2269 			unsigned int    count = BUFSIZ;
2270       int n;
2271 
2272       DCMD_ALEXIS(1,(stderr,"reading from shell(%d)\n",i));
2273 			cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
2274 
2275 		    /* while (count > sizeof(cmdbuf_base) / 2) */
2276       // on decremente count du nbr de char qu'on a lut avec read
2277 			while (count)
2278 			{
2279 				n = read(cmd_fds[i], cmdbuf_endp, count);
2280 
2281 				if (n <= 0) {
2282 					break;
2283         }
2284 				cmdbuf_endp += n;
2285 				count -= n;
2286 			}
2287 //      printf("COUNT: %d\n",count);
2288 		    /* some characters read in */
2289 			if (count != BUFSIZ) {
2290 //        DCMD_ALEXIS(1,(stderr,"f_cmd_getc, %d char reads\n",BUFSIZ-count));
2291 				goto Return_Char;
2292       }
2293 		}
2294     /* check if a child died */
2295     if( vt_died >= 0 ) {
2296       /* yes, return something */
2297 //      ++cmdbuf_endp;
2298       *cmdbuf_endp = ' ';
2299       goto Return_Char;
2300     }
2301 	    /* select statement timed out - better update the screen */
2302 		if (retval == 0)
2303 		{
2304 			refresh_count = 0;
2305 			refresh_limit = 1;
2306 			if (!refreshed)
2307 			{
2308 				refreshed = 1;
2309         if( TermWin.last_page >= 0 ) {
2310           f_scr_refresh(TermWin.active_page,refresh_type);
2311           scrollbar_show(1);
2312         }
2313 			}
2314 		}
2315 	}
2316   /* NOTREACHED */
2317 	return 0;
2318 
2319     Return_Char:
2320 	refreshed = 0;
2321 /*  tmp = strndup(cmdbuf_ptr,cmdbuf_endp-cmdbuf_ptr);
2322   tmp[cmdbuf_endp-cmdbuf_ptr] = 0;
2323   for(i=0; i < strlen(tmp); i++) {
2324     printf("cmdbuf: %o,%c\n",tmp[i],tmp[i]);
2325   }
2326 */
2327 	return (*cmdbuf_ptr++);
2328 }
2329 
2330 
2331 /*
2332  * the 'essential' information for reporting Mouse Events
2333  * pared down from XButtonEvent
2334  */
2335 static struct
2336 {
2337 	int             clicks;
2338 	Time            time;	/* milliseconds */
2339 	unsigned int    state;	/* key or button mask */
2340 	unsigned int    button;	/* detail */
2341 } MEvent = {0, CurrentTime, 0, AnyButton};
2342 
2343 /* PROTO */
2344 void
2345 mouse_report(XButtonEvent * ev)
2346 {
2347 	int             button_number, key_state = 0;
2348 	int             x, y;
2349 
2350 	x = ev->x;
2351 	y = ev->y;
2352 	pixel_position(&x, &y);
2353 
2354 	button_number = ((MEvent.button == AnyButton) ? 3 : (MEvent.button - Button1));
2355 
2356 	if (PrivateModes & PrivMode_MouseX10)
2357 	{
2358 	    /*
2359 	     * do not report ButtonRelease
2360 	     * no state info allowed
2361 	     */
2362 		key_state = 0;
2363 		if (button_number == 3)
2364 			return;
2365 	} else
2366 	{
2367 	    /* let's be explicit here ... from <X11/X.h>
2368 	     * #define ShiftMask        (1<<0)
2369 	     * #define ControlMask        (1<<2)
2370 	     * #define Mod1Mask           (1<<3)
2371 	     *
2372 	     * and XTerm mouse reporting needs these values:
2373 	     *   4 = Shift
2374 	     *   8 = Meta
2375 	     *  16 = Control
2376 	     * plus will add in our own Double-Click reporting
2377 	     *  32 = Double Click
2378 	     */
2379 		key_state = (((MEvent.state & (ShiftMask | ControlMask)) + ((MEvent.state & Mod1Mask) ? 2 : 0)
2380 #ifdef MOUSE_REPORT_DOUBLECLICK
2381 			      + (MEvent.clicks > 1 ? 8 : 0)
2382 #endif
2383 			     ) << 2);
2384 	}
2385 
2386 #ifdef DEBUG_MOUSEREPORT
2387 	fprintf(stderr, "Mouse [");
2388 	if (key_state & 16)
2389 		fputc('C', stderr);
2390 	if (key_state & 4)
2391 		fputc('S', stderr);
2392 	if (key_state & 2)
2393 		fputc('A', stderr);
2394 	if (key_state & 32)
2395 		fputc('2', stderr);
2396 	fprintf(stderr, "]: <%d>, %d/%d\n", button_number, x + 1, y + 1);
2397 #else
2398 	tt_printf((unsigned char *)"\033[M%c%c%c",
2399 		  (32 + button_number + key_state),
2400 		  (32 + x + 1), (32 + y + 1));
2401 #endif
2402 }
2403 
2404 /*{{{ process an X event */
2405 /* PROTO */
2406 void
2407 process_x_event(XEvent * ev)
2408 {
2409 	static int      bypass_keystate = 0;
2410 	int             reportmode;
2411 	static int      csrO = 0;	/* Hops - csr offset in thumb/slider      */
2412 
2413 
2414 /*        to give proper Scroll behaviour */
2415 	switch (ev->type)
2416 	{
2417 	case KeyPress:
2418       f_lookup_key(ev);
2419 		break;
2420 
2421 	case ClientMessage:
2422 		if (ev->xclient.format == 32 && ev->xclient.data.l[0] == wmDeleteWindow)
2423 			exit(EXIT_SUCCESS);
2424 #ifdef OFFIX_DND
2425 	    /* OffiX Dnd (drag 'n' drop) protocol */
2426 		if (ev->xclient.message_type == DndProtocol &&
2427 		    ((ev->xclient.data.l[0] == DndFile) ||
2428 		     (ev->xclient.data.l[0] == DndDir) ||
2429 		     (ev->xclient.data.l[0] == DndLink)))
2430 		{
2431 		    /* Get Dnd data */
2432 			Atom            ActualType;
2433 			int             ActualFormat;
2434 			unsigned char  *data;
2435 			unsigned long   Size, RemainingBytes;
2436 
2437 			XGetWindowProperty(Xdisplay, Xroot,
2438 					   DndSelection,
2439 					   0L, 1000000L,
2440 					   False, AnyPropertyType,
2441 					   &ActualType, &ActualFormat,
2442 					   &Size, &RemainingBytes, &data);
2443 			XChangeProperty(Xdisplay, Xroot,
2444 					XA_CUT_BUFFER0, XA_STRING,
2445 					8, PropModeReplace,
2446 					data, strlen(data));
2447 			selection_paste(Xroot, XA_CUT_BUFFER0, True);
2448 			XSetInputFocus(Xdisplay, Xroot, RevertToNone,
2449 				       CurrentTime);
2450 		}
2451 #endif				/* OFFIX_DND */
2452 		break;
2453 
2454 	case MappingNotify:
2455 		XRefreshKeyboardMapping(&(ev->xmapping));
2456 		break;
2457 
2458 	    /* Here's my conclusiion:
2459 	     * If the window is completely unobscured, use bitblt's
2460 	     * to scroll. Even then, they're only used when doing partial
2461 	     * screen scrolling. When partially obscured, we have to fill
2462 	     * in the GraphicsExpose parts, which means that after each refresh,
2463 	     * we need to wait for the graphics expose or Noexpose events,
2464 	     * which ought to make things real slow!
2465 	     */
2466 	case VisibilityNotify:
2467 		switch (ev->xvisibility.state)
2468 		{
2469 		case VisibilityUnobscured:
2470 			refresh_type = FAST_REFRESH;
2471 			break;
2472 
2473 		case VisibilityPartiallyObscured:
2474 			refresh_type = SLOW_REFRESH;
2475 			break;
2476 
2477 		default:
2478 			refresh_type = NO_REFRESH;
2479 			break;
2480 		}
2481 		break;
2482 
2483 	case FocusIn:
2484 		if (!TermWin.focus )
2485 		{
2486 			TermWin.focus = 1;
2487 
2488 #ifdef OFF_FOCUS_FADING
2489 			if (rs_fade != NULL)
2490 			{
2491 				PixColors = &(PixColorsFocused[0]);
2492 				f_on_colors_changed(TermWin.active_page,Color_bg);
2493 			}
2494 #endif
2495 #ifndef NO_XLOCALE
2496 			if (Input_Context != NULL)
2497 				XSetICFocus(Input_Context);
2498 #endif
2499 		}
2500 		break;
2501 
2502 	case FocusOut:
2503 		if (TermWin.focus )
2504 		{
2505       TermWin.focus = 0;
2506 
2507 #ifdef OFF_FOCUS_FADING
2508 			if (rs_fade != NULL)
2509 			{
2510 				PixColors = &(PixColorsUnFocused[0]);
2511 				f_on_colors_changed(TermWin.active_page,Color_bg);
2512 			}
2513 #endif
2514 #ifndef NO_XLOCALE
2515 			if (Input_Context != NULL)
2516 				XUnsetICFocus(Input_Context);
2517 #endif
2518 		}
2519 		break;
2520 
2521 	case ConfigureNotify:
2522 
2523       DCMD_ALEXIS(1,(stderr,"configureNofify event\n"));
2524       resize_thumb_bar(ev);
2525     if( TermWin.last_page >= 0 ) {
2526       resize_window(ev);
2527       menubar_expose();
2528     }
2529 		break;
2530 
2531 	case SelectionClear:
2532     DCMD_ALEXIS(1,(stderr,"SelectionClear\n"));
2533 		selection_clear();
2534 		break;
2535 
2536 	case SelectionNotify:
2537     DCMD_ALEXIS(1,(stderr,"SelectionNotify\n"));
2538 		selection_paste(ev->xselection.requestor,ev->xselection.property, True);
2539 		break;
2540 
2541 	case SelectionRequest:
2542     DCMD_ALEXIS(1,(stderr,"SelectionRequest\n"));
2543 		selection_send(&(ev->xselectionrequest));
2544 		break;
2545 
2546 	case PropertyNotify:
2547     DCMD_ALEXIS(1,(stderr,"propertyNotify event\n"));
2548 #ifdef _MYSTYLE_
2549 		if (ev->xproperty.atom == _AS_STYLE)
2550 		{
2551 			const char     *mystyle_name;
2552 			MyStyle        *mystyle;
2553 
2554 			if (rs_mystyle)
2555 				mystyle_name = rs_mystyle;
2556 			else
2557 				mystyle_name = GetDefaultMyStyle();
2558 
2559 			mystyle_get_property(Xdisplay, Xroot, _AS_STYLE,XA_INTEGER);
2560 
2561 			set_mystyle(mystyle_find(mystyle_name), True);
2562 			break;
2563 		} else if (TermWin.vts[TermWin.active_page].bg.trgType == BGT_MyStyle &&
2564 			   TermWin.vts[0].bg.mystyle->texture_type < TEXTURE_TRANSPARENT)
2565 			break;
2566 #endif
2567 #ifdef TRANSPARENT
2568 		refresh_transparent_scrollbar();
2569 		if (Options & Opt_transparent)
2570     //if (Options & TermWin.vts[TermWin.active_page].bg.transparent)
2571 		{
2572 		    /* if user used some Esetroot compatible prog to set the root
2573 		     * bg, use the property to determine that. We don't use it's
2574 		     * value, though */
2575 
2576 			static Atom     atom = None;
2577 
2578 			if (atom == None)
2579 				atom = XInternAtom(Xdisplay, "_XROOTPMAP_ID",True);
2580 
2581 			if (!atom)
2582 			{
2583 				f_SetSrcPixmap(TermWin.active_page,None);
2584 			} else if (ev->xproperty.atom == atom)
2585 			{
2586 				static Pixmap   LastRPixmap = None;
2587 				Pixmap          currentRPixmap = GetRootPixmap(atom);
2588 
2589 				if (currentRPixmap != None)
2590 				{
2591 					if (LastRPixmap != currentRPixmap && TermWin.vts[TermWin.active_page].bMapped
2592 					    && f_GetMyPosition(TermWin.active_page,NULL, NULL))
2593 					{
2594 	DCMD_ALEXIS(1,(stderr, "\n Root pixmap has changed\n"));
2595 						if (TermWin.vts[TermWin.active_page].bg.trgType != BGT_None)
2596 						{
2597 							f_SetSrcPixmap(TermWin.active_page,currentRPixmap);
2598 							f_RenderPixmap(TermWin.active_page,1);
2599 						    /* don't want to check if pixmap is valid
2600 						     * it's unlikely that user would set it to
2601 						     * something bogus. */
2602 						}
2603 						f_scr_clear(TermWin.active_page);
2604 						f_scr_touch(TermWin.active_page);
2605 					}
2606 				} else
2607 				{
2608 					f_SetSrcPixmap(TermWin.active_page,None);
2609 			DCMD_ALEXIS(1,( stderr, "aterm's root background set to None\n"));
2610 				}
2611 			    /* we want to preserve old pixmap ID so we can check on it
2612 			     * when window is mapped back */
2613 				if (TermWin.vts[TermWin.active_page].bMapped)
2614 					LastRPixmap = currentRPixmap;
2615 			}
2616 		}		/* case */
2617 #endif				/* TRANSPARENT */
2618 		break;
2619 	case UnmapNotify:
2620     if( TermWin.last_page >= 0 ) {
2621       DCMD_ALEXIS(1,(stderr, "aterm vt[%d] is UnMapped(event)\n",TermWin.active_page));
2622       TermWin.vts[TermWin.active_page].bMapped = 0;
2623     }
2624 		break;
2625 
2626 	case MapNotify:
2627     if( TermWin.last_page >= 0 ) {
2628       DCMD_ALEXIS(1,(stderr, "aterm vt[%d] is %s\n",
2629         TermWin.active_page,
2630         (TermWin.vts[TermWin.active_page].bMapped)?"Mapped":"UnMapped")
2631       );
2632 
2633       TermWin.vts[TermWin.active_page].bMapped = 1;
2634 #ifdef TRANSPARENT
2635       refresh_transparent_scrollbar();
2636       if (Options & Opt_transparent)
2637       //if (Options & TermWin.vts[TermWin.active_page].bg.transparent)
2638       {
2639         Pixmap tmp = GetRootPixmap(None);
2640 
2641         if (tmp != TermWin.vts[TermWin.active_page].bg.srcPixmap
2642             && TermWin.vts[TermWin.active_page].bg.srcPixmap != None) {
2643 
2644           if (TermWin.vts[TermWin.active_page].bg.trgType != BGT_None) {
2645             f_SetSrcPixmap(TermWin.active_page,tmp);
2646             f_RenderPixmap(TermWin.active_page,0);
2647           }
2648           f_scr_clear(TermWin.active_page);
2649           f_scr_touch(TermWin.active_page);
2650         }
2651       }
2652 #endif
2653     }
2654 		break;
2655 
2656 	case ReparentNotify:
2657 #ifdef TRANSPARENT
2658 	{
2659 		int n;
2660 		XWindowAttributes attr;
2661 		int (*oldXErrorHandler) (Display *, XErrorEvent *) =
2662       XSetErrorHandler(pixmap_error_handler);
2663 
2664 		for (n = 1; n < PARENTS_NUM; n++)
2665 			ParentWin[n] = None;
2666 	    /*
2667 	     * Make the frame window set by the window manager have
2668 	     * the root background. Some window managers put few nested frame
2669 	     * windows for each client, so we have to take care about that.
2670 	     */
2671 		for (ParentWinNum = 1; ParentWinNum < PARENTS_NUM; ParentWinNum++)
2672 		{
2673 			Window          root;
2674 			Window          parent;
2675 			Window         *list;
2676 
2677 			XQueryTree(Xdisplay, ParentWin[ParentWinNum - 1], &root, &parent, &list, &n);
2678 			XFree(list);
2679 			if (parent == Xroot)
2680 				break;
2681 			ParentWin[ParentWinNum] = parent;
2682 		    /* we want to get all map/unmap events from this window as well */
2683 		    /*      XSelectInput(Xdisplay, parent, StructureNotifyMask); */
2684 
2685 			if (Options & Opt_transparent)
2686       //if (Options & TermWin.vts[TermWin.active_page].bg.transparent)
2687 				XSetWindowBackgroundPixmap(Xdisplay, parent,ParentRelative);
2688 		}
2689 		if (XGetWindowAttributes(Xdisplay, ParentWin[0], &attr) && TermWin.last_page >= 0)
2690 			TermWin.vts[TermWin.active_page].bMapped = (attr.map_state == IsViewable) ? 1 : 0;
2691 
2692 		XSetErrorHandler(oldXErrorHandler);
2693     if( TermWin.last_page >= 0 )
2694       f_scr_clear(TermWin.active_page);
2695 	}
2696 #endif				/* TRANSPARENT */
2697 		break;
2698 	case GraphicsExpose:
2699 	case Expose:
2700     DCMD_ALEXIS(1,(stderr,"expose event\n"));
2701   {
2702       if (ev->xany.window == TermWin.vts[TermWin.active_page].vt)
2703     //    if( i <= TermWin.last_page && vt)
2704       {
2705           DCMD_ALEXIS(1,(stderr,"[%s]expose event on vt[%d]\n",__FILE__,TermWin.active_page));
2706           f_scr_expose(TermWin.active_page,ev->xexpose.x, ev->xexpose.y,ev->xexpose.width, ev->xexpose.height);
2707 #ifdef DRAW_THUMBBAR
2708       } else if (TermWin.thumb_bar == ev->xany.window) {
2709           // redraw the thumb_bar
2710           thumb_bar_expose();
2711 #endif
2712       } else {
2713           XEvent          unused_xevent;
2714 
2715           while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, Expose,&unused_xevent)) ;
2716           while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, GraphicsExpose,&unused_xevent)) ;
2717           if (isScrollbarWindow(ev->xany.window))
2718           {
2719             scrollbar_setNone();
2720             scrollbar_show(0);
2721           }
2722           if (menubar_visible() && isMenuBarWindow(ev->xany.window))
2723             menubar_expose();
2724         }
2725 
2726   }
2727 	break;
2728 
2729 	case ButtonPress:
2730 		bypass_keystate = (ev->xbutton.state & (Mod1Mask | ShiftMask));
2731 		reportmode = (bypass_keystate ? 0 : (PrivateModes & PrivMode_mouse_report));
2732 
2733 #ifdef DRAW_THUMBBAR
2734     if(ev->xany.window == TermWin.thumb_bar) {
2735       dispatch_button_press(ev->xbutton.x, ev->xbutton.y,cmd_pids[TermWin.active_page]);
2736     } else
2737 #endif
2738 	    if (ev->xany.window == TermWin.vts[TermWin.active_page].vt && TermWin.last_page >= 0)
2739 		{
2740 /*			if (ev->xbutton.subwindow != None)
2741 
2742       ;
2743 			else*/
2744 			if (ev->xbutton.subwindow == None) {
2745 				if (reportmode)
2746 				{
2747 				    /* mouse report from vt window */
2748 				    /* save the xbutton state (for ButtonRelease) */
2749 					MEvent.state = ev->xbutton.state;
2750 #ifdef MOUSE_REPORT_DOUBLECLICK
2751 					if (ev->xbutton.button == MEvent.button
2752 					    && (ev->xbutton.time - MEvent.time < MULTICLICK_TIME))
2753 					{
2754 					    /* same button, within alloted time */
2755 						MEvent.clicks++;
2756 						if (MEvent.clicks > 1)
2757 						{
2758 						    /* only report double clicks */
2759 							MEvent.clicks = 2;
2760 							mouse_report(&(ev->xbutton));
2761 
2762 						    /* don't report the release */
2763 							MEvent.clicks = 0;
2764 							MEvent.button = AnyButton;
2765 						}
2766 					} else
2767 					{
2768 					    /* different button, or time expired */
2769 						MEvent.clicks = 1;
2770 						MEvent.button = ev->xbutton.button;
2771 						mouse_report(&(ev->xbutton));
2772 					}
2773 #else
2774 					MEvent.button = ev->xbutton.button;
2775 					mouse_report(&(ev->xbutton));
2776 #endif				/* MOUSE_REPORT_DOUBLECLICK */
2777 				} else
2778 				{
2779           //DCMD_ALEXIS(1,(stderr,"no reportmode\n"));
2780 					if (ev->xbutton.button != MEvent.button)
2781 						MEvent.clicks = 0;
2782 					switch (ev->xbutton.button)
2783 					{
2784 					case Button1:
2785 						if (MEvent.button == Button1 && (ev->xbutton.time - MEvent.time < MULTICLICK_TIME))
2786 							MEvent.clicks++;
2787 						else
2788 							MEvent.clicks = 1;
2789 						selection_click(MEvent.clicks,ev->xbutton.x,ev->xbutton.y);
2790 						MEvent.button = Button1;
2791 						break;
2792 
2793 					case Button3:
2794 						if (MEvent.button == Button3 && (ev->xbutton.time - MEvent.time < MULTICLICK_TIME))
2795 							selection_rotate(ev->xbutton.x, ev->xbutton.y);
2796 						else
2797 							selection_extend(ev->xbutton.x,ev->xbutton.y, 1);
2798 						MEvent.button = Button3;
2799 						break;
2800           case Button4:
2801 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2802           scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
2803 #endif
2804           if (f_scr_page(TermWin.active_page,UP, 1))
2805             scrollbar_setUp();
2806           break;
2807           case Button5:
2808 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2809           scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
2810 #endif
2811           if (f_scr_page(TermWin.active_page,DN, 1))
2812             scrollbar_setDn();
2813           break;
2814 					}
2815 				}
2816 				MEvent.time = ev->xbutton.time;
2817 				return;
2818 			}
2819 		}
2820 		if (isScrollbarWindow(ev->xany.window))
2821 		{
2822 			scrollbar_setNone();
2823 		    /*
2824 		     * Rxvt-style scrollbar:
2825 		     * move up if mouse is above slider
2826 		     * move dn if mouse is below slider
2827 		     *
2828 		     * XTerm-style scrollbar:
2829 		     * Move display proportional to pointer location
2830 		     * pointer near top -> scroll one line
2831 		     * pointer near bot -> scroll full page
2832 		     */
2833 #ifndef NO_SCROLLBAR_REPORT
2834 			if (reportmode)
2835 			{
2836 			    /*
2837 			     * Mouse report disabled scrollbar:
2838 			     * arrow buttons - send up/down
2839 			     * click on scrollbar - send pageup/down
2840 			     */
2841 				if (scrollbar_upButton(ev->xbutton.y))
2842 					tt_printf((unsigned char *)"\033[A");
2843 				else if (scrollbar_dnButton(ev->xbutton.y))
2844 					tt_printf((unsigned char *)"\033[B");
2845 				else
2846 					switch (ev->xbutton.button)
2847 					{
2848 					case Button2:
2849 						tt_printf((unsigned char *)"\014");
2850 						break;
2851 					case Button1:
2852 						tt_printf((unsigned char *)"\033[6~");
2853 						break;
2854 					case Button3:
2855 						tt_printf((unsigned char *)"\033[5~");
2856 						break;
2857 					}
2858 			} else
2859 #endif				/* NO_SCROLLBAR_REPORT */
2860 			{
2861 				if (scrollbar_upButton(ev->xbutton.y))
2862 				{
2863 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2864 					scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
2865 #endif
2866 					if (f_scr_page(TermWin.active_page,UP, 1))
2867 						scrollbar_setUp();
2868 				} else if (scrollbar_dnButton(ev->xbutton.y))
2869 				{
2870 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2871 					scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
2872 #endif
2873 					if (f_scr_page(TermWin.active_page,DN, 1))
2874 						scrollbar_setDn();
2875 				} else
2876 					switch (ev->xbutton.button)
2877 					{
2878 					case Button2:
2879 #ifndef FUNKY_SCROLL_BEHAVIOUR
2880 						csrO = (scrollBar.bot - scrollBar.top) / 2;
2881 					    /* align to thumb center */
2882 #else
2883 # ifndef XTERM_SCROLLBAR
2884 						if (scrollbar_above_slider(ev->xbutton.y) || scrollbar_below_slider(ev->xbutton.y))
2885 # endif
2886 #endif				/* !FUNKY_SCROLL_BEHAVIOUR */
2887 							f_scr_move_to(TermWin.active_page,scrollbar_position(ev->xbutton.y) - csrO,scrollbar_size());
2888 						scrollbar_setMotion();
2889 						break;
2890 
2891 					case Button1:
2892 #ifndef FUNKY_SCROLL_BEHAVIOUR
2893 						csrO = ev->xbutton.y - scrollBar.top;
2894 					    /* ptr ofset in thumb */
2895 #endif
2896 					    /*drop */
2897 
2898 					case Button3:
2899 #ifndef XTERM_SCROLLBAR
2900 						if (scrollbar_above_slider(ev->xbutton.y))
2901 # ifdef RXVT_SCROLL_FULL
2902 							f_scr_page(TermWin.active_page,UP,TermWin.nrow -1);
2903 # else
2904 							f_scr_page(TermWin.active_page,UP,TermWin.nrow 4);
2905 # endif
2906 						else if (scrollbar_below_slider(ev->xbutton.y))
2907 # ifdef RXVT_SCROLL_FULL
2908 							f_scr_page(TermWin.active_page,DN,TermWin.nrow -1);
2909 # else
2910 							f_scr_page(TermWin.active_page,DN,TermWin.nrow 4);
2911 # endif
2912 						else
2913 							scrollbar_setMotion();
2914 #else				/* XTERM_SCROLLBAR */
2915 						f_scr_page(TermWin.active_page,(ev->xbutton.button == Button1 ? DN : UP),
2916               (TermWin.nrow * scrollbar_position(ev->xbutton.y)/scrollbar_size()));
2917 #endif				/* XTERM_SCROLLBAR */
2918 						break;
2919 					}
2920 			}
2921 			return;
2922 		}
2923 		if (isMenuBarWindow(ev->xany.window))
2924 		{
2925 			menubar_control(&(ev->xbutton));
2926 			return;
2927 		}
2928 		break;
2929 
2930 	case ButtonRelease:
2931 		csrO = 0;	/* reset csr Offset */
2932 		reportmode = (bypass_keystate ? 0 : (PrivateModes & PrivMode_mouse_report));
2933 
2934 		if (scrollbar_isUpDn())
2935 		{
2936 			scrollbar_setNone();
2937 			scrollbar_show(0);
2938 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2939 			refresh_type &= ~SMOOTH_REFRESH;
2940 #endif
2941 		}
2942 		if (ev->xany.window == TermWin.vts[TermWin.active_page].vt)
2943 		{
2944 			if (ev->xbutton.subwindow != None)
2945 
2946       ;
2947 			else
2948 			{
2949 				if (reportmode)
2950 				{
2951 				    /* mouse report from vt window */
2952 #ifdef MOUSE_REPORT_DOUBLECLICK
2953 				    /* only report the release of 'slow' single clicks */
2954 					if (MEvent.button != AnyButton && (ev->xbutton.button != MEvent.button
2955 					     || (ev->xbutton.time - MEvent.time > MULTICLICK_TIME / 2)))
2956 					{
2957 						MEvent.clicks = 0;
2958 						MEvent.button = AnyButton;
2959 						mouse_report(&(ev->xbutton));
2960 					}
2961 #else				/* MOUSE_REPORT_DOUBLECLICK */
2962 					MEvent.button = AnyButton;
2963 					mouse_report(&(ev->xbutton));
2964 #endif				/* MOUSE_REPORT_DOUBLECLICK */
2965 					return;
2966 				}
2967 			    /*
2968 			     * dumb hack to compensate for the failure of click-and-drag
2969 			     * when overriding mouse reporting
2970 			     */
2971 				if ((PrivateModes & PrivMode_mouse_report) &&
2972 				    (bypass_keystate) &&
2973 				    (ev->xbutton.button == Button1) &&
2974 				    (MEvent.clicks <= 1))
2975 					selection_extend(ev->xbutton.x, ev->xbutton.y, 0);
2976 
2977 				switch (ev->xbutton.button)
2978 				{
2979 				case Button1:
2980 				case Button3:
2981 					f_selection_make(TermWin.active_page,ev->xbutton.time);
2982 					break;
2983 
2984 				case Button2:
2985 					f_selection_request(TermWin.active_page,ev->xbutton.time,ev->xbutton.x,ev->xbutton.y);
2986 					break;
2987 #ifndef NO_MOUSE_WHEEL
2988 				case Button4:
2989 					f_scr_page(TermWin.active_page,UP,(ev->xbutton.state & ShiftMask) ? 1 : 5);
2990 					break;
2991 				case Button5:
2992 					f_scr_page(TermWin.active_page,DN,(ev->xbutton.state & ShiftMask) ? 1 : 5);
2993 					break;
2994 #endif
2995 				}
2996 			}
2997 		} else if (isMenuBarWindow(ev->xany.window))
2998 		{
2999 			menubar_control(&(ev->xbutton));
3000 		}
3001 		break;
3002 
3003 	case MotionNotify:
3004 		if (isMenuBarWindow(ev->xany.window))
3005 		{
3006 			menubar_control(&(ev->xbutton));
3007 			break;
3008 		}
3009 		if ((PrivateModes & PrivMode_mouse_report) && !(bypass_keystate))
3010 			break;
3011 
3012 		if (ev->xany.window == TermWin.vts[TermWin.active_page].vt)
3013 		{
3014 			if ((ev->xbutton.state & (Button1Mask | Button3Mask)))
3015 			{
3016 				Window          unused_root, unused_child;
3017 				int             unused_root_x, unused_root_y;
3018 				unsigned int    unused_mask;
3019 
3020 				while (XCheckTypedWindowEvent(Xdisplay, TermWin.vts[TermWin.active_page].vt, MotionNotify,ev)) ;
3021 				XQueryPointer(Xdisplay, TermWin.vts[TermWin.active_page].vt,
3022 					      &unused_root, &unused_child,
3023 					      &unused_root_x, &unused_root_y,
3024 					      &(ev->xbutton.x),
3025 					      &(ev->xbutton.y), &unused_mask);
3026 #ifdef MOUSE_THRESHOLD
3027 			    /* deal with a `jumpy' mouse */
3028 				if ((ev->xmotion.time - MEvent.time) > MOUSE_THRESHOLD)
3029 #endif
3030 				selection_extend((ev->xbutton.x),(ev->xbutton.y),
3031           (ev->xbutton.state & Button3Mask) ? 2 : 0);
3032 			}
3033 		}  else if ((ev->xany.window == scrollBar.win) && scrollbar_isMotion())
3034 		{
3035 			Window          unused_root, unused_child;
3036 			int             unused_root_x, unused_root_y;
3037 			unsigned int    unused_mask;
3038 
3039 			while (XCheckTypedWindowEvent(Xdisplay, scrollBar.win,MotionNotify, ev)) ;
3040 			XQueryPointer(Xdisplay, scrollBar.win,
3041 				      &unused_root, &unused_child,
3042 				      &unused_root_x, &unused_root_y,
3043 				      &(ev->xbutton.x), &(ev->xbutton.y),
3044 				      &unused_mask);
3045 			f_scr_move_to(TermWin.active_page,scrollbar_position(ev->xbutton.y) - csrO, scrollbar_size());
3046 			f_scr_refresh(TermWin.active_page,refresh_type);
3047 			refresh_count = refresh_limit = 0;
3048 			scrollbar_show(1);
3049 		}
3050 		break;
3051 	}
3052 }
3053 
3054 /*
3055  * Send printf() formatted output to the command.
3056  * Only use for small ammounts of data.
3057  */
3058 void tt_printf(const unsigned char *fmt, ...)
3059 {
3060 	static unsigned char buf[TT_PRINTF_LIMIT];
3061 	va_list         arg_ptr;
3062 
3063 	va_start(arg_ptr, fmt);
3064 	vsprintf((char *)buf, (char *)fmt, arg_ptr);
3065 	va_end(arg_ptr);
3066 	f_tt_write(TermWin.active_page,buf, strlen(buf));
3067 }
3068 
3069 /* print pipe
3070  */
3071 /*----------------------------------------------------------------------*/
3072 #ifdef PRINTPIPE
3073 
3074 FILE * popen_printer(void)
3075 {
3076 	FILE           *stream = popen(rs_print_pipe, "w");
3077 
3078 	if (stream == NULL)
3079 		print_error("can't open printer pipe");
3080 	return stream;
3081 }
3082 
3083 /* PROTO */
3084 int
3085 pclose_printer(FILE * stream)
3086 {
3087 	fflush(stream);
3088 /* pclose() reported not to work on SunOS 4.1.3 */
3089 #if defined (__sun__)		/* TODO: RESOLVE THIS */
3090 /* pclose works provided SIGCHLD handler uses waitpid */
3091 	return pclose(stream);	/* return fclose (stream); */
3092 #else
3093 	return pclose(stream);
3094 #endif
3095 }
3096 
3097 /*
3098  * simulate attached vt100 printer
3099  */
3100 /* PROTO */
3101 void
3102 process_print_pipe(void)
3103 {
3104 	int             done;
3105 	FILE           *fd;
3106 
3107 	if ((fd = popen_printer()) == NULL)
3108 		return;
3109 
3110 /*
3111  * Send all input to the printer until either ESC[4i or ESC[?4i
3112  * is received.
3113  */
3114 	for (done = 0; !done;)
3115 	{
3116 		unsigned char   buf[8];
3117 		unsigned char   ch;
3118 		unsigned int    i, len;
3119 
3120 		if ((ch = cmd_getc()) != '\033')
3121 		{
3122 			if (putc(ch, fd) == EOF)
3123 				break;	/* done = 1 */
3124 		} else
3125 		{
3126 			len = 0;
3127 			buf[len++] = ch;
3128 
3129 			if ((buf[len++] = cmd_getc()) == '[')
3130 			{
3131 				if ((ch = cmd_getc()) == '?')
3132 				{
3133 					buf[len++] = '?';
3134 					ch = cmd_getc();
3135 				}
3136 				if ((buf[len++] = ch) == '4')
3137 				{
3138 					if ((buf[len++] = cmd_getc()) == 'i')
3139 						break;	/* done = 1 */
3140 				}
3141 			}
3142 			for (i = 0; i < len; i++)
3143 				if (putc(buf[i], fd) == EOF)
3144 				{
3145 					done = 1;
3146 					break;
3147 				}
3148 		}
3149 	}
3150 	pclose_printer(fd);
3151 }
3152 #endif				/* PRINTPIPE */
3153 
3154 /* process escape sequences
3155  */
3156 void
3157 f_process_escape_seq(int page)
3158 {
3159 	unsigned char   ch = f_cmd_getc();
3160 
3161   DCMD_ALEXIS(2,(stderr,"f_process_escape_seq(%d)\n",page));
3162 	switch (ch)
3163 	{
3164 	    /* case 1:        do_tek_mode (); break; */
3165 	case '#':
3166 		if (f_cmd_getc() == '8')
3167 			f_scr_E(page);
3168 		break;
3169 	case '(':
3170 		f_scr_charset_set(page,0, f_cmd_getc());
3171 		break;
3172 	case ')':
3173 		f_scr_charset_set(page,1, f_cmd_getc());
3174 		break;
3175 	case '*':
3176 		f_scr_charset_set(page,2, f_cmd_getc());
3177 		break;
3178 	case '+':
3179 		f_scr_charset_set(page,3, f_cmd_getc());
3180 		break;
3181 #ifdef MULTICHAR_SET
3182 	case '$':
3183 		f_scr_charset_set(page,-2, f_cmd_getc());
3184 		break;
3185 #endif
3186 	case '7':
3187 		f_scr_cursor(page,SAVE);
3188 		break;
3189 	case '8':
3190 		f_scr_cursor(page,RESTORE);
3191 		break;
3192 	case '=':
3193 	case '>':
3194 		PrivMode((ch == '='), PrivMode_aplKP);
3195 		break;
3196 	case '@':
3197 		(void)f_cmd_getc();
3198 		break;
3199 	case 'D':
3200 		f_scr_index(page,UP);
3201 		break;
3202 	case 'E':
3203 		f_scr_add_lines(page,(unsigned char *)"\n\r", 1, 2);
3204 		break;
3205 	case 'G':
3206 		/*process_graphics();*/
3207 		break;
3208 	case 'H':
3209 		f_scr_set_tab(page,1);
3210 		break;
3211 	case 'M':
3212 		f_scr_index(page,DN);
3213 		break;
3214 	    /*case 'N': scr_single_shift (2);   break; */
3215 	    /*case 'O': scr_single_shift (3);   break; */
3216 	case 'Z':
3217 		tt_printf((unsigned char *)ESCZ_ANSWER);
3218 		break;		/* steal obsolete ESC [ c */
3219 	case '[':
3220 		f_process_csi_seq(page);
3221 		break;
3222 	case ']':
3223 		f_process_xterm_seq(page);
3224 		break;
3225 	case 'c':
3226       printf("HERE: [%s], %d\n",__FILE__,__LINE__);
3227 		f_scr_poweron(page);
3228 		break;
3229 	case 'n':
3230 		f_scr_charset_choose(page,2);
3231 		break;
3232 	case 'o':
3233 		f_scr_charset_choose(page,3);
3234 		break;
3235 	}
3236 }
3237 
3238 /*}}} */
3239 
3240 /*{{{ process CSI (code sequence introducer) sequences `ESC[' */
3241 /* PROTO */
3242 void
3243 f_process_csi_seq(int page)
3244 {
3245 	unsigned char   ch, priv;
3246 	unsigned int    nargs;
3247 	int             arg[ESC_ARGS];
3248 
3249   DCMD_ALEXIS(2,(stderr,"f_process_csi_seq(%d)\n",page));
3250 	nargs = 0;
3251 	arg[0] = 0;
3252 	arg[1] = 0;
3253 
3254 	priv = 0;
3255 	ch = f_cmd_getc();
3256 	if (ch >= '<' && ch <= '?')
3257 	{
3258 		priv = ch;
3259 		ch = f_cmd_getc();
3260 	}
3261 /* read any numerical arguments */
3262 	do
3263 	{
3264 		int             n;
3265 
3266 		for (n = 0; isdigit(ch); ch = f_cmd_getc())
3267 			n = n * 10 + (ch - '0');
3268 
3269 		if (nargs < ESC_ARGS)
3270 			arg[nargs++] = n;
3271 		if (ch == '\b')
3272 		{
3273 			f_scr_backspace(page);
3274 		} else if (ch == 033)
3275 		{
3276 			f_process_escape_seq(page);
3277 			return;
3278 		} else if (ch < ' ')
3279 		{
3280 			f_scr_add_lines(page,&ch, 0, 1);
3281 			return;
3282 		}
3283 		if (ch < '@')
3284 			ch = f_cmd_getc();
3285 	}
3286 	while (ch >= ' ' && ch < '@');
3287 	if (ch == 033)
3288 	{
3289 		f_process_escape_seq(page);
3290 		return;
3291 	} else if (ch < ' ')
3292 		return;
3293 
3294 	switch (ch)
3295 	{
3296 #ifdef PRINTPIPE
3297 	case 'i':		/* printing */
3298 		switch (arg[0])
3299 		{
3300 		case 0:
3301 			scr_printscreen(0);
3302 			break;
3303 		case 5:
3304 			process_print_pipe();
3305 			break;
3306 		}
3307 		break;
3308 #endif
3309 	case 'A':
3310 	case 'e':		/* up <n> */
3311 		f_scr_gotorc(page,(arg[0] ? -arg[0] : -1), 0, RELATIVE);
3312 		break;
3313 	case 'B':		/* down <n> */
3314 		f_scr_gotorc(page,(arg[0] ? +arg[0] : +1), 0, RELATIVE);
3315 		break;
3316 	case 'C':
3317 	case 'a':		/* right <n> */
3318 		f_scr_gotorc(page,0, (arg[0] ? +arg[0] : +1), RELATIVE);
3319 		break;
3320 	case 'D':		/* left <n> */
3321 		f_scr_gotorc(page,0, (arg[0] ? -arg[0] : -1), RELATIVE);
3322 		break;
3323 	case 'E':		/* down <n> & to first column */
3324 		f_scr_gotorc(page,(arg[0] ? +arg[0] : +1), 0, R_RELATIVE);
3325 		break;
3326 	case 'F':		/* up <n> & to first column */
3327 		f_scr_gotorc(page,(arg[0] ? -arg[0] : -1), 0, R_RELATIVE);
3328 		break;
3329 	case 'G':
3330 	case '`':		/* move to col <n> */
3331 		f_scr_gotorc(page,0, (arg[0] ? arg[0] - 1 : +1), R_RELATIVE);
3332 		break;
3333 	case 'd':		/* move to row <n> */
3334 		f_scr_gotorc(page,(arg[0] ? arg[0] - 1 : +1), 0, C_RELATIVE);
3335 		break;
3336 	case 'H':
3337 	case 'f':		/* position cursor */
3338 		switch (nargs)
3339 		{
3340 		case 0:
3341 			f_scr_gotorc(page,0, 0, 0);
3342 			break;
3343 		case 1:
3344 			f_scr_gotorc(page,(arg[0] ? arg[0] - 1 : 0), 0, 0);
3345 			break;
3346 		default:
3347 			f_scr_gotorc(page,arg[0] - 1, arg[1] - 1, 0);
3348 			break;
3349 		}
3350 		break;
3351 	case 'I':
3352 		f_scr_tab(page,arg[0] ? +arg[0] : +1);
3353 		break;
3354 	case 'Z':
3355 		f_scr_tab(page,arg[0] ? -arg[0] : -1);
3356 		break;
3357 	case 'J':
3358 		f_scr_erase_screen(page,arg[0]);
3359 		break;
3360 	case 'K':
3361 		f_scr_erase_line(page,arg[0]);
3362 		break;
3363 	case '@':
3364 		f_scr_insdel_chars(page,(arg[0] ? arg[0] : 1), INSERT);
3365 		break;
3366 	case 'L':
3367 		f_scr_insdel_lines(page,(arg[0] ? arg[0] : 1), INSERT);
3368 		break;
3369 	case 'M':
3370 		f_scr_insdel_lines(page,(arg[0] ? arg[0] : 1), DELETE);
3371 		break;
3372 	case 'X':
3373 		f_scr_insdel_chars(page,(arg[0] ? arg[0] : 1), ERASE);
3374 		break;
3375 	case 'P':
3376 		f_scr_insdel_chars(page,(arg[0] ? arg[0] : 1), DELETE);
3377 		break;
3378 
3379 	case 'c':
3380 		tt_printf((unsigned char *)VT100_ANS);
3381 		break;
3382 	case 'm':
3383 		process_sgr_mode(nargs, arg);
3384 		break;
3385 	case 'n':		/* request for information */
3386 		switch (arg[0])
3387 		{
3388 		case 5:
3389 			tt_printf((unsigned char *)"\033[0n");
3390 			break;	/* ready */
3391 		case 6:
3392 			f_scr_report_position(page);
3393 			break;
3394 #if defined (ENABLE_DISPLAY_ANSWER)
3395 		case 7:
3396 			if (strlen(display_name) < TT_PRINTF_LIMIT - 2)
3397 				tt_printf((unsigned char *)"%s\n",display_name);
3398 			break;
3399 #endif
3400 		case 8:
3401 			f_xterm_seq(page,XTerm_title, APL_NAME "-" VERSION);
3402 			break;
3403 		}
3404 		break;
3405 	case 'r':		/* set top and bottom margins */
3406 		if (priv != '?')
3407 		{
3408 			if (nargs < 2 || arg[0] >= arg[1])
3409 				f_scr_scroll_region(page,0, 10000);
3410 			else
3411 				f_scr_scroll_region(page,arg[0] - 1, arg[1] - 1);
3412 			break;
3413 		}
3414 	    /* drop */
3415 	case 's':
3416 	case 't':
3417 		if (arg[0] == 21)
3418 			tt_printf((unsigned char *)"\033]l%s\033\\", rs_title);
3419 		break;
3420 	case 'h':
3421 	case 'l':
3422 		f_process_terminal_mode(page,ch, priv, nargs, arg);
3423 		break;
3424 	case 'g':
3425 		switch (arg[0])
3426 		{
3427 		case 0:
3428 			f_scr_set_tab(page,0);
3429 			break;	/* delete tab */
3430 		case 3:
3431 			f_scr_set_tab(page,-1);
3432 			break;	/* clear all tabs */
3433 		}
3434 		break;
3435 	case 'W':
3436 		switch (arg[0])
3437 		{
3438 		case 0:
3439 			f_scr_set_tab(page,1);
3440 			break;	/* = ESC H */
3441 		case 2:
3442 			f_scr_set_tab(page,0);
3443 			break;	/* = ESC [ 0 g */
3444 		case 5:
3445 			f_scr_set_tab(page,-1);
3446 			break;	/* = ESC [ 3 g */
3447 		}
3448 		break;
3449 	}
3450 }
3451 
3452 /* process xterm text parameters sequences `ESC ] Ps ; Pt BEL'
3453  */
3454 void f_process_xterm_seq(int page)
3455 {
3456 	unsigned char   ch, string[STRING_MAX];
3457 	int             arg;
3458 
3459 	ch = f_cmd_getc();
3460 	for (arg = 0; isdigit(ch); ch = f_cmd_getc())
3461 		arg = arg * 10 + (ch - '0');
3462 
3463 	if (ch == ';')
3464 	{
3465 		int             n = 0;
3466 
3467 		while ((ch = f_cmd_getc()) != 007)
3468 		{
3469 			if (ch)
3470 			{
3471 				if (ch == '\t')
3472 					ch = ' ';	/* translate '\t' to space */
3473 				else if (ch < ' ')
3474 					return;	/* control character - exit */
3475 
3476 				if (n < sizeof(string) - 1)
3477 					string[n++] = ch;
3478 			}
3479 		}
3480 		string[n] = '\0';
3481 	    /*
3482 	     * menubar_dispatch() violates the constness of the string,
3483 	     * so do it here
3484 	     */
3485 		if (arg == XTerm_Menu)
3486 			menubar_dispatch((char *)string);
3487 		else
3488 			f_xterm_seq(page,arg, (char *)string);
3489 	}
3490 }
3491 
3492 /* process DEC private mode sequences `ESC [ ? Ps mode' */
3493 /*
3494  * mode can only have the following values:
3495  *      'l' = low
3496  *      'h' = high
3497  *      's' = save
3498  *      'r' = restore
3499  *      't' = toggle
3500  * so no need for fancy checking
3501  */
3502 void f_process_terminal_mode(int page,int mode, int priv, unsigned int nargs, int arg[]) {
3503 	unsigned int    i;
3504 	int             state;
3505 
3506 	if (nargs == 0)
3507 		return;
3508 
3509 /* make lo/hi boolean */
3510 	switch (mode)
3511 	{
3512 	case 'l':
3513 		mode = 0;
3514 		break;
3515 	case 'h':
3516 		mode = 1;
3517 		break;
3518 	}
3519 
3520 	switch (priv)
3521 	{
3522 	case 0:
3523 		if (mode && mode != 1)
3524 			return;	/* only do high/low */
3525 		for (i = 0; i < nargs; i++)
3526 			switch (arg[i])
3527 			{
3528 			case 4:
3529 				f_scr_insert_mode(page,mode);
3530 				break;
3531 			    /* case 38:  TEK mode */
3532 			}
3533 		break;
3534 
3535 #define PrivCases(bit)							\
3536     if (mode == 't')							\
3537 	state = !(PrivateModes & bit);					\
3538     else								\
3539         state = mode;							\
3540     switch (state) {							\
3541     case 's':								\
3542 	SavedModes |= (PrivateModes & bit);				\
3543 	continue;							\
3544 	break;								\
3545     case 'r':								\
3546 	state = (SavedModes & bit) ? 1 : 0;				\
3547 	/* FALLTHROUGH */						\
3548     default:								\
3549 	PrivMode (state, bit);						\
3550     }
3551 
3552 	case '?':
3553 		for (i = 0; i < nargs; i++)
3554 			switch (arg[i])
3555 			{
3556 			case 1:	/* application cursor keys */
3557 				PrivCases(PrivMode_aplCUR);
3558 				break;
3559 
3560 			    /* case 2:   - reset charsets to USASCII */
3561 
3562 			case 3:	/* 80/132 */
3563 				PrivCases(PrivMode_132);
3564 				if (PrivateModes & PrivMode_132OK)
3565 					set_width(state ? 132 : 80);
3566 				break;
3567 
3568 			    /* case 4:   - smooth scrolling */
3569 
3570 			case 5:	/* reverse video */
3571 				PrivCases(PrivMode_rVideo);
3572 				f_scr_rvideo_mode(page,state);
3573 				break;
3574 
3575 			case 6:	/* relative/absolute origins  */
3576 				PrivCases(PrivMode_relOrigin);
3577 				f_scr_relative_origin(page,state);
3578 				break;
3579 
3580 			case 7:	/* autowrap */
3581 				PrivCases(PrivMode_Autowrap);
3582 				f_scr_autowrap(page,state);
3583 				break;
3584 
3585 			    /* case 8:   - auto repeat, can't do on a per window basis */
3586 
3587 			case 9:	/* X10 mouse reporting */
3588 				PrivCases(PrivMode_MouseX10);
3589 			    /* orthogonal */
3590 				if (PrivateModes & PrivMode_MouseX10)
3591 					PrivateModes &= ~(PrivMode_MouseX11);
3592 				break;
3593 # ifdef menuBar_esc
3594 			case menuBar_esc:
3595 				PrivCases(PrivMode_menuBar);
3596 				map_menuBar(state);
3597 				break;
3598 # endif
3599 #ifdef scrollBar_esc
3600 			case scrollBar_esc:
3601 				PrivCases(PrivMode_scrollBar);
3602 				map_scrollBar(state);
3603 				break;
3604 #endif
3605 			case 25:	/* visible/invisible cursor */
3606 				PrivCases(PrivMode_VisibleCursor);
3607 				f_scr_cursor_visible(page,state);
3608 				break;
3609 
3610 			case 35:
3611 				PrivCases(PrivMode_ShiftKeys);
3612 				break;
3613 
3614 			case 40:	/* 80 <--> 132 mode */
3615 				PrivCases(PrivMode_132OK);
3616 				break;
3617 
3618 			case 47:	/* secondary screen */
3619 				PrivCases(PrivMode_Screen);
3620 				f_scr_change_screen(page,state);
3621 				break;
3622 
3623 			case 66:	/* application key pad */
3624 				PrivCases(PrivMode_aplKP);
3625 				break;
3626 
3627 			case 67:
3628 #ifndef NO_BACKSPACE_KEY
3629 				if (PrivateModes & PrivMode_HaveBackSpace) {
3630 					PrivCases(PrivMode_BackSpace);
3631         }
3632 #endif
3633 				break;
3634 
3635 			case 1000:	/* X11 mouse reporting */
3636 				PrivCases(PrivMode_MouseX11);
3637 			    /* orthogonal */
3638 				if (PrivateModes & PrivMode_MouseX11)
3639 					PrivateModes &= ~(PrivMode_MouseX10);
3640 				break;
3641 #if 0
3642 			case 1001:
3643 				break;	/* X11 mouse highlighting */
3644 #endif
3645 			case 1010:	/* scroll to bottom on TTY output inhibit */
3646 				PrivCases(PrivMode_TtyOutputInh);
3647 				if (PrivateModes & PrivMode_TtyOutputInh)
3648 					Options |= Opt_scrollTtyOutputInh;
3649 				else
3650 					Options &= ~Opt_scrollTtyOutputInh;
3651 				break;
3652 			case 1011:	/* scroll to bottom on key press */
3653 				PrivCases(PrivMode_Keypress);
3654 				if (PrivateModes & PrivMode_Keypress)
3655 					Options |= Opt_scrollKeypress;
3656 				else
3657 					Options &= ~Opt_scrollKeypress;
3658 				break;
3659 			}
3660 #undef PrivCases
3661 		break;
3662 	}
3663 }
3664 
3665 /* process sgr sequences
3666  */
3667 void process_sgr_mode(unsigned int nargs, int arg[])
3668 {
3669 	unsigned int    i;
3670 
3671 	if (nargs == 0)
3672 	{
3673 		scr_rendition(0, ~RS_None);
3674 		return;
3675 	}
3676 	for (i = 0; i < nargs; i++)
3677 		switch (arg[i])
3678 		{
3679 		case 0:
3680 			scr_rendition(0, ~RS_None);
3681 			break;
3682 		case 1:
3683 			scr_rendition(1, RS_Bold);
3684 			break;
3685 		case 4:
3686 			scr_rendition(1, RS_Uline);
3687 			break;
3688 		case 5:
3689 			scr_rendition(1, RS_Blink);
3690 			break;
3691 		case 7:
3692 			scr_rendition(1, RS_RVid);
3693 			break;
3694 		case 22:
3695 			scr_rendition(0, RS_Bold);
3696 			break;
3697 		case 24:
3698 			scr_rendition(0, RS_Uline);
3699 			break;
3700 		case 25:
3701 			scr_rendition(0, RS_Blink);
3702 			break;
3703 		case 27:
3704 			scr_rendition(0, RS_RVid);
3705 			break;
3706 
3707 		case 30:
3708 		case 31:	/* set fg color */
3709 		case 32:
3710 		case 33:
3711 		case 34:
3712 		case 35:
3713 		case 36:
3714 		case 37:
3715 			scr_color(minCOLOR + (arg[i] - 30), RS_Bold);
3716 			break;
3717 		case 39:	/* default fg */
3718 			scr_color(restoreFG, RS_Bold);
3719 			break;
3720 
3721 		case 40:
3722 		case 41:	/* set bg color */
3723 		case 42:
3724 		case 43:
3725 		case 44:
3726 		case 45:
3727 		case 46:
3728 		case 47:
3729 			scr_color(minCOLOR + (arg[i] - 40), RS_Blink);
3730 			break;
3731 		case 49:	/* default bg */
3732 			scr_color(restoreBG, RS_Blink);
3733 			break;
3734 		}
3735 }
3736 
3737 
3738 /* Read and process output from the application
3739  */
3740 
3741 void main_loop(void)
3742 {
3743 	int             ch;
3744 #ifdef UTMP_SUPPORT
3745   f_privileges(0,RESTORE);
3746   if (!(Options & Opt_utmpInhibit))
3747     makeutent(ttydevs[0], display_name);	/* stamp /etc/utmp */
3748   f_privileges(0,IGNORE);
3749 #endif
3750 
3751 	do
3752 	{
3753 		while ((ch = f_cmd_getc()) == 0 && vt_died < 0) ;	/* wait for something or a vt died */
3754     if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r')
3755 		{
3756 		    /* Read a text string from the input buffer */
3757 			int             nlines = 0;
3758 			unsigned char  *str;
3759 
3760 		    /*
3761 		     * point to the start of the string,
3762 		     * decrement first since it was post incremented in f_cmd_getc()
3763 		     */
3764 			str = --cmdbuf_ptr;
3765 			while (cmdbuf_ptr < cmdbuf_endp)
3766 			{
3767 				ch = *cmdbuf_ptr++;
3768 				if (ch >= ' ' || ch == '\t' || ch == '\r')
3769 				{
3770 				    /* nothing */
3771 				} else if (ch == '\n')
3772 				{
3773 					nlines++;
3774 					if (++refresh_count >= (refresh_limit * (TermWin.nrow - 1)))
3775 						break;
3776 				} else
3777 				{	/* unprintable */
3778 					cmdbuf_ptr--;
3779 					break;
3780 				}
3781 			}
3782 			//scr_add_lines(str, nlines, (cmdbuf_ptr - str));
3783       DCMD_ALEXIS(2,(stderr,"adding '%s' in %d\n",str,fd_read));
3784       f_scr_add_lines(fd_read,str, nlines, (cmdbuf_ptr - str));
3785 
3786 		} else
3787 		{
3788 			switch (ch)
3789 			{
3790 			case 005:	/* terminal Status */
3791         DCMD_ALEXIS(3,(stderr,"Terminal status\n"));
3792 				tt_printf((unsigned char *)VT100_ANS);
3793 				break;
3794 			case 007:	/* bell */
3795 				scr_bell();
3796 				break;
3797 			case '\b':	/* backspace */
3798         DCMD_ALEXIS(3,(stderr,"Backspace character\n"));
3799 				f_scr_backspace(fd_read);
3800 				break;
3801 			case 013:	/* vertical tab, form feed */
3802 			case 014:
3803 				f_scr_index(fd_read,UP);
3804 				break;
3805 			case 016:	/* shift out - acs */
3806         DCMD_ALEXIS(3,(stderr,"Shift out character\n"));
3807 				f_scr_charset_choose(fd_read,1);
3808 				break;
3809 			case 017:	/* shift in - acs */
3810         DCMD_ALEXIS(3,(stderr,"Shit in character\n"));
3811 				f_scr_charset_choose(fd_read,0);
3812 				break;
3813 			case 033:	/* escape char */
3814         DCMD_ALEXIS(2,(stderr,"Escape character\n"));
3815 				f_process_escape_seq(fd_read);
3816 				break;
3817 			}
3818 		}
3819 
3820 	}
3821 	while (ch != EOF);
3822 }
3823 
3824 /* ---------------------------------------------------------------------- */
3825 /* Addresses pasting large amounts of data and rxvt hang
3826  * code pinched from xterm (v_write()) and applied originally to
3827  * rxvt-2.18 - Hops
3828  * Write data to the pty as typed by the user, pasted with the mouse,
3829  * or generated by us in response to a query ESC sequence.
3830  */
3831 /* PROTO */
3832 void
3833 f_tt_write(int page,const unsigned char *d, int len)
3834 {
3835 	int             riten, p;
3836 
3837 	if (v_bufstr == NULL && len > 0)
3838 	{
3839 		v_buffer = v_bufstr = v_bufptr = MALLOC(len);
3840 		v_bufend = v_buffer + len;
3841 	}
3842 /*
3843  * Append to the block we already have.  Always doing this simplifies the
3844  * code, and isn't too bad, either.  If this is a short block, it isn't
3845  * too expensive, and if this is a long block, we won't be able to write
3846  * it all anyway.
3847  */
3848 	if (len > 0)
3849 	{
3850 		if (v_bufend < v_bufptr + len)
3851 		{		/* we've run out of room */
3852 			if (v_bufstr != v_buffer)
3853 			{
3854 			    /* there is unused space, move everything down */
3855 			    /* possibly overlapping bcopy here */
3856 			    /* bcopy(v_bufstr, v_buffer, v_bufptr - v_bufstr); */
3857 				memcpy(v_buffer, v_bufstr,v_bufptr - v_bufstr);
3858 				v_bufptr -= v_bufstr - v_buffer;
3859 				v_bufstr = v_buffer;
3860 			}
3861 			if (v_bufend < v_bufptr + len)
3862 			{
3863 			    /* still won't fit: get more space */
3864 			    /* Don't use XtRealloc because an error is not fatal. */
3865 				int             size = v_bufptr - v_buffer;
3866 
3867 			    /* save across realloc */
3868 				v_buffer = REALLOC(v_buffer, size + len);
3869 				if (v_buffer)
3870 				{
3871 					v_bufstr = v_buffer;
3872 					v_bufptr = v_buffer + size;
3873 					v_bufend = v_bufptr + len;
3874 				} else
3875 				{
3876 				    /* no memory: ignore entire write request */
3877 					print_error ("cannot allocate buffer space");
3878 					v_buffer = v_bufstr;	/* restore clobbered pointer */
3879 				}
3880 			}
3881 		}
3882 		if (v_bufend >= v_bufptr + len)
3883 		{		/* new stuff will fit */
3884 			memcpy(v_bufptr, d, len);	/* bcopy(d, v_bufptr, len); */
3885 			v_bufptr += len;
3886 		}
3887 	}
3888 /*
3889  * Write out as much of the buffer as we can.
3890  * Be careful not to overflow the pty's input silo.
3891  * We are conservative here and only write a small amount at a time.
3892  *
3893  * If we can't push all the data into the pty yet, we expect write
3894  * to return a non-negative number less than the length requested
3895  * (if some data written) or -1 and set errno to EAGAIN,
3896  * EWOULDBLOCK, or EINTR (if no data written).
3897  *
3898  * (Not all systems do this, sigh, so the code is actually
3899  * a little more forgiving.)
3900  */
3901 
3902 #define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
3903 
3904 	if ((p = v_bufptr - v_bufstr) > 0)
3905 	{
3906 		riten = write(cmd_fds[page], v_bufstr,p < MAX_PTY_WRITE ? p : MAX_PTY_WRITE);
3907 		if (riten < 0)
3908 			riten = 0;
3909 		v_bufstr += riten;
3910 		if (v_bufstr >= v_bufptr)	/* we wrote it all */
3911 			v_bufstr = v_bufptr = v_buffer;
3912 	}
3913 /*
3914  * If we have lots of unused memory allocated, return it
3915  */
3916 	if (v_bufend - v_bufptr > 1024)
3917 	{			/* arbitrary hysteresis */
3918 	    /* save pointers across realloc */
3919 		int             start = v_bufstr - v_buffer;
3920 		int             size = v_bufptr - v_buffer;
3921 		int             allocsize = size ? size : 1;
3922 
3923 		v_buffer = REALLOC(v_buffer, allocsize);
3924 		if (v_buffer)
3925 		{
3926 			v_bufstr = v_buffer + start;
3927 			v_bufptr = v_buffer + size;
3928 			v_bufend = v_buffer + allocsize;
3929 		} else
3930 		{
3931 		    /* should we print a warning if couldn't return memory? */
3932 			v_buffer = v_bufstr - start;	/* restore clobbered pointer */
3933 		}
3934 	}
3935 }
3936 
3937 /*----------------------- end-of-file (C source) -----------------------*/
3938