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 #if defined(USE_XIM) || !defined(NO_XLOCALE)
1490     len = 0;
1491     if (!XFilterEvent(ev, *(&ev->xkey.window))) {
1492         if (Input_Context != NULL) {
1493             Status          status_return;
1494 
1495             kbuf[0] = '\0';
1496             len = XmbLookupString(Input_Context, &ev->xkey, kbuf,
1497                     sizeof(kbuf), &keysym,
1498                     &status_return);
1499         } else {
1500             len = XLookupString(&ev->xkey, kbuf,
1501                     sizeof(kbuf), &keysym,
1502                     &compose);
1503         }
1504     }
1505 #else                         /* USE_XIM */
1506     len = XLookupString(&ev->xkey, (char *) kbuf, sizeof(kbuf), &keysym, &compose);
1507 /*
1508  * have unmapped Latin[2-4] entries -> Latin1
1509  * good for installations  with correct fonts, but without XLOCAL
1510  */
1511     if (!len && (keysym >= 0x0100) && (keysym < 0x0400)) {
1512 	len = 1;
1513 	kbuf[0] = (keysym & 0xFF);
1514     }
1515 #endif                                /* USE_XIM */
1516 
1517     if (len && (Options & Opt_scrollKeypress))
1518 	TermWin.view_start = 0;
1519 
1520 /* for some backwards compatibility */
1521 #if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
1522 # ifdef HOTKEY_CTRL
1523 #  define HOTKEY	ctrl
1524 # else
1525 #  ifdef HOTKEY_META
1526 #   define HOTKEY	meta
1527 #  endif
1528 # endif
1529     if (HOTKEY) {
1530 	if (keysym == ks_bigfont) {
1531 	    change_font(0, FONT_UP);
1532 	    return;
1533 	} else if (keysym == ks_smallfont) {
1534 	    change_font(0, FONT_DN);
1535 	    return;
1536 	}
1537     }
1538 # undef HOTKEY
1539 #endif
1540 
1541     if (shft) {
1542     /* Shift + F1 - F10 generates F11 - F20 */
1543 	if (keysym >= XK_F1 && keysym <= XK_F10) {
1544 	    keysym += (XK_F11 - XK_F1);
1545 	    shft = 0;		/* turn off Shift */
1546 	} else if (!ctrl && !meta && (PrivateModes & PrivMode_ShiftKeys)) {
1547 	    int             lnsppg = TermWin.nrow * 4 / 5;
1548 
1549 #ifdef PAGING_CONTEXT_LINES
1550 	    lnsppg = TermWin.nrow - PAGING_CONTEXT_LINES;
1551 #endif
1552 
1553 	    switch (keysym) {
1554 	    /* normal XTerm key bindings */
1555 	    case XK_Prior:	/* Shift+Prior = scroll back */
1556 		if (TermWin.saveLines) {
1557 		    scr_page(UP, lnsppg);
1558 		    return;
1559 		}
1560 		break;
1561 
1562 	    case XK_Up:		/* Shift+XK_Up = scroll up one line */
1563 		if (TermWin.saveLines) {
1564 		    scr_page(UP, 1);
1565 		    return;
1566 		}
1567 		break;
1568 
1569 	    case XK_Down:	/* Shift+XK_Down = scroll down one line */
1570 		if (TermWin.saveLines) {
1571 		    scr_page(DN, 1);
1572 		    return;
1573 		}
1574 		break;
1575 
1576 	    case XK_Next:	/* Shift+Next = scroll forward */
1577 		if (TermWin.saveLines) {
1578 		    scr_page(DN, lnsppg);
1579 		    return;
1580 		}
1581 		break;
1582 
1583 	    case XK_Insert:	/* Shift+Insert = paste mouse selection */
1584 		selection_request(ev->xkey.time, ev->xkey.x, ev->xkey.y);
1585 		return;
1586 		break;
1587 
1588 	    /* rxvt extras */
1589 	    case XK_KP_Add:	/* Shift+KP_Add = bigger font */
1590 		change_font(0, FONT_UP);
1591 		return;
1592 		break;
1593 
1594 	    case XK_KP_Subtract:	/* Shift+KP_Subtract = smaller font */
1595 		change_font(0, FONT_DN);
1596 		return;
1597 		break;
1598 	    }
1599 	}
1600     }
1601 #ifdef UNSHIFTED_SCROLLKEYS
1602     else if (!ctrl && !meta) {
1603 	switch (keysym) {
1604 	case XK_Prior:
1605 	    if (TermWin.saveLines) {
1606 		scr_page(UP, TermWin.nrow * 4 / 5);
1607 		return;
1608 	    }
1609 	    break;
1610 
1611 	case XK_Next:
1612 	    if (TermWin.saveLines) {
1613 		scr_page(DN, TermWin.nrow * 4 / 5);
1614 		return;
1615 	    }
1616 	    break;
1617 	}
1618     }
1619 #endif
1620 
1621     switch (keysym) {
1622     case XK_Print:
1623 #ifdef PRINTPIPE
1624 	scr_printscreen(ctrl | shft);
1625 	return;
1626 #endif
1627 	break;
1628 
1629     case XK_Mode_switch:
1630 #ifdef GREEK_SUPPORT
1631 	greek_mode = !greek_mode;
1632 	if (greek_mode) {
1633 	    xterm_seq(XTerm_title, (greek_getmode() == GREEK_ELOT928 ?
1634 				    "[Greek: iso]" : "[Greek: ibm]"));
1635 	    greek_reset();
1636 	} else
1637 	    xterm_seq(XTerm_title, APL_NAME "-" VERSION);
1638 	return;
1639 #endif
1640 	break;
1641     }
1642 
1643     if (keysym >= 0xFF00 && keysym <= 0xFFFF) {
1644 #ifdef KEYSYM_RESOURCE
1645 	if (!(shft | ctrl) && KeySym_map[keysym - 0xFF00] != NULL) {
1646 	    const unsigned char *kbuf;
1647 	    unsigned int    len;
1648 
1649 	    kbuf = (KeySym_map[keysym - 0xFF00]);
1650 	    len = *kbuf++;
1651 
1652 	/* escape prefix */
1653 	    if (meta
1654 # ifdef META8_OPTION
1655 		&& (meta_char == 033)
1656 # endif
1657 		) {
1658 		const unsigned char ch = '\033';
1659 
1660 		tt_write(&ch, 1);
1661 	    }
1662 	    tt_write(kbuf, len);
1663 	    return;
1664 	} else
1665 #endif
1666 	    switch (keysym) {
1667 #ifndef NO_BACKSPACE_KEY
1668 	    case XK_BackSpace:
1669 		if (PrivateModes & PrivMode_HaveBackSpace) {
1670 		    len = 1;
1671 		    kbuf[0] = (((PrivateModes & PrivMode_BackSpace) ?
1672 				!(shft | ctrl) : (shft | ctrl)) ? '\b' : '\177');
1673 		} else
1674 		    len = strlen(STRCPY(kbuf, rs_backspace_key));
1675 		break;
1676 #endif
1677 #ifndef NO_DELETE_KEY
1678 	    case XK_Delete:
1679 		len = strlen(STRCPY(kbuf, rs_delete_key));
1680 		break;
1681 #endif
1682 	    case XK_Tab:
1683 		if (shft) {
1684 		    len = 3;
1685 		    STRCPY(kbuf, "\033[Z");
1686 		}
1687 		break;
1688 
1689 #ifdef XK_KP_Home
1690 	    case XK_KP_Home:
1691 	    /* allow shift to override */
1692 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1693 		    len = 3;
1694 		    STRCPY(kbuf, "\033Ow");
1695 		    break;
1696 		}
1697 	    /* -> else FALL THROUGH */
1698 #endif
1699 	    case XK_Home:
1700 		len = strlen(STRCPY(kbuf, KS_HOME));
1701 		break;
1702 
1703 #ifdef XK_KP_Left
1704 	    case XK_KP_Left:	/* \033Ot or standard */
1705 	    case XK_KP_Up:	/* \033Ox or standard */
1706 	    case XK_KP_Right:	/* \033Ov or standard */
1707 	    case XK_KP_Down:	/* \033Or or standard */
1708 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1709 		    len = 3;
1710 		    STRCPY(kbuf, "\033OZ");
1711 		    kbuf[2] = ("txvr"[keysym - XK_KP_Left]);
1712 		    break;
1713 		} else {
1714 		/* translate to std. cursor key */
1715 		    keysym = XK_Left + (keysym - XK_KP_Left);
1716 		}
1717 	    /* FALL THROUGH */
1718 #endif
1719 	    case XK_Left:	/* "\033[D" */
1720 	    case XK_Up:	/* "\033[A" */
1721 	    case XK_Right:	/* "\033[C" */
1722 	    case XK_Down:	/* "\033[B" */
1723 		len = 3;
1724 		STRCPY(kbuf, "\033[@");
1725 		kbuf[2] = ("DACB"[keysym - XK_Left]);
1726 	    /* do Shift first */
1727 		if (shft) {
1728 		    kbuf[2] = ("dacb"[keysym - XK_Left]);
1729 		} else if (ctrl) {
1730 		    kbuf[1] = 'O';
1731 		    kbuf[2] = ("dacb"[keysym - XK_Left]);
1732 		} else if (PrivateModes & PrivMode_aplCUR) {
1733 		    kbuf[1] = 'O';
1734 		}
1735 		break;
1736 
1737 #ifndef UNSHIFTED_SCROLLKEYS
1738 # ifdef XK_KP_Prior
1739 	    case XK_KP_Prior:
1740 	    /* allow shift to override */
1741 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1742 		    len = 3;
1743 		    STRCPY(kbuf, "\033Oy");
1744 		    break;
1745 		}
1746 	    /* -> else FALL THROUGH */
1747 # endif
1748 	    case XK_Prior:
1749 		len = 4;
1750 		STRCPY(kbuf, "\033[5~");
1751 		break;
1752 # ifdef XK_KP_Next
1753 	    case XK_KP_Next:
1754 	    /* allow shift to override */
1755 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1756 		    len = 3;
1757 		    STRCPY(kbuf, "\033Os");
1758 		    break;
1759 		}
1760 	    /* -> else FALL THROUGH */
1761 # endif
1762 	    case XK_Next:
1763 		len = 4;
1764 		STRCPY(kbuf, "\033[6~");
1765 		break;
1766 #endif
1767 #ifdef XK_KP_End
1768 	    case XK_KP_End:
1769 	    /* allow shift to override */
1770 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1771 		    len = 3;
1772 		    STRCPY(kbuf, "\033Oq");
1773 		    break;
1774 		}
1775 	    /* -> else FALL THROUGH */
1776 #endif
1777 	    case XK_End:
1778 		len = strlen(STRCPY(kbuf, KS_END));
1779 		break;
1780 
1781 	    case XK_Select:
1782 		len = 4;
1783 		STRCPY(kbuf, "\033[4~");
1784 		break;
1785 #ifdef DXK_Remove		/* support for DEC remove like key */
1786 	    case DXK_Remove:	/* drop */
1787 #endif
1788 	    case XK_Execute:
1789 		len = 4;
1790 		STRCPY(kbuf, "\033[3~");
1791 		break;
1792 	    case XK_Insert:
1793 		len = 4;
1794 		STRCPY(kbuf, "\033[2~");
1795 		break;
1796 
1797 	    case XK_Menu:
1798 		len = 5;
1799 		STRCPY(kbuf, "\033[29~");
1800 		break;
1801 	    case XK_Find:
1802 		len = 4;
1803 		STRCPY(kbuf, "\033[1~");
1804 		break;
1805 	    case XK_Help:
1806 		len = 5;
1807 		STRCPY(kbuf, "\033[28~");
1808 		break;
1809 
1810 	    case XK_KP_Enter:
1811 	    /* allow shift to override */
1812 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1813 		    len = 3;
1814 		    STRCPY(kbuf, "\033OM");
1815 		} else {
1816 		    len = 1;
1817 		    kbuf[0] = '\r';
1818 		}
1819 		break;
1820 
1821 #ifdef XK_KP_Begin
1822 	    case XK_KP_Begin:
1823 		len = 3;
1824 		STRCPY(kbuf, "\033Ou");
1825 		break;
1826 
1827 	    case XK_KP_Insert:
1828 		len = 3;
1829 		STRCPY(kbuf, "\033Op");
1830 		break;
1831 
1832 	    case XK_KP_Delete:
1833 		len = 3;
1834 		STRCPY(kbuf, "\033On");
1835 		break;
1836 #endif
1837 
1838 	    case XK_KP_F1:	/* "\033OP" */
1839 	    case XK_KP_F2:	/* "\033OQ" */
1840 	    case XK_KP_F3:	/* "\033OR" */
1841 	    case XK_KP_F4:	/* "\033OS" */
1842 		len = 3;
1843 		STRCPY(kbuf, "\033OP");
1844 		kbuf[2] += (keysym - XK_KP_F1);
1845 		break;
1846 
1847 	    case XK_KP_Multiply:	/* "\033Oj" : "*" */
1848 	    case XK_KP_Add:	/* "\033Ok" : "+" */
1849 	    case XK_KP_Separator:	/* "\033Ol" : "," */
1850 	    case XK_KP_Subtract:	/* "\033Om" : "-" */
1851 	    case XK_KP_Decimal:	/* "\033On" : "." */
1852 	    case XK_KP_Divide:	/* "\033Oo" : "/" */
1853 	    case XK_KP_0:	/* "\033Op" : "0" */
1854 	    case XK_KP_1:	/* "\033Oq" : "1" */
1855 	    case XK_KP_2:	/* "\033Or" : "2" */
1856 	    case XK_KP_3:	/* "\033Os" : "3" */
1857 	    case XK_KP_4:	/* "\033Ot" : "4" */
1858 	    case XK_KP_5:	/* "\033Ou" : "5" */
1859 	    case XK_KP_6:	/* "\033Ov" : "6" */
1860 	    case XK_KP_7:	/* "\033Ow" : "7" */
1861 	    case XK_KP_8:	/* "\033Ox" : "8" */
1862 	    case XK_KP_9:	/* "\033Oy" : "9" */
1863 	    /* allow shift to override */
1864 		if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
1865 		    len = 3;
1866 		    STRCPY(kbuf, "\033Oj");
1867 		    kbuf[2] += (keysym - XK_KP_Multiply);
1868 		} else {
1869 		    len = 1;
1870 		    kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
1871 		}
1872 		break;
1873 
1874 		case XK_F1:		/* "\033OP" */
1875 	    case XK_F2:		/* "\033OQ" */
1876 	    case XK_F3:		/* "\033OR" */
1877 	    case XK_F4:		/* "\033OS" */
1878 		len = 3;
1879 		STRCPY(kbuf, "\033OP");
1880 		kbuf[2] += (keysym - XK_F1);
1881 		break;
1882 
1883 #define FKEY(n, fkey)							\
1884     len = 5;								\
1885     sprintf((char *) kbuf,"\033[%02d~", (int)((n) + (keysym - fkey)))
1886 #if 0                          /* old style keymappings : */
1887 	    case XK_F1:		/* "\033[11~" */
1888 	    case XK_F2:		/* "\033[12~" */
1889 	    case XK_F3:		/* "\033[13~" */
1890 	    case XK_F4:		/* "\033[14~" */
1891 			FKEY(11, XK_F1);
1892 		break;
1893 #endif
1894 	    case XK_F5:		/* "\033[15~" */
1895 			FKEY(15, XK_F5);
1896 		break;
1897 
1898 	    case XK_F6:		/* "\033[17~" */
1899 	    case XK_F7:		/* "\033[18~" */
1900 	    case XK_F8:		/* "\033[19~" */
1901 	    case XK_F9:		/* "\033[20~" */
1902 	    case XK_F10:	/* "\033[21~" */
1903 		FKEY(17, XK_F6);
1904 		break;
1905 
1906 	    case XK_F11:	/* "\033[23~" */
1907 	    case XK_F12:	/* "\033[24~" */
1908 	    case XK_F13:	/* "\033[25~" */
1909 	    case XK_F14:	/* "\033[26~" */
1910 		FKEY(23, XK_F11);
1911 		break;
1912 
1913 	    case XK_F15:	/* "\033[28~" */
1914 	    case XK_F16:	/* "\033[29~" */
1915 		FKEY(28, XK_F15);
1916 		break;
1917 
1918 	    case XK_F17:	/* "\033[31~" */
1919 	    case XK_F18:	/* "\033[32~" */
1920 	    case XK_F19:	/* "\033[33~" */
1921 	    case XK_F20:	/* "\033[34~" */
1922 	    case XK_F21:	/* "\033[35~" */
1923 	    case XK_F22:	/* "\033[36~" */
1924 	    case XK_F23:	/* "\033[37~" */
1925 	    case XK_F24:	/* "\033[38~" */
1926 	    case XK_F25:	/* "\033[39~" */
1927 	    case XK_F26:	/* "\033[40~" */
1928 	    case XK_F27:	/* "\033[41~" */
1929 	    case XK_F28:	/* "\033[42~" */
1930 	    case XK_F29:	/* "\033[43~" */
1931 	    case XK_F30:	/* "\033[44~" */
1932 	    case XK_F31:	/* "\033[45~" */
1933 	    case XK_F32:	/* "\033[46~" */
1934 	    case XK_F33:	/* "\033[47~" */
1935 	    case XK_F34:	/* "\033[48~" */
1936 	    case XK_F35:	/* "\033[49~" */
1937 		FKEY(31, XK_F17);
1938 		break;
1939 #undef FKEY
1940 	    }
1941     /*
1942      * Pass meta for all function keys, if 'meta' option set
1943      */
1944 #ifdef META8_OPTION
1945 	if (meta && (meta_char == 0x80) && len > 0) {
1946 	    kbuf[len - 1] |= 0x80;
1947 	}
1948 #endif
1949     } else if (ctrl && keysym == XK_minus) {
1950 	len = 1;
1951 	kbuf[0] = '\037';	/* Ctrl-Minus generates ^_ (31) */
1952     } else {
1953 #ifdef META8_OPTION
1954     /* set 8-bit on */
1955 	if (meta && (meta_char == 0x80)) {
1956 	    unsigned char  *ch;
1957 
1958 	    for (ch = kbuf; ch < kbuf + len; ch++)
1959 		*ch |= 0x80;
1960 	    meta = 0;
1961 	}
1962 #endif
1963 #ifdef GREEK_SUPPORT
1964 	if (greek_mode)
1965 	    len = greek_xlat(kbuf, len);
1966 #endif
1967     /* nil */ ;
1968     }
1969 
1970     if (len <= 0)
1971 	return;			/* not mapped */
1972 
1973 /*
1974  * these modifications only affect the static keybuffer
1975  * pass Shift/Control indicators for function keys ending with `~'
1976  *
1977  * eg,
1978  *   Prior = "ESC[5~"
1979  *   Shift+Prior = "ESC[5~"
1980  *   Ctrl+Prior = "ESC[5^"
1981  *   Ctrl+Shift+Prior = "ESC[5@"
1982  * Meta adds an Escape prefix (with META8_OPTION, if meta == <escape>).
1983  */
1984     if (kbuf[0] == '\033' && kbuf[1] == '[' && kbuf[len - 1] == '~')
1985 	kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
1986 
1987 /* escape prefix */
1988     if (meta
1989 #ifdef META8_OPTION
1990 	&& (meta_char == 033)
1991 #endif
1992 	) {
1993 	const unsigned char ch = '\033';
1994 
1995 	tt_write(&ch, 1);
1996     }
1997 #ifdef DEBUG_CMD
1998     if (debug_key) {		/* Display keyboard buffer contents */
1999 	char           *p;
2000 	int             i;
2001 
2002 	fprintf(stderr, "key 0x%04X [%d]: `", (unsigned int)keysym, len);
2003 	for (i = 0, p = kbuf; i < len; i++, p++)
2004 	    fprintf(stderr, (*p >= ' ' && *p < '\177' ? "%c" : "\\%03o"), *p);
2005 	fprintf(stderr, "'\n");
2006     }
2007 #endif				/* DEBUG_CMD */
2008     tt_write(kbuf, len);
2009 }
2010 /*}}} */
2011 
2012 #if (MENUBAR_MAX)
2013 /*{{{ cmd_write(), cmd_getc() */
2014 /* attempt to `write' COUNT to the input buffer */
2015 /* PROTO */
2016 unsigned int
2017 cmd_write(const unsigned char *str, unsigned int count)
2018 {
2019     int             n;
2020 
2021     n = (count - (cmdbuf_ptr - cmdbuf_base));
2022 /* need to insert more chars that space available in the front */
2023     if (n > 0) {
2024     /* try and get more space from the end */
2025 	unsigned char  *src, *dst;
2026 
2027 	dst = (cmdbuf_base + sizeof(cmdbuf_base) - 1);	/* max pointer */
2028 
2029 	if ((cmdbuf_ptr + n) > dst)
2030 	    n = (dst - cmdbuf_ptr);	/* max # chars to insert */
2031 
2032 	if ((cmdbuf_endp + n) > dst)
2033 	    cmdbuf_endp = (dst - n);	/* truncate end if needed */
2034 
2035     /* equiv: memmove ((cmdbuf_ptr+n), cmdbuf_ptr, n); */
2036 	src = cmdbuf_endp;
2037 	dst = src + n;
2038     /* FIXME: anything special to avoid possible pointer wrap? */
2039 	while (src >= cmdbuf_ptr)
2040 	    *dst-- = *src--;
2041 
2042     /* done */
2043 	cmdbuf_ptr += n;
2044 	cmdbuf_endp += n;
2045     }
2046     while (count-- && cmdbuf_ptr > cmdbuf_base) {
2047     /* sneak one in */
2048 	cmdbuf_ptr--;
2049 	*cmdbuf_ptr = str[count];
2050     }
2051 
2052     return 0;
2053 }
2054 #endif				/* MENUBAR_MAX */
2055 /* cmd_getc() - Return next input character */
2056 /*
2057  * Return the next input character after first passing any keyboard input
2058  * to the command.
2059  */
2060 /* PROTO */
2061 unsigned char
2062 cmd_getc(void)
2063 {
2064 #define TIMEOUT_USEC	5000
2065     static short    refreshed = 0;
2066     fd_set          readfds;
2067     int             retval;
2068 
2069 	struct timeval  value;
2070 #if 0
2071 #ifdef __CYGWIN32__
2072     struct timeval  value;
2073 #else
2074     struct itimerval value;
2075 #endif
2076 #endif
2077 
2078 /* If there have been a lot of new lines, then update the screen
2079  * What the heck I'll cheat and only refresh less than every page-full.
2080  * the number of pages between refreshes is refresh_limit, which
2081  * is incremented here because we must be doing flat-out scrolling.
2082  *
2083  * refreshing should be correct for small scrolls, because of the
2084  * time-out */
2085     if (refresh_count >= (refresh_limit * (TermWin.nrow - 1))) {
2086 		if (refresh_limit < REFRESH_PERIOD)
2087 	    	refresh_limit++;
2088 		refresh_count = 0;
2089 		refreshed = 1;
2090 		scr_refresh(refresh_type);
2091     }
2092 /* characters already read in */
2093     if (cmdbuf_ptr < cmdbuf_endp)
2094 	goto Return_Char;
2095 
2096     for (;;) {
2097 		struct timeval *timeout = &value;
2098 
2099 	if (v_bufstr < v_bufptr)	/* output any pending chars */
2100 	    tt_write(NULL, 0);
2101 	while (XPending(Xdisplay)) {	/* process pending X events */
2102 	    refreshed = 0;
2103 #ifdef USE_XIM
2104             XProcessEvent(Xdisplay);
2105 #else
2106 		{
2107 			XEvent          ev;
2108 			XNextEvent(Xdisplay, &ev);
2109 /*fprintf( stderr, "%s:%d Received event %d\n", __FUNCTION__, __LINE__, ev.type );*/
2110 	    	process_x_event(&ev);
2111 	    }
2112 #endif
2113 	/* in case button actions pushed chars to cmdbuf */
2114 	    if (cmdbuf_ptr < cmdbuf_endp)
2115 		goto Return_Char;
2116 	}
2117 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2118 	if (scrollbar_isUp()) {
2119 	    if (!scroll_arrow_delay-- && scr_page(UP, 1)) {
2120 		scroll_arrow_delay = SCROLLBAR_CONTINUOUS_DELAY;
2121 		refreshed = 0;
2122 		refresh_type |= SMOOTH_REFRESH;
2123 	    }
2124 	} else if (scrollbar_isDn()) {
2125 	    if (!scroll_arrow_delay-- && scr_page(DN, 1)) {
2126 		scroll_arrow_delay = SCROLLBAR_CONTINUOUS_DELAY;
2127 		refreshed = 0;
2128 		refresh_type |= SMOOTH_REFRESH;
2129 	    }
2130 	}
2131 #endif				/* NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING */
2132 
2133     /* Nothing to do! */
2134 	FD_ZERO(&readfds);
2135 	FD_SET(cmd_fd, &readfds);
2136 	FD_SET(Xfd, &readfds);
2137 
2138 	if( refreshed && last_update_background_request_sec == 0
2139 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2140 			  && !(scrollbar_isUpDn())
2141 #endif
2142 		)
2143 			timeout = NULL ;
2144 	else if( !refreshed )
2145 	{
2146 		timeout->tv_usec = TIMEOUT_USEC;
2147 		timeout->tv_sec = 0;
2148 	}else if( last_update_background_request_sec )
2149 	{
2150 		time_t curr_t_sec, curr_t_usec, wait_usec = 0 ;
2151 		timer_get_time (&curr_t_sec, &curr_t_usec);
2152 		if( curr_t_sec == last_update_background_request_sec )
2153 		{
2154 			if( curr_t_usec < last_update_background_request_usec )
2155 				wait_usec = last_update_background_request_usec - curr_t_usec ;
2156 		}else if( curr_t_sec < last_update_background_request_sec )
2157 		{
2158 			wait_usec = (last_update_background_request_sec - curr_t_sec)*1000000 ;
2159 			wait_usec += last_update_background_request_usec ;
2160 			wait_usec -= curr_t_usec ;
2161 		}
2162 		if( wait_usec == 0 )
2163 			wait_usec = TIMEOUT_USEC ;
2164 		timeout->tv_usec = wait_usec;
2165 		timeout->tv_sec = 0 ; /*UPDATE_BACKGROUND_TIMEOUT_SEC;*/
2166 	}
2167 /*fprintf( stderr, "%s:%d select(%d, cmd_fd = %d, Xfd = %d, %p)...", __FUNCTION__, __LINE__, num_fds, cmd_fd,Xfd ,timeout ); */
2168 	retval = select(max(cmd_fd,Xfd)+1, &readfds, NULL, NULL, timeout );
2169 /*	fprintf( stderr, "Done(retval = %d).\n", retval); */
2170     /* See if we can read from the application */
2171 	if (FD_ISSET(cmd_fd, &readfds)) {
2172 	    int             n;
2173 	    unsigned int    count;
2174 
2175 	    cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
2176 	    for (count = BUFSIZ; count; count -= n, cmdbuf_endp += n)
2177 		if ((n = read(cmd_fd, cmdbuf_endp, count)) > 0)
2178 		    continue;
2179 		else if (n == 0 || (n < 0 && errno == EAGAIN))
2180 		    break;
2181 		else {
2182 #if !defined(HAVE_ATEXIT) && !defined(__sun__)
2183 		    clean_exit();
2184 #endif
2185 		    exit(EXIT_SUCCESS);
2186 		}
2187 	/* some characters read in */
2188 	    if (count != BUFSIZ)
2189 		goto Return_Char;
2190 	}
2191     /* select statement timed out - better update the screen */
2192 	if (retval == 0)
2193 	{
2194 	    	refresh_count = 0;
2195 	    	refresh_limit = 1;
2196 			if( last_update_background_request_sec > 0 )
2197 			{
2198 				time_t curr_t_sec, curr_t_usec;
2199 				timer_get_time (&curr_t_sec, &curr_t_usec);
2200 				if( (	last_update_background_request_sec == curr_t_sec &&
2201 						last_update_background_request_usec < curr_t_usec) ||
2202 					last_update_background_request_sec < curr_t_sec ||
2203 					last_update_background_request_sec-1 > curr_t_sec )
2204 				{
2205 					/* TODO update background pixmap */
2206 					RenderPixmap(1);
2207 					refresh_transparent_scrollbar();
2208 	        		scr_clear();
2209 					scr_touch();
2210 					refreshed = True ;
2211 				}
2212 			}
2213 	    	if (!refreshed)
2214 			{
2215 				refreshed = 1;
2216 				scr_refresh(refresh_type);
2217 				scrollbar_show(1);
2218 #ifdef USE_XIM
2219                 IMSendSpot();
2220 #endif
2221 		    }
2222 		}
2223     }
2224     /* NOTREACHED */
2225     return 0;
2226 
2227   Return_Char:
2228     refreshed = 0;
2229     return (*cmdbuf_ptr++);
2230 }
2231 /*}}} */
2232 
2233 /*
2234  * the 'essential' information for reporting Mouse Events
2235  * pared down from XButtonEvent
2236  */
2237 static struct {
2238     int             clicks;
2239     Time            time;	/* milliseconds */
2240     unsigned int    state;	/* key or button mask */
2241     unsigned int    button;	/* detail */
2242 } MEvent = {
2243     0, CurrentTime, 0, AnyButton
2244 };
2245 
2246 /* PROTO */
2247 void
2248 mouse_report(XButtonEvent * ev)
2249 {
2250     int             button_number, key_state = 0;
2251     int             x, y;
2252 
2253     x = ev->x;
2254     y = ev->y;
2255     pixel_position(&x, &y);
2256 
2257     button_number = ((MEvent.button == AnyButton) ? 3 :
2258 		     (MEvent.button - Button1));
2259 
2260     if (PrivateModes & PrivMode_MouseX10) {
2261     /*
2262      * do not report ButtonRelease
2263      * no state info allowed
2264      */
2265 	key_state = 0;
2266 	if (button_number == 3)
2267 	    return;
2268     } else {
2269     /* let's be explicit here ... from <X11/X.h>
2270      * #define ShiftMask        (1<<0)
2271      * #define ControlMask        (1<<2)
2272      * #define Mod1Mask           (1<<3)
2273      *
2274      * and XTerm mouse reporting needs these values:
2275      *   4 = Shift
2276      *   8 = Meta
2277      *  16 = Control
2278      * plus will add in our own Double-Click reporting
2279      *  32 = Double Click
2280      */
2281 	key_state = (((MEvent.state & (ShiftMask | ControlMask))
2282 		      + ((MEvent.state & Mod1Mask) ? 2 : 0)
2283 #ifdef MOUSE_REPORT_DOUBLECLICK
2284 		      + (MEvent.clicks > 1 ? 8 : 0)
2285 #endif
2286 		     ) << 2);
2287 	/* Report mouse wheel events. */
2288 	if (ev->button == Button4 || ev->button == Button5) {
2289 	    key_state |= 1 << 6;
2290 	    button_number = ev->button - Button4;
2291 	}
2292     }
2293 
2294 #ifdef DEBUG_MOUSEREPORT
2295     fprintf(stderr, "Mouse [");
2296     if (key_state & 16)
2297 	fputc('C', stderr);
2298     if (key_state & 4)
2299 	fputc('S', stderr);
2300     if (key_state & 2)
2301 	fputc('A', stderr);
2302     if (key_state & 32)
2303 	fputc('2', stderr);
2304     fprintf(stderr, "]: <%d>, %d/%d\n",
2305 	    button_number,
2306 	    x + 1,
2307 	    y + 1);
2308 #else
2309     tt_printf((unsigned char *) "\033[M%c%c%c",
2310 	      (32 + button_number + key_state),
2311 	      (32 + x + 1),
2312 	      (32 + y + 1));
2313 #endif
2314 }
2315 
2316 /*{{{ process an X event */
2317 /* PROTO */
2318 void
2319 process_x_event(XEvent * ev)
2320 {
2321     static int      bypass_keystate = 0;
2322     int             reportmode;
2323     static int      csrO = 0;	/* Hops - csr offset in thumb/slider      */
2324 
2325 
2326 #if !defined(NO_DEBUG_OUTPUT)
2327    	fprintf(stderr, "****************************************************************\n");
2328    	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);
2329 #endif
2330 
2331 /*        to give proper Scroll behaviour */
2332     switch (ev->type) {
2333     case KeyPress:
2334 	lookup_key(ev);
2335 	break;
2336 
2337 	case DestroyNotify :
2338 		if( ev->xdestroywindow.window == TermWin.vt || ev->xdestroywindow.window == TermWin.parent )
2339 		{
2340 #ifdef __CYGWIN__
2341     	/* cygwin does not kill shell properly */
2342 		/* fprintf( stderr, "cmd_pid = %d\n", cmd_pid ); */
2343 			kill( cmd_pid, SIGKILL );
2344 #endif
2345 		    exit(EXIT_SUCCESS);
2346 		}
2347 	    break ;
2348 
2349     case ClientMessage:
2350 	if (ev->xclient.format == 32 && ev->xclient.data.l[0] == wmDeleteWindow)
2351 	{
2352 #ifdef __CYGWIN__
2353     	/* cygwin does not kill shell properly */
2354 		/* fprintf( stderr, "cmd_pid = %d\n", cmd_pid ); */
2355 		kill( cmd_pid, SIGKILL );
2356 #endif
2357 	    exit(EXIT_SUCCESS);
2358 	}
2359 #ifdef OFFIX_DND
2360     /* OffiX Dnd (drag 'n' drop) protocol */
2361 	if (ev->xclient.message_type == DndProtocol &&
2362 	    ((ev->xclient.data.l[0] == DndFile) ||
2363 	     (ev->xclient.data.l[0] == DndDir) ||
2364 	     (ev->xclient.data.l[0] == DndLink))) {
2365 	/* Get Dnd data */
2366 	    Atom            ActualType;
2367 	    int             ActualFormat;
2368 	    unsigned char  *data;
2369 	    unsigned long   Size, RemainingBytes;
2370 
2371 	    XGetWindowProperty(Xdisplay, Xroot,
2372 			       DndSelection,
2373 			       0L, 1000000L,
2374 			       False, AnyPropertyType,
2375 			       &ActualType, &ActualFormat,
2376 			       &Size, &RemainingBytes,
2377 			       &data);
2378 	    XChangeProperty(Xdisplay, Xroot,
2379 			    XA_CUT_BUFFER0, XA_STRING,
2380 			    8, PropModeReplace,
2381 			    data, strlen(data));
2382 	    selection_paste(Xroot, XA_CUT_BUFFER0, True);
2383 	    XSetInputFocus(Xdisplay, Xroot, RevertToNone, CurrentTime);
2384 	}
2385 #endif				/* OFFIX_DND */
2386 	break;
2387 
2388     case MappingNotify:
2389 	XRefreshKeyboardMapping(&(ev->xmapping));
2390 	break;
2391 
2392     /* Here's my conclusiion:
2393      * If the window is completely unobscured, use bitblt's
2394      * to scroll. Even then, they're only used when doing partial
2395      * screen scrolling. When partially obscured, we have to fill
2396      * in the GraphicsExpose parts, which means that after each refresh,
2397      * we need to wait for the graphics expose or Noexpose events,
2398      * which ought to make things real slow!
2399      */
2400     case VisibilityNotify:
2401 	switch (ev->xvisibility.state) {
2402 	case VisibilityUnobscured:
2403 	    refresh_type = FAST_REFRESH;
2404 	    break;
2405 
2406 	case VisibilityPartiallyObscured:
2407 	    refresh_type = SLOW_REFRESH;
2408 	    break;
2409 
2410 	default:
2411 	    refresh_type = NO_REFRESH;
2412 	    break;
2413 	}
2414 	break;
2415 
2416     case FocusIn:
2417 	if (!TermWin.focus) {
2418 	    TermWin.focus = 1;
2419 #ifdef OFF_FOCUS_FADING
2420 	    if( rs_fade != NULL )
2421 	    {
2422     		PixColors = &(PixColorsFocused[0]);
2423 		on_colors_changed(Color_bg);
2424 	    }
2425 #endif
2426 #if  !defined(USE_XIM) && !defined(NO_XLOCALE)
2427 	    if (Input_Context != NULL)
2428 		XSetICFocus(Input_Context);
2429 #endif
2430 	}
2431 	break;
2432 
2433     case FocusOut:
2434 	if (TermWin.focus) {
2435 	    TermWin.focus = 0;
2436 #ifdef OFF_FOCUS_FADING
2437 	    if( rs_fade != NULL )
2438 	    {
2439 		PixColors = &(PixColorsUnFocused[0]);
2440 		on_colors_changed(Color_bg);
2441 	    }
2442 #endif
2443 #if  !defined(USE_XIM) && !defined(NO_XLOCALE)
2444 	    if (Input_Context != NULL)
2445 		XUnsetICFocus(Input_Context);
2446 #endif
2447 	}
2448 	break;
2449 
2450     case ConfigureNotify:
2451 	while( XCheckTypedWindowEvent( Xdisplay, ev->xconfigure.window, ConfigureNotify, ev ) );
2452 	resize_window(ev);
2453 	menubar_expose();
2454 	break;
2455 
2456     case SelectionClear:
2457 	selection_clear();
2458 	break;
2459 
2460     case SelectionNotify:
2461 	selection_paste(ev->xselection.requestor, ev->xselection.property, True);
2462 	break;
2463 
2464     case SelectionRequest:
2465 	selection_send(&(ev->xselectionrequest));
2466 	break;
2467 
2468      case PropertyNotify:
2469 #ifdef DEBUG_BACKGROUND_PMAP
2470 		{
2471 			char *prop_name = XGetAtomName( Xdisplay, ev->xproperty.atom );
2472         	fprintf( stderr, "PropertyNotify : %s(%lX)\n", prop_name, ev->xproperty.atom );
2473 			if( prop_name )
2474 	    		XFree( prop_name );
2475     	}
2476 #endif
2477 		if( ev->xproperty.window == Xroot )
2478 		{
2479 #ifdef HAVE_AFTERSTEP
2480 			if (ev->xproperty.atom == _AS_STYLE )
2481 			{
2482 				const char *mystyle_name ;
2483 	    		if( rs_mystyle )
2484 					mystyle_name = rs_mystyle ;
2485 	    		else
2486 					mystyle_name = GetDefaultMyStyle() ;
2487 
2488 				mystyle_handle_property_event( ev );
2489 	    		set_mystyle( mystyle_find( mystyle_name ), True );
2490 	    		break;
2491 			}else if( ev->xproperty.atom  == _XROOTPMAP_ID )
2492 			{
2493 				if( TermWin.background.trgType == BGT_MyStyle )
2494 				{
2495 					if(	!TransparentMS(TermWin.background.mystyle) )
2496 					{
2497 #ifdef DEBUG_BACKGROUND_PMAP
2498 						fprintf( stderr, "texture type = %d\n", TermWin.background.mystyle->texture_type );
2499 #endif
2500 	    				break ;
2501 					}
2502 					destroy_asimage( &Scr.RootImage );
2503 				}
2504 			}
2505 #endif
2506 #ifdef TRANSPARENT
2507 			if( ev->xproperty.atom  == _XROOTPMAP_ID )
2508 			{
2509 				if( IsTransparentPixmap() )
2510 				{
2511 					Pixmap p;
2512 					if( read_32bit_property (Xroot, _XROOTPMAP_ID, &p) )
2513 					{
2514 						if( p != TermWin.background.srcPixmap )
2515 							SetSrcPixmap( p );
2516 					}else
2517 						ValidateSrcPixmap(True);
2518 
2519 #ifdef DEBUG_BACKGROUND_PMAP
2520 					fprintf( stderr, "root pmap changed to = %lX\n", TermWin.background.srcPixmap );
2521 #endif
2522 
2523 					if( TransparentPixmapNeedsUpdate() )
2524 						request_background_update();
2525 				}else if( get_flags(Options, Opt_transparent) )
2526 				{
2527 			        scr_clear();
2528 	    		    scr_touch();
2529 				}
2530 			}
2531 #endif
2532 			if( ev->xproperty.atom  == _XA_NET_SUPPORTING_WM_CHECK )
2533 			{
2534 				check_extended_wm_hints_support();
2535 #ifdef DEBUG_BACKGROUND_PMAP
2536 				fprintf( stderr, "WM change. Desktops are %ssupported\n", get_flags( ExtWM.flags, WM_SupportsDesktops )?"":"not " );
2537 #endif
2538 			}else if( ev->xproperty.atom  == _XA_NET_CURRENT_DESKTOP )
2539 			{
2540 				if( !read_32bit_property (Xroot, _XA_NET_CURRENT_DESKTOP, &ExtWM.current_desktop) )
2541 					clear_flags( ExtWM.flags, WM_SupportsDesktops );
2542 				else if( get_flags( ExtWM.flags, WM_ClaimSupportsDesktops ) )
2543 					set_flags( ExtWM.flags, WM_SupportsDesktops	);
2544 
2545 
2546 #ifdef DEBUG_BACKGROUND_PMAP
2547 				fprintf( stderr, "Curr Desk change to %ld. Desktops are %ssupported\n", ExtWM.current_desktop, get_flags( ExtWM.flags, WM_SupportsDesktops )?"":"not " );
2548 #endif
2549 				/* Don't do it here - wait for background change :
2550 				 * if( TransparentPixmapNeedsUpdate() )
2551 					request_background_update();
2552 				 */
2553 			}
2554 		}
2555 		if( ev->xproperty.window == TermWin.parent )
2556 		{
2557 			if( ev->xproperty.atom  == _XA_NET_WM_DESKTOP )
2558 			{
2559 #ifdef DEBUG_BACKGROUND_PMAP
2560 				fprintf( stderr, "Aterm Desk change from %ld. Desktops are %ssupported\n", ExtWM.aterm_desktop, get_flags( ExtWM.flags, WM_SupportsDesktops )?"":"not " );
2561 #endif
2562 				if( !read_32bit_property (TermWin.parent, _XA_NET_WM_DESKTOP, &ExtWM.aterm_desktop) )
2563 					clear_flags( ExtWM.flags, WM_SupportsDesktops );
2564 #ifdef DEBUG_BACKGROUND_PMAP
2565 				fprintf( stderr, "Aterm Desk change to %ld. Desktops are %ssupported\n", ExtWM.aterm_desktop, get_flags( ExtWM.flags, WM_SupportsDesktops )?"":"not " );
2566 #endif
2567 				if( TransparentPixmapNeedsUpdate() )
2568 					request_background_update();
2569 			}else if( ev->xproperty.atom  == _XA_NET_WM_STATE )
2570 			{
2571 				if( check_extended_wm_state() )
2572 					if( TransparentPixmapNeedsUpdate() )
2573 						request_background_update();
2574 #ifdef DEBUG_BACKGROUND_PMAP
2575 				fprintf( stderr, "Aterm state change to: %sSticky, %sShaded, %sHidden\n",
2576 								 get_flags( ExtWM.flags, WM_AtermStateSticky )?"":"not ",
2577 								 get_flags( ExtWM.flags, WM_AtermStateShaded )?"":"not ",
2578 								 get_flags( ExtWM.flags, WM_AtermStateHidden )?"":"not " );
2579 #endif
2580 
2581 			}
2582 		}
2583 		break;
2584      case UnmapNotify:
2585         TermWin.bMapped = 0 ;
2586 /*	fprintf(stderr, "\n aterm is UnMapped(event)");*/
2587 	break;
2588 
2589      case MapNotify:
2590 /*        {
2591 	  XWindowAttributes attr ;
2592 
2593 	    XGetWindowAttributes( Xdisplay, ParentWin[0], &attr );
2594 	    TermWin.bMapped = (attr.map_state == IsViewable)?1:0 ;
2595 
2596 	    fprintf(stderr, "\n aterm is %s", (TermWin.bMapped)?"Mapped":"UnMapped");
2597 	}*/
2598 /*        fprintf(stderr, "\n aterm is %s", (TermWin.bMapped)?"Mapped":"UnMapped");*/
2599 	TermWin.bMapped = 1 ;
2600 #ifdef TRANSPARENT
2601 	if ( TransparentPixmapNeedsUpdate() )
2602 		request_background_update();
2603 #endif
2604 #if 0
2605 	refresh_transparent_scrollbar();
2606 	if( Options & Opt_transparent)
2607 	{
2608 	  Pixmap tmp = GetRootPixmap(None);
2609 	    if( tmp != TermWin.background.srcPixmap && TermWin.background.srcPixmap != None )
2610 	    {
2611 	        if( TermWin.background.trgType != BGT_None )
2612 	        {
2613 	            SetSrcPixmap(tmp);
2614 	            RenderPixmap(0);
2615 	        }
2616 	        scr_clear();
2617 	        scr_touch();
2618 	    }
2619 	}
2620 #endif
2621 	break ;
2622      case ReparentNotify:
2623 #ifdef TRANSPARENT
2624          {
2625 	    int n;
2626 	    XWindowAttributes attr ;
2627             int (*oldXErrorHandler) (Display *, XErrorEvent *) =
2628 		  XSetErrorHandler (pixmap_error_handler);
2629 
2630 	    for( n = 1 ; n < PARENTS_NUM ; n ++ )    ParentWin[n] = None;
2631 	    /*
2632 	     * Make the frame window set by the window manager have
2633 	     * the root background. Some window managers put few nested frame
2634 	     * windows for each client, so we have to take care about that.
2635 	     */
2636 	    for( ParentWinNum = 1 ;ParentWinNum<PARENTS_NUM; ParentWinNum++)
2637 	    {
2638 		Window root;
2639 		Window parent;
2640 		Window *list;
2641 
2642 		XQueryTree(Xdisplay, ParentWin[ParentWinNum-1], &root, &parent, &list, &n);
2643 		XFree(list);
2644    		if (parent == Xroot) break;
2645 	        ParentWin[ParentWinNum] = parent;
2646 		/* we want to get all map/unmap events from this window as well*/
2647 	/*	XSelectInput(Xdisplay, parent, StructureNotifyMask); */
2648 
2649 		if (Options & Opt_transparent)
2650 		    XSetWindowBackgroundPixmap(Xdisplay, parent, ParentRelative);
2651 	    }
2652 	    if( XGetWindowAttributes( Xdisplay, ParentWin[0], &attr ))
2653 		TermWin.bMapped = (attr.map_state == IsViewable)?1:0 ;
2654 
2655 	    XSetErrorHandler (oldXErrorHandler);
2656     	    scr_clear();
2657 	}
2658 #endif /* TRANSPARENT */
2659 	break;
2660     case GraphicsExpose:
2661     case Expose:
2662 	if (ev->xany.window == TermWin.vt) {
2663 #if !defined(NO_DEBUG_OUTPUT)
2664    	fprintf(stderr, "exposed area = %dx%d%+d%+d\n", ev->xexpose.x, ev->xexpose.y,
2665 		       										ev->xexpose.width, ev->xexpose.height);
2666 #endif
2667 	    scr_expose(ev->xexpose.x, ev->xexpose.y,
2668 		       ev->xexpose.width, ev->xexpose.height);
2669 	} else {
2670 	    XEvent          unused_xevent;
2671 
2672 	    while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window,
2673 					  Expose,
2674 					  &unused_xevent)) ;
2675 	    while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window,
2676 					  GraphicsExpose,
2677 					  &unused_xevent)) ;
2678 	    if (isScrollbarWindow(ev->xany.window)) {
2679 		scrollbar_setNone();
2680 		scrollbar_show(0);
2681 	    }
2682 	    if (menubar_visible() && isMenuBarWindow(ev->xany.window))
2683 		menubar_expose();
2684 	    Gr_expose(ev->xany.window);
2685 	}
2686 	break;
2687 
2688     case ButtonPress:
2689 	bypass_keystate = (ev->xbutton.state & (Mod1Mask | ShiftMask));
2690 	reportmode = (bypass_keystate ?
2691 		      0 : (PrivateModes & PrivMode_mouse_report));
2692 
2693 	if (ev->xany.window == TermWin.vt) {
2694 	    if (ev->xbutton.subwindow != None)
2695 		Gr_ButtonPress(ev->xbutton.x, ev->xbutton.y);
2696 	    else {
2697 		if (reportmode) {
2698 		/* mouse report from vt window */
2699 		/* save the xbutton state (for ButtonRelease) */
2700 		    MEvent.state = ev->xbutton.state;
2701 #ifdef MOUSE_REPORT_DOUBLECLICK
2702 		    if (ev->xbutton.button == MEvent.button
2703 		     && (ev->xbutton.time - MEvent.time < MULTICLICK_TIME)) {
2704 		    /* same button, within alloted time */
2705 			MEvent.clicks++;
2706 			if (MEvent.clicks > 1) {
2707 			/* only report double clicks */
2708 			    MEvent.clicks = 2;
2709 			    mouse_report(&(ev->xbutton));
2710 
2711 			/* don't report the release */
2712 			    MEvent.clicks = 0;
2713 			    MEvent.button = AnyButton;
2714 			}
2715 		    } else {
2716 		    /* different button, or time expired */
2717 			MEvent.clicks = 1;
2718 			MEvent.button = ev->xbutton.button;
2719 			mouse_report(&(ev->xbutton));
2720 		    }
2721 #else
2722 		    MEvent.button = ev->xbutton.button;
2723 		    mouse_report(&(ev->xbutton));
2724 #endif				/* MOUSE_REPORT_DOUBLECLICK */
2725 		} else {
2726 		    if (ev->xbutton.button != MEvent.button)
2727 			MEvent.clicks = 0;
2728 		    switch (ev->xbutton.button) {
2729 		    case Button1:
2730 			if (MEvent.button == Button1
2731 			&& (ev->xbutton.time - MEvent.time < MULTICLICK_TIME))
2732 			    MEvent.clicks++;
2733 			else
2734 			    MEvent.clicks = 1;
2735 			selection_click(MEvent.clicks, ev->xbutton.x,
2736 					ev->xbutton.y);
2737 			MEvent.button = Button1;
2738 			break;
2739 
2740 		    case Button3:
2741 			if (MEvent.button == Button3
2742 			&& (ev->xbutton.time - MEvent.time < MULTICLICK_TIME))
2743 			    selection_rotate(ev->xbutton.x, ev->xbutton.y);
2744 			else
2745 			    selection_extend(ev->xbutton.x, ev->xbutton.y, 1);
2746 			MEvent.button = Button3;
2747 			break;
2748 		    }
2749 		}
2750 		MEvent.time = ev->xbutton.time;
2751 		return;
2752 	    }
2753 	}
2754 	if (isScrollbarWindow(ev->xany.window)) {
2755 	    scrollbar_setNone();
2756 	/*
2757 	 * Rxvt-style scrollbar:
2758 	 * move up if mouse is above slider
2759 	 * move dn if mouse is below slider
2760 	 *
2761 	 * XTerm-style scrollbar:
2762 	 * Move display proportional to pointer location
2763 	 * pointer near top -> scroll one line
2764 	 * pointer near bot -> scroll full page
2765 	 */
2766 #ifndef NO_SCROLLBAR_REPORT
2767 	    if (reportmode) {
2768 	    /*
2769 	     * Mouse report disabled scrollbar:
2770 	     * arrow buttons - send up/down
2771 	     * click on scrollbar - send pageup/down
2772 	     */
2773 		if (scrollbar_upButton(ev->xbutton.y))
2774 		    tt_printf((unsigned char *) "\033[A");
2775 		else if (scrollbar_dnButton(ev->xbutton.y))
2776 		    tt_printf((unsigned char *) "\033[B");
2777 		else
2778 		    switch (ev->xbutton.button) {
2779 		    case Button2:
2780 			tt_printf((unsigned char *) "\014");
2781 			break;
2782 		    case Button1:
2783 			tt_printf((unsigned char *) "\033[6~");
2784 			break;
2785 		    case Button3:
2786 			tt_printf((unsigned char *) "\033[5~");
2787 			break;
2788 		    }
2789 	    } else
2790 #endif				/* NO_SCROLLBAR_REPORT */
2791 	    {
2792 		if (scrollbar_upButton(ev->xbutton.y)) {
2793 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2794 		    scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
2795 #endif
2796 		    if (scr_page(UP, 1))
2797 			scrollbar_setUp();
2798 		} else if (scrollbar_dnButton(ev->xbutton.y)) {
2799 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2800 		    scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
2801 #endif
2802 		    if (scr_page(DN, 1))
2803 			scrollbar_setDn();
2804 		} else
2805 		    switch (ev->xbutton.button) {
2806 		    case Button2:
2807 #ifndef FUNKY_SCROLL_BEHAVIOUR
2808 			csrO = (scrollBar.bot - scrollBar.top) / 2;
2809 		    /* align to thumb center */
2810 #else
2811 # ifndef XTERM_SCROLLBAR
2812 			if (scrollbar_above_slider(ev->xbutton.y) ||
2813 			    scrollbar_below_slider(ev->xbutton.y))
2814 # endif
2815 #endif				/* !FUNKY_SCROLL_BEHAVIOUR */
2816 			    scr_move_to(scrollbar_position(ev->xbutton.y) - csrO,
2817 					scrollbar_size());
2818 			scrollbar_setMotion();
2819 			break;
2820 
2821 		    case Button1:
2822 #ifndef FUNKY_SCROLL_BEHAVIOUR
2823 			csrO = ev->xbutton.y - scrollBar.top;
2824 		    /* ptr ofset in thumb */
2825 #endif
2826 		    /*drop */
2827 
2828 		    case Button3:
2829 #ifndef XTERM_SCROLLBAR
2830 			if (scrollbar_above_slider(ev->xbutton.y))
2831 # ifdef RXVT_SCROLL_FULL
2832 			    scr_page(UP, TermWin.nrow - 1);
2833 # else
2834 			    scr_page(UP, TermWin.nrow / 4);
2835 # endif
2836 			else if (scrollbar_below_slider(ev->xbutton.y))
2837 # ifdef RXVT_SCROLL_FULL
2838 			    scr_page(DN, TermWin.nrow - 1);
2839 # else
2840 			    scr_page(DN, TermWin.nrow / 4);
2841 # endif
2842 			else
2843 			    scrollbar_setMotion();
2844 #else				/* XTERM_SCROLLBAR */
2845 			scr_page((ev->xbutton.button == Button1 ? DN : UP),
2846 				 (TermWin.nrow *
2847 				  scrollbar_position(ev->xbutton.y) /
2848 				  scrollbar_size())
2849 			    );
2850 #endif				/* XTERM_SCROLLBAR */
2851 			break;
2852 		    }
2853 	    }
2854 	    return;
2855 	}
2856 	if (isMenuBarWindow(ev->xany.window)) {
2857 	    menubar_control(&(ev->xbutton));
2858 	    return;
2859 	}
2860 	break;
2861 
2862     case ButtonRelease:
2863 	csrO = 0;		/* reset csr Offset */
2864 	reportmode = (bypass_keystate ?
2865 		      0 : (PrivateModes & PrivMode_mouse_report));
2866 
2867 	if (scrollbar_isUpDn()) {
2868 	    scrollbar_setNone();
2869 	    scrollbar_show(0);
2870 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2871 	    refresh_type &= ~SMOOTH_REFRESH;
2872 #endif
2873 	}
2874 	if (ev->xany.window == TermWin.vt) {
2875 	    if (ev->xbutton.subwindow != None)
2876 		Gr_ButtonRelease(ev->xbutton.x, ev->xbutton.y);
2877 	    else {
2878 		if (reportmode) {
2879 		/* Don't report release events for the mouse wheel */
2880 		if (ev->xbutton.button == Button4 || ev->xbutton.button == Button5)
2881 		    return;
2882 		/* mouse report from vt window */
2883 #ifdef MOUSE_REPORT_DOUBLECLICK
2884 		/* only report the release of 'slow' single clicks */
2885 		    if (MEvent.button != AnyButton &&
2886 			(ev->xbutton.button != MEvent.button ||
2887 		      (ev->xbutton.time - MEvent.time > MULTICLICK_TIME / 2))
2888 			) {
2889 			MEvent.clicks = 0;
2890 			MEvent.button = AnyButton;
2891 			mouse_report(&(ev->xbutton));
2892 		    }
2893 #else				/* MOUSE_REPORT_DOUBLECLICK */
2894 		    MEvent.button = AnyButton;
2895 		    mouse_report(&(ev->xbutton));
2896 #endif				/* MOUSE_REPORT_DOUBLECLICK */
2897 		    return;
2898 		}
2899 	    /*
2900 	     * dumb hack to compensate for the failure of click-and-drag
2901 	     * when overriding mouse reporting
2902 	     */
2903 		if ((PrivateModes & PrivMode_mouse_report) &&
2904 		    (bypass_keystate) &&
2905 		    (ev->xbutton.button == Button1) &&
2906 		    (MEvent.clicks <= 1))
2907 		    selection_extend(ev->xbutton.x, ev->xbutton.y, 0);
2908 
2909 		switch (ev->xbutton.button) {
2910 		case Button1:
2911 		case Button3:
2912 		    selection_make(ev->xbutton.time, ev->xbutton.state);
2913 		    break;
2914 
2915 		case Button2:
2916 		    selection_request(ev->xbutton.time,
2917 				      ev->xbutton.x, ev->xbutton.y);
2918 		    break;
2919 #ifndef NO_MOUSE_WHEEL
2920 		case Button4:
2921 		    scr_page(UP, (ev->xbutton.state & ShiftMask) ? 1 : 5);
2922 		    break;
2923 		case Button5:
2924 		    scr_page(DN, (ev->xbutton.state & ShiftMask) ? 1 : 5);
2925 		    break;
2926 #endif
2927 		}
2928 	    }
2929 	} else if (isMenuBarWindow(ev->xany.window)) {
2930 	    menubar_control(&(ev->xbutton));
2931 	}
2932 	break;
2933 
2934     case MotionNotify:
2935 	if (isMenuBarWindow(ev->xany.window)) {
2936 	    menubar_control(&(ev->xbutton));
2937 	    break;
2938 	}
2939 	if ((PrivateModes & PrivMode_mouse_report) && !(bypass_keystate))
2940 	    break;
2941 
2942 	if (ev->xany.window == TermWin.vt) {
2943 	    if ((ev->xbutton.state & (Button1Mask | Button3Mask))) {
2944 		Window          unused_root, unused_child;
2945 		int             unused_root_x, unused_root_y;
2946 		unsigned int    unused_mask;
2947 
2948 		while (XCheckTypedWindowEvent(Xdisplay, TermWin.vt,
2949 					      MotionNotify, ev)) ;
2950 		XQueryPointer(Xdisplay, TermWin.vt,
2951 			      &unused_root, &unused_child,
2952 			      &unused_root_x, &unused_root_y,
2953 			      &(ev->xbutton.x), &(ev->xbutton.y),
2954 			      &unused_mask);
2955 #ifdef MOUSE_THRESHOLD
2956 	    /* deal with a `jumpy' mouse */
2957 		if ((ev->xmotion.time - MEvent.time) > MOUSE_THRESHOLD)
2958 #endif
2959 		    selection_extend((ev->xbutton.x), (ev->xbutton.y),
2960 				  (ev->xbutton.state & Button3Mask) ? 2 : 0);
2961 	    }
2962 	} else if ((ev->xany.window == scrollBar.win) && scrollbar_isMotion()) {
2963 	    Window          unused_root, unused_child;
2964 	    int             unused_root_x, unused_root_y;
2965 	    unsigned int    unused_mask;
2966 
2967 	    while (XCheckTypedWindowEvent(Xdisplay, scrollBar.win,
2968 					  MotionNotify, ev)) ;
2969 	    XQueryPointer(Xdisplay, scrollBar.win,
2970 			  &unused_root, &unused_child,
2971 			  &unused_root_x, &unused_root_y,
2972 			  &(ev->xbutton.x), &(ev->xbutton.y),
2973 			  &unused_mask);
2974 	    scr_move_to(scrollbar_position(ev->xbutton.y) - csrO,
2975 			scrollbar_size());
2976 	    scr_refresh(refresh_type);
2977 	    refresh_count = refresh_limit = 0;
2978 	    scrollbar_show(1);
2979 #ifdef USE_XIM
2980             IMSendSpot();
2981 #endif
2982 	}
2983 	break;
2984     }
2985 }
2986 /*}}} */
2987 
2988 /*
2989  * Send printf() formatted output to the command.
2990  * Only use for small ammounts of data.
2991  */
2992 /* PROTO */
2993 void
2994 tt_printf(const unsigned char *fmt,...)
2995 {
2996 	static unsigned char buf[TT_PRINTF_LIMIT];
2997     va_list         arg_ptr;
2998 
2999     va_start(arg_ptr, fmt);
3000     vsprintf((char *) buf, (char *) fmt, arg_ptr);
3001     va_end(arg_ptr);
3002     tt_write(buf, strlen(buf));
3003 }
3004 
3005 /*}}} */
3006 
3007 /*{{{ print pipe */
3008 /*----------------------------------------------------------------------*/
3009 #ifdef PRINTPIPE
3010 /* PROTO */
3011 FILE           *
3012 popen_printer(void)
3013 {
3014     FILE           *stream = popen(rs_print_pipe, "w");
3015 
3016     if (stream == NULL)
3017 	print_error("can't open printer pipe");
3018     return stream;
3019 }
3020 
3021 /* PROTO */
3022 int
3023 pclose_printer(FILE * stream)
3024 {
3025     fflush(stream);
3026 /* pclose() reported not to work on SunOS 4.1.3 */
3027 #if defined (__sun__)		/* TODO: RESOLVE THIS */
3028 /* pclose works provided SIGCHLD handler uses waitpid */
3029     return pclose(stream);	/* return fclose (stream); */
3030 #else
3031     return pclose(stream);
3032 #endif
3033 }
3034 
3035 /*
3036  * simulate attached vt100 printer
3037  */
3038 /* PROTO */
3039 void
3040 process_print_pipe(void)
3041 {
3042     int		    done;
3043     FILE           *fd;
3044 
3045     if ((fd = popen_printer()) == NULL)
3046 	return;
3047 
3048 /*
3049  * Send all input to the printer until either ESC[4i or ESC[?4i
3050  * is received.
3051  */
3052     for (done = 0; !done;) {
3053 	unsigned char   buf[8];
3054 	unsigned char   ch;
3055 	unsigned int    i, len;
3056 
3057 	if ((ch = cmd_getc()) != '\033') {
3058 	    if (putc(ch, fd) == EOF)
3059 		break;		/* done = 1 */
3060 	} else {
3061 	    len = 0;
3062 	    buf[len++] = ch;
3063 
3064 	    if ((buf[len++] = cmd_getc()) == '[') {
3065 		if ((ch = cmd_getc()) == '?') {
3066 		    buf[len++] = '?';
3067 		    ch = cmd_getc();
3068 		}
3069 		if ((buf[len++] = ch) == '4') {
3070 		    if ((buf[len++] = cmd_getc()) == 'i')
3071 			break;	/* done = 1 */
3072 	        }
3073 	    }
3074 	    for (i = 0; i < len; i++)
3075 		if (putc(buf[i], fd) == EOF) {
3076 		    done = 1;
3077 		    break;
3078 		}
3079 	}
3080     }
3081     pclose_printer(fd);
3082 }
3083 #endif				/* PRINTPIPE */
3084 /*}}} */
3085 
3086 /*{{{ process escape sequences */
3087 /* PROTO */
3088 void
3089 process_escape_seq(void)
3090 {
3091     unsigned char   ch = cmd_getc();
3092 
3093     switch (ch) {
3094     /* case 1:        do_tek_mode (); break; */
3095     case '#':
3096 	if (cmd_getc() == '8')
3097 	    scr_E();
3098 	break;
3099     case '(':
3100 	scr_charset_set(0, cmd_getc());
3101 	break;
3102     case ')':
3103 	scr_charset_set(1, cmd_getc());
3104 	break;
3105     case '*':
3106 	scr_charset_set(2, cmd_getc());
3107 	break;
3108     case '+':
3109 	scr_charset_set(3, cmd_getc());
3110 	break;
3111 #ifdef MULTICHAR_SET
3112     case '$':
3113 	scr_charset_set(-2, cmd_getc());
3114 	break;
3115 #endif
3116     case '7':
3117 	scr_cursor(SAVE);
3118 	break;
3119     case '8':
3120 	scr_cursor(RESTORE);
3121 	break;
3122     case '=':
3123     case '>':
3124 	PrivMode((ch == '='), PrivMode_aplKP);
3125 	break;
3126     case '@':
3127 	(void)cmd_getc();
3128 	break;
3129     case 'D':
3130 	scr_index(UP);
3131 	break;
3132     case 'E':
3133 	scr_add_lines((unsigned char *) "\n\r", 1, 2);
3134 	break;
3135     case 'G':
3136 	process_graphics();
3137 	break;
3138     case 'H':
3139 	scr_set_tab(1);
3140 	break;
3141     case 'M':
3142 	scr_index(DN);
3143 	break;
3144     /*case 'N': scr_single_shift (2);   break; */
3145     /*case 'O': scr_single_shift (3);   break; */
3146     case 'Z':
3147 	tt_printf((unsigned char *) ESCZ_ANSWER);
3148 	break;			/* steal obsolete ESC [ c */
3149     case '[':
3150 	process_csi_seq();
3151 	break;
3152     case ']':
3153 	process_xterm_seq();
3154 	break;
3155     case 'c':
3156 	scr_poweron();
3157 	break;
3158     case 'n':
3159 	scr_charset_choose(2);
3160 	break;
3161     case 'o':
3162 	scr_charset_choose(3);
3163 	break;
3164     }
3165 }
3166 /*}}} */
3167 
3168 /*{{{ process CSI (code sequence introducer) sequences `ESC[' */
3169 /* PROTO */
3170 void
3171 process_csi_seq(void)
3172 {
3173     unsigned char   ch, priv;
3174     unsigned int    nargs;
3175     int             arg[ESC_ARGS];
3176 
3177     nargs = 0;
3178     arg[0] = 0;
3179     arg[1] = 0;
3180 
3181     priv = 0;
3182     ch = cmd_getc();
3183     if (ch >= '<' && ch <= '?') {
3184 	priv = ch;
3185 	ch = cmd_getc();
3186     }
3187 /* read any numerical arguments */
3188     do {
3189 	int             n;
3190 
3191 	for (n = 0; isdigit(ch); ch = cmd_getc())
3192 	    n = n * 10 + (ch - '0');
3193 
3194 	if (nargs < ESC_ARGS)
3195 	    arg[nargs++] = n;
3196 	if (ch == '\b') {
3197 	    scr_backspace();
3198 	} else if (ch == 033) {
3199 	    process_escape_seq();
3200 	    return;
3201 	} else if (ch < ' ') {
3202 	    scr_add_lines(&ch, 0, 1);
3203 	    return;
3204 	}
3205 	if (ch < '@')
3206 	    ch = cmd_getc();
3207     }
3208     while (ch >= ' ' && ch < '@');
3209     if (ch == 033) {
3210 	process_escape_seq();
3211 	return;
3212     } else if (ch < ' ')
3213 	return;
3214 
3215     switch (ch) {
3216 #ifdef PRINTPIPE
3217     case 'i':			/* printing */
3218 	switch (arg[0]) {
3219 	case 0:
3220 	    scr_printscreen(0);
3221 	    break;
3222 	case 5:
3223 	    process_print_pipe();
3224 	    break;
3225 	}
3226 	break;
3227 #endif
3228     case 'A':
3229     case 'e':			/* up <n> */
3230 	scr_gotorc((arg[0] ? -arg[0] : -1), 0, RELATIVE);
3231 	break;
3232     case 'B':			/* down <n> */
3233 	scr_gotorc((arg[0] ? +arg[0] : +1), 0, RELATIVE);
3234 	break;
3235     case 'C':
3236     case 'a':			/* right <n> */
3237 	scr_gotorc(0, (arg[0] ? +arg[0] : +1), RELATIVE);
3238 	break;
3239     case 'D':			/* left <n> */
3240 	scr_gotorc(0, (arg[0] ? -arg[0] : -1), RELATIVE);
3241 	break;
3242     case 'E':			/* down <n> & to first column */
3243 	scr_gotorc((arg[0] ? +arg[0] : +1), 0, R_RELATIVE);
3244 	break;
3245     case 'F':			/* up <n> & to first column */
3246 	scr_gotorc((arg[0] ? -arg[0] : -1), 0, R_RELATIVE);
3247 	break;
3248     case 'G':
3249     case '`':			/* move to col <n> */
3250 	scr_gotorc(0, (arg[0] ? arg[0] - 1 : +1), R_RELATIVE);
3251 	break;
3252     case 'd':			/* move to row <n> */
3253 	scr_gotorc((arg[0] ? arg[0] - 1 : +1), 0, C_RELATIVE);
3254 	break;
3255     case 'H':
3256     case 'f':			/* position cursor */
3257 	switch (nargs) {
3258 	case 0:
3259 	    scr_gotorc(0, 0, 0);
3260 	    break;
3261 	case 1:
3262 	    scr_gotorc((arg[0] ? arg[0] - 1 : 0), 0, 0);
3263 	    break;
3264 	default:
3265 	    scr_gotorc(arg[0] - 1, arg[1] - 1, 0);
3266 	    break;
3267 	}
3268 	break;
3269     case 'I':
3270 	scr_tab(arg[0] ? +arg[0] : +1);
3271 	break;
3272     case 'Z':
3273 	scr_tab(arg[0] ? -arg[0] : -1);
3274 	break;
3275     case 'J':
3276 	scr_erase_screen(arg[0]);
3277 	break;
3278     case 'K':
3279 	scr_erase_line(arg[0]);
3280 	break;
3281     case '@':
3282 	scr_insdel_chars((arg[0] ? arg[0] : 1), INSERT);
3283 	break;
3284     case 'L':
3285 	scr_insdel_lines((arg[0] ? arg[0] : 1), INSERT);
3286 	break;
3287     case 'M':
3288 	scr_insdel_lines((arg[0] ? arg[0] : 1), DELETE);
3289 	break;
3290     case 'X':
3291 	scr_insdel_chars((arg[0] ? arg[0] : 1), ERASE);
3292 	break;
3293     case 'P':
3294 	scr_insdel_chars((arg[0] ? arg[0] : 1), DELETE);
3295 	break;
3296 
3297     case 'c':
3298 	tt_printf((unsigned char *) VT100_ANS);
3299 	break;
3300     case 'm':
3301 	process_sgr_mode(nargs, arg);
3302 	break;
3303     case 'n':			/* request for information */
3304 	switch (arg[0]) {
3305 	case 5:
3306 	    tt_printf((unsigned char *) "\033[0n");
3307 	    break;		/* ready */
3308 	case 6:
3309 	    scr_report_position();
3310 	    break;
3311 #if defined (ENABLE_DISPLAY_ANSWER)
3312 	case 7:
3313 		if( strlen(display_name)  < TT_PRINTF_LIMIT-2 )
3314 	    	tt_printf((unsigned char *) "%s\n", display_name);
3315 	    break;
3316 #endif
3317 	case 8:
3318 	    xterm_seq(XTerm_title, APL_NAME "-" VERSION);
3319 	    break;
3320 	}
3321 	break;
3322     case 'r':			/* set top and bottom margins */
3323 	if (priv != '?') {
3324 	    if (nargs < 2 || arg[0] >= arg[1])
3325 		scr_scroll_region(0, 10000);
3326 	    else
3327 		scr_scroll_region(arg[0] - 1, arg[1] - 1);
3328 	    break;
3329 	}
3330     /* drop */
3331     case 's':
3332     case 't':
3333 		if(arg[0] == 21)
3334 			tt_printf((unsigned char *) "\033]l%s\033\\", rs_title);
3335         break;
3336     case 'h':
3337     case 'l':
3338 	process_terminal_mode(ch, priv, nargs, arg);
3339 	break;
3340     case 'g':
3341 	switch (arg[0]) {
3342 	case 0:
3343 	    scr_set_tab(0);
3344 	    break;		/* delete tab */
3345 	case 3:
3346 	    scr_set_tab(-1);
3347 	    break;		/* clear all tabs */
3348 	}
3349 	break;
3350     case 'W':
3351 	switch (arg[0]) {
3352 	case 0:
3353 	    scr_set_tab(1);
3354 	    break;		/* = ESC H */
3355 	case 2:
3356 	    scr_set_tab(0);
3357 	    break;		/* = ESC [ 0 g */
3358 	case 5:
3359 	    scr_set_tab(-1);
3360 	    break;		/* = ESC [ 3 g */
3361 	}
3362 	break;
3363     }
3364 }
3365 /*}}} */
3366 
3367 /*{{{ process xterm text parameters sequences `ESC ] Ps ; Pt BEL' */
3368 /* PROTO */
3369 void
3370 process_xterm_seq(void)
3371 {
3372     unsigned char   ch, string[STRING_MAX];
3373     int             arg;
3374 
3375     ch = cmd_getc();
3376     for (arg = 0; isdigit(ch); ch = cmd_getc())
3377 	arg = arg * 10 + (ch - '0');
3378 
3379     if (ch == ';') {
3380 	int             n = 0;
3381 
3382 	while ((ch = cmd_getc()) != 007) {
3383 	    if (ch) {
3384 		if (ch == '\t')
3385 		    ch = ' ';	/* translate '\t' to space */
3386 		else if (ch < ' ')
3387 		    return;	/* control character - exit */
3388 
3389 		if (n < sizeof(string) - 1)
3390 		    string[n++] = ch;
3391 	    }
3392 	}
3393 	string[n] = '\0';
3394     /*
3395      * menubar_dispatch() violates the constness of the string,
3396      * so do it here
3397      */
3398 	if (arg == XTerm_Menu)
3399 	    menubar_dispatch((char *) string);
3400 	else
3401 	    xterm_seq(arg, (char *) string);
3402     }
3403 }
3404 /*}}} */
3405 
3406 /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3407 /*
3408  * mode can only have the following values:
3409  *      'l' = low
3410  *      'h' = high
3411  *      's' = save
3412  *      'r' = restore
3413  *      't' = toggle
3414  * so no need for fancy checking
3415  */
3416 /* PROTO */
3417 void
3418 process_terminal_mode(int mode, int priv, unsigned int nargs, int arg[])
3419 {
3420     unsigned int    i;
3421     int             state;
3422 
3423     if (nargs == 0)
3424 	return;
3425 
3426 /* make lo/hi boolean */
3427     switch (mode) {
3428     case 'l':
3429 	mode = 0;
3430 	break;
3431     case 'h':
3432 	mode = 1;
3433 	break;
3434     }
3435 
3436     switch (priv) {
3437     case 0:
3438 	if (mode && mode != 1)
3439 	    return;		/* only do high/low */
3440 	for (i = 0; i < nargs; i++)
3441 	    switch (arg[i]) {
3442 	    case 4:
3443 		scr_insert_mode(mode);
3444 		break;
3445 	    /* case 38:  TEK mode */
3446 	    }
3447 	break;
3448 
3449 #define PrivCases(bit)							\
3450     if (mode == 't')							\
3451 	state = !(PrivateModes & bit);					\
3452     else								\
3453         state = mode;							\
3454     switch (state) {							\
3455     case 's':								\
3456 	SavedModes |= (PrivateModes & bit);				\
3457 	continue;							\
3458 	break;								\
3459     case 'r':								\
3460 	state = (SavedModes & bit) ? 1 : 0;				\
3461 	/* FALLTHROUGH */						\
3462     default:								\
3463 	PrivMode (state, bit);						\
3464     }
3465 
3466     case '?':
3467 	for (i = 0; i < nargs; i++)
3468 	    switch (arg[i]) {
3469 	    case 1:		/* application cursor keys */
3470 		PrivCases(PrivMode_aplCUR);
3471 		break;
3472 
3473 	    /* case 2:   - reset charsets to USASCII */
3474 
3475 	    case 3:		/* 80/132 */
3476 		PrivCases(PrivMode_132);
3477 		if (PrivateModes & PrivMode_132OK)
3478 		    set_width(state ? 132 : 80);
3479 		break;
3480 
3481 	    /* case 4:   - smooth scrolling */
3482 
3483 	    case 5:		/* reverse video */
3484 		PrivCases(PrivMode_rVideo);
3485 		scr_rvideo_mode(state);
3486 		break;
3487 
3488 	    case 6:		/* relative/absolute origins  */
3489 		PrivCases(PrivMode_relOrigin);
3490 		scr_relative_origin(state);
3491 		break;
3492 
3493 	    case 7:		/* autowrap */
3494 		PrivCases(PrivMode_Autowrap);
3495 		scr_autowrap(state);
3496 		break;
3497 
3498 	    /* case 8:   - auto repeat, can't do on a per window basis */
3499 
3500 	    case 9:		/* X10 mouse reporting */
3501 		PrivCases(PrivMode_MouseX10);
3502 	    /* orthogonal */
3503 		if (PrivateModes & PrivMode_MouseX10)
3504 		    PrivateModes &= ~(PrivMode_MouseX11);
3505 		break;
3506 # ifdef menuBar_esc
3507 	    case menuBar_esc:
3508 		PrivCases(PrivMode_menuBar);
3509 		map_menuBar(state);
3510 		break;
3511 # endif
3512 #ifdef scrollBar_esc
3513 	    case scrollBar_esc:
3514 		PrivCases(PrivMode_scrollBar);
3515 		map_scrollBar(state);
3516 		break;
3517 #endif
3518 	    case 25:		/* visible/invisible cursor */
3519 		PrivCases(PrivMode_VisibleCursor);
3520 		scr_cursor_visible(state);
3521 		break;
3522 
3523 	    case 35:
3524 		PrivCases(PrivMode_ShiftKeys);
3525 		break;
3526 
3527 	    case 40:		/* 80 <--> 132 mode */
3528 		PrivCases(PrivMode_132OK);
3529 		break;
3530 
3531 	    case 47:		/* secondary screen */
3532 		PrivCases(PrivMode_Screen);
3533 		scr_change_screen(state);
3534 		break;
3535 
3536 	    case 66:		/* application key pad */
3537 		PrivCases(PrivMode_aplKP);
3538 		break;
3539 
3540 	    case 67:
3541 #ifndef NO_BACKSPACE_KEY
3542 		if (PrivateModes & PrivMode_HaveBackSpace) {
3543 		    PrivCases(PrivMode_BackSpace);
3544 		}
3545 #endif
3546 		break;
3547 
3548 	    case 1000:		/* X11 mouse reporting */
3549 		PrivCases(PrivMode_MouseX11);
3550 	    /* orthogonal */
3551 		if (PrivateModes & PrivMode_MouseX11)
3552 		    PrivateModes &= ~(PrivMode_MouseX10);
3553 		break;
3554 #if 0
3555 	    case 1001:
3556 		break;		/* X11 mouse highlighting */
3557 #endif
3558 	    case 1010:		/* scroll to bottom on TTY output inhibit */
3559 		PrivCases(PrivMode_TtyOutputInh);
3560 		if (PrivateModes & PrivMode_TtyOutputInh)
3561 		    Options &= ~Opt_scrollTtyOutput;
3562 		else
3563 		    Options |= Opt_scrollTtyOutput;
3564 		break;
3565 	    case 1011:		/* scroll to bottom on key press */
3566 		PrivCases(PrivMode_Keypress);
3567 		if (PrivateModes & PrivMode_Keypress)
3568 		    Options |= Opt_scrollKeypress;
3569 		else
3570 		    Options &= ~Opt_scrollKeypress;
3571 		break;
3572 	    }
3573 #undef PrivCases
3574 	break;
3575     }
3576 }
3577 /*}}} */
3578 
3579 /*{{{ process sgr sequences */
3580 /* PROTO */
3581 void
3582 process_sgr_mode(unsigned int nargs, int arg[])
3583 {
3584     unsigned int    i;
3585 
3586     if (nargs == 0) {
3587 	scr_rendition(0, ~RS_None);
3588 	return;
3589     }
3590     for (i = 0; i < nargs; i++)
3591 	switch (arg[i]) {
3592 	case 0:
3593 	    scr_rendition(0, ~RS_None);
3594 	    break;
3595 	case 1:
3596 	    scr_rendition(1, RS_Bold);
3597 	    break;
3598 	case 4:
3599 	    scr_rendition(1, RS_Uline);
3600 	    break;
3601 	case 5:
3602 	    scr_rendition(1, RS_Blink);
3603 	    break;
3604 	case 7:
3605 	    scr_rendition(1, RS_RVid);
3606 	    break;
3607 	case 22:
3608 	    scr_rendition(0, RS_Bold);
3609 	    break;
3610 	case 24:
3611 	    scr_rendition(0, RS_Uline);
3612 	    break;
3613 	case 25:
3614 	    scr_rendition(0, RS_Blink);
3615 	    break;
3616 	case 27:
3617 	    scr_rendition(0, RS_RVid);
3618 	    break;
3619 
3620 	case 30:
3621 	case 31:		/* set fg color */
3622 	case 32:
3623 	case 33:
3624 	case 34:
3625 	case 35:
3626 	case 36:
3627 	case 37:
3628 	    scr_color(minCOLOR + (arg[i] - 30), RS_Bold);
3629 	    break;
3630 	case 39:		/* default fg */
3631 	    scr_color(restoreFG, RS_Bold);
3632 	    break;
3633 
3634 	case 40:
3635 	case 41:		/* set bg color */
3636 	case 42:
3637 	case 43:
3638 	case 44:
3639 	case 45:
3640 	case 46:
3641 	case 47:
3642 	    scr_color(minCOLOR + (arg[i] - 40), RS_Blink);
3643 	    break;
3644 	case 49:		/* default bg */
3645 	    scr_color(restoreBG, RS_Blink);
3646 	    break;
3647 	}
3648 }
3649 /*}}} */
3650 
3651 /*{{{ process Rob Nation's own graphics mode sequences */
3652 /* PROTO */
3653 void
3654 process_graphics(void)
3655 {
3656     unsigned char   ch, cmd = cmd_getc();
3657 
3658 #ifndef RXVT_GRAPHICS
3659     if (cmd == 'Q') {		/* query graphics */
3660 	tt_printf((unsigned char *) "\033G0\n");	/* no graphics */
3661 	return;
3662     }
3663 /* swallow other graphics sequences until terminating ':' */
3664     do
3665 	ch = cmd_getc();
3666     while (ch != ':');
3667 #else
3668     int             nargs;
3669     int             args[NGRX_PTS];
3670     unsigned char  *text = NULL;
3671 
3672     if (cmd == 'Q') {		/* query graphics */
3673 	tt_printf((unsigned char *) "\033G1\n");	/* yes, graphics (color) */
3674 	return;
3675     }
3676     for (nargs = 0; nargs < (sizeof(args) / sizeof(args[0])) - 1; ) {
3677 	int             neg;
3678 
3679 	ch = cmd_getc();
3680 	neg = (ch == '-');
3681 	if (neg || ch == '+')
3682 	    ch = cmd_getc();
3683 
3684 	for (args[nargs] = 0; isdigit(ch); ch = cmd_getc())
3685 	    args[nargs] = args[nargs] * 10 + (ch - '0');
3686 	if (neg)
3687 	    args[nargs] = -args[nargs];
3688 
3689 	nargs++;
3690 	args[nargs] = 0;
3691 	if (ch != ';')
3692 	    break;
3693     }
3694 
3695     if ((cmd == 'T') && (nargs >= 5)) {
3696 	int             i, len = args[4];
3697 
3698 	text = MALLOC((len + 1) * sizeof(char));
3699 
3700 	if (text != NULL) {
3701 	    for (i = 0; i < len; i++)
3702 		text[i] = cmd_getc();
3703 	    text[len] = '\0';
3704 	}
3705     }
3706     Gr_do_graphics(cmd, nargs, args, text);
3707 #ifdef USE_XIM
3708     IMSendSpot();
3709 #endif
3710 #endif
3711 }
3712 /*}}} */
3713 
3714 /*{{{ Read and process output from the application */
3715 /* PROTO */
3716 void
3717 main_loop(void)
3718 {
3719     int             ch;
3720     do {
3721 	while ((ch = cmd_getc()) == 0) ;	/* wait for something */
3722 	/* fprintf( stderr, "%d: cmd_getc returned 0x%x(%c)\n", ++i, ch, isprint(ch)?ch:' ' ); */
3723 	if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
3724 	/* Read a text string from the input buffer */
3725 	    int             nlines = 0;
3726 	    unsigned char  *str;
3727 
3728 	/*
3729 	 * point to the start of the string,
3730 	 * decrement first since it was post incremented in cmd_getc()
3731 	 */
3732 	    str = --cmdbuf_ptr;
3733 	    while (cmdbuf_ptr < cmdbuf_endp)
3734 		{
3735 			ch = *cmdbuf_ptr++;
3736 			/* fprintf( stderr, "%d: cmd_getc returned 0x%x(%c)\n", ++i, ch, isprint(ch)?ch:' ' ); */
3737 			if (ch >= ' ' || ch == '\t' )
3738 			{
3739 			/* nothing */
3740 			} else if (ch == '\r')
3741 			{                  /* we better flush that stuff to create an
3742 								* impression that there is something going on */
3743 				if( cmdbuf_ptr >= cmdbuf_endp ||
3744 					(*cmdbuf_ptr != '\n'  && *cmdbuf_ptr != '\r'))
3745 					break;
3746 			} else if (ch == '\n')
3747 			{
3748 		    	nlines++;
3749 		    	if (++refresh_count >= (refresh_limit * (TermWin.nrow - 1)))
3750 				break;
3751 			} else {	/* unprintable */
3752 		    	cmdbuf_ptr--;
3753 		    	break;
3754 			}
3755 	    }
3756 	    scr_add_lines(str, nlines, (cmdbuf_ptr - str));
3757 		if( ch == '\r' )
3758 		{
3759 			scr_refresh(refresh_type);
3760 		}
3761 	} else {
3762 	    switch (ch) {
3763 	    case 005:		/* terminal Status */
3764 		tt_printf((unsigned char *) VT100_ANS);
3765 		break;
3766 	    case 007:		/* bell */
3767 		scr_bell();
3768 		break;
3769 	    case '\b':		/* backspace */
3770 		scr_backspace();
3771 		break;
3772 	    case 013:		/* vertical tab, form feed */
3773 	    case 014:
3774 		scr_index(UP);
3775 		break;
3776 	    case 016:		/* shift out - acs */
3777 		scr_charset_choose(1);
3778 		break;
3779 	    case 017:		/* shift in - acs */
3780 		scr_charset_choose(0);
3781 		break;
3782 	    case 033:		/* escape char */
3783 		process_escape_seq();
3784 		break;
3785 	    }
3786 	}
3787     } while (ch != EOF);
3788 }
3789 
3790 /* ---------------------------------------------------------------------- */
3791 /* Addresses pasting large amounts of data and rxvt hang
3792  * code pinched from xterm (v_write()) and applied originally to
3793  * rxvt-2.18 - Hops
3794  * Write data to the pty as typed by the user, pasted with the mouse,
3795  * or generated by us in response to a query ESC sequence.
3796  */
3797 /* PROTO */
3798 void
3799 tt_write(const unsigned char *d, int len)
3800 {
3801     int             riten, p;
3802 
3803     if (v_bufstr == NULL && len > 0) {
3804 	v_buffer = v_bufstr = v_bufptr = MALLOC(len);
3805 	v_bufend = v_buffer + len;
3806     }
3807 /*
3808  * Append to the block we already have.  Always doing this simplifies the
3809  * code, and isn't too bad, either.  If this is a short block, it isn't
3810  * too expensive, and if this is a long block, we won't be able to write
3811  * it all anyway.
3812  */
3813     if (len > 0) {
3814 	if (v_bufend < v_bufptr + len) {	/* we've run out of room */
3815 	    if (v_bufstr != v_buffer) {
3816 	    /* there is unused space, move everything down */
3817 	    /* possibly overlapping bcopy here */
3818 	    /* bcopy(v_bufstr, v_buffer, v_bufptr - v_bufstr); */
3819 		memcpy(v_buffer, v_bufstr, v_bufptr - v_bufstr);
3820 		v_bufptr -= v_bufstr - v_buffer;
3821 		v_bufstr = v_buffer;
3822 	    }
3823 	    if (v_bufend < v_bufptr + len) {
3824 	    /* still won't fit: get more space */
3825 	    /* Don't use XtRealloc because an error is not fatal. */
3826 		int             size = v_bufptr - v_buffer;
3827 
3828 	    /* save across realloc */
3829 		v_buffer = REALLOC(v_buffer, size + len);
3830 		if (v_buffer) {
3831 		    v_bufstr = v_buffer;
3832 		    v_bufptr = v_buffer + size;
3833 		    v_bufend = v_bufptr + len;
3834 		} else {
3835 		/* no memory: ignore entire write request */
3836 		    print_error("cannot allocate buffer space");
3837 		    v_buffer = v_bufstr;	/* restore clobbered pointer */
3838 		}
3839 	    }
3840 	}
3841 	if (v_bufend >= v_bufptr + len) {	/* new stuff will fit */
3842 	    memcpy(v_bufptr, d, len);	/* bcopy(d, v_bufptr, len); */
3843 	    v_bufptr += len;
3844 	}
3845     }
3846 /*
3847  * Write out as much of the buffer as we can.
3848  * Be careful not to overflow the pty's input silo.
3849  * We are conservative here and only write a small amount at a time.
3850  *
3851  * If we can't push all the data into the pty yet, we expect write
3852  * to return a non-negative number less than the length requested
3853  * (if some data written) or -1 and set errno to EAGAIN,
3854  * EWOULDBLOCK, or EINTR (if no data written).
3855  *
3856  * (Not all systems do this, sigh, so the code is actually
3857  * a little more forgiving.)
3858  */
3859 
3860 #define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
3861 
3862     if ((p = v_bufptr - v_bufstr) > 0) {
3863 	riten = write(cmd_fd, v_bufstr, p < MAX_PTY_WRITE ? p : MAX_PTY_WRITE);
3864 	if (riten < 0)
3865 	    riten = 0;
3866 	v_bufstr += riten;
3867 	if (v_bufstr >= v_bufptr)	/* we wrote it all */
3868 	    v_bufstr = v_bufptr = v_buffer;
3869     }
3870 /*
3871  * If we have lots of unused memory allocated, return it
3872  */
3873     if (v_bufend - v_bufptr > 1024) {	/* arbitrary hysteresis */
3874     /* save pointers across realloc */
3875 	int             start = v_bufstr - v_buffer;
3876 	int             size = v_bufptr - v_buffer;
3877 	int             allocsize = size ? size : 1;
3878 
3879 	v_buffer = REALLOC(v_buffer, allocsize);
3880 	if (v_buffer) {
3881 	    v_bufstr = v_buffer + start;
3882 	    v_bufptr = v_buffer + size;
3883 	    v_bufend = v_buffer + allocsize;
3884 	} else {
3885 	/* should we print a warning if couldn't return memory? */
3886 	    v_buffer = v_bufstr - start;	/* restore clobbered pointer */
3887 	}
3888     }
3889 }
3890 
3891 #ifdef USE_XIM
3892 /* PROTO */
3893 void
3894 setSize( XRectangle *size )
3895 {
3896   size->x = TermWin_internalBorder;
3897   size->y = TermWin_internalBorder;
3898   size->width  = Width2Pixel (TermWin.ncol);
3899   size->height = Height2Pixel(TermWin.nrow);
3900   return;
3901 }
3902 
3903 /* PROTO */
3904 void
3905 setColor( unsigned long *fg, unsigned long *bg )
3906 {
3907   *fg = PixColors[Color_fg];
3908   *bg = PixColors[Color_bg];
3909   return;
3910 }
3911 /* PROTO */
3912 void
3913 IMSendSpot( void )
3914 {
3915   XPoint              spot;
3916   XVaNestedList       preedit_attr;
3917   XIMStyle            input_style;
3918 
3919   if( Input_Context == NULL )
3920     return;
3921   else {
3922     XGetICValues(Input_Context,XNInputStyle,&input_style,NULL);
3923     if (!(input_style & XIMPreeditPosition))
3924       return;
3925   }
3926   setPosition( &spot );
3927 
3928   preedit_attr = XVaCreateNestedList( 0, XNSpotLocation, &spot, NULL );
3929   XSetICValues( Input_Context, XNPreeditAttributes, preedit_attr, NULL );
3930   XFree( preedit_attr );
3931   return;
3932 }
3933 
3934 /* PROTO */
3935 void
3936 setTermFontSet( void )
3937 {
3938   char *string;
3939   long length, i;
3940 
3941   if( TermWin.fontset != NULL ){
3942     XFreeFontSet( Xdisplay, TermWin.fontset );
3943     TermWin.fontset = NULL;
3944   }
3945 
3946   length  = 0;
3947   for( i = 0 ; i < NFONTS ; i ++){
3948     if( rs_font[ i ] )
3949       length += strlen( rs_font[ i ] ) + 1;
3950 # ifdef MULTICHAR_SET
3951     if( rs_mfont[ i ] )
3952       length += strlen( rs_mfont[ i ] ) + 1;
3953 # endif
3954   }
3955   if( ( string = malloc( length ) ) != NULL ){
3956     char **missing_charsetlist, *def_string;
3957     int missing_charsetcount;
3958 
3959     string[ 0 ] = '\0';
3960     for( i = 0 ; i < NFONTS ; i ++){
3961       if( rs_font[ i ] ){
3962         strcat( string, rs_font[ i ] );
3963         strcat( string, "," );
3964       }
3965 # ifdef MULTICHAR_SET
3966       if( rs_mfont[ i ] ){
3967         strcat( string, rs_mfont[ i ] );
3968         strcat( string, "," );
3969       }
3970 # endif
3971     }
3972     length = strlen( string );
3973     if( length > 0 && string[ length - 1 ] == ',' ){
3974       string[ length - 1 ] = '\0';
3975       length --;
3976     }
3977     if( length > 0 ){
3978       TermWin.fontset = XCreateFontSet
3979       ( Xdisplay, string,
3980         &missing_charsetlist, &missing_charsetcount, &def_string );
3981     }
3982     free( string );
3983   } else {
3984     TermWin.fontset = NULL;
3985   }
3986   return;
3987 }
3988 
3989 /* PROTO */
3990 void
3991 setPreeditArea(XRectangle *preedit_rect, XRectangle *status_rect, XRectangle *needed_rect)
3992 {
3993     preedit_rect->x = needed_rect->width
3994                     + (scrollbar_visible() && !(Options & Opt_scrollBar_right)
3995                        ? (SB_WIDTH + sb_shadow * 2) : 0);
3996     preedit_rect->y = Height2Pixel(TermWin.nrow - 1)
3997                     + ((menuBar.state == 1) ? menuBar_TotalHeight() : 0);
3998 
3999     preedit_rect->width = Width2Pixel(TermWin.ncol + 1) - needed_rect->width
4000                         + (!(Options & Opt_scrollBar_right)
4001                            ? (SB_WIDTH + sb_shadow * 2) : 0);
4002     preedit_rect->height = Height2Pixel(1);
4003 
4004     status_rect->x = (scrollbar_visible() && !(Options & Opt_scrollBar_right))
4005                    ? (SB_WIDTH + sb_shadow * 2) : 0;
4006     status_rect->y = Height2Pixel(TermWin.nrow - 1)
4007                    + ((menuBar.state == 1) ? menuBar_TotalHeight() : 0);
4008 
4009     status_rect->width = needed_rect->width ? needed_rect->width
4010                                           : Width2Pixel(TermWin.ncol + 1);
4011     status_rect->height = Height2Pixel(1);
4012 }
4013 
4014 /* PROTO */
4015 void
4016 IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
4017 {
4018   Input_Context = NULL;
4019   XRegisterIMInstantiateCallback(Xdisplay, NULL, NULL, NULL, IMInstantiateCallback, NULL);
4020 }
4021 
4022 
4023 /* PROTO */
4024 void
4025 IMInstantiateCallback(Display *display, XPointer client_data, XPointer call_data)
4026 {
4027     char           *p, *s, buf[64], tmp[1024];
4028     char           *end, *next_s;
4029     XIM             xim = NULL;
4030     XIMStyle        input_style = 0;
4031     XIMStyles      *xim_styles = NULL;
4032     int             found;
4033     XPoint          spot;
4034     XRectangle      rect, status_rect, needed_rect;
4035     unsigned long   fg, bg;
4036     XVaNestedList   preedit_attr = NULL;
4037     XVaNestedList   status_attr = NULL;
4038     XIMCallback     ximcallback;
4039 
4040     Input_Context = NULL;
4041 
4042     if (Input_Context)
4043       return;
4044 
4045     ximcallback.callback = IMDestroyCallback;
4046     ximcallback.client_data = NULL;
4047 
4048     if (rs_inputMethod && *rs_inputMethod) {
4049       STRNCPY(tmp, rs_inputMethod, sizeof(tmp) - 1);
4050       for (s = tmp; *s; s = next_s + 1) {
4051           for (; *s && isspace(*s); s++);
4052           if (!*s)
4053               break;
4054           for (end = s; (*end && (*end != ',')); end++);
4055           for (next_s = end--; ((end >= s) && isspace(*end)); end--);
4056           *(end + 1) = '\0';
4057 
4058           if (*s) {
4059               STRCPY(buf, "@im=");
4060               strncat(buf, s, sizeof(buf) - 4 - 1);
4061               if ((p = XSetLocaleModifiers(buf)) != NULL
4062                   && (xim = XOpenIM(Xdisplay, NULL, NULL, NULL)) != NULL)
4063                   break;
4064           }
4065           if (!*next_s)
4066               break;
4067       }
4068     }
4069 
4070     /* try with XMODIFIERS env. var. */
4071     if (xim == NULL && (p = XSetLocaleModifiers("")) != NULL)
4072       xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
4073 
4074     /* try with no modifiers base */
4075     if (xim == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL)
4076       xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
4077 
4078     if (xim == NULL)
4079       return;
4080     XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
4081 
4082     if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL)
4083       || !xim_styles) {
4084       print_error("input method doesn't support any style");
4085       XCloseIM(xim);
4086       return;
4087     }
4088     STRNCPY(tmp, (rs_preeditType ? rs_preeditType
4089                                    : "OverTheSpot,OffTheSpot,Root"),
4090           sizeof(tmp) - 1);
4091     for (found = 0, s = tmp; *s && !found; s = next_s + 1) {
4092       unsigned short  i;
4093 
4094       for (; *s && isspace(*s); s++);
4095       if (!*s)
4096           break;
4097       for (end = s; (*end && (*end != ',')); end++);
4098       for (next_s = end--; ((end >= s) && isspace(*end)); end--);
4099       *(end + 1) = '\0';
4100 
4101       if (!strcmp(s, "OverTheSpot"))
4102           input_style = (XIMPreeditPosition | XIMStatusNothing);
4103       else if (!strcmp(s, "OffTheSpot"))
4104           input_style = (XIMPreeditArea | XIMStatusArea);
4105       else if (!strcmp(s, "Root"))
4106           input_style = (XIMPreeditNothing | XIMStatusNothing);
4107 
4108       for (i = 0; i < xim_styles->count_styles; i++)
4109           if (input_style == xim_styles->supported_styles[i]) {
4110               found = 1;
4111               break;
4112           }
4113     }
4114     XFree(xim_styles);
4115 
4116     if (found == 0) {
4117       print_error("input method doesn't support my preedit type");
4118       XCloseIM(xim);
4119       return;
4120     }
4121     if ((input_style != (XIMPreeditNothing | XIMStatusNothing))
4122       && (input_style != (XIMPreeditArea | XIMStatusArea))
4123       && (input_style != (XIMPreeditPosition | XIMStatusNothing))) {
4124       print_error("This program does not support the preedit type");
4125       XCloseIM(xim);
4126       return;
4127     }
4128     if (input_style & XIMPreeditPosition) {
4129       setSize(&rect);
4130       setPosition(&spot);
4131       setColor(&fg, &bg);
4132 
4133       preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
4134                                          XNSpotLocation, &spot,
4135                                          XNForeground, fg,
4136                                          XNBackground, bg,
4137                                          XNFontSet, TermWin.fontset,
4138                                          NULL);
4139     } else if (input_style & XIMPreeditArea) {
4140       setColor(&fg, &bg);
4141 
4142       /*
4143        * The necessary width of preedit area is unknown
4144        * until create input context.
4145        */
4146       needed_rect.width = 0;
4147 
4148       setPreeditArea(&rect, &status_rect, &needed_rect);
4149 
4150       preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
4151                                          XNForeground, fg,
4152                                          XNBackground, bg,
4153                                          XNFontSet, TermWin.fontset,
4154                                          NULL);
4155       status_attr = XVaCreateNestedList(0, XNArea, &status_rect,
4156                                         XNForeground, fg,
4157                                         XNBackground, bg,
4158                                         XNFontSet, TermWin.fontset,
4159                                         NULL);
4160     }
4161     Input_Context = XCreateIC(xim, XNInputStyle, input_style,
4162                             XNClientWindow, TermWin.parent,
4163                             XNFocusWindow, TermWin.parent,
4164                             XNDestroyCallback, &ximcallback,
4165                             preedit_attr ? XNPreeditAttributes : NULL,
4166                             preedit_attr,
4167                             status_attr ? XNStatusAttributes : NULL,
4168                             status_attr,
4169                             NULL);
4170     XFree(preedit_attr);
4171     XFree(status_attr);
4172     if (Input_Context == NULL) {
4173       print_error("Failed to create input context");
4174       XCloseIM(xim);
4175     }
4176     if (input_style & XIMPreeditArea)
4177       IMSetStatusPosition();
4178 }
4179 
4180 /* PROTO */
4181 void
4182 IMSetStatusPosition(void)
4183 {
4184   XIMStyle input_style;
4185   XRectangle rect, status_rect, *needed_rect;
4186   XVaNestedList preedit_attr, status_attr;
4187 
4188   if (Input_Context == NULL)
4189     return;
4190 
4191   XGetICValues(Input_Context, XNInputStyle, &input_style, NULL);
4192   if (input_style & XIMPreeditArea) {
4193     status_attr = XVaCreateNestedList(0, XNAreaNeeded, &needed_rect, NULL);
4194     XGetICValues(Input_Context, XNStatusAttributes, status_attr, NULL);
4195     XFree(status_attr);
4196     rect.x = needed_rect->width;
4197     if (menuBar.state == 1) {
4198       rect.y = Height2Pixel(TermWin.nrow - 1) - menuBar_TotalHeight();
4199     } else {
4200       rect.y = Height2Pixel(TermWin.nrow - 1);
4201     }
4202     if (Options & Opt_scrollBar_right) {
4203       rect.width = Width2Pixel(TermWin.ncol + 1) - needed_rect->width;
4204     } else {
4205       rect.width = Width2Pixel(TermWin.ncol + 1) + SB_WIDTH + SHADOW * 2 - needed_rect->width;
4206     }
4207     rect.height = needed_rect->height;
4208     preedit_attr = XVaCreateNestedList(0, XNArea, &rect, NULL);
4209 
4210     if (scrollbar_visible()) {
4211       if (Options & Opt_scrollBar_right) {
4212       status_rect.x = 0;
4213       } else {
4214       status_rect.x = SB_WIDTH + SHADOW * 2;
4215       }
4216     } else {
4217       status_rect.x = 0;
4218     }
4219     if (menuBar.state == 1) {
4220       status_rect.y = Height2Pixel(TermWin.nrow - 1) + menuBar_TotalHeight();
4221     } else {
4222       status_rect.y = Height2Pixel(TermWin.nrow - 1);
4223     }
4224     status_rect.width = needed_rect->width;
4225     status_rect.height = needed_rect->height;
4226     status_attr = XVaCreateNestedList(0, XNArea, &status_rect, NULL);
4227     XSetICValues(Input_Context,
4228                XNPreeditAttributes, preedit_attr,
4229                XNStatusAttributes, status_attr, NULL);
4230     XFree(preedit_attr);
4231     XFree(status_attr);
4232   }
4233 }
4234 
4235 /* PROTO */
4236 void
4237 XProcessEvent( Display *display )
4238 {
4239   XEvent xev;
4240   XNextEvent( display, &xev );
4241   if( !XFilterEvent( &xev, xev.xany.window ) )
4242     process_x_event( &xev );
4243   return;
4244 }
4245 
4246 #endif
4247 
4248 /*}}} */
4249 /*----------------------- end-of-file (C source) -----------------------*/
4250