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