ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
(Generate patch)

Comparing rxvt-unicode/src/screen.C (file contents):
Revision 1.307 by root, Fri Jun 27 00:44:32 2008 UTC vs.
Revision 1.414 by sf-exg, Tue Jan 24 17:05:05 2012 UTC

1/*---------------------------------------------------------------------------* 1/*---------------------------------------------------------------------------*
2 * File: screen.C 2 * File: screen.C
3 *---------------------------------------------------------------------------* 3 *---------------------------------------------------------------------------*
4 * 4 *
5 * Copyright (c) 1997-2001 Geoff Wing <gcw@pobox.com> 5 * Copyright (c) 1997-2001 Geoff Wing <gcw@pobox.com>
6 * Copyright (c) 2003-2007 Marc Lehmann <pcg@goof.com> 6 * Copyright (c) 2003-2007 Marc Lehmann <schmorp@schmorp.de>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version. 11 * (at your option) any later version.
28#include "rxvt.h" /* NECESSARY */ 28#include "rxvt.h" /* NECESSARY */
29#include "rxvtperl.h" /* NECESSARY */ 29#include "rxvtperl.h" /* NECESSARY */
30 30
31#include <inttypes.h> 31#include <inttypes.h>
32 32
33#include "salloc.C" // HACK, should be a seperate compile! 33#include "salloc.C" // HACK, should be a separate compile!
34 34
35static inline void
35static inline void fill_text (text_t *start, text_t value, int len) 36fill_text (text_t *start, text_t value, int len)
36{ 37{
37 while (len--) 38 while (len--)
38 *start++ = value; 39 *start++ = value;
39} 40}
40 41
41/* ------------------------------------------------------------------------- */ 42/* ------------------------------------------------------------------------- */
42#define PROP_SIZE 256*1024
43#define PASTE_SIZE 32768
44#define TABSIZE 8 /* default tab size */ 43#define TABSIZE 8 /* default tab size */
45 44
46/* ------------------------------------------------------------------------- * 45/* ------------------------------------------------------------------------- *
47 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES * 46 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
48 * ------------------------------------------------------------------------- */ 47 * ------------------------------------------------------------------------- */
132 131
133 l.l = 0; 132 l.l = 0;
134 l.f = 0; 133 l.f = 0;
135} 134}
136 135
136// nuke a single wide character at the given column
137void
138rxvt_term::scr_kill_char (line_t &l, int col) const NOTHROW
139{
140 // find begin
141 while (col > 0 && l.t[col] == NOCHAR)
142 col--;
143
144 rend_t rend = l.r[col] & ~RS_baseattrMask;
145 rend = SET_FONT (rend, FONTSET (rend)->find_font (' '));
146
147 l.touch ();
148
149 // found start, nuke
150 do {
151 l.t[col] = ' ';
152 l.r[col] = rend;
153 col++;
154 } while (col < ncol && l.t[col] == NOCHAR);
155}
156
137/* ------------------------------------------------------------------------- * 157/* ------------------------------------------------------------------------- *
138 * SCREEN INITIALISATION * 158 * SCREEN INITIALISATION *
139 * ------------------------------------------------------------------------- */ 159 * ------------------------------------------------------------------------- */
140 160
141void 161void
143{ 163{
144#if ENABLE_OVERLAY 164#if ENABLE_OVERLAY
145 scr_overlay_off (); 165 scr_overlay_off ();
146#endif 166#endif
147 167
148 rvideo_mode = false;
149 view_start = 0; 168 view_start = 0;
150 num_scr = 0; 169 num_scr = 0;
151 170
152 if (ncol == 0) 171 if (ncol == 0)
153 ncol = 80; 172 ncol = 80;
155 if (nrow == 0) 174 if (nrow == 0)
156 nrow = 24; 175 nrow = 24;
157 176
158 if (ncol == prev_ncol && nrow == prev_nrow) 177 if (ncol == prev_ncol && nrow == prev_nrow)
159 return; 178 return;
160
161 if (current_screen != PRIMARY)
162 scr_swap_screen ();
163 179
164 // we need at least two lines for wrapping to work correctly 180 // we need at least two lines for wrapping to work correctly
165 while (nrow + saveLines < 2) 181 while (nrow + saveLines < 2)
166 { 182 {
167 //TODO//FIXME 183 //TODO//FIXME
187 term_start = 0; 203 term_start = 0;
188 204
189 talloc = new rxvt_salloc (ncol * sizeof (text_t)); 205 talloc = new rxvt_salloc (ncol * sizeof (text_t));
190 ralloc = new rxvt_salloc (ncol * sizeof (rend_t)); 206 ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
191 207
192 row_buf = (line_t *)rxvt_calloc (total_rows + nrow, sizeof (line_t)); 208 row_buf = (line_t *)rxvt_calloc (total_rows , sizeof (line_t));
193 drawn_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t)); 209 drawn_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t));
194 swap_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t)); 210 swap_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t));
195 211
196 for (int row = nrow; row--; ) 212 for (int row = nrow; row--; )
197 { 213 {
220 selection.text = NULL; 236 selection.text = NULL;
221 selection.len = 0; 237 selection.len = 0;
222 selection.op = SELECTION_CLEAR; 238 selection.op = SELECTION_CLEAR;
223 selection.screen = PRIMARY; 239 selection.screen = PRIMARY;
224 selection.clicks = 0; 240 selection.clicks = 0;
241 selection.clip_text = NULL;
242 selection.clip_len = 0;
225 } 243 }
226 else 244 else
227 { 245 {
228 /* 246 /*
229 * add or delete rows as appropriate 247 * add or delete rows as appropriate
257 swap_buf [row].clear (); scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE); 275 swap_buf [row].clear (); scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
258 drawn_buf[row].clear (); scr_blank_screen_mem (drawn_buf[row], DEFAULT_RSTYLE); 276 drawn_buf[row].clear (); scr_blank_screen_mem (drawn_buf[row], DEFAULT_RSTYLE);
259 } 277 }
260 278
261 line_t *old_buf = row_buf; 279 line_t *old_buf = row_buf;
262 row_buf = (line_t *)rxvt_calloc (total_rows + nrow, sizeof (line_t)); 280 row_buf = (line_t *)rxvt_calloc (total_rows, sizeof (line_t));
263 281
264 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row 282 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row
265 int pend = MOD (term_start + top_row , prev_total_rows); 283 int pend = MOD (term_start + top_row , prev_total_rows);
266 int q = total_rows; // rewrapped row 284 int q = total_rows; // rewrapped row
267 285
268 if (top_row) 286 if (top_row)
269 { 287 {
270 // Re-wrap lines. This is rather ugly, possibly because I am too dumb 288 // Re-wrap lines. This is rather ugly, possibly because I am too dumb
271 // to come up with a lean and mean algorithm. 289 // to come up with a lean and mean algorithm.
290 // TODO: maybe optimise when width didn't change
272 291
273 row_col_t ocur = screen.cur; 292 row_col_t ocur = screen.cur;
274 ocur.row = MOD (term_start + ocur.row, prev_total_rows); 293 ocur.row = MOD (term_start + ocur.row, prev_total_rows);
275 294
276 do 295 do
277 { 296 {
278 p = MOD (p - 1, prev_total_rows); 297 p = MOD (p - 1, prev_total_rows);
279#ifdef DEBUG_STRICT
280 assert (old_buf [MOD (p, prev_total_rows)].t); 298 assert (old_buf [MOD (p, prev_total_rows)].t);
281#endif
282 int plines = 1; 299 int plines = 1;
283 int llen = old_buf [MOD (p, prev_total_rows)].l; 300 int llen = old_buf [MOD (p, prev_total_rows)].l;
284 301
285 while (p != pend && old_buf [MOD (p - 1, prev_total_rows)].is_longer ()) 302 while (p != pend && old_buf [MOD (p - 1, prev_total_rows)].is_longer ())
286 { 303 {
380 delete old_ta; 397 delete old_ta;
381 delete old_ra; 398 delete old_ra;
382 399
383 clamp_it (screen.cur.row, 0, nrow - 1); 400 clamp_it (screen.cur.row, 0, nrow - 1);
384 clamp_it (screen.cur.col, 0, ncol - 1); 401 clamp_it (screen.cur.col, 0, ncol - 1);
402 }
385 403
386 free (tabs); 404 free (tabs);
387 } 405 tabs = (char *)rxvt_malloc (ncol);
406
407 for (int col = ncol; col--; )
408 tabs [col] = col % TABSIZE == 0;
388 409
389 CLEAR_ALL_SELECTION (); 410 CLEAR_ALL_SELECTION ();
390 411
391 prev_nrow = nrow; 412 prev_nrow = nrow;
392 prev_ncol = ncol; 413 prev_ncol = ncol;
393
394 tabs = (char *)rxvt_malloc (ncol);
395
396 for (int col = ncol; --col; )
397 tabs [col] = col % TABSIZE == 0;
398
399 if (current_screen != PRIMARY)
400 scr_swap_screen ();
401 414
402 tt_winch (); 415 tt_winch ();
403 416
404 HOOK_INVOKE ((this, HOOK_RESET, DT_END)); 417 HOOK_INVOKE ((this, HOOK_RESET, DT_END));
405} 418}
417 delete ralloc; ralloc = 0; 430 delete ralloc; ralloc = 0;
418 431
419 free (row_buf); 432 free (row_buf);
420 free (swap_buf); 433 free (swap_buf);
421 free (drawn_buf); 434 free (drawn_buf);
435 row_buf = 0; // signal that we freed all the arrays above
436
422 free (tabs); 437 free (tabs);
423 438 tabs = 0;
424 row_buf = 0; // signal that we freed all the arrays
425 } 439 }
426} 440}
427 441
428/* ------------------------------------------------------------------------- */ 442/* ------------------------------------------------------------------------- */
429/* 443/*
430 * Hard reset 444 * Hard/Soft reset
431 */ 445 */
432void 446void
433rxvt_term::scr_poweron () 447rxvt_term::scr_poweron ()
434{ 448{
435 scr_release (); 449 scr_release ();
436 prev_nrow = prev_ncol = 0; 450 prev_nrow = prev_ncol = 0;
451 rvideo_mode = false;
452 scr_soft_reset ();
437 scr_reset (); 453 scr_reset ();
438 454
439 scr_clear (true); 455 scr_clear (true);
440 scr_refresh (); 456 scr_refresh ();
457}
458
459void
460rxvt_term::scr_soft_reset () NOTHROW
461{
462 /* only affects modes, nothing drastic such as clearing the screen */
463#if ENABLE_OVERLAY
464 scr_overlay_off ();
465#endif
466
467 if (current_screen != PRIMARY)
468 scr_swap_screen ();
469
470 scr_scroll_region (0, MAX_ROWS - 1);
471 scr_rendition (0, ~RS_None);
472 scr_insert_mode (0);
441} 473}
442 474
443/* ------------------------------------------------------------------------- * 475/* ------------------------------------------------------------------------- *
444 * PROCESS SCREEN COMMANDS * 476 * PROCESS SCREEN COMMANDS *
445 * ------------------------------------------------------------------------- */ 477 * ------------------------------------------------------------------------- */
483 } 515 }
484 516
485 /* boundary check in case screen size changed between SAVE and RESTORE */ 517 /* boundary check in case screen size changed between SAVE and RESTORE */
486 min_it (s->cur.row, nrow - 1); 518 min_it (s->cur.row, nrow - 1);
487 min_it (s->cur.col, ncol - 1); 519 min_it (s->cur.col, ncol - 1);
488#ifdef DEBUG_STRICT
489 assert (s->cur.row >= 0); 520 assert (s->cur.row >= 0);
490 assert (s->cur.col >= 0); 521 assert (s->cur.col >= 0);
491#endif
492} 522}
493 523
494void 524void
495rxvt_term::scr_swap_screen () 525rxvt_term::scr_swap_screen () NOTHROW
496{ 526{
497 if (!option (Opt_secondaryScreen)) 527 if (!option (Opt_secondaryScreen))
498 return; 528 return;
499 529
500 for (int i = prev_nrow; i--; ) 530 for (int i = prev_nrow; i--; )
519 return; 549 return;
520 550
521 want_refresh = 1; 551 want_refresh = 1;
522 view_start = 0; 552 view_start = 0;
523 553
524 selection_check (2); /* check for boundary cross */ 554 /* check for boundary cross */
555 row_col_t pos;
556 pos.row = pos.col = 0;
557 if (ROWCOL_IS_BEFORE (selection.beg, pos)
558 && ROWCOL_IS_AFTER (selection.end, pos))
559 CLEAR_SELECTION ();
525 560
526 int i = current_screen; current_screen = scrn; scrn = i; 561 current_screen = scrn;
527 562
528#if NSCREENS 563#if NSCREENS
529 if (option (Opt_secondaryScreen)) 564 if (option (Opt_secondaryScreen))
530 { 565 {
531 num_scr = 0; 566 num_scr = 0;
608 643
609 if (count > 0 644 if (count > 0
610 && row1 == 0 645 && row1 == 0
611 && (current_screen == PRIMARY || option (Opt_secondaryScroll))) 646 && (current_screen == PRIMARY || option (Opt_secondaryScroll)))
612 { 647 {
648 min_it (count, total_rows - (nrow - (row2 + 1)));
649
613 top_row = max (top_row - count, -saveLines); 650 top_row = max (top_row - count, -saveLines);
614
615 // scroll everything up 'count' lines
616 term_start = (term_start + count) % total_rows;
617 651
618 // sever bottommost line 652 // sever bottommost line
619 { 653 {
620 line_t &l = ROW(row2 - count); 654 line_t &l = ROW(row2);
621 l.is_longer (0); 655 l.is_longer (0);
622 l.touch (); 656 l.touch ();
623 } 657 }
624 658
659 // scroll everything up 'count' lines
660 term_start = (term_start + count) % total_rows;
661
662 // now copy lines below the scroll region bottom to the
663 // bottom of the screen again, so they look as if they
664 // hadn't moved.
665 for (int i = nrow; --i > row2; )
666 {
667 line_t &l1 = ROW(i - count);
668 line_t &l2 = ROW(i);
669
670 ::swap (l1, l2);
671 l2.touch ();
672 }
673
625 // erase newly scrolled-in lines 674 // erase newly scrolled-in lines
626 for (int i = count; i--; ) 675 for (int i = count; i--; )
627 { 676 {
628 line_t &l = ROW(nrow - 1 - i); 677 line_t &l = ROW(row2 - i);
629 678
630 // optimize if already cleared, can be significant on slow machines 679 // optimise if already cleared, can be significant on slow machines
631 // could be rolled into scr_blank_screen_mem 680 // could be rolled into scr_blank_screen_mem
632 if (l.r && l.l < ncol - 1 && !((l.r[l.l + 1] ^ rstyle) & (RS_fgMask | RS_bgMask))) 681 if (l.r && l.l < ncol - 1 && !((l.r[l.l + 1] ^ rstyle) & (RS_fgMask | RS_bgMask)))
633 { 682 {
634 scr_blank_line (l, 0, l.l, rstyle); 683 scr_blank_line (l, 0, l.l, rstyle);
635 l.l = 0; 684 l.l = 0;
637 } 686 }
638 else 687 else
639 scr_blank_screen_mem (l, rstyle); 688 scr_blank_screen_mem (l, rstyle);
640 } 689 }
641 690
642 // now copy lines below the scroll region bottom to the
643 // bottom of the screen again, so they look as if they
644 // hadn't moved.
645 for (int i = nrow; --i > row2; )
646 {
647 line_t &l1 = ROW(i - count);
648 line_t &l2 = ROW(i);
649
650 ::swap (l1, l2);
651 l2.touch ();
652 }
653
654 // move and/or clear selection, if any 691 // move and/or clear selection, if any
655 if (selection.op && current_screen == selection.screen) 692 if (selection.op && current_screen == selection.screen
693 && selection.beg.row <= row2)
656 { 694 {
657 selection.beg.row -= count; 695 selection.beg.row -= count;
658 selection.end.row -= count; 696 selection.end.row -= count;
659 selection.mark.row -= count; 697 selection.mark.row -= count;
660 698
661 if (selection.beg.row < top_row 699 selection_check (0);
662 || selection.end.row < top_row
663 || selection.mark.row < top_row)
664 {
665 CLEAR_ALL_SELECTION ();
666 selection.op = SELECTION_CLEAR;
667 }
668 } 700 }
669 701
670 // finally move the view window, if desired 702 // finally move the view window, if desired
671 if (option (Opt_scrollWithBuffer) 703 if (option (Opt_scrollWithBuffer)
672 && view_start != 0 704 && view_start != 0
702 } 734 }
703 735
704 // use a simple and robust scrolling algorithm, this 736 // use a simple and robust scrolling algorithm, this
705 // part of scr_scroll_text is not time-critical. 737 // part of scr_scroll_text is not time-critical.
706 738
739 // sever line above scroll region
740 if (row1)
741 {
742 line_t &l = ROW(row1 - 1);
743 l.is_longer (0);
744 l.touch ();
745 }
746
707 int rows = row2 - row1 + 1; 747 int rows = row2 - row1 + 1;
708 748
709 min_it (count, rows); 749 min_it (count, rows);
710 750
711 line_t *temp_buf = row_buf + total_rows; 751 line_t *temp_buf = rxvt_temp_buf<line_t> (rows);
712 752
713 for (int row = 0; row < rows; row++) 753 for (int row = 0; row < rows; row++)
714 { 754 {
715 temp_buf [row] = ROW(row1 + (row + count + rows) % rows); 755 temp_buf [row] = ROW(row1 + (row + count + rows) % rows);
716 756
718 scr_blank_screen_mem (temp_buf [row], rstyle); 758 scr_blank_screen_mem (temp_buf [row], rstyle);
719 } 759 }
720 760
721 for (int row = 0; row < rows; row++) 761 for (int row = 0; row < rows; row++)
722 ROW(row1 + row) = temp_buf [row]; 762 ROW(row1 + row) = temp_buf [row];
763
764 // sever bottommost line
765 {
766 line_t &l = ROW(row2);
767 l.is_longer (0);
768 l.touch ();
769 }
723 } 770 }
724 771
725 return count; 772 return count;
726} 773}
727 774
733rxvt_term::scr_add_lines (const wchar_t *str, int len, int minlines) NOTHROW 780rxvt_term::scr_add_lines (const wchar_t *str, int len, int minlines) NOTHROW
734{ 781{
735 if (len <= 0) /* sanity */ 782 if (len <= 0) /* sanity */
736 return; 783 return;
737 784
738 unsigned char checksel; 785 bool checksel;
739 unicode_t c; 786 unicode_t c;
740 int ncol = this->ncol; 787 int ncol = this->ncol;
741 const wchar_t *strend = str + len; 788 const wchar_t *strend = str + len;
742 789
743 want_refresh = 1; 790 want_refresh = 1;
756 scr_scroll_text (screen.tscroll, screen.bscroll, minlines); 803 scr_scroll_text (screen.tscroll, screen.bscroll, minlines);
757 screen.cur.row -= minlines; 804 screen.cur.row -= minlines;
758 } 805 }
759 } 806 }
760 807
761#ifdef DEBUG_STRICT
762 assert (screen.cur.col < ncol); 808 assert (screen.cur.col < ncol);
763 assert (screen.cur.row < nrow 809 assert (screen.cur.row < nrow
764 && screen.cur.row >= top_row); 810 && screen.cur.row >= top_row);
765#endif
766 int row = screen.cur.row; 811 int row = screen.cur.row;
767 812
768 checksel = selection.op && current_screen == selection.screen ? 1 : 0; 813 checksel = selection.op && current_screen == selection.screen ? 1 : 0;
769 814
770 line_t *line = &ROW(row); 815 line_t *line = &ROW(row);
771 816
772 while (str < strend) 817 while (str < strend)
773 { 818 {
774 c = (unicode_t)*str++; // convert to rxvt-unicodes representation 819 c = (unicode_t)*str++; // convert to rxvt-unicodes representation
775 820
776 if (c < 0x20) 821 if (ecb_unlikely (c < 0x20))
777 if (c == C0_LF) 822 if (c == C0_LF)
778 { 823 {
779 max_it (line->l, screen.cur.col); 824 max_it (line->l, screen.cur.col);
780 825
781 screen.flags &= ~Screen_WrapNext; 826 screen.flags &= ~Screen_WrapNext;
800 { 845 {
801 scr_tab (1, true); 846 scr_tab (1, true);
802 continue; 847 continue;
803 } 848 }
804 849
850 if (ecb_unlikely (
805 if (checksel /* see if we're writing within selection */ 851 checksel /* see if we're writing within selection */
806 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) 852 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
807 && ROWCOL_IS_BEFORE (screen.cur, selection.end)) 853 && ROWCOL_IS_BEFORE (screen.cur, selection.end)
854 ))
808 { 855 {
809 checksel = 0; 856 checksel = 0;
810 /* 857 /*
811 * If we wrote anywhere in the selected area, kill the selection 858 * If we wrote anywhere in the selected area, kill the selection
812 * XXX: should we kill the mark too? Possibly, but maybe that 859 * XXX: should we kill the mark too? Possibly, but maybe that
813 * should be a similar check. 860 * should be a similar check.
814 */ 861 */
815 CLEAR_SELECTION (); 862 CLEAR_SELECTION ();
816 } 863 }
817 864
818 if (screen.flags & Screen_WrapNext) 865 if (ecb_unlikely (screen.flags & Screen_WrapNext))
819 { 866 {
820 scr_do_wrap (); 867 scr_do_wrap ();
821 868
822 line->l = ncol; 869 line->l = ncol;
823 line->is_longer (1); 870 line->is_longer (1);
825 row = screen.cur.row; 872 row = screen.cur.row;
826 line = &ROW(row); /* _must_ refresh */ 873 line = &ROW(row); /* _must_ refresh */
827 } 874 }
828 875
829 // some utf-8 decoders "decode" surrogate characters: let's fix this. 876 // some utf-8 decoders "decode" surrogate characters: let's fix this.
830 if (IN_RANGE_INC (c, 0xd800, 0xdfff)) 877 if (ecb_unlikely (IN_RANGE_INC (c, 0xd800, 0xdfff)))
831 c = 0xfffd; 878 c = 0xfffd;
832 879
833 // rely on wcwidth to tell us the character width, do wcwidth before 880 // rely on wcwidth to tell us the character width, do wcwidth before
834 // further replacements, as wcwidth might return -1 for the line 881 // further replacements, as wcwidth might return -1 for the line
835 // drawing characters below as they might be invalid in the current 882 // drawing characters below as they might be invalid in the current
836 // locale. 883 // locale.
837 int width = WCWIDTH (c); 884 int width = WCWIDTH (c);
838 885
839 if (charsets [screen.charset] == '0') // DEC SPECIAL 886 if (ecb_unlikely (charsets [screen.charset] == '0')) // DEC SPECIAL
840 { 887 {
841 // vt100 special graphics and line drawing 888 // vt100 special graphics and line drawing
842 // 5f-7e standard vt100 889 // 5f-7e standard vt100
843 // 40-5e rxvt extension for extra curses acs chars 890 // 40-5e rxvt extension for extra curses acs chars
844 static uint16_t vt100_0[62] = { // 41 .. 7e 891 static uint16_t vt100_0[62] = { // 41 .. 7e
857 c = vt100_0[c - 0x41]; 904 c = vt100_0[c - 0x41];
858 width = 1; // vt100 line drawing characters are always single-width 905 width = 1; // vt100 line drawing characters are always single-width
859 } 906 }
860 } 907 }
861 908
862 if (screen.flags & Screen_Insert) 909 if (ecb_unlikely (screen.flags & Screen_Insert))
863 scr_insdel_chars (width, INSERT); 910 scr_insdel_chars (width, INSERT);
864 911
865 if (width != 0) 912 if (width != 0)
866 { 913 {
867#if !UNICODE_3 914#if !UNICODE_3
872# else 919# else
873 c = 0xfffd; 920 c = 0xfffd;
874# endif 921# endif
875#endif 922#endif
876 923
924 rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
925
926 // if the character doesn't fit into the remaining columns...
927 if (ecb_unlikely (screen.cur.col > ncol - width && ncol >= width))
928 {
929 if (screen.flags & Screen_Autowrap)
930 {
931 // ... artificially enlargen the previous one
932 c = NOCHAR;
933 // and try the same character next loop iteration
934 --str;
935 }
936 else
937 screen.cur.col = ncol - width;
938 }
939
877 // nuke the character at this position, if required 940 // nuke the character at this position, if required
941 // due to wonderful coincidences everywhere else in this loop
942 // we never have to check for overwriting a wide char itself,
943 // only its tail.
878 if (line->t[screen.cur.col] == NOCHAR 944 if (ecb_unlikely (line->t[screen.cur.col] == NOCHAR))
879 || (screen.cur.col < ncol - 1 945 scr_kill_char (*line, screen.cur.col);
880 && line->t[screen.cur.col + 1] == NOCHAR))
881 {
882 int col = screen.cur.col;
883
884 // find begin
885 while (col > 0 && line->t[col] == NOCHAR)
886 col--;
887
888 rend_t rend = SET_FONT (line->r[col], FONTSET (line->r[col])->find_font (' '));
889
890 // found begin, nuke
891 do {
892 line->t[col] = ' ';
893 line->r[col] = rend;
894 col++;
895 } while (col < ncol && line->t[col] == NOCHAR);
896 }
897
898 rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
899
900 // if the character doesn't fit into the remaining columns...
901 if (screen.cur.col > ncol - width && ncol >= width)
902 {
903 // ...output spaces
904 c = ' ';
905 // and try the same character next loop iteration
906 --str;
907 }
908 946
909 line->touch (); 947 line->touch ();
910 948
911 do 949 do
912 { 950 {
913 line->t[screen.cur.col] = c; 951 line->t[screen.cur.col] = c;
914 line->r[screen.cur.col] = rend; 952 line->r[screen.cur.col] = rend;
915 953
916 if (screen.cur.col < ncol - 1) 954 if (ecb_likely (screen.cur.col < ncol - 1))
917 screen.cur.col++; 955 screen.cur.col++;
918 else 956 else
919 { 957 {
920 line->l = ncol; 958 line->l = ncol;
921 if (screen.flags & Screen_Autowrap) 959 if (screen.flags & Screen_Autowrap)
922 screen.flags |= Screen_WrapNext; 960 screen.flags |= Screen_WrapNext;
923 break; 961
962 goto end_of_line;
924 } 963 }
925 964
926 c = NOCHAR; 965 c = NOCHAR;
927 } 966 }
928 while (--width > 0); 967 while (ecb_unlikely (--width > 0));
929 968
930 // pad with spaces when overwriting wide character with smaller one 969 // pad with spaces when overwriting wide character with smaller one
931 if (!width) 970 for (int c = screen.cur.col; ecb_unlikely (c < ncol && line->t[c] == NOCHAR); c++)
932 { 971 {
933 line->touch (); 972 line->t[c] = ' ';
973 line->r[c] = rend;
974 }
934 975
935 for (int c = screen.cur.col; c < ncol && line->t[c] == NOCHAR; c++) 976end_of_line:
977 ;
978 }
979#if ENABLE_COMBINING
980 else // width == 0
981 {
982 if (c != 0xfeff) // ignore BOM
983 {
984 // handle combining characters
985 // we just tag the accent on the previous on-screen character.
986 // this is arguably not correct, but also arguably not wrong.
987 // we don't handle double-width characters nicely yet.
988 line_t *linep;
989 text_t *tp;
990 rend_t *rp;
991
992 if (screen.cur.col > 0)
936 { 993 {
937 line->t[c] = ' ';
938 line->r[c] = rend; 994 linep = line;
995 tp = line->t + screen.cur.col - 1;
996 rp = line->r + screen.cur.col - 1;
939 } 997 }
998 else if (screen.cur.row > 0
999 && ROW(screen.cur.row - 1).is_longer ())
1000 {
1001 linep = &ROW(screen.cur.row - 1);
1002 tp = line->t + ncol - 1;
1003 rp = line->r + ncol - 1;
1004 }
1005 else
1006 continue;
1007
1008 linep->touch ();
1009
1010 while (*tp == NOCHAR && tp > linep->t)
1011 tp--, rp--;
1012
1013 // first try to find a precomposed character
1014 unicode_t n = rxvt_compose (*tp, c);
1015 if (n == NOCHAR)
1016 n = rxvt_composite.compose (*tp, c);
1017
1018 *tp = n;
1019 *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
940 } 1020 }
941 } 1021 }
942 else // width == 0
943 {
944#if ENABLE_COMBINING
945 // handle combining characters
946 // we just tag the accent on the previous on-screen character.
947 // this is arguably not correct, but also arguably not wrong.
948 // we don't handle double-width characters nicely yet.
949 line_t *linep;
950 text_t *tp;
951 rend_t *rp;
952
953 if (screen.cur.col > 0)
954 {
955 linep = line;
956 tp = line->t + screen.cur.col - 1;
957 rp = line->r + screen.cur.col - 1;
958 }
959 else if (screen.cur.row > 0
960 && ROW(screen.cur.row - 1).is_longer ())
961 {
962 linep = &ROW(screen.cur.row - 1);
963 tp = line->t + ncol - 1;
964 rp = line->r + ncol - 1;
965 }
966 else
967 continue;
968
969 linep->touch ();
970
971 while (*tp == NOCHAR && tp > linep->t)
972 tp--, rp--;
973
974 // first try to find a precomposed character
975 unicode_t n = rxvt_compose (*tp, c);
976 if (n == NOCHAR)
977 n = rxvt_composite.compose (*tp, c);
978
979 *tp = n;
980 *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
981#endif 1022#endif
982 }
983 } 1023 }
984 1024
985 max_it (line->l, screen.cur.col); 1025 max_it (line->l, screen.cur.col);
986 1026
987#ifdef DEBUG_STRICT
988 assert (screen.cur.row >= 0); 1027 assert (screen.cur.row >= 0);
989#endif
990} 1028}
991 1029
992/* ------------------------------------------------------------------------- */ 1030/* ------------------------------------------------------------------------- */
993/* 1031/*
994 * Process Backspace. Move back the cursor back a position, wrap if have to 1032 * Process Backspace. Move back the cursor back a position, wrap if have to
1007 1045
1008 want_refresh = 1; 1046 want_refresh = 1;
1009#endif 1047#endif
1010 } 1048 }
1011 } 1049 }
1050 else if (screen.flags & Screen_WrapNext)
1051 screen.flags &= ~Screen_WrapNext;
1012 else 1052 else
1013 scr_gotorc (0, -1, RELATIVE); 1053 scr_gotorc (0, -1, RELATIVE);
1014} 1054}
1015 1055
1016/* ------------------------------------------------------------------------- */ 1056/* ------------------------------------------------------------------------- */
1272 scr_blank_line (line, col, num, rstyle); 1312 scr_blank_line (line, col, num, rstyle);
1273} 1313}
1274 1314
1275/* ------------------------------------------------------------------------- */ 1315/* ------------------------------------------------------------------------- */
1276/* 1316/*
1277 * Erase part of whole of the screen 1317 * Erase part or whole of the screen
1278 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J 1318 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1279 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J 1319 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1280 * XTERM_SEQ: Clear whole screen : ESC [ 2 J 1320 * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1281 */ 1321 */
1282void 1322void
1291 ZERO_SCROLLBACK (); 1331 ZERO_SCROLLBACK ();
1292 1332
1293 switch (mode) 1333 switch (mode)
1294 { 1334 {
1295 case 0: /* erase to end of screen */ 1335 case 0: /* erase to end of screen */
1296 selection_check (1);
1297 scr_erase_line (0); 1336 scr_erase_line (0);
1298 row = screen.cur.row + 1; /* possible OOB */ 1337 row = screen.cur.row + 1; /* possible OOB */
1299 num = nrow - row; 1338 num = nrow - row;
1300 break; 1339 break;
1301 case 1: /* erase to beginning of screen */ 1340 case 1: /* erase to beginning of screen */
1302 selection_check (3);
1303 scr_erase_line (1); 1341 scr_erase_line (1);
1304 row = 0; 1342 row = 0;
1305 num = screen.cur.row; 1343 num = screen.cur.row;
1306 break; 1344 break;
1307 case 2: /* erase whole screen */ 1345 case 2: /* erase whole screen */
1308 selection_check (3);
1309 row = 0; 1346 row = 0;
1310 num = nrow; 1347 num = nrow;
1311 break; 1348 break;
1312 default: 1349 default:
1313 return; 1350 return;
1322 if (row >= nrow) /* Out Of Bounds */ 1359 if (row >= nrow) /* Out Of Bounds */
1323 return; 1360 return;
1324 1361
1325 min_it (num, nrow - row); 1362 min_it (num, nrow - row);
1326 1363
1327 /*TODO: the xlceararea/xfillrectangle below don't take scroll offste into account, ask mikachu for details */
1328 if (rstyle & (RS_RVid | RS_Uline)) 1364 if (rstyle & (RS_Blink | RS_RVid | RS_Uline))
1329 ren = (rend_t) ~RS_None; 1365 ren = (rend_t) ~RS_None;
1330 else if (GET_BASEBG (rstyle) == Color_bg) 1366 else if (GET_BASEBG (rstyle) == Color_bg)
1331 { 1367 {
1332 ren = DEFAULT_RSTYLE; 1368 ren = DEFAULT_RSTYLE;
1333 1369
1334 if (mapped) 1370 if (mapped)
1335 XClearArea (dpy, vt, 0, 1371 XClearArea (dpy, vt, 0,
1336 Row2Pixel (row), (unsigned int)width, 1372 Row2Pixel (row - view_start), (unsigned int)vt_width,
1337 (unsigned int)Height2Pixel (num), False); 1373 (unsigned int)Height2Pixel (num), False);
1338 } 1374 }
1339 else 1375 else
1340 { 1376 {
1341 ren = rstyle & (RS_fgMask | RS_bgMask); 1377 ren = rstyle & (RS_fgMask | RS_bgMask);
1342 1378
1379 if (mapped)
1380 {
1343 gcvalue.foreground = pix_colors[bgcolor_of (rstyle)]; 1381 gcvalue.foreground = pix_colors[bgcolor_of (rstyle)];
1344 XChangeGC (dpy, gc, GCForeground, &gcvalue); 1382 XChangeGC (dpy, gc, GCForeground, &gcvalue);
1345 XFillRectangle (dpy, vt, gc, 1383 XFillRectangle (dpy, vt, gc,
1346 0, Row2Pixel (row), 1384 0, Row2Pixel (row - view_start),
1347 (unsigned int)width, 1385 (unsigned int)vt_width,
1348 (unsigned int)Height2Pixel (num)); 1386 (unsigned int)Height2Pixel (num));
1349 gcvalue.foreground = pix_colors[Color_fg]; 1387 gcvalue.foreground = pix_colors[Color_fg];
1350 XChangeGC (dpy, gc, GCForeground, &gcvalue); 1388 XChangeGC (dpy, gc, GCForeground, &gcvalue);
1389 }
1351 } 1390 }
1352 1391
1353 for (; num--; row++) 1392 for (; num--; row++)
1354 { 1393 {
1355 scr_blank_screen_mem (ROW(row), rstyle); 1394 scr_blank_screen_mem (ROW(row), rstyle);
1395
1396 if (row - view_start < nrow)
1356 scr_blank_line (drawn_buf [row], 0, ncol, ren); 1397 scr_blank_line (drawn_buf [row - view_start], 0, ncol, ren);
1357 } 1398 }
1358} 1399}
1359 1400
1360#if !ENABLE_MINIMAL 1401#if !ENABLE_MINIMAL
1361void 1402void
1380 1421
1381 want_refresh = 1; 1422 want_refresh = 1;
1382 ZERO_SCROLLBACK (); 1423 ZERO_SCROLLBACK ();
1383 1424
1384 num_scr_allow = 0; 1425 num_scr_allow = 0;
1385 selection_check (3); 1426
1427 row_col_t pos;
1428 pos.row = pos.col = 0;
1429 if (ROWCOL_IS_AFTER (selection.end, pos))
1430 CLEAR_SELECTION ();
1386 1431
1387 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E')); 1432 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E'));
1388 for (int row = nrow; row--; ) 1433 for (int row = nrow; row--; )
1389 { 1434 {
1390 line_t &line = ROW(row); 1435 line_t &line = ROW(row);
1435 * Insert/Delete <count> characters from the current position 1480 * Insert/Delete <count> characters from the current position
1436 */ 1481 */
1437void 1482void
1438rxvt_term::scr_insdel_chars (int count, int insdel) NOTHROW 1483rxvt_term::scr_insdel_chars (int count, int insdel) NOTHROW
1439{ 1484{
1440 int col, row;
1441 rend_t tr;
1442
1443 want_refresh = 1; 1485 want_refresh = 1;
1444 ZERO_SCROLLBACK (); 1486 ZERO_SCROLLBACK ();
1445 1487
1446 if (count <= 0) 1488 if (count <= 0)
1447 return; 1489 return;
1449 scr_do_wrap (); 1491 scr_do_wrap ();
1450 1492
1451 selection_check (1); 1493 selection_check (1);
1452 min_it (count, ncol - screen.cur.col); 1494 min_it (count, ncol - screen.cur.col);
1453 1495
1454 row = screen.cur.row; 1496 int row = screen.cur.row;
1455 1497
1456 line_t *line = &ROW(row); 1498 line_t *line = &ROW(row);
1457 1499
1458 line->touch (); 1500 line->touch ();
1459 line->is_longer (0); 1501 line->is_longer (0);
1460 1502
1503 // nuke wide spanning the start
1504 if (line->t[screen.cur.col] == NOCHAR)
1505 scr_kill_char (*line, screen.cur.col);
1506
1461 switch (insdel) 1507 switch (insdel)
1462 { 1508 {
1463 case INSERT: 1509 case INSERT:
1464 for (col = ncol - 1; (col - count) >= screen.cur.col; col--) 1510 line->l = min (line->l + count, ncol);
1511
1512 if (line->t[screen.cur.col] == NOCHAR)
1513 scr_kill_char (*line, screen.cur.col);
1514
1515 for (int col = ncol - 1; (col - count) >= screen.cur.col; col--)
1465 { 1516 {
1466 line->t[col] = line->t[col - count]; 1517 line->t[col] = line->t[col - count];
1467 line->r[col] = line->r[col - count]; 1518 line->r[col] = line->r[col - count];
1468 } 1519 }
1469
1470 line->l = min (line->l + count, ncol);
1471 1520
1472 if (selection.op && current_screen == selection.screen 1521 if (selection.op && current_screen == selection.screen
1473 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) 1522 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1474 { 1523 {
1475 if (selection.end.row != screen.cur.row 1524 if (selection.end.row != screen.cur.row
1490 case ERASE: 1539 case ERASE:
1491 screen.cur.col += count; /* don't worry if > ncol */ 1540 screen.cur.col += count; /* don't worry if > ncol */
1492 selection_check (1); 1541 selection_check (1);
1493 screen.cur.col -= count; 1542 screen.cur.col -= count;
1494 1543
1495 line->l = max (line->l - count, 0); 1544 // nuke wide char after the end
1545 if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR)
1546 scr_kill_char (*line, screen.cur.col + count);
1547
1496 scr_blank_line (*line, screen.cur.col, count, rstyle); 1548 scr_blank_line (*line, screen.cur.col, count, rstyle);
1497 break; 1549 break;
1498 1550
1499 case DELETE: 1551 case DELETE:
1500 tr = line->r[ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask); 1552 line->l = max (line->l - count, 0);
1501 1553
1554 // nuke wide char spanning the end
1555 if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR)
1556 scr_kill_char (*line, screen.cur.col + count);
1557
1502 for (col = screen.cur.col; (col + count) < ncol; col++) 1558 for (int col = screen.cur.col; (col + count) < ncol; col++)
1503 { 1559 {
1504 line->t[col] = line->t[col + count]; 1560 line->t[col] = line->t[col + count];
1505 line->r[col] = line->r[col + count]; 1561 line->r[col] = line->r[col + count];
1506 } 1562 }
1507 1563
1508 line->l = max (line->l - count, 0);
1509 scr_blank_line (*line, ncol - count, count, tr); 1564 scr_blank_line (*line, ncol - count, count, rstyle);
1510 1565
1511 if (selection.op && current_screen == selection.screen 1566 if (selection.op && current_screen == selection.screen
1512 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) 1567 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1513 { 1568 {
1514 if (selection.end.row != screen.cur.row 1569 if (selection.end.row != screen.cur.row
1650 { 1705 {
1651 rvideo_state = on; 1706 rvideo_state = on;
1652 1707
1653 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]); 1708 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]);
1654#ifdef HAVE_BG_PIXMAP 1709#ifdef HAVE_BG_PIXMAP
1655 if (bgPixmap.pixmap == None) 1710 if (bg_pixmap == None)
1656#endif 1711#endif
1657 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]); 1712 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
1658 1713
1659 XGCValues gcvalue; 1714 XGCValues gcvalue;
1660 gcvalue.foreground = pix_colors[Color_fg]; 1715 gcvalue.foreground = pix_colors[Color_fg];
1804 for (i = PART_BEG; i < RC_COUNT; i++) 1859 for (i = PART_BEG; i < RC_COUNT; i++)
1805 { 1860 {
1806 min_it (rc[i].col, ncol - 1); 1861 min_it (rc[i].col, ncol - 1);
1807 min_it (rc[i].row, nrow - 1); 1862 min_it (rc[i].row, nrow - 1);
1808 } 1863 }
1809// TODO: this line somehow causes segfault if scr_expose() is called just after resize 1864
1810 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++) 1865 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1811 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1); 1866 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
1812 1867
1813 num_scr_allow = 0; 1868 num_scr_allow = 0;
1814 1869
1821 * Refresh the entire screen 1876 * Refresh the entire screen
1822 */ 1877 */
1823void 1878void
1824rxvt_term::scr_touch (bool refresh) NOTHROW 1879rxvt_term::scr_touch (bool refresh) NOTHROW
1825{ 1880{
1826 scr_expose (0, 0, width, height, refresh); 1881 scr_expose (0, 0, vt_width, vt_height, refresh);
1827} 1882}
1828 1883
1829/* ------------------------------------------------------------------------- */ 1884/* ------------------------------------------------------------------------- */
1830/* 1885/*
1831 * Move the display so that the line represented by scrollbar value Y is at 1886 * Move the display so that the line represented by scrollbar value Y is at
1887 1942
1888# ifndef NO_MAPALERT 1943# ifndef NO_MAPALERT
1889# ifdef MAPALERT_OPTION 1944# ifdef MAPALERT_OPTION
1890 if (option (Opt_mapAlert)) 1945 if (option (Opt_mapAlert))
1891# endif 1946# endif
1892 XMapWindow (dpy, parent[0]); 1947 XMapWindow (dpy, parent);
1893# endif 1948# endif
1894 1949
1895# if ENABLE_FRILLS 1950# if ENABLE_FRILLS
1896 if (option (Opt_urgentOnBell)) 1951 if (option (Opt_urgentOnBell))
1897 { 1952 set_urgency (1);
1898 if (XWMHints *h = XGetWMHints(dpy, parent[0]))
1899 {
1900 h->flags |= XUrgencyHint;
1901 XSetWMHints (dpy, parent[0], h);
1902 }
1903 }
1904# endif 1953# endif
1905 1954
1906 if (option (Opt_visualBell)) 1955 if (option (Opt_visualBell))
1907 { 1956 {
1908 rvideo_bell = true; 1957 rvideo_bell = true;
1911 1960
1912 bell_ev.start (VISUAL_BELL_DURATION); 1961 bell_ev.start (VISUAL_BELL_DURATION);
1913 } 1962 }
1914 else 1963 else
1915 XBell (dpy, 0); 1964 XBell (dpy, 0);
1965 HOOK_INVOKE ((this, HOOK_BELL, DT_END));
1916#endif 1966#endif
1917} 1967}
1918 1968
1919/* ------------------------------------------------------------------------- */ 1969/* ------------------------------------------------------------------------- */
1920/* ARGSUSED */
1921void 1970void
1922rxvt_term::scr_printscreen (int fullhist) NOTHROW 1971rxvt_term::scr_printscreen (int fullhist) NOTHROW
1923{ 1972{
1924#ifdef PRINTPIPE 1973#ifdef PRINTPIPE
1925 int nrows, row_start; 1974 int nrows, row_start;
1926 FILE *fd; 1975 FILE *fd = popen_printer ();
1927 1976
1928 if ((fd = popen_printer ()) == NULL) 1977 if (!fd)
1929 return; 1978 return;
1930 1979
1931 if (fullhist) 1980 if (fullhist)
1932 { 1981 {
1933 nrows = nrow - top_row; 1982 nrows = nrow - top_row;
1939 row_start = view_start; 1988 row_start = view_start;
1940 } 1989 }
1941 1990
1942 wctomb (0, 0); 1991 wctomb (0, 0);
1943 1992
1944 for (int r1 = 0; r1 < nrows; r1++) 1993 for (int r1 = row_start; r1 < row_start + nrows; r1++)
1945 { 1994 {
1946 text_t *tp = ROW(r1).t; 1995 text_t *tp = ROW(r1).t;
1947 int len = ROW(r1).l; 1996 int len = ROW(r1).l;
1948 1997
1949 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN 1998 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN
1978 * screen.text/screen.rend contain what the screen will change to. 2027 * screen.text/screen.rend contain what the screen will change to.
1979 */ 2028 */
1980void 2029void
1981rxvt_term::scr_refresh () NOTHROW 2030rxvt_term::scr_refresh () NOTHROW
1982{ 2031{
1983 unsigned char have_bg,
1984 showcursor; /* show the cursor */
1985 int16_t col, row, /* column/row we're processing */ 2032 int16_t col, row, /* column/row we're processing */
1986 ocrow; /* old cursor row */ 2033 ocrow; /* old cursor row */
1987 int i; /* tmp */ 2034 int i; /* tmp */
1988#ifndef NO_CURSORCOLOR 2035#ifndef NO_CURSORCOLOR
1989 rend_t cc1; /* store colours at cursor position (s) */ 2036 rend_t cc1; /* store colours at cursor position (s) */
2000 /* 2047 /*
2001 * A: set up vars 2048 * A: set up vars
2002 */ 2049 */
2003 refresh_count = 0; 2050 refresh_count = 0;
2004 2051
2052 unsigned int old_screen_flags = screen.flags;
2005 have_bg = 0; 2053 bool have_bg = 0;
2006#ifdef HAVE_BG_PIXMAP 2054#ifdef HAVE_BG_PIXMAP
2007 have_bg = bgPixmap.pixmap != None; 2055 have_bg = bg_pixmap != None;
2008#endif 2056#endif
2009 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */ 2057 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
2010 2058
2011 /* 2059 /*
2012 * B: reverse any characters which are selected 2060 * B: reverse any characters which are selected
2013 */ 2061 */
2014 scr_reverse_selection (); 2062 scr_reverse_selection ();
2015 2063
2064 HOOK_INVOKE ((this, HOOK_REFRESH_BEGIN, DT_END));
2065#if ENABLE_OVERLAY
2066 scr_swap_overlay ();
2067#endif
2068
2069 bool showcursor = screen.flags & Screen_VisibleCursor;
2070
2016 /* 2071 /*
2017 * C: set the cursor character (s) 2072 * C: set the cursor character (s)
2018 */ 2073 */
2019 { 2074 {
2020 unsigned char setoldcursor; 2075 bool setoldcursor;
2021 2076
2022 showcursor = (screen.flags & Screen_VisibleCursor);
2023#ifdef CURSOR_BLINK 2077#ifdef CURSOR_BLINK
2024 if (hidden_cursor) 2078 if (hidden_cursor)
2025 showcursor = 0; 2079 showcursor = 0;
2026#endif 2080#endif
2027 2081
2055 ccol2 = bgcolor_of (rstyle); 2109 ccol2 = bgcolor_of (rstyle);
2056#else 2110#else
2057 ccol2 = Color_bg; 2111 ccol2 = Color_bg;
2058#endif 2112#endif
2059 2113
2060 if (showcursor && focus) 2114 if (focus)
2061 { 2115 {
2062 if (option (Opt_cursorUnderline)) 2116 if (option (Opt_cursorUnderline))
2063 *crp ^= RS_Uline; 2117 *crp ^= RS_Uline;
2064 else 2118 else
2065 { 2119 {
2100 oldcursor.col = screen.cur.col; 2154 oldcursor.col = screen.cur.col;
2101 } 2155 }
2102 } 2156 }
2103 } 2157 }
2104 2158
2105 HOOK_INVOKE ((this, HOOK_REFRESH_BEGIN, DT_END));
2106#if ENABLE_OVERLAY
2107 scr_swap_overlay ();
2108#endif
2109
2110#ifndef NO_SLOW_LINK_SUPPORT 2159#ifndef NO_SLOW_LINK_SUPPORT
2111 /* 2160 /*
2112 * D: CopyArea pass - very useful for slower links 2161 * D: CopyArea pass - very useful for slower links
2113 * This has been deliberately kept simple. 2162 * This has been deliberately kept simple.
2114 */ 2163 */
2118 { 2167 {
2119 int16_t nits; 2168 int16_t nits;
2120 int i = num_scr; 2169 int i = num_scr;
2121 int j; 2170 int j;
2122 int len, wlen; 2171 int len, wlen;
2123 dLocal (int, num_scr);
2124 2172
2125 j = nrow; 2173 j = nrow;
2126 wlen = len = -1; 2174 wlen = len = -1;
2127 row = i > 0 ? 0 : j - 1; 2175 row = i > 0 ? 0 : j - 1;
2128 2176
2203 continue; 2251 continue;
2204 2252
2205 // redraw one or more characters 2253 // redraw one or more characters
2206 2254
2207 // seek to the beginning of wide characters 2255 // seek to the beginning of wide characters
2208 while (stp[col] == NOCHAR && col > 0) 2256 while (ecb_unlikely (stp[col] == NOCHAR && col > 0))
2209 --col; 2257 --col;
2210 2258
2211 rend_t rend = srp[col]; /* screen rendition (target rendtion) */ 2259 rend_t rend = srp[col]; /* screen rendition (target rendition) */
2212 text_t *text = stp + col; 2260 text_t *text = stp + col;
2213 int count = 1; 2261 int count = 1;
2214 2262
2215 dtp[col] = stp[col]; 2263 dtp[col] = stp[col];
2216 drp[col] = rend; 2264 drp[col] = rend;
2220 for (i = 0; ++col < ncol; ) 2268 for (i = 0; ++col < ncol; )
2221 { 2269 {
2222 if (stp[col] == NOCHAR) 2270 if (stp[col] == NOCHAR)
2223 { 2271 {
2224 dtp[col] = stp[col]; 2272 dtp[col] = stp[col];
2225 drp[col] = rend; 2273 drp[col] = srp[col];
2274
2226 count++; 2275 count++;
2227 i++; 2276 i++;
2228 2277
2229 continue; 2278 continue;
2230 } 2279 }
2250 2299
2251 col--; /* went one too far. move back */ 2300 col--; /* went one too far. move back */
2252 count -= i; /* dump any matching trailing chars */ 2301 count -= i; /* dump any matching trailing chars */
2253 2302
2254 // sometimes we optimize away the trailing NOCHAR's, add them back 2303 // sometimes we optimize away the trailing NOCHAR's, add them back
2255 while (i && text[count] == NOCHAR) 2304 while (ecb_unlikely (i && text[count] == NOCHAR))
2256 count++, i--; 2305 count++, i--;
2257 2306
2258 /* 2307 /*
2259 * Determine the attributes for the string 2308 * Determine the attributes for the string
2260 */ 2309 */
2261 int fore = fgcolor_of (rend); // desired foreground 2310 int fore = fgcolor_of (rend); // desired foreground
2262 int back = bgcolor_of (rend); // desired background 2311 int back = bgcolor_of (rend); // desired background
2263 2312
2264 // only do special processing if any attributes are set, which is unlikely 2313 // only do special processing if any attributes are set, which is unlikely
2265 if (rend & (RS_Bold | RS_Italic | RS_Uline | RS_RVid | RS_Blink | RS_Careful)) 2314 if (ecb_unlikely (rend & (RS_baseattrMask | RS_Careful | RS_Sel)))
2266 { 2315 {
2267 bool invert = rend & RS_RVid; 2316 bool invert = rend & RS_RVid;
2268 2317
2269#ifndef NO_BOLD_UNDERLINE_REVERSE 2318#ifndef NO_BOLD_UNDERLINE_REVERSE
2270 if (rend & RS_Bold && fore == Color_fg) 2319 if (rend & RS_Bold && fore == Color_fg)
2289 2338
2290 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL)) 2339 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL))
2291 fore = Color_UL; 2340 fore = Color_UL;
2292#endif 2341#endif
2293 2342
2343#ifdef OPTION_HC
2344 if (rend & RS_Sel)
2345 {
2346 /* invert the column if no highlightColor is set or it is the
2347 * current cursor column */
2348 if (!(showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2349 && ISSET_PIXCOLOR (Color_HC))
2350 {
2351 if (ISSET_PIXCOLOR (Color_HTC))
2352 fore = Color_HTC;
2353 // if invert is 0 reverse video is set so we use bg color as fg color
2354 else if (!invert)
2355 fore = back;
2356
2357 back = Color_HC;
2358 invert = 0;
2359 }
2360 }
2361#endif
2362
2294 if (invert) 2363 if (invert)
2295 { 2364 {
2296#ifdef OPTION_HC
2297 if ((showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2298 || !ISSET_PIXCOLOR (Color_HC))
2299#endif
2300 /* invert the column if no highlightColor is set or it is the
2301 * current cursor column */
2302 ::swap (fore, back); 2365 ::swap (fore, back);
2303#ifdef OPTION_HC
2304 else if (ISSET_PIXCOLOR (Color_HC))
2305 back = Color_HC;
2306#endif
2307 2366
2308#ifndef NO_BOLD_UNDERLINE_REVERSE 2367#ifndef NO_BOLD_UNDERLINE_REVERSE
2309# ifndef OPTION_HC
2310 if (ISSET_PIXCOLOR (Color_RV))
2311 back = Color_RV;
2312# endif
2313 if (fore == back) 2368 if (fore == back)
2314 { 2369 {
2315 fore = Color_bg; 2370 fore = Color_bg;
2316 back = Color_fg; 2371 back = Color_fg;
2317 } 2372 }
2353 /* 2408 /*
2354 * Actually do the drawing of the string here 2409 * Actually do the drawing of the string here
2355 */ 2410 */
2356 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)]; 2411 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)];
2357 2412
2358 if (have_bg && back == Color_bg) 2413 if (ecb_likely (have_bg && back == Color_bg))
2359 { 2414 {
2360 // this is very ugly, maybe push it into ->draw? 2415 // this is very ugly, maybe push it into ->draw?
2361 2416
2362 for (i = 0; i < count; i++) /* don't draw empty strings */ 2417 for (i = 0; i < count; i++) /* don't draw empty strings */
2363 if (text[i] != ' ') 2418 if (text[i] != ' ')
2370 did_clear: ; 2425 did_clear: ;
2371 } 2426 }
2372 else 2427 else
2373 font->draw (*drawable, xpixel, ypixel, text, count, fore, back); 2428 font->draw (*drawable, xpixel, ypixel, text, count, fore, back);
2374 2429
2375 if (rend & RS_Uline && font->descent > 1 && fore != back) 2430 if (ecb_unlikely (rend & RS_Uline && font->descent > 1 && fore != back))
2376 { 2431 {
2377#if ENABLE_FRILLS 2432#if ENABLE_FRILLS
2378 if (ISSET_PIXCOLOR (Color_underline)) 2433 if (ISSET_PIXCOLOR (Color_underline))
2379 XSetForeground (dpy, gc, pix_colors[Color_underline]); 2434 XSetForeground (dpy, gc, pix_colors[Color_underline]);
2380 else 2435 else
2385 xpixel, ypixel + font->ascent + 1, 2440 xpixel, ypixel + font->ascent + 1,
2386 xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1); 2441 xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2387 } 2442 }
2388 } /* for (col....) */ 2443 } /* for (col....) */
2389 } /* for (row....) */ 2444 } /* for (row....) */
2390
2391#if ENABLE_OVERLAY
2392 scr_swap_overlay ();
2393#endif
2394 HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2395 2445
2396 /* 2446 /*
2397 * G: cleanup cursor and display outline cursor if necessary 2447 * G: cleanup cursor and display outline cursor if necessary
2398 */ 2448 */
2399 if (showcursor) 2449 if (showcursor)
2431 2481
2432 XDrawRectangle (dpy, vt, gc, 2482 XDrawRectangle (dpy, vt, gc,
2433 Col2Pixel (col), 2483 Col2Pixel (col),
2434 Row2Pixel (oldcursor.row), 2484 Row2Pixel (oldcursor.row),
2435 (unsigned int) (Width2Pixel (cursorwidth) - 1), 2485 (unsigned int) (Width2Pixel (cursorwidth) - 1),
2436 (unsigned int) (Height2Pixel (1) - lineSpace - 1)); 2486 (unsigned int) (Height2Pixel (1) - 1));
2437 } 2487 }
2438 } 2488 }
2439 2489
2440 /* 2490 /*
2441 * H: cleanup selection 2491 * H: cleanup selection
2442 */ 2492 */
2493#if ENABLE_OVERLAY
2494 scr_swap_overlay ();
2495#endif
2496 HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2497
2443 scr_reverse_selection (); 2498 scr_reverse_selection ();
2444 2499
2500 screen.flags = old_screen_flags;
2445 num_scr = 0; 2501 num_scr = 0;
2446 num_scr_allow = 1; 2502 num_scr_allow = 1;
2447} 2503}
2448 2504
2449void 2505void
2470 scr_remap_chars (swap_buf [i]); 2526 scr_remap_chars (swap_buf [i]);
2471 } 2527 }
2472} 2528}
2473 2529
2474void 2530void
2475rxvt_term::scr_recolour () NOTHROW 2531rxvt_term::scr_recolour (bool refresh) NOTHROW
2476{ 2532{
2533 bool transparent = false;
2534
2477#ifdef HAVE_BG_PIXMAP 2535#ifdef HAVE_BG_PIXMAP
2478 bgPixmap.apply (); 2536 if (bg_pixmap != None)
2479#else 2537 {
2538# ifdef ENABLE_TRANSPARENCY
2539 if (bg_flags & BG_IS_TRANSPARENT)
2540 {
2541 XSetWindowBackgroundPixmap (dpy, parent, bg_pixmap);
2542 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2480 2543
2544 transparent = true;
2545 }
2546 else
2547# endif
2548 {
2549 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2550 XSetWindowBackgroundPixmap (dpy, vt, bg_pixmap);
2551 }
2552 }
2553 else
2554#endif
2555 {
2481 XSetWindowBackground (dpy, parent[0], pix_colors[Color_border]); 2556 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2482 XClearWindow (dpy, parent[0]);
2483 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]); 2557 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
2558 }
2559
2560 XClearWindow (dpy, parent);
2484 2561
2485 if (scrollBar.win) 2562 if (scrollBar.win)
2486 { 2563 {
2564 if (transparent)
2565 XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
2566 else
2487 XSetWindowBackground (dpy, scrollBar.win, pix_colors[Color_border]); 2567 XSetWindowBackground (dpy, scrollBar.win, pix_colors[Color_border]);
2488 scrollBar.state = STATE_IDLE; 2568 scrollBar.state = SB_STATE_IDLE;
2489 scrollBar.show (0); 2569 scrollBar.show (0);
2490 } 2570 }
2491 2571
2492#endif 2572 if (refresh)
2493 2573 {
2494 /* bgPixmap.apply () does not do the following : */
2495 scr_clear (); 2574 scr_clear ();
2496 scr_touch (true); 2575 scr_touch (true);
2576 }
2497 want_refresh = 1; 2577 want_refresh = 1;
2498} 2578}
2499 2579
2500/* ------------------------------------------------------------------------- */ 2580/* ------------------------------------------------------------------------- */
2501void 2581void
2569 { 2649 {
2570#if !ENABLE_MINIMAL 2650#if !ENABLE_MINIMAL
2571 if (selection.rect) 2651 if (selection.rect)
2572 scr_xor_rect (selection.beg.row, selection.beg.col, 2652 scr_xor_rect (selection.beg.row, selection.beg.col,
2573 selection.end.row, selection.end.col, 2653 selection.end.row, selection.end.col,
2574 RS_RVid, RS_RVid | RS_Uline); 2654 RS_Sel | RS_RVid, RS_Sel | RS_RVid | RS_Uline);
2575 else 2655 else
2576#endif 2656#endif
2577 scr_xor_span (selection.beg.row, selection.beg.col, 2657 scr_xor_span (selection.beg.row, selection.beg.col,
2578 selection.end.row, selection.end.col, 2658 selection.end.row, selection.end.col,
2579 RS_RVid); 2659 RS_Sel | RS_RVid);
2580 } 2660 }
2581} 2661}
2582 2662
2583/* ------------------------------------------------------------------------- */ 2663/* ------------------------------------------------------------------------- */
2584/* 2664/*
2587 */ 2667 */
2588#if 0 2668#if 0
2589void 2669void
2590rxvt_term::scr_dump (int fd) NOTHROW 2670rxvt_term::scr_dump (int fd) NOTHROW
2591{ 2671{
2592 int row, wrote; 2672 // if this method is needed, it can be implemented by factoring the
2593 unsigned int width, towrite; 2673 // relevant code in scr_printscreen
2594 char r1[] = "\n";
2595
2596 for (row = saveLines + top_row;
2597 row < saveLines + nrow - 1; row++)
2598 {
2599 width = row_buf[row].l >= 0 ? row_buf[row].l
2600 : ncol;
2601 for (towrite = width; towrite; towrite -= wrote)
2602 {
2603 wrote = write (fd, & (row_buf[row].t[width - towrite]),
2604 towrite);
2605 if (wrote < 0)
2606 return; /* XXX: death, no report */
2607 }
2608 if (row_buf[row].l >= 0)
2609 if (write (fd, r1, 1) <= 0)
2610 return; /* XXX: death, no report */
2611 }
2612} 2674}
2613#endif 2675#endif
2614 2676
2615/* ------------------------------------------------------------------------- * 2677/* ------------------------------------------------------------------------- *
2616 * CHARACTER SELECTION * 2678 * CHARACTER SELECTION *
2617 * ------------------------------------------------------------------------- */ 2679 * ------------------------------------------------------------------------- */
2618void 2680void
2619rxvt_term::selection_check (int check_more) NOTHROW 2681rxvt_term::selection_check (int check_more) NOTHROW
2620{ 2682{
2621 row_col_t pos;
2622
2623 if (!selection.op) 2683 if (!selection.op)
2624 return; 2684 return;
2625 2685
2626 pos.row = pos.col = 0;
2627 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow) 2686 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow)
2628 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow) 2687 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow)
2629 || !IN_RANGE_EXC (selection.end.row, top_row, nrow) 2688 || !IN_RANGE_EXC (selection.end.row, top_row, nrow)
2630 || (check_more == 1 2689 || (check_more == 1
2631 && current_screen == selection.screen 2690 && current_screen == selection.screen
2632 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) 2691 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2633 && ROWCOL_IS_BEFORE (screen.cur, selection.end)) 2692 && ROWCOL_IS_BEFORE (screen.cur, selection.end)))
2634 || (check_more == 2
2635 && ROWCOL_IS_BEFORE (selection.beg, pos)
2636 && ROWCOL_IS_AFTER (selection.end, pos))
2637 || (check_more == 3
2638 && ROWCOL_IS_AFTER (selection.end, pos))
2639 || (check_more == 4 /* screen width change */
2640 && (selection.beg.row != selection.end.row
2641 || selection.end.col > ncol)))
2642 CLEAR_SELECTION (); 2693 CLEAR_ALL_SELECTION ();
2643} 2694}
2644 2695
2645/* ------------------------------------------------------------------------- */ 2696/* ------------------------------------------------------------------------- */
2646/* 2697/*
2647 * Paste a selection direct to the command fd 2698 * Paste a selection direct to the command fd
2648 */ 2699 */
2649void 2700void
2650rxvt_term::paste (char *data, unsigned int len) NOTHROW 2701rxvt_term::tt_paste (char *data, unsigned int len) NOTHROW
2651{ 2702{
2652 /* convert normal newline chars into common keyboard Return key sequence */ 2703 /* convert normal newline chars into common keyboard Return key sequence */
2653 for (unsigned int i = 0; i < len; i++) 2704 for (unsigned int i = 0; i < len; i++)
2654 if (data[i] == C0_LF) 2705 if (data[i] == C0_LF)
2655 data[i] = C0_CR; 2706 data[i] = C0_CR;
2656 2707
2657 if (priv_modes & PrivMode_BracketPaste) 2708 if (priv_modes & PrivMode_BracketPaste)
2658 tt_printf ("\e[200~"); 2709 tt_printf ("\x1b[200~");
2659 2710
2660 tt_write (data, len); 2711 tt_write (data, len);
2661 2712
2662 if (priv_modes & PrivMode_BracketPaste) 2713 if (priv_modes & PrivMode_BracketPaste)
2663 tt_printf ("\e[201~"); 2714 tt_printf ("\x1b[201~");
2664} 2715}
2665 2716
2666/* ------------------------------------------------------------------------- */
2667/*
2668 * Respond to a notification that a primary selection has been sent
2669 * EXT: SelectionNotify
2670 */
2671void 2717void
2672rxvt_term::selection_paste (Window win, Atom prop, bool delete_prop) NOTHROW 2718rxvt_term::paste (char *data, unsigned int len) NOTHROW
2673{ 2719{
2674 if (prop == None) /* check for failed XConvertSelection */ 2720 if (HOOK_INVOKE ((this, HOOK_TT_PASTE, DT_STR_LEN, data, len, DT_END)))
2675 {
2676 if ((selection_type & Sel_CompoundText))
2677 {
2678 int selnum = selection_type & Sel_whereMask;
2679
2680 selection_type = 0;
2681 if (selnum != Sel_direct)
2682 selection_request_other (XA_STRING, selnum);
2683 }
2684
2685 if ((selection_type & Sel_UTF8String))
2686 {
2687 int selnum = selection_type & Sel_whereMask;
2688
2689 selection_type = Sel_CompoundText;
2690 if (selnum != Sel_direct)
2691 selection_request_other (xa[XA_COMPOUND_TEXT], selnum);
2692 else
2693 selection_type = 0;
2694 }
2695
2696 return;
2697 }
2698
2699 unsigned long bytes_after;
2700 XTextProperty ct;
2701
2702 if (XGetWindowProperty (dpy, win, prop,
2703 0, PROP_SIZE / 4,
2704 delete_prop, AnyPropertyType,
2705 &ct.encoding, &ct.format,
2706 &ct.nitems, &bytes_after,
2707 &ct.value) != Success)
2708 {
2709 ct.value = 0;
2710 goto bailout;
2711 }
2712
2713 if (ct.encoding == None)
2714 goto bailout;
2715
2716 if (bytes_after)
2717 {
2718 // fetch and append remaining data
2719 XTextProperty ct2;
2720
2721 if (XGetWindowProperty (dpy, win, prop,
2722 ct.nitems / 4, (bytes_after + 3) / 4,
2723 delete_prop, AnyPropertyType,
2724 &ct2.encoding, &ct2.format,
2725 &ct2.nitems, &bytes_after,
2726 &ct2.value) != Success)
2727 goto bailout;
2728
2729 // realloc should be compatible to XFree, here, and elsewhere, too
2730 ct.value = (unsigned char *)realloc (ct.value, ct.nitems + ct2.nitems + 1);
2731 memcpy (ct.value + ct.nitems, ct2.value, ct2.nitems + 1);
2732 ct.nitems += ct2.nitems;
2733
2734 XFree (ct2.value);
2735 }
2736
2737 if (ct.value == 0)
2738 goto bailout;
2739
2740 if (ct.encoding == xa[XA_INCR])
2741 {
2742 // INCR selection, start handshake
2743 if (!delete_prop)
2744 XDeleteProperty (dpy, win, prop);
2745
2746 selection_wait = Sel_incr;
2747 incr_buf_fill = 0;
2748 incr_ev.start (10);
2749
2750 goto bailout;
2751 }
2752
2753 if (ct.nitems == 0)
2754 {
2755 if (selection_wait == Sel_incr)
2756 {
2757 XFree (ct.value);
2758
2759 // finally complete, now paste the whole thing
2760 selection_wait = Sel_normal;
2761 ct.value = (unsigned char *)incr_buf;
2762 ct.nitems = incr_buf_fill;
2763 incr_buf = 0;
2764 incr_buf_size = 0;
2765 incr_ev.stop ();
2766 }
2767 else
2768 {
2769 if (selection_wait == Sel_normal
2770 && (win != display->root || prop != XA_CUT_BUFFER0)) // avoid recursion
2771 {
2772 /*
2773 * pass through again trying CUT_BUFFER0 if we've come from
2774 * XConvertSelection () but nothing was presented
2775 */
2776 selection_paste (display->root, XA_CUT_BUFFER0, False);
2777 }
2778
2779 goto bailout;
2780 }
2781 }
2782 else if (selection_wait == Sel_incr)
2783 {
2784 incr_ev.start (10);
2785
2786 while (incr_buf_fill + ct.nitems > incr_buf_size)
2787 {
2788 incr_buf_size = incr_buf_size ? incr_buf_size * 2 : 128*1024;
2789 incr_buf = (char *)realloc (incr_buf, incr_buf_size);
2790 }
2791
2792 memcpy (incr_buf + incr_buf_fill, ct.value, ct.nitems);
2793 incr_buf_fill += ct.nitems;
2794
2795 goto bailout;
2796 }
2797
2798 char **cl;
2799 int cr;
2800
2801#if !ENABLE_MINIMAL
2802 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
2803 // so recode it manually
2804 if (ct.encoding == xa[XA_UTF8_STRING])
2805 {
2806 wchar_t *w = rxvt_utf8towcs ((const char *)ct.value, ct.nitems);
2807 char *s = rxvt_wcstombs (w);
2808 free (w);
2809 // TODO: strlen == only the first element will be converted. well...
2810 paste (s, strlen (s));
2811 free (s);
2812 }
2813 else
2814#endif
2815 if (XmbTextPropertyToTextList (dpy, &ct, &cl, &cr) >= 0
2816 && cl)
2817 {
2818 for (int i = 0; i < cr; i++)
2819 paste (cl[i], strlen (cl[i]));
2820
2821 XFreeStringList (cl);
2822 }
2823 else
2824 paste ((char *)ct.value, ct.nitems); // paste raw
2825
2826bailout:
2827 XFree (ct.value);
2828
2829 if (selection_wait == Sel_normal)
2830 selection_wait = Sel_none;
2831}
2832
2833void
2834rxvt_term::incr_cb (ev::timer &w, int revents) NOTHROW
2835{
2836 selection_wait = Sel_none;
2837
2838 incr_buf_size = 0;
2839 free (incr_buf);
2840
2841 rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
2842}
2843
2844void
2845rxvt_term::selection_property (Window win, Atom prop) NOTHROW
2846{
2847 if (prop == None || selection_wait != Sel_incr)
2848 return; 2721 return;
2849 2722
2850 selection_paste (win, prop, true); 2723 tt_paste (data, len);
2851} 2724}
2852 2725
2853/* ------------------------------------------------------------------------- */ 2726/* ------------------------------------------------------------------------- */
2854/* 2727/*
2855 * Request the current selection: 2728 * Request PRIMARY, SECONDARY or CLIPBOARD selection.
2856 * Order: > internal selection if available 2729 * if the requested selection has no owner or is empty CUT_BUFFER0 is used
2857 * > PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+) 2730 * as fallback
2858 * > CUT_BUFFER0
2859 * (+) if ownership is claimed but property is empty, rxvt_selection_paste ()
2860 * will auto fallback to CUT_BUFFER0
2861 * EXT: button 2 release 2731 * EXT: button 2 release
2862 */ 2732 */
2863void 2733void
2864rxvt_term::selection_request (Time tm, int selnum) NOTHROW 2734rxvt_term::selection_request (Time tm, int selnum) NOTHROW
2865{ 2735{
2866 if (selection.text && selnum == Sel_Primary) 2736 if (!selection_req)
2867 {
2868 /* internal selection */
2869 char *str = rxvt_wcstombs (selection.text, selection.len);
2870 paste (str, strlen (str));
2871 free (str);
2872 return;
2873 } 2737 {
2874 else 2738 selection_req = new rxvt_selection (display, selnum, tm, vt, xa[XA_VT_SELECTION], this);
2739 selection_req->run ();
2875 { 2740 }
2876 selection_request_time = tm;
2877 selection_wait = Sel_normal;
2878
2879#if X_HAVE_UTF8_STRING
2880 selection_type = Sel_UTF8String;
2881 if (selection_request_other (xa[XA_UTF8_STRING], selnum))
2882 return;
2883#else
2884 selection_type = Sel_CompoundText;
2885 if (selection_request_other (xa[XA_COMPOUND_TEXT], selnum))
2886 return;
2887#endif
2888 }
2889
2890 selection_wait = Sel_none; /* don't loop in selection_paste () */
2891 selection_paste (display->root, XA_CUT_BUFFER0, false);
2892}
2893
2894int
2895rxvt_term::selection_request_other (Atom target, int selnum) NOTHROW
2896{
2897 Atom sel;
2898
2899 selection_type |= selnum;
2900
2901 if (selnum == Sel_Primary)
2902 sel = XA_PRIMARY;
2903 else if (selnum == Sel_Secondary)
2904 sel = XA_SECONDARY;
2905 else
2906 sel = xa[XA_CLIPBOARD];
2907
2908 if (XGetSelectionOwner (dpy, sel) != None)
2909 {
2910 XConvertSelection (dpy, sel, target, xa[XA_VT_SELECTION],
2911 vt, selection_request_time);
2912 return 1;
2913 }
2914
2915 return 0;
2916} 2741}
2917 2742
2918/* ------------------------------------------------------------------------- */ 2743/* ------------------------------------------------------------------------- */
2919/* 2744/*
2920 * Clear all selected text 2745 * Clear all selected text
2921 * EXT: SelectionClear 2746 * EXT: SelectionClear
2922 */ 2747 */
2923void 2748void
2924rxvt_term::selection_clear () NOTHROW 2749rxvt_term::selection_clear (bool clipboard) NOTHROW
2925{ 2750{
2751 if (!clipboard)
2752 {
2926 want_refresh = 1; 2753 want_refresh = 1;
2927 free (selection.text); 2754 free (selection.text);
2928 selection.text = NULL; 2755 selection.text = NULL;
2929 selection.len = 0; 2756 selection.len = 0;
2930 CLEAR_SELECTION (); 2757 CLEAR_SELECTION ();
2931 2758
2932 if (display->selection_owner == this) 2759 if (display->selection_owner == this)
2933 display->selection_owner = 0; 2760 display->selection_owner = 0;
2761 }
2762 else
2763 {
2764 free (selection.clip_text);
2765 selection.clip_text = NULL;
2766 selection.clip_len = 0;
2767
2768 if (display->clipboard_owner == this)
2769 display->clipboard_owner = 0;
2770 }
2934} 2771}
2935 2772
2936/* ------------------------------------------------------------------------- */ 2773/* ------------------------------------------------------------------------- */
2937/* 2774/*
2938 * Copy a selection into the cut buffer 2775 * Copy a selection into the cut buffer
2939 * EXT: button 1 or 3 release 2776 * EXT: button 1 or 3 release
2940 */ 2777 */
2941void 2778void
2942rxvt_term::selection_make (Time tm) 2779rxvt_term::selection_make (Time tm)
2943{ 2780{
2944 int i; 2781 int size;
2945 wchar_t *new_selection_text; 2782 wchar_t *new_selection_text;
2946 text_t *t; 2783 text_t *t;
2947 2784
2948 switch (selection.op) 2785 switch (selection.op)
2949 { 2786 {
2965 return; /* nothing selected, go away */ 2802 return; /* nothing selected, go away */
2966 2803
2967 if (HOOK_INVOKE ((this, HOOK_SEL_MAKE, DT_LONG, (long)tm, DT_END))) 2804 if (HOOK_INVOKE ((this, HOOK_SEL_MAKE, DT_LONG, (long)tm, DT_END)))
2968 return; 2805 return;
2969 2806
2970 i = (selection.end.row - selection.beg.row + 1) * (ncol + 1); 2807 size = (selection.end.row - selection.beg.row + 1) * (ncol + 1);
2971 new_selection_text = (wchar_t *)rxvt_malloc ((i + 4) * sizeof (wchar_t)); 2808 new_selection_text = (wchar_t *)rxvt_malloc ((size + 4) * sizeof (wchar_t));
2972 2809
2973 int ofs = 0; 2810 int ofs = 0;
2974 int extra = 0; 2811 int extra = 0;
2975 2812
2976 int col = selection.beg.col; 2813 int col = selection.beg.col;
2982 { 2819 {
2983#if !ENABLE_MINIMAL 2820#if !ENABLE_MINIMAL
2984 if (selection.rect) 2821 if (selection.rect)
2985 { 2822 {
2986 col = selection.beg.col; 2823 col = selection.beg.col;
2987 end_col = ncol + 1; 2824 end_col = selection.end.col;
2988 } 2825 }
2989 else 2826 else
2990#endif 2827#endif
2991 end_col = ROW(row).l; 2828 end_col = ROW(row).l;
2992 2829
2993 col = max (col, 0); 2830 col = max (col, 0);
2994 2831
2995 if (row == selection.end.row 2832 if (row == selection.end.row)
2996#if !ENABLE_MINIMAL
2997 || selection.rect
2998#endif
2999 )
3000 min_it (end_col, selection.end.col); 2833 min_it (end_col, selection.end.col);
3001 2834
3002 t = ROW(row).t + col; 2835 t = ROW(row).t + col;
3003 2836
3004 for (; col < end_col; col++) 2837 for (; col < end_col; col++)
3012 2845
3013 extra -= (len - 1); 2846 extra -= (len - 1);
3014 2847
3015 if (extra < 0) 2848 if (extra < 0)
3016 { 2849 {
3017 extra += i; 2850 extra += size;
3018 i += i; 2851 size += size;
3019 new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (i + 4) * sizeof (wchar_t)); 2852 new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (size + 4) * sizeof (wchar_t));
3020 } 2853 }
3021 2854
3022 ofs += rxvt_composite.expand (*t++, new_selection_text + ofs); 2855 ofs += rxvt_composite.expand (*t++, new_selection_text + ofs);
3023 } 2856 }
3024#endif 2857#endif
3036 2869
3037 new_selection_text[ofs++] = C0_LF; 2870 new_selection_text[ofs++] = C0_LF;
3038 } 2871 }
3039 else 2872 else
3040#endif 2873#endif
3041 if (!ROW(row).is_longer () && row != selection.end.row) 2874 if (!ROW(row).is_longer ()
2875 && (row != selection.end.row || end_col != selection.end.col)
2876 && (row != selection.beg.row || selection.beg.col < ncol))
3042 new_selection_text[ofs++] = C0_LF; 2877 new_selection_text[ofs++] = C0_LF;
3043 } 2878 }
3044
3045 if (end_col != selection.end.col)
3046 new_selection_text[ofs++] = C0_LF;
3047 2879
3048 new_selection_text[ofs] = 0; 2880 new_selection_text[ofs] = 0;
3049 2881
3050 if (ofs == 0) 2882 if (ofs == 0)
3051 { 2883 {
3064 2896
3065 selection_grab (tm); 2897 selection_grab (tm);
3066} 2898}
3067 2899
3068bool 2900bool
3069rxvt_term::selection_grab (Time tm) NOTHROW 2901rxvt_term::selection_grab (Time tm, bool clipboard) NOTHROW
3070{ 2902{
2903 Atom sel;
2904
2905 if (!clipboard)
2906 {
3071 selection_time = tm; 2907 selection_time = tm;
2908 sel = XA_PRIMARY;
2909 }
2910 else
2911 {
2912 clipboard_time = tm;
2913 sel = xa[XA_CLIPBOARD];
2914 }
3072 2915
3073 XSetSelectionOwner (dpy, XA_PRIMARY, vt, tm); 2916 XSetSelectionOwner (dpy, sel, vt, tm);
3074 if (XGetSelectionOwner (dpy, XA_PRIMARY) == vt) 2917 if (XGetSelectionOwner (dpy, sel) == vt)
3075 { 2918 {
3076 display->set_selection_owner (this); 2919 display->set_selection_owner (this, clipboard);
3077 return true; 2920 return true;
3078 } 2921 }
3079 else 2922 else
3080 { 2923 {
3081 selection_clear (); 2924 selection_clear (clipboard);
3082 return false; 2925 return false;
3083 } 2926 }
3084 2927
3085#if 0 2928#if 0
3086 XTextProperty ct; 2929 XTextProperty ct;
3546 * EXT: SelectionRequest 3389 * EXT: SelectionRequest
3547 */ 3390 */
3548void 3391void
3549rxvt_term::selection_send (const XSelectionRequestEvent &rq) NOTHROW 3392rxvt_term::selection_send (const XSelectionRequestEvent &rq) NOTHROW
3550{ 3393{
3394 Atom property = rq.property == None ? rq.target : rq.property;
3551 XSelectionEvent ev; 3395 XSelectionEvent ev;
3552 3396
3553 ev.type = SelectionNotify; 3397 ev.type = SelectionNotify;
3554 ev.property = None; 3398 ev.property = None;
3555 ev.display = rq.display; 3399 ev.display = rq.display;
3570 *target++ = xa[XA_COMPOUND_TEXT]; 3414 *target++ = xa[XA_COMPOUND_TEXT];
3571#if X_HAVE_UTF8_STRING 3415#if X_HAVE_UTF8_STRING
3572 *target++ = xa[XA_UTF8_STRING]; 3416 *target++ = xa[XA_UTF8_STRING];
3573#endif 3417#endif
3574 3418
3575 XChangeProperty (dpy, rq.requestor, rq.property, XA_ATOM, 3419 XChangeProperty (dpy, rq.requestor, property, XA_ATOM,
3576 32, PropModeReplace, 3420 32, PropModeReplace,
3577 (unsigned char *)target_list, target - target_list); 3421 (unsigned char *)target_list, target - target_list);
3578 ev.property = rq.property; 3422 ev.property = property;
3579 } 3423 }
3580#if TODO // TODO 3424#if TODO // TODO
3581 else if (rq.target == xa[XA_MULTIPLE]) 3425 else if (rq.target == xa[XA_MULTIPLE])
3582 { 3426 {
3583 /* TODO: Handle MULTIPLE */ 3427 /* TODO: Handle MULTIPLE */
3584 } 3428 }
3585#endif 3429#endif
3586 else if (rq.target == xa[XA_TIMESTAMP] && selection.text) 3430 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == XA_PRIMARY && selection.text)
3587 { 3431 {
3588 XChangeProperty (dpy, rq.requestor, rq.property, rq.target, 3432 XChangeProperty (dpy, rq.requestor, property, rq.target,
3589 32, PropModeReplace, (unsigned char *)&selection_time, 1); 3433 32, PropModeReplace, (unsigned char *)&selection_time, 1);
3590 ev.property = rq.property; 3434 ev.property = property;
3435 }
3436 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3437 {
3438 XChangeProperty (dpy, rq.requestor, property, rq.target,
3439 32, PropModeReplace, (unsigned char *)&clipboard_time, 1);
3440 ev.property = property;
3591 } 3441 }
3592 else if (rq.target == XA_STRING 3442 else if (rq.target == XA_STRING
3593 || rq.target == xa[XA_TEXT] 3443 || rq.target == xa[XA_TEXT]
3594 || rq.target == xa[XA_COMPOUND_TEXT] 3444 || rq.target == xa[XA_COMPOUND_TEXT]
3595 || rq.target == xa[XA_UTF8_STRING] 3445 || rq.target == xa[XA_UTF8_STRING]
3627 { 3477 {
3628 target = xa[XA_COMPOUND_TEXT]; 3478 target = xa[XA_COMPOUND_TEXT];
3629 style = enc_compound_text; 3479 style = enc_compound_text;
3630 } 3480 }
3631 3481
3632 if (selection.text) 3482 if (rq.selection == XA_PRIMARY && selection.text)
3633 { 3483 {
3634 cl = selection.text; 3484 cl = selection.text;
3635 selectlen = selection.len; 3485 selectlen = selection.len;
3486 }
3487 else if (rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3488 {
3489 cl = selection.clip_text;
3490 selectlen = selection.clip_len;
3636 } 3491 }
3637 else 3492 else
3638 { 3493 {
3639 cl = L""; 3494 cl = L"";
3640 selectlen = 0; 3495 selectlen = 0;
3661 ct.value = (unsigned char *)cl; 3516 ct.value = (unsigned char *)cl;
3662 ct.nitems = selectlen; 3517 ct.nitems = selectlen;
3663 ct.encoding = target; 3518 ct.encoding = target;
3664 } 3519 }
3665 3520
3666 XChangeProperty (dpy, rq.requestor, rq.property, 3521 XChangeProperty (dpy, rq.requestor, property,
3667 ct.encoding, 8, PropModeReplace, 3522 ct.encoding, 8, PropModeReplace,
3668 ct.value, (int)ct.nitems); 3523 ct.value, (int)ct.nitems);
3669 ev.property = rq.property; 3524 ev.property = property;
3670 3525
3671 if (freect) 3526 if (freect)
3672 XFree (ct.value); 3527 XFree (ct.value);
3673 } 3528 }
3674 3529
3708 h += 2; min_it (h, nrow); 3563 h += 2; min_it (h, nrow);
3709 3564
3710 x -= 1; clamp_it (x, 0, ncol - w); 3565 x -= 1; clamp_it (x, 0, ncol - w);
3711 y -= 1; clamp_it (y, 0, nrow - h); 3566 y -= 1; clamp_it (y, 0, nrow - h);
3712 3567
3713 ov_x = x; ov_y = y; 3568 ov.x = x; ov.y = y;
3714 ov_w = w; ov_h = h; 3569 ov.w = w; ov.h = h;
3715 3570
3716 ov_text = new text_t *[h]; 3571 ov.text = new text_t *[h];
3717 ov_rend = new rend_t *[h]; 3572 ov.rend = new rend_t *[h];
3718 3573
3719 for (y = 0; y < h; y++) 3574 for (y = 0; y < h; y++)
3720 { 3575 {
3721 text_t *tp = ov_text[y] = new text_t[w]; 3576 text_t *tp = ov.text[y] = new text_t[w];
3722 rend_t *rp = ov_rend[y] = new rend_t[w]; 3577 rend_t *rp = ov.rend[y] = new rend_t[w];
3723 3578
3724 text_t t0, t1, t2; 3579 text_t t0, t1, t2;
3725 rend_t r = OVERLAY_RSTYLE; 3580 rend_t r = OVERLAY_RSTYLE;
3726 3581
3727 if (y == 0) 3582 if (y == 0)
3746} 3601}
3747 3602
3748void 3603void
3749rxvt_term::scr_overlay_off () NOTHROW 3604rxvt_term::scr_overlay_off () NOTHROW
3750{ 3605{
3751 if (!ov_text) 3606 if (!ov.text)
3752 return; 3607 return;
3753 3608
3754 want_refresh = 1; 3609 want_refresh = 1;
3755 3610
3756 for (int y = 0; y < ov_h; y++) 3611 for (int y = 0; y < ov.h; y++)
3757 { 3612 {
3758 delete [] ov_text[y]; 3613 delete [] ov.text[y];
3759 delete [] ov_rend[y]; 3614 delete [] ov.rend[y];
3760 } 3615 }
3761 3616
3762 delete [] ov_text; ov_text = 0; 3617 delete [] ov.text; ov.text = 0;
3763 delete [] ov_rend; ov_rend = 0; 3618 delete [] ov.rend; ov.rend = 0;
3764} 3619}
3765 3620
3766void 3621void
3767rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) NOTHROW 3622rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) NOTHROW
3768{ 3623{
3769 if (!ov_text || x >= ov_w - 2 || y >= ov_h - 2) 3624 if (!ov.text || x >= ov.w - 2 || y >= ov.h - 2)
3770 return; 3625 return;
3771 3626
3772 x++, y++; 3627 x++, y++;
3773 3628
3774 ov_text[y][x] = text; 3629 ov.text[y][x] = text;
3775 ov_rend[y][x] = rend; 3630 ov.rend[y][x] = rend;
3776} 3631}
3777 3632
3778void 3633void
3779rxvt_term::scr_overlay_set (int x, int y, const char *s) NOTHROW 3634rxvt_term::scr_overlay_set (int x, int y, const char *s) NOTHROW
3780{ 3635{
3799} 3654}
3800 3655
3801void 3656void
3802rxvt_term::scr_swap_overlay () NOTHROW 3657rxvt_term::scr_swap_overlay () NOTHROW
3803{ 3658{
3804 if (!ov_text) 3659 if (!ov.text)
3805 return; 3660 return;
3806 3661
3662 // hide cursor if it is within the overlay area
3663 if (IN_RANGE_EXC (screen.cur.col - ov.x, 0, ov.w)
3664 && IN_RANGE_EXC (screen.cur.row - ov.y, 0, ov.h))
3665 screen.flags &= ~Screen_VisibleCursor;
3666
3807 // swap screen mem with overlay 3667 // swap screen mem with overlay
3808 for (int y = ov_h; y--; ) 3668 for (int y = ov.h; y--; )
3809 { 3669 {
3810 text_t *t1 = ov_text[y]; 3670 text_t *t1 = ov.text[y];
3811 rend_t *r1 = ov_rend[y]; 3671 rend_t *r1 = ov.rend[y];
3812 3672
3813 text_t *t2 = ROW(y + ov_y + view_start).t + ov_x; 3673 text_t *t2 = ROW(y + ov.y + view_start).t + ov.x;
3814 rend_t *r2 = ROW(y + ov_y + view_start).r + ov_x; 3674 rend_t *r2 = ROW(y + ov.y + view_start).r + ov.x;
3815 3675
3816 for (int x = ov_w; x--; ) 3676 for (int x = ov.w; x--; )
3817 { 3677 {
3818 text_t t = *t1; *t1++ = *t2; *t2++ = t; 3678 text_t t = *t1; *t1++ = *t2; *t2++ = t;
3819 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t)); 3679 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t));
3820 } 3680 }
3821 } 3681 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines