--- rxvt-unicode/src/screen.C 2007/12/11 03:30:50 1.285 +++ rxvt-unicode/src/screen.C 2008/11/04 23:20:17 1.320 @@ -3,7 +3,7 @@ *---------------------------------------------------------------------------* * * Copyright (c) 1997-2001 Geoff Wing - * Copyright (c) 2003-2006 Marc Lehmann + * Copyright (c) 2003-2007 Marc Lehmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,30 +85,14 @@ ROW_AND_COL_IN_ROW_AT_OR_BEFORE ((X).row, (X).col, (Y).row, (Y).col) /* - * CLEAR_ROWS : clear rows starting from row * CLEAR_CHARS: clear chars starting from pixel position - * ERASE_ROWS : set rows starting from row to the foreground colour */ -#define drawBuffer vt - -#define CLEAR_ROWS(row, num) \ - if (mapped) \ - XClearArea (dpy, drawBuffer, 0, \ - Row2Pixel (row), (unsigned int)width, \ - (unsigned int)Height2Pixel (num), False) - #define CLEAR_CHARS(x, y, num) \ - if (mapped) \ - XClearArea (dpy, drawBuffer, x, y, \ + if (mapped) \ + XClearArea (dpy, vt, x, y, \ (unsigned int)Width2Pixel (num), \ (unsigned int)Height2Pixel (1), False) -#define ERASE_ROWS(row, num) \ - XFillRectangle (dpy, drawBuffer, gc, \ - 0, Row2Pixel (row), \ - (unsigned int)width, \ - (unsigned int)Height2Pixel (num)) - /* ------------------------------------------------------------------------- * * SCREEN `COMMON' ROUTINES * * ------------------------------------------------------------------------- */ @@ -150,6 +134,25 @@ l.f = 0; } +// nuke a single wide character at the given column +void +rxvt_term::scr_kill_char (line_t &l, int col) const NOTHROW +{ + // find begin + while (col > 0 && l.t[col] == NOCHAR) + col--; + + rend_t rend = l.r[col] & ~RS_baseattrMask; + rend = SET_FONT (rend, FONTSET (rend)->find_font (' ')); + + // found start, nuke + do { + l.t[col] = ' '; + l.r[col] = rend; + col++; + } while (col < ncol && l.t[col] == NOCHAR); +} + /* ------------------------------------------------------------------------- * * SCREEN INITIALISATION * * ------------------------------------------------------------------------- */ @@ -157,12 +160,9 @@ void rxvt_term::scr_reset () { -#if ENABLE_OVERLAY - scr_overlay_off (); -#endif - - rvideo_mode = false; + scr_soft_reset (); view_start = 0; + num_scr = 0; if (ncol == 0) @@ -174,9 +174,6 @@ if (ncol == prev_ncol && nrow == prev_nrow) return; - if (current_screen != PRIMARY) - scr_swap_screen (); - // we need at least two lines for wrapping to work correctly while (nrow + saveLines < 2) { @@ -398,8 +395,6 @@ clamp_it (screen.cur.row, 0, nrow - 1); clamp_it (screen.cur.col, 0, ncol - 1); - - free (tabs); } CLEAR_ALL_SELECTION (); @@ -407,14 +402,6 @@ prev_nrow = nrow; prev_ncol = ncol; - tabs = (char *)rxvt_malloc (ncol); - - for (int col = ncol; --col; ) - tabs [col] = col % TABSIZE == 0; - - if (current_screen != PRIMARY) - scr_swap_screen (); - tt_winch (); HOOK_INVOKE ((this, HOOK_RESET, DT_END)); @@ -435,15 +422,16 @@ free (row_buf); free (swap_buf); free (drawn_buf); - free (tabs); + row_buf = 0; // signal that we freed all the arrays above - row_buf = 0; // signal that we freed all the arrays + free (tabs); + tabs = 0; } } /* ------------------------------------------------------------------------- */ /* - * Hard reset + * Hard/Soft reset */ void rxvt_term::scr_poweron () @@ -456,6 +444,30 @@ scr_refresh (); } +void +rxvt_term::scr_soft_reset () +{ + /* only affects modes, nothing drastic such as clearing the screen */ +#if ENABLE_OVERLAY + scr_overlay_off (); +#endif + + rvideo_mode = false; + + if (current_screen != PRIMARY) + scr_swap_screen (); + + free (tabs); + tabs = (char *)rxvt_malloc (ncol); + + for (int col = ncol; --col; ) + tabs [col] = col % TABSIZE == 0; + + scr_scroll_region (0, MAX_ROWS - 1); + scr_rendition (0, ~RS_None); + scr_insert_mode (0); +} + /* ------------------------------------------------------------------------- * * PROCESS SCREEN COMMANDS * * ------------------------------------------------------------------------- */ @@ -598,14 +610,14 @@ */ void rxvt_term::scr_rendition (int set, int style) NOTHROW - { - if (set) - rstyle |= style; - else if (style == ~RS_None) - rstyle = DEFAULT_RSTYLE; - else - rstyle &= ~style; - } +{ + if (set) + rstyle |= style; + else if (style == ~RS_None) + rstyle = DEFAULT_RSTYLE; + else + rstyle &= ~style; +} /* ------------------------------------------------------------------------- */ /* @@ -789,7 +801,7 @@ { c = (unicode_t)*str++; // convert to rxvt-unicodes representation - if (c < 0x20) + if (expect_false (c < 0x20)) if (c == C0_LF) { max_it (line->l, screen.cur.col); @@ -818,9 +830,11 @@ continue; } - if (checksel /* see if we're writing within selection */ - && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) - && ROWCOL_IS_BEFORE (screen.cur, selection.end)) + if (expect_false ( + checksel /* see if we're writing within selection */ + && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) + && ROWCOL_IS_BEFORE (screen.cur, selection.end) + )) { checksel = 0; /* @@ -831,7 +845,7 @@ CLEAR_SELECTION (); } - if (screen.flags & Screen_WrapNext) + if (expect_false (screen.flags & Screen_WrapNext)) { scr_do_wrap (); @@ -843,7 +857,7 @@ } // some utf-8 decoders "decode" surrogate characters: let's fix this. - if (IN_RANGE_INC (c, 0xd800, 0xdfff)) + if (expect_false (IN_RANGE_INC (c, 0xd800, 0xdfff))) c = 0xfffd; // rely on wcwidth to tell us the character width, do wcwidth before @@ -852,7 +866,7 @@ // locale. int width = WCWIDTH (c); - if (charsets [screen.charset] == '0') // DEC SPECIAL + if (expect_false (charsets [screen.charset] == '0')) // DEC SPECIAL { // vt100 special graphics and line drawing // 5f-7e standard vt100 @@ -875,7 +889,7 @@ } } - if (screen.flags & Screen_Insert) + if (expect_false (screen.flags & Screen_Insert)) scr_insdel_chars (width, INSERT); if (width != 0) @@ -891,33 +905,20 @@ #endif // nuke the character at this position, if required - if (line->t[screen.cur.col] == NOCHAR - || (screen.cur.col < ncol - 1 - && line->t[screen.cur.col + 1] == NOCHAR)) - { - int col = screen.cur.col; - - // find begin - while (col > 0 && line->t[col] == NOCHAR) - col--; - - rend_t rend = SET_FONT (line->r[col], FONTSET (line->r[col])->find_font (' ')); - - // found begin, nuke - do { - line->t[col] = ' '; - line->r[col] = rend; - col++; - } while (col < ncol && line->t[col] == NOCHAR); - } + if (expect_false ( + line->t[screen.cur.col] == NOCHAR + || (screen.cur.col < ncol - 1 + && line->t[screen.cur.col + 1] == NOCHAR) + )) + scr_kill_char (*line, screen.cur.col); rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c)); // if the character doesn't fit into the remaining columns... - if (screen.cur.col > ncol - width && ncol >= width) + if (expect_false (screen.cur.col > ncol - width && ncol >= width)) { - // ...output spaces - c = ' '; + // ... artificially enlargen the previous one + c = NOCHAR; // and try the same character next loop iteration --str; } @@ -929,7 +930,7 @@ line->t[screen.cur.col] = c; line->r[screen.cur.col] = rend; - if (screen.cur.col < ncol - 1) + if (expect_true (screen.cur.col < ncol - 1)) screen.cur.col++; else { @@ -941,10 +942,10 @@ c = NOCHAR; } - while (--width > 0); + while (expect_false (--width > 0)); // pad with spaces when overwriting wide character with smaller one - if (!width) + if (expect_false (!width)) { line->touch (); @@ -955,47 +956,50 @@ } } } +#if ENABLE_COMBINING else // width == 0 { -#if ENABLE_COMBINING - // handle combining characters - // we just tag the accent on the previous on-screen character. - // this is arguably not correct, but also arguably not wrong. - // we don't handle double-width characters nicely yet. - line_t *linep; - text_t *tp; - rend_t *rp; - - if (screen.cur.col > 0) - { - linep = line; - tp = line->t + screen.cur.col - 1; - rp = line->r + screen.cur.col - 1; - } - else if (screen.cur.row > 0 - && ROW(screen.cur.row - 1).is_longer ()) - { - linep = &ROW(screen.cur.row - 1); - tp = line->t + ncol - 1; - rp = line->r + ncol - 1; - } - else - continue; + if (c != 0xfeff) // ignore BOM + { + // handle combining characters + // we just tag the accent on the previous on-screen character. + // this is arguably not correct, but also arguably not wrong. + // we don't handle double-width characters nicely yet. + line_t *linep; + text_t *tp; + rend_t *rp; - linep->touch (); + if (screen.cur.col > 0) + { + linep = line; + tp = line->t + screen.cur.col - 1; + rp = line->r + screen.cur.col - 1; + } + else if (screen.cur.row > 0 + && ROW(screen.cur.row - 1).is_longer ()) + { + linep = &ROW(screen.cur.row - 1); + tp = line->t + ncol - 1; + rp = line->r + ncol - 1; + } + else + continue; - while (*tp == NOCHAR && tp > linep->t) - tp--, rp--; + linep->touch (); - // first try to find a precomposed character - unicode_t n = rxvt_compose (*tp, c); - if (n == NOCHAR) - n = rxvt_composite.compose (*tp, c); + while (*tp == NOCHAR && tp > linep->t) + tp--, rp--; - *tp = n; - *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp)); -#endif + // first try to find a precomposed character + unicode_t n = rxvt_compose (*tp, c); + if (n == NOCHAR) + n = rxvt_composite.compose (*tp, c); + + *tp = n; + *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp)); + } } +#endif } max_it (line->l, screen.cur.col); @@ -1013,23 +1017,20 @@ void rxvt_term::scr_backspace () NOTHROW { - want_refresh = 1; - if (screen.cur.col == 0) { if (screen.cur.row > 0) { #ifdef TERMCAP_HAS_BW screen.cur.col = ncol - 1; - screen.cur.row--; - return; + --screen.cur.row; + + want_refresh = 1; #endif } } - else if (!(screen.flags & Screen_WrapNext)) + else scr_gotorc (0, -1, RELATIVE); - - screen.flags &= ~Screen_WrapNext; } /* ------------------------------------------------------------------------- */ @@ -1232,6 +1233,7 @@ * XTERM_SEQ: Clear line to right: ESC [ 0 K * XTERM_SEQ: Clear line to left : ESC [ 1 K * XTERM_SEQ: Clear whole line : ESC [ 2 K + * extension: clear to right unless wrapped: ESC [ 3 K */ void rxvt_term::scr_erase_line (int mode) NOTHROW @@ -1250,21 +1252,31 @@ switch (mode) { + case 3: + if (screen.flags & Screen_WrapNext) + return; + + /* fall through */ + case 0: /* erase to end of line */ col = screen.cur.col; num = ncol - col; min_it (line.l, col); + if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur) || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur)) CLEAR_SELECTION (); break; + case 1: /* erase to beginning of line */ col = 0; num = screen.cur.col + 1; + if (ROWCOL_IN_ROW_AT_OR_BEFORE (selection.beg, screen.cur) || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur)) CLEAR_SELECTION (); break; + case 2: /* erase whole line */ col = 0; num = ncol; @@ -1332,19 +1344,28 @@ min_it (num, nrow - row); + /*TODO: the xlceararea/xfillrectangle below don't take scroll offste into account, ask mikachu for details */ if (rstyle & (RS_RVid | RS_Uline)) ren = (rend_t) ~RS_None; else if (GET_BASEBG (rstyle) == Color_bg) { ren = DEFAULT_RSTYLE; - CLEAR_ROWS (row, num); + + if (mapped) + XClearArea (dpy, vt, 0, + Row2Pixel (row), (unsigned int)width, + (unsigned int)Height2Pixel (num), False); } else { ren = rstyle & (RS_fgMask | RS_bgMask); + gcvalue.foreground = pix_colors[bgcolor_of (rstyle)]; XChangeGC (dpy, gc, GCForeground, &gcvalue); - ERASE_ROWS (row, num); + XFillRectangle (dpy, vt, gc, + 0, Row2Pixel (row), + (unsigned int)width, + (unsigned int)Height2Pixel (num)); gcvalue.foreground = pix_colors[Color_fg]; XChangeGC (dpy, gc, GCForeground, &gcvalue); } @@ -1436,9 +1457,6 @@ void rxvt_term::scr_insdel_chars (int count, int insdel) NOTHROW { - int col, row; - rend_t tr; - want_refresh = 1; ZERO_SCROLLBACK (); @@ -1450,24 +1468,31 @@ selection_check (1); min_it (count, ncol - screen.cur.col); - row = screen.cur.row; + int row = screen.cur.row; line_t *line = &ROW(row); line->touch (); line->is_longer (0); + // nuke wide spanning the start + if (line->t[screen.cur.col] == NOCHAR) + scr_kill_char (*line, screen.cur.col); + switch (insdel) { case INSERT: - for (col = ncol - 1; (col - count) >= screen.cur.col; col--) + line->l = min (line->l + count, ncol); + + if (line->t[screen.cur.col] == NOCHAR) + scr_kill_char (*line, screen.cur.col); + + for (int col = ncol - 1; (col - count) >= screen.cur.col; col--) { line->t[col] = line->t[col - count]; line->r[col] = line->r[col - count]; } - line->l = min (line->l + count, ncol); - if (selection.op && current_screen == selection.screen && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) { @@ -1491,21 +1516,28 @@ selection_check (1); screen.cur.col -= count; - line->l = max (line->l - count, 0); + // nuke wide char after the end + if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR) + scr_kill_char (*line, screen.cur.col + count); + scr_blank_line (*line, screen.cur.col, count, rstyle); break; case DELETE: - tr = line->r[ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask); + line->l = max (line->l - count, 0); + + // nuke wide char spanning the end + if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR) + scr_kill_char (*line, screen.cur.col + count); - for (col = screen.cur.col; (col + count) < ncol; col++) + for (int col = screen.cur.col; (col + count) < ncol; col++) { line->t[col] = line->t[col + count]; line->r[col] = line->r[col + count]; } - line->l = max (line->l - count, 0); - scr_blank_line (*line, ncol - count, count, tr); + scr_blank_line (*line, ncol - count, count, + line->r[ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask)); if (selection.op && current_screen == selection.screen && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) @@ -1874,6 +1906,7 @@ { rvideo_bell = false; scr_rvideo_mode (rvideo_mode); + refresh_check (); } #endif @@ -1892,20 +1925,14 @@ # if ENABLE_FRILLS if (option (Opt_urgentOnBell)) - { - if (XWMHints *h = XGetWMHints(dpy, parent[0])) - { - h->flags |= XUrgencyHint; - XSetWMHints (dpy, parent[0], h); - } - } + set_urgency (1); # endif if (option (Opt_visualBell)) { rvideo_bell = true; scr_rvideo_mode (rvideo_mode); - display->flush (); + flush (); bell_ev.start (VISUAL_BELL_DURATION); } @@ -1921,9 +1948,9 @@ { #ifdef PRINTPIPE int nrows, row_start; - FILE *fd; + FILE *fd = popen_printer (); - if ((fd = popen_printer ()) == NULL) + if (!fd) return; if (fullhist) @@ -1998,11 +2025,11 @@ /* * A: set up vars */ - have_bg = 0; refresh_count = 0; + have_bg = 0; #ifdef HAVE_BG_PIXMAP - have_bg |= bgPixmap.pixmap != None; + have_bg = bgPixmap.pixmap != None; #endif ocrow = oldcursor.row; /* is there an old outline cursor on screen? */ @@ -2203,7 +2230,7 @@ // redraw one or more characters // seek to the beginning of wide characters - while (stp[col] == NOCHAR && col > 0) + while (expect_false (stp[col] == NOCHAR && col > 0)) --col; rend_t rend = srp[col]; /* screen rendition (target rendtion) */ @@ -2250,7 +2277,7 @@ count -= i; /* dump any matching trailing chars */ // sometimes we optimize away the trailing NOCHAR's, add them back - while (i && text[count] == NOCHAR) + while (expect_false (i && text[count] == NOCHAR)) count++, i--; /* @@ -2260,13 +2287,12 @@ int back = bgcolor_of (rend); // desired background // only do special processing if any attributes are set, which is unlikely - if (rend & (RS_Bold | RS_Italic | RS_Uline | RS_RVid | RS_Blink | RS_Careful)) + if (expect_false (rend & (RS_Bold | RS_Italic | RS_Uline | RS_RVid | RS_Blink | RS_Careful))) { bool invert = rend & RS_RVid; #ifndef NO_BOLD_UNDERLINE_REVERSE - if (rend & RS_Bold - && fore == Color_fg) + if (rend & RS_Bold && fore == Color_fg) { if (ISSET_PIXCOLOR (Color_BD)) fore = Color_BD; @@ -2276,8 +2302,7 @@ # endif } - if (rend & RS_Italic - && fore == Color_fg) + if (rend & RS_Italic && fore == Color_fg) { if (ISSET_PIXCOLOR (Color_IT)) fore = Color_IT; @@ -2321,9 +2346,9 @@ #ifdef TEXT_BLINK if (rend & RS_Blink && (back == Color_bg || fore == Color_bg)) { - if (!ev_is_active (&text_blink_ev)) + if (!text_blink_ev.is_active ()) { - text_blink_ev.start (TEXT_BLINK_INTERVAL, TEXT_BLINK_INTERVAL); + text_blink_ev.again (); hidden_text = 0; } else if (hidden_text) @@ -2355,7 +2380,7 @@ */ rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)]; - if (have_bg && back == Color_bg) + if (expect_true (have_bg && back == Color_bg)) { // this is very ugly, maybe push it into ->draw? @@ -2372,7 +2397,7 @@ else font->draw (*drawable, xpixel, ypixel, text, count, fore, back); - if (rend & RS_Uline && font->descent > 1 && fore != back) + if (expect_false (rend & RS_Uline && font->descent > 1 && fore != back)) { #if ENABLE_FRILLS if (ISSET_PIXCOLOR (Color_underline)) @@ -2381,7 +2406,7 @@ #endif XSetForeground (dpy, gc, pix_colors[fore]); - XDrawLine (dpy, drawBuffer, gc, + XDrawLine (dpy, vt, gc, xpixel, ypixel + font->ascent + 1, xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1); } @@ -2429,7 +2454,7 @@ #endif XSetForeground (dpy, gc, pix_colors[ccol1]); - XDrawRectangle (dpy, drawBuffer, gc, + XDrawRectangle (dpy, vt, gc, Col2Pixel (col), Row2Pixel (oldcursor.row), (unsigned int) (Width2Pixel (cursorwidth) - 1), @@ -2477,22 +2502,24 @@ #ifdef HAVE_BG_PIXMAP bgPixmap.apply (); #else + XSetWindowBackground (dpy, parent[0], pix_colors[Color_border]); XClearWindow (dpy, parent[0]); XSetWindowBackground (dpy, vt, pix_colors[Color_bg]); -# if HAVE_SCROLLBARS + if (scrollBar.win) { XSetWindowBackground (dpy, scrollBar.win, pix_colors[Color_border]); - scrollBar.setIdle (); - scrollbar_show (0); + scrollBar.state = STATE_IDLE; + scrollBar.show (0); } -# endif + +#endif + + /* bgPixmap.apply () does not do the following : */ scr_clear (); scr_touch (true); want_refresh = 1; -#endif - } /* ------------------------------------------------------------------------- */ @@ -2591,7 +2618,7 @@ unsigned int width, towrite; char r1[] = "\n"; - for (row = saveLines - nsaved; + for (row = saveLines + top_row; row < saveLines + nrow - 1; row++) { width = row_buf[row].l >= 0 ? row_buf[row].l @@ -2652,7 +2679,13 @@ if (data[i] == C0_LF) data[i] = C0_CR; + if (priv_modes & PrivMode_BracketPaste) + tt_printf ("\e[200~"); + tt_write (data, len); + + if (priv_modes & PrivMode_BracketPaste) + tt_printf ("\e[201~"); } /* ------------------------------------------------------------------------- */