--- rxvt-unicode/src/command.C 2003/11/25 11:52:42 1.3 +++ rxvt-unicode/src/command.C 2004/01/29 23:26:01 1.31 @@ -1,7 +1,7 @@ /*--------------------------------*-C-*---------------------------------* * File: command.c *----------------------------------------------------------------------* - * $Id: command.C,v 1.3 2003/11/25 11:52:42 pcg Exp $ + * $Id: command.C,v 1.31 2004/01/29 23:26:01 pcg Exp $ * * All portions of code are copyright by their respective author/s. * Copyright (c) 1992 John Bovey, University of Kent at Canterbury @@ -50,6 +50,8 @@ #include "version.h" #include "command.h" +#include + /*----------------------------------------------------------------------*/ /*{{{ Convert the keypress event into a string */ @@ -63,10 +65,8 @@ #ifdef DEBUG_CMD static int debug_key = 1; /* accessible by a debugger only */ #endif -#ifdef USE_XIM int valid_keysym; -#endif - unsigned char *kbuf = R->kbuf; + unsigned char kbuf[KBUFSZ]; /* * use Num_Lock to toggle Keypad on/off. If Num_Lock is off, allow an @@ -77,65 +77,82 @@ shft = (ev->state & ShiftMask); ctrl = (ev->state & ControlMask); meta = (ev->state & R->ModMetaMask); - if (R->numlock_state || (ev->state & R->ModNumLockMask)) { + + if (R->numlock_state || (ev->state & R->ModNumLockMask)) + { R->numlock_state = (ev->state & R->ModNumLockMask); PrivMode((!R->numlock_state), PrivMode_aplKP); - } + } + + kbuf[0] = 0; + #ifdef USE_XIM - if (R->Input_Context != NULL) { - Status status_return; + if (R->Input_Context) + { + Status status_return; - kbuf[0] = '\0'; #ifdef X_HAVE_UTF8_STRING - len = Xutf8LookupString(R->Input_Context, ev, (char *)kbuf, - KBUFSZ, &keysym, &status_return); -#else - len = XmbLookupString(R->Input_Context, ev, (char *)kbuf, - KBUFSZ, &keysym, &status_return); + if (R->enc_utf8 && 0) + len = Xutf8LookupString (R->Input_Context, ev, (char *)kbuf, + KBUFSZ, &keysym, &status_return); + else #endif - valid_keysym = ((status_return == XLookupKeySym) - || (status_return == XLookupBoth)); - } else { - len = XLookupString(ev, (char *)kbuf, KBUFSZ, &keysym, - &R->compose); - valid_keysym = 1; - } -#else /* USE_XIM */ - len = XLookupString(ev, (char *)kbuf, KBUFSZ, &keysym, - &R->compose); -/* - * map unmapped Latin[2-4]/Katakana/Arabic/Cyrillic/Greek entries -> Latin1 - * good for installations with correct fonts, but without XLOCALE - */ - if (!len) { - if ((keysym >= 0x0100) && (keysym < 0x0800)) { - kbuf[0] = (keysym & 0xFF); - kbuf[1] = '\0'; - len = 1; - } else - kbuf[0] = '\0'; - } -#endif /* USE_XIM */ + { + wchar_t wkbuf[KBUFSZ + 1]; -#ifdef USE_XIM - if (valid_keysym) + // the XOpenIM manpage lies about hardcoding the locale + // at the point of XOpenIM, so temporarily switch locales + if (R->rs[Rs_imLocale]) + SET_LOCALE (R->rs[Rs_imLocale]); + // assume wchar_t == unicode or better + len = XwcLookupString (R->Input_Context, ev, wkbuf, + KBUFSZ, &keysym, &status_return); + if (R->rs[Rs_imLocale]) + SET_LOCALE (R->locale); + + if (status_return == XLookupChars + || status_return == XLookupBoth) + { + wkbuf[len] = 0; + len = wcstombs ((char *)kbuf, wkbuf, KBUFSZ); + if (len < 0) + len = 0; + } + else + len = 0; + } + + valid_keysym = status_return == XLookupKeySym + || status_return == XLookupBoth; + } + else #endif - { + { + len = XLookupString (ev, (char *)kbuf, KBUFSZ, &keysym, &R->compose); + valid_keysym = !len; + } + + if (valid_keysym) + { /* for some backwards compatibility */ #if defined(HOTKEY_CTRL) || defined(HOTKEY_META) # ifdef HOTKEY_CTRL - if (ctrl) { + if (ctrl) # else - if (meta) { + if (meta) # endif - if (keysym == R->ks_bigfont) { + { + if (keysym == R->ks_bigfont) + { rxvt_change_font(aR_ 0, FONT_UP); return; - } else if (keysym == R->ks_smallfont) { + } + else if (keysym == R->ks_smallfont) + { rxvt_change_font(aR_ 0, FONT_DN); return; - } - } + } + } #endif if (R->TermWin.saveLines) { @@ -239,8 +256,8 @@ # ifdef META8_OPTION if (R->meta_char == C0_ESC) # endif - rxvt_tt_write(aR_ &ch, 1); - rxvt_tt_write(aR_ kbuf0, l); + R->tt_write (&ch, 1); + R->tt_write (kbuf0, l); return; } else #endif @@ -574,7 +591,7 @@ #endif /* nil */ ; } - } + } if (len <= 0) return; /* not mapped */ @@ -607,7 +624,7 @@ ) { const unsigned char ch = C0_ESC; - rxvt_tt_write(aR_ &ch, 1); + R->tt_write(&ch, 1); } #ifdef DEBUG_CMD if (debug_key) { /* Display keyboard buffer contents */ @@ -620,7 +637,7 @@ fprintf(stderr, "'\n"); } #endif /* DEBUG_CMD */ - rxvt_tt_write(aR_ kbuf, (unsigned int)len); + R->tt_write (kbuf, (unsigned int)len); } /*}}} */ @@ -634,7 +651,7 @@ unsigned int n, s; unsigned char *cmdbuf_base = R->cmdbuf_base, *cmdbuf_endp = R->cmdbuf_endp, - *cmdbuf_ptr = R->cmdbuf_ptr; + *cmdbuf_ptr = R->cmdbuf_ptr; n = cmdbuf_ptr - cmdbuf_base; s = cmdbuf_base + BUFSIZ - 1 - cmdbuf_endp; @@ -658,6 +675,40 @@ #endif /* MENUBAR_MAX */ void +rxvt_term::flush () +{ +#ifdef TRANSPARENT + if (want_full_refresh) + { + want_full_refresh = 0; + scr_clear (); + scr_touch (false); + want_refresh = 1; + } +#endif + + if (want_refresh) + { + scr_refresh (refresh_type); + rxvt_scrollbar_show (this, 1); +#ifdef USE_XIM + rxvt_IMSendSpot (this); +#endif + } + + XFlush (Xdisplay); +} + +void +rxvt_term::check_cb (check_watcher &w) +{ + SET_R (this); + SET_LOCALE (locale); + + flush (); +} + +void rxvt_term::process_x_events () { do @@ -665,30 +716,32 @@ XEvent xev; XNextEvent (Xdisplay, &xev); + #if defined(CURSOR_BLINK) - if ((Options & Opt_cursorBlink) - && xev.type == KeyPress) { - if (hidden_cursor) { + if ((Options & Opt_cursorBlink) && xev.type == KeyPress) + { + if (hidden_cursor) + { hidden_cursor = 0; want_refresh = 1; - } - want_keypress_time = 1; - } + } + + cursor_blink_ev.start (NOW + BLINK_INTERVAL); + } #endif #if defined(POINTER_BLANK) - if ((Options & Opt_pointerBlank) - && (pointerBlankDelay > 0)) { + if ((Options & Opt_pointerBlank) && pointerBlankDelay > 0) + { if (xev.type == MotionNotify || xev.type == ButtonPress - || xev.type == ButtonRelease) { - if (hidden_pointer) - rxvt_pointer_unblank(aR); - want_motion_time = 1; - } + || xev.type == ButtonRelease) + if (hidden_pointer) + pointer_unblank (); + if (xev.type == KeyPress && hidden_pointer == 0) - rxvt_pointer_blank (this); - } + pointer_blank (); + } #endif #ifdef USE_XIM @@ -699,101 +752,203 @@ while (XPending (Xdisplay)); } +#ifdef CURSOR_BLINK void -rxvt_term::x_cb (io_watcher &w, short revents) +rxvt_term::cursor_blink_cb (time_watcher &w) { - process_x_events (); + hidden_cursor = !hidden_cursor; + want_refresh = 1; + + w.start (w.at + BLINK_INTERVAL); } +#endif -// read the next character, currently handles UTF-8 -// will probably handle all sorts of other stuff in the future -static uint32_t -next_char (pR) +#ifdef TEXT_BLINK +void +rxvt_term::text_blink_cb (time_watcher &w) { - mbstate &s = R->mbstate; - - while (R->cmdbuf_ptr < R->cmdbuf_endp) + if (scr_refresh_rend (RS_Blink, RS_Blink)) { - uint8_t ch = *R->cmdbuf_ptr; + hidden_text = !hidden_text; + want_refresh = 1; + w.start (w.at + TEXT_BLINK_INTERVAL); + } +} +#endif - if (s.cnt) - { - if ((ch & 0xc0) == 0x80) - { - R->cmdbuf_ptr++; +void +rxvt_term::x_cb (io_watcher &w, short revents) +{ + SET_R (this); + SET_LOCALE (locale); - /* continuation */ - s.reg = (s.reg << 6) | (ch & 0x7f); + process_x_events (); +} - if (--s.cnt == 0 && s.reg >= 128) /* if !inrange then corruption or Racking */ - return s.reg; +bool +rxvt_term::pty_fill () +{ + ssize_t n = cmdbuf_endp - cmdbuf_ptr; - continue; - } - else - { - s.cnt = 0; - return s.orig; /* the _occasional_ non-utf-8 character may slip through... */ - } - } - - if ((ch & 0xc0) == 0xc0) - { - R->cmdbuf_ptr++; + memmove (cmdbuf_base, cmdbuf_ptr, n); + cmdbuf_ptr = cmdbuf_base; + cmdbuf_endp = cmdbuf_ptr + n; + + n = read (cmd_fd, cmdbuf_endp, BUFSIZ - n); - /* first byte */ - s.orig = ch; /* for broken encodings */ - s.reg = ch; - if ((ch & 0xe0) == 0xc0) { s.reg &= 0x1f; s.cnt = 1; } - if ((ch & 0xf0) == 0xe0) { s.reg &= 0x0f; s.cnt = 2; } - if ((ch & 0xf8) == 0xf0) { s.reg &= 0x07; s.cnt = 3; } - if ((ch & 0xfc) == 0xf8) { s.reg &= 0x03; s.cnt = 4; } - if ((ch & 0xfe) == 0xfc) { s.reg &= 0x01; s.cnt = 5; } - } - else - { - R->cmdbuf_ptr++; /* _occasional_ non-utf8 may slip through... */ - return ch; - } + if (n > 0) + { + cmdbuf_endp += n; + return true; } + else if (n < 0 && errno != EAGAIN) + destroy (); - return NOCHAR; + return false; } void rxvt_term::pty_cb (io_watcher &w, short revents) { - int n; - unsigned int count; + SET_R (this); + SET_LOCALE (locale); - if (count = (cmdbuf_endp - cmdbuf_ptr)) + if (revents & EVENT_WRITE) + tt_write (0, 0); + else if (revents & EVENT_READ) { - memmove (cmdbuf_base, cmdbuf_ptr, count); - cmdbuf_ptr = cmdbuf_base; - cmdbuf_endp = cmdbuf_ptr + count; - } - - - for (count = BUFSIZ - count; count; count -= n, cmdbuf_endp += n) - if ((n = read(cmd_fd, cmdbuf_endp, count)) > 0) - continue; - else if (n == 0 || (n < 0 && errno == EAGAIN)) - break; - else + 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 ()) { - rxvt_clean_exit(); - exit(EXIT_FAILURE); /* bad order of events? */ + if (!seen_input) + { + seen_input = 1; + /* once we know the shell is running, send the screen size. Again! */ + tt_winch (); + } + + uint32_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 */ + uint32_t buf[BUFSIZ]; + bool refreshnow = false; + int nlines = 0; + uint32_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; + } + } + + if (str >= buf + BUFSIZ) + { + ch = NOCHAR; + break; + } + } + } + + rxvt_scr_add_lines (this, 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: + rxvt_process_nonprinting (this, ch); + break; + case C0_ESC: /* escape char */ + rxvt_process_escape_seq (this); + break; + /*case 0x9b: */ /* CSI */ + /* rxvt_process_csi_seq (this); */ + } + + ch = NOCHAR; + } + } } + } +} - if (count != BUFSIZ) /* some characters read in */ +// read the next character, currently handles UTF-8 +// will probably handle all sorts of other stuff in the future +uint32_t +rxvt_term::next_char () +{ + while (cmdbuf_ptr < cmdbuf_endp) { - uint32_t c = next_char (this); + if (*cmdbuf_ptr < 0x80) // assume < 0x80 to be ascii ALWAYS (all shift-states etc.) uh-oh + return *cmdbuf_ptr++; -#if 0 - if (c != NOCHAR) - return c; -#endif + wchar_t wc; + int len = mbrtowc (&wc, (char *)cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, &mbstate.mbs); + + if (len == (size_t)-2) + return NOCHAR; + + 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 */ @@ -805,6 +960,20 @@ uint32_t rxvt_cmd_getc(pR) { + for (;;) + { + uint32_t c = R->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 (R->cmd_fd, F_SETFL, 0); + R->pty_fill (); + fcntl (R->cmd_fd, F_SETFL, O_NONBLOCK); + } + +#if 0 #define TIMEOUT_USEC 5000 fd_set readfds; int quick_timeout, select_res; @@ -814,55 +983,11 @@ struct timeval tp; #endif - uint32_t c = next_char (aR); - if (c != NOCHAR) - return c; - for (;;) { /* loop until we can return something */ if (R->v_bufstr < R->v_bufptr) /* output any pending chars */ - rxvt_tt_write(aR_ NULL, 0); - -#if defined(POINTER_BLANK) || defined(CURSOR_BLINK) - tp.tv_sec = 0; /* presume == 0 implies time not yet retrieved */ -#endif -#if defined(CURSOR_BLINK) - want_keypress_time = 0; -#endif -#if defined(POINTER_BLANK) - want_motion_time = 0; -#endif - - if (XPending (R->Xdisplay)) - { - R->process_x_events (); - - /* in case button actions pushed chars to cmdbuf */ - if (R->cmdbuf_ptr < R->cmdbuf_endp) - return *R->cmdbuf_ptr++; - } - -#if defined(CURSOR_BLINK) - if (want_keypress_time) { - (void)gettimeofday(&tp, NULL); - R->lastcursorchange.tv_sec = tp.tv_sec; - R->lastcursorchange.tv_usec = tp.tv_usec; - } -#endif -#if defined(POINTER_BLANK) - if (want_motion_time) { - if (!tp.tv_sec) - (void)gettimeofday(&tp, NULL); - R->lastmotion.tv_sec = tp.tv_sec; - R->lastmotion.tv_usec = tp.tv_usec; - } -#endif - -/* - * the command input buffer is empty and we have no pending X events - */ - quick_timeout = 0; + R->tt_write(NULL, 0); #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING) if (R->mouse_slip_wheel_speed) { @@ -882,7 +1007,7 @@ if (!R->scroll_selection_delay-- && rxvt_scr_page(aR_ R->scroll_selection_dir, R->scroll_selection_lines)) { - rxvt_selection_extend(aR_ R->selection_save_x, + R->selection_extend (R->selection_save_x, R->selection_save_y, R->selection_save_state); R->scroll_selection_delay = SCROLLBAR_CONTINUOUS_DELAY; R->refresh_type |= SMOOTH_REFRESH; @@ -902,155 +1027,44 @@ } #endif /* NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING */ - FD_ZERO(&readfds); - FD_SET(R->cmd_fd, &readfds); - FD_SET(R->Xfd, &readfds); - value.tv_usec = TIMEOUT_USEC; - value.tv_sec = 0; - - if (!R->TermWin.mapped) - quick_timeout = 0; - else { - quick_timeout |= R->want_refresh; #ifdef TRANSPARENT quick_timeout |= R->want_full_refresh; #endif - } - -#if defined(POINTER_BLANK) || defined(CURSOR_BLINK) - { - int set_quick_timeout = 0; - long csdiff, psdiff; - -#define BLINK_TIME 500000L - csdiff = psdiff = 60000000L; /* or, say, LONG_MAX */ -# if defined(CURSOR_BLINK) - if (R->Options & Opt_cursorBlink) { - if (!tp.tv_sec) /* didn't get it before so get it now */ - (void)gettimeofday(&tp, NULL); - - csdiff = (tp.tv_sec - R->lastcursorchange.tv_sec) * 1000000L - + tp.tv_usec - R->lastcursorchange.tv_usec; - if (csdiff > BLINK_TIME) { /* XXX: settable blink times */ - R->lastcursorchange.tv_sec = tp.tv_sec; - R->lastcursorchange.tv_usec = tp.tv_usec; - R->hidden_cursor = !R->hidden_cursor; - csdiff = 0; - } else - csdiff = BLINK_TIME - csdiff; - set_quick_timeout = 1; - } -# endif -# if defined(POINTER_BLANK) - /* - * If we haven't moved the pointer for a while - */ - if ((R->Options & Opt_pointerBlank) - && (R->pointerBlankDelay > 0) - && (R->hidden_pointer == 0)) { - long pdelay; - - if (!tp.tv_sec) /* didn't get it before so get it now */ - (void)gettimeofday(&tp, NULL); - psdiff = (tp.tv_sec - R->lastmotion.tv_sec) * 1000000L - + tp.tv_usec - R->lastmotion.tv_usec; - pdelay = R->pointerBlankDelay * 1000000L; - if (psdiff >= pdelay) - rxvt_pointer_blank(aR); - else { - set_quick_timeout = 1; - psdiff = pdelay - psdiff; - } - } -# endif - if (!quick_timeout && set_quick_timeout) { - MIN_IT(csdiff, psdiff); - value.tv_sec = csdiff / 1000000L; - value.tv_usec = csdiff % 1000000L; - quick_timeout = 1; - } - } #endif +} - if ((select_res = select(R->num_fds, &readfds, NULL, NULL, - (quick_timeout ? &value : NULL))) == 0) { - /* select statement timed out - we're not hard and fast scrolling */ - R->refresh_limit = 1; - } -#if defined(CURSOR_BLINK) - if (R->Options & Opt_cursorBlink) - R->want_refresh = 1; -#endif +#ifdef POINTER_BLANK +void +rxvt_term::pointer_unblank () +{ + XDefineCursor (Xdisplay, TermWin.vt, TermWin_cursor); + recolour_cursor (); - /* See if we can read new data from the application */ - if (select_res > 0 && FD_ISSET(R->cmd_fd, &readfds)) { - int n; - unsigned int count; - - R->cmdbuf_ptr = R->cmdbuf_endp = R->cmdbuf_base; - for (count = BUFSIZ; count; count -= n, R->cmdbuf_endp += n) - if ((n = read(R->cmd_fd, R->cmdbuf_endp, count)) > 0) - continue; - else if (n == 0 || (n < 0 && errno == EAGAIN)) - break; - else { - rxvt_clean_exit(); - exit(EXIT_FAILURE); /* bad order of events? */ - } + hidden_pointer = 0; - if (count != BUFSIZ) /* some characters read in */ - { - uint32_t c = next_char (aR); - if (c != NOCHAR) - return c; - } - } -#ifdef TRANSPARENT - if (R->want_full_refresh) { - R->want_full_refresh = 0; - rxvt_scr_clear(aR); - rxvt_scr_touch(aR_ False); - R->want_refresh = 1; - } -#endif - if (R->want_refresh) { - rxvt_scr_refresh(aR_ R->refresh_type); - rxvt_scrollbar_show(aR_ 1); -#ifdef USE_XIM - rxvt_IMSendSpot(aR); -#endif - } - } -/* NOTREACHED */ + if (Options & Opt_pointerBlank) + pointer_ev.start (NOW + pointerBlankDelay); } -/*}}} */ -/* EXTPROTO */ void -rxvt_pointer_unblank(pR) +rxvt_term::pointer_blank () { - XDefineCursor(R->Xdisplay, R->TermWin.vt, R->TermWin_cursor); - rxvt_recolour_cursor(aR); -#ifdef POINTER_BLANK - R->hidden_pointer = 0; - if (R->pointerBlankDelay > 0) { - struct timeval tp; - - (void)gettimeofday(&tp, NULL); - R->lastmotion.tv_sec = tp.tv_sec; - R->lastmotion.tv_usec = tp.tv_usec; - } -#endif + if (!(Options & Opt_pointerBlank)) + return; + + XDefineCursor (Xdisplay, TermWin.vt, blank_cursor); + XFlush (Xdisplay); + + hidden_pointer = 1; } -#ifdef POINTER_BLANK -/* INTPROTO */ void -rxvt_pointer_blank(pR) +rxvt_term::pointer_cb (time_watcher &w) { - XDefineCursor(R->Xdisplay, R->TermWin.vt, R->pointer_blank); - XFlush(R->Xdisplay); - R->hidden_pointer = 1; + SET_R (this); + SET_LOCALE (locale); + + pointer_blank (); } #endif @@ -1063,7 +1077,7 @@ x = ev->x; y = ev->y; - rxvt_pixel_position(aR_ &x, &y); + R->pixel_position (&x, &y); if (R->MEvent.button == AnyButton) { button_number = 3; @@ -1113,7 +1127,7 @@ x + 1, y + 1); #else - rxvt_tt_printf(aR_ "\033[M%c%c%c", + R->tt_printf("\033[M%c%c%c", (32 + button_number + key_state), (32 + x + 1), (32 + y + 1)); @@ -1140,7 +1154,6 @@ Window unused_root, unused_child; int unused_root_x, unused_root_y; unsigned int unused_mask; - struct timeval tp; #ifdef DEBUG_X const char *const eventnames[] = @@ -1181,49 +1194,16 @@ "ClientMessage", "MappingNotify" }; - struct tm *ltt; -#endif - - /* - * check if we need to get the time for any timeouts - */ - - for (i = NUM_TIMEOUTS; i--; ) - if (R->timeout[i].tv_sec) { - want_timeout = 1; - break; - } - -#ifndef DEBUG_X - if (want_timeout) #endif - (void)gettimeofday(&tp, NULL); #ifdef DEBUG_X + struct timeval tp; + struct tm *ltt; + (void)gettimeofday(&tp, NULL); ltt = localtime(&(tp.tv_sec)); D_X((stderr, "Event: %-16s %-7s %08lx (%4d-%02d-%02d %02d:%02d:%02d.%.6ld) %s %lu", eventnames[ev->type], (ev->xany.window == R->TermWin.parent[0] ? "parent" : (ev->xany.window == R->TermWin.vt ? "vt" : (ev->xany.window == R->scrollBar.win ? "scroll" : (ev->xany.window == R->menuBar.win ? "menubar" : "UNKNOWN")))), (ev->xany.window == R->TermWin.parent[0] ? R->TermWin.parent[0] : (ev->xany.window == R->TermWin.vt ? R->TermWin.vt : (ev->xany.window == R->scrollBar.win ? R->scrollBar.win : (ev->xany.window == R->menuBar.win ? R->menuBar.win : 0)))), ltt->tm_year + 1900, ltt->tm_mon + 1, ltt->tm_mday, ltt->tm_hour, ltt->tm_min, ltt->tm_sec, tp.tv_usec, ev->xany.send_event ? "S" : " ", ev->xany.serial)); #endif - /* X event timeouts */ - if (want_timeout) - for (i = NUM_TIMEOUTS; i--; ) { - if (R->timeout[i].tv_sec == 0) - continue; - if ((tp.tv_sec < R->timeout[i].tv_sec) - || (tp.tv_sec == R->timeout[i].tv_sec - && tp.tv_usec < R->timeout[i].tv_usec)) - continue; - R->timeout[i].tv_sec = 0; - switch(i) { - case TIMEOUT_INCR: - rxvt_print_error("data loss: timeout on INCR selection paste"); - R->selection_wait = Sel_none; - break; - default: - break; - } - } - switch (ev->type) { case KeyPress: rxvt_lookup_key(aR_ (XKeyEvent *)ev); @@ -1256,10 +1236,10 @@ case ClientMessage: if (ev->xclient.format == 32 && (Atom)ev->xclient.data.l[0] == R->xa[XA_WMDELETEWINDOW]) - exit(EXIT_SUCCESS); + R->destroy (); #ifdef OFFIX_DND /* OffiX Dnd (drag 'n' drop) protocol */ - if (ev->xclient.message_type == R->xa[XA_DNDPROTOCOL] + else if (ev->xclient.message_type == R->xa[XA_DNDPROTOCOL] && (ev->xclient.data.l[0] == DndFile || ev->xclient.data.l[0] == DndDir || ev->xclient.data.l[0] == DndLink)) { @@ -1301,17 +1281,18 @@ * which ought to make things real slow! */ case VisibilityNotify: - switch (ev->xvisibility.state) { - case VisibilityUnobscured: - R->refresh_type = FAST_REFRESH; - break; - case VisibilityPartiallyObscured: - R->refresh_type = SLOW_REFRESH; - break; - default: - R->refresh_type = NO_REFRESH; - break; - } + switch (ev->xvisibility.state) + { + case VisibilityUnobscured: + R->refresh_type = FAST_REFRESH; + break; + case VisibilityPartiallyObscured: + R->refresh_type = SLOW_REFRESH; + break; + default: + R->refresh_type = NO_REFRESH; + break; + } break; case FocusIn: @@ -1322,6 +1303,10 @@ if (R->Input_Context != NULL) XSetICFocus(R->Input_Context); #endif +#ifdef CURSOR_BLINK + if (R->Options & Opt_cursorBlink) + R->cursor_blink_ev.start (NOW + BLINK_INTERVAL); +#endif } break; @@ -1333,6 +1318,11 @@ if (R->Input_Context != NULL) XUnsetICFocus(R->Input_Context); #endif +#ifdef CURSOR_BLINK + if (R->Options & Opt_cursorBlink) + R->cursor_blink_ev.stop (); + R->hidden_cursor = 0; +#endif } break; @@ -1348,8 +1338,7 @@ ConfigureNotify, ev)); if (R->szHint.width != width || R->szHint.height != height) { D_SIZE((stderr, "Size: Resizing from: %4d x %4d", R->szHint.width, R->szHint.height)); - rxvt_resize_all_windows(aR_ (unsigned int)width, - (unsigned int)height, 1); + R->resize_all_windows (width, height, 1); } #ifdef DEBUG_SIZE else { @@ -1382,10 +1371,16 @@ case UnmapNotify: R->TermWin.mapped = 0; +#ifdef TEXT_BLINK + R->text_blink_ev.stop (); +#endif break; case MapNotify: R->TermWin.mapped = 1; +#ifdef TEXT_BLINK + R->text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL); +#endif break; case PropertyNotify: @@ -1418,12 +1413,12 @@ case Expose: if (ev->xany.window == R->TermWin.vt) { #ifdef NO_SLOW_LINK_SUPPORT - rxvt_scr_expose(aR_ ev->xexpose.x, ev->xexpose.y, - ev->xexpose.width, ev->xexpose.height, False); + R->scr_expose (ev->xexpose.x, ev->xexpose.y, + ev->xexpose.width, ev->xexpose.height, False); #else // don't understand this, so commented it out - rxvt_scr_expose(aR_ ev->xexpose.x, ev->xexpose.y, - ev->xexpose.width, ev->xexpose.height, False); + R->scr_expose (ev->xexpose.x, ev->xexpose.y, + ev->xexpose.width, ev->xexpose.height, False); //rxvt_scr_expose(aR_ ev->xexpose.x, 0, // ev->xexpose.width, R->TermWin.height, False); #endif @@ -1438,7 +1433,7 @@ GraphicsExpose, &unused_xevent)) ; if (isScrollbarWindow(ev->xany.window)) { - scrollbar_setIdle(); + R->scrollBar.setIdle(); rxvt_scrollbar_show(aR_ 0); } #ifdef MENUBAR @@ -1454,7 +1449,7 @@ case MotionNotify: #ifdef POINTER_BLANK if (R->hidden_pointer) - rxvt_pointer_unblank(aR); + R->pointer_unblank (); #endif #if MENUBAR if (isMenuBarWindow(ev->xany.window)) { @@ -1478,7 +1473,7 @@ /* deal with a `jumpy' mouse */ if ((ev->xmotion.time - R->MEvent.time) > MOUSE_THRESHOLD) { #endif - rxvt_selection_extend(aR_ (ev->xbutton.x), (ev->xbutton.y), + R->selection_extend ((ev->xbutton.x), (ev->xbutton.y), (ev->xbutton.state & Button3Mask) ? 2 : 0); #ifdef SELECTION_SCROLLING if (ev->xbutton.yTermWin.int_bwidth || @@ -1537,7 +1532,7 @@ &unused_mask); rxvt_scr_move_to(aR_ scrollbar_position(ev->xbutton.y) - R->csrO, scrollbar_size()); - rxvt_scr_refresh(aR_ R->refresh_type); + R->scr_refresh (R->refresh_type); R->refresh_limit = 0; rxvt_scrollbar_show(aR_ 1); } @@ -1549,7 +1544,7 @@ void rxvt_button_press(pR_ XButtonEvent *ev) { - int reportmode = 0, clickintime; + int reportmode = 0, clickintime; R->bypass_keystate = ev->state & (R->ModMetaMask | ShiftMask); if (!R->bypass_keystate) @@ -1561,7 +1556,7 @@ { #if RXVT_GRAPHICS if (ev->subwindow != None) - rxvt_Gr_ButtonPress(ev->x, ev->y); + rxvt_Gr_ButtonPress (ev->x, ev->y); else #endif { @@ -1606,19 +1601,32 @@ switch (ev->button) { case Button1: - if (R->MEvent.button == Button1 && clickintime) - R->MEvent.clicks++; + /* allow shift+left click to extend selection */ + if (ev->state & ShiftMask && !(R->PrivateModes & PrivMode_mouse_report)) + { + if (R->MEvent.button == Button1 && clickintime) + R->selection_rotate (ev->x, ev->y); + else + R->selection_extend (ev->x, ev->y, 1); + } else - R->MEvent.clicks = 1; - rxvt_selection_click(aR_ R->MEvent.clicks, ev->x, ev->y); + { + if (R->MEvent.button == Button1 && clickintime) + R->MEvent.clicks++; + else + R->MEvent.clicks = 1; + + R->selection_click (R->MEvent.clicks, ev->x, ev->y); + } + R->MEvent.button = Button1; break; case Button3: if (R->MEvent.button == Button3 && clickintime) - rxvt_selection_rotate(aR_ ev->x, ev->y); + R->selection_rotate (ev->x, ev->y); else - rxvt_selection_extend(aR_ ev->x, ev->y, 1); + R->selection_extend (ev->x, ev->y, 1); R->MEvent.button = Button3; break; } @@ -1633,7 +1641,7 @@ */ if (isScrollbarWindow(ev->window)) { - scrollbar_setIdle(); + R->scrollBar.setIdle (); /* * Rxvt-style scrollbar: * move up if mouse is above slider @@ -1655,22 +1663,22 @@ && scrollbarnext_upButton(ev->y)) || (R->scrollBar.style == R_SB_RXVT && scrollbarrxvt_upButton(ev->y))) - rxvt_tt_printf(aR_ "\033[A"); + R->tt_printf("\033[A"); else if ((R->scrollBar.style == R_SB_NEXT && scrollbarnext_dnButton(ev->y)) || (R->scrollBar.style == R_SB_RXVT && scrollbarrxvt_dnButton(ev->y))) - rxvt_tt_printf(aR_ "\033[B"); + R->tt_printf("\033[B"); else switch (ev->button) { case Button2: - rxvt_tt_printf(aR_ "\014"); + R->tt_printf("\014"); break; case Button1: - rxvt_tt_printf(aR_ "\033[6~"); + R->tt_printf("\033[6~"); break; case Button3: - rxvt_tt_printf(aR_ "\033[5~"); + R->tt_printf("\033[5~"); break; } } @@ -1696,9 +1704,9 @@ #endif if (rxvt_scr_page(aR_ upordown < 0 ? UP : DN, 1)) { if (upordown < 0) - scrollbar_setUp(); + R->scrollBar.setUp (); else - scrollbar_setDn(); + R->scrollBar.setDn (); } } else switch (ev->button) { @@ -1720,7 +1728,7 @@ rxvt_scr_move_to(aR_ scrollbar_position(ev->y) - R->csrO, scrollbar_size()); - scrollbar_setMotion(); + R->scrollBar.setMotion (); break; case Button1: @@ -1743,7 +1751,7 @@ rxvt_scr_page(aR_ DN, R->TermWin.nrow / 4); # endif else - scrollbar_setMotion(); + R->scrollBar.setMotion (); } else { rxvt_scr_page(aR_ (ev->button == Button1 ? DN : UP), (R->TermWin.nrow @@ -1775,7 +1783,7 @@ reportmode = !!(R->PrivateModes & PrivMode_mouse_report); if (scrollbar_isUpDn()) { - scrollbar_setIdle(); + R->scrollBar.setIdle (); rxvt_scrollbar_show(aR_ 0); #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING R->refresh_type &= ~SMOOTH_REFRESH; @@ -1822,7 +1830,7 @@ if (R->PrivateModes & PrivMode_mouse_report && R->bypass_keystate && ev->button == Button1 && R->MEvent.clicks <= 1) - rxvt_selection_extend(aR_ ev->x, ev->y, 0); + R->selection_extend (ev->x, ev->y, 0); switch (ev->button) { case Button1: @@ -1836,7 +1844,8 @@ case Button4: case Button5: { - int i, v; + int i; + page_dirn v; v = (ev->button == Button4) ? UP : DN; if (ev->state & ShiftMask) @@ -1854,13 +1863,13 @@ # endif # ifdef JUMP_MOUSE_WHEEL rxvt_scr_page(aR_ v, i); - rxvt_scr_refresh(aR_ SMOOTH_REFRESH); + R->scr_refresh (SMOOTH_REFRESH); rxvt_scrollbar_show(aR_ 1); # else - for (; i--;) + while (i--) { rxvt_scr_page(aR_ v, 1); - rxvt_scr_refresh(aR_ SMOOTH_REFRESH); + R->scr_refresh (SMOOTH_REFRESH); rxvt_scrollbar_show(aR_ 1); } # endif @@ -2021,7 +2030,7 @@ for (; n < (unsigned int)i; n++) { XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[n], &wattr); D_X((stderr, "InheritPixmap Checking Parent[%d]: %s", n, (wattr.depth == rootdepth && wattr.class != InputOnly) ? "OK" : "FAIL")); - if (wattr.depth != rootdepth || wattr.class == InputOnly) { + if (wattr.depth != rootdepth || wattr.c_class == InputOnly) { n = (int)(sizeof(R->TermWin.parent) / sizeof(Window)) + 1; break; } @@ -2081,15 +2090,15 @@ /* EXTPROTO */ int -rxvt_pclose_printer(FILE *stream) +rxvt_pclose_printer (FILE *stream) { - fflush(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); */ + return pclose (stream); /* return fclose (stream); */ # else - return pclose(stream); + return pclose (stream); # endif } @@ -2162,11 +2171,11 @@ switch (ch) { case C0_ENQ: /* terminal Status */ if (R->rs[Rs_answerbackstring]) - rxvt_tt_write(aR_ + R->tt_write( (const unsigned char *)R->rs[Rs_answerbackstring], (unsigned int)STRLEN(R->rs[Rs_answerbackstring])); else - rxvt_tt_write(aR_ (unsigned char *)VT100_ANS, + R->tt_write((unsigned char *)VT100_ANS, (unsigned int)STRLEN(VT100_ANS)); break; case C0_BEL: /* bell */ @@ -2224,7 +2233,7 @@ rxvt_scr_index(aR_ DN); break; case 'J': /* erase to end of screen */ - rxvt_scr_erase_screen(aR_ 0); + R->scr_erase_screen (0); break; case 'K': /* erase to end of line */ rxvt_scr_erase_line(aR_ 0); @@ -2239,7 +2248,7 @@ rxvt_scr_gotorc(aR_ row, col, 0); break; case 'Z': /* identify the terminal type */ - rxvt_tt_printf(aR_ "\033/Z"); /* I am a VT100 emulating a VT52 */ + R->tt_printf("\033/Z"); /* I am a VT100 emulating a VT52 */ break; case '<': /* turn off VT52 mode */ PrivMode(0, PrivMode_vt52); @@ -2356,7 +2365,7 @@ /* 8.3.110: SINGLE CHARACTER INTRODUCER */ case C1_SCI: /* ESC Z */ - rxvt_tt_write(aR_ (const unsigned char *)ESCZ_ANSWER, + R->tt_write((const unsigned char *)ESCZ_ANSWER, (unsigned int)(sizeof(ESCZ_ANSWER) - 1)); break; /* steal obsolete ESC [ c */ @@ -2487,7 +2496,7 @@ switch (priv) { case '>': if (ch == CSI_DA) /* secondary device attributes */ - rxvt_tt_printf(aR_ "\033[>%d;%-.8s;0c", 'R', VSTRING); + R->tt_printf("\033[>%d;%-.8s;0c", 'R', VSTRING); break; case '?': if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't') @@ -2569,7 +2578,7 @@ break; case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */ - rxvt_scr_erase_screen(aR_ arg[0]); + R->scr_erase_screen (arg[0]); break; case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */ @@ -2600,11 +2609,11 @@ arg[0] = -arg[0]; /* FALLTHROUGH */ case CSI_SU: /* 8.3.148: (1) SCROLL UP */ - rxvt_scroll_text(aR_ R->screen.tscroll, R->screen.bscroll, arg[0], 0); + R->scr_scroll_text (R->screen.tscroll, R->screen.bscroll, arg[0], 0); break; case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */ - rxvt_tt_write(aR_ (const unsigned char *)VT100_ANS, + R->tt_write((const unsigned char *)VT100_ANS, (unsigned int)(sizeof(VT100_ANS) - 1)); break; @@ -2615,14 +2624,14 @@ case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */ switch (arg[0]) { case 5: /* DSR requested */ - rxvt_tt_printf(aR_ "\033[0n"); + R->tt_printf("\033[0n"); break; case 6: /* CPR requested */ rxvt_scr_report_position(aR); break; #if defined (ENABLE_DISPLAY_ANSWER) case 7: /* unofficial extension */ - rxvt_tt_printf(aR_ "%-.250s\n", R->rs[Rs_display_name]); + R->tt_printf("%-.250s\n", R->rs[Rs_display_name]); break; #endif case 8: /* unofficial extension */ @@ -2701,7 +2710,7 @@ case CSI_78: /* DECREQTPARM */ if (arg[0] == 0 || arg[0] == 1) - rxvt_tt_printf(aR_ "\033[%d;1;1;112;112;1;0x", arg[0] + 2); + R->tt_printf("\033[%d;1;1;128;128;1;0x", arg[0] + 2); /* FALLTHROUGH */ default: @@ -2749,7 +2758,7 @@ XLowerWindow(R->Xdisplay, R->TermWin.parent[0]); break; case 7: /* refresh window */ - rxvt_scr_touch(aR_ True); + R->scr_touch (true); break; case 8: /* set size (chars) */ rxvt_set_widthheight(aR_ (unsigned int)(args[2] * R->TermWin.fwidth), @@ -2765,30 +2774,30 @@ */ case 11: /* report window state */ XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr); - rxvt_tt_printf(aR_ "\033[%dt", wattr.map_state == IsViewable ? 1 : 2); + R->tt_printf("\033[%dt", wattr.map_state == IsViewable ? 1 : 2); break; case 13: /* report window position */ XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr); XTranslateCoordinates(R->Xdisplay, R->TermWin.parent[0], wattr.root, -wattr.border_width, -wattr.border_width, &x, &y, &wdummy); - rxvt_tt_printf(aR_ "\033[3;%d;%dt", x, y); + R->tt_printf("\033[3;%d;%dt", x, y); break; case 14: /* report window size (pixels) */ XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr); - rxvt_tt_printf(aR_ "\033[4;%d;%dt", wattr.height, wattr.width); + R->tt_printf("\033[4;%d;%dt", wattr.height, wattr.width); break; case 18: /* report window size (chars) */ - rxvt_tt_printf(aR_ "\033[8;%d;%dt", R->TermWin.nrow, R->TermWin.ncol); + R->tt_printf("\033[8;%d;%dt", R->TermWin.nrow, R->TermWin.ncol); break; #if 0 /* XXX: currently disabled due to security concerns */ case 20: /* report icon label */ XGetIconName(R->Xdisplay, R->TermWin.parent[0], &s); - rxvt_tt_printf(aR_ "\033]L%-.200s\234", s ? s : ""); /* 8bit ST */ + R->tt_printf("\033]L%-.200s\234", s ? s : ""); /* 8bit ST */ break; case 21: /* report window title */ XFetchName(R->Xdisplay, R->TermWin.parent[0], &s); - rxvt_tt_printf(aR_ "\033]l%-.200s\234", s ? s : ""); /* 8bit ST */ + R->tt_printf("\033]l%-.200s\234", s ? s : ""); /* 8bit ST */ break; #endif } @@ -2970,7 +2979,7 @@ rxvt_scale_pixmap(aR_ ""); /* reset to default scaling */ rxvt_set_bgPixmap(aR_ str); /* change pixmap */ #endif - rxvt_scr_touch(aR_ True); + R->scr_touch (true); } while ((str = STRCHR(str, ';')) != NULL) { str++; @@ -2982,7 +2991,7 @@ #ifdef XPM_BACKGROUND rxvt_resize_pixmap(aR); #endif - rxvt_scr_touch(aR_ True); + R->scr_touch (true); } break; @@ -3158,8 +3167,8 @@ #ifdef scrollBar_esc case scrollBar_esc: if (rxvt_scrollbar_mapping(aR_ state)) { - rxvt_resize_all_windows(aR_ 0, 0, 0); - rxvt_scr_touch(aR_ True); + R->resize_all_windows (0, 0, 0); + R->scr_touch (true); } break; #endif @@ -3195,7 +3204,7 @@ break; case 1047: /* secondary screen w/ clearing */ if (R->current_screen != PRIMARY) - rxvt_scr_erase_screen(aR_ 2); + R->scr_erase_screen (2); rxvt_scr_change_screen(aR_ state); /* FALLTHROUGH */ default: @@ -3341,7 +3350,7 @@ #ifndef RXVT_GRAPHICS if (cmd == 'Q') { /* query graphics */ - rxvt_tt_printf(aR_ "\033G0\n"); /* no graphics */ + R->tt_printf("\033G0\n"); /* no graphics */ return; } /* swallow other graphics sequences until terminating ':' */ @@ -3354,7 +3363,7 @@ unsigned char *text = NULL; if (cmd == 'Q') { /* query graphics */ - rxvt_tt_printf(aR_ "\033G1\n"); /* yes, graphics (color) */ + R->tt_printf("\033G1\n"); /* yes, graphics (color) */ return; } for (nargs = 0; nargs < (sizeof(args) / sizeof(args[0])) - 1;) { @@ -3379,7 +3388,7 @@ if ((cmd == 'T') && (nargs >= 5)) { int i, len = args[4]; - text = rxvt_malloc((len + 1) * sizeof(char)); + text = (unsigned char *)rxvt_malloc((len + 1) * sizeof(char)); if (text != NULL) { for (i = 0; i < len; i++) @@ -3394,239 +3403,80 @@ /* ------------------------------------------------------------------------- */ -/*{{{ Read and process output from the application */ -/* LIBPROTO */ -void -rxvt_main_loop(pR) -{ - uint32_t ch, *str, buf[BUFSIZ]; - int nlines, refreshnow; - - R->cmdbuf_ptr = R->cmdbuf_endp = R->cmdbuf_base; - - /* once we know the shell is running, send the screen size. Again! */ - ch = rxvt_cmd_getc(aR); /* wait for something */ - rxvt_tt_winsize(R->cmd_fd, R->TermWin.ncol, R->TermWin.nrow, R->cmd_pid); - - refreshnow = 0; - for (;;) { - if (ch == NOCHAR) - ch = rxvt_cmd_getc(aR); - - if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r') - { - /* Read a text string from the input buffer */ - nlines = 0; - str = buf; - *str++ = ch; - for (;;) - { - ch = next_char (aR); - - if (ch == NOCHAR || (ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r')) - break; - else - { - *str++ = ch; - - if (ch == '\n') - { - nlines++; - R->refresh_count++; - if (!(R->Options & Opt_jumpScroll) - || (R->refresh_count >= (R->refresh_limit - * (R->TermWin.nrow - 1)))) - { - refreshnow = 1; - ch = NOCHAR; - break; - } - } - - if (str >= buf + BUFSIZ) - { - ch = NOCHAR; - break; - } - } - } - - rxvt_scr_add_lines(aR_ 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 R->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 - */ - - //TODO: REFRESH_PERIOD is one, fix it - if (refreshnow) - { - refreshnow = 0; - - if ((R->Options & Opt_jumpScroll) && R->refresh_limit < REFRESH_PERIOD) - R->refresh_limit++; - - rxvt_scr_refresh(aR_ R->refresh_type); - } - - } - else - { - switch (ch) - { - default: - rxvt_process_nonprinting(aR_ ch); - break; - case C0_ESC: /* escape char */ - rxvt_process_escape_seq(aR); - break; - /* case 0x9b: */ /* CSI */ - /* rxvt_process_csi_seq(aR); */ - } - - ch = NOCHAR; - } - } -/* NOTREACHED */ -} - /* * Send printf() formatted output to the command. * Only use for small amounts of data. */ -/* EXTPROTO */ void -rxvt_tt_printf(pR_ const char *fmt,...) +rxvt_term::tt_printf (const char *fmt,...) { - va_list arg_ptr; - unsigned char buf[256]; + va_list arg_ptr; + unsigned char buf[256]; - va_start(arg_ptr, fmt); - vsprintf((char *)buf, fmt, arg_ptr); - va_end(arg_ptr); - rxvt_tt_write(aR_ buf, (unsigned int)STRLEN(buf)); + va_start (arg_ptr, fmt); + vsnprintf ((char *)buf, 256, fmt, arg_ptr); + va_end (arg_ptr); + tt_write (buf, STRLEN (buf)); } /* ---------------------------------------------------------------------- */ -/* Addresses pasting large amounts of data and rxvt hang - * code pinched from xterm (v_write()) and applied originally to - * rxvt-2.18 - Hops - * Write data to the pty as typed by the user, pasted with the mouse, +/* 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. */ -/* EXTPROTO */ void -rxvt_tt_write(pR_ const unsigned char *d, unsigned int len) +rxvt_term::tt_write (const unsigned char *data, unsigned int len) { -#define MAX_PTY_WRITE 256 /* POSIX minimum MAX_INPUT */ - int riten; - unsigned int p; - unsigned char *v_buffer, /* start of physical buffer */ - *v_bufstr, /* start of current buffer pending */ - *v_bufptr, /* end of current buffer pending */ - *v_bufend; /* end of physical buffer */ - - if (R->v_bufstr == NULL && len > 0) { - p = (len / MAX_PTY_WRITE + 1) * MAX_PTY_WRITE; - v_buffer = v_bufstr = v_bufptr = (unsigned char *)rxvt_malloc(p); - v_bufend = v_buffer + p; - } else { - v_buffer = R->v_buffer; - v_bufstr = R->v_bufstr; - v_bufptr = R->v_bufptr; - v_bufend = R->v_bufend; - } + enum { MAX_PTY_WRITE = 255 }; // minimum MAX_INPUT - /* - * 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) { /* run out of room */ - if (v_bufstr != v_buffer) { - /* there is unused space, move everything down */ - MEMMOVE(v_buffer, v_bufstr, - (unsigned int)(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 */ - /* use most basic realloc because an error is not fatal. */ - unsigned int size = v_bufptr - v_buffer; - unsigned int reallocto; - - reallocto = ((size + len) / MAX_PTY_WRITE + 1) * MAX_PTY_WRITE; - v_buffer = (unsigned char *)realloc(v_buffer, reallocto); - /* save across realloc */ - if (v_buffer) { - v_bufstr = v_buffer; - v_bufptr = v_buffer + size; - v_bufend = v_buffer + reallocto; - } else { /* no memory: ignore entire write request */ - rxvt_print_error("data loss: cannot allocate buffer space"); - v_buffer = v_bufstr; /* restore clobbered pointer */ - } - } - } - if (v_bufend >= v_bufptr + len) { /* new stuff will fit */ - MEMCPY(v_bufptr, d, len); - v_bufptr += len; - } - } + if (len) + { + if (v_buflen == 0) + { + int written = write (cmd_fd, data, min (MAX_PTY_WRITE, len)); + if (written == len) + return; - /* - * 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 ((p = v_bufptr - v_bufstr) > 0) { - riten = write(R->cmd_fd, v_bufstr, min(p, MAX_PTY_WRITE)); - if (riten < 0) - riten = 0; - v_bufstr += riten; - if (v_bufstr >= v_bufptr) /* we wrote it all */ - v_bufstr = v_bufptr = v_buffer; + data += written; + len -= written; + } + + + v_buffer = (unsigned char *)realloc (v_buffer, v_buflen + len); + + memcpy (v_buffer + v_buflen, data, len); + v_buflen += len; } - /* - * If we have lots of unused memory allocated, return it - */ - if (v_bufend - v_bufptr > MAX_PTY_WRITE * 8) { /* arbitrary hysteresis */ - /* save pointers across realloc */ - unsigned int start = v_bufstr - v_buffer; - unsigned int size = v_bufptr - v_buffer; - unsigned int reallocto; - - reallocto = (size / MAX_PTY_WRITE + 1) * MAX_PTY_WRITE; - v_buffer = (unsigned char *)realloc(v_buffer, reallocto); - if (v_buffer) { - v_bufstr = v_buffer + start; - v_bufptr = v_buffer + size; - v_bufend = v_buffer + reallocto; - } else { - /* should we print a warning if couldn't return memory? */ - v_buffer = v_bufstr - start; /* restore clobbered pointer */ - } + + for (;;) + { + int written = write (cmd_fd, v_buffer, min (MAX_PTY_WRITE, v_buflen)); + + if (written > 0) + { + v_buflen -= written; + + if (v_buflen == 0) + { + free (v_buffer); + v_buffer = 0; + v_buflen = 0; + + pty_ev.set (EVENT_READ); + return; + } + + memmove (v_buffer, v_buffer + written, v_buflen); + } + else if (written != -1 || (errno != EAGAIN && errno != EINTR)) + // original code just ignores this... + destroy (); + else + { + pty_ev.set (EVENT_READ | EVENT_WRITE); + return; + } } - R->v_buffer = v_buffer; - R->v_bufstr = v_bufstr; - R->v_bufptr = v_bufptr; - R->v_bufend = v_bufend; } + /*----------------------- end-of-file (C source) -----------------------*/