--- rxvt-unicode/src/screen.C 2007/10/31 09:55:24 1.281 +++ rxvt-unicode/src/screen.C 2008/11/04 15:09:51 1.317 @@ -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 * * ------------------------------------------------------------------------- */ @@ -598,14 +601,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 +792,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 +821,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 +836,7 @@ CLEAR_SELECTION (); } - if (screen.flags & Screen_WrapNext) + if (expect_false (screen.flags & Screen_WrapNext)) { scr_do_wrap (); @@ -843,7 +848,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 +857,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 +880,7 @@ } } - if (screen.flags & Screen_Insert) + if (expect_false (screen.flags & Screen_Insert)) scr_insdel_chars (width, INSERT); if (width != 0) @@ -891,33 +896,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 +921,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 +933,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 +947,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 +1008,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; } /* ------------------------------------------------------------------------- */ @@ -1188,7 +1180,8 @@ else { if (screen.flags & Screen_Relative) - { /* relative origin mode */ + { + /* relative origin mode */ screen.cur.row = row + screen.tscroll; min_it (screen.cur.row, screen.bscroll); } @@ -1231,6 +1224,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 @@ -1249,21 +1243,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; @@ -1331,19 +1335,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); } @@ -1435,9 +1448,6 @@ void rxvt_term::scr_insdel_chars (int count, int insdel) NOTHROW { - int col, row; - rend_t tr; - want_refresh = 1; ZERO_SCROLLBACK (); @@ -1449,24 +1459,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)) { @@ -1474,7 +1491,8 @@ || (selection.end.col + count >= ncol)) CLEAR_SELECTION (); else - { /* shift selection */ + { + /* shift selection */ selection.beg.col += count; selection.mark.col += count; /* XXX: yes? */ selection.end.col += count; @@ -1489,21 +1507,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)) @@ -1673,7 +1698,7 @@ { tt_printf ("\033[%d;%dR", screen.cur.row + 1, screen.cur.col + 1); } - + /* ------------------------------------------------------------------------- * * FONTS * * ------------------------------------------------------------------------- */ @@ -1736,7 +1761,7 @@ set_font_style (); } - + /* ------------------------------------------------------------------------- * * MAJOR SCREEN MANIPULATION * * ------------------------------------------------------------------------- */ @@ -1868,10 +1893,11 @@ #ifndef NO_BELL void -rxvt_term::bell_cb (time_watcher &w) +rxvt_term::bell_cb (ev::timer &w, int revents) { rvideo_bell = false; scr_rvideo_mode (rvideo_mode); + refresh_check (); } #endif @@ -1890,22 +1916,16 @@ # 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 (NOW + VISUAL_BELL_DURATION); + bell_ev.start (VISUAL_BELL_DURATION); } else XBell (dpy, 0); @@ -1919,9 +1939,9 @@ { #ifdef PRINTPIPE int nrows, row_start; - FILE *fd; + FILE *fd = popen_printer (); - if ((fd = popen_printer ()) == NULL) + if (!fd) return; if (fullhist) @@ -1996,11 +2016,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? */ @@ -2201,7 +2221,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) */ @@ -2248,7 +2268,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--; /* @@ -2258,13 +2278,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; @@ -2274,8 +2293,7 @@ # endif } - if (rend & RS_Italic - && fore == Color_fg) + if (rend & RS_Italic && fore == Color_fg) { if (ISSET_PIXCOLOR (Color_IT)) fore = Color_IT; @@ -2319,9 +2337,9 @@ #ifdef TEXT_BLINK if (rend & RS_Blink && (back == Color_bg || fore == Color_bg)) { - if (!text_blink_ev.active) + if (!text_blink_ev.is_active ()) { - text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL); + text_blink_ev.again (); hidden_text = 0; } else if (hidden_text) @@ -2353,7 +2371,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? @@ -2370,7 +2388,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)) @@ -2379,7 +2397,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); } @@ -2427,7 +2445,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), @@ -2475,22 +2493,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 - } /* ------------------------------------------------------------------------- */ @@ -2589,7 +2609,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 @@ -2607,7 +2627,7 @@ } } #endif - + /* ------------------------------------------------------------------------- * * CHARACTER SELECTION * * ------------------------------------------------------------------------- */ @@ -2650,7 +2670,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~"); } /* ------------------------------------------------------------------------- */ @@ -2735,7 +2761,7 @@ selection_wait = Sel_incr; incr_buf_fill = 0; - incr_ev.start (NOW + 10); + incr_ev.start (10); goto bailout; } @@ -2771,7 +2797,7 @@ } else if (selection_wait == Sel_incr) { - incr_ev.start (NOW + 10); + incr_ev.start (10); while (incr_buf_fill + ct.nitems > incr_buf_size) { @@ -2821,7 +2847,7 @@ } void -rxvt_term::incr_cb (time_watcher &w) NOTHROW +rxvt_term::incr_cb (ev::timer &w, int revents) NOTHROW { selection_wait = Sel_none; @@ -2854,7 +2880,8 @@ rxvt_term::selection_request (Time tm, int selnum) NOTHROW { if (selection.text && selnum == Sel_Primary) - { /* internal selection */ + { + /* internal selection */ char *str = rxvt_wcstombs (selection.text, selection.len); paste (str, strlen (str)); free (str); @@ -3132,7 +3159,8 @@ --selection.mark.col; if (selection.op) - { /* clear the old selection */ + { + /* clear the old selection */ selection.beg.row = selection.end.row = selection.mark.row; selection.beg.col = selection.end.col = selection.mark.col; } @@ -3331,7 +3359,8 @@ * time of the most recent button3 press */ if (button3 && buttonpress) - { /* button3 press */ + { + /* button3 press */ /* * first determine which edge of the selection we are closest to */ @@ -3359,7 +3388,8 @@ } } else - { /* button1 drag or button3 drag */ + { + /* button1 drag or button3 drag */ if (ROWCOL_IS_AFTER (selection.mark, pos)) { if (selection.mark.row == selection.end.row @@ -3450,7 +3480,8 @@ } if (button3 && buttonpress) - { /* mark may need to be changed */ + { + /* mark may need to be changed */ if (closeto == LEFT) { selection.mark.row = selection.end.row; @@ -3660,10 +3691,6 @@ XSendEvent (dpy, rq.requestor, False, 0L, (XEvent *)&ev); } -/* ------------------------------------------------------------------------- * - * MOUSE ROUTINES * - * ------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------- */ #ifdef USE_XIM void