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