7124 lines
172 KiB
C
7124 lines
172 KiB
C
|
/*--------------------------------*-C-*---------------------------------*
|
||
|
* File: command.c
|
||
|
*/
|
||
|
/* notes: */
|
||
|
/*----------------------------------------------------------------------*
|
||
|
* Copyright 1992 John Bovey, University of Kent at Canterbury.
|
||
|
*
|
||
|
* You can do what you like with this source code as long as
|
||
|
* you don't try to make money out of it and you include an
|
||
|
* unaltered copy of this message (including the copyright).
|
||
|
*
|
||
|
* This module has been very heavily modified by R. Nation
|
||
|
* <nation@rocket.sanders.lockheed.com>
|
||
|
* No additional restrictions are applied
|
||
|
*
|
||
|
* Additional modification by Garrett D'Amore <garrett@netcom.com> to
|
||
|
* allow vt100 printing. No additional restrictions are applied.
|
||
|
*
|
||
|
* Integrated modifications by Steven Hirsch <hirsch@emba.uvm.edu> to
|
||
|
* properly support X11 mouse report mode and support for DEC
|
||
|
* "private mode" save/restore functions.
|
||
|
*
|
||
|
* Integrated key-related changes by Jakub Jelinek <jj@gnu.ai.mit.edu>
|
||
|
* to handle Shift+function keys properly.
|
||
|
* Should be used with enclosed termcap / terminfo database.
|
||
|
*
|
||
|
* Extensive modifications by mj olesen <olesen@me.QueensU.CA>
|
||
|
* No additional restrictions.
|
||
|
*
|
||
|
* Further modification and cleanups for Solaris 2.x and Linux 1.2.x
|
||
|
* by Raul Garcia Garcia <rgg@tid.es>. No additional restrictions.
|
||
|
*
|
||
|
* As usual, the author accepts no responsibility for anything, nor does
|
||
|
* he guarantee anything whatsoever.
|
||
|
*----------------------------------------------------------------------*/
|
||
|
|
||
|
static const char cvs_ident[] = "$Id$";
|
||
|
|
||
|
/* includes: */
|
||
|
#include "feature.h"
|
||
|
#include "config.h"
|
||
|
|
||
|
/* System Headers */
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#ifdef HAVE_UNISTD_H
|
||
|
# include <unistd.h>
|
||
|
#endif
|
||
|
#include <ctype.h>
|
||
|
#include <errno.h>
|
||
|
#include <signal.h>
|
||
|
#if !defined(SIGSYS)
|
||
|
# if defined(SIGUNUSED)
|
||
|
# define SIGSYS SIGUNUSED
|
||
|
# else
|
||
|
# define SIGSYS ((int) 0)
|
||
|
# endif
|
||
|
#endif
|
||
|
#ifdef HAVE_UNISTD_H
|
||
|
# include <unistd.h>
|
||
|
#endif
|
||
|
#ifdef HAVE_FCNTL_H
|
||
|
# include <fcntl.h>
|
||
|
#endif
|
||
|
#ifdef HAVE_SYS_IOCTL_H
|
||
|
# include <sys/ioctl.h>
|
||
|
#endif
|
||
|
#include <sys/types.h>
|
||
|
#include <limits.h>
|
||
|
|
||
|
/* X11 Headers */
|
||
|
#include <X11/cursorfont.h>
|
||
|
#include <X11/keysym.h>
|
||
|
#include <X11/Xlib.h>
|
||
|
#include <X11/Xutil.h>
|
||
|
#include <X11/Xatom.h>
|
||
|
#include <X11/Xos.h>
|
||
|
#include <X11/Xproto.h>
|
||
|
#include <X11/IntrinsicP.h>
|
||
|
#ifdef OFFIX_DND
|
||
|
# define DndFile 2
|
||
|
# define DndDir 5
|
||
|
# define DndLink 7
|
||
|
#endif
|
||
|
#include <X11/keysym.h>
|
||
|
#ifndef NO_XLOCALE
|
||
|
# if (XtVersion < 11005)
|
||
|
# define NO_XLOCALE
|
||
|
# include <locale.h>
|
||
|
# else
|
||
|
# include <X11/Xlocale.h>
|
||
|
# endif
|
||
|
#endif /* NO_XLOCALE */
|
||
|
#ifdef USE_GETGRNAME
|
||
|
# include <grp.h>
|
||
|
#endif
|
||
|
#ifdef TIME_WITH_SYS_TIME
|
||
|
# include <sys/time.h>
|
||
|
# include <time.h>
|
||
|
#else
|
||
|
# ifdef HAVE_SYS_TIME_H
|
||
|
# include <sys/time.h>
|
||
|
# else
|
||
|
# include <time.h>
|
||
|
# endif
|
||
|
#endif
|
||
|
#if defined (__svr4__)
|
||
|
# include <sys/resource.h> /* for struct rlimit */
|
||
|
# include <sys/stropts.h> /* for I_PUSH */
|
||
|
# ifdef HAVE_SYS_STRTIO_H
|
||
|
# include <sys/strtio.h>
|
||
|
# endif
|
||
|
# ifdef HAVE_BSDTTY_H
|
||
|
# include <bsdtty.h>
|
||
|
# endif
|
||
|
# define _NEW_TTY_CTRL /* to get proper defines in <termios.h> */
|
||
|
#endif
|
||
|
#ifdef HAVE_SYS_SELECT_H
|
||
|
# include <sys/select.h>
|
||
|
#endif
|
||
|
#ifdef HAVE_TERMIOS_H
|
||
|
# include <termios.h>
|
||
|
#else
|
||
|
# include <sgtty.h>
|
||
|
#endif
|
||
|
#if defined(__sun) && defined(__SVR4)
|
||
|
# include <sys/strredir.h>
|
||
|
#endif
|
||
|
#include <sys/wait.h>
|
||
|
#include <sys/stat.h>
|
||
|
#if defined(linux)
|
||
|
# include <linux/tty.h> /* For N_TTY_BUF_SIZE. */
|
||
|
#endif
|
||
|
#if defined(linux)
|
||
|
# include <string.h> /* For strsep(). -vendu */
|
||
|
#endif
|
||
|
|
||
|
/* Eterm-specific Headers */
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
# include "activetags.h"
|
||
|
# include "activeeterm.h"
|
||
|
#endif
|
||
|
#include "command.h"
|
||
|
#include "main.h"
|
||
|
#include "../libmej/debug.h"
|
||
|
#include "debug.h"
|
||
|
#include "../libmej/mem.h"
|
||
|
#include "../libmej/strings.h"
|
||
|
#include "string.h"
|
||
|
#include "graphics.h"
|
||
|
#include "grkelot.h"
|
||
|
#include "scrollbar.h"
|
||
|
#include "menubar.h"
|
||
|
#include "screen.h"
|
||
|
#include "options.h"
|
||
|
#include "pixmap.h"
|
||
|
#ifdef USE_POSIX_THREADS
|
||
|
# include "threads.h"
|
||
|
#endif
|
||
|
#ifdef PROFILE
|
||
|
# include "profile.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
extern pixmap_t sbPixmap;
|
||
|
|
||
|
#endif
|
||
|
#ifdef PIXMAP_MENUBAR
|
||
|
extern pixmap_t mbPixmap;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* terminal mode defines: */
|
||
|
/* ways to deal with getting/setting termios structure */
|
||
|
#ifdef HAVE_TERMIOS_H
|
||
|
typedef struct termios ttymode_t;
|
||
|
|
||
|
# ifdef TCSANOW /* POSIX */
|
||
|
# define GET_TERMIOS(fd,tios) tcgetattr (fd, tios)
|
||
|
# define SET_TERMIOS(fd,tios) do {\
|
||
|
cfsetospeed (tios, BAUDRATE);\
|
||
|
cfsetispeed (tios, BAUDRATE);\
|
||
|
tcsetattr (fd, TCSANOW, tios);\
|
||
|
} while (0)
|
||
|
# else
|
||
|
# ifdef TIOCSETA
|
||
|
# define GET_TERMIOS(fd,tios) ioctl (fd, TIOCGETA, tios)
|
||
|
# define SET_TERMIOS(fd,tios) do {\
|
||
|
tios->c_cflag |= BAUDRATE;\
|
||
|
ioctl (fd, TIOCSETA, tios);\
|
||
|
} while (0)
|
||
|
# else
|
||
|
# define GET_TERMIOS(fd,tios) ioctl (fd, TCGETS, tios)
|
||
|
# define SET_TERMIOS(fd,tios) do {\
|
||
|
tios->c_cflag |= BAUDRATE;\
|
||
|
ioctl (fd, TCSETS, tios);\
|
||
|
} while (0)
|
||
|
# endif
|
||
|
# endif
|
||
|
# define SET_TTYMODE(fd,tios) SET_TERMIOS (fd, tios)
|
||
|
#else
|
||
|
/* sgtty interface */
|
||
|
typedef struct {
|
||
|
struct sgttyb sg;
|
||
|
struct tchars tc;
|
||
|
struct ltchars lc;
|
||
|
int line;
|
||
|
int local;
|
||
|
} ttymode_t;
|
||
|
|
||
|
# define SET_TTYMODE(fd,tt) \
|
||
|
do { \
|
||
|
tt->sg.sg_ispeed = tt->sg.sg_ospeed = BAUDRATE;\
|
||
|
ioctl (fd, TIOCSETP, &(tt->sg));\
|
||
|
ioctl (fd, TIOCSETC, &(tt->tc));\
|
||
|
ioctl (fd, TIOCSLTC, &(tt->lc));\
|
||
|
ioctl (fd, TIOCSETD, &(tt->line));\
|
||
|
ioctl (fd, TIOCLSET, &(tt->local));\
|
||
|
} while (0)
|
||
|
#endif /* HAVE_TERMIOS_H */
|
||
|
|
||
|
/* use the fastest baud-rate */
|
||
|
#ifdef B38400
|
||
|
# define BAUDRATE B38400
|
||
|
#else
|
||
|
# ifdef B19200
|
||
|
# define BAUDRATE B19200
|
||
|
# else
|
||
|
# define BAUDRATE B9600
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/* Disable special character functions */
|
||
|
#ifdef _POSIX_VDISABLE
|
||
|
# define VDISABLE _POSIX_VDISABLE
|
||
|
#else
|
||
|
# define VDISABLE 255
|
||
|
#endif
|
||
|
|
||
|
/*----------------------------------------------------------------------*
|
||
|
* system default characters if defined and reasonable
|
||
|
*/
|
||
|
#ifndef CINTR
|
||
|
# define CINTR '\003' /* ^C */
|
||
|
#endif
|
||
|
#ifndef CQUIT
|
||
|
# define CQUIT '\034' /* ^\ */
|
||
|
#endif
|
||
|
#ifndef CERASE
|
||
|
# ifdef linux
|
||
|
# define CERASE '\177' /* ^? */
|
||
|
# else
|
||
|
# define CERASE '\010' /* ^H */
|
||
|
# endif
|
||
|
#endif
|
||
|
#ifndef CKILL
|
||
|
# define CKILL '\025' /* ^U */
|
||
|
#endif
|
||
|
#ifndef CEOF
|
||
|
# define CEOF '\004' /* ^D */
|
||
|
#endif
|
||
|
#ifndef CSTART
|
||
|
# define CSTART '\021' /* ^Q */
|
||
|
#endif
|
||
|
#ifndef CSTOP
|
||
|
# define CSTOP '\023' /* ^S */
|
||
|
#endif
|
||
|
#ifndef CSUSP
|
||
|
# define CSUSP '\032' /* ^Z */
|
||
|
#endif
|
||
|
#ifndef CDSUSP
|
||
|
# define CDSUSP '\031' /* ^Y */
|
||
|
#endif
|
||
|
#ifndef CRPRNT
|
||
|
# define CRPRNT '\022' /* ^R */
|
||
|
#endif
|
||
|
#ifndef CFLUSH
|
||
|
# define CFLUSH '\017' /* ^O */
|
||
|
#endif
|
||
|
#ifndef CWERASE
|
||
|
# define CWERASE '\027' /* ^W */
|
||
|
#endif
|
||
|
#ifndef CLNEXT
|
||
|
# define CLNEXT '\026' /* ^V */
|
||
|
#endif
|
||
|
|
||
|
#ifndef VDISCRD
|
||
|
# ifdef VDISCARD
|
||
|
# define VDISCRD VDISCARD
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifndef VWERSE
|
||
|
# ifdef VWERASE
|
||
|
# define VWERSE VWERASE
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/* defines: */
|
||
|
|
||
|
#define KBUFSZ 8 /* size of keyboard mapping buffer */
|
||
|
#define STRING_MAX 512 /* max string size for process_xterm_seq() */
|
||
|
#define ESC_ARGS 32 /* max # of args for esc sequences */
|
||
|
|
||
|
/* a large REFRESH_PERIOD causes problems with `cat' */
|
||
|
|
||
|
#ifndef REFRESH_PERIOD
|
||
|
# define REFRESH_PERIOD 3
|
||
|
#endif
|
||
|
|
||
|
#ifndef MULTICLICK_TIME
|
||
|
# define MULTICLICK_TIME 500
|
||
|
#endif
|
||
|
#ifndef SCROLLBAR_INITIAL_DELAY
|
||
|
# define SCROLLBAR_INITIAL_DELAY 40
|
||
|
#endif
|
||
|
#ifndef SCROLLBAR_CONTINUOUS_DELAY
|
||
|
# define SCROLLBAR_CONTINUOUS_DELAY 2
|
||
|
#endif
|
||
|
|
||
|
/* time factor to slow down a `jumpy' mouse */
|
||
|
#define MOUSE_THRESHOLD 50
|
||
|
#define CONSOLE "/dev/console" /* console device */
|
||
|
|
||
|
/*
|
||
|
* key-strings: if only these keys were standardized <sigh>
|
||
|
*/
|
||
|
#ifdef LINUX_KEYS
|
||
|
# define KS_HOME "\033[1~" /* Home == Find */
|
||
|
# define KS_END "\033[4~" /* End == Select */
|
||
|
#else
|
||
|
# define KS_HOME "\033[7~" /* Home */
|
||
|
# define KS_END "\033[8~" /* End */
|
||
|
#endif
|
||
|
|
||
|
/* and this one too! */
|
||
|
#ifdef NO_DELETE_KEY
|
||
|
# undef KS_DELETE /* use X server definition */
|
||
|
#else
|
||
|
# ifndef KS_DELETE
|
||
|
# define KS_DELETE "\033[3~" /* Delete = Execute */
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* ESC-Z processing:
|
||
|
*
|
||
|
* By stealing a sequence to which other xterms respond, and sending the
|
||
|
* same number of characters, but having a distinguishable sequence,
|
||
|
* we can avoid having a timeout (when not under an Eterm) for every login
|
||
|
* shell to auto-set its DISPLAY.
|
||
|
*
|
||
|
* This particular sequence is even explicitly stated as obsolete since
|
||
|
* about 1985, so only very old software is likely to be confused, a
|
||
|
* confusion which can likely be remedied through termcap or TERM. Frankly,
|
||
|
* I doubt anyone will even notice. We provide a #ifdef just in case they
|
||
|
* don't care about auto-display setting. Just in case the ancient
|
||
|
* software in question is broken enough to be case insensitive to the 'c'
|
||
|
* character in the answerback string, we make the distinguishing
|
||
|
* characteristic be capitalization of that character. The length of the
|
||
|
* two strings should be the same so that identical read(2) calls may be
|
||
|
* used.
|
||
|
*/
|
||
|
#define VT100_ANS "\033[?1;2c" /* vt100 answerback */
|
||
|
#ifndef ESCZ_ANSWER
|
||
|
# define ESCZ_ANSWER VT100_ANS /* obsolete ANSI ESC[c */
|
||
|
#endif
|
||
|
|
||
|
/* Global attributes */
|
||
|
extern XWindowAttributes attr;
|
||
|
extern XSetWindowAttributes Attributes;
|
||
|
extern char *orig_argv0;
|
||
|
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
extern short bg_needs_update;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* extern functions referenced */
|
||
|
extern char *ptsname();
|
||
|
|
||
|
#ifdef DISPLAY_IS_IP
|
||
|
extern char *network_display(const char *display);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
extern void get_initial_options(int, char **);
|
||
|
extern void menubar_read(const char *filename);
|
||
|
|
||
|
#ifdef USE_POSIX_THREADS
|
||
|
extern static void **retval;
|
||
|
extern static int join_value;
|
||
|
extern static pthread_t main_loop_thr;
|
||
|
extern static pthread_attr_t main_loop_attr;
|
||
|
|
||
|
# ifdef MUTEX_SYNCH
|
||
|
extern pthread_mutex_t mutex;
|
||
|
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
extern void render_pixmap(Window win, imlib_t image, pixmap_t pmap,
|
||
|
int which, renderop_t renderop);
|
||
|
|
||
|
# ifdef BACKING_STORE
|
||
|
extern const char *rs_saveUnder;
|
||
|
|
||
|
# endif
|
||
|
|
||
|
extern char *rs_noCursor;
|
||
|
|
||
|
# ifdef USE_IMLIB
|
||
|
extern ImlibData *imlib_id;
|
||
|
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/* extern variables referenced */
|
||
|
extern int my_ruid, my_rgid, my_euid, my_egid;
|
||
|
|
||
|
#ifdef PIXMAP_OFFSET
|
||
|
extern unsigned int rs_shadePct;
|
||
|
extern unsigned long rs_tintMask;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef PIXMAP_OFFSET
|
||
|
extern Pixmap desktop_pixmap, viewport_pixmap;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* extern variables declared here */
|
||
|
extern TermWin_t TermWin;
|
||
|
extern Display *Xdisplay; /* display */
|
||
|
|
||
|
extern char *rs_color[NRS_COLORS];
|
||
|
extern Pixel PixColors[NRS_COLORS + NSHADOWCOLORS];
|
||
|
|
||
|
extern unsigned long Options;
|
||
|
|
||
|
extern const char *display_name;
|
||
|
extern char *rs_name; /* client instance (resource name) */
|
||
|
|
||
|
#ifndef NO_BOLDFONT
|
||
|
extern const char *rs_boldFont;
|
||
|
|
||
|
#endif
|
||
|
extern const char *rs_font[NFONTS];
|
||
|
|
||
|
#ifdef KANJI
|
||
|
extern const char *rs_kfont[NFONTS];
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef PRINTPIPE
|
||
|
extern char *rs_print_pipe;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
extern char *rs_cutchars;
|
||
|
|
||
|
/* local variables */
|
||
|
extern Cursor TermWin_cursor; /* cursor for vt window */
|
||
|
extern unsigned int colorfgbg;
|
||
|
extern menuBar_t menuBar;
|
||
|
unsigned char keypress_exit = 0;
|
||
|
|
||
|
extern XSizeHints szHint;
|
||
|
|
||
|
extern char *def_colorName[];
|
||
|
|
||
|
#ifdef KANJI
|
||
|
/* Kanji font names, roman fonts sized to match */
|
||
|
extern const char *def_kfontName[];
|
||
|
|
||
|
#endif /* KANJI */
|
||
|
extern const char *def_fontName[];
|
||
|
|
||
|
/* extern functions referenced */
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
/* the originally loaded pixmap and its scaling */
|
||
|
extern pixmap_t bgPixmap;
|
||
|
extern void set_bgPixmap(const char * /* file */ );
|
||
|
|
||
|
# ifdef USE_IMLIB
|
||
|
extern imlib_t imlib_bg;
|
||
|
|
||
|
# endif
|
||
|
# ifdef PIXMAP_SCROLLBAR
|
||
|
extern pixmap_t sbPixmap;
|
||
|
extern pixmap_t upPixmap, up_clkPixmap;
|
||
|
extern pixmap_t dnPixmap, dn_clkPixmap;
|
||
|
extern pixmap_t saPixmap, sa_clkPixmap;
|
||
|
|
||
|
# ifdef USE_IMLIB
|
||
|
extern imlib_t imlib_sb, imlib_sa, imlib_saclk;
|
||
|
|
||
|
# endif
|
||
|
# endif
|
||
|
# ifdef PIXMAP_MENUBAR
|
||
|
extern pixmap_t mbPixmap, mb_selPixmap;
|
||
|
|
||
|
# ifdef USE_IMLIB
|
||
|
extern imlib_t imlib_mb, imlib_ms;
|
||
|
|
||
|
# endif
|
||
|
# endif
|
||
|
|
||
|
extern int scale_pixmap(const char *geom, pixmap_t * pmap);
|
||
|
|
||
|
#endif /* PIXMAP_SUPPORT */
|
||
|
|
||
|
/* have we changed the font? Needed to avoid race conditions
|
||
|
* while window resizing */
|
||
|
extern int font_change_count;
|
||
|
|
||
|
static void resize(void);
|
||
|
|
||
|
/* extern functions referenced */
|
||
|
#ifdef UTMP_SUPPORT
|
||
|
extern void cleanutent(void);
|
||
|
extern void makeutent(const char *, const char *);
|
||
|
|
||
|
#else
|
||
|
# define cleanutent() ((void)(0))
|
||
|
# define makeutent(pty, hostname) ((void)(0))
|
||
|
#endif
|
||
|
|
||
|
/* extern variables referenced */
|
||
|
extern int my_ruid, my_rgid, my_euid, my_egid;
|
||
|
|
||
|
/* extern variables declared here */
|
||
|
|
||
|
/* local variables */
|
||
|
/* static unsigned char segv=0; */
|
||
|
char initial_dir[PATH_MAX + 1];
|
||
|
static char *ptydev = NULL, *ttydev = NULL; /* pty/tty name */
|
||
|
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
int cmd_fd = -1; /* file descriptor connected to the command */
|
||
|
pid_t cmd_pid = -1; /* process id if child */
|
||
|
|
||
|
#else
|
||
|
static int cmd_fd = -1; /* file descriptor connected to the command */
|
||
|
static pid_t cmd_pid = -1; /* process id if child */
|
||
|
|
||
|
#endif
|
||
|
static int Xfd = -1; /* file descriptor of X server connection */
|
||
|
static unsigned int num_fds = 0; /* number of file descriptors being used */
|
||
|
static struct stat ttyfd_stat; /* original status of the tty we will use */
|
||
|
|
||
|
#ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
|
||
|
static int scroll_arrow_delay;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef META8_OPTION
|
||
|
static unsigned char meta_char = 033; /* Alt-key prefix */
|
||
|
|
||
|
#endif
|
||
|
|
||
|
unsigned long PrivateModes = PrivMode_Default;
|
||
|
static unsigned long SavedModes = PrivMode_Default;
|
||
|
|
||
|
#ifndef USE_POSIX_THREADS
|
||
|
static int refresh_count = 0, refresh_limit = 1;
|
||
|
|
||
|
#else
|
||
|
int refresh_count = 0, refresh_limit = 1;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* Why? -vendu */
|
||
|
/* static int refresh_type = SLOW_REFRESH; */
|
||
|
static int refresh_type = FAST_REFRESH;
|
||
|
|
||
|
static Atom wmDeleteWindow;
|
||
|
|
||
|
/* OffiX Dnd (drag 'n' drop) support */
|
||
|
#ifdef OFFIX_DND
|
||
|
static Atom DndProtocol, DndSelection;
|
||
|
|
||
|
#endif /* OFFIX_DND */
|
||
|
|
||
|
#ifndef NO_XLOCALE
|
||
|
static char *rs_inputMethod = ""; /* XtNinputMethod */
|
||
|
static char *rs_preeditType = NULL; /* XtNpreeditType */
|
||
|
static XIC Input_Context; /* input context */
|
||
|
|
||
|
#endif /* NO_XLOCALE */
|
||
|
|
||
|
/* command input buffering */
|
||
|
|
||
|
#if defined(linux) && defined(N_TTY_BUF_SIZE)
|
||
|
# define CMD_BUF_SIZE N_TTY_BUF_SIZE
|
||
|
#else
|
||
|
# ifndef CMD_BUF_SIZE
|
||
|
# define CMD_BUF_SIZE 4096
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifndef USE_POSIX_THREADS
|
||
|
static unsigned char cmdbuf_base[CMD_BUF_SIZE], *cmdbuf_ptr, *cmdbuf_endp;
|
||
|
|
||
|
#else
|
||
|
unsigned char cmdbuf_base[CMD_BUF_SIZE], *cmdbuf_ptr, *cmdbuf_endp;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* local functions referenced */
|
||
|
void privileges(int mode);
|
||
|
|
||
|
RETSIGTYPE Child_signal(int);
|
||
|
RETSIGTYPE Exit_signal(int);
|
||
|
int get_pty(void);
|
||
|
int get_tty(void);
|
||
|
int run_command(char * /* argv */ []);
|
||
|
unsigned char cmd_getc(void);
|
||
|
|
||
|
#if 0
|
||
|
void lookup_key(XEvent * /* ev */ );
|
||
|
|
||
|
#endif
|
||
|
inline void lookup_key(XEvent * /* ev */ );
|
||
|
void process_x_event(XEvent * /* ev */ );
|
||
|
|
||
|
/*static void process_string (int); */
|
||
|
#ifdef PRINTPIPE
|
||
|
void process_print_pipe(void);
|
||
|
|
||
|
#endif
|
||
|
void process_escape_seq(void);
|
||
|
void process_csi_seq(void);
|
||
|
void process_xterm_seq(void);
|
||
|
void process_window_mode(unsigned int, int[]);
|
||
|
void process_terminal_mode(int, int, unsigned int, int[]);
|
||
|
void process_sgr_mode(unsigned int, int[]);
|
||
|
void process_graphics(void);
|
||
|
|
||
|
void tt_winsize(int);
|
||
|
|
||
|
#ifndef NO_XLOCALE
|
||
|
void init_xlocale(void);
|
||
|
|
||
|
#else
|
||
|
# define init_xlocale() ((void)0)
|
||
|
#endif
|
||
|
|
||
|
/*for Big Paste Handling */
|
||
|
static int v_doPending(void);
|
||
|
static void v_writeBig(int, char *, int);
|
||
|
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
|
||
|
/* Substitutes for missing system functions */
|
||
|
#ifndef _POSIX_VERSION
|
||
|
# if defined (__svr4__)
|
||
|
int
|
||
|
getdtablesize(void)
|
||
|
{
|
||
|
struct rlimit rlim;
|
||
|
|
||
|
getrlimit(RLIMIT_NOFILE, &rlim);
|
||
|
return rlim.rlim_cur;
|
||
|
}
|
||
|
# endif
|
||
|
# endif
|
||
|
|
||
|
/* Take care of suid/sgid super-user (root) privileges */
|
||
|
void
|
||
|
privileges(int mode)
|
||
|
{
|
||
|
|
||
|
#ifdef __CYGWIN32__
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
switch (mode) {
|
||
|
case IGNORE:
|
||
|
/* Revoke suid/sgid privs and return to normal uid/gid -- mej */
|
||
|
D_UTMP(("[%ld]: Before privileges(REVERT): [ %ld, %ld ] [ %ld, %ld ]\n",
|
||
|
getpid(), getuid(), getgid(), geteuid(), getegid()));
|
||
|
|
||
|
#ifdef HAVE_SETRESGID
|
||
|
setresgid(my_rgid, my_rgid, my_egid);
|
||
|
#elif defined(HAVE_SAVED_UIDS)
|
||
|
setregid(my_rgid, my_rgid);
|
||
|
#else
|
||
|
setregid(my_egid, -1);
|
||
|
setregid(-1, my_rgid);
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_SETRESUID
|
||
|
setresuid(my_ruid, my_ruid, my_euid);
|
||
|
#elif defined(HAVE_SAVED_UIDS)
|
||
|
setreuid(my_ruid, my_ruid);
|
||
|
#else
|
||
|
setreuid(my_euid, -1);
|
||
|
setreuid(-1, my_ruid);
|
||
|
#endif
|
||
|
|
||
|
D_UTMP(("[%ld]: After privileges(REVERT): [ %ld, %ld ] [ %ld, %ld ]\n",
|
||
|
getpid(), getuid(), getgid(), geteuid(), getegid()));
|
||
|
break;
|
||
|
|
||
|
case SAVE:
|
||
|
break;
|
||
|
|
||
|
case RESTORE:
|
||
|
D_UTMP(("[%ld]: Before privileges(INVOKE): [ %ld, %ld ] [ %ld, %ld ]\n",
|
||
|
getpid(), getuid(), getgid(), geteuid(), getegid()));
|
||
|
|
||
|
#ifdef HAVE_SETRESUID
|
||
|
setresuid(my_ruid, my_euid, my_euid);
|
||
|
#elif defined(HAVE_SAVED_UIDS)
|
||
|
setreuid(my_ruid, my_euid);
|
||
|
#else
|
||
|
setreuid(-1, my_euid);
|
||
|
setreuid(my_ruid, -1);
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_SETRESGID
|
||
|
setresgid(my_rgid, my_egid, my_egid);
|
||
|
#elif defined(HAVE_SAVED_UIDS)
|
||
|
setregid(my_rgid, my_egid);
|
||
|
#else
|
||
|
setregid(-1, my_egid);
|
||
|
setregid(my_rgid, -1);
|
||
|
#endif
|
||
|
|
||
|
D_UTMP(("[%ld]: After privileges(INVOKE): [ %ld, %ld ] [ %ld, %ld ]\n",
|
||
|
getpid(), getuid(), getgid(), geteuid(), getegid()));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
sig_to_str(int sig)
|
||
|
{
|
||
|
|
||
|
/* NOTE: This can't be done with a switch because of possible conflicting
|
||
|
* conflicting signal types. -vendu
|
||
|
*/
|
||
|
|
||
|
#ifdef SIGHUP
|
||
|
if (sig == SIGHUP) {
|
||
|
return ("SIGHUP");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGINT
|
||
|
if (sig == SIGINT) {
|
||
|
return ("SIGINT");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGQUIT
|
||
|
if (sig == SIGQUIT) {
|
||
|
return ("SIGQUIT");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGILL
|
||
|
if (sig == SIGILL) {
|
||
|
return ("SIGILL");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGTRAP
|
||
|
if (sig == SIGTRAP) {
|
||
|
return ("SIGTRAP");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGABRT
|
||
|
if (sig == SIGABRT) {
|
||
|
return ("SIGABRT");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGIOT
|
||
|
if (sig == SIGIOT) {
|
||
|
return ("SIGIOT");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGEMT
|
||
|
if (sig == SIGEMT) {
|
||
|
return ("SIGEMT");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGFPE
|
||
|
if (sig == SIGFPE) {
|
||
|
return ("SIGFPE");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGKILL
|
||
|
if (sig == SIGKILL) {
|
||
|
return ("SIGKILL");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGBUS
|
||
|
if (sig == SIGBUS) {
|
||
|
return ("SIGBUS");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGSEGV
|
||
|
if (sig == SIGSEGV) {
|
||
|
return ("SIGSEGV");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGSYS
|
||
|
if (sig == SIGSYS) {
|
||
|
return ("SIGSYS");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGPIPE
|
||
|
if (sig == SIGPIPE) {
|
||
|
return ("SIGPIPE");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGALRM
|
||
|
if (sig == SIGALRM) {
|
||
|
return ("SIGALRM");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGTERM
|
||
|
if (sig == SIGTERM) {
|
||
|
return ("SIGTERM");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGUSR1
|
||
|
if (sig == SIGUSR1) {
|
||
|
return ("SIGUSR1");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGUSR2
|
||
|
if (sig == SIGUSR2) {
|
||
|
return ("SIGUSR2");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGCHLD
|
||
|
if (sig == SIGCHLD) {
|
||
|
return ("SIGCHLD");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGCLD
|
||
|
if (sig == SIGCLD) {
|
||
|
return ("SIGCLD");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGPWR
|
||
|
if (sig == SIGPWR) {
|
||
|
return ("SIGPWR");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGVTALRM
|
||
|
if (sig == SIGVTALRM) {
|
||
|
return ("SIGVTALRM");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGPROF
|
||
|
if (sig == SIGPROF) {
|
||
|
return ("SIGPROF");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGIO
|
||
|
if (sig == SIGIO) {
|
||
|
return ("SIGIO");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGPOLL
|
||
|
if (sig == SIGPOLL) {
|
||
|
return ("SIGPOLL");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGWINCH
|
||
|
if (sig == SIGWINCH) {
|
||
|
return ("SIGWINCH");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGWINDOW
|
||
|
if (sig == SIGWINDOW) {
|
||
|
return ("SIGWINDOW");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGSTOP
|
||
|
if (sig == SIGSTOP) {
|
||
|
return ("SIGSTOP");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGTSTP
|
||
|
if (sig == SIGTSTP) {
|
||
|
return ("SIGTSTP");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGCONT
|
||
|
if (sig == SIGCONT) {
|
||
|
return ("SIGCONT");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGTTIN
|
||
|
if (sig == SIGTTIN) {
|
||
|
return ("SIGTTIN");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGTTOU
|
||
|
if (sig == SIGTTOU) {
|
||
|
return ("SIGTTOU");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGURG
|
||
|
if (sig == SIGURG) {
|
||
|
return ("SIGURG");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGLOST
|
||
|
if (sig == SIGLOST) {
|
||
|
return ("SIGLOST");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGRESERVE
|
||
|
if (sig == SIGRESERVE) {
|
||
|
return ("SIGRESERVE");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGDIL
|
||
|
if (sig == SIGDIL) {
|
||
|
return ("SIGDIL");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGXCPU
|
||
|
if (sig == SIGXCPU) {
|
||
|
return ("SIGXCPU");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef SIGXFSZ
|
||
|
if (sig == SIGXFSZ) {
|
||
|
return ("SIGXFSZ");
|
||
|
}
|
||
|
#endif
|
||
|
return ("Unknown signal");
|
||
|
}
|
||
|
|
||
|
const char *
|
||
|
event_type_to_name(int type)
|
||
|
{
|
||
|
|
||
|
if (type == KeyPress) {
|
||
|
return "KeyPress";
|
||
|
}
|
||
|
if (type == KeyRelease) {
|
||
|
return "KeyRelease";
|
||
|
}
|
||
|
if (type == ButtonPress) {
|
||
|
return "ButtonPress";
|
||
|
}
|
||
|
if (type == ButtonRelease) {
|
||
|
return "ButtonRelease";
|
||
|
}
|
||
|
if (type == MotionNotify) {
|
||
|
return "MotionNotify";
|
||
|
}
|
||
|
if (type == EnterNotify) {
|
||
|
return "EnterNotify";
|
||
|
}
|
||
|
if (type == LeaveNotify) {
|
||
|
return "LeaveNotify";
|
||
|
}
|
||
|
if (type == FocusIn) {
|
||
|
return "FocusIn";
|
||
|
}
|
||
|
if (type == FocusOut) {
|
||
|
return "FocusOut";
|
||
|
}
|
||
|
if (type == KeymapNotify) {
|
||
|
return "KeymapNotify";
|
||
|
}
|
||
|
if (type == Expose) {
|
||
|
return "Expose";
|
||
|
}
|
||
|
if (type == GraphicsExpose) {
|
||
|
return "GraphicsExpose";
|
||
|
}
|
||
|
if (type == NoExpose) {
|
||
|
return "NoExpose";
|
||
|
}
|
||
|
if (type == VisibilityNotify) {
|
||
|
return "VisibilityNotify";
|
||
|
}
|
||
|
if (type == CreateNotify) {
|
||
|
return "CreateNotify";
|
||
|
}
|
||
|
if (type == DestroyNotify) {
|
||
|
return "DestroyNotify";
|
||
|
}
|
||
|
if (type == UnmapNotify) {
|
||
|
return "UnmapNotify";
|
||
|
}
|
||
|
if (type == MapNotify) {
|
||
|
return "MapNotify";
|
||
|
}
|
||
|
if (type == MapRequest) {
|
||
|
return "MapRequest";
|
||
|
}
|
||
|
if (type == ReparentNotify) {
|
||
|
return "ReparentNotify";
|
||
|
}
|
||
|
if (type == ConfigureNotify) {
|
||
|
return "ConfigureNotify";
|
||
|
}
|
||
|
if (type == ConfigureRequest) {
|
||
|
return "ConfigureRequest";
|
||
|
}
|
||
|
if (type == GravityNotify) {
|
||
|
return "GravityNotify";
|
||
|
}
|
||
|
if (type == ResizeRequest) {
|
||
|
return "ResizeRequest";
|
||
|
}
|
||
|
if (type == CirculateNotify) {
|
||
|
return "CirculateNotify";
|
||
|
}
|
||
|
if (type == CirculateRequest) {
|
||
|
return "CirculateRequest";
|
||
|
}
|
||
|
if (type == PropertyNotify) {
|
||
|
return "PropertyNotify";
|
||
|
}
|
||
|
if (type == SelectionClear) {
|
||
|
return "SelectionClear";
|
||
|
}
|
||
|
if (type == SelectionRequest) {
|
||
|
return "SelectionRequest";
|
||
|
}
|
||
|
if (type == SelectionNotify) {
|
||
|
return "SelectionNotify";
|
||
|
}
|
||
|
if (type == ColormapNotify) {
|
||
|
return "ColormapNotify";
|
||
|
}
|
||
|
if (type == ClientMessage) {
|
||
|
return "ClientMessage";
|
||
|
}
|
||
|
if (type == MappingNotify) {
|
||
|
return "MappingNotify";
|
||
|
}
|
||
|
return "Bad Event!";
|
||
|
}
|
||
|
|
||
|
const char *
|
||
|
request_code_to_name(int code)
|
||
|
{
|
||
|
|
||
|
if (code == X_CreateWindow) {
|
||
|
return "XCreateWindow";
|
||
|
}
|
||
|
if (code == X_ChangeWindowAttributes) {
|
||
|
return "XChangeWindowAttributes";
|
||
|
}
|
||
|
if (code == X_GetWindowAttributes) {
|
||
|
return "XGetWindowAttributes";
|
||
|
}
|
||
|
if (code == X_DestroyWindow) {
|
||
|
return "XDestroyWindow";
|
||
|
}
|
||
|
if (code == X_DestroySubwindows) {
|
||
|
return "XDestroySubwindows";
|
||
|
}
|
||
|
if (code == X_ChangeSaveSet) {
|
||
|
return "XChangeSaveSet";
|
||
|
}
|
||
|
if (code == X_ReparentWindow) {
|
||
|
return "XReparentWindow";
|
||
|
}
|
||
|
if (code == X_MapWindow) {
|
||
|
return "XMapWindow";
|
||
|
}
|
||
|
if (code == X_MapSubwindows) {
|
||
|
return "XMapSubwindows";
|
||
|
}
|
||
|
if (code == X_UnmapWindow) {
|
||
|
return "XUnmapWindow";
|
||
|
}
|
||
|
if (code == X_UnmapSubwindows) {
|
||
|
return "XUnmapSubwindows";
|
||
|
}
|
||
|
if (code == X_ConfigureWindow) {
|
||
|
return "XConfigureWindow";
|
||
|
}
|
||
|
if (code == X_CirculateWindow) {
|
||
|
return "XCirculateWindow";
|
||
|
}
|
||
|
if (code == X_GetGeometry) {
|
||
|
return "XGetGeometry";
|
||
|
}
|
||
|
if (code == X_QueryTree) {
|
||
|
return "XQueryTree";
|
||
|
}
|
||
|
if (code == X_InternAtom) {
|
||
|
return "XInternAtom";
|
||
|
}
|
||
|
if (code == X_GetAtomName) {
|
||
|
return "XGetAtomName";
|
||
|
}
|
||
|
if (code == X_ChangeProperty) {
|
||
|
return "XChangeProperty";
|
||
|
}
|
||
|
if (code == X_DeleteProperty) {
|
||
|
return "XDeleteProperty";
|
||
|
}
|
||
|
if (code == X_GetProperty) {
|
||
|
return "XGetProperty";
|
||
|
}
|
||
|
if (code == X_ListProperties) {
|
||
|
return "XListProperties";
|
||
|
}
|
||
|
if (code == X_SetSelectionOwner) {
|
||
|
return "XSetSelectionOwner";
|
||
|
}
|
||
|
if (code == X_GetSelectionOwner) {
|
||
|
return "XGetSelectionOwner";
|
||
|
}
|
||
|
if (code == X_ConvertSelection) {
|
||
|
return "XConvertSelection";
|
||
|
}
|
||
|
if (code == X_SendEvent) {
|
||
|
return "XSendEvent";
|
||
|
}
|
||
|
if (code == X_GrabPointer) {
|
||
|
return "XGrabPointer";
|
||
|
}
|
||
|
if (code == X_UngrabPointer) {
|
||
|
return "XUngrabPointer";
|
||
|
}
|
||
|
if (code == X_GrabButton) {
|
||
|
return "XGrabButton";
|
||
|
}
|
||
|
if (code == X_UngrabButton) {
|
||
|
return "XUngrabButton";
|
||
|
}
|
||
|
if (code == X_ChangeActivePointerGrab) {
|
||
|
return "XChangeActivePointerGrab";
|
||
|
}
|
||
|
if (code == X_GrabKeyboard) {
|
||
|
return "XGrabKeyboard";
|
||
|
}
|
||
|
if (code == X_UngrabKeyboard) {
|
||
|
return "XUngrabKeyboard";
|
||
|
}
|
||
|
if (code == X_GrabKey) {
|
||
|
return "XGrabKey";
|
||
|
}
|
||
|
if (code == X_UngrabKey) {
|
||
|
return "XUngrabKey";
|
||
|
}
|
||
|
if (code == X_AllowEvents) {
|
||
|
return "XAllowEvents";
|
||
|
}
|
||
|
if (code == X_GrabServer) {
|
||
|
return "XGrabServer";
|
||
|
}
|
||
|
if (code == X_UngrabServer) {
|
||
|
return "XUngrabServer";
|
||
|
}
|
||
|
if (code == X_QueryPointer) {
|
||
|
return "XQueryPointer";
|
||
|
}
|
||
|
if (code == X_GetMotionEvents) {
|
||
|
return "XGetMotionEvents";
|
||
|
}
|
||
|
if (code == X_TranslateCoords) {
|
||
|
return "XTranslateCoords";
|
||
|
}
|
||
|
if (code == X_WarpPointer) {
|
||
|
return "XWarpPointer";
|
||
|
}
|
||
|
if (code == X_SetInputFocus) {
|
||
|
return "XSetInputFocus";
|
||
|
}
|
||
|
if (code == X_GetInputFocus) {
|
||
|
return "XGetInputFocus";
|
||
|
}
|
||
|
if (code == X_QueryKeymap) {
|
||
|
return "XQueryKeymap";
|
||
|
}
|
||
|
if (code == X_OpenFont) {
|
||
|
return "XOpenFont";
|
||
|
}
|
||
|
if (code == X_CloseFont) {
|
||
|
return "XCloseFont";
|
||
|
}
|
||
|
if (code == X_QueryFont) {
|
||
|
return "XQueryFont";
|
||
|
}
|
||
|
if (code == X_QueryTextExtents) {
|
||
|
return "XQueryTextExtents";
|
||
|
}
|
||
|
if (code == X_ListFonts) {
|
||
|
return "XListFonts";
|
||
|
}
|
||
|
if (code == X_ListFontsWithInfo) {
|
||
|
return "XListFontsWithInfo";
|
||
|
}
|
||
|
if (code == X_SetFontPath) {
|
||
|
return "XSetFontPath";
|
||
|
}
|
||
|
if (code == X_GetFontPath) {
|
||
|
return "XGetFontPath";
|
||
|
}
|
||
|
if (code == X_CreatePixmap) {
|
||
|
return "XCreatePixmap";
|
||
|
}
|
||
|
if (code == X_FreePixmap) {
|
||
|
return "XFreePixmap";
|
||
|
}
|
||
|
if (code == X_CreateGC) {
|
||
|
return "XCreateGC";
|
||
|
}
|
||
|
if (code == X_ChangeGC) {
|
||
|
return "XChangeGC";
|
||
|
}
|
||
|
if (code == X_CopyGC) {
|
||
|
return "XCopyGC";
|
||
|
}
|
||
|
if (code == X_SetDashes) {
|
||
|
return "XSetDashes";
|
||
|
}
|
||
|
if (code == X_SetClipRectangles) {
|
||
|
return "XSetClipRectangles";
|
||
|
}
|
||
|
if (code == X_FreeGC) {
|
||
|
return "XFreeGC";
|
||
|
}
|
||
|
if (code == X_ClearArea) {
|
||
|
return "XClearArea";
|
||
|
}
|
||
|
if (code == X_CopyArea) {
|
||
|
return "XCopyArea";
|
||
|
}
|
||
|
if (code == X_CopyPlane) {
|
||
|
return "XCopyPlane";
|
||
|
}
|
||
|
if (code == X_PolyPoint) {
|
||
|
return "XPolyPoint";
|
||
|
}
|
||
|
if (code == X_PolyLine) {
|
||
|
return "XPolyLine";
|
||
|
}
|
||
|
if (code == X_PolySegment) {
|
||
|
return "XPolySegment";
|
||
|
}
|
||
|
if (code == X_PolyRectangle) {
|
||
|
return "XPolyRectangle";
|
||
|
}
|
||
|
if (code == X_PolyArc) {
|
||
|
return "XPolyArc";
|
||
|
}
|
||
|
if (code == X_FillPoly) {
|
||
|
return "XFillPoly";
|
||
|
}
|
||
|
if (code == X_PolyFillRectangle) {
|
||
|
return "XPolyFillRectangle";
|
||
|
}
|
||
|
if (code == X_PolyFillArc) {
|
||
|
return "XPolyFillArc";
|
||
|
}
|
||
|
if (code == X_PutImage) {
|
||
|
return "XPutImage";
|
||
|
}
|
||
|
if (code == X_GetImage) {
|
||
|
return "XGetImage";
|
||
|
}
|
||
|
if (code == X_PolyText8) {
|
||
|
return "XPolyText8";
|
||
|
}
|
||
|
if (code == X_PolyText16) {
|
||
|
return "XPolyText16";
|
||
|
}
|
||
|
if (code == X_ImageText8) {
|
||
|
return "XImageText8";
|
||
|
}
|
||
|
if (code == X_ImageText16) {
|
||
|
return "XImageText16";
|
||
|
}
|
||
|
if (code == X_CreateColormap) {
|
||
|
return "XCreateColormap";
|
||
|
}
|
||
|
if (code == X_FreeColormap) {
|
||
|
return "XFreeColormap";
|
||
|
}
|
||
|
if (code == X_CopyColormapAndFree) {
|
||
|
return "XCopyColormapAndFree";
|
||
|
}
|
||
|
if (code == X_InstallColormap) {
|
||
|
return "XInstallColormap";
|
||
|
}
|
||
|
if (code == X_UninstallColormap) {
|
||
|
return "XUninstallColormap";
|
||
|
}
|
||
|
if (code == X_ListInstalledColormaps) {
|
||
|
return "XListInstalledColormaps";
|
||
|
}
|
||
|
if (code == X_AllocColor) {
|
||
|
return "XAllocColor";
|
||
|
}
|
||
|
if (code == X_AllocNamedColor) {
|
||
|
return "XAllocNamedColor";
|
||
|
}
|
||
|
if (code == X_AllocColorCells) {
|
||
|
return "XAllocColorCells";
|
||
|
}
|
||
|
if (code == X_AllocColorPlanes) {
|
||
|
return "XAllocColorPlanes";
|
||
|
}
|
||
|
if (code == X_FreeColors) {
|
||
|
return "XFreeColors";
|
||
|
}
|
||
|
if (code == X_StoreColors) {
|
||
|
return "XStoreColors";
|
||
|
}
|
||
|
if (code == X_StoreNamedColor) {
|
||
|
return "XStoreNamedColor";
|
||
|
}
|
||
|
if (code == X_QueryColors) {
|
||
|
return "XQueryColors";
|
||
|
}
|
||
|
if (code == X_LookupColor) {
|
||
|
return "XLookupColor";
|
||
|
}
|
||
|
if (code == X_CreateCursor) {
|
||
|
return "XCreateCursor";
|
||
|
}
|
||
|
if (code == X_CreateGlyphCursor) {
|
||
|
return "XCreateGlyphCursor";
|
||
|
}
|
||
|
if (code == X_FreeCursor) {
|
||
|
return "XFreeCursor";
|
||
|
}
|
||
|
if (code == X_RecolorCursor) {
|
||
|
return "XRecolorCursor";
|
||
|
}
|
||
|
if (code == X_QueryBestSize) {
|
||
|
return "XQueryBestSize";
|
||
|
}
|
||
|
if (code == X_QueryExtension) {
|
||
|
return "XQueryExtension";
|
||
|
}
|
||
|
if (code == X_ListExtensions) {
|
||
|
return "XListExtensions";
|
||
|
}
|
||
|
if (code == X_ChangeKeyboardMapping) {
|
||
|
return "XChangeKeyboardMapping";
|
||
|
}
|
||
|
if (code == X_GetKeyboardMapping) {
|
||
|
return "XGetKeyboardMapping";
|
||
|
}
|
||
|
if (code == X_ChangeKeyboardControl) {
|
||
|
return "XChangeKeyboardControl";
|
||
|
}
|
||
|
if (code == X_GetKeyboardControl) {
|
||
|
return "XGetKeyboardControl";
|
||
|
}
|
||
|
if (code == X_Bell) {
|
||
|
return "XBell";
|
||
|
}
|
||
|
if (code == X_ChangePointerControl) {
|
||
|
return "XChangePointerControl";
|
||
|
}
|
||
|
if (code == X_GetPointerControl) {
|
||
|
return "XGetPointerControl";
|
||
|
}
|
||
|
if (code == X_SetScreenSaver) {
|
||
|
return "XSetScreenSaver";
|
||
|
}
|
||
|
if (code == X_GetScreenSaver) {
|
||
|
return "XGetScreenSaver";
|
||
|
}
|
||
|
if (code == X_ChangeHosts) {
|
||
|
return "XChangeHosts";
|
||
|
}
|
||
|
if (code == X_ListHosts) {
|
||
|
return "XListHosts";
|
||
|
}
|
||
|
if (code == X_SetAccessControl) {
|
||
|
return "XSetAccessControl";
|
||
|
}
|
||
|
if (code == X_SetCloseDownMode) {
|
||
|
return "XSetCloseDownMode";
|
||
|
}
|
||
|
if (code == X_KillClient) {
|
||
|
return "XKillClient";
|
||
|
}
|
||
|
if (code == X_RotateProperties) {
|
||
|
return "XRotateProperties";
|
||
|
}
|
||
|
if (code == X_ForceScreenSaver) {
|
||
|
return "XForceScreenSaver";
|
||
|
}
|
||
|
if (code == X_SetPointerMapping) {
|
||
|
return "XSetPointerMapping";
|
||
|
}
|
||
|
if (code == X_GetPointerMapping) {
|
||
|
return "XGetPointerMapping";
|
||
|
}
|
||
|
if (code == X_SetModifierMapping) {
|
||
|
return "XSetModifierMapping";
|
||
|
}
|
||
|
if (code == X_GetModifierMapping) {
|
||
|
return "XGetModifierMapping";
|
||
|
}
|
||
|
if (code == X_NoOperation) {
|
||
|
return "XNoOperation";
|
||
|
}
|
||
|
return "Unknown";
|
||
|
}
|
||
|
|
||
|
/* Try to get a stack trace when we croak */
|
||
|
#ifdef HAVE_U_STACK_TRACE
|
||
|
extern void U_STACK_TRACE(void);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void
|
||
|
dump_stack_trace(void)
|
||
|
{
|
||
|
|
||
|
char cmd[256];
|
||
|
|
||
|
#ifdef NO_STACK_TRACE
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
print_error("Attempting to dump a stack trace....\n");
|
||
|
signal(SIGTSTP, exit); /* Don't block on tty output, just die */
|
||
|
|
||
|
#ifdef HAVE_U_STACK_TRACE
|
||
|
U_STACK_TRACE();
|
||
|
return;
|
||
|
#elif defined(GDB)
|
||
|
snprintf(cmd, sizeof(cmd), "/bin/echo backtrace | " GDB " " APL_NAME " %d", getpid());
|
||
|
#elif defined(PSTACK)
|
||
|
snprintf(cmd, sizeof(cmd), PSTACK " %d", getpid());
|
||
|
#elif defined(DBX)
|
||
|
# ifdef _AIX
|
||
|
snprintf(cmd, sizeof(cmd), "/bin/echo 'where\ndetach' | " DBX " -a %d", getpid());
|
||
|
# elif defined(__sgi)
|
||
|
snprintf(cmd, sizeof(cmd), "/bin/echo 'where\ndetach' | " DBX " -p %d", getpid());
|
||
|
# else
|
||
|
snprintf(cmd, sizeof(cmd), "/bin/echo 'where\ndetach' | " DBX " %s %d", orig_argv0, getpid());
|
||
|
# endif
|
||
|
#else
|
||
|
print_error("Your system does not support any of the methods Eterm uses. Exiting.\n");
|
||
|
return;
|
||
|
#endif
|
||
|
system(cmd);
|
||
|
}
|
||
|
|
||
|
/* signal handling, exit handler */
|
||
|
/*
|
||
|
* Catch a SIGCHLD signal and exit if the direct child has died
|
||
|
*/
|
||
|
RETSIGTYPE
|
||
|
Child_signal(int sig)
|
||
|
{
|
||
|
|
||
|
int pid, save_errno = errno;
|
||
|
|
||
|
D_CMD(("Received signal %s (%d)\n", sig_to_str(sig), sig));
|
||
|
|
||
|
do {
|
||
|
errno = 0;
|
||
|
} while ((-1 == (pid = waitpid(-1, NULL, WNOHANG))) &&
|
||
|
(errno == EINTR));
|
||
|
|
||
|
D_CMD(("pid == %d, cmd_pid == %d\n", pid, cmd_pid));
|
||
|
/* If the child that exited is the command we spawned, or if the
|
||
|
child exited before fork() returned in the parent, it must be
|
||
|
our immediate child that exited. We exit gracefully. */
|
||
|
if (pid == cmd_pid || cmd_pid == -1) {
|
||
|
if (Options & Opt_pause) {
|
||
|
const char *message = "\r\nPress any key to exit " APL_NAME "....";
|
||
|
|
||
|
scr_refresh(SMOOTH_REFRESH);
|
||
|
scr_add_lines(message, 1, strlen(message));
|
||
|
scr_refresh(SMOOTH_REFRESH);
|
||
|
keypress_exit = 1;
|
||
|
return;
|
||
|
}
|
||
|
exit(EXIT_SUCCESS);
|
||
|
}
|
||
|
errno = save_errno;
|
||
|
|
||
|
D_CMD(("Child_signal: installing signal handler\n"));
|
||
|
signal(SIGCHLD, Child_signal);
|
||
|
|
||
|
#ifdef NEED_EXPLICIT_RETURN
|
||
|
D_CMD(("FUN FUN FUN. Child_signal returned 0 :)\n"));
|
||
|
return ((RETSIGTYPE) 0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* Handles signals usually sent by a user, like HUP, TERM, INT. */
|
||
|
RETSIGTYPE
|
||
|
Exit_signal(int sig)
|
||
|
{
|
||
|
|
||
|
print_error("Received terminal signal %s (%d)", sig_to_str(sig), sig);
|
||
|
signal(sig, SIG_DFL);
|
||
|
|
||
|
#ifdef UTMP_SUPPORT
|
||
|
privileges(INVOKE);
|
||
|
cleanutent();
|
||
|
privileges(REVERT);
|
||
|
#endif
|
||
|
|
||
|
/* No! This causes unhandled signal propogation! -- mej */
|
||
|
/* kill(getpid(), sig); */
|
||
|
|
||
|
D_CMD(("Exit_signal(): exit(%s)\n", sig_to_str(sig)));
|
||
|
exit(sig);
|
||
|
}
|
||
|
|
||
|
/* Handles abnormal termination signals -- mej */
|
||
|
static RETSIGTYPE
|
||
|
SegvHandler(int sig)
|
||
|
{
|
||
|
|
||
|
print_error("Received terminal signal %s (%d)", sig_to_str(sig), sig);
|
||
|
signal(sig, SIG_DFL); /* Let the OS handle recursive seg faults */
|
||
|
|
||
|
/* Lock down security so we don't write any core files as root. */
|
||
|
privileges(REVERT);
|
||
|
umask(077);
|
||
|
|
||
|
/* Make an attempt to dump a stack trace */
|
||
|
dump_stack_trace();
|
||
|
|
||
|
/* Exit */
|
||
|
exit(sig);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Exit gracefully, clearing the utmp entry and restoring tty attributes
|
||
|
* TODO: Also free up X resources, etc., if possible
|
||
|
*/
|
||
|
void
|
||
|
clean_exit(void)
|
||
|
{
|
||
|
scr_release();
|
||
|
privileges(INVOKE);
|
||
|
|
||
|
#ifndef __CYGWIN32__
|
||
|
if (ttydev) {
|
||
|
D_CMD(("Restoring \"%s\" to mode %03o, uid %d, gid %d\n", ttydev, ttyfd_stat.st_mode,
|
||
|
ttyfd_stat.st_uid, ttyfd_stat.st_gid));
|
||
|
if (chmod(ttydev, ttyfd_stat.st_mode) != 0) {
|
||
|
D_UTMP(("chmod(\"%s\", %03o) failed: %s\n", ttydev, ttyfd_stat.st_mode, strerror(errno)));
|
||
|
}
|
||
|
if (chown(ttydev, ttyfd_stat.st_uid, ttyfd_stat.st_gid) != 0) {
|
||
|
D_UTMP(("chown(\"%s\", %d, %d) failed: %s\n", ttydev, ttyfd_stat.st_uid, ttyfd_stat.st_gid, strerror(errno)));
|
||
|
}
|
||
|
}
|
||
|
#endif /* __CYGWIN32__ */
|
||
|
|
||
|
#ifdef UTMP_SUPPORT
|
||
|
cleanutent();
|
||
|
#endif
|
||
|
privileges(REVERT);
|
||
|
#ifdef USE_POSIX_THREADS
|
||
|
/* Get rid of threads if there are any running. Doesn't work yet. */
|
||
|
# if 0
|
||
|
D_THREADS(("pthread_kill_other_threads_np();\n"));
|
||
|
pthread_kill_other_threads_np();
|
||
|
D_THREADS(("pthread_exit();\n"));
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/* Work around a nasty Solaris X bug. If we're not unmapped in
|
||
|
3 seconds, it ain't gonna happen. Die anyway. -- mej */
|
||
|
#ifdef HAVE__EXIT
|
||
|
signal(SIGALRM, _exit);
|
||
|
#else
|
||
|
signal(SIGALRM, abort);
|
||
|
#endif
|
||
|
alarm(3);
|
||
|
|
||
|
/* Close the display connection to the X server. Unmap the windows
|
||
|
* first.
|
||
|
*/
|
||
|
D_X11(("XUnmapWindow(Xdisplay, TermWin.parent);\n"));
|
||
|
XUnmapWindow(Xdisplay, TermWin.parent);
|
||
|
D_X11(("XSync(Xdisplay, TRUE) - discarding events\n"));
|
||
|
/* XSync discards all events in the event queue. */
|
||
|
XSync(Xdisplay, TRUE);
|
||
|
D_X11(("XCloseDisplay(Xdisplay);\n"));
|
||
|
XCloseDisplay(Xdisplay);
|
||
|
}
|
||
|
#if (MENUBAR_MAX)
|
||
|
inline void
|
||
|
map_menuBar(int map)
|
||
|
{
|
||
|
|
||
|
if (delay_menu_drawing) {
|
||
|
delay_menu_drawing++;
|
||
|
} else if (menubar_mapping(map)) {
|
||
|
resize();
|
||
|
}
|
||
|
PrivMode(map, PrivMode_menuBar);
|
||
|
}
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
|
||
|
inline void
|
||
|
map_scrollBar(int map)
|
||
|
{
|
||
|
|
||
|
if (scrollbar_mapping(map)) {
|
||
|
scr_touch();
|
||
|
resize();
|
||
|
}
|
||
|
PrivMode(map, PrivMode_scrollBar);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Returns true if running under E, false otherwise */
|
||
|
inline unsigned char
|
||
|
check_for_enlightenment(void)
|
||
|
{
|
||
|
static char have_e = -1;
|
||
|
|
||
|
if (have_e == -1) {
|
||
|
if (XInternAtom(Xdisplay, "ENLIGHTENMENT_COMMS", True) != None) {
|
||
|
D_X11(("Enlightenment detected.\n"));
|
||
|
have_e = 1;
|
||
|
} else {
|
||
|
D_X11(("Enlightenment not detected.\n"));
|
||
|
have_e = 0;
|
||
|
}
|
||
|
}
|
||
|
return (have_e);
|
||
|
}
|
||
|
|
||
|
/* Acquire a pseudo-teletype from the system. */
|
||
|
/*
|
||
|
* On failure, returns -1.
|
||
|
* On success, returns the file descriptor.
|
||
|
*
|
||
|
* If successful, ttydev and ptydev point to the names of the
|
||
|
* master and slave parts
|
||
|
*/
|
||
|
|
||
|
#ifdef __sgi
|
||
|
inline int
|
||
|
sgi_get_pty(void)
|
||
|
{
|
||
|
|
||
|
int fd = -1;
|
||
|
|
||
|
ptydev = ttydev = _getpty(&fd, O_RDWR | O_NDELAY, 0622, 0);
|
||
|
return (ptydev == NULL ? -1 : fd);
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef _AIX
|
||
|
inline int
|
||
|
aix_get_pty(void)
|
||
|
{
|
||
|
|
||
|
int fd = -1;
|
||
|
|
||
|
if ((fd = open("/dev/ptc", O_RDWR)) < 0)
|
||
|
return (-1);
|
||
|
else
|
||
|
ptydev = ttydev = ttyname(fd);
|
||
|
return (fd);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef ALL_NUMERIC_PTYS
|
||
|
inline int
|
||
|
sco_get_pty(void)
|
||
|
{
|
||
|
|
||
|
static char pty_name[] = "/dev/ptyp??\0\0\0";
|
||
|
static char tty_name[] = "/dev/ttyp??\0\0\0";
|
||
|
int idx;
|
||
|
int fd = -1;
|
||
|
|
||
|
ptydev = pty_name;
|
||
|
ttydev = tty_name;
|
||
|
|
||
|
for (idx = 0; idx < 256; idx++) {
|
||
|
|
||
|
sprintf(ptydev, "%s%d", "/dev/ptyp", idx);
|
||
|
sprintf(ttydev, "%s%d", "/dev/ttyp", idx);
|
||
|
|
||
|
if (access(ttydev, F_OK) < 0) {
|
||
|
idx = 256;
|
||
|
break;
|
||
|
}
|
||
|
if ((fd = open(ptydev, O_RDWR)) >= 0) {
|
||
|
if (access(ttydev, R_OK | W_OK) == 0)
|
||
|
return (fd);
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
return (-1);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if defined (__svr4__) || defined(__CYGWIN32__) || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1))
|
||
|
inline int
|
||
|
svr_get_pty(void)
|
||
|
{
|
||
|
|
||
|
int fd = -1;
|
||
|
|
||
|
/* open the STREAMS, clone device /dev/ptmx (master pty) */
|
||
|
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) {
|
||
|
return (-1);
|
||
|
} else {
|
||
|
if (grantpt(fd) != 0) {
|
||
|
print_error("grantpt(%d) failed: %s\n", fd, strerror(errno));
|
||
|
return (-1);
|
||
|
} else if (unlockpt(fd) != 0) {
|
||
|
print_error("unlockpt(%d) failed: %s\n", fd, strerror(errno));
|
||
|
return (-1);
|
||
|
} else {
|
||
|
ptydev = ttydev = ptsname(fd);
|
||
|
if (ttydev == NULL) {
|
||
|
print_error("ptsname(%d) failed: %s\n", fd, strerror(errno));
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (fd);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#define PTYCHAR1 "pqrstuvwxyz"
|
||
|
#define PTYCHAR2 "0123456789abcdefghijklmnopqrstuvwxyz"
|
||
|
|
||
|
inline int
|
||
|
gen_get_pty(void)
|
||
|
{
|
||
|
|
||
|
static char pty_name[] = "/dev/pty??";
|
||
|
static char tty_name[] = "/dev/tty??";
|
||
|
int len = sizeof(tty_name);
|
||
|
char *c1, *c2;
|
||
|
int fd = -1;
|
||
|
|
||
|
ptydev = pty_name;
|
||
|
ttydev = tty_name;
|
||
|
|
||
|
for (c1 = PTYCHAR1; *c1; c1++) {
|
||
|
ptydev[len - 3] = ttydev[len - 3] = *c1;
|
||
|
for (c2 = PTYCHAR2; *c2; c2++) {
|
||
|
ptydev[len - 2] = ttydev[len - 2] = *c2;
|
||
|
if ((fd = open(ptydev, O_RDWR)) >= 0) {
|
||
|
if (access(ttydev, R_OK | W_OK) == 0)
|
||
|
return (fd);
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
get_pty(void)
|
||
|
{
|
||
|
|
||
|
int fd = -1;
|
||
|
|
||
|
#if defined(__sgi)
|
||
|
fd = sgi_get_pty();
|
||
|
#elif defined(_AIX)
|
||
|
fd = aix_get_pty();
|
||
|
#elif defined(__svr4__) || defined(__CYGWIN32__)
|
||
|
fd = svr_get_pty();
|
||
|
#elif ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1))
|
||
|
fd = svr_get_pty();
|
||
|
#elif defined(ALL_NUMERIC_PTYS) /* SCO OSr5 */
|
||
|
fd = sco_get_pty();
|
||
|
#endif
|
||
|
|
||
|
/* Fall back on this method */
|
||
|
if (fd == -1) {
|
||
|
fd = gen_get_pty();
|
||
|
}
|
||
|
if (fd != -1) {
|
||
|
fcntl(fd, F_SETFL, O_NDELAY);
|
||
|
return (fd);
|
||
|
} else {
|
||
|
print_error("Can't open pseudo-tty -- %s", strerror(errno));
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* establish a controlling teletype for new session */
|
||
|
/*
|
||
|
* On some systems this can be done with ioctl() but on others we
|
||
|
* need to re-open the slave tty.
|
||
|
*/
|
||
|
int
|
||
|
get_tty(void)
|
||
|
{
|
||
|
int fd;
|
||
|
pid_t pid;
|
||
|
|
||
|
/*
|
||
|
* setsid() [or setpgrp] must be before open of the terminal,
|
||
|
* otherwise there is no controlling terminal (Solaris 2.4, HP-UX 9)
|
||
|
*/
|
||
|
#ifndef ultrix
|
||
|
# ifdef NO_SETSID
|
||
|
pid = setpgrp(0, 0);
|
||
|
# else
|
||
|
pid = setsid();
|
||
|
# endif
|
||
|
if (pid < 0) {
|
||
|
D_TTYMODE(("%s: setsid() failed: %s, PID == %d\n", rs_name, strerror(errno), pid));
|
||
|
}
|
||
|
#endif /* ultrix */
|
||
|
|
||
|
privileges(INVOKE);
|
||
|
if (ttydev == NULL) {
|
||
|
print_error("Slave tty device name is NULL. Failed to open slave pty.\n");
|
||
|
exit(EXIT_FAILURE);
|
||
|
} else if ((fd = open(ttydev, O_RDWR)) < 0) {
|
||
|
print_error("Can't open slave tty %s -- %s", ttydev, strerror(errno));
|
||
|
exit(EXIT_FAILURE);
|
||
|
} else {
|
||
|
D_TTY(("Opened slave tty %s\n", ttydev));
|
||
|
privileges(REVERT);
|
||
|
}
|
||
|
|
||
|
#if defined (__svr4__)
|
||
|
/*
|
||
|
* Push STREAMS modules:
|
||
|
* ptem: pseudo-terminal hardware emulation module.
|
||
|
* ldterm: standard terminal line discipline.
|
||
|
* ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
|
||
|
*/
|
||
|
ioctl(fd, I_PUSH, "ptem");
|
||
|
ioctl(fd, I_PUSH, "ldterm");
|
||
|
ioctl(fd, I_PUSH, "ttcompat");
|
||
|
#else /* __svr4__ */
|
||
|
{
|
||
|
/* change ownership of tty to real uid and real group */
|
||
|
unsigned int mode = 0620;
|
||
|
gid_t gid = my_rgid;
|
||
|
|
||
|
# ifdef USE_GETGRNAME
|
||
|
{
|
||
|
struct group *gr = getgrnam(TTY_GRP_NAME);
|
||
|
|
||
|
if (gr) {
|
||
|
/* change ownership of tty to real uid, "tty" gid */
|
||
|
gid = gr->gr_gid;
|
||
|
mode = 0620;
|
||
|
}
|
||
|
}
|
||
|
# endif /* USE_GETGRNAME */
|
||
|
|
||
|
privileges(INVOKE);
|
||
|
# ifndef __CYGWIN32__
|
||
|
fchown(fd, my_ruid, gid); /* fail silently */
|
||
|
fchmod(fd, mode);
|
||
|
# endif
|
||
|
privileges(REVERT);
|
||
|
}
|
||
|
#endif /* __svr4__ */
|
||
|
|
||
|
/*
|
||
|
* Close all file descriptors. If only stdin/out/err are closed,
|
||
|
* child processes remain alive upon deletion of the window.
|
||
|
*/
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < num_fds; i++) {
|
||
|
if (i != fd)
|
||
|
close(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Reopen stdin, stdout and stderr over the tty file descriptor */
|
||
|
dup(fd); /* 0: stdin */
|
||
|
dup(fd); /* 1: stdout */
|
||
|
dup(fd); /* 2: stderr */
|
||
|
|
||
|
if (fd > 2)
|
||
|
close(fd);
|
||
|
|
||
|
privileges(INVOKE);
|
||
|
|
||
|
#ifdef ultrix
|
||
|
if ((fd = open("/dev/tty", O_RDONLY)) >= 0) {
|
||
|
ioctl(fd, TIOCNOTTY, 0);
|
||
|
close(fd);
|
||
|
} else {
|
||
|
# ifdef NO_SETSID
|
||
|
pid = setpgrp(0, 0);
|
||
|
# else
|
||
|
pid = setsid();
|
||
|
# endif
|
||
|
if (pid < 0) {
|
||
|
D_TTYMODE(("%s: setsid() failed: %s, PID == %d\n", rs_name, strerror(errno), pid));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* no error, we could run with no tty to begin with */
|
||
|
#else /* ultrix */
|
||
|
|
||
|
# ifdef TIOCSCTTY
|
||
|
ioctl(0, TIOCSCTTY, 0);
|
||
|
# endif
|
||
|
|
||
|
/* set process group */
|
||
|
# if defined (_POSIX_VERSION) || defined (__svr4__)
|
||
|
tcsetpgrp(0, pid);
|
||
|
# elif defined (TIOCSPGRP)
|
||
|
ioctl(0, TIOCSPGRP, &pid);
|
||
|
# endif
|
||
|
|
||
|
/* svr4 problems: reports no tty, no job control */
|
||
|
/* # if !defined (__svr4__) && defined (TIOCSPGRP) */
|
||
|
|
||
|
close(open(ttydev, O_RDWR, 0));
|
||
|
/* # endif */
|
||
|
#endif /* ultrix */
|
||
|
|
||
|
privileges(REVERT);
|
||
|
|
||
|
return (fd);
|
||
|
}
|
||
|
|
||
|
/* debug_ttymode() */
|
||
|
#if DEBUG >= DEBUG_TTYMODE && defined(HAVE_TERMIOS_H)
|
||
|
|
||
|
/* cpp token stringize doesn't work on all machines <sigh> */
|
||
|
# define SHOW_TTY_FLAG(flag,name) do { \
|
||
|
if ((ttymode->c_iflag) & (flag)) { \
|
||
|
fprintf(stderr, "+%s ", name); \
|
||
|
} else { \
|
||
|
fprintf(stderr, "-%s ", name); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
# define SHOW_CONT_CHAR(entry, name) fprintf(stderr, "%s=%#3o ", name, ttymode->c_cc[entry])
|
||
|
static void
|
||
|
debug_ttymode(ttymode_t * ttymode)
|
||
|
{
|
||
|
|
||
|
/* c_iflag bits */
|
||
|
fprintf(stderr, "Input flags: ");
|
||
|
SHOW_TTY_FLAG(IGNBRK, "IGNBRK");
|
||
|
SHOW_TTY_FLAG(BRKINT, "BRKINT");
|
||
|
SHOW_TTY_FLAG(IGNPAR, "IGNPAR");
|
||
|
SHOW_TTY_FLAG(PARMRK, "PARMRK");
|
||
|
SHOW_TTY_FLAG(INPCK, "INPCK");
|
||
|
SHOW_TTY_FLAG(ISTRIP, "ISTRIP");
|
||
|
SHOW_TTY_FLAG(INLCR, "INLCR");
|
||
|
SHOW_TTY_FLAG(IGNCR, "IGNCR");
|
||
|
SHOW_TTY_FLAG(ICRNL, "ICRNL");
|
||
|
SHOW_TTY_FLAG(IXON, "IXON");
|
||
|
SHOW_TTY_FLAG(IXOFF, "IXOFF");
|
||
|
# ifdef IUCLC
|
||
|
SHOW_TTY_FLAG(IUCLC, "IUCLC");
|
||
|
# endif
|
||
|
# ifdef IXANY
|
||
|
SHOW_TTY_FLAG(IXANY, "IXANY");
|
||
|
# endif
|
||
|
# ifdef IMAXBEL
|
||
|
SHOW_TTY_FLAG(IMAXBEL, "IMAXBEL");
|
||
|
# endif
|
||
|
fprintf(stderr, "\n");
|
||
|
|
||
|
fprintf(stderr, "Control character mappings: ");
|
||
|
SHOW_CONT_CHAR(VINTR, "VINTR");
|
||
|
SHOW_CONT_CHAR(VQUIT, "VQUIT");
|
||
|
SHOW_CONT_CHAR(VERASE, "VERASE");
|
||
|
SHOW_CONT_CHAR(VKILL, "VKILL");
|
||
|
SHOW_CONT_CHAR(VEOF, "VEOF");
|
||
|
SHOW_CONT_CHAR(VEOL, "VEOL");
|
||
|
# ifdef VEOL2
|
||
|
SHOW_CONT_CHAR(VEOL2, "VEOL2");
|
||
|
# endif
|
||
|
# ifdef VSWTC
|
||
|
SHOW_CONT_CHAR(VSWTC, "VSWTC");
|
||
|
# endif
|
||
|
# ifdef VSWTCH
|
||
|
SHOW_CONT_CHAR(VSWTCH, "VSWTCH");
|
||
|
# endif
|
||
|
SHOW_CONT_CHAR(VSTART, "VSTART");
|
||
|
SHOW_CONT_CHAR(VSTOP, "VSTOP");
|
||
|
SHOW_CONT_CHAR(VSUSP, "VSUSP");
|
||
|
# ifdef VDSUSP
|
||
|
SHOW_CONT_CHAR(VDSUSP, "VDSUSP");
|
||
|
# endif
|
||
|
# ifdef VREPRINT
|
||
|
SHOW_CONT_CHAR(VREPRINT, "VREPRINT");
|
||
|
# endif
|
||
|
# ifdef VDISCRD
|
||
|
SHOW_CONT_CHAR(VDISCRD, "VDISCRD");
|
||
|
# endif
|
||
|
# ifdef VWERSE
|
||
|
SHOW_CONT_CHAR(VWERSE, "VWERSE");
|
||
|
# endif
|
||
|
# ifdef VLNEXT
|
||
|
SHOW_CONT_CHAR(VLNEXT, "VLNEXT");
|
||
|
# endif
|
||
|
fprintf(stderr, "\n\n");
|
||
|
}
|
||
|
|
||
|
# undef SHOW_TTY_FLAG
|
||
|
# undef SHOW_CONT_CHAR
|
||
|
#endif /* DEBUG_TTYMODE */
|
||
|
|
||
|
/* get_ttymode() */
|
||
|
static void
|
||
|
get_ttymode(ttymode_t * tio)
|
||
|
{
|
||
|
#ifdef HAVE_TERMIOS_H
|
||
|
/*
|
||
|
* standard System V termios interface
|
||
|
*/
|
||
|
if (GET_TERMIOS(0, tio) < 0) {
|
||
|
/* return error - use system defaults */
|
||
|
tio->c_cc[VINTR] = CINTR;
|
||
|
tio->c_cc[VQUIT] = CQUIT;
|
||
|
tio->c_cc[VERASE] = CERASE;
|
||
|
tio->c_cc[VKILL] = CKILL;
|
||
|
tio->c_cc[VSTART] = CSTART;
|
||
|
tio->c_cc[VSTOP] = CSTOP;
|
||
|
tio->c_cc[VSUSP] = CSUSP;
|
||
|
# ifdef VDSUSP
|
||
|
tio->c_cc[VDSUSP] = CDSUSP;
|
||
|
# endif
|
||
|
# ifdef VREPRINT
|
||
|
tio->c_cc[VREPRINT] = CRPRNT;
|
||
|
# endif
|
||
|
# ifdef VDISCRD
|
||
|
tio->c_cc[VDISCRD] = CFLUSH;
|
||
|
# endif
|
||
|
# ifdef VWERSE
|
||
|
tio->c_cc[VWERSE] = CWERASE;
|
||
|
# endif
|
||
|
# ifdef VLNEXT
|
||
|
tio->c_cc[VLNEXT] = CLNEXT;
|
||
|
# endif
|
||
|
}
|
||
|
tio->c_cc[VEOF] = CEOF;
|
||
|
tio->c_cc[VEOL] = VDISABLE;
|
||
|
# ifdef VEOL2
|
||
|
tio->c_cc[VEOL2] = VDISABLE;
|
||
|
# endif
|
||
|
# ifdef VSWTC
|
||
|
tio->c_cc[VSWTC] = VDISABLE;
|
||
|
# endif
|
||
|
# ifdef VSWTCH
|
||
|
tio->c_cc[VSWTCH] = VDISABLE;
|
||
|
# endif
|
||
|
# if VMIN != VEOF
|
||
|
tio->c_cc[VMIN] = 1;
|
||
|
# endif
|
||
|
# if VTIME != VEOL
|
||
|
tio->c_cc[VTIME] = 0;
|
||
|
# endif
|
||
|
|
||
|
/* input modes */
|
||
|
tio->c_iflag = (BRKINT | IGNPAR | ICRNL | IXON
|
||
|
# ifdef IMAXBEL
|
||
|
| IMAXBEL
|
||
|
# endif
|
||
|
);
|
||
|
|
||
|
/* output modes */
|
||
|
tio->c_oflag = (OPOST | ONLCR);
|
||
|
|
||
|
/* control modes */
|
||
|
tio->c_cflag = (CS8 | CREAD);
|
||
|
|
||
|
/* line discipline modes */
|
||
|
tio->c_lflag = (ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK
|
||
|
# if defined (ECHOCTL) && defined (ECHOKE)
|
||
|
| ECHOCTL | ECHOKE
|
||
|
# endif
|
||
|
);
|
||
|
|
||
|
/*
|
||
|
* guess an appropriate value for Backspace
|
||
|
*/
|
||
|
|
||
|
#if defined(FORCE_BACKSPACE) && 0
|
||
|
PrivMode(1, PrivMode_BackSpace);
|
||
|
tio->c_cc[VERASE] = '\b'; /* force ^H for stty setting... */
|
||
|
SET_TERMIOS(0, tio); /* ...and make it stick -- casey */
|
||
|
#elif defined(FORCE_DELETE) && 0
|
||
|
PrivMode(0, PrivMode_BackSpace);
|
||
|
tio->c_cc[VERASE] = 0x7f; /* force ^? for stty setting... */
|
||
|
SET_TERMIOS(0, tio); /* ...and make it stick -- casey */
|
||
|
#else
|
||
|
PrivMode((tio->c_cc[VERASE] == '\b'), PrivMode_BackSpace);
|
||
|
#endif
|
||
|
|
||
|
#else /* HAVE_TERMIOS_H */
|
||
|
|
||
|
/*
|
||
|
* sgtty interface
|
||
|
*/
|
||
|
|
||
|
/* get parameters -- gtty */
|
||
|
if (ioctl(0, TIOCGETP, &(tio->sg)) < 0) {
|
||
|
tio->sg.sg_erase = CERASE; /* ^H */
|
||
|
tio->sg.sg_kill = CKILL; /* ^U */
|
||
|
}
|
||
|
tio->sg.sg_flags = (CRMOD | ECHO | EVENP | ODDP);
|
||
|
|
||
|
/* get special characters */
|
||
|
if (ioctl(0, TIOCGETC, &(tio->tc)) < 0) {
|
||
|
tio->tc.t_intrc = CINTR; /* ^C */
|
||
|
tio->tc.t_quitc = CQUIT; /* ^\ */
|
||
|
tio->tc.t_startc = CSTART; /* ^Q */
|
||
|
tio->tc.t_stopc = CSTOP; /* ^S */
|
||
|
tio->tc.t_eofc = CEOF; /* ^D */
|
||
|
tio->tc.t_brkc = -1;
|
||
|
}
|
||
|
/* get local special chars */
|
||
|
if (ioctl(0, TIOCGLTC, &(tio->lc)) < 0) {
|
||
|
tio->lc.t_suspc = CSUSP; /* ^Z */
|
||
|
tio->lc.t_dsuspc = CDSUSP; /* ^Y */
|
||
|
tio->lc.t_rprntc = CRPRNT; /* ^R */
|
||
|
tio->lc.t_flushc = CFLUSH; /* ^O */
|
||
|
tio->lc.t_werasc = CWERASE; /* ^W */
|
||
|
tio->lc.t_lnextc = CLNEXT; /* ^V */
|
||
|
}
|
||
|
/* get line discipline */
|
||
|
ioctl(0, TIOCGETD, &(tio->line));
|
||
|
# ifdef NTTYDISC
|
||
|
tio->line = NTTYDISC;
|
||
|
# endif /* NTTYDISC */
|
||
|
tio->local = (LCRTBS | LCRTERA | LCTLECH | LPASS8 | LCRTKIL);
|
||
|
|
||
|
/*
|
||
|
* guess an appropriate value for Backspace
|
||
|
*/
|
||
|
|
||
|
# ifdef FORCE_BACKSPACE
|
||
|
PrivMode(1, PrivMode_BackSpace);
|
||
|
tio->sg.sg_erase = '\b';
|
||
|
SET_TTYMODE(0, tio);
|
||
|
# elif defined (FORCE_DELETE)
|
||
|
PrivMode(0, PrivMode_BackSpace);
|
||
|
tio->sg.sg_erase = 0x7f;
|
||
|
SET_TTYMODE(0, tio);
|
||
|
# else
|
||
|
PrivMode((tio->sg.sg_erase == '\b'), PrivMode_BackSpace);
|
||
|
# endif
|
||
|
|
||
|
#endif /* HAVE_TERMIOS_H */
|
||
|
}
|
||
|
|
||
|
/* run_command() */
|
||
|
/*
|
||
|
* Run the command in a subprocess and return a file descriptor for the
|
||
|
* master end of the pseudo-teletype pair with the command talking to
|
||
|
* the slave.
|
||
|
*/
|
||
|
int
|
||
|
run_command(char *argv[])
|
||
|
{
|
||
|
|
||
|
ttymode_t tio;
|
||
|
int ptyfd;
|
||
|
|
||
|
/* Save and then give up any super-user privileges */
|
||
|
privileges(IGNORE);
|
||
|
|
||
|
ptyfd = get_pty();
|
||
|
if (ptyfd < 0)
|
||
|
return (-1);
|
||
|
|
||
|
/* store original tty status for restoration clean_exit() -- rgg 04/12/95 */
|
||
|
lstat(ttydev, &ttyfd_stat);
|
||
|
D_CMD(("Original settings of %s are mode %o, uid %d, gid %d\n", ttydev, ttyfd_stat.st_mode,
|
||
|
ttyfd_stat.st_uid, ttyfd_stat.st_gid));
|
||
|
|
||
|
/* install exit handler for cleanup */
|
||
|
#ifdef HAVE_ATEXIT
|
||
|
atexit(clean_exit);
|
||
|
#else
|
||
|
# if defined (__sun__)
|
||
|
on_exit(clean_exit, NULL); /* non-ANSI exit handler */
|
||
|
# else
|
||
|
print_error("no atexit(), UTMP entries can't be cleaned");
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* get tty settings before fork()
|
||
|
* and make a reasonable guess at the value for BackSpace
|
||
|
*/
|
||
|
get_ttymode(&tio);
|
||
|
/* add Backspace value */
|
||
|
SavedModes |= (PrivateModes & PrivMode_BackSpace);
|
||
|
|
||
|
/* add value for scrollBar */
|
||
|
if (scrollbar_visible()) {
|
||
|
PrivateModes |= PrivMode_scrollBar;
|
||
|
SavedModes |= PrivMode_scrollBar;
|
||
|
}
|
||
|
if (menubar_visible()) {
|
||
|
PrivateModes |= PrivMode_menuBar;
|
||
|
SavedModes |= PrivMode_menuBar;
|
||
|
}
|
||
|
#if DEBUG >= DEBUG_TTYMODE && defined(HAVE_TERMIOS_H)
|
||
|
if (debug_level >= DEBUG_TTYMODE) {
|
||
|
debug_ttymode(&tio);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* spin off the command interpreter */
|
||
|
signal(SIGHUP, Exit_signal);
|
||
|
#ifndef __svr4__
|
||
|
signal(SIGINT, Exit_signal);
|
||
|
#endif
|
||
|
signal(SIGQUIT, SegvHandler);
|
||
|
signal(SIGTERM, Exit_signal);
|
||
|
signal(SIGCHLD, Child_signal);
|
||
|
signal(SIGSEGV, SegvHandler);
|
||
|
signal(SIGBUS, SegvHandler);
|
||
|
signal(SIGABRT, SegvHandler);
|
||
|
signal(SIGFPE, SegvHandler);
|
||
|
signal(SIGILL, SegvHandler);
|
||
|
signal(SIGSYS, SegvHandler);
|
||
|
|
||
|
/* need to trap SIGURG for SVR4 (Unixware) rlogin */
|
||
|
/* signal (SIGURG, SIG_DFL); */
|
||
|
|
||
|
D_CMD(("run_command(): forking\n"));
|
||
|
cmd_pid = fork();
|
||
|
D_CMD(("After fork(), cmd_pid == %d\n", cmd_pid));
|
||
|
if (cmd_pid < 0) {
|
||
|
print_error("fork(): %s", strerror(errno));
|
||
|
return (-1);
|
||
|
}
|
||
|
if (cmd_pid == 0) { /* child */
|
||
|
|
||
|
/* signal (SIGHUP, Exit_signal); */
|
||
|
/* signal (SIGINT, Exit_signal); */
|
||
|
#ifdef HAVE_UNSETENV
|
||
|
/* avoid passing old settings and confusing term size */
|
||
|
unsetenv("LINES");
|
||
|
unsetenv("COLUMNS");
|
||
|
/* avoid passing termcap since terminfo should be okay */
|
||
|
unsetenv("TERMCAP");
|
||
|
#endif /* HAVE_UNSETENV */
|
||
|
/* establish a controlling teletype for the new session */
|
||
|
get_tty();
|
||
|
|
||
|
/* initialize terminal attributes */
|
||
|
SET_TTYMODE(0, &tio);
|
||
|
|
||
|
/* become virtual console, fail silently */
|
||
|
if (Options & Opt_console) {
|
||
|
int fd = 1;
|
||
|
|
||
|
privileges(INVOKE);
|
||
|
#ifdef SRIOCSREDIR
|
||
|
fd = open(CONSOLE, O_WRONLY);
|
||
|
if (fd < 0 || ioctl(fd, SRIOCSREDIR, 0) < 0) {
|
||
|
if (fd >= 0)
|
||
|
close(fd);
|
||
|
}
|
||
|
#elif defined(TIOCCONS)
|
||
|
ioctl(0, TIOCCONS, &fd);
|
||
|
#endif /* SRIOCSREDIR */
|
||
|
privileges(REVERT);
|
||
|
}
|
||
|
tt_winsize(0); /* set window size */
|
||
|
|
||
|
/* Permanently revoke all privileges for the child process.
|
||
|
Root shells for everyone are tres uncool.... ;^) -- mej */
|
||
|
#ifdef _HPUX_SOURCE
|
||
|
setresuid(my_ruid, my_ruid, my_euid);
|
||
|
setresgid(my_rgid, my_rgid, my_egid);
|
||
|
#else
|
||
|
/* No special treatment is needed for systems with saved uids/gids,
|
||
|
because the exec*() calls reset the saved uid/gid to the
|
||
|
effective uid/gid -- mej */
|
||
|
# ifndef __CYGWIN32__
|
||
|
setregid(my_rgid, my_rgid);
|
||
|
setreuid(my_ruid, my_ruid);
|
||
|
# endif /* __CYGWIN32__ */
|
||
|
#endif /* _HPUX_SOURCE */
|
||
|
|
||
|
D_UTMP(("Child process reset\n"));
|
||
|
my_euid = my_ruid;
|
||
|
my_egid = my_rgid;
|
||
|
|
||
|
/* reset signals and spin off the command interpreter */
|
||
|
signal(SIGINT, SIG_DFL);
|
||
|
signal(SIGQUIT, SIG_DFL);
|
||
|
signal(SIGCHLD, SIG_DFL);
|
||
|
signal(SIGSEGV, SIG_DFL);
|
||
|
signal(SIGBUS, SIG_DFL);
|
||
|
signal(SIGABRT, SIG_DFL);
|
||
|
signal(SIGFPE, SIG_DFL);
|
||
|
signal(SIGILL, SIG_DFL);
|
||
|
signal(SIGSYS, SIG_DFL);
|
||
|
signal(SIGALRM, SIG_DFL);
|
||
|
|
||
|
/*
|
||
|
* mimick login's behavior by disabling the job control signals
|
||
|
* a shell that wants them can turn them back on
|
||
|
*/
|
||
|
#ifdef SIGTSTP
|
||
|
signal(SIGTSTP, SIG_IGN);
|
||
|
signal(SIGTTIN, SIG_IGN);
|
||
|
signal(SIGTTOU, SIG_IGN);
|
||
|
#endif /* SIGTSTP */
|
||
|
|
||
|
/* command interpreter path */
|
||
|
D_CMD(("[%d] About to spawn shell\n", getpid()));
|
||
|
chdir(initial_dir);
|
||
|
if (argv != NULL) {
|
||
|
#if DEBUG >= DEBUG_CMD
|
||
|
if (debug_level >= DEBUG_CMD) {
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; argv[i]; i++) {
|
||
|
DPRINTF1(("argv[%d] = \"%s\"\n", i, argv[i]));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
execvp(argv[0], argv);
|
||
|
print_error("execvp() failed, cannot execute \"%s\": %s", argv[0], strerror(errno));
|
||
|
} else {
|
||
|
|
||
|
const char *argv0, *shell;
|
||
|
|
||
|
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
|
||
|
shell = "/bin/sh";
|
||
|
|
||
|
argv0 = my_basename(shell);
|
||
|
if (Options & Opt_loginShell) {
|
||
|
char *p = MALLOC((strlen(argv0) + 2) * sizeof(char));
|
||
|
|
||
|
p[0] = '-';
|
||
|
strcpy(&p[1], argv0);
|
||
|
argv0 = p;
|
||
|
}
|
||
|
execlp(shell, argv0, NULL);
|
||
|
print_error("execlp() failed, cannot execute \"%s\": %s", shell, strerror(errno));
|
||
|
}
|
||
|
sleep(3); /* Sleep to make sure fork() returns in the parent, and so user can read error message */
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
#ifdef UTMP_SUPPORT
|
||
|
privileges(RESTORE);
|
||
|
if (Options & Opt_utmpLogging)
|
||
|
makeutent(ttydev, display_name); /* stamp /etc/utmp */
|
||
|
privileges(IGNORE);
|
||
|
#endif
|
||
|
|
||
|
#if 0
|
||
|
D_THREADS(("run_command(): pthread_join(resize_sub_thr)\n"));
|
||
|
pthread_join(resize_sub_thr, NULL);
|
||
|
#endif
|
||
|
|
||
|
D_CMD(("run_command() returning\n"));
|
||
|
return (ptyfd);
|
||
|
}
|
||
|
|
||
|
/* init_command() */
|
||
|
void
|
||
|
init_command(char *argv[])
|
||
|
{
|
||
|
|
||
|
/* Initialize the command connection. This should be called after
|
||
|
the X server connection is established. */
|
||
|
|
||
|
/* Enable delete window protocol */
|
||
|
wmDeleteWindow = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", False);
|
||
|
XSetWMProtocols(Xdisplay, TermWin.parent, &wmDeleteWindow, 1);
|
||
|
|
||
|
#ifdef OFFIX_DND
|
||
|
/* Enable OffiX Dnd (drag 'n' drop) protocol */
|
||
|
DndProtocol = XInternAtom(Xdisplay, "DndProtocol", False);
|
||
|
DndSelection = XInternAtom(Xdisplay, "DndSelection", False);
|
||
|
#endif /* OFFIX_DND */
|
||
|
|
||
|
init_xlocale();
|
||
|
|
||
|
/* get number of available file descriptors */
|
||
|
#ifdef _POSIX_VERSION
|
||
|
num_fds = sysconf(_SC_OPEN_MAX);
|
||
|
#else
|
||
|
num_fds = getdtablesize();
|
||
|
#endif
|
||
|
|
||
|
#ifdef META8_OPTION
|
||
|
meta_char = (Options & Opt_meta8 ? 0x80 : 033);
|
||
|
#endif
|
||
|
|
||
|
#ifdef GREEK_SUPPORT
|
||
|
greek_init();
|
||
|
#endif
|
||
|
|
||
|
Xfd = XConnectionNumber(Xdisplay);
|
||
|
D_CMD(("Xfd = %d\n", Xfd));
|
||
|
cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
|
||
|
|
||
|
if ((cmd_fd = run_command(argv)) < 0) {
|
||
|
print_error("aborting");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Xlocale */
|
||
|
#ifndef NO_XLOCALE
|
||
|
inline const char *
|
||
|
get_input_style_flags(XIMStyle style)
|
||
|
{
|
||
|
|
||
|
static char style_buff[256];
|
||
|
|
||
|
strcpy(style_buff, "(");
|
||
|
if (style & XIMPreeditCallbacks) {
|
||
|
strcat(style_buff, "XIMPreeditCallbacks");
|
||
|
} else if (style & XIMPreeditPosition) {
|
||
|
strcat(style_buff, "XIMPreeditPosition");
|
||
|
} else if (style & XIMPreeditArea) {
|
||
|
strcat(style_buff, "XIMPreeditArea");
|
||
|
} else if (style & XIMPreeditNothing) {
|
||
|
strcat(style_buff, "XIMPreeditNothing");
|
||
|
} else if (style & XIMPreeditNone) {
|
||
|
strcat(style_buff, "XIMPreeditNone");
|
||
|
}
|
||
|
strcat(style_buff, " | ");
|
||
|
if (style & XIMStatusCallbacks) {
|
||
|
strcat(style_buff, "XIMStatusCallbacks");
|
||
|
} else if (style & XIMStatusArea) {
|
||
|
strcat(style_buff, "XIMStatusArea");
|
||
|
} else if (style & XIMStatusNothing) {
|
||
|
strcat(style_buff, "XIMStatusNothing");
|
||
|
} else if (style & XIMStatusNone) {
|
||
|
strcat(style_buff, "XIMStatusNone");
|
||
|
}
|
||
|
strcat(style_buff, ")");
|
||
|
return style_buff;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_xlocale(void)
|
||
|
{
|
||
|
|
||
|
char *p, *s, buf[32], tmp[1024];
|
||
|
XIM xim = NULL;
|
||
|
XIMStyle input_style;
|
||
|
XIMStyles *xim_styles = NULL;
|
||
|
int found, i, mc;
|
||
|
XFontSet fontset = 0;
|
||
|
char *fontname, **ml, *ds;
|
||
|
XVaNestedList list;
|
||
|
const char fs_base[] = ",-misc-fixed-*-r-*-*-*-120-*-*-*-*-*-*";
|
||
|
|
||
|
D_X11(("Initializing X locale and Input Method...\n"));
|
||
|
Input_Context = NULL;
|
||
|
if (rs_inputMethod && strlen(rs_inputMethod) >= sizeof(tmp)) {
|
||
|
print_error("Input Method too long, ignoring.");
|
||
|
rs_inputMethod = NULL;
|
||
|
}
|
||
|
# ifdef KANJI
|
||
|
setlocale(LC_CTYPE, "");
|
||
|
# else
|
||
|
if (rs_inputMethod && !*rs_inputMethod) {
|
||
|
rs_inputMethod = NULL;
|
||
|
}
|
||
|
# endif
|
||
|
|
||
|
if (rs_inputMethod == NULL) {
|
||
|
if ((p = XSetLocaleModifiers("@im=none")) != NULL && *p) {
|
||
|
xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
|
||
|
}
|
||
|
} else {
|
||
|
strcpy(tmp, rs_inputMethod);
|
||
|
for (s = tmp; *s; /*nil */ ) {
|
||
|
|
||
|
char *end, *next_s;
|
||
|
|
||
|
for (; *s && isspace(*s); s++);
|
||
|
if (!*s)
|
||
|
break;
|
||
|
end = s;
|
||
|
for (; *end && (*end != ','); end++);
|
||
|
next_s = end--;
|
||
|
for (; (end >= s) && isspace(*end); end--);
|
||
|
*(end + 1) = '\0';
|
||
|
|
||
|
if (*s) {
|
||
|
snprintf(buf, sizeof(buf), "@im=%s", s);
|
||
|
if ((p = XSetLocaleModifiers(buf)) != NULL && *p && (xim = XOpenIM(Xdisplay, NULL, NULL, NULL)) != NULL) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!*next_s)
|
||
|
break;
|
||
|
s = (next_s + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (xim == NULL && (p = XSetLocaleModifiers("")) != NULL && *p) {
|
||
|
xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
|
||
|
}
|
||
|
if (xim == NULL) {
|
||
|
D_X11(("Error: Failed to open Input Method\n"));
|
||
|
return;
|
||
|
} else {
|
||
|
D_X11(("Opened X Input Method. xim == 0x%08x\n", xim));
|
||
|
}
|
||
|
|
||
|
if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles) {
|
||
|
D_X11(("Error: Input Method doesn't support any style\n"));
|
||
|
XCloseIM(xim);
|
||
|
return;
|
||
|
} else {
|
||
|
D_X11((" -> Input Method supports %d styles.\n", xim_styles->count_styles));
|
||
|
}
|
||
|
|
||
|
/* We only support the Root preedit type */
|
||
|
input_style = (XIMPreeditNothing | XIMStatusNothing);
|
||
|
D_X11((" -> input_style == 0x%08x\n", input_style));
|
||
|
|
||
|
for (i = 0, found = 0; i < xim_styles->count_styles; i++) {
|
||
|
D_X11((" -> Supported style flags: 0x%08x %s\n", xim_styles->supported_styles[i], get_input_style_flags(xim_styles->supported_styles[i])));
|
||
|
D_X11((" -> 0x%08x %s\n", xim_styles->supported_styles[i] & input_style,
|
||
|
get_input_style_flags(xim_styles->supported_styles[i] & input_style)));
|
||
|
if ((xim_styles->supported_styles[i] & input_style) == (xim_styles->supported_styles[i])) {
|
||
|
input_style = xim_styles->supported_styles[i];
|
||
|
found = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
XFree(xim_styles);
|
||
|
|
||
|
if (!found) {
|
||
|
D_X11(("Error: " APL_NAME " " VERSION " only supports the \"Root\" preedit type, which the Input Method does not support.\n"));
|
||
|
XCloseIM(xim);
|
||
|
return;
|
||
|
}
|
||
|
/* Create Font Set */
|
||
|
|
||
|
#ifdef KANJI
|
||
|
fontname = MALLOC(strlen(rs_font[0]) + strlen(rs_kfont[0]) + sizeof(fs_base) + 2);
|
||
|
if (fontname) {
|
||
|
strcpy(fontname, rs_font[0]);
|
||
|
strcat(fontname, fs_base);
|
||
|
strcat(fontname, ",");
|
||
|
strcat(fontname, rs_kfont[0]);
|
||
|
}
|
||
|
#else
|
||
|
fontname = MALLOC(strlen(rs_font[0]) + sizeof(fs_base) + 1);
|
||
|
if (fontname) {
|
||
|
strcpy(fontname, rs_font[0]);
|
||
|
strcat(fontname, fs_base);
|
||
|
}
|
||
|
#endif
|
||
|
if (fontname) {
|
||
|
setlocale(LC_ALL, "");
|
||
|
fontset = XCreateFontSet(Xdisplay, fontname, &ml, &mc, &ds);
|
||
|
FREE(fontname);
|
||
|
if (mc) {
|
||
|
XFreeStringList(ml);
|
||
|
fontset = 0;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
list = XVaCreateNestedList(0, XNFontSet, fontset, NULL);
|
||
|
Input_Context = XCreateIC(xim, XNInputStyle, input_style, XNClientWindow, TermWin.parent, XNFocusWindow, TermWin.parent,
|
||
|
XNPreeditAttributes, list, XNStatusAttributes, list, NULL);
|
||
|
if (Input_Context == NULL) {
|
||
|
D_X11(("Error: Unable to create Input Context\n"));
|
||
|
XCloseIM(xim);
|
||
|
}
|
||
|
}
|
||
|
#endif /* NO_XLOCALE */
|
||
|
|
||
|
/* window resizing */
|
||
|
/*
|
||
|
* Tell the teletype handler what size the window is.
|
||
|
* Called after a window size change.
|
||
|
*/
|
||
|
void
|
||
|
tt_winsize(int fd)
|
||
|
{
|
||
|
|
||
|
struct winsize ws;
|
||
|
|
||
|
if (fd < 0)
|
||
|
return;
|
||
|
|
||
|
ws.ws_col = (unsigned short) TermWin.ncol;
|
||
|
ws.ws_row = (unsigned short) TermWin.nrow;
|
||
|
#ifndef __CYGWIN32__
|
||
|
ws.ws_xpixel = ws.ws_ypixel = 0;
|
||
|
#endif
|
||
|
ioctl(fd, TIOCSWINSZ, &ws);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tt_resize(void)
|
||
|
{
|
||
|
tt_winsize(cmd_fd);
|
||
|
}
|
||
|
|
||
|
/* Convert the keypress event into a string */
|
||
|
inline void
|
||
|
lookup_key(XEvent * ev)
|
||
|
{
|
||
|
|
||
|
static int numlock_state = 0;
|
||
|
static unsigned char kbuf[KBUFSZ];
|
||
|
int ctrl, meta, shft, len;
|
||
|
KeySym keysym;
|
||
|
|
||
|
#ifndef NO_XLOCALE
|
||
|
static Status status_return;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if DEBUG >= DEBUG_CMD
|
||
|
static int debug_key = 1; /* accessible by a debugger only */
|
||
|
|
||
|
#endif
|
||
|
#ifdef GREEK_SUPPORT
|
||
|
static short greek_mode = 0;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* use Num_Lock to toggle Keypad on/off. If Num_Lock is off, allow an
|
||
|
* escape sequence to toggle the Keypad.
|
||
|
*
|
||
|
* Always permit `shift' to override the current setting
|
||
|
*/
|
||
|
shft = (ev->xkey.state & ShiftMask);
|
||
|
ctrl = (ev->xkey.state & ControlMask);
|
||
|
meta = (ev->xkey.state & Mod1Mask);
|
||
|
if (numlock_state || (ev->xkey.state & Mod5Mask)) {
|
||
|
numlock_state = (ev->xkey.state & Mod5Mask); /* numlock toggle */
|
||
|
PrivMode((!numlock_state), PrivMode_aplKP);
|
||
|
}
|
||
|
#ifndef NO_XLOCALE
|
||
|
if (Input_Context != NULL) {
|
||
|
len = XmbLookupString(Input_Context, &ev->xkey, kbuf, sizeof(kbuf), &keysym, &status_return);
|
||
|
if (status_return == XLookupNone) {
|
||
|
D_X11(("XmbLookupString() returned len == %d, status_return == XLookupNone\n", len));
|
||
|
len = 0;
|
||
|
} else if (status_return == XBufferOverflow) {
|
||
|
D_X11(("XmbLookupString() returned len == %d, status_return == XBufferOverflow\n", len));
|
||
|
print_error("XmbLookupString(): Buffer overflow, string too long.");
|
||
|
XmbResetIC(Input_Context);
|
||
|
} else if (status_return == XLookupKeySym) {
|
||
|
D_X11(("XmbLookupString() returned len == %d, status_return == XLookupKeySym\n", len));
|
||
|
if ((keysym >= 0x0100) && (keysym < 0x0400)) {
|
||
|
len = 1;
|
||
|
kbuf[0] = (keysym & 0xff);
|
||
|
}
|
||
|
} else if (status_return == XLookupBoth) {
|
||
|
D_X11(("XmbLookupString() returned len == %d, status_return == XLookupBoth\n", len));
|
||
|
if ((keysym >= 0x0100) && (keysym < 0x0400)) {
|
||
|
len = 1;
|
||
|
kbuf[0] = (keysym & 0xff);
|
||
|
}
|
||
|
} else if (status_return == XLookupChars) {
|
||
|
D_X11(("XmbLookupString() returned len == %d, status_return == XLookupChars\n", len));
|
||
|
/* Nothing */
|
||
|
}
|
||
|
} else {
|
||
|
len = XLookupString(&ev->xkey, kbuf, sizeof(kbuf), &keysym, NULL);
|
||
|
}
|
||
|
#else /* NO_XLOCALE */
|
||
|
len = XLookupString(&ev->xkey, kbuf, sizeof(kbuf), &keysym, NULL);
|
||
|
/*
|
||
|
* have unmapped Latin[2-4] entries -> Latin1
|
||
|
* good for installations with correct fonts, but without XLOCAL
|
||
|
*/
|
||
|
if (!len && (keysym >= 0x0100) && (keysym < 0x0400)) {
|
||
|
len = 1;
|
||
|
kbuf[0] = (keysym & 0xff);
|
||
|
}
|
||
|
#endif /* NO_XLOCALE */
|
||
|
|
||
|
if (len && (Options & Opt_homeOnInput))
|
||
|
TermWin.view_start = 0;
|
||
|
|
||
|
/* for some backwards compatibility */
|
||
|
#if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
|
||
|
# ifdef HOTKEY_CTRL
|
||
|
# define HOTKEY ctrl
|
||
|
# else
|
||
|
# ifdef HOTKEY_META
|
||
|
# define HOTKEY meta
|
||
|
# endif
|
||
|
# endif
|
||
|
if (HOTKEY) {
|
||
|
if (keysym == ks_bigfont) {
|
||
|
change_font(0, FONT_UP);
|
||
|
return;
|
||
|
} else if (keysym == ks_smallfont) {
|
||
|
change_font(0, FONT_DN);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
# undef HOTKEY
|
||
|
#endif
|
||
|
|
||
|
if (shft) {
|
||
|
/* Shift + F1 - F10 generates F11 - F20 */
|
||
|
if (keysym >= XK_F1 && keysym <= XK_F10) {
|
||
|
keysym += (XK_F11 - XK_F1);
|
||
|
shft = 0; /* turn off Shift */
|
||
|
} else if (!ctrl && !meta && (PrivateModes & PrivMode_ShiftKeys)) {
|
||
|
|
||
|
int lnsppg; /* Lines per page to scroll */
|
||
|
|
||
|
#ifdef PAGING_CONTEXT_LINES
|
||
|
lnsppg = TermWin.nrow - PAGING_CONTEXT_LINES;
|
||
|
#else
|
||
|
lnsppg = TermWin.nrow * 4 / 5;
|
||
|
#endif
|
||
|
|
||
|
switch (keysym) {
|
||
|
/* normal XTerm key bindings */
|
||
|
case XK_Prior: /* Shift+Prior = scroll back */
|
||
|
if (TermWin.saveLines) {
|
||
|
scr_page(UP, lnsppg);
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case XK_Next: /* Shift+Next = scroll forward */
|
||
|
if (TermWin.saveLines) {
|
||
|
scr_page(DN, lnsppg);
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case XK_Insert: /* Shift+Insert = paste mouse selection */
|
||
|
selection_request(ev->xkey.time, ev->xkey.x, ev->xkey.y);
|
||
|
return;
|
||
|
break;
|
||
|
|
||
|
/* Eterm extras */
|
||
|
case XK_KP_Add: /* Shift+KP_Add = bigger font */
|
||
|
change_font(0, FONT_UP);
|
||
|
return;
|
||
|
break;
|
||
|
|
||
|
case XK_KP_Subtract: /* Shift+KP_Subtract = smaller font */
|
||
|
change_font(0, FONT_DN);
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#ifdef UNSHIFTED_SCROLLKEYS
|
||
|
else if (!ctrl && !meta) {
|
||
|
switch (keysym) {
|
||
|
case XK_Prior:
|
||
|
if (TermWin.saveLines) {
|
||
|
scr_page(UP, TermWin.nrow * 4 / 5);
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case XK_Next:
|
||
|
if (TermWin.saveLines) {
|
||
|
scr_page(DN, TermWin.nrow * 4 / 5);
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
switch (keysym) {
|
||
|
case XK_Print:
|
||
|
#if DEBUG >= DEBUG_SELECTION
|
||
|
if (debug_level >= DEBUG_SELECTION) {
|
||
|
debug_selection();
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef PRINTPIPE
|
||
|
scr_printscreen(ctrl | shft);
|
||
|
return;
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case XK_Mode_switch:
|
||
|
#ifdef GREEK_SUPPORT
|
||
|
greek_mode = !greek_mode;
|
||
|
if (greek_mode) {
|
||
|
xterm_seq(XTerm_title, (greek_getmode() == GREEK_ELOT928 ? "[Greek: iso]" : "[Greek: ibm]"));
|
||
|
greek_reset();
|
||
|
} else
|
||
|
xterm_seq(XTerm_title, APL_NAME "-" VERSION);
|
||
|
return;
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (keysym >= 0xFF00 && keysym <= 0xFFFF) {
|
||
|
#ifdef KEYSYM_ATTRIBUTE
|
||
|
if (!(shft | ctrl) && KeySym_map[keysym - 0xFF00] != NULL) {
|
||
|
|
||
|
const unsigned char *kbuf;
|
||
|
unsigned int len;
|
||
|
|
||
|
kbuf = (KeySym_map[keysym - 0xFF00]);
|
||
|
len = *kbuf++;
|
||
|
|
||
|
/* escape prefix */
|
||
|
if (meta
|
||
|
# ifdef META8_OPTION
|
||
|
&& (meta_char == 033)
|
||
|
# endif
|
||
|
) {
|
||
|
const unsigned char ch = '\033';
|
||
|
|
||
|
tt_write(&ch, 1);
|
||
|
}
|
||
|
tt_write(kbuf, len);
|
||
|
return;
|
||
|
} else
|
||
|
#endif
|
||
|
switch (keysym) {
|
||
|
case XK_BackSpace:
|
||
|
len = 1;
|
||
|
#ifdef FORCE_BACKSPACE
|
||
|
kbuf[0] = (!(shft | ctrl) ? '\b' : '\177');
|
||
|
#elif defined(FORCE_DELETE)
|
||
|
kbuf[0] = ((shft | ctrl) ? '\b' : '\177');
|
||
|
#else
|
||
|
kbuf[0] = (((PrivateModes & PrivMode_BackSpace) ? !(shft | ctrl) : (shft | ctrl)) ? '\b' : '\177');
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case XK_Tab:
|
||
|
if (shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033[Z");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#ifdef XK_KP_Home
|
||
|
case XK_KP_Home:
|
||
|
/* allow shift to override */
|
||
|
if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Ow");
|
||
|
break;
|
||
|
}
|
||
|
/* -> else FALL THROUGH */
|
||
|
#endif
|
||
|
|
||
|
case XK_Home:
|
||
|
len = strlen(strcpy(kbuf, KS_HOME));
|
||
|
break;
|
||
|
|
||
|
#ifdef XK_KP_Left
|
||
|
case XK_KP_Left: /* \033Ot or standard */
|
||
|
case XK_KP_Up: /* \033Ox or standard */
|
||
|
case XK_KP_Right: /* \033Ov or standard */
|
||
|
case XK_KP_Down: /* \033Ow or standard */
|
||
|
if ((PrivateModes && PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033OZ");
|
||
|
kbuf[2] = ("txvw"[keysym - XK_KP_Left]);
|
||
|
break;
|
||
|
} else {
|
||
|
/* translate to std. cursor key */
|
||
|
keysym = XK_Left + (keysym - XK_KP_Left);
|
||
|
}
|
||
|
/* FALL THROUGH */
|
||
|
#endif
|
||
|
case XK_Left: /* "\033[D" */
|
||
|
case XK_Up: /* "\033[A" */
|
||
|
case XK_Right: /* "\033[C" */
|
||
|
case XK_Down: /* "\033[B" */
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033[@");
|
||
|
kbuf[2] = ("DACB"[keysym - XK_Left]);
|
||
|
if (PrivateModes & PrivMode_aplCUR) {
|
||
|
kbuf[1] = 'O';
|
||
|
} else if (shft) { /* do Shift first */
|
||
|
kbuf[2] = ("dacb"[keysym - XK_Left]);
|
||
|
} else if (ctrl) {
|
||
|
kbuf[1] = 'O';
|
||
|
kbuf[2] = ("dacb"[keysym - XK_Left]);
|
||
|
}
|
||
|
break;
|
||
|
#ifndef UNSHIFTED_SCROLLKEYS
|
||
|
# ifdef XK_KP_Prior
|
||
|
case XK_KP_Prior:
|
||
|
/* allow shift to override */
|
||
|
if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Oy");
|
||
|
break;
|
||
|
}
|
||
|
/* -> else FALL THROUGH */
|
||
|
# endif /* XK_KP_Prior */
|
||
|
case XK_Prior:
|
||
|
len = 4;
|
||
|
strcpy(kbuf, "\033[5~");
|
||
|
break;
|
||
|
# ifdef XK_KP_Next
|
||
|
case XK_KP_Next:
|
||
|
/* allow shift to override */
|
||
|
if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Os");
|
||
|
break;
|
||
|
}
|
||
|
/* -> else FALL THROUGH */
|
||
|
# endif /* XK_KP_Next */
|
||
|
case XK_Next:
|
||
|
len = 4;
|
||
|
strcpy(kbuf, "\033[6~");
|
||
|
break;
|
||
|
#endif /* UNSHIFTED_SCROLLKEYS */
|
||
|
#ifdef XK_KP_End
|
||
|
case XK_KP_End:
|
||
|
/* allow shift to override */
|
||
|
if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Oq");
|
||
|
break;
|
||
|
}
|
||
|
/* -> else FALL THROUGH */
|
||
|
#endif /* XK_KP_End */
|
||
|
case XK_End:
|
||
|
len = strlen(strcpy(kbuf, KS_END));
|
||
|
break;
|
||
|
|
||
|
case XK_Select:
|
||
|
len = 4;
|
||
|
strcpy(kbuf, "\033[4~");
|
||
|
break;
|
||
|
|
||
|
#ifdef DXK_Remove /* support for DEC remove like key */
|
||
|
case DXK_Remove: /* drop */
|
||
|
#endif
|
||
|
case XK_Execute:
|
||
|
len = 4;
|
||
|
strcpy(kbuf, "\033[3~");
|
||
|
break;
|
||
|
case XK_Insert:
|
||
|
len = 4;
|
||
|
strcpy(kbuf, "\033[2~");
|
||
|
break;
|
||
|
|
||
|
case XK_Menu:
|
||
|
len = 5;
|
||
|
strcpy(kbuf, "\033[29~");
|
||
|
break;
|
||
|
case XK_Find:
|
||
|
len = 4;
|
||
|
strcpy(kbuf, "\033[1~");
|
||
|
break;
|
||
|
case XK_Help:
|
||
|
len = 5;
|
||
|
strcpy(kbuf, "\033[28~");
|
||
|
break;
|
||
|
|
||
|
case XK_KP_Enter:
|
||
|
/* allow shift to override */
|
||
|
if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033OM");
|
||
|
} else {
|
||
|
len = 1;
|
||
|
kbuf[0] = '\r';
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#ifdef XK_KP_Begin
|
||
|
case XK_KP_Begin:
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Ou");
|
||
|
break;
|
||
|
|
||
|
case XK_KP_Insert:
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Op");
|
||
|
break;
|
||
|
|
||
|
case XK_KP_Delete:
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033On");
|
||
|
break;
|
||
|
#endif /* XK_KP_Begin */
|
||
|
|
||
|
case XK_KP_F1: /* "\033OP" */
|
||
|
case XK_KP_F2: /* "\033OQ" */
|
||
|
case XK_KP_F3: /* "\033OR" */
|
||
|
case XK_KP_F4: /* "\033OS" */
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033OP");
|
||
|
kbuf[2] += (keysym - XK_KP_F1);
|
||
|
break;
|
||
|
|
||
|
case XK_KP_Multiply: /* "\033Oj" : "*" */
|
||
|
case XK_KP_Add: /* "\033Ok" : "+" */
|
||
|
case XK_KP_Separator: /* "\033Ol" : "," */
|
||
|
case XK_KP_Subtract: /* "\033Om" : "-" */
|
||
|
case XK_KP_Decimal: /* "\033On" : "." */
|
||
|
case XK_KP_Divide: /* "\033Oo" : "/" */
|
||
|
case XK_KP_0: /* "\033Op" : "0" */
|
||
|
case XK_KP_1: /* "\033Oq" : "1" */
|
||
|
case XK_KP_2: /* "\033Or" : "2" */
|
||
|
case XK_KP_3: /* "\033Os" : "3" */
|
||
|
case XK_KP_4: /* "\033Ot" : "4" */
|
||
|
case XK_KP_5: /* "\033Ou" : "5" */
|
||
|
case XK_KP_6: /* "\033Ov" : "6" */
|
||
|
case XK_KP_7: /* "\033Ow" : "7" */
|
||
|
case XK_KP_8: /* "\033Ox" : "8" */
|
||
|
case XK_KP_9: /* "\033Oy" : "9" */
|
||
|
/* allow shift to override */
|
||
|
if ((PrivateModes & PrivMode_aplKP) ? !shft : shft) {
|
||
|
len = 3;
|
||
|
strcpy(kbuf, "\033Oj");
|
||
|
kbuf[2] += (keysym - XK_KP_Multiply);
|
||
|
} else {
|
||
|
len = 1;
|
||
|
kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#define FKEY(n,fkey) do { \
|
||
|
len = 5; \
|
||
|
sprintf(kbuf,"\033[%02d~", (int)((n) + (keysym - fkey))); \
|
||
|
} while (0);
|
||
|
|
||
|
case XK_F1: /* "\033[11~" */
|
||
|
case XK_F2: /* "\033[12~" */
|
||
|
case XK_F3: /* "\033[13~" */
|
||
|
case XK_F4: /* "\033[14~" */
|
||
|
case XK_F5: /* "\033[15~" */
|
||
|
FKEY(11, XK_F1);
|
||
|
break;
|
||
|
|
||
|
case XK_F6: /* "\033[17~" */
|
||
|
case XK_F7: /* "\033[18~" */
|
||
|
case XK_F8: /* "\033[19~" */
|
||
|
case XK_F9: /* "\033[20~" */
|
||
|
case XK_F10: /* "\033[21~" */
|
||
|
FKEY(17, XK_F6);
|
||
|
break;
|
||
|
|
||
|
case XK_F11: /* "\033[23~" */
|
||
|
case XK_F12: /* "\033[24~" */
|
||
|
case XK_F13: /* "\033[25~" */
|
||
|
case XK_F14: /* "\033[26~" */
|
||
|
FKEY(23, XK_F11);
|
||
|
break;
|
||
|
|
||
|
case XK_F15: /* "\033[28~" */
|
||
|
case XK_F16: /* "\033[29~" */
|
||
|
FKEY(28, XK_F15);
|
||
|
break;
|
||
|
|
||
|
case XK_F17: /* "\033[31~" */
|
||
|
case XK_F18: /* "\033[32~" */
|
||
|
case XK_F19: /* "\033[33~" */
|
||
|
case XK_F20: /* "\033[34~" */
|
||
|
case XK_F21: /* "\033[35~" */
|
||
|
case XK_F22: /* "\033[36~" */
|
||
|
case XK_F23: /* "\033[37~" */
|
||
|
case XK_F24: /* "\033[38~" */
|
||
|
case XK_F25: /* "\033[39~" */
|
||
|
case XK_F26: /* "\033[40~" */
|
||
|
case XK_F27: /* "\033[41~" */
|
||
|
case XK_F28: /* "\033[42~" */
|
||
|
case XK_F29: /* "\033[43~" */
|
||
|
case XK_F30: /* "\033[44~" */
|
||
|
case XK_F31: /* "\033[45~" */
|
||
|
case XK_F32: /* "\033[46~" */
|
||
|
case XK_F33: /* "\033[47~" */
|
||
|
case XK_F34: /* "\033[48~" */
|
||
|
case XK_F35: /* "\033[49~" */
|
||
|
FKEY(31, XK_F17);
|
||
|
break;
|
||
|
#undef FKEY
|
||
|
#ifdef KS_DELETE
|
||
|
case XK_Delete:
|
||
|
len = strlen(strcpy(kbuf, KS_DELETE));
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef META8_OPTION
|
||
|
if (meta && (meta_char == 0x80) && len > 0) {
|
||
|
kbuf[len - 1] |= 0x80;
|
||
|
}
|
||
|
#endif
|
||
|
} else if (ctrl && keysym == XK_minus) {
|
||
|
len = 1;
|
||
|
kbuf[0] = '\037'; /* Ctrl-Minus generates ^_ (31) */
|
||
|
} else {
|
||
|
#ifdef META8_OPTION
|
||
|
/* set 8-bit on */
|
||
|
if (meta && (meta_char == 0x80)) {
|
||
|
|
||
|
unsigned char *ch;
|
||
|
|
||
|
for (ch = kbuf; ch < kbuf + len; ch++)
|
||
|
*ch |= 0x80;
|
||
|
meta = 0;
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef GREEK_SUPPORT
|
||
|
if (greek_mode)
|
||
|
len = greek_xlat(kbuf, len);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (len <= 0)
|
||
|
return; /* not mapped */
|
||
|
|
||
|
/*
|
||
|
* these modifications only affect the static keybuffer
|
||
|
* pass Shift/Control indicators for function keys ending with `~'
|
||
|
*
|
||
|
* eg,
|
||
|
* Prior = "ESC[5~"
|
||
|
* Shift+Prior = "ESC[5~"
|
||
|
* Ctrl+Prior = "ESC[5^"
|
||
|
* Ctrl+Shift+Prior = "ESC[5@"
|
||
|
*/
|
||
|
if (kbuf[0] == '\033' && kbuf[1] == '[' && kbuf[len - 1] == '~')
|
||
|
kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
|
||
|
|
||
|
/* escape prefix */
|
||
|
if (meta
|
||
|
#ifdef META8_OPTION
|
||
|
&& (meta_char == 033)
|
||
|
#endif
|
||
|
) {
|
||
|
|
||
|
const unsigned char ch = '\033';
|
||
|
|
||
|
tt_write(&ch, 1);
|
||
|
}
|
||
|
#if DEBUG >= DEBUG_CMD
|
||
|
if (debug_level >= DEBUG_CMD && debug_key) { /* Display keyboard buffer contents */
|
||
|
|
||
|
char *p;
|
||
|
int i;
|
||
|
|
||
|
fprintf(stderr, "key 0x%04X[%d]: `", (unsigned int) keysym, len);
|
||
|
for (i = 0, p = kbuf; i < len; i++, p++)
|
||
|
fprintf(stderr, (*p >= ' ' && *p < '\177' ? "%c" : "\\%03o"), *p);
|
||
|
fprintf(stderr, "'\n");
|
||
|
}
|
||
|
#endif /* DEBUG_CMD */
|
||
|
tt_write(kbuf, len);
|
||
|
}
|
||
|
|
||
|
#if (MENUBAR_MAX)
|
||
|
|
||
|
/* attempt to `write' COUNT to the input buffer */
|
||
|
unsigned int
|
||
|
cmd_write(const unsigned char *str, unsigned int count)
|
||
|
{
|
||
|
|
||
|
int n;
|
||
|
|
||
|
n = (count - (cmdbuf_ptr - cmdbuf_base));
|
||
|
/* need to insert more chars that space available in the front */
|
||
|
if (n > 0) {
|
||
|
/* try and get more space from the end */
|
||
|
unsigned char *src, *dst;
|
||
|
|
||
|
dst = (cmdbuf_base + sizeof(cmdbuf_base) - 1); /* max pointer */
|
||
|
|
||
|
if ((cmdbuf_ptr + n) > dst)
|
||
|
n = (dst - cmdbuf_ptr); /* max # chars to insert */
|
||
|
|
||
|
if ((cmdbuf_endp + n) > dst)
|
||
|
cmdbuf_endp = (dst - n); /* truncate end if needed */
|
||
|
|
||
|
/* equiv: memmove ((cmdbuf_ptr+n), cmdbuf_ptr, n); */
|
||
|
src = cmdbuf_endp;
|
||
|
dst = src + n;
|
||
|
/* FIXME: anything special to avoid possible pointer wrap? */
|
||
|
while (src >= cmdbuf_ptr)
|
||
|
*dst-- = *src--;
|
||
|
|
||
|
/* done */
|
||
|
cmdbuf_ptr += n;
|
||
|
cmdbuf_endp += n;
|
||
|
}
|
||
|
while (count-- && cmdbuf_ptr > cmdbuf_base) {
|
||
|
/* sneak one in */
|
||
|
cmdbuf_ptr--;
|
||
|
*cmdbuf_ptr = str[count];
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
|
||
|
#ifdef BACKGROUND_CYCLING_SUPPORT
|
||
|
# if RETSIGTYPE != void
|
||
|
# define CPC_RETURN(x) return ((RETSIGTYPE) x)
|
||
|
# else
|
||
|
# define CPC_RETURN(x) return
|
||
|
# endif
|
||
|
|
||
|
RETSIGTYPE
|
||
|
check_pixmap_change(int sig)
|
||
|
{
|
||
|
|
||
|
static time_t last_update = 0;
|
||
|
time_t now;
|
||
|
static unsigned long image_idx = 0;
|
||
|
void (*old_handler) (int);
|
||
|
static unsigned char in_cpc = 0;
|
||
|
|
||
|
if (in_cpc)
|
||
|
CPC_RETURN(0);
|
||
|
in_cpc = 1;
|
||
|
D_PIXMAP(("check_pixmap_change(): rs_anim_delay == %lu seconds, last_update == %lu\n",
|
||
|
rs_anim_delay, last_update));
|
||
|
if (!rs_anim_delay)
|
||
|
CPC_RETURN(0);
|
||
|
if (last_update == 0) {
|
||
|
last_update = time(NULL);
|
||
|
old_handler = signal(SIGALRM, check_pixmap_change);
|
||
|
alarm(rs_anim_delay);
|
||
|
in_cpc = 0;
|
||
|
CPC_RETURN(0);
|
||
|
}
|
||
|
now = time(NULL);
|
||
|
D_PIXMAP(("now %lu >= %lu (last_update %lu + rs_anim_delay %lu) ?\n", now, last_update + rs_anim_delay, last_update, rs_anim_delay));
|
||
|
if (now >= last_update + rs_anim_delay || 1) {
|
||
|
D_PIXMAP(("Time to update pixmap. now == %lu\n", now));
|
||
|
Imlib_destroy_image(imlib_id, imlib_bg.im);
|
||
|
imlib_bg.im = NULL;
|
||
|
xterm_seq(XTerm_Pixmap, rs_anim_pixmaps[image_idx++]);
|
||
|
last_update = now;
|
||
|
old_handler = signal(SIGALRM, check_pixmap_change);
|
||
|
alarm(rs_anim_delay);
|
||
|
if (rs_anim_pixmaps[image_idx] == NULL) {
|
||
|
image_idx = 0;
|
||
|
}
|
||
|
}
|
||
|
in_cpc = 0;
|
||
|
if (old_handler) {
|
||
|
CPC_RETURN((*old_handler) (sig));
|
||
|
} else {
|
||
|
CPC_RETURN(sig);
|
||
|
}
|
||
|
}
|
||
|
#endif /* BACKGROUND_CYCLING_SUPPORT */
|
||
|
|
||
|
/* cmd_getc() - Return next input character */
|
||
|
/*
|
||
|
* Return the next input character after first passing any keyboard input
|
||
|
* to the command.
|
||
|
*/
|
||
|
#define CHARS_READ() (cmdbuf_ptr < cmdbuf_endp)
|
||
|
#define CHARS_BUFFERED() (count != CMD_BUF_SIZE)
|
||
|
#define RETURN_CHAR() do { refreshed = 0; return (*cmdbuf_ptr++); } while (0)
|
||
|
|
||
|
#ifdef REFRESH_DELAY
|
||
|
# define REFRESH_DELAY_USEC 1000000/25
|
||
|
#endif
|
||
|
|
||
|
unsigned char
|
||
|
cmd_getc(void)
|
||
|
{
|
||
|
|
||
|
#define TIMEOUT_USEC 2500
|
||
|
static short refreshed = 0;
|
||
|
fd_set readfds;
|
||
|
int retval;
|
||
|
struct timeval value, *delay;
|
||
|
|
||
|
/* If there has been a lot of new lines, then update the screen
|
||
|
* What the heck I'll cheat and only refresh less than every page-full.
|
||
|
* the number of pages between refreshes is refresh_limit, which
|
||
|
* is incremented here because we must be doing flat-out scrolling.
|
||
|
*
|
||
|
* refreshing should be correct for small scrolls, because of the
|
||
|
* time-out
|
||
|
*/
|
||
|
if (refresh_count >= (refresh_limit * (TermWin.nrow - 1))) {
|
||
|
if (refresh_limit < REFRESH_PERIOD)
|
||
|
refresh_limit++;
|
||
|
refresh_count = 0;
|
||
|
refreshed = 1;
|
||
|
D_CMD(("cmd_getc(): scr_refresh() #1\n"));
|
||
|
#ifdef PROFILE
|
||
|
P_CALL(scr_refresh(refresh_type), "cmd_getc()->scr_refresh()");
|
||
|
#else
|
||
|
scr_refresh(refresh_type);
|
||
|
#endif
|
||
|
}
|
||
|
/* characters already read in */
|
||
|
if (CHARS_READ()) {
|
||
|
RETURN_CHAR();
|
||
|
}
|
||
|
for (;;) {
|
||
|
|
||
|
v_doPending();
|
||
|
while (XPending(Xdisplay)) { /* process pending X events */
|
||
|
|
||
|
XEvent ev;
|
||
|
|
||
|
refreshed = 0;
|
||
|
XNextEvent(Xdisplay, &ev);
|
||
|
|
||
|
#ifndef NO_XLOCALE
|
||
|
if (!XFilterEvent(&ev, ev.xkey.window)) {
|
||
|
D_X11(("cmd_getc(): process_x_event();\n"));
|
||
|
process_x_event(&ev);
|
||
|
}
|
||
|
#else
|
||
|
D_X11(("cmd_getc(): process_x_event();\n"));
|
||
|
process_x_event(&ev);
|
||
|
#endif
|
||
|
|
||
|
/* in case button actions pushed chars to cmdbuf */
|
||
|
if (CHARS_READ()) {
|
||
|
RETURN_CHAR();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
|
||
|
if (scrollbar_isUp()) {
|
||
|
if (!scroll_arrow_delay-- && scr_page(UP, 1)) {
|
||
|
scroll_arrow_delay = SCROLLBAR_CONTINUOUS_DELAY;
|
||
|
refreshed = 0;
|
||
|
/* refresh_type |= SMOOTH_REFRESH; */
|
||
|
}
|
||
|
} else if (scrollbar_isDn()) {
|
||
|
if (!scroll_arrow_delay-- && scr_page(DN, 1)) {
|
||
|
scroll_arrow_delay = SCROLLBAR_CONTINUOUS_DELAY;
|
||
|
refreshed = 0;
|
||
|
/* refresh_type |= SMOOTH_REFRESH; */
|
||
|
}
|
||
|
}
|
||
|
#endif /* SCROLLBAR_BUTTON_CONTINUAL_SCROLLING */
|
||
|
|
||
|
/* Nothing to do! */
|
||
|
FD_ZERO(&readfds);
|
||
|
FD_SET(cmd_fd, &readfds);
|
||
|
FD_SET(Xfd, &readfds);
|
||
|
value.tv_usec = TIMEOUT_USEC;
|
||
|
value.tv_sec = 0;
|
||
|
|
||
|
if (refreshed
|
||
|
#ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
|
||
|
&& !(scrollbar_isUpDn())
|
||
|
#endif
|
||
|
) {
|
||
|
delay = NULL;
|
||
|
} else {
|
||
|
delay = &value;
|
||
|
}
|
||
|
retval = select(num_fds, &readfds, NULL, NULL, delay);
|
||
|
|
||
|
/* See if we can read from the application */
|
||
|
if (FD_ISSET(cmd_fd, &readfds)) {
|
||
|
|
||
|
/* unsigned int count = BUFSIZ; */
|
||
|
register unsigned int count = CMD_BUF_SIZE;
|
||
|
|
||
|
cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
|
||
|
|
||
|
/* while (count > sizeof(cmdbuf_base) / 2) */
|
||
|
while (count) {
|
||
|
|
||
|
/* int n = read(cmd_fd, cmdbuf_endp, count); */
|
||
|
register int n = read(cmd_fd, cmdbuf_endp, count);
|
||
|
|
||
|
if (n <= 0)
|
||
|
break;
|
||
|
cmdbuf_endp += n;
|
||
|
count -= n;
|
||
|
}
|
||
|
/* some characters read in */
|
||
|
if (CHARS_BUFFERED()) {
|
||
|
RETURN_CHAR();
|
||
|
}
|
||
|
}
|
||
|
/* select statement timed out - better update the screen */
|
||
|
|
||
|
if (retval == 0) {
|
||
|
refresh_count = 0;
|
||
|
refresh_limit = 1;
|
||
|
if (!refreshed) {
|
||
|
refreshed = 1;
|
||
|
D_CMD(("cmd_getc(): scr_refresh() #2\n"));
|
||
|
scr_refresh(refresh_type);
|
||
|
if (scrollbar_visible())
|
||
|
scrollbar_show(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
D_CMD(("cmd_getc() returning\n"));
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
#if MENUBAR_MAX
|
||
|
# define XEVENT_IS_MYWIN(ev) (((ev)->xany.window == TermWin.parent) \
|
||
|
|| ((ev)->xany.window == TermWin.vt) \
|
||
|
|| ((ev)->xany.window == menuBar.win) \
|
||
|
|| ((ev)->xany.window == scrollBar.win))
|
||
|
#else
|
||
|
# define XEVENT_IS_MYWIN(ev) (((ev)->xany.window == TermWin.parent) \
|
||
|
|| ((ev)->xany.window == TermWin.vt) \
|
||
|
|| ((ev)->xany.window == scrollBar.win))
|
||
|
#endif
|
||
|
#define XEVENT_IS_PARENT(ev) (((ev)->xany.window == TermWin.wm_parent) \
|
||
|
|| ((ev)->xany.window == TermWin.wm_grandparent))
|
||
|
#define XEVENT_REQUIRE(bool_test) do { if (!(bool_test)) return; } while (0)
|
||
|
|
||
|
void
|
||
|
process_x_event(XEvent * ev)
|
||
|
{
|
||
|
static Time buttonpress_time, lastbutton_press;
|
||
|
static int clicks = 0;
|
||
|
|
||
|
#define clickOnce() (clicks <= 1)
|
||
|
static int bypass_keystate = 0;
|
||
|
int reportmode;
|
||
|
static int mouseoffset = 0; /* Mouse pointer offset info scrollbar anchor */
|
||
|
|
||
|
#ifdef COUNT_X_EVENTS
|
||
|
static long long event_cnt = 0;
|
||
|
static long long keypress_cnt = 0;
|
||
|
static long long motion_cnt = 0;
|
||
|
static long long expose_cnt = 0;
|
||
|
|
||
|
#endif
|
||
|
#ifdef PIXMAP_OFFSET
|
||
|
Atom type;
|
||
|
int format;
|
||
|
unsigned long length, after;
|
||
|
unsigned char *data;
|
||
|
|
||
|
#endif
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
static Time activate_time;
|
||
|
|
||
|
#endif
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
struct timeval expose_start, expose_stop, motion_start, motion_stop, keypress_start, keypress_stop;
|
||
|
static long expose_total = 0;
|
||
|
|
||
|
#endif
|
||
|
#ifdef WATCH_DESKTOP_OPTION
|
||
|
Window new_desktop_window, last_desktop_window = desktop_window;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef COUNT_X_EVENTS
|
||
|
event_cnt++;
|
||
|
D_EVENTS(("total number of events: %ld\n", event_cnt));
|
||
|
#endif
|
||
|
|
||
|
D_EVENTS(("process_x_event(0x%02x): %s, for window 0x%08x\n",
|
||
|
ev->type, event_type_to_name(ev->type), ev->xany.window));
|
||
|
|
||
|
switch (ev->type) {
|
||
|
case KeyPress:
|
||
|
if (keypress_exit)
|
||
|
exit(EXIT_SUCCESS);
|
||
|
D_EVENTS(("process_x_event(%s)\n", "KeyPress"));
|
||
|
#ifdef COUNT_X_EVENTS
|
||
|
keypress_cnt++;
|
||
|
D_EVENTS(("total number of KeyPress events: %ld\n", keypress_cnt));
|
||
|
#endif
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
P_SETTIMEVAL(keypress_start);
|
||
|
#endif
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
lookup_key(ev);
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
P_SETTIMEVAL(keypress_stop);
|
||
|
fprintf(stderr, "KeyPress: %ld microseconds\n",
|
||
|
P_CMPTIMEVALS_USEC(keypress_start, keypress_stop));
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
#ifdef WATCH_DESKTOP_OPTION
|
||
|
case PropertyNotify:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "PropertyNotify"));
|
||
|
if (Options & Opt_pixmapTrans && Options & Opt_watchDesktop) {
|
||
|
if (desktop_window != None) {
|
||
|
XSelectInput(Xdisplay, desktop_window, 0);
|
||
|
} else {
|
||
|
XSelectInput(Xdisplay, Xroot, 0);
|
||
|
}
|
||
|
XGetWindowProperty(Xdisplay, Xroot, ev->xproperty.atom, 0L, 1L, False,
|
||
|
AnyPropertyType, &type, &format, &length, &after, &data);
|
||
|
if (type == XA_PIXMAP) {
|
||
|
if (desktop_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, desktop_pixmap);
|
||
|
desktop_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_expose(0, 0, TermWin_TotalWidth(), TermWin_TotalHeight());
|
||
|
}
|
||
|
if (desktop_window != None) {
|
||
|
XSelectInput(Xdisplay, desktop_window, PropertyChangeMask);
|
||
|
} else {
|
||
|
XSelectInput(Xdisplay, Xroot, PropertyChangeMask);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ReparentNotify:
|
||
|
D_EVENTS(("ReparentNotify: window == 0x%08x, parent == 0x%08x, TermWin.parent == 0x%08x, TermWin.wm_parent == 0x%08x\n",
|
||
|
ev->xreparent.window, ev->xreparent.parent, TermWin.parent, TermWin.wm_parent));
|
||
|
if (Options & Opt_watchDesktop) {
|
||
|
if (ev->xreparent.window == TermWin.parent) {
|
||
|
D_EVENTS(("It's TermWin.parent. Assigning TermWin.wm_parent to 0x%08x\n", ev->xreparent.parent));
|
||
|
if (TermWin.wm_parent != None) {
|
||
|
XSelectInput(Xdisplay, TermWin.wm_parent, None);
|
||
|
}
|
||
|
TermWin.wm_parent = ev->xreparent.parent;
|
||
|
XSelectInput(Xdisplay, TermWin.wm_parent, (StructureNotifyMask | SubstructureNotifyMask));
|
||
|
} else if (ev->xreparent.window == TermWin.wm_parent || ev->xreparent.window == TermWin.wm_grandparent) {
|
||
|
D_EVENTS(("It's my parent! last_desktop_window == 0x%08x, desktop_window == 0x%08x\n",
|
||
|
last_desktop_window, get_desktop_window()));
|
||
|
if (Options & Opt_pixmapTrans && Options & Opt_watchDesktop && get_desktop_window() != last_desktop_window) {
|
||
|
D_EVENTS(("Desktop changed!\n"));
|
||
|
if (desktop_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, desktop_pixmap);
|
||
|
desktop_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_expose(0, 0, TermWin_TotalWidth(), TermWin_TotalHeight());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
case ClientMessage:
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
D_EVENTS(("process_x_event(%s)\n", "ClientMessage"));
|
||
|
if (ev->xclient.format == 32 && ev->xclient.data.l[0] == wmDeleteWindow)
|
||
|
exit(EXIT_SUCCESS);
|
||
|
#ifdef OFFIX_DND
|
||
|
/* OffiX Dnd (drag 'n' drop) protocol */
|
||
|
if (ev->xclient.message_type == DndProtocol &&
|
||
|
((ev->xclient.data.l[0] == DndFile) ||
|
||
|
(ev->xclient.data.l[0] == DndDir) ||
|
||
|
(ev->xclient.data.l[0] == DndLink))) {
|
||
|
/* Get Dnd data */
|
||
|
Atom ActualType;
|
||
|
int ActualFormat;
|
||
|
unsigned char *data;
|
||
|
unsigned long Size, RemainingBytes;
|
||
|
|
||
|
XGetWindowProperty(Xdisplay, Xroot,
|
||
|
DndSelection,
|
||
|
0L, 1000000L,
|
||
|
False, AnyPropertyType,
|
||
|
&ActualType, &ActualFormat,
|
||
|
&Size, &RemainingBytes,
|
||
|
&data);
|
||
|
XChangeProperty(Xdisplay, Xroot,
|
||
|
XA_CUT_BUFFER0, XA_STRING,
|
||
|
8, PropModeReplace,
|
||
|
data, strlen(data));
|
||
|
selection_paste(Xroot, XA_CUT_BUFFER0, True);
|
||
|
XSetInputFocus(Xdisplay, Xroot, RevertToNone, CurrentTime);
|
||
|
}
|
||
|
#endif /* OFFIX_DND */
|
||
|
break;
|
||
|
|
||
|
case MappingNotify:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "MappingNotify"));
|
||
|
XRefreshKeyboardMapping(&(ev->xmapping));
|
||
|
break;
|
||
|
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
case LeaveNotify:
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
tag_hide();
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
/* Here's my conclusion:
|
||
|
* If the window is completely unobscured, use bitblt's
|
||
|
* to scroll. Even then, they're only used when doing partial
|
||
|
* screen scrolling. When partially obscured, we have to fill
|
||
|
* in the GraphicsExpose parts, which means that after each refresh,
|
||
|
* we need to wait for the graphics expose or Noexpose events,
|
||
|
* which ought to make things real slow!
|
||
|
*/
|
||
|
case VisibilityNotify:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "VisibilityNotify"));
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
switch (ev->xvisibility.state) {
|
||
|
case VisibilityUnobscured:
|
||
|
#ifdef USE_SMOOTH_REFRESH
|
||
|
refresh_type = SMOOTH_REFRESH;
|
||
|
#else
|
||
|
refresh_type = FAST_REFRESH;
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case VisibilityPartiallyObscured:
|
||
|
refresh_type = SLOW_REFRESH;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
refresh_type = NO_REFRESH;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case FocusIn:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "FocusIn"));
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
if (!TermWin.focus) {
|
||
|
TermWin.focus = 1;
|
||
|
#ifdef CHANGE_SCROLLCOLOR_ON_FOCUS
|
||
|
menubar_expose();
|
||
|
#endif
|
||
|
if (Options & Opt_scrollbar_popup) {
|
||
|
map_scrollBar(Options & Opt_scrollBar);
|
||
|
}
|
||
|
#ifndef NO_XLOCALE
|
||
|
if (Input_Context != NULL)
|
||
|
XSetICFocus(Input_Context);
|
||
|
#endif
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case FocusOut:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "FocusOut"));
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
if (TermWin.focus) {
|
||
|
TermWin.focus = 0;
|
||
|
#ifdef CHANGE_SCROLLCOLOR_ON_FOCUS
|
||
|
menubar_expose();
|
||
|
#endif
|
||
|
if (Options & Opt_scrollbar_popup) {
|
||
|
map_scrollBar(0);
|
||
|
}
|
||
|
#ifndef NO_XLOCALE
|
||
|
if (Input_Context != NULL)
|
||
|
XUnsetICFocus(Input_Context);
|
||
|
#endif
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ConfigureNotify:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "ConfigureNotify"));
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
#ifdef PIXMAP_OFFSET
|
||
|
if (Options & Opt_pixmapTrans || Options & Opt_viewport_mode) {
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 2);
|
||
|
scr_expose(0, 0, TermWin_TotalWidth(), TermWin_TotalHeight());
|
||
|
}
|
||
|
#endif
|
||
|
resize_window();
|
||
|
menubar_expose();
|
||
|
break;
|
||
|
|
||
|
case SelectionClear:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "SelectionClear"));
|
||
|
selection_clear();
|
||
|
break;
|
||
|
|
||
|
case SelectionNotify:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "SelectionNotify"));
|
||
|
selection_paste(ev->xselection.requestor, ev->xselection.property, True);
|
||
|
break;
|
||
|
|
||
|
case SelectionRequest:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "SelectionRequest"));
|
||
|
selection_send(&(ev->xselectionrequest));
|
||
|
break;
|
||
|
|
||
|
case GraphicsExpose:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "GraphicsExpose"));
|
||
|
case Expose:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "Expose"));
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
P_SETTIMEVAL(expose_start);
|
||
|
#endif
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
if (ev->xany.window == TermWin.vt) {
|
||
|
scr_expose(ev->xexpose.x, ev->xexpose.y, ev->xexpose.width, ev->xexpose.height);
|
||
|
} else {
|
||
|
|
||
|
XEvent unused_xevent;
|
||
|
|
||
|
while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, Expose, &unused_xevent));
|
||
|
while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, GraphicsExpose, &unused_xevent));
|
||
|
if (isScrollbarWindow(ev->xany.window)) {
|
||
|
scrollbar_setNone();
|
||
|
scrollbar_show(0);
|
||
|
}
|
||
|
#if (MENUBAR_MAX)
|
||
|
if (menubar_visible() && isMenuBarWindow(ev->xany.window)) {
|
||
|
menubar_expose();
|
||
|
}
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
Gr_expose(ev->xany.window);
|
||
|
}
|
||
|
#ifdef WATCH_DESKTOP_OPTION
|
||
|
if (Options & Opt_pixmapTrans && Options & Opt_watchDesktop) {
|
||
|
if (desktop_window != None) {
|
||
|
XSelectInput(Xdisplay, desktop_window, PropertyChangeMask);
|
||
|
} else {
|
||
|
XSelectInput(Xdisplay, Xroot, PropertyChangeMask);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
P_SETTIMEVAL(expose_stop);
|
||
|
expose_total += P_CMPTIMEVALS_USEC(expose_start, expose_stop);
|
||
|
fprintf(stderr, "Expose: %ld(%ld) microseconds\n",
|
||
|
P_CMPTIMEVALS_USEC(expose_start, expose_stop),
|
||
|
expose_total);
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case ButtonPress:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "ButtonPress"));
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
if (Options & Opt_borderless) {
|
||
|
XSetInputFocus(Xdisplay, Xroot, RevertToNone, CurrentTime);
|
||
|
}
|
||
|
#if defined(CTRL_CLICK_RAISE) || defined(CTRL_CLICK_SCROLLBAR) || defined(CTRL_CLICK_MENU)
|
||
|
if ((ev->xbutton.state & ControlMask) && (ev->xany.window == TermWin.vt)) {
|
||
|
D_EVENTS(("Checking for Ctrl+Button\n"));
|
||
|
switch (ev->xbutton.button) {
|
||
|
case Button1:
|
||
|
D_EVENTS(("Ctrl+Button1\n"));
|
||
|
# ifdef CTRL_CLICK_RAISE
|
||
|
XSetInputFocus(Xdisplay, TermWin.parent, RevertToParent, CurrentTime);
|
||
|
XRaiseWindow(Xdisplay, TermWin.parent);
|
||
|
/*XWarpPointer(Xdisplay, None, TermWin.vt, 0, 0, 0, 0, TermWin.width/2, TermWin.height/2); */
|
||
|
# endif
|
||
|
break;
|
||
|
case Button2:
|
||
|
D_EVENTS(("Ctrl+Button2\n"));
|
||
|
# ifdef CTRL_CLICK_SCROLLBAR
|
||
|
map_scrollBar(scrollbar_visible()? 0 : 1);
|
||
|
# endif
|
||
|
break;
|
||
|
case Button3:
|
||
|
D_EVENTS(("Ctrl+Button3\n"));
|
||
|
# if defined(CTRL_CLICK_MENU) && (MENUBAR_MAX)
|
||
|
map_menuBar(menubar_visible()? 0 : 1);
|
||
|
# endif
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
#endif /* CTRL_CLICK_RAISE || CTRL_CLICK_MENU */
|
||
|
|
||
|
bypass_keystate = (ev->xbutton.state & (Mod1Mask | ShiftMask));
|
||
|
reportmode = (bypass_keystate ? 0 : (PrivateModes & PrivMode_mouse_report));
|
||
|
|
||
|
if (ev->xany.window == TermWin.vt) {
|
||
|
if (ev->xbutton.subwindow != None) {
|
||
|
Gr_ButtonPress(ev->xbutton.x, ev->xbutton.y);
|
||
|
} else {
|
||
|
if (reportmode) {
|
||
|
if (reportmode & PrivMode_MouseX10) {
|
||
|
/* no state info allowed */
|
||
|
ev->xbutton.state = 0;
|
||
|
}
|
||
|
#ifdef MOUSE_REPORT_DOUBLECLICK
|
||
|
if (ev->xbutton.button == Button1) {
|
||
|
if (ev->xbutton.time - buttonpress_time < MULTICLICK_TIME)
|
||
|
clicks++;
|
||
|
else
|
||
|
clicks = 1;
|
||
|
}
|
||
|
#else
|
||
|
clicks = 1;
|
||
|
#endif /* MOUSE_REPORT_DOUBLECLICK */
|
||
|
mouse_report(&(ev->xbutton));
|
||
|
} else {
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
if (tag_click(ev->xbutton.x, ev->xbutton.y, ev->xbutton.button, ev->xkey.state))
|
||
|
activate_time = ev->xbutton.time;
|
||
|
else
|
||
|
#endif
|
||
|
switch (ev->xbutton.button) {
|
||
|
case Button1:
|
||
|
if (lastbutton_press == 1
|
||
|
&& (ev->xbutton.time - buttonpress_time < MULTICLICK_TIME))
|
||
|
clicks++;
|
||
|
else
|
||
|
clicks = 1;
|
||
|
selection_click(clicks, ev->xbutton.x, ev->xbutton.y);
|
||
|
lastbutton_press = 1;
|
||
|
break;
|
||
|
|
||
|
case Button3:
|
||
|
if (lastbutton_press == 3
|
||
|
&& (ev->xbutton.time - buttonpress_time < MULTICLICK_TIME))
|
||
|
selection_rotate(ev->xbutton.x, ev->xbutton.y);
|
||
|
else
|
||
|
selection_extend(ev->xbutton.x, ev->xbutton.y, 1);
|
||
|
lastbutton_press = 3;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
buttonpress_time = ev->xbutton.time;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
if ((isScrollbarWindow(ev->xany.window))
|
||
|
|| (scrollbar_upButtonWin(ev->xany.window))
|
||
|
|| (scrollbar_dnButtonWin(ev->xany.window)))
|
||
|
#else
|
||
|
if (isScrollbarWindow(ev->xany.window))
|
||
|
#endif
|
||
|
{
|
||
|
scrollbar_setNone();
|
||
|
/*
|
||
|
* Eterm-style scrollbar:
|
||
|
* move up if mouse is above slider
|
||
|
* move dn if mouse is below slider
|
||
|
*
|
||
|
* XTerm-style scrollbar:
|
||
|
* Move display proportional to pointer location
|
||
|
* pointer near top -> scroll one line
|
||
|
* pointer near bot -> scroll full page
|
||
|
*/
|
||
|
#ifndef NO_SCROLLBAR_REPORT
|
||
|
if (reportmode) {
|
||
|
/*
|
||
|
* Mouse report disabled scrollbar:
|
||
|
* arrow buttons - send up/down
|
||
|
* click on scrollbar - send pageup/down
|
||
|
*/
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
if ((scrollbar_upButtonWin(ev->xany.window))
|
||
|
|| (!(scrollbar_is_pixmapped()) &&
|
||
|
(scrollbar_upButton(ev->xbutton.y))))
|
||
|
#else
|
||
|
if (scrollbar_upButton(ev->xbutton.y))
|
||
|
#endif
|
||
|
tt_printf("\033[A");
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
else if ((scrollbar_dnButtonWin(ev->xany.window))
|
||
|
|| (!(scrollbar_is_pixmapped()) &&
|
||
|
(scrollbar_upButton(ev->xbutton.y))))
|
||
|
#else
|
||
|
else if (scrollbar_dnButton(ev->xbutton.y))
|
||
|
#endif
|
||
|
tt_printf("\033[B");
|
||
|
else
|
||
|
switch (ev->xbutton.button) {
|
||
|
case Button2:
|
||
|
tt_printf("\014");
|
||
|
break;
|
||
|
case Button1:
|
||
|
tt_printf("\033[6~");
|
||
|
break;
|
||
|
case Button3:
|
||
|
tt_printf("\033[5~");
|
||
|
break;
|
||
|
}
|
||
|
} else
|
||
|
#endif /* NO_SCROLLBAR_REPORT */
|
||
|
{
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
if ((scrollbar_upButtonWin(ev->xany.window))
|
||
|
|| (!(scrollbar_is_pixmapped()) &&
|
||
|
(scrollbar_upButton(ev->xbutton.y))))
|
||
|
#else
|
||
|
if (scrollbar_upButton(ev->xbutton.y))
|
||
|
#endif
|
||
|
{
|
||
|
#ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
|
||
|
scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
|
||
|
#endif
|
||
|
if (scr_page(UP, 1)) {
|
||
|
scrollbar_setUp();
|
||
|
}
|
||
|
} else if
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
((scrollbar_dnButtonWin(ev->xany.window))
|
||
|
|| (!(scrollbar_is_pixmapped())
|
||
|
&& (scrollbar_dnButton(ev->xbutton.y))))
|
||
|
#else
|
||
|
(scrollbar_dnButton(ev->xbutton.y))
|
||
|
#endif
|
||
|
{
|
||
|
#ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
|
||
|
scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
|
||
|
#endif
|
||
|
if (scr_page(DN, 1)) {
|
||
|
scrollbar_setDn();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
switch (ev->xbutton.button) {
|
||
|
case Button2:
|
||
|
mouseoffset = (scrollBar.bot - scrollBar.top) / 2; /* Align to center */
|
||
|
if (scrollbar_above_slider(ev->xbutton.y) || scrollbar_below_slider(ev->xbutton.y)
|
||
|
|| scrollBar.type == SCROLLBAR_XTERM) {
|
||
|
scr_move_to(scrollbar_position(ev->xbutton.y) - mouseoffset,
|
||
|
scrollbar_size());
|
||
|
}
|
||
|
scrollbar_setMotion();
|
||
|
break;
|
||
|
|
||
|
case Button1:
|
||
|
mouseoffset = ev->xbutton.y - scrollBar.top;
|
||
|
MAX_IT(mouseoffset, 1);
|
||
|
/* drop */
|
||
|
case Button3:
|
||
|
#if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR)
|
||
|
if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) {
|
||
|
# ifdef PIXMAP_SCROLLBAR
|
||
|
if (!(ev->xany.window == scrollBar.sa_win)
|
||
|
&& (scrollbar_above_slider(ev->xbutton.y)))
|
||
|
# else
|
||
|
if (scrollbar_above_slider(ev->xbutton.y))
|
||
|
# endif
|
||
|
scr_page(UP, TermWin.nrow - 1);
|
||
|
# ifdef PIXMAP_SCROLLBAR
|
||
|
else if (!(ev->xany.window == scrollBar.sa_win)
|
||
|
&& (scrollbar_below_slider(ev->xbutton.y)))
|
||
|
# else
|
||
|
else
|
||
|
if (scrollbar_below_slider(ev->xbutton.y))
|
||
|
# endif
|
||
|
scr_page(DN, TermWin.nrow - 1);
|
||
|
else
|
||
|
scrollbar_setMotion();
|
||
|
}
|
||
|
#endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */
|
||
|
|
||
|
#ifdef XTERM_SCROLLBAR
|
||
|
if (scrollBar.type == SCROLLBAR_XTERM) {
|
||
|
scr_page((ev->xbutton.button == Button1 ? DN : UP),
|
||
|
(TermWin.nrow *
|
||
|
scrollbar_position(ev->xbutton.y) /
|
||
|
scrollbar_size())
|
||
|
);
|
||
|
}
|
||
|
#endif /* XTERM_SCROLLBAR */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
#if (MENUBAR_MAX)
|
||
|
if (isMenuBarWindow(ev->xany.window)) {
|
||
|
menubar_control(&(ev->xbutton));
|
||
|
return;
|
||
|
}
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
break;
|
||
|
|
||
|
case ButtonRelease:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "ButtonRelease"));
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
mouseoffset = 0;
|
||
|
reportmode = (bypass_keystate ?
|
||
|
0 : (PrivateModes & PrivMode_mouse_report));
|
||
|
|
||
|
if (scrollbar_isUpDn()) {
|
||
|
scrollbar_setNone();
|
||
|
scrollbar_show(0);
|
||
|
#ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
|
||
|
/* refresh_type &= ~SMOOTH_REFRESH; */
|
||
|
#endif
|
||
|
}
|
||
|
if (ev->xany.window == TermWin.vt) {
|
||
|
if (ev->xbutton.subwindow != None)
|
||
|
Gr_ButtonRelease(ev->xbutton.x, ev->xbutton.y);
|
||
|
else {
|
||
|
if (reportmode) {
|
||
|
switch (reportmode & PrivMode_mouse_report) {
|
||
|
case PrivMode_MouseX10:
|
||
|
break;
|
||
|
|
||
|
case PrivMode_MouseX11:
|
||
|
ev->xbutton.state = bypass_keystate;
|
||
|
ev->xbutton.button = AnyButton;
|
||
|
mouse_report(&(ev->xbutton));
|
||
|
break;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
/*
|
||
|
* dumb hack to compensate for the failure of click-and-drag
|
||
|
* when overriding mouse reporting
|
||
|
*/
|
||
|
if ((PrivateModes & PrivMode_mouse_report) &&
|
||
|
(bypass_keystate) &&
|
||
|
(ev->xbutton.button == Button1) &&
|
||
|
(clickOnce()))
|
||
|
selection_extend(ev->xbutton.x, ev->xbutton.y, 0);
|
||
|
|
||
|
switch (ev->xbutton.button) {
|
||
|
case Button1:
|
||
|
case Button3:
|
||
|
#if defined(CTRL_CLICK_RAISE) || defined(CTRL_CLICK_MENU)
|
||
|
if (!(ev->xbutton.state & ControlMask))
|
||
|
#endif
|
||
|
selection_make(ev->xbutton.time);
|
||
|
break;
|
||
|
|
||
|
case Button2:
|
||
|
#ifdef CTRL_CLICK_SCROLLBAR
|
||
|
if (!(ev->xbutton.state & ControlMask))
|
||
|
#endif
|
||
|
selection_request(ev->xbutton.time, ev->xbutton.x, ev->xbutton.y);
|
||
|
break;
|
||
|
case Button4:
|
||
|
scr_page(UP, (ev->xbutton.state & ShiftMask) ? 1 : 5);
|
||
|
break;
|
||
|
case Button5:
|
||
|
scr_page(DN, (ev->xbutton.state & ShiftMask) ? 1 : 5);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#if (MENUBAR_MAX)
|
||
|
else if (isMenuBarWindow(ev->xany.window)) {
|
||
|
menubar_control(&(ev->xbutton));
|
||
|
}
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
break;
|
||
|
|
||
|
case MotionNotify:
|
||
|
D_EVENTS(("process_x_event(%s)\n", "MotionNotify"));
|
||
|
#ifdef COUNT_X_EVENTS
|
||
|
motion_cnt++;
|
||
|
D_EVENTS(("total number of MotionNotify events: %ld\n", motion_cnt));
|
||
|
#endif
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
P_SETTIMEVAL(motion_start);
|
||
|
#endif
|
||
|
XEVENT_REQUIRE(XEVENT_IS_MYWIN(ev));
|
||
|
#if (MENUBAR_MAX)
|
||
|
if (isMenuBarWindow(ev->xany.window)) {
|
||
|
menubar_control(&(ev->xbutton));
|
||
|
break;
|
||
|
}
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
if ((PrivateModes & PrivMode_mouse_report) && !(bypass_keystate))
|
||
|
break;
|
||
|
|
||
|
if (ev->xany.window == TermWin.vt) {
|
||
|
if ((ev->xbutton.state & (Button1Mask | Button3Mask))
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
&& ((ev->xmotion.time - activate_time) > TAG_DRAG_THRESHHOLD)
|
||
|
#endif
|
||
|
) {
|
||
|
Window unused_root, unused_child;
|
||
|
int unused_root_x, unused_root_y;
|
||
|
unsigned int unused_mask;
|
||
|
|
||
|
while (XCheckTypedWindowEvent(Xdisplay, TermWin.vt,
|
||
|
MotionNotify, ev));
|
||
|
XQueryPointer(Xdisplay, TermWin.vt,
|
||
|
&unused_root, &unused_child,
|
||
|
&unused_root_x, &unused_root_y,
|
||
|
&(ev->xbutton.x), &(ev->xbutton.y),
|
||
|
&unused_mask);
|
||
|
#ifdef MOUSE_THRESHOLD
|
||
|
/* deal with a `jumpy' mouse */
|
||
|
if ((ev->xmotion.time - buttonpress_time) > MOUSE_THRESHOLD)
|
||
|
#endif
|
||
|
selection_extend((ev->xbutton.x), (ev->xbutton.y),
|
||
|
(ev->xbutton.state & Button3Mask));
|
||
|
}
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
else
|
||
|
tag_pointer_new_position(ev->xbutton.x, ev->xbutton.y);
|
||
|
#endif
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
} else if ((scrollbar_is_pixmapped()) && (ev->xany.window == scrollBar.sa_win) && scrollbar_isMotion()) {
|
||
|
|
||
|
Window unused_root, unused_child;
|
||
|
int unused_root_x, unused_root_y;
|
||
|
unsigned int unused_mask;
|
||
|
|
||
|
/* FIXME: I guess pointer or server should be grabbed here
|
||
|
* or something like that :) -vendu
|
||
|
*/
|
||
|
|
||
|
while (XCheckTypedWindowEvent(Xdisplay, scrollBar.sa_win,
|
||
|
MotionNotify, ev));
|
||
|
|
||
|
XQueryPointer(Xdisplay, scrollBar.sa_win,
|
||
|
&unused_root, &unused_child,
|
||
|
&unused_root_x, &unused_root_y,
|
||
|
&(ev->xbutton.x), &(ev->xbutton.y),
|
||
|
&unused_mask);
|
||
|
|
||
|
scr_move_to(scrollbar_position(ev->xbutton.y) - mouseoffset,
|
||
|
scrollbar_size());
|
||
|
refresh_count = refresh_limit = 0;
|
||
|
scr_refresh(refresh_type);
|
||
|
scrollbar_show(mouseoffset);
|
||
|
#endif
|
||
|
} else if ((ev->xany.window == scrollBar.win) && scrollbar_isMotion()) {
|
||
|
Window unused_root, unused_child;
|
||
|
int unused_root_x, unused_root_y;
|
||
|
unsigned int unused_mask;
|
||
|
|
||
|
while (XCheckTypedWindowEvent(Xdisplay, scrollBar.win, MotionNotify, ev));
|
||
|
XQueryPointer(Xdisplay, scrollBar.win,
|
||
|
&unused_root, &unused_child,
|
||
|
&unused_root_x, &unused_root_y,
|
||
|
&(ev->xbutton.x), &(ev->xbutton.y),
|
||
|
&unused_mask);
|
||
|
scr_move_to(scrollbar_position(ev->xbutton.y) - mouseoffset,
|
||
|
scrollbar_size());
|
||
|
refresh_count = refresh_limit = 0;
|
||
|
scr_refresh(refresh_type);
|
||
|
scrollbar_show(mouseoffset);
|
||
|
}
|
||
|
#ifdef PROFILE_X_EVENTS
|
||
|
P_SETTIMEVAL(motion_stop);
|
||
|
fprintf(stderr, "MotionNotify: %ld microseconds\n",
|
||
|
P_CMPTIMEVALS_USEC(motion_start, motion_stop));
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* tt_write(), tt_printf() - output to command */
|
||
|
/*
|
||
|
* Send count characters directly to the command
|
||
|
*/
|
||
|
void
|
||
|
tt_write(const unsigned char *buf, unsigned int count)
|
||
|
{
|
||
|
|
||
|
v_writeBig(cmd_fd, (char *) buf, count);
|
||
|
|
||
|
#if 0 /* Fixes the bug that hung Eterm when pasting a lot of stuff */
|
||
|
while (count > 0) {
|
||
|
int n = write(cmd_fd, buf, count);
|
||
|
|
||
|
if (n > 0) {
|
||
|
count -= n;
|
||
|
buf += n;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Send printf() formatted output to the command.
|
||
|
* Only use for small ammounts of data.
|
||
|
*/
|
||
|
void
|
||
|
tt_printf(const unsigned char *fmt,...)
|
||
|
{
|
||
|
static unsigned char buf[256];
|
||
|
va_list arg_ptr;
|
||
|
|
||
|
va_start(arg_ptr, fmt);
|
||
|
vsprintf(buf, fmt, arg_ptr);
|
||
|
va_end(arg_ptr);
|
||
|
tt_write(buf, strlen(buf));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* print pipe */
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
#ifdef PRINTPIPE
|
||
|
/* PROTO */
|
||
|
FILE *
|
||
|
popen_printer(void)
|
||
|
{
|
||
|
FILE *stream = popen(rs_print_pipe, "w");
|
||
|
|
||
|
if (stream == NULL)
|
||
|
print_error("can't open printer pipe \"%s\" -- %s", rs_print_pipe, strerror(errno));
|
||
|
return stream;
|
||
|
}
|
||
|
|
||
|
/* PROTO */
|
||
|
int
|
||
|
pclose_printer(FILE * stream)
|
||
|
{
|
||
|
fflush(stream);
|
||
|
/* pclose() reported not to work on SunOS 4.1.3 */
|
||
|
# if defined (__sun__)
|
||
|
/* pclose works provided SIGCHLD handler uses waitpid */
|
||
|
return pclose(stream); /* return fclose (stream); */
|
||
|
# else
|
||
|
return pclose(stream);
|
||
|
# endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* simulate attached vt100 printer
|
||
|
*/
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_print_pipe(void)
|
||
|
{
|
||
|
const char *const escape_seq = "\033[4i";
|
||
|
const char *const rev_escape_seq = "i4[\033";
|
||
|
int index;
|
||
|
FILE *fd;
|
||
|
|
||
|
if ((fd = popen_printer()) != NULL) {
|
||
|
for (index = 0; index < 4; /* nil */ ) {
|
||
|
unsigned char ch = cmd_getc();
|
||
|
|
||
|
if (ch == escape_seq[index])
|
||
|
index++;
|
||
|
else if (index)
|
||
|
for ( /*nil */ ; index > 0; index--)
|
||
|
fputc(rev_escape_seq[index - 1], fd);
|
||
|
|
||
|
if (index == 0)
|
||
|
fputc(ch, fd);
|
||
|
}
|
||
|
pclose_printer(fd);
|
||
|
}
|
||
|
}
|
||
|
#endif /* PRINTPIPE */
|
||
|
|
||
|
/* process escape sequences */
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_escape_seq(void)
|
||
|
{
|
||
|
unsigned char ch = cmd_getc();
|
||
|
|
||
|
switch (ch) {
|
||
|
/* case 1: do_tek_mode (); break; */
|
||
|
case '#':
|
||
|
if (cmd_getc() == '8')
|
||
|
scr_E();
|
||
|
break;
|
||
|
case '(':
|
||
|
scr_charset_set(0, cmd_getc());
|
||
|
break;
|
||
|
case ')':
|
||
|
scr_charset_set(1, cmd_getc());
|
||
|
break;
|
||
|
case '*':
|
||
|
scr_charset_set(2, cmd_getc());
|
||
|
break;
|
||
|
case '+':
|
||
|
scr_charset_set(3, cmd_getc());
|
||
|
break;
|
||
|
#ifdef KANJI
|
||
|
case '$':
|
||
|
scr_charset_set(-2, cmd_getc());
|
||
|
break;
|
||
|
#endif
|
||
|
case '7':
|
||
|
scr_cursor(SAVE);
|
||
|
break;
|
||
|
case '8':
|
||
|
scr_cursor(RESTORE);
|
||
|
break;
|
||
|
case '=':
|
||
|
case '>':
|
||
|
PrivMode((ch == '='), PrivMode_aplKP);
|
||
|
break;
|
||
|
case '@':
|
||
|
(void) cmd_getc();
|
||
|
break;
|
||
|
case 'D':
|
||
|
scr_index(UP);
|
||
|
break;
|
||
|
case 'E':
|
||
|
scr_add_lines("\n\r", 1, 2);
|
||
|
break;
|
||
|
case 'G':
|
||
|
process_graphics();
|
||
|
break;
|
||
|
case 'H':
|
||
|
scr_set_tab(1);
|
||
|
break;
|
||
|
case 'M':
|
||
|
scr_index(DN);
|
||
|
break;
|
||
|
/*case 'N': scr_single_shift (2); break; */
|
||
|
/*case 'O': scr_single_shift (3); break; */
|
||
|
case 'Z':
|
||
|
tt_printf(ESCZ_ANSWER);
|
||
|
break; /* steal obsolete ESC [ c */
|
||
|
case '[':
|
||
|
process_csi_seq();
|
||
|
break;
|
||
|
case ']':
|
||
|
process_xterm_seq();
|
||
|
break;
|
||
|
case 'c':
|
||
|
scr_poweron();
|
||
|
break;
|
||
|
case 'n':
|
||
|
scr_charset_choose(2);
|
||
|
break;
|
||
|
case 'o':
|
||
|
scr_charset_choose(3);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* process CSI (code sequence introducer) sequences `ESC[' */
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_csi_seq(void)
|
||
|
{
|
||
|
|
||
|
unsigned char ch, priv;
|
||
|
unsigned int nargs;
|
||
|
int arg[ESC_ARGS];
|
||
|
|
||
|
nargs = 0;
|
||
|
arg[0] = 0;
|
||
|
arg[1] = 0;
|
||
|
|
||
|
priv = 0;
|
||
|
ch = cmd_getc();
|
||
|
if (ch >= '<' && ch <= '?') {
|
||
|
priv = ch;
|
||
|
ch = cmd_getc();
|
||
|
}
|
||
|
/* read any numerical arguments */
|
||
|
do {
|
||
|
int n;
|
||
|
|
||
|
for (n = 0; isdigit(ch); ch = cmd_getc())
|
||
|
n = n * 10 + (ch - '0');
|
||
|
|
||
|
if (nargs < ESC_ARGS)
|
||
|
arg[nargs++] = n;
|
||
|
if (ch == '\b') {
|
||
|
scr_backspace();
|
||
|
} else if (ch == 033) {
|
||
|
process_escape_seq();
|
||
|
return;
|
||
|
} else if (ch < ' ') {
|
||
|
scr_add_lines(&ch, 0, 1);
|
||
|
return;
|
||
|
}
|
||
|
if (ch < '@')
|
||
|
ch = cmd_getc();
|
||
|
}
|
||
|
while (ch >= ' ' && ch < '@');
|
||
|
if (ch == 033) {
|
||
|
process_escape_seq();
|
||
|
return;
|
||
|
} else if (ch < ' ')
|
||
|
return;
|
||
|
|
||
|
switch (ch) {
|
||
|
#ifdef PRINTPIPE
|
||
|
case 'i': /* printing */
|
||
|
switch (arg[0]) {
|
||
|
case 0:
|
||
|
scr_printscreen(0);
|
||
|
break;
|
||
|
case 5:
|
||
|
process_print_pipe();
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
case 'A':
|
||
|
case 'e': /* up <n> */
|
||
|
scr_gotorc((arg[0] ? -arg[0] : -1), 0, RELATIVE);
|
||
|
break;
|
||
|
case 'B': /* down <n> */
|
||
|
scr_gotorc((arg[0] ? +arg[0] : +1), 0, RELATIVE);
|
||
|
break;
|
||
|
case 'C':
|
||
|
case 'a': /* right <n> */
|
||
|
scr_gotorc(0, (arg[0] ? +arg[0] : +1), RELATIVE);
|
||
|
break;
|
||
|
case 'D': /* left <n> */
|
||
|
scr_gotorc(0, (arg[0] ? -arg[0] : -1), RELATIVE);
|
||
|
break;
|
||
|
case 'E': /* down <n> & to first column */
|
||
|
scr_gotorc((arg[0] ? +arg[0] : +1), 0, R_RELATIVE);
|
||
|
break;
|
||
|
case 'F': /* up <n> & to first column */
|
||
|
scr_gotorc((arg[0] ? -arg[0] : -1), 0, R_RELATIVE);
|
||
|
break;
|
||
|
case 'G':
|
||
|
case '`': /* move to col <n> */
|
||
|
scr_gotorc(0, (arg[0] ? arg[0] - 1 : +1), R_RELATIVE);
|
||
|
break;
|
||
|
case 'd': /* move to row <n> */
|
||
|
scr_gotorc((arg[0] ? arg[0] - 1 : +1), 0, C_RELATIVE);
|
||
|
break;
|
||
|
case 'H':
|
||
|
case 'f': /* position cursor */
|
||
|
switch (nargs) {
|
||
|
case 0:
|
||
|
scr_gotorc(0, 0, 0);
|
||
|
break;
|
||
|
case 1:
|
||
|
scr_gotorc((arg[0] ? arg[0] - 1 : 0), 0, 0);
|
||
|
break;
|
||
|
default:
|
||
|
scr_gotorc(arg[0] - 1, arg[1] - 1, 0);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'I':
|
||
|
scr_tab(arg[0] ? +arg[0] : +1);
|
||
|
break;
|
||
|
case 'Z':
|
||
|
scr_tab(arg[0] ? -arg[0] : -1);
|
||
|
break;
|
||
|
case 'J':
|
||
|
scr_erase_screen(arg[0]);
|
||
|
break;
|
||
|
case 'K':
|
||
|
scr_erase_line(arg[0]);
|
||
|
break;
|
||
|
case '@':
|
||
|
scr_insdel_chars((arg[0] ? arg[0] : 1), INSERT);
|
||
|
break;
|
||
|
case 'L':
|
||
|
scr_insdel_lines((arg[0] ? arg[0] : 1), INSERT);
|
||
|
break;
|
||
|
case 'M':
|
||
|
scr_insdel_lines((arg[0] ? arg[0] : 1), DELETE);
|
||
|
break;
|
||
|
case 'X':
|
||
|
scr_insdel_chars((arg[0] ? arg[0] : 1), ERASE);
|
||
|
break;
|
||
|
case 'P':
|
||
|
scr_insdel_chars((arg[0] ? arg[0] : 1), DELETE);
|
||
|
break;
|
||
|
|
||
|
case 'c':
|
||
|
#ifndef NO_VT100_ANS
|
||
|
tt_printf(VT100_ANS);
|
||
|
#endif
|
||
|
break;
|
||
|
case 'm':
|
||
|
process_sgr_mode(nargs, arg);
|
||
|
break;
|
||
|
case 'n': /* request for information */
|
||
|
switch (arg[0]) {
|
||
|
case 5:
|
||
|
tt_printf("\033[0n");
|
||
|
break; /* ready */
|
||
|
case 6:
|
||
|
scr_report_position();
|
||
|
break;
|
||
|
#if defined (ENABLE_DISPLAY_ANSWER)
|
||
|
case 7:
|
||
|
tt_printf("%s\n", display_name);
|
||
|
break;
|
||
|
#endif
|
||
|
case 8:
|
||
|
xterm_seq(XTerm_title, APL_NAME "-" VERSION);
|
||
|
break;
|
||
|
case 9:
|
||
|
#ifdef PIXMAP_OFFSET
|
||
|
if (Options & Opt_pixmapTrans) {
|
||
|
char tbuff[70];
|
||
|
|
||
|
snprintf(tbuff, sizeof(tbuff), APL_NAME "-" VERSION ": Transparent - %d%% shading - 0x%06x tint mask",
|
||
|
rs_shadePct, rs_tintMask);
|
||
|
xterm_seq(XTerm_title, tbuff);
|
||
|
} else
|
||
|
#endif
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
{
|
||
|
char *tbuff;
|
||
|
unsigned short len;
|
||
|
|
||
|
if (imlib_bg.im) {
|
||
|
len = strlen(imlib_bg.im->filename) + sizeof(APL_NAME) + sizeof(VERSION) + 5;
|
||
|
tbuff = MALLOC(len);
|
||
|
snprintf(tbuff, len, APL_NAME "-" VERSION ": %s", imlib_bg.im->filename);
|
||
|
xterm_seq(XTerm_title, tbuff);
|
||
|
FREE(tbuff);
|
||
|
} else {
|
||
|
xterm_seq(XTerm_title, APL_NAME "-" VERSION ": No Pixmap");
|
||
|
}
|
||
|
}
|
||
|
#endif /* PIXMAP_SUPPORT */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'r': /* set top and bottom margins */
|
||
|
if (priv != '?') {
|
||
|
if (nargs < 2 || arg[0] >= arg[1])
|
||
|
scr_scroll_region(0, 10000);
|
||
|
else
|
||
|
scr_scroll_region(arg[0] - 1, arg[1] - 1);
|
||
|
break;
|
||
|
}
|
||
|
/* drop */
|
||
|
case 't':
|
||
|
if (priv != '?') {
|
||
|
process_window_mode(nargs, arg);
|
||
|
break;
|
||
|
}
|
||
|
/* drop */
|
||
|
case 's':
|
||
|
case 'h':
|
||
|
case 'l':
|
||
|
process_terminal_mode(ch, priv, nargs, arg);
|
||
|
break;
|
||
|
case 'g':
|
||
|
switch (arg[0]) {
|
||
|
case 0:
|
||
|
scr_set_tab(0);
|
||
|
break; /* delete tab */
|
||
|
case 3:
|
||
|
scr_set_tab(-1);
|
||
|
break; /* clear all tabs */
|
||
|
}
|
||
|
break;
|
||
|
case 'W':
|
||
|
switch (arg[0]) {
|
||
|
case 0:
|
||
|
scr_set_tab(1);
|
||
|
break; /* = ESC H */
|
||
|
case 2:
|
||
|
scr_set_tab(0);
|
||
|
break; /* = ESC [ 0 g */
|
||
|
case 5:
|
||
|
scr_set_tab(-1);
|
||
|
break; /* = ESC [ 3 g */
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* process xterm text parameters sequences `ESC ] Ps ; Pt BEL' */
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_xterm_seq(void)
|
||
|
{
|
||
|
unsigned char ch, string[STRING_MAX];
|
||
|
int arg;
|
||
|
|
||
|
ch = cmd_getc();
|
||
|
if (isdigit(ch)) {
|
||
|
for (arg = 0; isdigit(ch); ch = cmd_getc()) {
|
||
|
arg = arg * 10 + (ch - '0');
|
||
|
}
|
||
|
} else if (ch == ';') {
|
||
|
arg = 0;
|
||
|
} else {
|
||
|
arg = ch;
|
||
|
ch = cmd_getc();
|
||
|
}
|
||
|
if (ch == ';') {
|
||
|
int n = 0;
|
||
|
|
||
|
while ((ch = cmd_getc()) != 007) {
|
||
|
if (ch) {
|
||
|
if (ch == '\t')
|
||
|
ch = ' '; /* translate '\t' to space */
|
||
|
else if (ch < ' ')
|
||
|
return; /* control character - exit */
|
||
|
|
||
|
if (n < sizeof(string) - 1)
|
||
|
string[n++] = ch;
|
||
|
}
|
||
|
}
|
||
|
string[n] = '\0';
|
||
|
|
||
|
/*
|
||
|
* menubar_dispatch() violates the constness of the string,
|
||
|
* so do it here
|
||
|
*/
|
||
|
if (arg == XTerm_Menu)
|
||
|
menubar_dispatch(string);
|
||
|
else
|
||
|
xterm_seq(arg, string);
|
||
|
} else {
|
||
|
int n = 0;
|
||
|
|
||
|
for (; ch != '\e'; ch = cmd_getc()) {
|
||
|
if (ch) {
|
||
|
if (ch == '\t')
|
||
|
ch = ' '; /* translate '\t' to space */
|
||
|
else if (ch < ' ')
|
||
|
return; /* control character - exit */
|
||
|
|
||
|
if (n < sizeof(string) - 1)
|
||
|
string[n++] = ch;
|
||
|
}
|
||
|
}
|
||
|
string[n] = '\0';
|
||
|
|
||
|
if ((ch = cmd_getc()) != '\\') {
|
||
|
return;
|
||
|
}
|
||
|
switch (arg) {
|
||
|
case 'l':
|
||
|
xterm_seq(XTerm_title, string);
|
||
|
break;
|
||
|
case 'L':
|
||
|
xterm_seq(XTerm_iconName, string);
|
||
|
break;
|
||
|
case 'I':
|
||
|
set_icon_pixmap(string, NULL);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Process window manipulations */
|
||
|
void
|
||
|
process_window_mode(unsigned int nargs, int args[])
|
||
|
{
|
||
|
|
||
|
register unsigned int i;
|
||
|
unsigned int x, y;
|
||
|
Screen *scr;
|
||
|
Window dummy_child;
|
||
|
char buff[128], *name;
|
||
|
|
||
|
if (!nargs)
|
||
|
return;
|
||
|
scr = ScreenOfDisplay(Xdisplay, Xscreen);
|
||
|
if (!scr)
|
||
|
return;
|
||
|
|
||
|
for (i = 0; i < nargs; i++) {
|
||
|
if (args[i] == 14) {
|
||
|
int dummy_x, dummy_y;
|
||
|
unsigned int dummy_border, dummy_depth;
|
||
|
|
||
|
/* Store current width and height in x and y */
|
||
|
XGetGeometry(Xdisplay, TermWin.parent, &dummy_child, &dummy_x, &dummy_y, &x, &y, &dummy_border, &dummy_depth);
|
||
|
}
|
||
|
switch (args[i]) {
|
||
|
case 1:
|
||
|
XRaiseWindow(Xdisplay, TermWin.parent);
|
||
|
break;
|
||
|
case 2:
|
||
|
XIconifyWindow(Xdisplay, TermWin.parent, Xscreen);
|
||
|
break;
|
||
|
case 3:
|
||
|
if (i + 2 >= nargs)
|
||
|
return; /* Make sure there are 2 args left */
|
||
|
x = args[++i];
|
||
|
y = args[++i];
|
||
|
if (x > scr->width || y > scr->height)
|
||
|
return; /* Don't move off-screen */
|
||
|
XMoveWindow(Xdisplay, TermWin.parent, x, y);
|
||
|
break;
|
||
|
case 4:
|
||
|
if (i + 2 >= nargs)
|
||
|
return; /* Make sure there are 2 args left */
|
||
|
y = args[++i];
|
||
|
x = args[++i];
|
||
|
XResizeWindow(Xdisplay, TermWin.parent, x, y);
|
||
|
break;
|
||
|
case 5:
|
||
|
XRaiseWindow(Xdisplay, TermWin.parent);
|
||
|
break;
|
||
|
case 6:
|
||
|
XLowerWindow(Xdisplay, TermWin.parent);
|
||
|
break;
|
||
|
case 7:
|
||
|
XClearWindow(Xdisplay, TermWin.vt);
|
||
|
XSync(Xdisplay, False);
|
||
|
scr_touch();
|
||
|
scr_refresh(SMOOTH_REFRESH);
|
||
|
break;
|
||
|
case 8:
|
||
|
if (i + 2 >= nargs)
|
||
|
return; /* Make sure there are 2 args left */
|
||
|
y = args[++i];
|
||
|
x = args[++i];
|
||
|
XResizeWindow(Xdisplay, TermWin.parent,
|
||
|
Width2Pixel(x) + 2 * TermWin.internalBorder + (scrollbar_visible()? scrollbar_total_width() : 0),
|
||
|
Height2Pixel(y) + 2 * TermWin.internalBorder + (menubar_visible()? menuBar_TotalHeight() : 0));
|
||
|
break;
|
||
|
case 11:
|
||
|
break;
|
||
|
case 13:
|
||
|
XTranslateCoordinates(Xdisplay, TermWin.parent, Xroot, 0, 0, &x, &y, &dummy_child);
|
||
|
snprintf(buff, sizeof(buff), "\e[3;%d;%dt", x, y);
|
||
|
tt_write(buff, strlen(buff));
|
||
|
break;
|
||
|
case 14:
|
||
|
snprintf(buff, sizeof(buff), "\e[4;%d;%dt", y, x);
|
||
|
tt_write(buff, strlen(buff));
|
||
|
break;
|
||
|
case 18:
|
||
|
snprintf(buff, sizeof(buff), "\e[8;%d;%dt", TermWin.nrow, TermWin.ncol);
|
||
|
tt_write(buff, strlen(buff));
|
||
|
break;
|
||
|
case 20:
|
||
|
XGetIconName(Xdisplay, TermWin.parent, &name);
|
||
|
snprintf(buff, sizeof(buff), "\e]L%s\e\\", name);
|
||
|
tt_write(buff, strlen(buff));
|
||
|
XFree(name);
|
||
|
break;
|
||
|
case 21:
|
||
|
XFetchName(Xdisplay, TermWin.parent, &name);
|
||
|
snprintf(buff, sizeof(buff), "\e]l%s\e\\", name);
|
||
|
tt_write(buff, strlen(buff));
|
||
|
XFree(name);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* process DEC private mode sequences `ESC [ ? Ps mode' */
|
||
|
/*
|
||
|
* mode can only have the following values:
|
||
|
* 'l' = low
|
||
|
* 'h' = high
|
||
|
* 's' = save
|
||
|
* 'r' = restore
|
||
|
* 't' = toggle
|
||
|
* so no need for fancy checking
|
||
|
*/
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_terminal_mode(int mode, int priv, unsigned int nargs, int arg[])
|
||
|
{
|
||
|
unsigned int i;
|
||
|
int state;
|
||
|
|
||
|
if (nargs == 0)
|
||
|
return;
|
||
|
|
||
|
/* make lo/hi boolean */
|
||
|
switch (mode) {
|
||
|
case 'l':
|
||
|
mode = 0;
|
||
|
break;
|
||
|
case 'h':
|
||
|
mode = 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (priv) {
|
||
|
case 0:
|
||
|
if (mode && mode != 1)
|
||
|
return; /* only do high/low */
|
||
|
for (i = 0; i < nargs; i++)
|
||
|
switch (arg[i]) {
|
||
|
case 4:
|
||
|
scr_insert_mode(mode);
|
||
|
break;
|
||
|
/* case 38: TEK mode */
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#define PrivCases(bit) \
|
||
|
if (mode == 't') state = !(PrivateModes & bit); else state = mode;\
|
||
|
switch (state) {\
|
||
|
case 's': SavedModes |= (PrivateModes & bit); continue; break;\
|
||
|
case 'r': state = (SavedModes & bit) ? 1 : 0;/*drop*/\
|
||
|
default: PrivMode (state, bit); }
|
||
|
|
||
|
case '?':
|
||
|
for (i = 0; i < nargs; i++)
|
||
|
switch (arg[i]) {
|
||
|
case 1: /* application cursor keys */
|
||
|
PrivCases(PrivMode_aplCUR);
|
||
|
break;
|
||
|
|
||
|
/* case 2: - reset charsets to USASCII */
|
||
|
|
||
|
case 3: /* 80/132 */
|
||
|
PrivCases(PrivMode_132);
|
||
|
if (PrivateModes & PrivMode_132OK)
|
||
|
set_width(state ? 132 : 80);
|
||
|
break;
|
||
|
|
||
|
/* case 4: - smooth scrolling */
|
||
|
|
||
|
case 5: /* reverse video */
|
||
|
PrivCases(PrivMode_rVideo);
|
||
|
scr_rvideo_mode(state);
|
||
|
break;
|
||
|
|
||
|
case 6: /* relative/absolute origins */
|
||
|
PrivCases(PrivMode_relOrigin);
|
||
|
scr_relative_origin(state);
|
||
|
break;
|
||
|
|
||
|
case 7: /* autowrap */
|
||
|
PrivCases(PrivMode_Autowrap);
|
||
|
scr_autowrap(state);
|
||
|
break;
|
||
|
|
||
|
/* case 8: - auto repeat, can't do on a per window basis */
|
||
|
|
||
|
case 9: /* X10 mouse reporting */
|
||
|
PrivCases(PrivMode_MouseX10);
|
||
|
/* orthogonal */
|
||
|
if (PrivateModes & PrivMode_MouseX10)
|
||
|
PrivateModes &= ~(PrivMode_MouseX11);
|
||
|
break;
|
||
|
|
||
|
#if (MENUBAR_MAX)
|
||
|
# ifdef menuBar_esc
|
||
|
case menuBar_esc:
|
||
|
PrivCases(PrivMode_menuBar);
|
||
|
map_menuBar(state);
|
||
|
break;
|
||
|
# endif
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
|
||
|
#ifdef scrollBar_esc
|
||
|
case scrollBar_esc:
|
||
|
PrivCases(PrivMode_scrollBar);
|
||
|
map_scrollBar(state);
|
||
|
break;
|
||
|
#endif
|
||
|
case 25: /* visible/invisible cursor */
|
||
|
PrivCases(PrivMode_VisibleCursor);
|
||
|
scr_cursor_visible(state);
|
||
|
break;
|
||
|
|
||
|
case 35:
|
||
|
PrivCases(PrivMode_ShiftKeys);
|
||
|
break;
|
||
|
|
||
|
case 40: /* 80 <--> 132 mode */
|
||
|
PrivCases(PrivMode_132OK);
|
||
|
break;
|
||
|
|
||
|
case 47: /* secondary screen */
|
||
|
PrivCases(PrivMode_Screen);
|
||
|
scr_change_screen(state);
|
||
|
break;
|
||
|
|
||
|
case 66: /* application key pad */
|
||
|
PrivCases(PrivMode_aplKP);
|
||
|
break;
|
||
|
|
||
|
case 67:
|
||
|
PrivCases(PrivMode_BackSpace);
|
||
|
break;
|
||
|
|
||
|
case 1000: /* X11 mouse reporting */
|
||
|
PrivCases(PrivMode_MouseX11);
|
||
|
/* orthogonal */
|
||
|
if (PrivateModes & PrivMode_MouseX11)
|
||
|
PrivateModes &= ~(PrivMode_MouseX10);
|
||
|
break;
|
||
|
|
||
|
#if 0
|
||
|
case 1001:
|
||
|
break; /* X11 mouse highlighting */
|
||
|
#endif
|
||
|
case 1010: /* Scroll to bottom on TTY output */
|
||
|
if (Options & Opt_homeOnEcho)
|
||
|
Options &= ~Opt_homeOnEcho;
|
||
|
else
|
||
|
Options |= Opt_homeOnEcho;
|
||
|
break;
|
||
|
case 1011: /* scroll to bottom on refresh */
|
||
|
if (Options & Opt_homeOnRefresh)
|
||
|
Options &= ~Opt_homeOnRefresh;
|
||
|
else
|
||
|
Options |= Opt_homeOnRefresh;
|
||
|
break;
|
||
|
case 1012: /* Scroll to bottom on TTY input */
|
||
|
if (Options & Opt_homeOnInput)
|
||
|
Options &= ~Opt_homeOnInput;
|
||
|
else
|
||
|
Options |= Opt_homeOnInput;
|
||
|
break;
|
||
|
}
|
||
|
#undef PrivCases
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* process sgr sequences */
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_sgr_mode(unsigned int nargs, int arg[])
|
||
|
{
|
||
|
unsigned int i;
|
||
|
|
||
|
if (nargs == 0) {
|
||
|
scr_rendition(0, ~RS_None);
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < nargs; i++)
|
||
|
switch (arg[i]) {
|
||
|
case 0:
|
||
|
scr_rendition(0, ~RS_None);
|
||
|
break;
|
||
|
case 1:
|
||
|
scr_rendition(1, RS_Bold);
|
||
|
break;
|
||
|
case 4:
|
||
|
scr_rendition(1, RS_Uline);
|
||
|
break;
|
||
|
case 5:
|
||
|
scr_rendition(1, RS_Blink);
|
||
|
break;
|
||
|
case 7:
|
||
|
scr_rendition(1, RS_RVid);
|
||
|
break;
|
||
|
case 22:
|
||
|
scr_rendition(0, RS_Bold);
|
||
|
break;
|
||
|
case 24:
|
||
|
scr_rendition(0, RS_Uline);
|
||
|
break;
|
||
|
case 25:
|
||
|
scr_rendition(0, RS_Blink);
|
||
|
break;
|
||
|
case 27:
|
||
|
scr_rendition(0, RS_RVid);
|
||
|
break;
|
||
|
|
||
|
case 30:
|
||
|
case 31: /* set fg color */
|
||
|
case 32:
|
||
|
case 33:
|
||
|
case 34:
|
||
|
case 35:
|
||
|
case 36:
|
||
|
case 37:
|
||
|
scr_color(minColor + (arg[i] - 30), RS_Bold);
|
||
|
break;
|
||
|
case 39: /* default fg */
|
||
|
scr_color(restoreFG, RS_Bold);
|
||
|
break;
|
||
|
|
||
|
case 40:
|
||
|
case 41: /* set bg color */
|
||
|
case 42:
|
||
|
case 43:
|
||
|
case 44:
|
||
|
case 45:
|
||
|
case 46:
|
||
|
case 47:
|
||
|
scr_color(minColor + (arg[i] - 40), RS_Blink);
|
||
|
break;
|
||
|
case 49: /* default bg */
|
||
|
scr_color(restoreBG, RS_Blink);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* process Rob Nation's own graphics mode sequences */
|
||
|
/* PROTO */
|
||
|
void
|
||
|
process_graphics(void)
|
||
|
{
|
||
|
unsigned char ch, cmd = cmd_getc();
|
||
|
|
||
|
#ifndef RXVT_GRAPHICS
|
||
|
if (cmd == 'Q') { /* query graphics */
|
||
|
tt_printf("\033G0\n"); /* no graphics */
|
||
|
return;
|
||
|
}
|
||
|
/* swallow other graphics sequences until terminating ':' */
|
||
|
do
|
||
|
ch = cmd_getc();
|
||
|
while (ch != ':');
|
||
|
#else
|
||
|
int nargs;
|
||
|
int args[NGRX_PTS];
|
||
|
unsigned char *text = NULL;
|
||
|
|
||
|
if (cmd == 'Q') { /* query graphics */
|
||
|
tt_printf("\033G1\n"); /* yes, graphics (color) */
|
||
|
return;
|
||
|
}
|
||
|
for (nargs = 0; nargs < (sizeof(args) / sizeof(args[0])) - 1; /*nil */ ) {
|
||
|
int neg;
|
||
|
|
||
|
ch = cmd_getc();
|
||
|
neg = (ch == '-');
|
||
|
if (neg || ch == '+')
|
||
|
ch = cmd_getc();
|
||
|
|
||
|
for (args[nargs] = 0; isdigit(ch); ch = cmd_getc())
|
||
|
args[nargs] = args[nargs] * 10 + (ch - '0');
|
||
|
if (neg)
|
||
|
args[nargs] = -args[nargs];
|
||
|
|
||
|
nargs++;
|
||
|
args[nargs] = 0;
|
||
|
if (ch != ';')
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((cmd == 'T') && (nargs >= 5)) {
|
||
|
int i, len = args[4];
|
||
|
|
||
|
text = MALLOC((len + 1) * sizeof(char));
|
||
|
|
||
|
if (text != NULL) {
|
||
|
for (i = 0; i < len; i++)
|
||
|
text[i] = cmd_getc();
|
||
|
text[len] = '\0';
|
||
|
}
|
||
|
}
|
||
|
Gr_do_graphics(cmd, nargs, args, text);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifndef USE_POSIX_THREADS
|
||
|
/* Read and process output from the application */
|
||
|
|
||
|
void
|
||
|
main_loop(void)
|
||
|
{
|
||
|
/* int ch; */
|
||
|
register int ch;
|
||
|
|
||
|
D_CMD(("[%d] main_loop() called\n", getpid()));
|
||
|
|
||
|
#ifdef BACKGROUND_CYCLING_SUPPORT
|
||
|
if (rs_anim_delay) {
|
||
|
check_pixmap_change(0);
|
||
|
}
|
||
|
#endif
|
||
|
do {
|
||
|
while ((ch = cmd_getc()) == 0); /* wait for something */
|
||
|
if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
|
||
|
/* Read a text string from the input buffer */
|
||
|
int nlines = 0;
|
||
|
|
||
|
/* unsigned char * str; */
|
||
|
register unsigned char *str;
|
||
|
|
||
|
/*
|
||
|
* point to the start of the string,
|
||
|
* decrement first since already did get_com_char ()
|
||
|
*/
|
||
|
str = --cmdbuf_ptr;
|
||
|
while (cmdbuf_ptr < cmdbuf_endp) {
|
||
|
|
||
|
ch = *cmdbuf_ptr++;
|
||
|
if (ch >= ' ' || ch == '\t' || ch == '\r') {
|
||
|
/* nothing */
|
||
|
} else if (ch == '\n') {
|
||
|
nlines++;
|
||
|
if (++refresh_count >= (refresh_limit * (TermWin.nrow - 1)))
|
||
|
break;
|
||
|
} else { /* unprintable */
|
||
|
cmdbuf_ptr--;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
D_SCREEN(("Adding lines, str == 0x%08x, cmdbuf_ptr == 0x%08x, cmdbuf_endp == 0x%08x\n", str, cmdbuf_ptr,
|
||
|
cmdbuf_endp));
|
||
|
D_SCREEN(("Command buffer base == 0x%08x, length %lu, end at 0x%08x\n", cmdbuf_base, CMD_BUF_SIZE,
|
||
|
cmdbuf_base + CMD_BUF_SIZE - 1));
|
||
|
scr_add_lines(str, nlines, (cmdbuf_ptr - str));
|
||
|
} else {
|
||
|
switch (ch) {
|
||
|
# ifdef NO_VT100_ANS
|
||
|
case 005:
|
||
|
break;
|
||
|
# else
|
||
|
case 005:
|
||
|
tt_printf(VT100_ANS);
|
||
|
break; /* terminal Status */
|
||
|
# endif
|
||
|
case 007:
|
||
|
scr_bell();
|
||
|
break; /* bell */
|
||
|
case '\b':
|
||
|
scr_backspace();
|
||
|
break; /* backspace */
|
||
|
case 013:
|
||
|
case 014:
|
||
|
scr_index(UP);
|
||
|
break; /* vertical tab, form feed */
|
||
|
case 016:
|
||
|
scr_charset_choose(1);
|
||
|
break; /* shift out - acs */
|
||
|
case 017:
|
||
|
scr_charset_choose(0);
|
||
|
break; /* shift in - acs */
|
||
|
case 033:
|
||
|
process_escape_seq();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} while (ch != EOF);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Addresses pasting large amounts of data
|
||
|
* code pinched from xterm
|
||
|
*/
|
||
|
|
||
|
static char *v_buffer; /* pointer to physical buffer */
|
||
|
static char *v_bufstr = NULL; /* beginning of area to write */
|
||
|
static char *v_bufptr; /* end of area to write */
|
||
|
static char *v_bufend; /* end of physical buffer */
|
||
|
|
||
|
/* output a burst of any pending data from a paste... */
|
||
|
static int
|
||
|
v_doPending()
|
||
|
{
|
||
|
|
||
|
if (v_bufstr >= v_bufptr)
|
||
|
return (0);
|
||
|
v_writeBig(cmd_fd, NULL, 0);
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
/* Write data to the pty as typed by the user, pasted with the mouse,
|
||
|
* or generated by us in response to a query ESC sequence.
|
||
|
* Code stolen from xterm
|
||
|
*/
|
||
|
static void
|
||
|
v_writeBig(int f, char *d, int len)
|
||
|
{
|
||
|
|
||
|
int written;
|
||
|
int c = len;
|
||
|
|
||
|
if (v_bufstr == NULL && len > 0) {
|
||
|
|
||
|
v_buffer = malloc(len);
|
||
|
v_bufstr = v_buffer;
|
||
|
v_bufptr = v_buffer;
|
||
|
v_bufend = v_buffer + len;
|
||
|
}
|
||
|
/*
|
||
|
* Append to the block we already have.
|
||
|
* Always doing this simplifies the code, and
|
||
|
* isn't too bad, either. If this is a short
|
||
|
* block, it isn't too expensive, and if this is
|
||
|
* a long block, we won't be able to write it all
|
||
|
* anyway.
|
||
|
*/
|
||
|
|
||
|
if (len > 0) {
|
||
|
if (v_bufend < v_bufptr + len) { /* we've run out of room */
|
||
|
if (v_bufstr != v_buffer) {
|
||
|
/* there is unused space, move everything down */
|
||
|
/* possibly overlapping bcopy here */
|
||
|
|
||
|
/* bcopy(v_bufstr, v_buffer, v_bufptr - v_bufstr); */
|
||
|
memcpy(v_buffer, v_bufstr, v_bufptr - v_bufstr);
|
||
|
v_bufptr -= v_bufstr - v_buffer;
|
||
|
v_bufstr = v_buffer;
|
||
|
}
|
||
|
if (v_bufend < v_bufptr + len) {
|
||
|
/* still won't fit: get more space */
|
||
|
/* Don't use XtRealloc because an error is not fatal. */
|
||
|
int size = v_bufptr - v_buffer; /* save across realloc */
|
||
|
|
||
|
v_buffer = realloc(v_buffer, size + len);
|
||
|
if (v_buffer) {
|
||
|
v_bufstr = v_buffer;
|
||
|
v_bufptr = v_buffer + size;
|
||
|
v_bufend = v_bufptr + len;
|
||
|
} else {
|
||
|
/* no memory: ignore entire write request */
|
||
|
print_error("cannot allocate buffer space\n");
|
||
|
v_buffer = v_bufstr; /* restore clobbered pointer */
|
||
|
c = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (v_bufend >= v_bufptr + len) { /* new stuff will fit */
|
||
|
memcpy(v_bufptr, d, len); /* bcopy(d, v_bufptr, len); */
|
||
|
v_bufptr += len;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Write out as much of the buffer as we can.
|
||
|
* Be careful not to overflow the pty's input silo.
|
||
|
* We are conservative here and only write
|
||
|
* a small amount at a time.
|
||
|
*
|
||
|
* If we can't push all the data into the pty yet, we expect write
|
||
|
* to return a non-negative number less than the length requested
|
||
|
* (if some data written) or -1 and set errno to EAGAIN,
|
||
|
* EWOULDBLOCK, or EINTR (if no data written).
|
||
|
*
|
||
|
* (Not all systems do this, sigh, so the code is actually
|
||
|
* a little more forgiving.)
|
||
|
*/
|
||
|
|
||
|
#if defined(linux)
|
||
|
# ifdef PTY_BUF_SIZE /* From <linux/tty.h> */
|
||
|
# define MAX_PTY_WRITE PTY_BUF_SIZE
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/* NOTE: _POSIX_MAX_INPUT is defined _through_ <limits.h> at least for
|
||
|
* the following systems: HP-UX 10.20, AIX (no idea about the version),
|
||
|
* OSF1/alpha 4.0, Linux (probably any Linux system).
|
||
|
*/
|
||
|
#ifndef MAX_PTY_WRITE
|
||
|
# ifdef _POSIX_VERSION
|
||
|
# ifdef _POSIX_MAX_INPUT
|
||
|
# define MAX_PTY_WRITE _POSIX_MAX_INPUT
|
||
|
# else
|
||
|
# define MAX_PTY_WRITE 255 /* POSIX minimum MAX_INPUT */
|
||
|
# endif
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifndef MAX_PTY_WRITE
|
||
|
# define MAX_PTY_WRITE 128 /* 1/2 POSIX minimum MAX_INPUT */
|
||
|
#endif
|
||
|
|
||
|
if (v_bufptr > v_bufstr) {
|
||
|
written = write(f, v_bufstr, v_bufptr - v_bufstr <= MAX_PTY_WRITE ?
|
||
|
v_bufptr - v_bufstr : MAX_PTY_WRITE);
|
||
|
if (written < 0) {
|
||
|
written = 0;
|
||
|
}
|
||
|
D_TTY(("v_writeBig(): Wrote %d characters\n", written));
|
||
|
v_bufstr += written;
|
||
|
if (v_bufstr >= v_bufptr) /* we wrote it all */
|
||
|
v_bufstr = v_bufptr = v_buffer;
|
||
|
}
|
||
|
/*
|
||
|
* If we have lots of unused memory allocated, return it
|
||
|
*/
|
||
|
if (v_bufend - v_bufptr > 1024) { /* arbitrary hysteresis */
|
||
|
/* save pointers across realloc */
|
||
|
int start = v_bufstr - v_buffer;
|
||
|
int size = v_bufptr - v_buffer;
|
||
|
int allocsize = size ? size : 1;
|
||
|
|
||
|
v_buffer = realloc(v_buffer, allocsize);
|
||
|
if (v_buffer) {
|
||
|
v_bufstr = v_buffer + start;
|
||
|
v_bufptr = v_buffer + size;
|
||
|
v_bufend = v_buffer + allocsize;
|
||
|
} else {
|
||
|
/* should we print a warning if couldn't return memory? */
|
||
|
v_buffer = v_bufstr - start; /* restore clobbered pointer */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifndef MAX
|
||
|
# define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||
|
#endif
|
||
|
|
||
|
XErrorHandler
|
||
|
xerror_handler(Display * display, XErrorEvent * event)
|
||
|
{
|
||
|
|
||
|
char err_string[2048];
|
||
|
extern char *XRequest, *XlibMessage;
|
||
|
|
||
|
strcpy(err_string, "");
|
||
|
XGetErrorText(Xdisplay, event->error_code, err_string, sizeof(err_string));
|
||
|
print_error("XError in function %s (request %d.%d): %s (error %d)", request_code_to_name(event->request_code),
|
||
|
event->request_code, event->minor_code, err_string, event->error_code);
|
||
|
#if DEBUG > DEBUG_X11
|
||
|
if (debug_level >= DEBUG_X11) {
|
||
|
dump_stack_trace();
|
||
|
}
|
||
|
#endif
|
||
|
print_error("Attempting to continue...");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* color aliases, fg/bg bright-bold */
|
||
|
/*static inline void */
|
||
|
/* inline void */
|
||
|
void
|
||
|
color_aliases(int idx)
|
||
|
{
|
||
|
|
||
|
if (rs_color[idx] && isdigit(*rs_color[idx])) {
|
||
|
|
||
|
int i = atoi(rs_color[idx]);
|
||
|
|
||
|
if (i >= 8 && i <= 15) { /* bright colors */
|
||
|
i -= 8;
|
||
|
#ifndef NO_BRIGHTCOLOR
|
||
|
rs_color[idx] = rs_color[minBright + i];
|
||
|
return;
|
||
|
#endif
|
||
|
}
|
||
|
if (i >= 0 && i <= 7) /* normal colors */
|
||
|
rs_color[idx] = rs_color[minColor + i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* find if fg/bg matches any of the normal (low-intensity) colors
|
||
|
*/
|
||
|
#ifndef NO_BRIGHTCOLOR
|
||
|
static inline void
|
||
|
set_colorfgbg(void)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
static char *colorfgbg_env = NULL;
|
||
|
char *p;
|
||
|
int fg = -1, bg = -1;
|
||
|
|
||
|
if (!colorfgbg_env) {
|
||
|
colorfgbg_env = (char *) malloc(30);
|
||
|
strcpy(colorfgbg_env, "COLORFGBG=default;default;bg");
|
||
|
}
|
||
|
for (i = BlackColor; i <= WhiteColor; i++) {
|
||
|
if (PixColors[fgColor] == PixColors[i]) {
|
||
|
fg = (i - BlackColor);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (i = BlackColor; i <= WhiteColor; i++) {
|
||
|
if (PixColors[bgColor] == PixColors[i]) {
|
||
|
bg = (i - BlackColor);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p = strchr(colorfgbg_env, '=');
|
||
|
p++;
|
||
|
if (fg >= 0)
|
||
|
sprintf(p, "%d;", fg);
|
||
|
else
|
||
|
strcpy(p, "default;");
|
||
|
p = strchr(p, '\0');
|
||
|
if (bg >= 0)
|
||
|
sprintf(p,
|
||
|
# ifdef PIXMAP_SUPPORT
|
||
|
"default;"
|
||
|
# endif
|
||
|
"%d", bg);
|
||
|
else
|
||
|
strcpy(p, "default");
|
||
|
putenv(colorfgbg_env);
|
||
|
|
||
|
colorfgbg = DEFAULT_RSTYLE;
|
||
|
for (i = minColor; i <= maxColor; i++) {
|
||
|
if (PixColors[fgColor] == PixColors[i]
|
||
|
# ifndef NO_BOLDUNDERLINE
|
||
|
&& PixColors[fgColor] == PixColors[colorBD]
|
||
|
# endif /* NO_BOLDUNDERLINE */
|
||
|
/* if we wanted boldFont to have precedence */
|
||
|
# if 0 /* ifndef NO_BOLDFONT */
|
||
|
&& TermWin.boldFont == NULL
|
||
|
# endif /* NO_BOLDFONT */
|
||
|
)
|
||
|
colorfgbg = SET_FGCOLOR(colorfgbg, i);
|
||
|
if (PixColors[bgColor] == PixColors[i])
|
||
|
colorfgbg = SET_BGCOLOR(colorfgbg, i);
|
||
|
}
|
||
|
}
|
||
|
#else /* NO_BRIGHTCOLOR */
|
||
|
# define set_colorfgbg() ((void)0)
|
||
|
#endif /* NO_BRIGHTCOLOR */
|
||
|
|
||
|
/* Create_Windows() - Open and map the window */
|
||
|
void
|
||
|
Create_Windows(int argc, char *argv[])
|
||
|
{
|
||
|
|
||
|
Cursor cursor;
|
||
|
XClassHint classHint;
|
||
|
XWMHints wmHint;
|
||
|
Atom prop;
|
||
|
CARD32 val;
|
||
|
int i, x, y, flags;
|
||
|
unsigned int width, height;
|
||
|
unsigned int r, g, b;
|
||
|
MWMHints mwmhints;
|
||
|
|
||
|
/* char *tmp; */
|
||
|
|
||
|
if (Options & Opt_borderless) {
|
||
|
prop = XInternAtom(Xdisplay, "_MOTIF_WM_HINTS", True);
|
||
|
if (prop == None) {
|
||
|
print_warning("Window Manager does not support MWM hints. Bypassing window manager control for borderless window.");
|
||
|
Attributes.override_redirect = TRUE;
|
||
|
mwmhints.flags = 0;
|
||
|
} else {
|
||
|
mwmhints.flags = MWM_HINTS_DECORATIONS;
|
||
|
mwmhints.decorations = 0;
|
||
|
}
|
||
|
}
|
||
|
Attributes.save_under = TRUE;
|
||
|
Attributes.backing_store = WhenMapped;
|
||
|
|
||
|
/*
|
||
|
* grab colors before netscape does
|
||
|
*/
|
||
|
for (i = 0; i < (Xdepth <= 2 ? 2 : NRS_COLORS); i++) {
|
||
|
|
||
|
XColor xcol;
|
||
|
unsigned char found_color;
|
||
|
|
||
|
if (!rs_color[i])
|
||
|
continue;
|
||
|
|
||
|
if (!XParseColor(Xdisplay, Xcmap, rs_color[i], &xcol)) {
|
||
|
print_warning("Unable to resolve \"%s\" as a color name. Falling back on \"%s\".",
|
||
|
rs_color[i], def_colorName[i] ? def_colorName[i] : "(nil)");
|
||
|
rs_color[i] = def_colorName[i];
|
||
|
if (!rs_color[i])
|
||
|
continue;
|
||
|
if (!XParseColor(Xdisplay, Xcmap, rs_color[i], &xcol)) {
|
||
|
print_warning("Unable to resolve \"%s\" as a color name. This should never fail. Please repair/restore your RGB database.", rs_color[i]);
|
||
|
found_color = 0;
|
||
|
} else {
|
||
|
found_color = 1;
|
||
|
}
|
||
|
} else {
|
||
|
found_color = 1;
|
||
|
}
|
||
|
if (found_color) {
|
||
|
r = xcol.red;
|
||
|
g = xcol.green;
|
||
|
b = xcol.blue;
|
||
|
xcol.pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_warning("Unable to allocate \"%s\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map. "
|
||
|
"Falling back on \"%s\".",
|
||
|
rs_color[i], xcol.pixel, r, g, b, def_colorName[i] ? def_colorName[i] : "(nil)");
|
||
|
rs_color[i] = def_colorName[i];
|
||
|
if (!rs_color[i])
|
||
|
continue;
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_warning("Unable to allocate \"%s\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.",
|
||
|
rs_color[i], xcol.pixel, r, g, b);
|
||
|
found_color = 0;
|
||
|
} else {
|
||
|
found_color = 1;
|
||
|
}
|
||
|
} else {
|
||
|
found_color = 1;
|
||
|
}
|
||
|
}
|
||
|
if (!found_color) {
|
||
|
switch (i) {
|
||
|
case fgColor:
|
||
|
case bgColor:
|
||
|
/* fatal: need bg/fg color */
|
||
|
fatal_error("Unable to get foreground/background colors!");
|
||
|
break;
|
||
|
#ifndef NO_CURSORCOLOR
|
||
|
case cursorColor:
|
||
|
xcol.pixel = PixColors[bgColor];
|
||
|
break;
|
||
|
case cursorColor2:
|
||
|
xcol.pixel = PixColors[fgColor];
|
||
|
break;
|
||
|
#endif /* NO_CURSORCOLOR */
|
||
|
default:
|
||
|
xcol.pixel = PixColors[bgColor]; /* None */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
PixColors[i] = xcol.pixel;
|
||
|
}
|
||
|
|
||
|
#ifndef NO_CURSORCOLOR
|
||
|
if (Xdepth <= 2 || !rs_color[cursorColor])
|
||
|
PixColors[cursorColor] = PixColors[bgColor];
|
||
|
if (Xdepth <= 2 || !rs_color[cursorColor2])
|
||
|
PixColors[cursorColor2] = PixColors[fgColor];
|
||
|
#endif /* NO_CURSORCOLOR */
|
||
|
if (Xdepth <= 2 || !rs_color[pointerColor])
|
||
|
PixColors[pointerColor] = PixColors[fgColor];
|
||
|
if (Xdepth <= 2 || !rs_color[borderColor])
|
||
|
PixColors[borderColor] = PixColors[bgColor];
|
||
|
|
||
|
#ifndef NO_BOLDUNDERLINE
|
||
|
if (Xdepth <= 2 || !rs_color[colorBD])
|
||
|
PixColors[colorBD] = PixColors[fgColor];
|
||
|
if (Xdepth <= 2 || !rs_color[colorUL])
|
||
|
PixColors[colorUL] = PixColors[fgColor];
|
||
|
#endif /* NO_BOLDUNDERLINE */
|
||
|
|
||
|
/*
|
||
|
* get scrollBar/menuBar shadow colors
|
||
|
*
|
||
|
* The calculations of topShadow/bottomShadow values are adapted
|
||
|
* from the fvwm window manager.
|
||
|
*/
|
||
|
#ifdef KEEP_SCROLLCOLOR
|
||
|
if (Xdepth <= 2) { /* Monochrome */
|
||
|
PixColors[scrollColor] = PixColors[bgColor];
|
||
|
PixColors[topShadowColor] = PixColors[fgColor];
|
||
|
PixColors[bottomShadowColor] = PixColors[fgColor];
|
||
|
|
||
|
# ifdef CHANGE_SCROLLCOLOR_ON_FOCUS
|
||
|
PixColors[unfocusedScrollColor] = PixColors[bgColor];
|
||
|
PixColors[unfocusedTopShadowColor] = PixColors[fgColor];
|
||
|
PixColors[unfocusedBottomShadowColor] = PixColors[fgColor];
|
||
|
# endif
|
||
|
|
||
|
} else {
|
||
|
|
||
|
XColor xcol, white;
|
||
|
|
||
|
/* bottomShadowColor */
|
||
|
xcol.pixel = PixColors[scrollColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &xcol);
|
||
|
|
||
|
xcol.red /= 2;
|
||
|
xcol.green /= 2;
|
||
|
xcol.blue /= 2;
|
||
|
r = xcol.red;
|
||
|
g = xcol.green;
|
||
|
b = xcol.blue;
|
||
|
xcol.pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_error("Unable to allocate \"bottomShadowColor\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.",
|
||
|
xcol.pixel, r, g, b);
|
||
|
xcol.pixel = PixColors[minColor];
|
||
|
}
|
||
|
PixColors[bottomShadowColor] = xcol.pixel;
|
||
|
|
||
|
#ifdef CHANGE_SCROLLCOLOR_ON_FOCUS
|
||
|
/* unfocusedBottomShadowColor */
|
||
|
xcol.pixel = PixColors[unfocusedScrollColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &xcol);
|
||
|
|
||
|
xcol.red /= 2;
|
||
|
xcol.green /= 2;
|
||
|
xcol.blue /= 2;
|
||
|
r = xcol.red;
|
||
|
g = xcol.green;
|
||
|
b = xcol.blue;
|
||
|
xcol.pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_error("Unable to allocate \"unfocusedbottomShadowColor\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.",
|
||
|
xcol.pixel, r, g, b);
|
||
|
xcol.pixel = PixColors[minColor];
|
||
|
}
|
||
|
PixColors[unfocusedBottomShadowColor] = xcol.pixel;
|
||
|
#endif
|
||
|
|
||
|
/* topShadowColor */
|
||
|
# ifdef PREFER_24BIT
|
||
|
white.red = white.green = white.blue = r = g = b = ~0;
|
||
|
white.pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
XAllocColor(Xdisplay, Xcmap, &white);
|
||
|
# else
|
||
|
white.pixel = WhitePixel(Xdisplay, Xscreen);
|
||
|
XQueryColor(Xdisplay, Xcmap, &white);
|
||
|
# endif
|
||
|
|
||
|
xcol.pixel = PixColors[scrollColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &xcol);
|
||
|
|
||
|
xcol.red = max((white.red / 5), xcol.red);
|
||
|
xcol.green = max((white.green / 5), xcol.green);
|
||
|
xcol.blue = max((white.blue / 5), xcol.blue);
|
||
|
|
||
|
xcol.red = min(white.red, (xcol.red * 7) / 5);
|
||
|
xcol.green = min(white.green, (xcol.green * 7) / 5);
|
||
|
xcol.blue = min(white.blue, (xcol.blue * 7) / 5);
|
||
|
r = xcol.red;
|
||
|
g = xcol.green;
|
||
|
b = xcol.blue;
|
||
|
xcol.pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_error("Unable to allocate \"topShadowColor\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.",
|
||
|
xcol.pixel, r, g, b);
|
||
|
xcol.pixel = PixColors[WhiteColor];
|
||
|
}
|
||
|
PixColors[topShadowColor] = xcol.pixel;
|
||
|
|
||
|
#ifdef CHANGE_SCROLLCOLOR_ON_FOCUS
|
||
|
/* Do same for unfocusedTopShadowColor */
|
||
|
xcol.pixel = PixColors[unfocusedScrollColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &xcol);
|
||
|
|
||
|
xcol.red = max((white.red / 5), xcol.red);
|
||
|
xcol.green = max((white.green / 5), xcol.green);
|
||
|
xcol.blue = max((white.blue / 5), xcol.blue);
|
||
|
|
||
|
xcol.red = min(white.red, (xcol.red * 7) / 5);
|
||
|
xcol.green = min(white.green, (xcol.green * 7) / 5);
|
||
|
xcol.blue = min(white.blue, (xcol.blue * 7) / 5);
|
||
|
r = xcol.red;
|
||
|
g = xcol.green;
|
||
|
b = xcol.blue;
|
||
|
xcol.pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_error("Unable to allocate \"unfocusedtopShadowColor\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.",
|
||
|
xcol.pixel, r, g, b);
|
||
|
xcol.pixel = PixColors[WhiteColor];
|
||
|
}
|
||
|
PixColors[unfocusedTopShadowColor] = xcol.pixel;
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
#endif /* KEEP_SCROLLCOLOR */
|
||
|
|
||
|
szHint.base_width = (2 * TermWin.internalBorder +
|
||
|
(Options & Opt_scrollBar ? scrollbar_total_width()
|
||
|
: 0));
|
||
|
szHint.base_height = (2 * TermWin.internalBorder);
|
||
|
|
||
|
flags = (rs_geometry ? XParseGeometry(rs_geometry, &x, &y, &width, &height) : 0);
|
||
|
D_X11(("XParseGeometry(geom, %d, %d, %d, %d)\n", x, y, width, height));
|
||
|
|
||
|
if (flags & WidthValue) {
|
||
|
szHint.width = width;
|
||
|
szHint.flags |= USSize;
|
||
|
}
|
||
|
if (flags & HeightValue) {
|
||
|
szHint.height = height;
|
||
|
szHint.flags |= USSize;
|
||
|
}
|
||
|
TermWin.ncol = szHint.width;
|
||
|
TermWin.nrow = szHint.height;
|
||
|
|
||
|
change_font(1, NULL);
|
||
|
#if (MENUBAR_MAX)
|
||
|
szHint.base_height += (delay_menu_drawing ? menuBar_TotalHeight() : 0);
|
||
|
#endif
|
||
|
if (flags & XValue) {
|
||
|
if (flags & XNegative) {
|
||
|
if (check_for_enlightenment()) {
|
||
|
x += (DisplayWidth(Xdisplay, Xscreen));
|
||
|
} else {
|
||
|
x += (DisplayWidth(Xdisplay, Xscreen) - (szHint.width + TermWin.internalBorder));
|
||
|
}
|
||
|
szHint.win_gravity = NorthEastGravity;
|
||
|
}
|
||
|
szHint.x = x;
|
||
|
szHint.flags |= USPosition;
|
||
|
}
|
||
|
if (flags & YValue) {
|
||
|
if (flags & YNegative) {
|
||
|
if (check_for_enlightenment()) {
|
||
|
y += (DisplayHeight(Xdisplay, Xscreen) - (2 * TermWin.internalBorder));
|
||
|
} else {
|
||
|
y += (DisplayHeight(Xdisplay, Xscreen) - (szHint.height + TermWin.internalBorder));
|
||
|
}
|
||
|
szHint.win_gravity = (szHint.win_gravity == NorthEastGravity ?
|
||
|
SouthEastGravity : SouthWestGravity);
|
||
|
}
|
||
|
szHint.y = y;
|
||
|
szHint.flags |= USPosition;
|
||
|
}
|
||
|
D_X11(("Geometry values after parsing: %dx%d%+d%+d\n", width, height, x, y));
|
||
|
|
||
|
/* parent window - reverse video so we can see placement errors
|
||
|
* sub-window placement & size in resize_subwindows()
|
||
|
*/
|
||
|
|
||
|
Attributes.background_pixel = PixColors[bgColor];
|
||
|
Attributes.border_pixel = PixColors[bgColor];
|
||
|
#ifdef PREFER_24BIT
|
||
|
Attributes.colormap = Xcmap;
|
||
|
TermWin.parent = XCreateWindow(Xdisplay, Xroot,
|
||
|
szHint.x, szHint.y,
|
||
|
szHint.width, szHint.height,
|
||
|
0,
|
||
|
Xdepth, InputOutput,
|
||
|
Xvisual,
|
||
|
CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect,
|
||
|
&Attributes);
|
||
|
#else
|
||
|
TermWin.parent = XCreateWindow(Xdisplay, Xroot,
|
||
|
szHint.x, szHint.y,
|
||
|
szHint.width, szHint.height,
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWBackPixel | CWBorderPixel | CWOverrideRedirect,
|
||
|
&Attributes);
|
||
|
#endif
|
||
|
|
||
|
xterm_seq(XTerm_title, rs_title);
|
||
|
xterm_seq(XTerm_iconName, rs_iconName);
|
||
|
classHint.res_name = (char *) rs_name;
|
||
|
classHint.res_class = APL_NAME;
|
||
|
wmHint.window_group = TermWin.parent;
|
||
|
wmHint.input = True;
|
||
|
wmHint.initial_state = (Options & Opt_iconic ? IconicState : NormalState);
|
||
|
wmHint.window_group = TermWin.parent;
|
||
|
wmHint.flags = (InputHint | StateHint | WindowGroupHint);
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
set_icon_pixmap(rs_icon, &wmHint);
|
||
|
#endif
|
||
|
|
||
|
XSetWMProperties(Xdisplay, TermWin.parent, NULL, NULL, argv, argc, &szHint, &wmHint, &classHint);
|
||
|
XSelectInput(Xdisplay, TermWin.parent, (KeyPressMask | FocusChangeMask | StructureNotifyMask | VisibilityChangeMask));
|
||
|
if (mwmhints.flags) {
|
||
|
XChangeProperty(Xdisplay, TermWin.parent, prop, prop, 32, PropModeReplace, (unsigned char *) &mwmhints, PROP_MWM_HINTS_ELEMENTS);
|
||
|
}
|
||
|
/* vt cursor: Black-on-White is standard, but this is more popular */
|
||
|
TermWin_cursor = XCreateFontCursor(Xdisplay, XC_xterm);
|
||
|
{
|
||
|
|
||
|
XColor fg, bg;
|
||
|
|
||
|
fg.pixel = PixColors[pointerColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &fg);
|
||
|
bg.pixel = PixColors[bgColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &bg);
|
||
|
XRecolorCursor(Xdisplay, TermWin_cursor, &fg, &bg);
|
||
|
}
|
||
|
|
||
|
/* cursor (menuBar/scrollBar): Black-on-White */
|
||
|
cursor = XCreateFontCursor(Xdisplay, XC_left_ptr);
|
||
|
|
||
|
/* the vt window */
|
||
|
|
||
|
#ifdef BACKING_STORE
|
||
|
if ((!(Options & Opt_borderless))
|
||
|
&& (Options & Opt_saveUnder)) {
|
||
|
D_X11(("Creating term window with save_under = TRUE\n"));
|
||
|
TermWin.vt = XCreateWindow(Xdisplay, TermWin.parent,
|
||
|
0, 0,
|
||
|
szHint.width, szHint.height,
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder | CWBackingStore,
|
||
|
&Attributes);
|
||
|
if (!(background_is_pixmap()) && !(Options & Opt_borderless)) {
|
||
|
XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
|
||
|
XClearWindow(Xdisplay, TermWin.vt);
|
||
|
}
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
D_X11(("Creating term window with no backing store\n"));
|
||
|
TermWin.vt = XCreateWindow(Xdisplay, TermWin.parent,
|
||
|
0, 0,
|
||
|
szHint.width, szHint.height,
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWBackPixel | CWBorderPixel | CWOverrideRedirect,
|
||
|
&Attributes);
|
||
|
if (!(background_is_pixmap()) && !(Options & Opt_borderless)) {
|
||
|
XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
|
||
|
XClearWindow(Xdisplay, TermWin.vt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
XDefineCursor(Xdisplay, TermWin.vt, TermWin_cursor);
|
||
|
#ifdef USE_ACTIVE_TAGS
|
||
|
XSelectInput(Xdisplay, TermWin.vt,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask | Button3MotionMask |
|
||
|
PointerMotionMask | LeaveWindowMask));
|
||
|
#else
|
||
|
XSelectInput(Xdisplay, TermWin.vt,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask | Button3MotionMask));
|
||
|
#endif
|
||
|
|
||
|
/* If the user wants a specific desktop, tell the WM that */
|
||
|
if (rs_desktop != -1) {
|
||
|
prop = XInternAtom(Xdisplay, "_WIN_WORKSPACE", False);
|
||
|
val = rs_desktop;
|
||
|
XChangeProperty(Xdisplay, TermWin.parent, prop, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &val, 1);
|
||
|
}
|
||
|
XMapWindow(Xdisplay, TermWin.vt);
|
||
|
XMapWindow(Xdisplay, TermWin.parent);
|
||
|
|
||
|
/* scrollBar: size doesn't matter */
|
||
|
#ifdef KEEP_SCROLLCOLOR
|
||
|
Attributes.background_pixel = PixColors[scrollColor];
|
||
|
#else
|
||
|
Attributes.background_pixel = PixColors[fgColor];
|
||
|
#endif
|
||
|
Attributes.border_pixel = PixColors[bgColor];
|
||
|
|
||
|
scrollBar.win = XCreateWindow(Xdisplay, TermWin.parent,
|
||
|
0, 0,
|
||
|
1, 1,
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWOverrideRedirect | CWSaveUnder | CWBackPixel | CWBorderPixel,
|
||
|
&Attributes);
|
||
|
|
||
|
XDefineCursor(Xdisplay, scrollBar.win, cursor);
|
||
|
XSelectInput(Xdisplay, scrollBar.win,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask | Button2MotionMask | Button3MotionMask)
|
||
|
);
|
||
|
|
||
|
#ifdef PIXMAP_SCROLLBAR
|
||
|
if (scrollbar_is_pixmapped()) {
|
||
|
scrollBar.up_win = XCreateWindow(Xdisplay, scrollBar.win,
|
||
|
0, 0,
|
||
|
scrollbar_total_width(),
|
||
|
scrollbar_arrow_height(),
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWOverrideRedirect | CWSaveUnder,
|
||
|
&Attributes);
|
||
|
|
||
|
XDefineCursor(Xdisplay, scrollBar.up_win, cursor);
|
||
|
XSelectInput(Xdisplay, scrollBar.up_win,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask | Button2MotionMask | Button3MotionMask)
|
||
|
);
|
||
|
|
||
|
scrollBar.dn_win = XCreateWindow(Xdisplay, scrollBar.win,
|
||
|
0,
|
||
|
scrollbar_arrow_height()
|
||
|
+ scrollbar_anchor_max_height(),
|
||
|
scrollbar_total_width(),
|
||
|
scrollbar_arrow_height(),
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWOverrideRedirect | CWSaveUnder,
|
||
|
&Attributes);
|
||
|
|
||
|
XDefineCursor(Xdisplay, scrollBar.dn_win, cursor);
|
||
|
XSelectInput(Xdisplay, scrollBar.dn_win,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask | Button2MotionMask | Button3MotionMask)
|
||
|
);
|
||
|
scrollBar.sa_win = XCreateWindow(Xdisplay, scrollBar.win,
|
||
|
0,
|
||
|
scrollbar_arrow_height(),
|
||
|
scrollbar_total_width(),
|
||
|
scrollbar_anchor_max_height(),
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWOverrideRedirect | CWSaveUnder | CWBackingStore,
|
||
|
&Attributes);
|
||
|
|
||
|
XDefineCursor(Xdisplay, scrollBar.sa_win, cursor);
|
||
|
XSelectInput(Xdisplay, scrollBar.sa_win,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask | Button2MotionMask | Button3MotionMask)
|
||
|
);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (MENUBAR_MAX)
|
||
|
/* menuBar: size doesn't matter */
|
||
|
# ifdef KEEP_SCROLLCOLOR
|
||
|
Attributes.background_pixel = PixColors[scrollColor];
|
||
|
# else
|
||
|
Attributes.background_pixel = PixColors[fgColor];
|
||
|
# endif
|
||
|
Attributes.border_pixel = PixColors[bgColor];
|
||
|
menuBar.win = XCreateWindow(Xdisplay, TermWin.parent,
|
||
|
0, 0,
|
||
|
1, 1,
|
||
|
0,
|
||
|
Xdepth,
|
||
|
InputOutput,
|
||
|
CopyFromParent,
|
||
|
CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWBackPixel | CWBorderPixel,
|
||
|
&Attributes);
|
||
|
|
||
|
|
||
|
# ifdef PIXMAP_MENUBAR
|
||
|
if (menubar_is_pixmapped()) {
|
||
|
set_Pixmap(rs_pixmaps[pixmap_mb], mbPixmap.pixmap, pixmap_mb);
|
||
|
XSetWindowBackgroundPixmap(Xdisplay, menuBar.win,
|
||
|
mbPixmap.pixmap);
|
||
|
} else
|
||
|
# endif
|
||
|
{
|
||
|
# ifdef KEEP_SCROLLCOLOR
|
||
|
XSetWindowBackground(Xdisplay, menuBar.win, PixColors[scrollColor]);
|
||
|
# else
|
||
|
XSetWindowBackground(Xdisplay, menuBar.win, PixColors[fgColor]);
|
||
|
# endif
|
||
|
}
|
||
|
|
||
|
XClearWindow(Xdisplay, menuBar.win);
|
||
|
|
||
|
XDefineCursor(Xdisplay, menuBar.win, cursor);
|
||
|
XSelectInput(Xdisplay, menuBar.win,
|
||
|
(ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
Button1MotionMask)
|
||
|
);
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
|
||
|
XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
|
||
|
XClearWindow(Xdisplay, TermWin.vt);
|
||
|
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
if (rs_pixmaps[pixmap_bg] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_bg];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &bgPixmap);
|
||
|
}
|
||
|
D_PIXMAP(("set_bgPixmap() call #1\n"));
|
||
|
set_bgPixmap(rs_pixmaps[pixmap_bg]);
|
||
|
}
|
||
|
# ifdef PIXMAP_SCROLLBAR
|
||
|
if (scrollbar_is_pixmapped()) {
|
||
|
if (rs_pixmaps[pixmap_sb] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_sb];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &sbPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar sb: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_sb], pixmap_sb)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_sb], sbPixmap.pixmap, pixmap_sb);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_up] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_up];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &upPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar up: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_up], pixmap_up)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_up], upPixmap.pixmap, pixmap_up);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_upclk] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_upclk];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &up_clkPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar upclk: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_upclk], pixmap_upclk)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_upclk], up_clkPixmap.pixmap, pixmap_upclk);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_dn] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_dn];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &dnPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar dn: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_dn], pixmap_dn)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_dn], dnPixmap.pixmap, pixmap_dn);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_dnclk] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_dnclk];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &dn_clkPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar dnclk: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_dnclk], pixmap_dnclk)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_dnclk], dn_clkPixmap.pixmap, pixmap_dnclk);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_sa] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_sa];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &saPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar sa: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_sa], pixmap_sa)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_sa], saPixmap.pixmap, pixmap_sa);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_saclk] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_saclk];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &sa_clkPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "scrollbar saclk: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_saclk], pixmap_saclk)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_saclk], sa_clkPixmap.pixmap, pixmap_saclk);
|
||
|
}
|
||
|
}
|
||
|
# endif /* PIXMAP_SCROLLBAR */
|
||
|
|
||
|
# ifdef PIXMAP_MENUBAR
|
||
|
if (menubar_is_pixmapped()) {
|
||
|
if (rs_pixmaps[pixmap_mb] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_mb];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &mbPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "menubar mb: %s\n", p);
|
||
|
set_Pixmap(rs_pixmaps[pixmap_mb], mbPixmap.pixmap, pixmap_mb);
|
||
|
}
|
||
|
if (rs_pixmaps[pixmap_ms] != NULL) {
|
||
|
|
||
|
char *p = rs_pixmaps[pixmap_ms];
|
||
|
|
||
|
if ((p = strchr(p, '@')) != NULL) {
|
||
|
p++;
|
||
|
scale_pixmap(p, &mb_selPixmap);
|
||
|
}
|
||
|
fprintf(stderr, "menubar ms: %s\n", p);
|
||
|
D_PIXMAP(("set_Pixmap(rs_pixmaps[pixmap_ms], pixmap_ms)\n"));
|
||
|
set_Pixmap(rs_pixmaps[pixmap_ms], mb_selPixmap.pixmap, pixmap_ms);
|
||
|
}
|
||
|
}
|
||
|
# endif /* PIXMAP_MENUBAR */
|
||
|
#else /* PIXMAP_SUPPORT */
|
||
|
XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
|
||
|
XClearWindow(Xdisplay, TermWin.vt);
|
||
|
#endif /* PIXMAP_SUPPORT */
|
||
|
|
||
|
/* graphics context for the vt window */
|
||
|
{
|
||
|
|
||
|
XGCValues gcvalue;
|
||
|
|
||
|
gcvalue.font = TermWin.font->fid;
|
||
|
gcvalue.foreground = PixColors[fgColor];
|
||
|
gcvalue.background = PixColors[bgColor];
|
||
|
gcvalue.graphics_exposures = 0;
|
||
|
TermWin.gc = XCreateGC(Xdisplay, TermWin.vt,
|
||
|
GCForeground | GCBackground | GCFont | GCGraphicsExposures,
|
||
|
&gcvalue);
|
||
|
}
|
||
|
|
||
|
if (Options & Opt_noCursor)
|
||
|
scr_cursor_visible(0);
|
||
|
}
|
||
|
|
||
|
/* window resizing - assuming the parent window is the correct size */
|
||
|
void
|
||
|
resize_subwindows(int width, int height)
|
||
|
{
|
||
|
|
||
|
int x = 0, y = 0;
|
||
|
|
||
|
#ifdef RXVT_GRAPHICS
|
||
|
int old_width = TermWin.width;
|
||
|
int old_height = TermWin.height;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
D_SCREEN(("resize_subwindows(%d, %d)\n", width, height));
|
||
|
TermWin.width = TermWin.ncol * TermWin.fwidth;
|
||
|
TermWin.height = TermWin.nrow * TermWin.fheight;
|
||
|
|
||
|
/* size and placement */
|
||
|
if (scrollbar_visible()) {
|
||
|
scrollBar.beg = 0;
|
||
|
scrollBar.end = height;
|
||
|
#ifdef MOTIF_SCROLLBAR
|
||
|
if (scrollBar.type == SCROLLBAR_MOTIF) {
|
||
|
/* arrows are as high as wide - leave 1 pixel gap */
|
||
|
scrollBar.beg += scrollbar_arrow_height();
|
||
|
scrollBar.end -= scrollbar_arrow_height();
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef NEXT_SCROLLBAR
|
||
|
if (scrollBar.type == SCROLLBAR_NEXT) {
|
||
|
scrollBar.beg = sb_shadow;
|
||
|
scrollBar.end -= (scrollBar.width * 2 + (sb_shadow ? sb_shadow : 1) + 2);
|
||
|
}
|
||
|
#endif
|
||
|
width -= scrollbar_total_width();
|
||
|
XMoveResizeWindow(Xdisplay, scrollBar.win,
|
||
|
((Options & Opt_scrollBar_right) ? (width) : (x)),
|
||
|
0, scrollbar_total_width(), height);
|
||
|
|
||
|
if (!(Options & Opt_scrollBar_right)) {
|
||
|
x = scrollbar_total_width();
|
||
|
}
|
||
|
}
|
||
|
#if (MENUBAR_MAX)
|
||
|
if (menubar_visible()) {
|
||
|
y = menuBar_TotalHeight(); /* for placement of vt window */
|
||
|
XMoveResizeWindow(Xdisplay, menuBar.win, x, 0, width, y);
|
||
|
if ((!(menubar_is_pixmapped()))
|
||
|
&& ((Options & Opt_borderless) || (Options & Opt_saveUnder)))
|
||
|
XSetWindowBackground(Xdisplay, menuBar.win, PixColors[scrollColor]);
|
||
|
}
|
||
|
#endif /* NO_MENUBAR */
|
||
|
|
||
|
XMoveResizeWindow(Xdisplay, TermWin.vt, x, y, width, height + 1);
|
||
|
|
||
|
#ifdef RXVT_GRAPHICS
|
||
|
if (old_width)
|
||
|
Gr_Resize(old_width, old_height);
|
||
|
#endif
|
||
|
XClearWindow(Xdisplay, TermWin.vt);
|
||
|
if (!(background_is_pixmap()))
|
||
|
XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
|
||
|
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
# ifdef USE_POSIX_THREADS
|
||
|
|
||
|
D_PIXMAP(("resize_subwindows(): start_bg_thread()\n"));
|
||
|
pthread_attr_init(&resize_sub_thr_attr);
|
||
|
|
||
|
# ifdef MUTEX_SYNCH
|
||
|
if (pthread_mutex_trylock(&mutex) == EBUSY) {
|
||
|
D_THREADS(("resize_subwindows(): mutex locked, bbl\n"));
|
||
|
} else {
|
||
|
D_THREADS(("pthread_mutex_trylock(&mutex): "));
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
D_THREADS(("pthread_mutex_unlock(&mutex)\n"));
|
||
|
}
|
||
|
# endif
|
||
|
|
||
|
if (!(pthread_create(&resize_sub_thr, &resize_sub_thr_attr,
|
||
|
(void *) &render_bg_thread, NULL))) {
|
||
|
/* bg_set = 0; */
|
||
|
D_THREADS(("thread created\n"));
|
||
|
} else {
|
||
|
D_THREADS(("pthread_create() failed!\n"));
|
||
|
}
|
||
|
|
||
|
# else
|
||
|
D_PIXMAP(("resize_subwindows(): render_pixmap(TermWin.vt)\n"));
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
XSync(Xdisplay, 0);
|
||
|
# endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
resize(void)
|
||
|
{
|
||
|
szHint.base_width = (2 * TermWin.internalBorder);
|
||
|
szHint.base_height = (2 * TermWin.internalBorder);
|
||
|
|
||
|
szHint.base_width += (scrollbar_visible()? scrollbar_total_width() : 0);
|
||
|
#if (MENUBAR_MAX)
|
||
|
szHint.base_height += (menubar_visible()? menuBar_TotalHeight() : 0);
|
||
|
#endif
|
||
|
|
||
|
szHint.min_width = szHint.base_width + szHint.width_inc;
|
||
|
szHint.min_height = szHint.base_height + szHint.height_inc;
|
||
|
|
||
|
szHint.width = szHint.base_width + TermWin.width;
|
||
|
szHint.height = szHint.base_height + TermWin.height;
|
||
|
|
||
|
szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
|
||
|
|
||
|
XSetWMNormalHints(Xdisplay, TermWin.parent, &szHint);
|
||
|
XResizeWindow(Xdisplay, TermWin.parent, szHint.width, szHint.height);
|
||
|
|
||
|
resize_subwindows(szHint.width, szHint.height);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Redraw window after exposure or size change
|
||
|
*/
|
||
|
static void
|
||
|
resize_window1(unsigned int width, unsigned int height)
|
||
|
{
|
||
|
static short first_time = 1;
|
||
|
int new_ncol = (width - szHint.base_width) / TermWin.fwidth;
|
||
|
int new_nrow = (height - szHint.base_height) / TermWin.fheight;
|
||
|
|
||
|
if (first_time ||
|
||
|
(new_ncol != TermWin.ncol) ||
|
||
|
(new_nrow != TermWin.nrow)) {
|
||
|
int curr_screen = -1;
|
||
|
|
||
|
/* scr_reset only works on the primary screen */
|
||
|
if (!first_time) { /* this is not the first time thru */
|
||
|
selection_clear();
|
||
|
curr_screen = scr_change_screen(PRIMARY);
|
||
|
}
|
||
|
TermWin.ncol = new_ncol;
|
||
|
TermWin.nrow = new_nrow;
|
||
|
|
||
|
resize_subwindows(width, height);
|
||
|
scr_reset();
|
||
|
|
||
|
if (curr_screen >= 0) /* this is not the first time thru */
|
||
|
scr_change_screen(curr_screen);
|
||
|
first_time = 0;
|
||
|
} else if (Options & Opt_pixmapTrans) {
|
||
|
resize_subwindows(width, height);
|
||
|
scrollbar_show(0);
|
||
|
scr_expose(0, 0, width, height);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* good for toggling 80/132 columns
|
||
|
*/
|
||
|
void
|
||
|
set_width(unsigned short width)
|
||
|
{
|
||
|
unsigned short height = TermWin.nrow;
|
||
|
|
||
|
if (width != TermWin.ncol) {
|
||
|
width = szHint.base_width + width * TermWin.fwidth;
|
||
|
height = szHint.base_height + height * TermWin.fheight;
|
||
|
|
||
|
XResizeWindow(Xdisplay, TermWin.parent, width, height);
|
||
|
resize_window1(width, height);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Redraw window after exposure or size change
|
||
|
*/
|
||
|
void
|
||
|
resize_window(void)
|
||
|
{
|
||
|
Window root;
|
||
|
XEvent dummy;
|
||
|
int x, y;
|
||
|
unsigned int border, depth, width, height;
|
||
|
|
||
|
while (XCheckTypedWindowEvent(Xdisplay, TermWin.parent,
|
||
|
ConfigureNotify, &dummy));
|
||
|
|
||
|
/* do we come from an fontchange? */
|
||
|
if (font_change_count > 0) {
|
||
|
font_change_count--;
|
||
|
return;
|
||
|
}
|
||
|
XGetGeometry(Xdisplay, TermWin.parent,
|
||
|
&root, &x, &y, &width, &height, &border, &depth);
|
||
|
#if 0
|
||
|
XGetGeometry(Xdisplay, TermWin.vt,
|
||
|
&root, &x, &y, &width, &height, &border, &depth);
|
||
|
#endif
|
||
|
|
||
|
/* parent already resized */
|
||
|
|
||
|
resize_window1(width, height);
|
||
|
}
|
||
|
|
||
|
/* xterm sequences - title, iconName, color (exptl) */
|
||
|
#ifdef SMART_WINDOW_TITLE
|
||
|
static void
|
||
|
set_title(const char *str)
|
||
|
{
|
||
|
|
||
|
char *name;
|
||
|
|
||
|
if (XFetchName(Xdisplay, TermWin.parent, &name))
|
||
|
name = NULL;
|
||
|
if (name == NULL || strcmp(name, str))
|
||
|
XStoreName(Xdisplay, TermWin.parent, str);
|
||
|
if (name)
|
||
|
XFree(name);
|
||
|
}
|
||
|
#else
|
||
|
# define set_title(str) XStoreName(Xdisplay, TermWin.parent, str)
|
||
|
#endif
|
||
|
|
||
|
#ifdef SMART_WINDOW_TITLE
|
||
|
static void
|
||
|
set_iconName(const char *str)
|
||
|
{
|
||
|
|
||
|
char *name;
|
||
|
|
||
|
if (XGetIconName(Xdisplay, TermWin.parent, &name))
|
||
|
name = NULL;
|
||
|
if (name == NULL || strcmp(name, str))
|
||
|
XSetIconName(Xdisplay, TermWin.parent, str);
|
||
|
if (name)
|
||
|
XFree(name);
|
||
|
}
|
||
|
#else
|
||
|
# define set_iconName(str) XSetIconName (Xdisplay, TermWin.parent, str)
|
||
|
#endif
|
||
|
|
||
|
#ifdef XTERM_COLOR_CHANGE
|
||
|
static void
|
||
|
set_window_color(int idx, const char *color)
|
||
|
{
|
||
|
|
||
|
XColor xcol;
|
||
|
int i;
|
||
|
unsigned int pixel, r, g, b;
|
||
|
|
||
|
if (color == NULL || *color == '\0')
|
||
|
return;
|
||
|
|
||
|
/* handle color aliases */
|
||
|
if (isdigit(*color)) {
|
||
|
i = atoi(color);
|
||
|
if (i >= 8 && i <= 15) { /* bright colors */
|
||
|
i -= 8;
|
||
|
# ifndef NO_BRIGHTCOLOR
|
||
|
PixColors[idx] = PixColors[minBright + i];
|
||
|
goto Done;
|
||
|
# endif
|
||
|
}
|
||
|
if (i >= 0 && i <= 7) { /* normal colors */
|
||
|
PixColors[idx] = PixColors[minColor + i];
|
||
|
goto Done;
|
||
|
}
|
||
|
}
|
||
|
if (XParseColor(Xdisplay, Xcmap, color, &xcol)) {
|
||
|
r = xcol.red;
|
||
|
g = xcol.green;
|
||
|
b = xcol.blue;
|
||
|
pixel = Imlib_best_color_match(imlib_id, &r, &g, &b);
|
||
|
xcol.pixel = pixel;
|
||
|
if (!XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
print_warning("Unable to allocate \"%s\" in the color map.\n", color);
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
print_warning("Unable to resolve \"%s\" as a color name.\n", color);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* XStoreColor(Xdisplay, Xcmap, XColor*); */
|
||
|
|
||
|
/*
|
||
|
* FIXME: should free colors here, but no idea how to do it so instead,
|
||
|
* so just keep gobbling up the colormap
|
||
|
*/
|
||
|
# if 0
|
||
|
for (i = BlackColor; i <= WhiteColor; i++)
|
||
|
if (PixColors[idx] == PixColors[i])
|
||
|
break;
|
||
|
if (i > WhiteColor) {
|
||
|
/* fprintf (stderr, "XFreeColors: PixColors[%d] = %lu\n", idx, PixColors[idx]); */
|
||
|
XFreeColors(Xdisplay, Xcmap, (PixColors + idx), 1,
|
||
|
DisplayPlanes(Xdisplay, Xscreen));
|
||
|
}
|
||
|
# endif
|
||
|
|
||
|
PixColors[idx] = xcol.pixel;
|
||
|
|
||
|
/* XSetWindowAttributes attr; */
|
||
|
/* Cursor cursor; */
|
||
|
Done:
|
||
|
if (idx == bgColor)
|
||
|
XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
|
||
|
|
||
|
/* handle colorBD, scrollbar background, etc. */
|
||
|
|
||
|
set_colorfgbg();
|
||
|
{
|
||
|
|
||
|
XColor fg, bg;
|
||
|
|
||
|
fg.pixel = PixColors[fgColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &fg);
|
||
|
bg.pixel = PixColors[bgColor];
|
||
|
XQueryColor(Xdisplay, Xcmap, &bg);
|
||
|
|
||
|
XRecolorCursor(Xdisplay, TermWin_cursor, &fg, &bg);
|
||
|
}
|
||
|
/* the only reasonable way to enforce a clean update */
|
||
|
scr_poweron();
|
||
|
}
|
||
|
#else
|
||
|
# define set_window_color(idx,color) ((void)0)
|
||
|
#endif /* XTERM_COLOR_CHANGE */
|
||
|
|
||
|
/* Macros to make parsing escape sequences slightly more readable.... <G> */
|
||
|
#define OPT_SET_OR_TOGGLE(s, mask, bit) do { \
|
||
|
if (!(s) || !(*(s))) { \
|
||
|
if ((mask) & (bit)) { \
|
||
|
(mask) &= ~(bit); \
|
||
|
} else { \
|
||
|
(mask) |= (bit); \
|
||
|
} \
|
||
|
} else if (BOOL_OPT_ISTRUE(s)) { \
|
||
|
if ((mask) & (bit)) return; \
|
||
|
(mask) |= (bit); \
|
||
|
} else if (BOOL_OPT_ISFALSE(s)) { \
|
||
|
if (!((mask) & (bit))) return; \
|
||
|
(mask) &= ~(bit); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
/* The macro below forces bit to the opposite state from what we want, so that the
|
||
|
code that follows will set it right. Hackish, but saves space. :) Use this
|
||
|
if you need to do some processing other than just setting the flag right. */
|
||
|
#define OPT_SET_OR_TOGGLE_NEG(s, mask, bit) do { if (s) { \
|
||
|
if (BOOL_OPT_ISTRUE(s)) { \
|
||
|
if ((mask) & (bit)) return; \
|
||
|
(mask) &= ~(bit); \
|
||
|
} else if (BOOL_OPT_ISFALSE(s)) { \
|
||
|
if (!((mask) & (bit))) return; \
|
||
|
(mask) |= (bit); \
|
||
|
} \
|
||
|
} } while (0)
|
||
|
|
||
|
/*
|
||
|
* XTerm escape sequences: ESC ] Ps;Pt BEL
|
||
|
* 0 = change iconName/title
|
||
|
* 1 = change iconName
|
||
|
* 2 = change title
|
||
|
* 46 = change logfile (not implemented)
|
||
|
* 50 = change font
|
||
|
*
|
||
|
* rxvt/Eterm extensions:
|
||
|
* 5 = Hostile takeover (grab focus and raise)
|
||
|
* 6 = Transparency mode stuff
|
||
|
* 10 = menu
|
||
|
* 20 = bg pixmap
|
||
|
* 39 = change default fg color
|
||
|
* 49 = change default bg color
|
||
|
*/
|
||
|
void
|
||
|
xterm_seq(int op, const char *str)
|
||
|
{
|
||
|
|
||
|
XColor xcol;
|
||
|
char *nstr, *tnstr, *orig_tnstr;
|
||
|
unsigned char eterm_seq_op;
|
||
|
|
||
|
#if MENUBAR_MAX
|
||
|
char *menu_str;
|
||
|
|
||
|
#endif
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
int changed = 0, scaled = 0;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
if (!str)
|
||
|
return;
|
||
|
|
||
|
#if MENUBAR_MAX
|
||
|
menu_str = strdup(str);
|
||
|
#endif
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
orig_tnstr = tnstr = strdup(str);
|
||
|
#endif
|
||
|
|
||
|
switch (op) {
|
||
|
case XTerm_title:
|
||
|
set_title(str);
|
||
|
break;
|
||
|
case XTerm_name:
|
||
|
set_title(str); /* drop */
|
||
|
case XTerm_iconName:
|
||
|
set_iconName(str);
|
||
|
break;
|
||
|
case XTerm_Takeover:
|
||
|
XSetInputFocus(Xdisplay, TermWin.parent, RevertToParent, CurrentTime);
|
||
|
XRaiseWindow(Xdisplay, TermWin.parent);
|
||
|
break;
|
||
|
#if MENUBAR_MAX
|
||
|
case XTerm_Menu:
|
||
|
menubar_dispatch(menu_str);
|
||
|
free(menu_str);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
case XTerm_EtermSeq:
|
||
|
|
||
|
/* Eterm proprietary escape sequences
|
||
|
|
||
|
Syntax: ESC ] 6 ; <op> ; <arg> BEL
|
||
|
|
||
|
where <op> is: 0 Set/toggle transparency
|
||
|
1 Set shade percentage
|
||
|
2 Set tint mask
|
||
|
3 Force update of pseudo-transparent background
|
||
|
4 Set/toggle desktop watching
|
||
|
10 Set scrollbar type/width
|
||
|
11 Set/toggle right-side scrollbar
|
||
|
12 Set/toggle floating scrollbar
|
||
|
13 Set/toggle popup scrollbar
|
||
|
15 Set/toggle menubar move
|
||
|
20 Set/toggle visual bell
|
||
|
21 Set/toggle map alert
|
||
|
22 Set/toggle xterm selection behavior
|
||
|
23 Set/toggle triple-click line selection
|
||
|
24 Set/toggle viewport mode
|
||
|
25 Set/toggle selection of trailing spaces
|
||
|
30 Do not use
|
||
|
40 Do not use
|
||
|
50 Move window to another desktop
|
||
|
70 Exit Eterm
|
||
|
71 Save current configuration to a file
|
||
|
and <arg> is an optional argument, depending
|
||
|
on the particular sequence being used. It
|
||
|
(along with its preceeding semicolon) may or
|
||
|
may not be needed.
|
||
|
*/
|
||
|
|
||
|
D_EVENTS(("Got XTerm_EtermSeq sequence\n"));
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
eterm_seq_op = (unsigned char) strtol(nstr, (char **) NULL, 10);
|
||
|
D_EVENTS((" XTerm_EtermSeq operation is %d\n", eterm_seq_op));
|
||
|
/* Yes, there is order to the numbers for this stuff. And here it is:
|
||
|
0-9 Transparency Configuration
|
||
|
10-14 Scrollbar Configuration
|
||
|
15-19 Menubar Configuration
|
||
|
20-29 Miscellaneous Toggles
|
||
|
30-39 Foreground/Text Color Configuration
|
||
|
40-49 Background Color Configuration
|
||
|
50-69 Window/Window Manager Configuration/Interaction
|
||
|
70-79 Internal Eterm Operations
|
||
|
*/
|
||
|
switch (eterm_seq_op) {
|
||
|
#ifdef PIXMAP_OFFSET
|
||
|
case 0:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE_NEG(nstr, Options, Opt_pixmapTrans);
|
||
|
if (Options & Opt_pixmapTrans) {
|
||
|
Options &= ~(Opt_pixmapTrans);
|
||
|
# ifdef IMLIB_TRANS
|
||
|
if (imlib_id) {
|
||
|
if (imlib_bg.im != NULL) {
|
||
|
Imlib_kill_image(imlib_id, imlib_bg.im);
|
||
|
imlib_bg.im = NULL;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
set_bgPixmap(rs_pixmaps[pixmap_bg]);
|
||
|
} else {
|
||
|
Options |= Opt_pixmapTrans;
|
||
|
if (imlib_id) {
|
||
|
ImlibFreePixmap(imlib_id, bgPixmap.pixmap);
|
||
|
if (imlib_bg.im != NULL) {
|
||
|
D_IMLIB(("ImlibDestroyImage()\n"));
|
||
|
ImlibDestroyImage(imlib_id, imlib_bg.im);
|
||
|
imlib_bg.im = NULL;
|
||
|
}
|
||
|
bgPixmap.pixmap = None;
|
||
|
}
|
||
|
TermWin.pixmap = None;
|
||
|
}
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_touch();
|
||
|
break;
|
||
|
case 1:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (!nstr) {
|
||
|
break;
|
||
|
}
|
||
|
rs_shadePct = strtoul(nstr, (char **) NULL, 0);
|
||
|
D_EVENTS((" XTerm_EtermSeq shade percentage is %d%%\n", rs_shadePct));
|
||
|
if (Options & Opt_pixmapTrans && desktop_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, desktop_pixmap);
|
||
|
desktop_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
if (Options & Opt_viewport_mode && viewport_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, viewport_pixmap);
|
||
|
viewport_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_touch();
|
||
|
break;
|
||
|
case 2:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (!nstr) {
|
||
|
break;
|
||
|
}
|
||
|
if (!BEG_STRCASECMP(nstr, "none")) {
|
||
|
rs_tintMask = 0xffffff;
|
||
|
} else if (!BEG_STRCASECMP(nstr, "red")) {
|
||
|
rs_tintMask = 0xff8080;
|
||
|
} else if (!BEG_STRCASECMP(nstr, "green")) {
|
||
|
rs_tintMask = 0x80ff80;
|
||
|
} else if (!BEG_STRCASECMP(nstr, "blue")) {
|
||
|
rs_tintMask = 0x8080ff;
|
||
|
} else if (!BEG_STRCASECMP(nstr, "cyan")) {
|
||
|
rs_tintMask = 0x80ffff;
|
||
|
} else if (!BEG_STRCASECMP(nstr, "magenta")) {
|
||
|
rs_tintMask = 0xff80ff;
|
||
|
} else if (!BEG_STRCASECMP(nstr, "yellow")) {
|
||
|
rs_tintMask = 0xffff80;
|
||
|
} else {
|
||
|
rs_tintMask = strtoul(nstr, (char **) NULL, 0);
|
||
|
}
|
||
|
D_EVENTS((" XTerm_EtermSeq tint mask is 0x%06x\n", rs_tintMask));
|
||
|
if (Options & Opt_pixmapTrans && desktop_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, desktop_pixmap);
|
||
|
desktop_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
if (Options & Opt_viewport_mode && viewport_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, viewport_pixmap);
|
||
|
viewport_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_touch();
|
||
|
break;
|
||
|
case 3:
|
||
|
if (Options & Opt_pixmapTrans) {
|
||
|
get_desktop_window();
|
||
|
if (desktop_pixmap != None) {
|
||
|
XFreePixmap(Xdisplay, desktop_pixmap);
|
||
|
desktop_pixmap = None; /* Force the re-read */
|
||
|
}
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_expose(0, 0, TermWin_TotalWidth(), TermWin_TotalHeight());
|
||
|
}
|
||
|
break;
|
||
|
case 4:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_watchDesktop);
|
||
|
if (Options & Opt_pixmapTrans) {
|
||
|
get_desktop_window();
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
case 10:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr && *nstr) {
|
||
|
if (!strcasecmp(nstr, "xterm")) {
|
||
|
#ifdef XTERM_SCROLLBAR
|
||
|
scrollBar.type = SCROLLBAR_XTERM;
|
||
|
#else
|
||
|
print_error("Support for xterm scrollbars was not compiled in. Sorry.");
|
||
|
#endif
|
||
|
} else if (!strcasecmp(nstr, "next")) {
|
||
|
#ifdef NEXT_SCROLLBAR
|
||
|
scrollBar.type = SCROLLBAR_NEXT;
|
||
|
#else
|
||
|
print_error("Support for NeXT scrollbars was not compiled in. Sorry.");
|
||
|
#endif
|
||
|
} else if (!strcasecmp(nstr, "motif")) {
|
||
|
#ifdef MOTIF_SCROLLBAR
|
||
|
scrollBar.type = SCROLLBAR_MOTIF;
|
||
|
#else
|
||
|
print_error("Support for motif scrollbars was not compiled in. Sorry.");
|
||
|
#endif
|
||
|
} else {
|
||
|
print_error("Unrecognized scrollbar type \"%s\".", nstr);
|
||
|
}
|
||
|
scrollbar_reset();
|
||
|
map_scrollBar(0);
|
||
|
map_scrollBar(1);
|
||
|
scrollbar_show(0);
|
||
|
}
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr && *nstr) {
|
||
|
scrollBar.width = strtoul(nstr, (char **) NULL, 0);
|
||
|
if (scrollBar.width == 0) {
|
||
|
print_error("Invalid scrollbar length \"%s\".", nstr);
|
||
|
scrollBar.width = SB_WIDTH;
|
||
|
}
|
||
|
scrollbar_reset();
|
||
|
map_scrollBar(0);
|
||
|
map_scrollBar(1);
|
||
|
scrollbar_show(0);
|
||
|
}
|
||
|
break;
|
||
|
case 11:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_scrollBar_right);
|
||
|
scrollbar_reset();
|
||
|
map_scrollBar(0);
|
||
|
map_scrollBar(1);
|
||
|
scrollbar_show(0);
|
||
|
break;
|
||
|
case 12:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_scrollBar_floating);
|
||
|
scrollbar_reset();
|
||
|
map_scrollBar(0);
|
||
|
map_scrollBar(1);
|
||
|
scrollbar_show(0);
|
||
|
break;
|
||
|
case 13:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_scrollbar_popup);
|
||
|
break;
|
||
|
case 15:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_menubar_move);
|
||
|
break;
|
||
|
case 20:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_visualBell);
|
||
|
break;
|
||
|
#ifdef MAPALERT_OPTION
|
||
|
case 21:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_mapAlert);
|
||
|
break;
|
||
|
#endif
|
||
|
case 22:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_xterm_select);
|
||
|
break;
|
||
|
case 23:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_select_whole_line);
|
||
|
break;
|
||
|
case 24:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_viewport_mode);
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_touch();
|
||
|
break;
|
||
|
case 25:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
OPT_SET_OR_TOGGLE(nstr, Options, Opt_select_trailing_spaces);
|
||
|
break;
|
||
|
case 30:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr) {
|
||
|
if (XParseColor(Xdisplay, Xcmap, nstr, &xcol) && XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
PixColors[fgColor] = xcol.pixel;
|
||
|
scr_refresh(SMOOTH_REFRESH);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 40:
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr) {
|
||
|
if (XParseColor(Xdisplay, Xcmap, nstr, &xcol) && XAllocColor(Xdisplay, Xcmap, &xcol)) {
|
||
|
PixColors[bgColor] = xcol.pixel;
|
||
|
scr_refresh(SMOOTH_REFRESH);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 50:
|
||
|
/* Change desktops */
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr && *nstr) {
|
||
|
XClientMessageEvent xev;
|
||
|
|
||
|
rs_desktop = (int) strtol(nstr, (char **) NULL, 0);
|
||
|
xev.type = ClientMessage;
|
||
|
xev.window = TermWin.parent;
|
||
|
xev.message_type = XInternAtom(Xdisplay, "_WIN_WORKSPACE", False);
|
||
|
xev.format = 32;
|
||
|
xev.data.l[0] = rs_desktop;
|
||
|
XChangeProperty(Xdisplay, TermWin.parent, xev.message_type, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &rs_desktop, 1);
|
||
|
XSendEvent(Xdisplay, Xroot, False, SubstructureNotifyMask, (XEvent *) & xev);
|
||
|
}
|
||
|
break;
|
||
|
case 70:
|
||
|
/* Exit Eterm */
|
||
|
exit(0);
|
||
|
break;
|
||
|
case 71:
|
||
|
/* Save current config */
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr && *nstr) {
|
||
|
save_config(nstr);
|
||
|
} else {
|
||
|
save_config(NULL);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case XTerm_Pixmap:
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
# ifdef PIXMAP_OFFSET
|
||
|
if (Options & Opt_pixmapTrans) {
|
||
|
Options &= ~(Opt_pixmapTrans);
|
||
|
}
|
||
|
# endif
|
||
|
rs_shadePct = 0;
|
||
|
rs_tintMask = 0xffffff;
|
||
|
if (!strcmp(str, ";")) {
|
||
|
rs_pixmaps[pixmap_bg] = "";
|
||
|
set_bgPixmap("");
|
||
|
return;
|
||
|
}
|
||
|
nstr = strsep(&tnstr, ";");
|
||
|
if (nstr) {
|
||
|
if (*nstr) {
|
||
|
scale_pixmap("", &bgPixmap);
|
||
|
D_PIXMAP(("set_bgPixmap() call #2\n"));
|
||
|
bg_needs_update = 1;
|
||
|
set_bgPixmap(nstr);
|
||
|
}
|
||
|
while ((nstr = strsep(&tnstr, ";")) && *nstr) {
|
||
|
changed += scale_pixmap(nstr, &bgPixmap);
|
||
|
scaled = 1;
|
||
|
}
|
||
|
/* FIXME: This used to be && instead of || to avoid unnecessary
|
||
|
* rendering under some circumstances... I'll try to look
|
||
|
* deeper :) -vendu
|
||
|
*/
|
||
|
if ((changed) || (bg_needs_update)) {
|
||
|
D_PIXMAP(("XTerm_Pixmap sequence: render_pixmap(TermWin.vt)\n"));
|
||
|
render_pixmap(TermWin.vt, imlib_bg, bgPixmap, 0, 1);
|
||
|
scr_touch();
|
||
|
}
|
||
|
} else {
|
||
|
D_PIXMAP(("set_bgPixmap() call #3\n"));
|
||
|
set_bgPixmap("");
|
||
|
}
|
||
|
#endif /* PIXMAP_SUPPORT */
|
||
|
break;
|
||
|
|
||
|
case XTerm_restoreFG:
|
||
|
set_window_color(fgColor, str);
|
||
|
break;
|
||
|
case XTerm_restoreBG:
|
||
|
set_window_color(bgColor, str);
|
||
|
break;
|
||
|
case XTerm_logfile:
|
||
|
break;
|
||
|
case XTerm_font:
|
||
|
change_font(0, str);
|
||
|
break;
|
||
|
#ifdef ETERM_COMMAND_MODE
|
||
|
case ETerm_command_mode:
|
||
|
fprintf(stderr, "ETerm_command_mode\n");
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
D_CMD(("Unsupported xterm escape sequence operator: 0x%02x\n", op));
|
||
|
break;
|
||
|
}
|
||
|
#ifdef PIXMAP_SUPPORT
|
||
|
free(orig_tnstr);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* change_font() - Switch to a new font */
|
||
|
/*
|
||
|
* init = 1 - initialize
|
||
|
*
|
||
|
* fontname == FONT_UP - switch to bigger font
|
||
|
* fontname == FONT_DN - switch to smaller font
|
||
|
*/
|
||
|
#define ABORT() do { print_error("aborting"); exit(EXIT_FAILURE); } while (0)
|
||
|
void
|
||
|
change_font(int init, const char *fontname)
|
||
|
{
|
||
|
const char *const msg = "can't load font \"%s\"";
|
||
|
XFontStruct *xfont;
|
||
|
static char *newfont[NFONTS];
|
||
|
|
||
|
#ifndef NO_BOLDFONT
|
||
|
static XFontStruct *boldFont = NULL;
|
||
|
|
||
|
#endif
|
||
|
static int fnum = FONT0_IDX; /* logical font number */
|
||
|
int idx = 0; /* index into rs_font[] */
|
||
|
|
||
|
#if (FONT0_IDX == 0)
|
||
|
# define IDX2FNUM(i) (i)
|
||
|
# define FNUM2IDX(f) (f)
|
||
|
#else
|
||
|
# define IDX2FNUM(i) (i == 0? FONT0_IDX : (i <= FONT0_IDX? (i-1) : i))
|
||
|
# define FNUM2IDX(f) (f == FONT0_IDX ? 0 : (f < FONT0_IDX ? (f+1) : f))
|
||
|
#endif
|
||
|
#define FNUM_RANGE(i) (i <= 0 ? 0 : (i >= NFONTS ? (NFONTS-1) : i))
|
||
|
|
||
|
if (!init) {
|
||
|
switch (fontname[0]) {
|
||
|
case '\0':
|
||
|
fnum = FONT0_IDX;
|
||
|
fontname = NULL;
|
||
|
break;
|
||
|
|
||
|
/* special (internal) prefix for font commands */
|
||
|
case FONT_CMD:
|
||
|
idx = atoi(fontname + 1);
|
||
|
switch (fontname[1]) {
|
||
|
case '+': /* corresponds to FONT_UP */
|
||
|
fnum += (idx ? idx : 1);
|
||
|
fnum = FNUM_RANGE(fnum);
|
||
|
break;
|
||
|
|
||
|
case '-': /* corresponds to FONT_DN */
|
||
|
fnum += (idx ? idx : -1);
|
||
|
fnum = FNUM_RANGE(fnum);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (fontname[1] != '\0' && !isdigit(fontname[1]))
|
||
|
return;
|
||
|
if (idx < 0 || idx >= (NFONTS))
|
||
|
return;
|
||
|
fnum = IDX2FNUM(idx);
|
||
|
break;
|
||
|
}
|
||
|
fontname = NULL;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (fontname != NULL) {
|
||
|
/* search for existing fontname */
|
||
|
for (idx = 0; idx < NFONTS; idx++) {
|
||
|
if (!strcmp(rs_font[idx], fontname)) {
|
||
|
fnum = IDX2FNUM(idx);
|
||
|
fontname = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
/* re-position around the normal font */
|
||
|
idx = FNUM2IDX(fnum);
|
||
|
|
||
|
if (fontname != NULL) {
|
||
|
char *name;
|
||
|
|
||
|
xfont = XLoadQueryFont(Xdisplay, fontname);
|
||
|
if (!xfont)
|
||
|
return;
|
||
|
|
||
|
name = MALLOC(strlen(fontname + 1) * sizeof(char));
|
||
|
|
||
|
if (name == NULL) {
|
||
|
XFreeFont(Xdisplay, xfont);
|
||
|
return;
|
||
|
}
|
||
|
strcpy(name, fontname);
|
||
|
if (newfont[idx] != NULL)
|
||
|
FREE(newfont[idx]);
|
||
|
newfont[idx] = name;
|
||
|
rs_font[idx] = newfont[idx];
|
||
|
}
|
||
|
}
|
||
|
if (TermWin.font)
|
||
|
XFreeFont(Xdisplay, TermWin.font);
|
||
|
|
||
|
/* load font or substitute */
|
||
|
xfont = XLoadQueryFont(Xdisplay, rs_font[idx]);
|
||
|
if (!xfont) {
|
||
|
print_error(msg, rs_font[idx]);
|
||
|
rs_font[idx] = "fixed";
|
||
|
xfont = XLoadQueryFont(Xdisplay, rs_font[idx]);
|
||
|
if (!xfont) {
|
||
|
print_error(msg, rs_font[idx]);
|
||
|
ABORT();
|
||
|
}
|
||
|
}
|
||
|
TermWin.font = xfont;
|
||
|
|
||
|
#ifndef NO_BOLDFONT
|
||
|
/* fail silently */
|
||
|
if (init && rs_boldFont != NULL)
|
||
|
boldFont = XLoadQueryFont(Xdisplay, rs_boldFont);
|
||
|
#endif
|
||
|
|
||
|
#ifdef KANJI
|
||
|
if (TermWin.kanji)
|
||
|
XFreeFont(Xdisplay, TermWin.kanji);
|
||
|
|
||
|
/* load font or substitute */
|
||
|
xfont = XLoadQueryFont(Xdisplay, rs_kfont[idx]);
|
||
|
if (!xfont) {
|
||
|
print_error(msg, rs_kfont[idx]);
|
||
|
rs_kfont[idx] = "k14";
|
||
|
xfont = XLoadQueryFont(Xdisplay, rs_kfont[idx]);
|
||
|
if (!xfont) {
|
||
|
print_error(msg, rs_kfont[idx]);
|
||
|
ABORT();
|
||
|
}
|
||
|
}
|
||
|
TermWin.kanji = xfont;
|
||
|
#endif /* KANJI */
|
||
|
|
||
|
/* alter existing GC */
|
||
|
if (!init) {
|
||
|
XSetFont(Xdisplay, TermWin.gc, TermWin.font->fid);
|
||
|
#if (MENUBAR_MAX)
|
||
|
menubar_expose();
|
||
|
#endif /* MENUBAR_MAX */
|
||
|
}
|
||
|
/* set the sizes */
|
||
|
{
|
||
|
|
||
|
int i, cw, fh, fw = 0;
|
||
|
|
||
|
fw = TermWin.font->min_bounds.width;
|
||
|
fh = TermWin.font->ascent + TermWin.font->descent;
|
||
|
|
||
|
D_X11(("Font information: Ascent == %hd, Descent == %hd\n", TermWin.font->ascent, TermWin.font->descent));
|
||
|
if (TermWin.font->min_bounds.width == TermWin.font->max_bounds.width)
|
||
|
TermWin.fprop = 0; /* Mono-spaced (fixed width) font */
|
||
|
else
|
||
|
TermWin.fprop = 1; /* Proportional font */
|
||
|
if (TermWin.fprop == 1)
|
||
|
for (i = TermWin.font->min_char_or_byte2;
|
||
|
i <= TermWin.font->max_char_or_byte2; i++) {
|
||
|
cw = TermWin.font->per_char[i].width;
|
||
|
MAX_IT(fw, cw);
|
||
|
}
|
||
|
/* not the first time thru and sizes haven't changed */
|
||
|
if (fw == TermWin.fwidth && fh == TermWin.fheight)
|
||
|
return; /* TODO: not return; check KANJI if needed */
|
||
|
|
||
|
TermWin.fwidth = fw;
|
||
|
TermWin.fheight = fh;
|
||
|
}
|
||
|
|
||
|
/* check that size of boldFont is okay */
|
||
|
#ifndef NO_BOLDFONT
|
||
|
TermWin.boldFont = NULL;
|
||
|
if (boldFont != NULL) {
|
||
|
int i, cw, fh, fw = 0;
|
||
|
|
||
|
fw = boldFont->min_bounds.width;
|
||
|
fh = boldFont->ascent + boldFont->descent;
|
||
|
if (TermWin.fprop == 0) { /* bold font must also be monospaced */
|
||
|
if (fw != boldFont->max_bounds.width)
|
||
|
fw = -1;
|
||
|
} else {
|
||
|
for (i = 0; i < 256; i++) {
|
||
|
if (!isprint(i))
|
||
|
continue;
|
||
|
cw = boldFont->per_char[i].width;
|
||
|
MAX_IT(fw, cw);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fw == TermWin.fwidth && fh == TermWin.fheight)
|
||
|
TermWin.boldFont = boldFont;
|
||
|
}
|
||
|
#endif /* NO_BOLDFONT */
|
||
|
|
||
|
set_colorfgbg();
|
||
|
|
||
|
TermWin.width = TermWin.ncol * TermWin.fwidth;
|
||
|
TermWin.height = TermWin.nrow * TermWin.fheight;
|
||
|
|
||
|
szHint.width_inc = TermWin.fwidth;
|
||
|
szHint.height_inc = TermWin.fheight;
|
||
|
|
||
|
szHint.min_width = szHint.base_width + szHint.width_inc;
|
||
|
szHint.min_height = szHint.base_height + szHint.height_inc;
|
||
|
|
||
|
szHint.width = szHint.base_width + TermWin.width;
|
||
|
szHint.height = szHint.base_height + TermWin.height;
|
||
|
#if (MENUBAR_MAX)
|
||
|
szHint.height += (delay_menu_drawing ? menuBar_TotalHeight() : 0);
|
||
|
#endif
|
||
|
|
||
|
szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
|
||
|
|
||
|
if (!init) {
|
||
|
font_change_count++;
|
||
|
resize();
|
||
|
}
|
||
|
return;
|
||
|
#undef IDX2FNUM
|
||
|
#undef FNUM2IDX
|
||
|
#undef FNUM_RANGE
|
||
|
}
|