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