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