+2.5 Sun Mar 28 04:05:51 CEST 2004
+ - the usual sprinkled little code cleanups.
+ - support more 8-bit controls.
+ - more informative error messages.
+ - fix some minor memleaks and possible memory corruptions.
+ - the use of exception handling allowed the following improvements:
+ - no longer block when waiting for completion of escape sequences
+ (e.g. printf '\e';sleep 3;printf 'c' will no longer block).
+ - rxvtc usage errors should no longer kill rxvtd (debian bug #237510).
+
2.4 Tue Mar 16 07:06:51 CET 2004
- fix stupid double-free() bug on exit.
- implement xterm private mode 1049.
-COMMENT(-- $Id: versioninfo.yo,v 1.5 2004-03-16 06:00:41 pcg Exp $ --)
+COMMENT(-- $Id: versioninfo.yo,v 1.6 2004-03-28 02:07:08 pcg Exp $ --)
DEFINEMACRO(RXVTNAME)(0)
(rxvt)
DEFINEMACRO(RXVTDATE)(0)
- (2004-03-16)
+ (2004-03-28)
DEFINEMACRO(RXVTVERSION)(0)
- (2.4)
+ (2.5)
DEFINEMACRO(RXVTMAINT)(0)
(Marc A. Lehmann)
DEFINEMACRO(RXVTMAINTEMAIL)(0)
/*----------------------------------------------------------------------*/
+#define IS_CONTROL(ch) !((ch) & 0xffffff60UL)
+
+// exception thrown when the command parser runs out of input data
+class out_of_input { } out_of_input;
+
/*{{{ Convert the keypress event into a string */
void
rxvt_term::lookup_key (XKeyEvent &ev)
{
Status status_return;
+#if 0
#ifdef X_HAVE_UTF8_STRING
if (enc_utf8 && 0) // currently disabled, doesn't seem to work, nor is useful
len = Xutf8LookupString (Input_Context, &ev, (char *)kbuf,
KBUFSZ, &keysym, &status_return);
else
#endif
+#endif
{
wchar_t wkbuf[KBUFSZ + 1];
unsigned int
rxvt_term::cmd_write (const unsigned char *str, unsigned int count)
{
- unsigned int n, s;
+ unsigned int n, s;
n = cmdbuf_ptr - cmdbuf_base;
- s = cmdbuf_base + BUFSIZ - 1 - cmdbuf_endp;
+ s = cmdbuf_base + CBUFSIZ - 1 - cmdbuf_endp;
if (n > 0 && s < count)
{
if (count > s)
{
- rxvt_print_error ("data loss: cmd_write too large");
+ rxvt_warn ("data loss: cmd_write too large, continuing.\n");
count = s;
}
cmdbuf_ptr = cmdbuf_base;
cmdbuf_endp = cmdbuf_ptr + n;
- n = read (cmd_fd, cmdbuf_endp, BUFSIZ - n);
+ n = read (cmd_fd, cmdbuf_endp, CBUFSIZ - n);
if (n > 0)
{
tt_write (0, 0);
else if (revents & EVENT_READ)
{
- bool flag = true;
-
// loop, but don't allow a single term to monopolize us
// the number of loops is fully arbitrary, and thus wrong
- while (flag && pty_fill ())
+ while (pty_fill ())
{
if (!seen_input)
{
seen_input = 1;
/* once we know the shell is running, send the screen size. Again! */
+ // I don't know why, btw.
tt_winch ();
}
}
}
-bool
-rxvt_term::cmd_parse ()
-{
- bool flag = false;
- unicode_t ch = NOCHAR;
-
- for (;;)
- {
- if (ch == NOCHAR)
- ch = next_char ();
-
- if (ch == NOCHAR) // TODO: improve
- break;
-
- if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r')
- {
- /* Read a text string from the input buffer */
- unicode_t buf[BUFSIZ];
- bool refreshnow = false;
- int nlines = 0;
- unicode_t *str = buf;
-
- *str++ = ch;
-
- for (;;)
- {
- ch = next_char ();
-
- if (ch == NOCHAR || (ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r'))
- break;
- else
- {
- *str++ = ch;
-
- if (ch == '\n')
- {
- nlines++;
- refresh_count++;
-
- if (! (Options & Opt_jumpScroll)
- || (refresh_count >= (refresh_limit * (TermWin.nrow - 1))))
- {
- refreshnow = true;
- flag = false;
- ch = NOCHAR;
- break;
- }
-
- // scr_add_lines only works for nlines < TermWin.nrow - 1.
- if (nlines >= TermWin.nrow - 1)
- {
- scr_add_lines (buf, nlines, str - buf);
- nlines = 0;
- str = buf;
- }
- }
-
- if (str >= buf + BUFSIZ)
- {
- ch = NOCHAR;
- break;
- }
- }
- }
-
- scr_add_lines (buf, nlines, str - buf);
-
- /*
- * If there have 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 (refreshnow)
- {
- if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
- refresh_limit++;
-
- scr_refresh (refresh_type);
- }
-
- }
- else
- {
- switch (ch)
- {
- default:
- process_nonprinting (ch);
- break;
- case C0_ESC: /* escape char */
- process_escape_seq ();
- break;
- /*case 0x9b: */ /* CSI */
- /* process_csi_seq (); */
- }
-
- ch = NOCHAR;
- }
- }
-
- return flag;
-}
-
-// read the next character, currently handles UTF-8
-// will probably handle all sorts of other stuff in the future
-unicode_t
-rxvt_term::next_char ()
-{
- while (cmdbuf_ptr < cmdbuf_endp)
- {
- // assume 0x20 .. 0x7f to be ascii ALWAYS (all shift-states etc.) uh-oh
- if ((*cmdbuf_ptr <= 0x7f && 0x20 <= *cmdbuf_ptr)
- || !*cmdbuf_ptr)
- return *cmdbuf_ptr++;
-
- wchar_t wc;
- size_t len = mbrtowc (&wc, (char *)cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
-
- if (len == (size_t)-2)
- {
- // the mbstate stores incomplete sequences. didn't know this :/
- cmdbuf_ptr = cmdbuf_endp;
- break;
- }
-
- if (len == (size_t)-1)
- return *cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
-
- // assume wchar == unicode
- cmdbuf_ptr += len;
- return wc;
- }
-
- return NOCHAR;
-}
-
-/* rxvt_cmd_getc () - Return next input character */
-/*
- * Return the next input character after first passing any keyboard input
- * to the command.
- */
-unicode_t
-rxvt_term::cmd_getc ()
-{
- for (;;)
- {
- unicode_t c = next_char ();
- if (c != NOCHAR)
- return c;
-
- // incomplete sequences should occur rarely, still, a better solution
- // would be preferred. either setjmp/longjmp or better design.
- fcntl (cmd_fd, F_SETFL, 0);
- pty_fill ();
- fcntl (cmd_fd, F_SETFL, O_NONBLOCK);
- }
-}
-
#ifdef POINTER_BLANK
void
rxvt_term::pointer_unblank ()
break;
case SelectionClear:
- display->set_selection_owner (0);
+ selection_clear ();
break;
case SelectionNotify:
/*}}} */
+bool
+rxvt_term::cmd_parse ()
+{
+ bool flag = false;
+ unicode_t ch = NOCHAR;
+ unsigned char *seq_begin; // remember start of esc-sequence here
+
+ for (;;)
+ {
+ if (ch == NOCHAR)
+ {
+ seq_begin = cmdbuf_ptr;
+ ch = next_char ();
+ }
+
+ if (ch == NOCHAR) // TODO: improve
+ break;
+
+ if (!IS_CONTROL (ch) || ch == '\t' || ch == '\n' || ch == '\r')
+ {
+ /* Read a text string from the input buffer */
+ unicode_t buf[UBUFSIZ];
+ bool refreshnow = false;
+ int nlines = 0;
+ unicode_t *str = buf;
+
+ *str++ = ch;
+
+ for (;;)
+ {
+ seq_begin = cmdbuf_ptr;
+ ch = next_char ();
+
+ if (ch == NOCHAR || (IS_CONTROL (ch) && ch != '\t' && ch != '\n' && ch != '\r'))
+ break;
+
+ *str++ = ch;
+
+ if (ch == '\n')
+ {
+ nlines++;
+ refresh_count++;
+
+ if (! (Options & Opt_jumpScroll)
+ || (refresh_count >= (refresh_limit * (TermWin.nrow - 1))))
+ {
+ refreshnow = true;
+ flag = true;
+ ch = NOCHAR;
+ break;
+ }
+
+ // scr_add_lines only works for nlines < TermWin.nrow - 1.
+ if (nlines >= TermWin.nrow - 1)
+ {
+ scr_add_lines (buf, nlines, str - buf);
+ nlines = 0;
+ str = buf;
+ }
+ }
+
+ if (str >= buf + UBUFSIZ)
+ {
+ ch = NOCHAR;
+ break;
+ }
+ }
+
+ scr_add_lines (buf, nlines, str - buf);
+
+ /*
+ * If there have 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 (refreshnow)
+ {
+ if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
+ refresh_limit++;
+
+ scr_refresh (refresh_type);
+ }
+
+ }
+ else
+ {
+ try
+ {
+ process_nonprinting (ch);
+ }
+ catch (const class out_of_input &o)
+ {
+ // we ran out of input, retry later
+ cmdbuf_ptr = seq_begin;
+ break;
+ }
+
+ ch = NOCHAR;
+ }
+ }
+
+ return flag;
+}
+
+// read the next character
+unicode_t
+rxvt_term::next_char ()
+{
+ while (cmdbuf_ptr < cmdbuf_endp)
+ {
+ // assume 7-bit to be ascii ALWAYS
+ if (*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b)
+ return *cmdbuf_ptr++;
+
+ wchar_t wc;
+ size_t len = mbrtowc (&wc, (char *)cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
+
+ if (len == (size_t)-2)
+ {
+ // the mbstate stores incomplete sequences. didn't know this :/
+ cmdbuf_ptr = cmdbuf_endp;
+ break;
+ }
+
+ if (len == (size_t)-1)
+ return *cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
+
+ // assume wchar == unicode
+ cmdbuf_ptr += len;
+ return wc;
+ }
+
+ return NOCHAR;
+}
+
+/* rxvt_cmd_getc () - Return next input character */
+/*
+ * Return the next input character after first passing any keyboard input
+ * to the command.
+ */
+unicode_t
+rxvt_term::cmd_getc ()
+{
+ unicode_t c = next_char ();
+
+ if (c == NOCHAR)
+ throw out_of_input;
+
+ return c;
+}
+
/*{{{ print pipe */
/*----------------------------------------------------------------------*/
#ifdef PRINTPIPE
FILE *stream = popen (rs[Rs_print_pipe], "w");
if (stream == NULL)
- rxvt_print_error ("can't open printer pipe");
+ rxvt_warn ("can't open printer pipe, not printing.\n");
+
return stream;
}
rxvt_term::pclose_printer (FILE *stream)
{
fflush (stream);
- /* pclose () reported not to work on SunOS 4.1.3 */
-# if defined (__sun__) /* TODO: RESOLVE THIS */
- /* pclose works provided SIGCHLD handler uses waitpid */
- return pclose (stream); /* return fclose (stream); */
-# else
return pclose (stream);
-# endif
}
/*
void
rxvt_term::process_print_pipe ()
{
- int done;
- FILE *fd;
+ int done;
+ FILE *fd;
if ((fd = popen_printer ()) == NULL)
return;
*/
for (done = 0; !done;)
{
- unsigned char buf[8];
- unsigned char ch;
- unsigned int i, len;
+ unsigned char buf[8];
+ unicode_t ch;
+ unsigned int i, len;
if ((ch = cmd_getc ()) != C0_ESC)
{
break; /* done = 1 */
}
}
+
for (i = 0; i < len; i++)
if (putc (buf[i], fd) == EOF)
{
}
}
}
+
pclose_printer (fd);
}
#endif /* PRINTPIPE */
/*{{{ process non-printing single characters */
void
-rxvt_term::process_nonprinting (unsigned char ch)
+rxvt_term::process_nonprinting (unicode_t ch)
{
switch (ch)
{
+ case C0_ESC:
+ process_escape_seq ();
+ break;
case C0_ENQ: /* terminal Status */
if (rs[Rs_answerbackstring])
tt_write (
case C0_SI: /* shift in - acs */
scr_charset_choose (0);
break;
+
+ // 8-bit controls
+ case 0x90: /* DCS */
+ process_dcs_seq ();
+ break;
+ case 0x9b: /* CSI */
+ process_csi_seq ();
+ break;
+ case 0x9d: /* CSI */
+ process_osc_seq ();
+ break;
}
}
/*}}} */
/*{{{ process VT52 escape sequences */
void
-rxvt_term::process_escape_vt52 (unsigned char ch)
+rxvt_term::process_escape_vt52 (unicode_t ch)
{
int row, col;
void
rxvt_term::process_escape_seq ()
{
- unsigned char ch = cmd_getc ();
+ unicode_t ch = cmd_getc ();
if (PrivateModes & PrivMode_vt52)
{
void
rxvt_term::process_csi_seq ()
{
- unsigned char ch, priv, i;
- unsigned int nargs, p;
- int n, ndef;
- int arg[ESC_ARGS];
+ unicode_t ch, priv, i;
+ unsigned int nargs, p;
+ int n, ndef;
+ int arg[ESC_ARGS];
for (nargs = ESC_ARGS; nargs > 0;)
arg[--nargs] = 0;
priv = ch;
ch = cmd_getc ();
}
+
/* read any numerical arguments */
for (n = -1; ch < CSI_ICH; )
{
arg[nargs++] = n;
n = -1;
}
- else if (ch == '\b')
- {
- scr_backspace ();
- }
- else if (ch == C0_ESC)
- {
- process_escape_seq ();
- return;
- }
- else if (ch < ' ')
- {
- process_nonprinting (ch);
- }
+ else if (IS_CONTROL (ch))
+ process_nonprinting (ch);
+
ch = cmd_getc ();
}
case CSI_78: /* DECREQTPARM */
if (arg[0] == 0 || arg[0] == 1)
tt_printf ("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
- /* FALLTHROUGH */
+ break;
default:
break;
void
rxvt_term::process_window_ops (const int *args, unsigned int nargs)
{
- int x, y;
-#if 0
- char *s;
-#endif
+ int x, y;
XWindowAttributes wattr;
- Window wdummy;
+ Window wdummy;
if (nargs == 0)
return;
+
switch (args[0])
{
- /*
- * commands
- */
+ /*
+ * commands
+ */
case 1: /* deiconify window */
XMapWindow (display->display, TermWin.parent[0]);
break;
set_widthheight ((unsigned int) (args[2] * TermWin.fwidth),
(unsigned int) (args[1] * TermWin.fheight));
break;
+
+ //case 9: NYI, TODO, restore maximized window or maximize window
default:
if (args[0] >= 24) /* set height (chars) */
set_widthheight ((unsigned int)TermWin.width,
(unsigned int) (args[1] * TermWin.fheight));
break;
- /*
- * reports - some output format copied from XTerm
- */
+
+
+ /*
+ * reports - some output format copied from XTerm
+ */
case 11: /* report window state */
XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
tt_printf ("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
tt_printf ("\033[4;%d;%dt", wattr.height, wattr.width);
break;
- case 18: /* report window size (chars) */
+ case 18: /* report text area size (chars) */
tt_printf ("\033[8;%d;%dt", TermWin.nrow, TermWin.ncol);
break;
+ case 19: /* report window size (chars) */
+ tt_printf ("\033[9;%d;%dt", TermWin.nrow, TermWin.ncol);
+ break;
#if 0 /* XXX: currently disabled due to security concerns */
case 20: /* report icon label */
XGetIconName (display->display, TermWin.parent[0], &s);
tt_printf ("\033]l%-.200s\234", s ? s : ""); /* 8bit ST */
break;
#endif
-
}
}
#endif
/*----------------------------------------------------------------------*/
/*
* get input up until STRING TERMINATOR (or BEL)
- * ends_how is terminator used. returned input must be free ()d
+ * ends_how is terminator used. returned input must be free ()d
*/
-unsigned char *
-rxvt_term::get_to_st (unsigned char *ends_how)
+unsigned char *
+rxvt_term::get_to_st (unicode_t &ends_how)
{
- int seen_esc = 0; /* seen escape? */
- unsigned int n = 0;
- unsigned char *s;
- unsigned char ch, string[STRING_MAX];
+ int seen_esc = 0; /* seen escape? */
+ unsigned int n = 0;
+ unsigned char *s;
+ unicode_t ch;
+ unsigned char string[STRING_MAX];
- for (; (ch = cmd_getc ());)
+ while ((ch = cmd_getc ()))
{
if (ch == C0_BEL
|| ch == CHAR_ST
|| (ch == 0x5c && seen_esc)) /* 7bit ST */
break;
+
if (ch == C0_ESC)
{
seen_esc = 1;
ch = ' '; /* translate '\t' to space */
else if (ch < 0x08 || (ch > 0x0d && ch < 0x20))
return NULL; /* other control character - exit */
+
if (n < sizeof (string) - 1)
string[n++] = ch;
+
seen_esc = 0;
}
+
string[n++] = '\0';
+
if ((s = (unsigned char *)rxvt_malloc (n)) == NULL)
return NULL;
- *ends_how = (ch == 0x5c ? C0_ESC : ch);
+
+ ends_how = (ch == 0x5c ? C0_ESC : ch);
STRNCPY (s, string, n);
return s;
}
void
rxvt_term::process_dcs_seq ()
{
- unsigned char eh, *s;
+ unsigned char *s;
+ unicode_t eh;
+
/*
* Not handled yet
*/
- s = get_to_st (&eh);
+ s = get_to_st (eh);
if (s)
free (s);
+
return;
}
void
rxvt_term::process_osc_seq ()
{
- unsigned char ch, eh, *s;
- int arg;
+ unicode_t ch, eh;
+ int arg;
ch = cmd_getc ();
for (arg = 0; isdigit (ch); ch = cmd_getc ())
if (ch == ';')
{
- s = get_to_st (&eh);
+ unsigned char *s = get_to_st (eh);
+
if (s)
{
/*
#endif
else
xterm_seq (arg, (char *)s, eh);
+
free (s);
}
}
void
rxvt_term::xterm_seq (int op, const char *str, unsigned char resp __attribute__ ((unused)))
{
- int changed = 0;
- int color;
- char *buf, *name;
+ int changed = 0;
+ int color;
+ char *buf, *name;
assert (str != NULL);
switch (op)
set_title (str);
/* FALLTHROUGH */
case XTerm_iconName:
- set_iconName (str);
+ set_icon_name (str);
break;
case XTerm_title:
set_title (str);
{
if ((name = STRCHR (buf, ';')) == NULL)
break;
+
*name++ = '\0';
color = atoi (buf);
+
if (color < 0 || color >= TOTAL_COLORS)
break;
+
if ((buf = STRCHR (name, ';')) != NULL)
*buf++ = '\0';
+
set_window_color (color + minCOLOR, name);
}
break;
set_window_color (Color_bg, str);
break;
case XTerm_logfile:
+ // TODO, when secure mode?
break;
case XTerm_font:
change_font (str);
}
break;
#endif
-
}
}
/*----------------------------------------------------------------------*/
int
rxvt_term::privcases (int mode, unsigned long bit)
{
- int state;
+ int state;
if (mode == 's')
{
state = (mode == 't') ? ! (PrivateModes & bit) : mode;
PrivMode (state, bit);
}
+
return state;
}
void
rxvt_term::process_terminal_mode (int mode, int priv __attribute__ ((unused)), unsigned int nargs, const int *arg)
{
- unsigned int i, j;
- int state;
+ unsigned int i, j;
+ int state;
+
static const struct
{
const int argval;
const unsigned long bit;
}
+
argtopriv[] = {
{ 1, PrivMode_aplCUR },
{ 2, PrivMode_vt52 },
/* case 8: - auto repeat, can't do on a per window basis */
case 9: /* X10 mouse reporting */
if (state) /* orthogonal */
- PrivateModes &= ~ (PrivMode_MouseX11);
+ PrivateModes &= ~PrivMode_MouseX11;
break;
#ifdef menuBar_esc
case menuBar_esc:
/* case 67: - backspace key */
case 1000: /* X11 mouse reporting */
if (state) /* orthogonal */
- PrivateModes &= ~ (PrivMode_MouseX10);
+ PrivateModes &= ~PrivMode_MouseX10;
break;
#if 0
case 1001:
case 1049: /* better secondary screen w/ clearing, but not fully implemented */
if (current_screen != PRIMARY)
scr_erase_screen (2);
+
scr_change_screen (state);
/* FALLTHROUGH */
default:
void
rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
{
- unsigned int i;
- short rendset;
- int rendstyle;
+ unsigned int i;
+ short rendset;
+ int rendstyle;
if (nargs == 0)
{
scr_rendition (0, ~RS_None);
return;
}
+
for (i = 0; i < nargs; i++)
{
rendset = -1;
void
rxvt_term::process_graphics ()
{
- unsigned char ch, cmd = cmd_getc ();
+ unicode_t ch, cmd = cmd_getc ();
if (cmd == 'Q')
{ /* query graphics */
XGCValues v;
v.foreground = r->PixColors[fg];
- v.background = r->PixColors[bg];
v.font = f->fid;
if (enc2b)
if (bg == Color_bg && !slow)
{
+ v.background = r->PixColors[bg];
XChangeGC (d.display->display, TGC, GCForeground | GCBackground | GCFont, &v);
XDrawImageString16 (d.display->display, d, TGC, x, y + base, xc, len);
}
if (bg == Color_bg && !slow)
{
+ v.background = r->PixColors[bg];
XChangeGC (d.display->display, TGC, GCForeground | GCBackground | GCFont, &v);
XDrawImageString (d.display->display, d, TGC, x, y + base, xc, len);
}
#endif
#if IOM_IO
- fd_set rfd, wfd, efd;
+ fd_set rfd, wfd;
FD_ZERO (&rfd);
FD_ZERO (&wfd);
if (!to && !fds) //TODO: also check idle_watchers and check_watchers
break; // no events
- fds = select (fds, &rfd, &wfd, &efd, to);
+ fds = select (fds, &rfd, &wfd, NULL, to);
# if IOM_TIME
set_now ();
# endif
if (display)
{
+ selection_clear ();
+
+#ifdef MENUBAR
+ if (menubarGC) XFreeGC (display->display, menubarGC);
+#endif
+#ifdef XTERM_SCROLLBAR
+ if (xscrollbarGC) XFreeGC (display->display, xscrollbarGC);
+ if (ShadowGC) XFreeGC (display->display, ShadowGC);
+#endif
+#ifdef PLAIN_SCROLLBAR
+ if (pscrollbarGC) XFreeGC (display->display, pscrollbarGC);
+#endif
+#ifdef NEXT_SCROLLBAR
+ if (blackGC) XFreeGC (display->display, blackGC);
+ if (whiteGC) XFreeGC (display->display, whiteGC);
+ if (grayGC) XFreeGC (display->display, grayGC);
+ if (darkGC) XFreeGC (display->display, darkGC);
+ if (stippleGC) XFreeGC (display->display, stippleGC);
+ if (dimple) XFreePixmap (display->display, dimple);
+ if (upArrow) XFreePixmap (display->display, upArrow);
+ if (downArrow) XFreePixmap (display->display, downArrow);
+ if (upArrowHi) XFreePixmap (display->display, upArrowHi);
+ if (downArrowHi) XFreePixmap (display->display, downArrowHi);
+#endif
+#if defined(MENUBAR) || defined(RXVT_SCROLLBAR)
+ if (topShadowGC) XFreeGC (display->display, topShadowGC);
+ if (botShadowGC) XFreeGC (display->display, botShadowGC);
+ if (scrollbarGC) XFreeGC (display->display, scrollbarGC);
+#endif
+ if (TermWin.gc) XFreeGC (display->display, TermWin.gc);
+
#if defined(MENUBAR) && (MENUBAR_MAX > 1)
delete menuBar.drawable;
//if (menuBar.win)
scr_release ();
+ /* clear all resources */
+ for (int i = 0; i < allocated.size (); i++)
+ free (allocated[i]);
+
+ free (selection.text);
+ // TODO: manage env vars in child only(!)
free (env_windowid);
free (env_display);
free (env_term);
free (env_colorfgbg);
free (locale);
+#if 0
free (codeset);
+#endif
delete envv;
delete argv;
/*----------------------------------------------------------------------*/
/* rxvt_init () */
-/* LIBPROTO */
-rxvt_t
-rxvt_init (int argc, const char *const *argv)
-{
- SET_R (new rxvt_term);
-
- if (!GET_R->init_vars () || !GET_R->init (argc, argv))
- {
- delete GET_R;
- SET_R (0);
- }
-
- return GET_R;
-}
-
-static int (*old_xerror_handler) (Display *dpy, XErrorEvent *event);
-
-void
-rxvt_init_signals ()
-{
- /* install exit handler for cleanup */
-#if 0
-#ifdef HAVE_ATEXIT
- atexit (rxvt_clean_exit);
-#else
-#endif
-#endif
-
- struct sigaction sa;
-
- sigfillset (&sa.sa_mask);
- sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
- sa.sa_handler = SIG_IGN; sigaction (SIGHUP , &sa, 0);
- sa.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa, 0);
- sa.sa_handler = rxvt_Exit_signal; sigaction (SIGINT , &sa, 0);
- sa.sa_handler = rxvt_Exit_signal; sigaction (SIGQUIT, &sa, 0);
- sa.sa_handler = rxvt_Exit_signal; sigaction (SIGTERM, &sa, 0);
- sa.sa_handler = rxvt_Child_signal; sigaction (SIGCHLD, &sa, 0);
-
- /* need to trap SIGURG for SVR4 (Unixware) rlogin */
- /* signal (SIGURG, SIG_DFL); */
-
- old_xerror_handler = XSetErrorHandler ((XErrorHandler) rxvt_xerror_handler);
- //XSetIOErrorHandler ((XErrorHandler) rxvt_xioerror_handler);
-}
-
bool
rxvt_term::init (int argc, const char *const *argv)
{
+ SET_R (this);
+
+ if (!init_vars ())
+ return false;
+
/*
* Save and then give up any super-user privileges
* If we need privileges in any area then we must specifically request it.
return true;
}
+static int (*old_xerror_handler) (Display *dpy, XErrorEvent *event);
+
+void
+rxvt_init_signals ()
+{
+ /* install exit handler for cleanup */
+#if 0
+#ifdef HAVE_ATEXIT
+ atexit (rxvt_clean_exit);
+#else
+#endif
+#endif
+
+ struct sigaction sa;
+
+ sigfillset (&sa.sa_mask);
+ sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+ sa.sa_handler = SIG_IGN; sigaction (SIGHUP , &sa, 0);
+ sa.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa, 0);
+ sa.sa_handler = rxvt_Exit_signal; sigaction (SIGINT , &sa, 0);
+ sa.sa_handler = rxvt_Exit_signal; sigaction (SIGQUIT, &sa, 0);
+ sa.sa_handler = rxvt_Exit_signal; sigaction (SIGTERM, &sa, 0);
+ sa.sa_handler = rxvt_Child_signal; sigaction (SIGCHLD, &sa, 0);
+
+ /* need to trap SIGURG for SVR4 (Unixware) rlogin */
+ /* signal (SIGURG, SIG_DFL); */
+
+ old_xerror_handler = XSetErrorHandler ((XErrorHandler) rxvt_xerror_handler);
+ //XSetIOErrorHandler ((XErrorHandler) rxvt_xioerror_handler);
+}
+
/* ------------------------------------------------------------------------- *
* SIGNAL HANDLING & EXIT HANDLER *
* ------------------------------------------------------------------------- */
{
signal (sig, SIG_DFL);
#ifdef DEBUG_CMD
- rxvt_print_error ("signal %d", sig);
+ rxvt_warn ("caught signal %d, exiting.\n", sig);
#endif
rxvt_clean_exit ();
kill (getpid (), sig);
#else
char *name;
- if (XFetchName (display->display, TermWin.parent[0], &name) == 0)
+ if (!XFetchName (display->display, TermWin.parent[0], &name))
name = NULL;
+
if (name == NULL || STRCMP (name, str))
XStoreName (display->display, TermWin.parent[0], str);
+
if (name)
XFree (name);
#endif
}
void
-rxvt_term::set_iconName (const char *str)
+rxvt_term::set_icon_name (const char *str)
{
#ifndef SMART_WINDOW_TITLE
XSetIconName (display->display, TermWin.parent[0], str);
#else
char *name;
- if (XGetIconName (display->display, TermWin.parent[0], &name))
+ if (!XGetIconName (display->display, TermWin.parent[0], &name))
name = NULL;
+
if (name == NULL || STRCMP (name, str))
XSetIconName (display->display, TermWin.parent[0], str);
+
if (name)
XFree (name);
#endif
{
if (!screen_in_out->set (display, colour))
{
- rxvt_print_error ("can't allocate colour: %s", colour);
+ rxvt_warn ("can't get colour '%s', continuing without.\n", colour);
return false;
}
if (Input_Context == NULL)
{
- rxvt_print_error ("failed to create input context");
+ rxvt_warn ("failed to create input context, continuing without XIM.\n");
display->put_xim (input_method);
return false;
}
total_rows = TermWin.nrow + TermWin.saveLines;
-#ifdef DEBUG_STRICT
- for (i = 0; i < total_rows; i++)
- {
- if (screen.text[i])
- /* then so is screen.rend[i] */
- assert (screen.rend[i]);
- }
-#endif
-
delete talloc; talloc = 0;
delete ralloc; ralloc = 0;
void
rxvt_term::scr_cursor (int mode)
{
- screen_t *s;
+ screen_t *s;
D_SCREEN ((stderr, "rxvt_scr_cursor (%c)", mode));
#if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
if (current_screen == SECONDARY)
- s = & (swap);
+ s = &swap;
else
#endif
- s = & (screen);
+ s = &screen;
+
switch (mode)
{
case SAVE:
set_font_style ();
break;
}
+
/* boundary check in case screen size changed between SAVE and RESTORE */
MIN_IT (s->cur.row, TermWin.nrow - 1);
MIN_IT (s->cur.col, TermWin.ncol - 1);
int
rxvt_term::scr_change_screen (int scrn)
{
- int i;
+ int i;
#if NSCREENS
- int offset;
+ int offset;
#endif
want_refresh = 1;
#endif
row = screen.cur.row + TermWin.saveLines;
- checksel = (selection.op
- && current_screen == selection.screen) ? 1 : 0;
+ checksel = selection.op && current_screen == selection.screen ? 1 : 0;
clearsel = 0;
stp = screen.text[row];
srp = screen.rend[row];
- for (i = 0; i < len;)
+ while (len--)
{
- c = str[i++];
- switch (c)
- {
- case '\t':
- scr_tab (1);
- continue;
- case '\n':
- if (screen.tlen[row] != -1) /* XXX: think about this */
- MAX_IT (screen.tlen[row], screen.cur.col);
- screen.flags &= ~Screen_WrapNext;
- if (screen.cur.row == screen.bscroll)
- scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
- else if (screen.cur.row < (TermWin.nrow - 1))
- row = (++screen.cur.row) + TermWin.saveLines;
- stp = screen.text[row]; /* _must_ refresh */
- srp = screen.rend[row]; /* _must_ refresh */
- continue;
- case '\r':
- if (screen.tlen[row] != -1) /* XXX: think about this */
- MAX_IT (screen.tlen[row], screen.cur.col);
- screen.flags &= ~Screen_WrapNext;
- screen.cur.col = 0;
- continue;
- default:
- if (c == 127)
- continue; /* yummmm..... */
- break;
- }
+ c = *str++;
+
+ if (c < 0x20)
+ switch (c)
+ {
+ case '\t':
+ scr_tab (1);
+ continue;
+
+ case '\n':
+ if (screen.tlen[row] != -1) /* XXX: think about this */
+ MAX_IT (screen.tlen[row], screen.cur.col);
+
+ screen.flags &= ~Screen_WrapNext;
+
+ if (screen.cur.row == screen.bscroll)
+ scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
+ else if (screen.cur.row < (TermWin.nrow - 1))
+ row = (++screen.cur.row) + TermWin.saveLines;
+
+ stp = screen.text[row]; /* _must_ refresh */
+ srp = screen.rend[row]; /* _must_ refresh */
+ continue;
+
+ case '\r':
+ if (screen.tlen[row] != -1) /* XXX: think about this */
+ MAX_IT (screen.tlen[row], screen.cur.col);
+
+ screen.flags &= ~Screen_WrapNext;
+ screen.cur.col = 0;
+ continue;
+ }
if (checksel /* see if we're writing within selection */
&& !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
// rely on wcwidth to tell us the character width, at least for non-latin1
// do wcwidth before further replacements, as wcwidth says that line-drawing
- // characters have width -1 (DOH!) on gnu/linux sometimes.
+ // characters have width -1 (DOH!) on GNU/Linux sometimes.
int width = c < 256 ? 1 : wcwidth (c);
if (charsets[screen.charset] == '0') // DEC SPECIAL
- switch (c)
- {
- // vt100 special graphics and line drawing
- case '`': c = 0x25c6; break; case '_': c = 0x0020; break;
- case 'a': c = 0x2592; break; case 'b': c = 0x2409; break; case 'c': c = 0x240c; break;
- case 'd': c = 0x240d; break; case 'e': c = 0x240a; break; case 'f': c = 0x00b0; break;
- case 'g': c = 0x00b1; break; case 'h': c = 0x2424; break; case 'i': c = 0x240b; break;
- case 'j': c = 0x2518; break; case 'k': c = 0x2510; break; case 'l': c = 0x250c; break;
- case 'm': c = 0x2514; break; case 'n': c = 0x253c; break; case 'o': c = 0x23ba; break;
- case 'p': c = 0x23bb; break; case 'q': c = 0x2500; break; case 'r': c = 0x23bc; break;
- case 's': c = 0x23bd; break; case 't': c = 0x251c; break; case 'u': c = 0x2524; break;
- case 'v': c = 0x2534; break; case 'w': c = 0x252c; break; case 'x': c = 0x2502; break;
- case 'y': c = 0x2264; break; case 'z': c = 0x2265; break; case '{': c = 0x03c0; break;
- case '|': c = 0x2260; break; case '}': c = 0x00a3; break; case '~': c = 0x00b7; break;
- }
+ {
+ // vt100 special graphics and line drawing
+ static uint16_t vt100_0[32] = { // 5f .. 7e
+ 0x0020, 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
+ 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
+ 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534,
+ 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7,
+ };
+
+ if (c >= 0x5f && c <= 0x7e)
+ {
+ c = vt100_0[c - 0x5f];
+ width = 1;
+ }
+ }
if (width > 0)
{
void
rxvt_term::scr_tab (int count)
{
- int i, x;
+ int i, x;
D_SCREEN ((stderr, "rxvt_scr_tab (%d)", count));
want_refresh = 1;
i = x = screen.cur.col;
+
if (count == 0)
return;
else if (count > 0)
if (!--count)
break;
}
+
if (count)
x = TermWin.ncol - 1;
}
if (!++count)
break;
}
+
if (count)
x = 0;
}
+
if (x != screen.cur.col)
scr_gotorc (0, x, R_RELATIVE);
}
void
rxvt_term::scr_erase_screen (int mode)
{
- int num;
- int32_t row, row_offset;
- rend_t ren;
- XGCValues gcvalue;
+ int num;
+ int32_t row, row_offset;
+ rend_t ren;
+ XGCValues gcvalue;
want_refresh = 1;
D_SCREEN ((stderr, "rxvt_scr_erase_screen (%d) at screen row: %d", mode, screen.cur.row));
default:
return;
}
+
refresh_type |= REFRESH_BOUNDS;
+
if (selection.op && current_screen == selection.screen
&& ((selection.beg.row >= row && selection.beg.row <= row + num)
|| (selection.end.row >= row
&& selection.end.row <= row + num)))
CLEAR_SELECTION ();
+
if (row >= TermWin.nrow) /* Out Of Bounds */
return;
+
MIN_IT (num, (TermWin.nrow - row));
+
if (rstyle & (RS_RVid | RS_Uline))
ren = (rend_t) ~RS_None;
else if (GET_BASEBG (rstyle) == Color_bg)
gcvalue.foreground = PixColors[Color_fg];
XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue);
}
+
for (; num--; row++)
{
scr_blank_screen_mem (screen.text, screen.rend,
void
rxvt_term::scr_insdel_lines (int count, int insdel)
{
- int end;
+ int end;
ZERO_SCROLLBACK ();
void
rxvt_term::scr_insdel_chars (int count, int insdel)
{
- int col, row;
- rend_t tr;
- text_t *stp;
- rend_t *srp;
- int16_t *slp;
+ int col, row;
+ rend_t tr;
+ text_t *stp;
+ rend_t *srp;
+ int16_t *slp;
want_refresh = 1;
ZERO_SCROLLBACK ();
stp = screen.text[row];
srp = screen.rend[row];
slp = & (screen.tlen[row]);
+
switch (insdel)
{
case INSERT:
stp[col] = stp[col - count];
srp[col] = srp[col - count];
}
+
if (*slp != -1)
{
*slp += count;
MIN_IT (*slp, TermWin.ncol);
}
+
if (selection.op && current_screen == selection.screen
&& ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
{
selection.end.col += count;
}
}
+
scr_blank_line (& (stp[screen.cur.col]), & (srp[screen.cur.col]),
(unsigned int)count, rstyle);
break;
+
case ERASE:
screen.cur.col += count; /* don't worry if > TermWin.ncol */
selection_check (1);
scr_blank_line (& (stp[screen.cur.col]), & (srp[screen.cur.col]),
(unsigned int)count, rstyle);
break;
+
case DELETE:
- tr = srp[TermWin.ncol - 1]
- & (RS_fgMask | RS_bgMask | RS_baseattrMask);
+ tr = srp[TermWin.ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask);
+
for (col = screen.cur.col; (col + count) < TermWin.ncol; col++)
{
stp[col] = stp[col + count];
srp[col] = srp[col + count];
}
+
scr_blank_line (& (stp[TermWin.ncol - count]),
& (srp[TermWin.ncol - count]),
(unsigned int)count, tr);
+
if (*slp == -1) /* break line continuation */
*slp = TermWin.ncol;
+
*slp -= count;
MAX_IT (*slp, 0);
+
if (selection.op && current_screen == selection.screen
&& ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
{
selection.end.col -= count;
}
}
+
break;
}
}
{
MAX_IT (top, 0);
MIN_IT (bot, (int)TermWin.nrow - 1);
+
if (top > bot)
return;
+
screen.tscroll = top;
screen.bscroll = bot;
scr_gotorc (0, 0, 0);
* C: set the cursor character (s)
*/
{
- unsigned char setoldcursor;
- rend_t ccol1, /* Cursor colour */
- ccol2; /* Cursor colour2 */
+ unsigned char setoldcursor;
+ rend_t ccol1, /* Cursor colour */
+ ccol2; /* Cursor colour2 */
showcursor = (screen.flags & Screen_VisibleCursor);
#ifdef CURSOR_BLINK
if (showcursor)
{
- srp = & (screen.rend[screen.cur.row + TermWin.saveLines]
- [screen.cur.col]);
+ srp = &(screen.rend[screen.cur.row + TermWin.saveLines][screen.cur.col]);
if (showcursor && TermWin.focus)
{
{
if (ocrow < TermWin.nrow
&& oldcursor.col < TermWin.ncol)
- {
- drawn_rend[ocrow][oldcursor.col] ^= (RS_RVid | RS_Uline);
- }
+ drawn_rend[ocrow][oldcursor.col] ^= (RS_RVid | RS_Uline);
+
if (TermWin.focus || !showcursor)
oldcursor.row = -1;
else
}
else if (!TermWin.focus)
setoldcursor = 1;
+
if (setoldcursor)
{
if (screen.cur.row + TermWin.view_start >= TermWin.nrow)
if (refresh_type == FAST_REFRESH && num_scr_allow && i
&& abs (i) < TermWin.nrow && !must_clear)
{
- int16_t nits;
- int j;
- rend_t *drp2;
- text_t *dtp2;
- int len, wlen;
+ int16_t nits;
+ int j;
+ rend_t *drp2;
+ text_t *dtp2;
+ int len, wlen;
j = TermWin.nrow;
wlen = len = -1;
{
selection_wait = Sel_none;
- rxvt_print_error ("data loss: timeout on INCR selection paste");
+ rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
}
/*
selection_request_time = tm;
selection_wait = Sel_normal;
+
for (i = Sel_Primary; i <= Sel_Clipboard; i++)
{
#if X_HAVE_UTF8_STRING
selection.text = NULL;
selection.len = 0;
CLEAR_SELECTION ();
+
+ if (display->selection_owner == this)
+ display->selection_owner = 0;
}
/* ------------------------------------------------------------------------- */
if (XGetSelectionOwner (display->display, XA_PRIMARY) == TermWin.vt)
display->set_selection_owner (this);
else
- rxvt_print_error ("can't get primary selection");
+ rxvt_warn ("can't get primary selection, ignoring.\n");
#if 0
XTextProperty ct;
else if (rq.target == xa[XA_TIMESTAMP] && selection.text)
{
XChangeProperty (display->display, rq.requestor, rq.property, XA_INTEGER,
- (8 * sizeof (Time)), PropModeReplace,
- (unsigned char *)&selection_time, 1);
+ (8 * sizeof (Time)), PropModeReplace,
+ (unsigned char *)&selection_time, 1);
ev.property = rq.property;
}
else if (rq.target == XA_STRING
-#define VERSION "2.4"
-#define VSTRING "20400"
-#define DATE "2004-03-16"
-#define LSMDATE "16MAR04"
-#define LIBVERSION "2:4:0"
+#define VERSION "2.5"
+#define VSTRING "20500"
+#define DATE "2004-03-28"
+#define LSMDATE "28MAR04"
+#define LIBVERSION "2:5:0"