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.316 by root, Tue Nov 4 15:02:35 2008 UTC vs.
Revision 1.415 by root, Mon May 28 14:25:16 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 * ------------------------------------------------------------------------- */
99 98
100/* Fill part/all of a line with blanks. */ 99/* Fill part/all of a line with blanks. */
101void 100void
102rxvt_term::scr_blank_line (line_t &l, unsigned int col, unsigned int width, rend_t efs) const NOTHROW 101rxvt_term::scr_blank_line (line_t &l, unsigned int col, unsigned int width, rend_t efs) const NOTHROW
103{ 102{
104 if (!l.t) 103 if (!l.valid ())
105 { 104 {
106 lalloc (l); 105 l.alloc ();
107 col = 0; 106 col = 0;
108 width = ncol; 107 width = ncol;
109 } 108 }
110 109
111 l.touch (); 110 l.touch ();
142 while (col > 0 && l.t[col] == NOCHAR) 141 while (col > 0 && l.t[col] == NOCHAR)
143 col--; 142 col--;
144 143
145 rend_t rend = l.r[col] & ~RS_baseattrMask; 144 rend_t rend = l.r[col] & ~RS_baseattrMask;
146 rend = SET_FONT (rend, FONTSET (rend)->find_font (' ')); 145 rend = SET_FONT (rend, FONTSET (rend)->find_font (' '));
146
147 l.touch ();
147 148
148 // found start, nuke 149 // found start, nuke
149 do { 150 do {
150 l.t[col] = ' '; 151 l.t[col] = ' ';
151 l.r[col] = rend; 152 l.r[col] = rend;
156/* ------------------------------------------------------------------------- * 157/* ------------------------------------------------------------------------- *
157 * SCREEN INITIALISATION * 158 * SCREEN INITIALISATION *
158 * ------------------------------------------------------------------------- */ 159 * ------------------------------------------------------------------------- */
159 160
160void 161void
162rxvt_term::scr_alloc ()
163{
164 int tsize = sizeof (text_t) * ncol;
165 int rsize = sizeof (rend_t) * ncol;
166
167 // we assume that rend_t size is a sufficient alignment
168 // factor for tetx_t and line_t values, and we only
169 // need to adjust tsize.
170 tsize = (tsize + sizeof (rend_t) - 1);
171 tsize -= tsize % sizeof (rend_t);
172
173 int all_rows = total_rows + nrow + nrow;
174
175 chunk_size = (sizeof (line_t) + rsize + tsize) * all_rows;
176 chunk = rxvt_malloc (chunk_size);
177
178 char *base = (char *)chunk + sizeof (line_t) * all_rows;
179
180 for (int row = 0; row < all_rows; ++row)
181 {
182 line_t &l = ((line_t *)chunk) [row];
183
184 l.t = (text_t *)base; base += tsize;
185 l.r = (rend_t *)base; base += rsize;
186 l.l = -1;
187 l.f = 0;
188 }
189
190 drawn_buf = (line_t *)chunk;
191 swap_buf = drawn_buf + nrow;
192 row_buf = swap_buf + nrow;
193}
194
195void
161rxvt_term::scr_reset () 196rxvt_term::scr_reset ()
162{ 197{
163#if ENABLE_OVERLAY 198#if ENABLE_OVERLAY
164 scr_overlay_off (); 199 scr_overlay_off ();
165#endif 200#endif
166 201
167 rvideo_mode = false;
168 view_start = 0; 202 view_start = 0;
169 num_scr = 0; 203 num_scr = 0;
170 204
171 if (ncol == 0) 205 if (ncol == 0)
172 ncol = 80; 206 ncol = 80;
174 if (nrow == 0) 208 if (nrow == 0)
175 nrow = 24; 209 nrow = 24;
176 210
177 if (ncol == prev_ncol && nrow == prev_nrow) 211 if (ncol == prev_ncol && nrow == prev_nrow)
178 return; 212 return;
179
180 if (current_screen != PRIMARY)
181 scr_swap_screen ();
182 213
183 // we need at least two lines for wrapping to work correctly 214 // we need at least two lines for wrapping to work correctly
184 while (nrow + saveLines < 2) 215 while (nrow + saveLines < 2)
185 { 216 {
186 //TODO//FIXME 217 //TODO//FIXME
195 total_rows = nrow + saveLines; 226 total_rows = nrow + saveLines;
196 227
197 screen.tscroll = 0; 228 screen.tscroll = 0;
198 screen.bscroll = nrow - 1; 229 screen.bscroll = nrow - 1;
199 230
231 void *prev_chunk = chunk;
232 line_t *prev_drawn_buf = drawn_buf;
233 line_t *prev_swap_buf = swap_buf;
234 line_t *prev_row_buf = row_buf;
235
236 int common_col = min (prev_ncol, ncol);
237
238 scr_alloc ();
239
200 if (!row_buf) 240 if (!prev_row_buf)
201 { 241 {
202 /* 242 /*
203 * first time called so just malloc everything: don't rely on realloc 243 * first time called so just malloc everything: don't rely on realloc
204 */ 244 */
205 top_row = 0; 245 top_row = 0;
206 term_start = 0; 246 term_start = 0;
207
208 talloc = new rxvt_salloc (ncol * sizeof (text_t));
209 ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
210
211 row_buf = (line_t *)rxvt_calloc (total_rows + nrow, sizeof (line_t));
212 drawn_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t));
213 swap_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t));
214
215 for (int row = nrow; row--; )
216 {
217 scr_blank_screen_mem (ROW (row), DEFAULT_RSTYLE);
218 scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
219 scr_blank_screen_mem (drawn_buf[row], DEFAULT_RSTYLE);
220 }
221 247
222 memset (charsets, 'B', sizeof (charsets)); 248 memset (charsets, 'B', sizeof (charsets));
223 rstyle = DEFAULT_RSTYLE; 249 rstyle = DEFAULT_RSTYLE;
224 screen.flags = Screen_DefaultFlags; 250 screen.flags = Screen_DefaultFlags;
225 screen.cur.row = screen.cur.col = 0; 251 screen.cur.row = screen.cur.col = 0;
239 selection.text = NULL; 265 selection.text = NULL;
240 selection.len = 0; 266 selection.len = 0;
241 selection.op = SELECTION_CLEAR; 267 selection.op = SELECTION_CLEAR;
242 selection.screen = PRIMARY; 268 selection.screen = PRIMARY;
243 selection.clicks = 0; 269 selection.clicks = 0;
270 selection.clip_text = NULL;
271 selection.clip_len = 0;
244 } 272 }
245 else 273 else
246 { 274 {
247 /* 275 /*
248 * add or delete rows as appropriate 276 * add or delete rows as appropriate
249 */ 277 */
250 278
251 rxvt_salloc *old_ta = talloc; talloc = new rxvt_salloc (ncol * sizeof (text_t));
252 rxvt_salloc *old_ra = ralloc; ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
253
254#if 0
255 if (nrow < prev_nrow)
256 {
257 for (int row = nrow; row < prev_nrow; row++)
258 {
259 lfree (swap_buf [row]);
260 lfree (drawn_buf[row]);
261 }
262 }
263#endif
264
265 drawn_buf = (line_t *)rxvt_realloc (drawn_buf, nrow * sizeof (line_t));
266 swap_buf = (line_t *)rxvt_realloc (swap_buf , nrow * sizeof (line_t));
267
268 for (int row = min (nrow, prev_nrow); row--; ) 279 for (int row = min (nrow, prev_nrow); row--; )
269 { 280 {
270 lresize (drawn_buf[row]); 281 scr_blank_screen_mem (drawn_buf [row], DEFAULT_RSTYLE);
271 lresize (swap_buf [row]); 282 scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
272 }
273 283
274 for (int row = prev_nrow; row < nrow; row++) 284 memcpy (drawn_buf [row].t, prev_drawn_buf [row].t, sizeof (text_t) * common_col);
285 memcpy (drawn_buf [row].r, prev_drawn_buf [row].r, sizeof (rend_t) * common_col);
286 memcpy (swap_buf [row].t, prev_swap_buf [row].t, sizeof (text_t) * common_col);
287 memcpy (swap_buf [row].r, prev_swap_buf [row].r, sizeof (rend_t) * common_col);
275 { 288 }
276 swap_buf [row].clear (); scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
277 drawn_buf[row].clear (); scr_blank_screen_mem (drawn_buf[row], DEFAULT_RSTYLE);
278 }
279
280 line_t *old_buf = row_buf;
281 row_buf = (line_t *)rxvt_calloc (total_rows + nrow, sizeof (line_t));
282 289
283 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row 290 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row
284 int pend = MOD (term_start + top_row , prev_total_rows); 291 int pend = MOD (term_start + top_row , prev_total_rows);
285 int q = total_rows; // rewrapped row 292 int q = total_rows; // rewrapped row
286 293
287 if (top_row) 294 if (top_row)
288 { 295 {
289 // Re-wrap lines. This is rather ugly, possibly because I am too dumb 296 // Re-wrap lines. This is rather ugly, possibly because I am too dumb
290 // to come up with a lean and mean algorithm. 297 // to come up with a lean and mean algorithm.
298 // TODO: maybe optimise when width didn't change
291 299
292 row_col_t ocur = screen.cur; 300 row_col_t ocur = screen.cur;
293 ocur.row = MOD (term_start + ocur.row, prev_total_rows); 301 ocur.row = MOD (term_start + ocur.row, prev_total_rows);
294 302
295 do 303 do
296 { 304 {
297 p = MOD (p - 1, prev_total_rows); 305 p = MOD (p - 1, prev_total_rows);
298#ifdef DEBUG_STRICT
299 assert (old_buf [MOD (p, prev_total_rows)].t); 306 assert (prev_row_buf [MOD (p, prev_total_rows)].t);
300#endif
301 int plines = 1; 307 int plines = 1;
302 int llen = old_buf [MOD (p, prev_total_rows)].l; 308 int llen = prev_row_buf [MOD (p, prev_total_rows)].l;
303 309
304 while (p != pend && old_buf [MOD (p - 1, prev_total_rows)].is_longer ()) 310 while (p != pend && prev_row_buf [MOD (p - 1, prev_total_rows)].is_longer ())
305 { 311 {
306 p = MOD (p - 1, prev_total_rows); 312 p = MOD (p - 1, prev_total_rows);
307 313
308 plines++; 314 plines++;
309 llen += prev_ncol; 315 llen += prev_ncol;
322 328
323 // re-assemble the full line by destination lines 329 // re-assemble the full line by destination lines
324 for (int qrow = q; qlines--; qrow++) 330 for (int qrow = q; qlines--; qrow++)
325 { 331 {
326 qline = row_buf + qrow; 332 qline = row_buf + qrow;
327 lalloc (*qline); 333 qline->alloc (); // redundant with next line
328 qline->l = ncol; 334 qline->l = ncol;
329 qline->is_longer (1); 335 qline->is_longer (1);
330 336
331 int qcol = 0; 337 int qcol = 0;
332 338
347 // this seems to upset applications/shells/readline 353 // this seems to upset applications/shells/readline
348 // least. 354 // least.
349 if (prow == ocur.row) 355 if (prow == ocur.row)
350 screen.cur.row = q - (total_rows - nrow); 356 screen.cur.row = q - (total_rows - nrow);
351 357
352 line_t &pline = old_buf [prow]; 358 line_t &pline = prev_row_buf [prow];
353 359
354 int len = min (min (prev_ncol - pcol, ncol - qcol), llen - lofs); 360 int len = min (min (prev_ncol - pcol, ncol - qcol), llen - lofs);
355 361
356 memcpy (qline->t + qcol, pline.t + pcol, len * sizeof (text_t)); 362 memcpy (qline->t + qcol, pline.t + pcol, len * sizeof (text_t));
357 memcpy (qline->r + qcol, pline.r + pcol, len * sizeof (rend_t)); 363 memcpy (qline->r + qcol, pline.r + pcol, len * sizeof (rend_t));
378 { 384 {
379 // if no scrollback exists (yet), wing, instead of wrap 385 // if no scrollback exists (yet), wing, instead of wrap
380 386
381 for (int row = min (nrow, prev_nrow); row--; ) 387 for (int row = min (nrow, prev_nrow); row--; )
382 { 388 {
383 line_t &pline = old_buf [MOD (term_start + row, prev_total_rows)]; 389 line_t &src = prev_row_buf [MOD (term_start + row, prev_total_rows)];
384 line_t &qline = row_buf [row]; 390 line_t &dst = row_buf [row];
385 391
386 qline = pline; 392 scr_blank_screen_mem (dst, DEFAULT_RSTYLE);
387 lresize (qline); 393
394 memcpy (dst.t, src.t, sizeof (text_t) * common_col);
395 memcpy (dst.r, src.r, sizeof (rend_t) * common_col);
388 } 396 }
389 397
390 for (int row = prev_nrow; row < nrow; row++) 398 for (int row = prev_nrow; row < nrow; row++)
391 {
392 row_buf [row].clear (); scr_blank_screen_mem (row_buf [row], DEFAULT_RSTYLE); 399 scr_blank_screen_mem (row_buf [row], DEFAULT_RSTYLE);
393 }
394 400
395 term_start = 0; 401 term_start = 0;
396 } 402 }
397
398 free (old_buf);
399 delete old_ta;
400 delete old_ra;
401 403
402 clamp_it (screen.cur.row, 0, nrow - 1); 404 clamp_it (screen.cur.row, 0, nrow - 1);
403 clamp_it (screen.cur.col, 0, ncol - 1); 405 clamp_it (screen.cur.col, 0, ncol - 1);
406 }
404 407
408 for (int row = nrow; row--; )
409 {
410 if (!ROW (row).valid ()) scr_blank_screen_mem (ROW (row), DEFAULT_RSTYLE);
411 if (!swap_buf [row].valid ()) scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
412 if (!drawn_buf [row].valid ()) scr_blank_screen_mem (drawn_buf [row], DEFAULT_RSTYLE);
413 }
414
415 free (prev_chunk);
416
405 free (tabs); 417 free (tabs);
406 } 418 tabs = (char *)rxvt_malloc (ncol);
419
420 for (int col = ncol; col--; )
421 tabs [col] = col % TABSIZE == 0;
407 422
408 CLEAR_ALL_SELECTION (); 423 CLEAR_ALL_SELECTION ();
409 424
410 prev_nrow = nrow; 425 prev_nrow = nrow;
411 prev_ncol = ncol; 426 prev_ncol = ncol;
412 427
413 tabs = (char *)rxvt_malloc (ncol); 428 tt_winch ();
414 429
415 for (int col = ncol; --col; ) 430 HOOK_INVOKE ((this, HOOK_RESET, DT_END));
416 tabs [col] = col % TABSIZE == 0; 431}
432
433/* ------------------------------------------------------------------------- */
434/*
435 * Free everything. That way malloc debugging can find leakage.
436 */
437void
438rxvt_term::scr_release () NOTHROW
439{
440 free (chunk);
441 free (tabs);
442}
443
444/* ------------------------------------------------------------------------- */
445/*
446 * Hard/Soft reset
447 */
448void
449rxvt_term::scr_poweron ()
450{
451 scr_release ();
452
453 row_buf = 0;
454 tabs = 0;
455 prev_nrow = prev_ncol = 0;
456 rvideo_mode = false;
457 scr_soft_reset ();
458 scr_reset ();
459
460 scr_clear (true);
461 scr_refresh ();
462}
463
464void
465rxvt_term::scr_soft_reset () NOTHROW
466{
467 /* only affects modes, nothing drastic such as clearing the screen */
468#if ENABLE_OVERLAY
469 scr_overlay_off ();
470#endif
417 471
418 if (current_screen != PRIMARY) 472 if (current_screen != PRIMARY)
419 scr_swap_screen (); 473 scr_swap_screen ();
420 474
421 tt_winch (); 475 scr_scroll_region (0, MAX_ROWS - 1);
422 476 scr_rendition (0, ~RS_None);
423 HOOK_INVOKE ((this, HOOK_RESET, DT_END)); 477 scr_insert_mode (0);
424}
425
426/* ------------------------------------------------------------------------- */
427/*
428 * Free everything. That way malloc debugging can find leakage.
429 */
430void
431rxvt_term::scr_release () NOTHROW
432{
433 if (row_buf)
434 {
435 delete talloc; talloc = 0;
436 delete ralloc; ralloc = 0;
437
438 free (row_buf);
439 free (swap_buf);
440 free (drawn_buf);
441 free (tabs);
442
443 row_buf = 0; // signal that we freed all the arrays
444 }
445}
446
447/* ------------------------------------------------------------------------- */
448/*
449 * Hard reset
450 */
451void
452rxvt_term::scr_poweron ()
453{
454 scr_release ();
455 prev_nrow = prev_ncol = 0;
456 scr_reset ();
457
458 scr_clear (true);
459 scr_refresh ();
460} 478}
461 479
462/* ------------------------------------------------------------------------- * 480/* ------------------------------------------------------------------------- *
463 * PROCESS SCREEN COMMANDS * 481 * PROCESS SCREEN COMMANDS *
464 * ------------------------------------------------------------------------- */ 482 * ------------------------------------------------------------------------- */
502 } 520 }
503 521
504 /* boundary check in case screen size changed between SAVE and RESTORE */ 522 /* boundary check in case screen size changed between SAVE and RESTORE */
505 min_it (s->cur.row, nrow - 1); 523 min_it (s->cur.row, nrow - 1);
506 min_it (s->cur.col, ncol - 1); 524 min_it (s->cur.col, ncol - 1);
507#ifdef DEBUG_STRICT
508 assert (s->cur.row >= 0); 525 assert (s->cur.row >= 0);
509 assert (s->cur.col >= 0); 526 assert (s->cur.col >= 0);
510#endif
511} 527}
512 528
513void 529void
514rxvt_term::scr_swap_screen () 530rxvt_term::scr_swap_screen () NOTHROW
515{ 531{
516 if (!option (Opt_secondaryScreen)) 532 if (!option (Opt_secondaryScreen))
517 return; 533 return;
518 534
519 for (int i = prev_nrow; i--; ) 535 for (int i = prev_nrow; i--; )
538 return; 554 return;
539 555
540 want_refresh = 1; 556 want_refresh = 1;
541 view_start = 0; 557 view_start = 0;
542 558
543 selection_check (2); /* check for boundary cross */ 559 /* check for boundary cross */
560 row_col_t pos;
561 pos.row = pos.col = 0;
562 if (ROWCOL_IS_BEFORE (selection.beg, pos)
563 && ROWCOL_IS_AFTER (selection.end, pos))
564 CLEAR_SELECTION ();
544 565
545 int i = current_screen; current_screen = scrn; scrn = i; 566 current_screen = scrn;
546 567
547#if NSCREENS 568#if NSCREENS
548 if (option (Opt_secondaryScreen)) 569 if (option (Opt_secondaryScreen))
549 { 570 {
550 num_scr = 0; 571 num_scr = 0;
627 648
628 if (count > 0 649 if (count > 0
629 && row1 == 0 650 && row1 == 0
630 && (current_screen == PRIMARY || option (Opt_secondaryScroll))) 651 && (current_screen == PRIMARY || option (Opt_secondaryScroll)))
631 { 652 {
653 min_it (count, total_rows - (nrow - (row2 + 1)));
654
632 top_row = max (top_row - count, -saveLines); 655 top_row = max (top_row - count, -saveLines);
633
634 // scroll everything up 'count' lines
635 term_start = (term_start + count) % total_rows;
636 656
637 // sever bottommost line 657 // sever bottommost line
638 { 658 {
639 line_t &l = ROW(row2 - count); 659 line_t &l = ROW(row2);
640 l.is_longer (0); 660 l.is_longer (0);
641 l.touch (); 661 l.touch ();
642 } 662 }
643 663
664 // scroll everything up 'count' lines
665 term_start = (term_start + count) % total_rows;
666
667 // now copy lines below the scroll region bottom to the
668 // bottom of the screen again, so they look as if they
669 // hadn't moved.
670 for (int i = nrow; --i > row2; )
671 {
672 line_t &l1 = ROW(i - count);
673 line_t &l2 = ROW(i);
674
675 ::swap (l1, l2);
676 l2.touch ();
677 }
678
644 // erase newly scrolled-in lines 679 // erase newly scrolled-in lines
645 for (int i = count; i--; ) 680 for (int i = count; i--; )
646 { 681 {
647 line_t &l = ROW(nrow - 1 - i); 682 line_t &l = ROW(row2 - i);
648 683
649 // optimize if already cleared, can be significant on slow machines 684 // optimise if already cleared, can be significant on slow machines
650 // could be rolled into scr_blank_screen_mem 685 // could be rolled into scr_blank_screen_mem
651 if (l.r && l.l < ncol - 1 && !((l.r[l.l + 1] ^ rstyle) & (RS_fgMask | RS_bgMask))) 686 if (l.r && l.l < ncol - 1 && !((l.r[l.l + 1] ^ rstyle) & (RS_fgMask | RS_bgMask)))
652 { 687 {
653 scr_blank_line (l, 0, l.l, rstyle); 688 scr_blank_line (l, 0, l.l, rstyle);
654 l.l = 0; 689 l.l = 0;
656 } 691 }
657 else 692 else
658 scr_blank_screen_mem (l, rstyle); 693 scr_blank_screen_mem (l, rstyle);
659 } 694 }
660 695
661 // now copy lines below the scroll region bottom to the
662 // bottom of the screen again, so they look as if they
663 // hadn't moved.
664 for (int i = nrow; --i > row2; )
665 {
666 line_t &l1 = ROW(i - count);
667 line_t &l2 = ROW(i);
668
669 ::swap (l1, l2);
670 l2.touch ();
671 }
672
673 // move and/or clear selection, if any 696 // move and/or clear selection, if any
674 if (selection.op && current_screen == selection.screen) 697 if (selection.op && current_screen == selection.screen
698 && selection.beg.row <= row2)
675 { 699 {
676 selection.beg.row -= count; 700 selection.beg.row -= count;
677 selection.end.row -= count; 701 selection.end.row -= count;
678 selection.mark.row -= count; 702 selection.mark.row -= count;
679 703
680 if (selection.beg.row < top_row 704 selection_check (0);
681 || selection.end.row < top_row
682 || selection.mark.row < top_row)
683 {
684 CLEAR_ALL_SELECTION ();
685 selection.op = SELECTION_CLEAR;
686 }
687 } 705 }
688 706
689 // finally move the view window, if desired 707 // finally move the view window, if desired
690 if (option (Opt_scrollWithBuffer) 708 if (option (Opt_scrollWithBuffer)
691 && view_start != 0 709 && view_start != 0
721 } 739 }
722 740
723 // use a simple and robust scrolling algorithm, this 741 // use a simple and robust scrolling algorithm, this
724 // part of scr_scroll_text is not time-critical. 742 // part of scr_scroll_text is not time-critical.
725 743
744 // sever line above scroll region
745 if (row1)
746 {
747 line_t &l = ROW(row1 - 1);
748 l.is_longer (0);
749 l.touch ();
750 }
751
726 int rows = row2 - row1 + 1; 752 int rows = row2 - row1 + 1;
727 753
728 min_it (count, rows); 754 min_it (count, rows);
729 755
730 line_t *temp_buf = row_buf + total_rows; 756 line_t *temp_buf = rxvt_temp_buf<line_t> (rows);
731 757
732 for (int row = 0; row < rows; row++) 758 for (int row = 0; row < rows; row++)
733 { 759 {
734 temp_buf [row] = ROW(row1 + (row + count + rows) % rows); 760 temp_buf [row] = ROW(row1 + (row + count + rows) % rows);
735 761
737 scr_blank_screen_mem (temp_buf [row], rstyle); 763 scr_blank_screen_mem (temp_buf [row], rstyle);
738 } 764 }
739 765
740 for (int row = 0; row < rows; row++) 766 for (int row = 0; row < rows; row++)
741 ROW(row1 + row) = temp_buf [row]; 767 ROW(row1 + row) = temp_buf [row];
768
769 // sever bottommost line
770 {
771 line_t &l = ROW(row2);
772 l.is_longer (0);
773 l.touch ();
774 }
742 } 775 }
743 776
744 return count; 777 return count;
745} 778}
746 779
752rxvt_term::scr_add_lines (const wchar_t *str, int len, int minlines) NOTHROW 785rxvt_term::scr_add_lines (const wchar_t *str, int len, int minlines) NOTHROW
753{ 786{
754 if (len <= 0) /* sanity */ 787 if (len <= 0) /* sanity */
755 return; 788 return;
756 789
757 unsigned char checksel; 790 bool checksel;
758 unicode_t c; 791 unicode_t c;
759 int ncol = this->ncol; 792 int ncol = this->ncol;
760 const wchar_t *strend = str + len; 793 const wchar_t *strend = str + len;
761 794
762 want_refresh = 1; 795 want_refresh = 1;
775 scr_scroll_text (screen.tscroll, screen.bscroll, minlines); 808 scr_scroll_text (screen.tscroll, screen.bscroll, minlines);
776 screen.cur.row -= minlines; 809 screen.cur.row -= minlines;
777 } 810 }
778 } 811 }
779 812
780#ifdef DEBUG_STRICT
781 assert (screen.cur.col < ncol); 813 assert (screen.cur.col < ncol);
782 assert (screen.cur.row < nrow 814 assert (screen.cur.row < nrow
783 && screen.cur.row >= top_row); 815 && screen.cur.row >= top_row);
784#endif
785 int row = screen.cur.row; 816 int row = screen.cur.row;
786 817
787 checksel = selection.op && current_screen == selection.screen ? 1 : 0; 818 checksel = selection.op && current_screen == selection.screen ? 1 : 0;
788 819
789 line_t *line = &ROW(row); 820 line_t *line = &ROW(row);
790 821
791 while (str < strend) 822 while (str < strend)
792 { 823 {
793 c = (unicode_t)*str++; // convert to rxvt-unicodes representation 824 c = (unicode_t)*str++; // convert to rxvt-unicodes representation
794 825
795 if (expect_false (c < 0x20)) 826 if (ecb_unlikely (c < 0x20))
796 if (c == C0_LF) 827 if (c == C0_LF)
797 { 828 {
798 max_it (line->l, screen.cur.col); 829 max_it (line->l, screen.cur.col);
799 830
800 screen.flags &= ~Screen_WrapNext; 831 screen.flags &= ~Screen_WrapNext;
819 { 850 {
820 scr_tab (1, true); 851 scr_tab (1, true);
821 continue; 852 continue;
822 } 853 }
823 854
824 if (expect_false ( 855 if (ecb_unlikely (
825 checksel /* see if we're writing within selection */ 856 checksel /* see if we're writing within selection */
826 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) 857 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
827 && ROWCOL_IS_BEFORE (screen.cur, selection.end) 858 && ROWCOL_IS_BEFORE (screen.cur, selection.end)
828 )) 859 ))
829 { 860 {
834 * should be a similar check. 865 * should be a similar check.
835 */ 866 */
836 CLEAR_SELECTION (); 867 CLEAR_SELECTION ();
837 } 868 }
838 869
839 if (expect_false (screen.flags & Screen_WrapNext)) 870 if (ecb_unlikely (screen.flags & Screen_WrapNext))
840 { 871 {
841 scr_do_wrap (); 872 scr_do_wrap ();
842 873
843 line->l = ncol; 874 line->l = ncol;
844 line->is_longer (1); 875 line->is_longer (1);
846 row = screen.cur.row; 877 row = screen.cur.row;
847 line = &ROW(row); /* _must_ refresh */ 878 line = &ROW(row); /* _must_ refresh */
848 } 879 }
849 880
850 // some utf-8 decoders "decode" surrogate characters: let's fix this. 881 // some utf-8 decoders "decode" surrogate characters: let's fix this.
851 if (expect_false (IN_RANGE_INC (c, 0xd800, 0xdfff))) 882 if (ecb_unlikely (IN_RANGE_INC (c, 0xd800, 0xdfff)))
852 c = 0xfffd; 883 c = 0xfffd;
853 884
854 // rely on wcwidth to tell us the character width, do wcwidth before 885 // rely on wcwidth to tell us the character width, do wcwidth before
855 // further replacements, as wcwidth might return -1 for the line 886 // further replacements, as wcwidth might return -1 for the line
856 // drawing characters below as they might be invalid in the current 887 // drawing characters below as they might be invalid in the current
857 // locale. 888 // locale.
858 int width = WCWIDTH (c); 889 int width = WCWIDTH (c);
859 890
860 if (expect_false (charsets [screen.charset] == '0')) // DEC SPECIAL 891 if (ecb_unlikely (charsets [screen.charset] == '0')) // DEC SPECIAL
861 { 892 {
862 // vt100 special graphics and line drawing 893 // vt100 special graphics and line drawing
863 // 5f-7e standard vt100 894 // 5f-7e standard vt100
864 // 40-5e rxvt extension for extra curses acs chars 895 // 40-5e rxvt extension for extra curses acs chars
865 static uint16_t vt100_0[62] = { // 41 .. 7e 896 static uint16_t vt100_0[62] = { // 41 .. 7e
878 c = vt100_0[c - 0x41]; 909 c = vt100_0[c - 0x41];
879 width = 1; // vt100 line drawing characters are always single-width 910 width = 1; // vt100 line drawing characters are always single-width
880 } 911 }
881 } 912 }
882 913
883 if (expect_false (screen.flags & Screen_Insert)) 914 if (ecb_unlikely (screen.flags & Screen_Insert))
884 scr_insdel_chars (width, INSERT); 915 scr_insdel_chars (width, INSERT);
885 916
886 if (width != 0) 917 if (width != 0)
887 { 918 {
888#if !UNICODE_3 919#if !UNICODE_3
893# else 924# else
894 c = 0xfffd; 925 c = 0xfffd;
895# endif 926# endif
896#endif 927#endif
897 928
929 rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
930
931 // if the character doesn't fit into the remaining columns...
932 if (ecb_unlikely (screen.cur.col > ncol - width && ncol >= width))
933 {
934 if (screen.flags & Screen_Autowrap)
935 {
936 // ... artificially enlargen the previous one
937 c = NOCHAR;
938 // and try the same character next loop iteration
939 --str;
940 }
941 else
942 screen.cur.col = ncol - width;
943 }
944
898 // nuke the character at this position, if required 945 // nuke the character at this position, if required
899 if (expect_false ( 946 // due to wonderful coincidences everywhere else in this loop
947 // we never have to check for overwriting a wide char itself,
948 // only its tail.
900 line->t[screen.cur.col] == NOCHAR 949 if (ecb_unlikely (line->t[screen.cur.col] == NOCHAR))
901 || (screen.cur.col < ncol - 1
902 && line->t[screen.cur.col + 1] == NOCHAR)
903 ))
904 scr_kill_char (*line, screen.cur.col); 950 scr_kill_char (*line, screen.cur.col);
905
906 rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
907
908 // if the character doesn't fit into the remaining columns...
909 if (expect_false (screen.cur.col > ncol - width && ncol >= width))
910 {
911 // ...output spaces
912 c = ' ';
913 // and try the same character next loop iteration
914 --str;
915 }
916 951
917 line->touch (); 952 line->touch ();
918 953
919 do 954 do
920 { 955 {
921 line->t[screen.cur.col] = c; 956 line->t[screen.cur.col] = c;
922 line->r[screen.cur.col] = rend; 957 line->r[screen.cur.col] = rend;
923 958
924 if (expect_true (screen.cur.col < ncol - 1)) 959 if (ecb_likely (screen.cur.col < ncol - 1))
925 screen.cur.col++; 960 screen.cur.col++;
926 else 961 else
927 { 962 {
928 line->l = ncol; 963 line->l = ncol;
929 if (screen.flags & Screen_Autowrap) 964 if (screen.flags & Screen_Autowrap)
930 screen.flags |= Screen_WrapNext; 965 screen.flags |= Screen_WrapNext;
931 break; 966
967 goto end_of_line;
932 } 968 }
933 969
934 c = NOCHAR; 970 c = NOCHAR;
935 } 971 }
936 while (expect_false (--width > 0)); 972 while (ecb_unlikely (--width > 0));
937 973
938 // pad with spaces when overwriting wide character with smaller one 974 // pad with spaces when overwriting wide character with smaller one
939 if (expect_false (!width)) 975 for (int c = screen.cur.col; ecb_unlikely (c < ncol && line->t[c] == NOCHAR); c++)
940 { 976 {
941 line->touch ();
942
943 for (int c = screen.cur.col; c < ncol && line->t[c] == NOCHAR; c++)
944 {
945 line->t[c] = ' '; 977 line->t[c] = ' ';
946 line->r[c] = rend; 978 line->r[c] = rend;
947 }
948 } 979 }
980
981end_of_line:
982 ;
949 } 983 }
950#if ENABLE_COMBINING 984#if ENABLE_COMBINING
951 else // width == 0 985 else // width == 0
952 { 986 {
953 if (c != 0xfeff) // ignore BOM 987 if (c != 0xfeff) // ignore BOM
993#endif 1027#endif
994 } 1028 }
995 1029
996 max_it (line->l, screen.cur.col); 1030 max_it (line->l, screen.cur.col);
997 1031
998#ifdef DEBUG_STRICT
999 assert (screen.cur.row >= 0); 1032 assert (screen.cur.row >= 0);
1000#endif
1001} 1033}
1002 1034
1003/* ------------------------------------------------------------------------- */ 1035/* ------------------------------------------------------------------------- */
1004/* 1036/*
1005 * Process Backspace. Move back the cursor back a position, wrap if have to 1037 * Process Backspace. Move back the cursor back a position, wrap if have to
1018 1050
1019 want_refresh = 1; 1051 want_refresh = 1;
1020#endif 1052#endif
1021 } 1053 }
1022 } 1054 }
1055 else if (screen.flags & Screen_WrapNext)
1056 screen.flags &= ~Screen_WrapNext;
1023 else 1057 else
1024 scr_gotorc (0, -1, RELATIVE); 1058 scr_gotorc (0, -1, RELATIVE);
1025} 1059}
1026 1060
1027/* ------------------------------------------------------------------------- */ 1061/* ------------------------------------------------------------------------- */
1283 scr_blank_line (line, col, num, rstyle); 1317 scr_blank_line (line, col, num, rstyle);
1284} 1318}
1285 1319
1286/* ------------------------------------------------------------------------- */ 1320/* ------------------------------------------------------------------------- */
1287/* 1321/*
1288 * Erase part of whole of the screen 1322 * Erase part or whole of the screen
1289 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J 1323 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1290 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J 1324 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1291 * XTERM_SEQ: Clear whole screen : ESC [ 2 J 1325 * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1292 */ 1326 */
1293void 1327void
1302 ZERO_SCROLLBACK (); 1336 ZERO_SCROLLBACK ();
1303 1337
1304 switch (mode) 1338 switch (mode)
1305 { 1339 {
1306 case 0: /* erase to end of screen */ 1340 case 0: /* erase to end of screen */
1307 selection_check (1);
1308 scr_erase_line (0); 1341 scr_erase_line (0);
1309 row = screen.cur.row + 1; /* possible OOB */ 1342 row = screen.cur.row + 1; /* possible OOB */
1310 num = nrow - row; 1343 num = nrow - row;
1311 break; 1344 break;
1312 case 1: /* erase to beginning of screen */ 1345 case 1: /* erase to beginning of screen */
1313 selection_check (3);
1314 scr_erase_line (1); 1346 scr_erase_line (1);
1315 row = 0; 1347 row = 0;
1316 num = screen.cur.row; 1348 num = screen.cur.row;
1317 break; 1349 break;
1318 case 2: /* erase whole screen */ 1350 case 2: /* erase whole screen */
1319 selection_check (3);
1320 row = 0; 1351 row = 0;
1321 num = nrow; 1352 num = nrow;
1322 break; 1353 break;
1323 default: 1354 default:
1324 return; 1355 return;
1333 if (row >= nrow) /* Out Of Bounds */ 1364 if (row >= nrow) /* Out Of Bounds */
1334 return; 1365 return;
1335 1366
1336 min_it (num, nrow - row); 1367 min_it (num, nrow - row);
1337 1368
1338 /*TODO: the xlceararea/xfillrectangle below don't take scroll offste into account, ask mikachu for details */
1339 if (rstyle & (RS_RVid | RS_Uline)) 1369 if (rstyle & (RS_Blink | RS_RVid | RS_Uline))
1340 ren = (rend_t) ~RS_None; 1370 ren = (rend_t) ~RS_None;
1341 else if (GET_BASEBG (rstyle) == Color_bg) 1371 else if (GET_BASEBG (rstyle) == Color_bg)
1342 { 1372 {
1343 ren = DEFAULT_RSTYLE; 1373 ren = DEFAULT_RSTYLE;
1344 1374
1345 if (mapped) 1375 if (mapped)
1346 XClearArea (dpy, vt, 0, 1376 XClearArea (dpy, vt, 0,
1347 Row2Pixel (row), (unsigned int)width, 1377 Row2Pixel (row - view_start), (unsigned int)vt_width,
1348 (unsigned int)Height2Pixel (num), False); 1378 (unsigned int)Height2Pixel (num), False);
1349 } 1379 }
1350 else 1380 else
1351 { 1381 {
1352 ren = rstyle & (RS_fgMask | RS_bgMask); 1382 ren = rstyle & (RS_fgMask | RS_bgMask);
1353 1383
1384 if (mapped)
1385 {
1354 gcvalue.foreground = pix_colors[bgcolor_of (rstyle)]; 1386 gcvalue.foreground = pix_colors[bgcolor_of (rstyle)];
1355 XChangeGC (dpy, gc, GCForeground, &gcvalue); 1387 XChangeGC (dpy, gc, GCForeground, &gcvalue);
1356 XFillRectangle (dpy, vt, gc, 1388 XFillRectangle (dpy, vt, gc,
1357 0, Row2Pixel (row), 1389 0, Row2Pixel (row - view_start),
1358 (unsigned int)width, 1390 (unsigned int)vt_width,
1359 (unsigned int)Height2Pixel (num)); 1391 (unsigned int)Height2Pixel (num));
1360 gcvalue.foreground = pix_colors[Color_fg]; 1392 gcvalue.foreground = pix_colors[Color_fg];
1361 XChangeGC (dpy, gc, GCForeground, &gcvalue); 1393 XChangeGC (dpy, gc, GCForeground, &gcvalue);
1394 }
1362 } 1395 }
1363 1396
1364 for (; num--; row++) 1397 for (; num--; row++)
1365 { 1398 {
1366 scr_blank_screen_mem (ROW(row), rstyle); 1399 scr_blank_screen_mem (ROW(row), rstyle);
1400
1401 if (row - view_start < nrow)
1367 scr_blank_line (drawn_buf [row], 0, ncol, ren); 1402 scr_blank_line (drawn_buf [row - view_start], 0, ncol, ren);
1368 } 1403 }
1369} 1404}
1370 1405
1371#if !ENABLE_MINIMAL 1406#if !ENABLE_MINIMAL
1372void 1407void
1391 1426
1392 want_refresh = 1; 1427 want_refresh = 1;
1393 ZERO_SCROLLBACK (); 1428 ZERO_SCROLLBACK ();
1394 1429
1395 num_scr_allow = 0; 1430 num_scr_allow = 0;
1396 selection_check (3); 1431
1432 row_col_t pos;
1433 pos.row = pos.col = 0;
1434 if (ROWCOL_IS_AFTER (selection.end, pos))
1435 CLEAR_SELECTION ();
1397 1436
1398 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E')); 1437 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E'));
1399 for (int row = nrow; row--; ) 1438 for (int row = nrow; row--; )
1400 { 1439 {
1401 line_t &line = ROW(row); 1440 line_t &line = ROW(row);
1525 { 1564 {
1526 line->t[col] = line->t[col + count]; 1565 line->t[col] = line->t[col + count];
1527 line->r[col] = line->r[col + count]; 1566 line->r[col] = line->r[col + count];
1528 } 1567 }
1529 1568
1530 scr_blank_line (*line, ncol - count, count, 1569 scr_blank_line (*line, ncol - count, count, rstyle);
1531 line->r[ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask));
1532 1570
1533 if (selection.op && current_screen == selection.screen 1571 if (selection.op && current_screen == selection.screen
1534 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) 1572 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1535 { 1573 {
1536 if (selection.end.row != screen.cur.row 1574 if (selection.end.row != screen.cur.row
1672 { 1710 {
1673 rvideo_state = on; 1711 rvideo_state = on;
1674 1712
1675 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]); 1713 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]);
1676#ifdef HAVE_BG_PIXMAP 1714#ifdef HAVE_BG_PIXMAP
1677 if (bgPixmap.pixmap == None) 1715 if (bg_pixmap == None)
1678#endif 1716#endif
1679 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]); 1717 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
1680 1718
1681 XGCValues gcvalue; 1719 XGCValues gcvalue;
1682 gcvalue.foreground = pix_colors[Color_fg]; 1720 gcvalue.foreground = pix_colors[Color_fg];
1826 for (i = PART_BEG; i < RC_COUNT; i++) 1864 for (i = PART_BEG; i < RC_COUNT; i++)
1827 { 1865 {
1828 min_it (rc[i].col, ncol - 1); 1866 min_it (rc[i].col, ncol - 1);
1829 min_it (rc[i].row, nrow - 1); 1867 min_it (rc[i].row, nrow - 1);
1830 } 1868 }
1831// TODO: this line somehow causes segfault if scr_expose() is called just after resize 1869
1832 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++) 1870 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1833 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1); 1871 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
1834 1872
1835 num_scr_allow = 0; 1873 num_scr_allow = 0;
1836 1874
1843 * Refresh the entire screen 1881 * Refresh the entire screen
1844 */ 1882 */
1845void 1883void
1846rxvt_term::scr_touch (bool refresh) NOTHROW 1884rxvt_term::scr_touch (bool refresh) NOTHROW
1847{ 1885{
1848 scr_expose (0, 0, width, height, refresh); 1886 scr_expose (0, 0, vt_width, vt_height, refresh);
1849} 1887}
1850 1888
1851/* ------------------------------------------------------------------------- */ 1889/* ------------------------------------------------------------------------- */
1852/* 1890/*
1853 * Move the display so that the line represented by scrollbar value Y is at 1891 * Move the display so that the line represented by scrollbar value Y is at
1909 1947
1910# ifndef NO_MAPALERT 1948# ifndef NO_MAPALERT
1911# ifdef MAPALERT_OPTION 1949# ifdef MAPALERT_OPTION
1912 if (option (Opt_mapAlert)) 1950 if (option (Opt_mapAlert))
1913# endif 1951# endif
1914 XMapWindow (dpy, parent[0]); 1952 XMapWindow (dpy, parent);
1915# endif 1953# endif
1916 1954
1917# if ENABLE_FRILLS 1955# if ENABLE_FRILLS
1918 if (option (Opt_urgentOnBell)) 1956 if (option (Opt_urgentOnBell))
1919 set_urgency (1); 1957 set_urgency (1);
1927 1965
1928 bell_ev.start (VISUAL_BELL_DURATION); 1966 bell_ev.start (VISUAL_BELL_DURATION);
1929 } 1967 }
1930 else 1968 else
1931 XBell (dpy, 0); 1969 XBell (dpy, 0);
1970 HOOK_INVOKE ((this, HOOK_BELL, DT_END));
1932#endif 1971#endif
1933} 1972}
1934 1973
1935/* ------------------------------------------------------------------------- */ 1974/* ------------------------------------------------------------------------- */
1936/* ARGSUSED */
1937void 1975void
1938rxvt_term::scr_printscreen (int fullhist) NOTHROW 1976rxvt_term::scr_printscreen (int fullhist) NOTHROW
1939{ 1977{
1940#ifdef PRINTPIPE 1978#ifdef PRINTPIPE
1941 int nrows, row_start; 1979 int nrows, row_start;
1955 row_start = view_start; 1993 row_start = view_start;
1956 } 1994 }
1957 1995
1958 wctomb (0, 0); 1996 wctomb (0, 0);
1959 1997
1960 for (int r1 = 0; r1 < nrows; r1++) 1998 for (int r1 = row_start; r1 < row_start + nrows; r1++)
1961 { 1999 {
1962 text_t *tp = ROW(r1).t; 2000 text_t *tp = ROW(r1).t;
1963 int len = ROW(r1).l; 2001 int len = ROW(r1).l;
1964 2002
1965 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN 2003 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN
1994 * screen.text/screen.rend contain what the screen will change to. 2032 * screen.text/screen.rend contain what the screen will change to.
1995 */ 2033 */
1996void 2034void
1997rxvt_term::scr_refresh () NOTHROW 2035rxvt_term::scr_refresh () NOTHROW
1998{ 2036{
1999 unsigned char have_bg,
2000 showcursor; /* show the cursor */
2001 int16_t col, row, /* column/row we're processing */ 2037 int16_t col, row, /* column/row we're processing */
2002 ocrow; /* old cursor row */ 2038 ocrow; /* old cursor row */
2003 int i; /* tmp */ 2039 int i; /* tmp */
2004#ifndef NO_CURSORCOLOR 2040#ifndef NO_CURSORCOLOR
2005 rend_t cc1; /* store colours at cursor position (s) */ 2041 rend_t cc1; /* store colours at cursor position (s) */
2016 /* 2052 /*
2017 * A: set up vars 2053 * A: set up vars
2018 */ 2054 */
2019 refresh_count = 0; 2055 refresh_count = 0;
2020 2056
2057 unsigned int old_screen_flags = screen.flags;
2021 have_bg = 0; 2058 bool have_bg = 0;
2022#ifdef HAVE_BG_PIXMAP 2059#ifdef HAVE_BG_PIXMAP
2023 have_bg = bgPixmap.pixmap != None; 2060 have_bg = bg_pixmap != None;
2024#endif 2061#endif
2025 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */ 2062 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
2026 2063
2027 /* 2064 /*
2028 * B: reverse any characters which are selected 2065 * B: reverse any characters which are selected
2029 */ 2066 */
2030 scr_reverse_selection (); 2067 scr_reverse_selection ();
2031 2068
2069 HOOK_INVOKE ((this, HOOK_REFRESH_BEGIN, DT_END));
2070#if ENABLE_OVERLAY
2071 scr_swap_overlay ();
2072#endif
2073
2074 bool showcursor = screen.flags & Screen_VisibleCursor;
2075
2032 /* 2076 /*
2033 * C: set the cursor character (s) 2077 * C: set the cursor character (s)
2034 */ 2078 */
2035 { 2079 {
2036 unsigned char setoldcursor; 2080 bool setoldcursor;
2037 2081
2038 showcursor = (screen.flags & Screen_VisibleCursor);
2039#ifdef CURSOR_BLINK 2082#ifdef CURSOR_BLINK
2040 if (hidden_cursor) 2083 if (hidden_cursor)
2041 showcursor = 0; 2084 showcursor = 0;
2042#endif 2085#endif
2043 2086
2071 ccol2 = bgcolor_of (rstyle); 2114 ccol2 = bgcolor_of (rstyle);
2072#else 2115#else
2073 ccol2 = Color_bg; 2116 ccol2 = Color_bg;
2074#endif 2117#endif
2075 2118
2076 if (showcursor && focus) 2119 if (focus)
2077 { 2120 {
2078 if (option (Opt_cursorUnderline)) 2121 if (option (Opt_cursorUnderline))
2079 *crp ^= RS_Uline; 2122 *crp ^= RS_Uline;
2080 else 2123 else
2081 { 2124 {
2116 oldcursor.col = screen.cur.col; 2159 oldcursor.col = screen.cur.col;
2117 } 2160 }
2118 } 2161 }
2119 } 2162 }
2120 2163
2121 HOOK_INVOKE ((this, HOOK_REFRESH_BEGIN, DT_END));
2122#if ENABLE_OVERLAY
2123 scr_swap_overlay ();
2124#endif
2125
2126#ifndef NO_SLOW_LINK_SUPPORT 2164#ifndef NO_SLOW_LINK_SUPPORT
2127 /* 2165 /*
2128 * D: CopyArea pass - very useful for slower links 2166 * D: CopyArea pass - very useful for slower links
2129 * This has been deliberately kept simple. 2167 * This has been deliberately kept simple.
2130 */ 2168 */
2134 { 2172 {
2135 int16_t nits; 2173 int16_t nits;
2136 int i = num_scr; 2174 int i = num_scr;
2137 int j; 2175 int j;
2138 int len, wlen; 2176 int len, wlen;
2139 dLocal (int, num_scr);
2140 2177
2141 j = nrow; 2178 j = nrow;
2142 wlen = len = -1; 2179 wlen = len = -1;
2143 row = i > 0 ? 0 : j - 1; 2180 row = i > 0 ? 0 : j - 1;
2144 2181
2219 continue; 2256 continue;
2220 2257
2221 // redraw one or more characters 2258 // redraw one or more characters
2222 2259
2223 // seek to the beginning of wide characters 2260 // seek to the beginning of wide characters
2224 while (expect_false (stp[col] == NOCHAR && col > 0)) 2261 while (ecb_unlikely (stp[col] == NOCHAR && col > 0))
2225 --col; 2262 --col;
2226 2263
2227 rend_t rend = srp[col]; /* screen rendition (target rendtion) */ 2264 rend_t rend = srp[col]; /* screen rendition (target rendition) */
2228 text_t *text = stp + col; 2265 text_t *text = stp + col;
2229 int count = 1; 2266 int count = 1;
2230 2267
2231 dtp[col] = stp[col]; 2268 dtp[col] = stp[col];
2232 drp[col] = rend; 2269 drp[col] = rend;
2236 for (i = 0; ++col < ncol; ) 2273 for (i = 0; ++col < ncol; )
2237 { 2274 {
2238 if (stp[col] == NOCHAR) 2275 if (stp[col] == NOCHAR)
2239 { 2276 {
2240 dtp[col] = stp[col]; 2277 dtp[col] = stp[col];
2241 drp[col] = rend; 2278 drp[col] = srp[col];
2279
2242 count++; 2280 count++;
2243 i++; 2281 i++;
2244 2282
2245 continue; 2283 continue;
2246 } 2284 }
2266 2304
2267 col--; /* went one too far. move back */ 2305 col--; /* went one too far. move back */
2268 count -= i; /* dump any matching trailing chars */ 2306 count -= i; /* dump any matching trailing chars */
2269 2307
2270 // sometimes we optimize away the trailing NOCHAR's, add them back 2308 // sometimes we optimize away the trailing NOCHAR's, add them back
2271 while (expect_false (i && text[count] == NOCHAR)) 2309 while (ecb_unlikely (i && text[count] == NOCHAR))
2272 count++, i--; 2310 count++, i--;
2273 2311
2274 /* 2312 /*
2275 * Determine the attributes for the string 2313 * Determine the attributes for the string
2276 */ 2314 */
2277 int fore = fgcolor_of (rend); // desired foreground 2315 int fore = fgcolor_of (rend); // desired foreground
2278 int back = bgcolor_of (rend); // desired background 2316 int back = bgcolor_of (rend); // desired background
2279 2317
2280 // only do special processing if any attributes are set, which is unlikely 2318 // only do special processing if any attributes are set, which is unlikely
2281 if (expect_false (rend & (RS_Bold | RS_Italic | RS_Uline | RS_RVid | RS_Blink | RS_Careful))) 2319 if (ecb_unlikely (rend & (RS_baseattrMask | RS_Careful | RS_Sel)))
2282 { 2320 {
2283 bool invert = rend & RS_RVid; 2321 bool invert = rend & RS_RVid;
2284 2322
2285#ifndef NO_BOLD_UNDERLINE_REVERSE 2323#ifndef NO_BOLD_UNDERLINE_REVERSE
2286 if (rend & RS_Bold && fore == Color_fg) 2324 if (rend & RS_Bold && fore == Color_fg)
2305 2343
2306 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL)) 2344 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL))
2307 fore = Color_UL; 2345 fore = Color_UL;
2308#endif 2346#endif
2309 2347
2348#ifdef OPTION_HC
2349 if (rend & RS_Sel)
2350 {
2351 /* invert the column if no highlightColor is set or it is the
2352 * current cursor column */
2353 if (!(showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2354 && ISSET_PIXCOLOR (Color_HC))
2355 {
2356 if (ISSET_PIXCOLOR (Color_HTC))
2357 fore = Color_HTC;
2358 // if invert is 0 reverse video is set so we use bg color as fg color
2359 else if (!invert)
2360 fore = back;
2361
2362 back = Color_HC;
2363 invert = 0;
2364 }
2365 }
2366#endif
2367
2310 if (invert) 2368 if (invert)
2311 { 2369 {
2312#ifdef OPTION_HC
2313 if ((showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2314 || !ISSET_PIXCOLOR (Color_HC))
2315#endif
2316 /* invert the column if no highlightColor is set or it is the
2317 * current cursor column */
2318 ::swap (fore, back); 2370 ::swap (fore, back);
2319#ifdef OPTION_HC
2320 else if (ISSET_PIXCOLOR (Color_HC))
2321 back = Color_HC;
2322#endif
2323 2371
2324#ifndef NO_BOLD_UNDERLINE_REVERSE 2372#ifndef NO_BOLD_UNDERLINE_REVERSE
2325# ifndef OPTION_HC
2326 if (ISSET_PIXCOLOR (Color_RV))
2327 back = Color_RV;
2328# endif
2329 if (fore == back) 2373 if (fore == back)
2330 { 2374 {
2331 fore = Color_bg; 2375 fore = Color_bg;
2332 back = Color_fg; 2376 back = Color_fg;
2333 } 2377 }
2369 /* 2413 /*
2370 * Actually do the drawing of the string here 2414 * Actually do the drawing of the string here
2371 */ 2415 */
2372 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)]; 2416 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)];
2373 2417
2374 if (expect_true (have_bg && back == Color_bg)) 2418 if (ecb_likely (have_bg && back == Color_bg))
2375 { 2419 {
2376 // this is very ugly, maybe push it into ->draw? 2420 // this is very ugly, maybe push it into ->draw?
2377 2421
2378 for (i = 0; i < count; i++) /* don't draw empty strings */ 2422 for (i = 0; i < count; i++) /* don't draw empty strings */
2379 if (text[i] != ' ') 2423 if (text[i] != ' ')
2386 did_clear: ; 2430 did_clear: ;
2387 } 2431 }
2388 else 2432 else
2389 font->draw (*drawable, xpixel, ypixel, text, count, fore, back); 2433 font->draw (*drawable, xpixel, ypixel, text, count, fore, back);
2390 2434
2391 if (expect_false (rend & RS_Uline && font->descent > 1 && fore != back)) 2435 if (ecb_unlikely (rend & RS_Uline && font->descent > 1 && fore != back))
2392 { 2436 {
2393#if ENABLE_FRILLS 2437#if ENABLE_FRILLS
2394 if (ISSET_PIXCOLOR (Color_underline)) 2438 if (ISSET_PIXCOLOR (Color_underline))
2395 XSetForeground (dpy, gc, pix_colors[Color_underline]); 2439 XSetForeground (dpy, gc, pix_colors[Color_underline]);
2396 else 2440 else
2401 xpixel, ypixel + font->ascent + 1, 2445 xpixel, ypixel + font->ascent + 1,
2402 xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1); 2446 xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2403 } 2447 }
2404 } /* for (col....) */ 2448 } /* for (col....) */
2405 } /* for (row....) */ 2449 } /* for (row....) */
2406
2407#if ENABLE_OVERLAY
2408 scr_swap_overlay ();
2409#endif
2410 HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2411 2450
2412 /* 2451 /*
2413 * G: cleanup cursor and display outline cursor if necessary 2452 * G: cleanup cursor and display outline cursor if necessary
2414 */ 2453 */
2415 if (showcursor) 2454 if (showcursor)
2447 2486
2448 XDrawRectangle (dpy, vt, gc, 2487 XDrawRectangle (dpy, vt, gc,
2449 Col2Pixel (col), 2488 Col2Pixel (col),
2450 Row2Pixel (oldcursor.row), 2489 Row2Pixel (oldcursor.row),
2451 (unsigned int) (Width2Pixel (cursorwidth) - 1), 2490 (unsigned int) (Width2Pixel (cursorwidth) - 1),
2452 (unsigned int) (Height2Pixel (1) - lineSpace - 1)); 2491 (unsigned int) (Height2Pixel (1) - 1));
2453 } 2492 }
2454 } 2493 }
2455 2494
2456 /* 2495 /*
2457 * H: cleanup selection 2496 * H: cleanup selection
2458 */ 2497 */
2498#if ENABLE_OVERLAY
2499 scr_swap_overlay ();
2500#endif
2501 HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2502
2459 scr_reverse_selection (); 2503 scr_reverse_selection ();
2460 2504
2505 screen.flags = old_screen_flags;
2461 num_scr = 0; 2506 num_scr = 0;
2462 num_scr_allow = 1; 2507 num_scr_allow = 1;
2463} 2508}
2464 2509
2465void 2510void
2466rxvt_term::scr_remap_chars (line_t &l) NOTHROW 2511rxvt_term::scr_remap_chars (line_t &l) NOTHROW
2467{ 2512{
2468 if (!l.t) 2513 if (!l.valid ())
2469 return; 2514 return;
2470 2515
2471 l.touch (); // maybe a bit of an overkill, but it's not performance-relevant 2516 l.touch (); // maybe a bit of an overkill, but it's not performance-relevant
2472 2517
2473 for (int i = ncol; i--; ) 2518 for (int i = ncol; i--; )
2486 scr_remap_chars (swap_buf [i]); 2531 scr_remap_chars (swap_buf [i]);
2487 } 2532 }
2488} 2533}
2489 2534
2490void 2535void
2491rxvt_term::scr_recolour () NOTHROW 2536rxvt_term::scr_recolour (bool refresh) NOTHROW
2492{ 2537{
2538 bool transparent = false;
2539
2493#ifdef HAVE_BG_PIXMAP 2540#ifdef HAVE_BG_PIXMAP
2494 bgPixmap.apply (); 2541 if (bg_pixmap != None)
2495#else 2542 {
2543# ifdef ENABLE_TRANSPARENCY
2544 if (bg_flags & BG_IS_TRANSPARENT)
2545 {
2546 XSetWindowBackgroundPixmap (dpy, parent, bg_pixmap);
2547 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2496 2548
2549 transparent = true;
2550 }
2551 else
2552# endif
2553 {
2554 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2555 XSetWindowBackgroundPixmap (dpy, vt, bg_pixmap);
2556 }
2557 }
2558 else
2559#endif
2560 {
2497 XSetWindowBackground (dpy, parent[0], pix_colors[Color_border]); 2561 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2498 XClearWindow (dpy, parent[0]);
2499 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]); 2562 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
2563 }
2564
2565 XClearWindow (dpy, parent);
2500 2566
2501 if (scrollBar.win) 2567 if (scrollBar.win)
2502 { 2568 {
2569 if (transparent)
2570 XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
2571 else
2503 XSetWindowBackground (dpy, scrollBar.win, pix_colors[Color_border]); 2572 XSetWindowBackground (dpy, scrollBar.win, pix_colors[Color_border]);
2504 scrollBar.state = STATE_IDLE; 2573 scrollBar.state = SB_STATE_IDLE;
2505 scrollBar.show (0); 2574 scrollBar.show (0);
2506 } 2575 }
2507 2576
2508#endif 2577 if (refresh)
2509 2578 {
2510 /* bgPixmap.apply () does not do the following : */
2511 scr_clear (); 2579 scr_clear ();
2512 scr_touch (true); 2580 scr_touch (true);
2581 }
2513 want_refresh = 1; 2582 want_refresh = 1;
2514} 2583}
2515 2584
2516/* ------------------------------------------------------------------------- */ 2585/* ------------------------------------------------------------------------- */
2517void 2586void
2585 { 2654 {
2586#if !ENABLE_MINIMAL 2655#if !ENABLE_MINIMAL
2587 if (selection.rect) 2656 if (selection.rect)
2588 scr_xor_rect (selection.beg.row, selection.beg.col, 2657 scr_xor_rect (selection.beg.row, selection.beg.col,
2589 selection.end.row, selection.end.col, 2658 selection.end.row, selection.end.col,
2590 RS_RVid, RS_RVid | RS_Uline); 2659 RS_Sel | RS_RVid, RS_Sel | RS_RVid | RS_Uline);
2591 else 2660 else
2592#endif 2661#endif
2593 scr_xor_span (selection.beg.row, selection.beg.col, 2662 scr_xor_span (selection.beg.row, selection.beg.col,
2594 selection.end.row, selection.end.col, 2663 selection.end.row, selection.end.col,
2595 RS_RVid); 2664 RS_Sel | RS_RVid);
2596 } 2665 }
2597} 2666}
2598 2667
2599/* ------------------------------------------------------------------------- */ 2668/* ------------------------------------------------------------------------- */
2600/* 2669/*
2603 */ 2672 */
2604#if 0 2673#if 0
2605void 2674void
2606rxvt_term::scr_dump (int fd) NOTHROW 2675rxvt_term::scr_dump (int fd) NOTHROW
2607{ 2676{
2608 int row, wrote; 2677 // if this method is needed, it can be implemented by factoring the
2609 unsigned int width, towrite; 2678 // relevant code in scr_printscreen
2610 char r1[] = "\n";
2611
2612 for (row = saveLines + top_row;
2613 row < saveLines + nrow - 1; row++)
2614 {
2615 width = row_buf[row].l >= 0 ? row_buf[row].l
2616 : ncol;
2617 for (towrite = width; towrite; towrite -= wrote)
2618 {
2619 wrote = write (fd, & (row_buf[row].t[width - towrite]),
2620 towrite);
2621 if (wrote < 0)
2622 return; /* XXX: death, no report */
2623 }
2624 if (row_buf[row].l >= 0)
2625 if (write (fd, r1, 1) <= 0)
2626 return; /* XXX: death, no report */
2627 }
2628} 2679}
2629#endif 2680#endif
2630 2681
2631/* ------------------------------------------------------------------------- * 2682/* ------------------------------------------------------------------------- *
2632 * CHARACTER SELECTION * 2683 * CHARACTER SELECTION *
2633 * ------------------------------------------------------------------------- */ 2684 * ------------------------------------------------------------------------- */
2634void 2685void
2635rxvt_term::selection_check (int check_more) NOTHROW 2686rxvt_term::selection_check (int check_more) NOTHROW
2636{ 2687{
2637 row_col_t pos;
2638
2639 if (!selection.op) 2688 if (!selection.op)
2640 return; 2689 return;
2641 2690
2642 pos.row = pos.col = 0;
2643 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow) 2691 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow)
2644 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow) 2692 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow)
2645 || !IN_RANGE_EXC (selection.end.row, top_row, nrow) 2693 || !IN_RANGE_EXC (selection.end.row, top_row, nrow)
2646 || (check_more == 1 2694 || (check_more == 1
2647 && current_screen == selection.screen 2695 && current_screen == selection.screen
2648 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) 2696 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2649 && ROWCOL_IS_BEFORE (screen.cur, selection.end)) 2697 && ROWCOL_IS_BEFORE (screen.cur, selection.end)))
2650 || (check_more == 2
2651 && ROWCOL_IS_BEFORE (selection.beg, pos)
2652 && ROWCOL_IS_AFTER (selection.end, pos))
2653 || (check_more == 3
2654 && ROWCOL_IS_AFTER (selection.end, pos))
2655 || (check_more == 4 /* screen width change */
2656 && (selection.beg.row != selection.end.row
2657 || selection.end.col > ncol)))
2658 CLEAR_SELECTION (); 2698 CLEAR_ALL_SELECTION ();
2659} 2699}
2660 2700
2661/* ------------------------------------------------------------------------- */ 2701/* ------------------------------------------------------------------------- */
2662/* 2702/*
2663 * Paste a selection direct to the command fd 2703 * Paste a selection direct to the command fd
2664 */ 2704 */
2665void 2705void
2666rxvt_term::paste (char *data, unsigned int len) NOTHROW 2706rxvt_term::tt_paste (char *data, unsigned int len) NOTHROW
2667{ 2707{
2668 /* convert normal newline chars into common keyboard Return key sequence */ 2708 /* convert normal newline chars into common keyboard Return key sequence */
2669 for (unsigned int i = 0; i < len; i++) 2709 for (unsigned int i = 0; i < len; i++)
2670 if (data[i] == C0_LF) 2710 if (data[i] == C0_LF)
2671 data[i] = C0_CR; 2711 data[i] = C0_CR;
2672 2712
2673 if (priv_modes & PrivMode_BracketPaste) 2713 if (priv_modes & PrivMode_BracketPaste)
2674 tt_printf ("\e[200~"); 2714 tt_printf ("\x1b[200~");
2675 2715
2676 tt_write (data, len); 2716 tt_write (data, len);
2677 2717
2678 if (priv_modes & PrivMode_BracketPaste) 2718 if (priv_modes & PrivMode_BracketPaste)
2679 tt_printf ("\e[201~"); 2719 tt_printf ("\x1b[201~");
2680} 2720}
2681 2721
2682/* ------------------------------------------------------------------------- */
2683/*
2684 * Respond to a notification that a primary selection has been sent
2685 * EXT: SelectionNotify
2686 */
2687void 2722void
2688rxvt_term::selection_paste (Window win, Atom prop, bool delete_prop) NOTHROW 2723rxvt_term::paste (char *data, unsigned int len) NOTHROW
2689{ 2724{
2690 if (prop == None) /* check for failed XConvertSelection */ 2725 if (HOOK_INVOKE ((this, HOOK_TT_PASTE, DT_STR_LEN, data, len, DT_END)))
2691 {
2692 if ((selection_type & Sel_CompoundText))
2693 {
2694 int selnum = selection_type & Sel_whereMask;
2695
2696 selection_type = 0;
2697 if (selnum != Sel_direct)
2698 selection_request_other (XA_STRING, selnum);
2699 }
2700
2701 if ((selection_type & Sel_UTF8String))
2702 {
2703 int selnum = selection_type & Sel_whereMask;
2704
2705 selection_type = Sel_CompoundText;
2706 if (selnum != Sel_direct)
2707 selection_request_other (xa[XA_COMPOUND_TEXT], selnum);
2708 else
2709 selection_type = 0;
2710 }
2711
2712 return;
2713 }
2714
2715 unsigned long bytes_after;
2716 XTextProperty ct;
2717
2718 if (XGetWindowProperty (dpy, win, prop,
2719 0, PROP_SIZE / 4,
2720 delete_prop, AnyPropertyType,
2721 &ct.encoding, &ct.format,
2722 &ct.nitems, &bytes_after,
2723 &ct.value) != Success)
2724 {
2725 ct.value = 0;
2726 goto bailout;
2727 }
2728
2729 if (ct.encoding == None)
2730 goto bailout;
2731
2732 if (bytes_after)
2733 {
2734 // fetch and append remaining data
2735 XTextProperty ct2;
2736
2737 if (XGetWindowProperty (dpy, win, prop,
2738 ct.nitems / 4, (bytes_after + 3) / 4,
2739 delete_prop, AnyPropertyType,
2740 &ct2.encoding, &ct2.format,
2741 &ct2.nitems, &bytes_after,
2742 &ct2.value) != Success)
2743 goto bailout;
2744
2745 // realloc should be compatible to XFree, here, and elsewhere, too
2746 ct.value = (unsigned char *)realloc (ct.value, ct.nitems + ct2.nitems + 1);
2747 memcpy (ct.value + ct.nitems, ct2.value, ct2.nitems + 1);
2748 ct.nitems += ct2.nitems;
2749
2750 XFree (ct2.value);
2751 }
2752
2753 if (ct.value == 0)
2754 goto bailout;
2755
2756 if (ct.encoding == xa[XA_INCR])
2757 {
2758 // INCR selection, start handshake
2759 if (!delete_prop)
2760 XDeleteProperty (dpy, win, prop);
2761
2762 selection_wait = Sel_incr;
2763 incr_buf_fill = 0;
2764 incr_ev.start (10);
2765
2766 goto bailout;
2767 }
2768
2769 if (ct.nitems == 0)
2770 {
2771 if (selection_wait == Sel_incr)
2772 {
2773 XFree (ct.value);
2774
2775 // finally complete, now paste the whole thing
2776 selection_wait = Sel_normal;
2777 ct.value = (unsigned char *)incr_buf;
2778 ct.nitems = incr_buf_fill;
2779 incr_buf = 0;
2780 incr_buf_size = 0;
2781 incr_ev.stop ();
2782 }
2783 else
2784 {
2785 if (selection_wait == Sel_normal
2786 && (win != display->root || prop != XA_CUT_BUFFER0)) // avoid recursion
2787 {
2788 /*
2789 * pass through again trying CUT_BUFFER0 if we've come from
2790 * XConvertSelection () but nothing was presented
2791 */
2792 selection_paste (display->root, XA_CUT_BUFFER0, False);
2793 }
2794
2795 goto bailout;
2796 }
2797 }
2798 else if (selection_wait == Sel_incr)
2799 {
2800 incr_ev.start (10);
2801
2802 while (incr_buf_fill + ct.nitems > incr_buf_size)
2803 {
2804 incr_buf_size = incr_buf_size ? incr_buf_size * 2 : 128*1024;
2805 incr_buf = (char *)realloc (incr_buf, incr_buf_size);
2806 }
2807
2808 memcpy (incr_buf + incr_buf_fill, ct.value, ct.nitems);
2809 incr_buf_fill += ct.nitems;
2810
2811 goto bailout;
2812 }
2813
2814 char **cl;
2815 int cr;
2816
2817#if !ENABLE_MINIMAL
2818 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
2819 // so recode it manually
2820 if (ct.encoding == xa[XA_UTF8_STRING])
2821 {
2822 wchar_t *w = rxvt_utf8towcs ((const char *)ct.value, ct.nitems);
2823 char *s = rxvt_wcstombs (w);
2824 free (w);
2825 // TODO: strlen == only the first element will be converted. well...
2826 paste (s, strlen (s));
2827 free (s);
2828 }
2829 else
2830#endif
2831 if (XmbTextPropertyToTextList (dpy, &ct, &cl, &cr) >= 0
2832 && cl)
2833 {
2834 for (int i = 0; i < cr; i++)
2835 paste (cl[i], strlen (cl[i]));
2836
2837 XFreeStringList (cl);
2838 }
2839 else
2840 paste ((char *)ct.value, ct.nitems); // paste raw
2841
2842bailout:
2843 XFree (ct.value);
2844
2845 if (selection_wait == Sel_normal)
2846 selection_wait = Sel_none;
2847}
2848
2849void
2850rxvt_term::incr_cb (ev::timer &w, int revents) NOTHROW
2851{
2852 selection_wait = Sel_none;
2853
2854 incr_buf_size = 0;
2855 free (incr_buf);
2856
2857 rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
2858}
2859
2860void
2861rxvt_term::selection_property (Window win, Atom prop) NOTHROW
2862{
2863 if (prop == None || selection_wait != Sel_incr)
2864 return; 2726 return;
2865 2727
2866 selection_paste (win, prop, true); 2728 tt_paste (data, len);
2867} 2729}
2868 2730
2869/* ------------------------------------------------------------------------- */ 2731/* ------------------------------------------------------------------------- */
2870/* 2732/*
2871 * Request the current selection: 2733 * Request PRIMARY, SECONDARY or CLIPBOARD selection.
2872 * Order: > internal selection if available 2734 * if the requested selection has no owner or is empty CUT_BUFFER0 is used
2873 * > PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+) 2735 * as fallback
2874 * > CUT_BUFFER0
2875 * (+) if ownership is claimed but property is empty, rxvt_selection_paste ()
2876 * will auto fallback to CUT_BUFFER0
2877 * EXT: button 2 release 2736 * EXT: button 2 release
2878 */ 2737 */
2879void 2738void
2880rxvt_term::selection_request (Time tm, int selnum) NOTHROW 2739rxvt_term::selection_request (Time tm, int selnum) NOTHROW
2881{ 2740{
2882 if (selection.text && selnum == Sel_Primary) 2741 if (!selection_req)
2883 {
2884 /* internal selection */
2885 char *str = rxvt_wcstombs (selection.text, selection.len);
2886 paste (str, strlen (str));
2887 free (str);
2888 return;
2889 } 2742 {
2890 else 2743 selection_req = new rxvt_selection (display, selnum, tm, vt, xa[XA_VT_SELECTION], this);
2744 selection_req->run ();
2891 { 2745 }
2892 selection_request_time = tm;
2893 selection_wait = Sel_normal;
2894
2895#if X_HAVE_UTF8_STRING
2896 selection_type = Sel_UTF8String;
2897 if (selection_request_other (xa[XA_UTF8_STRING], selnum))
2898 return;
2899#else
2900 selection_type = Sel_CompoundText;
2901 if (selection_request_other (xa[XA_COMPOUND_TEXT], selnum))
2902 return;
2903#endif
2904 }
2905
2906 selection_wait = Sel_none; /* don't loop in selection_paste () */
2907 selection_paste (display->root, XA_CUT_BUFFER0, false);
2908}
2909
2910int
2911rxvt_term::selection_request_other (Atom target, int selnum) NOTHROW
2912{
2913 Atom sel;
2914
2915 selection_type |= selnum;
2916
2917 if (selnum == Sel_Primary)
2918 sel = XA_PRIMARY;
2919 else if (selnum == Sel_Secondary)
2920 sel = XA_SECONDARY;
2921 else
2922 sel = xa[XA_CLIPBOARD];
2923
2924 if (XGetSelectionOwner (dpy, sel) != None)
2925 {
2926 XConvertSelection (dpy, sel, target, xa[XA_VT_SELECTION],
2927 vt, selection_request_time);
2928 return 1;
2929 }
2930
2931 return 0;
2932} 2746}
2933 2747
2934/* ------------------------------------------------------------------------- */ 2748/* ------------------------------------------------------------------------- */
2935/* 2749/*
2936 * Clear all selected text 2750 * Clear all selected text
2937 * EXT: SelectionClear 2751 * EXT: SelectionClear
2938 */ 2752 */
2939void 2753void
2940rxvt_term::selection_clear () NOTHROW 2754rxvt_term::selection_clear (bool clipboard) NOTHROW
2941{ 2755{
2756 if (!clipboard)
2757 {
2942 want_refresh = 1; 2758 want_refresh = 1;
2943 free (selection.text); 2759 free (selection.text);
2944 selection.text = NULL; 2760 selection.text = NULL;
2945 selection.len = 0; 2761 selection.len = 0;
2946 CLEAR_SELECTION (); 2762 CLEAR_SELECTION ();
2947 2763
2948 if (display->selection_owner == this) 2764 if (display->selection_owner == this)
2949 display->selection_owner = 0; 2765 display->selection_owner = 0;
2766 }
2767 else
2768 {
2769 free (selection.clip_text);
2770 selection.clip_text = NULL;
2771 selection.clip_len = 0;
2772
2773 if (display->clipboard_owner == this)
2774 display->clipboard_owner = 0;
2775 }
2950} 2776}
2951 2777
2952/* ------------------------------------------------------------------------- */ 2778/* ------------------------------------------------------------------------- */
2953/* 2779/*
2954 * Copy a selection into the cut buffer 2780 * Copy a selection into the cut buffer
2955 * EXT: button 1 or 3 release 2781 * EXT: button 1 or 3 release
2956 */ 2782 */
2957void 2783void
2958rxvt_term::selection_make (Time tm) 2784rxvt_term::selection_make (Time tm)
2959{ 2785{
2960 int i; 2786 int size;
2961 wchar_t *new_selection_text; 2787 wchar_t *new_selection_text;
2962 text_t *t; 2788 text_t *t;
2963 2789
2964 switch (selection.op) 2790 switch (selection.op)
2965 { 2791 {
2981 return; /* nothing selected, go away */ 2807 return; /* nothing selected, go away */
2982 2808
2983 if (HOOK_INVOKE ((this, HOOK_SEL_MAKE, DT_LONG, (long)tm, DT_END))) 2809 if (HOOK_INVOKE ((this, HOOK_SEL_MAKE, DT_LONG, (long)tm, DT_END)))
2984 return; 2810 return;
2985 2811
2986 i = (selection.end.row - selection.beg.row + 1) * (ncol + 1); 2812 size = (selection.end.row - selection.beg.row + 1) * (ncol + 1);
2987 new_selection_text = (wchar_t *)rxvt_malloc ((i + 4) * sizeof (wchar_t)); 2813 new_selection_text = (wchar_t *)rxvt_malloc ((size + 4) * sizeof (wchar_t));
2988 2814
2989 int ofs = 0; 2815 int ofs = 0;
2990 int extra = 0; 2816 int extra = 0;
2991 2817
2992 int col = selection.beg.col; 2818 int col = selection.beg.col;
2998 { 2824 {
2999#if !ENABLE_MINIMAL 2825#if !ENABLE_MINIMAL
3000 if (selection.rect) 2826 if (selection.rect)
3001 { 2827 {
3002 col = selection.beg.col; 2828 col = selection.beg.col;
3003 end_col = ncol + 1; 2829 end_col = selection.end.col;
3004 } 2830 }
3005 else 2831 else
3006#endif 2832#endif
3007 end_col = ROW(row).l; 2833 end_col = ROW(row).l;
3008 2834
3009 col = max (col, 0); 2835 col = max (col, 0);
3010 2836
3011 if (row == selection.end.row 2837 if (row == selection.end.row)
3012#if !ENABLE_MINIMAL
3013 || selection.rect
3014#endif
3015 )
3016 min_it (end_col, selection.end.col); 2838 min_it (end_col, selection.end.col);
3017 2839
3018 t = ROW(row).t + col; 2840 t = ROW(row).t + col;
3019 2841
3020 for (; col < end_col; col++) 2842 for (; col < end_col; col++)
3028 2850
3029 extra -= (len - 1); 2851 extra -= (len - 1);
3030 2852
3031 if (extra < 0) 2853 if (extra < 0)
3032 { 2854 {
3033 extra += i; 2855 extra += size;
3034 i += i; 2856 size += size;
3035 new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (i + 4) * sizeof (wchar_t)); 2857 new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (size + 4) * sizeof (wchar_t));
3036 } 2858 }
3037 2859
3038 ofs += rxvt_composite.expand (*t++, new_selection_text + ofs); 2860 ofs += rxvt_composite.expand (*t++, new_selection_text + ofs);
3039 } 2861 }
3040#endif 2862#endif
3052 2874
3053 new_selection_text[ofs++] = C0_LF; 2875 new_selection_text[ofs++] = C0_LF;
3054 } 2876 }
3055 else 2877 else
3056#endif 2878#endif
3057 if (!ROW(row).is_longer () && row != selection.end.row) 2879 if (!ROW(row).is_longer ()
2880 && (row != selection.end.row || end_col != selection.end.col)
2881 && (row != selection.beg.row || selection.beg.col < ncol))
3058 new_selection_text[ofs++] = C0_LF; 2882 new_selection_text[ofs++] = C0_LF;
3059 } 2883 }
3060
3061 if (end_col != selection.end.col)
3062 new_selection_text[ofs++] = C0_LF;
3063 2884
3064 new_selection_text[ofs] = 0; 2885 new_selection_text[ofs] = 0;
3065 2886
3066 if (ofs == 0) 2887 if (ofs == 0)
3067 { 2888 {
3080 2901
3081 selection_grab (tm); 2902 selection_grab (tm);
3082} 2903}
3083 2904
3084bool 2905bool
3085rxvt_term::selection_grab (Time tm) NOTHROW 2906rxvt_term::selection_grab (Time tm, bool clipboard) NOTHROW
3086{ 2907{
2908 Atom sel;
2909
2910 if (!clipboard)
2911 {
3087 selection_time = tm; 2912 selection_time = tm;
2913 sel = XA_PRIMARY;
2914 }
2915 else
2916 {
2917 clipboard_time = tm;
2918 sel = xa[XA_CLIPBOARD];
2919 }
3088 2920
3089 XSetSelectionOwner (dpy, XA_PRIMARY, vt, tm); 2921 XSetSelectionOwner (dpy, sel, vt, tm);
3090 if (XGetSelectionOwner (dpy, XA_PRIMARY) == vt) 2922 if (XGetSelectionOwner (dpy, sel) == vt)
3091 { 2923 {
3092 display->set_selection_owner (this); 2924 display->set_selection_owner (this, clipboard);
3093 return true; 2925 return true;
3094 } 2926 }
3095 else 2927 else
3096 { 2928 {
3097 selection_clear (); 2929 selection_clear (clipboard);
3098 return false; 2930 return false;
3099 } 2931 }
3100 2932
3101#if 0 2933#if 0
3102 XTextProperty ct; 2934 XTextProperty ct;
3562 * EXT: SelectionRequest 3394 * EXT: SelectionRequest
3563 */ 3395 */
3564void 3396void
3565rxvt_term::selection_send (const XSelectionRequestEvent &rq) NOTHROW 3397rxvt_term::selection_send (const XSelectionRequestEvent &rq) NOTHROW
3566{ 3398{
3399 Atom property = rq.property == None ? rq.target : rq.property;
3567 XSelectionEvent ev; 3400 XSelectionEvent ev;
3568 3401
3569 ev.type = SelectionNotify; 3402 ev.type = SelectionNotify;
3570 ev.property = None; 3403 ev.property = None;
3571 ev.display = rq.display; 3404 ev.display = rq.display;
3586 *target++ = xa[XA_COMPOUND_TEXT]; 3419 *target++ = xa[XA_COMPOUND_TEXT];
3587#if X_HAVE_UTF8_STRING 3420#if X_HAVE_UTF8_STRING
3588 *target++ = xa[XA_UTF8_STRING]; 3421 *target++ = xa[XA_UTF8_STRING];
3589#endif 3422#endif
3590 3423
3591 XChangeProperty (dpy, rq.requestor, rq.property, XA_ATOM, 3424 XChangeProperty (dpy, rq.requestor, property, XA_ATOM,
3592 32, PropModeReplace, 3425 32, PropModeReplace,
3593 (unsigned char *)target_list, target - target_list); 3426 (unsigned char *)target_list, target - target_list);
3594 ev.property = rq.property; 3427 ev.property = property;
3595 } 3428 }
3596#if TODO // TODO 3429#if TODO // TODO
3597 else if (rq.target == xa[XA_MULTIPLE]) 3430 else if (rq.target == xa[XA_MULTIPLE])
3598 { 3431 {
3599 /* TODO: Handle MULTIPLE */ 3432 /* TODO: Handle MULTIPLE */
3600 } 3433 }
3601#endif 3434#endif
3602 else if (rq.target == xa[XA_TIMESTAMP] && selection.text) 3435 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == XA_PRIMARY && selection.text)
3603 { 3436 {
3604 XChangeProperty (dpy, rq.requestor, rq.property, rq.target, 3437 XChangeProperty (dpy, rq.requestor, property, rq.target,
3605 32, PropModeReplace, (unsigned char *)&selection_time, 1); 3438 32, PropModeReplace, (unsigned char *)&selection_time, 1);
3606 ev.property = rq.property; 3439 ev.property = property;
3440 }
3441 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3442 {
3443 XChangeProperty (dpy, rq.requestor, property, rq.target,
3444 32, PropModeReplace, (unsigned char *)&clipboard_time, 1);
3445 ev.property = property;
3607 } 3446 }
3608 else if (rq.target == XA_STRING 3447 else if (rq.target == XA_STRING
3609 || rq.target == xa[XA_TEXT] 3448 || rq.target == xa[XA_TEXT]
3610 || rq.target == xa[XA_COMPOUND_TEXT] 3449 || rq.target == xa[XA_COMPOUND_TEXT]
3611 || rq.target == xa[XA_UTF8_STRING] 3450 || rq.target == xa[XA_UTF8_STRING]
3643 { 3482 {
3644 target = xa[XA_COMPOUND_TEXT]; 3483 target = xa[XA_COMPOUND_TEXT];
3645 style = enc_compound_text; 3484 style = enc_compound_text;
3646 } 3485 }
3647 3486
3648 if (selection.text) 3487 if (rq.selection == XA_PRIMARY && selection.text)
3649 { 3488 {
3650 cl = selection.text; 3489 cl = selection.text;
3651 selectlen = selection.len; 3490 selectlen = selection.len;
3491 }
3492 else if (rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3493 {
3494 cl = selection.clip_text;
3495 selectlen = selection.clip_len;
3652 } 3496 }
3653 else 3497 else
3654 { 3498 {
3655 cl = L""; 3499 cl = L"";
3656 selectlen = 0; 3500 selectlen = 0;
3677 ct.value = (unsigned char *)cl; 3521 ct.value = (unsigned char *)cl;
3678 ct.nitems = selectlen; 3522 ct.nitems = selectlen;
3679 ct.encoding = target; 3523 ct.encoding = target;
3680 } 3524 }
3681 3525
3682 XChangeProperty (dpy, rq.requestor, rq.property, 3526 XChangeProperty (dpy, rq.requestor, property,
3683 ct.encoding, 8, PropModeReplace, 3527 ct.encoding, 8, PropModeReplace,
3684 ct.value, (int)ct.nitems); 3528 ct.value, (int)ct.nitems);
3685 ev.property = rq.property; 3529 ev.property = property;
3686 3530
3687 if (freect) 3531 if (freect)
3688 XFree (ct.value); 3532 XFree (ct.value);
3689 } 3533 }
3690 3534
3724 h += 2; min_it (h, nrow); 3568 h += 2; min_it (h, nrow);
3725 3569
3726 x -= 1; clamp_it (x, 0, ncol - w); 3570 x -= 1; clamp_it (x, 0, ncol - w);
3727 y -= 1; clamp_it (y, 0, nrow - h); 3571 y -= 1; clamp_it (y, 0, nrow - h);
3728 3572
3729 ov_x = x; ov_y = y; 3573 ov.x = x; ov.y = y;
3730 ov_w = w; ov_h = h; 3574 ov.w = w; ov.h = h;
3731 3575
3732 ov_text = new text_t *[h]; 3576 ov.text = new text_t *[h];
3733 ov_rend = new rend_t *[h]; 3577 ov.rend = new rend_t *[h];
3734 3578
3735 for (y = 0; y < h; y++) 3579 for (y = 0; y < h; y++)
3736 { 3580 {
3737 text_t *tp = ov_text[y] = new text_t[w]; 3581 text_t *tp = ov.text[y] = new text_t[w];
3738 rend_t *rp = ov_rend[y] = new rend_t[w]; 3582 rend_t *rp = ov.rend[y] = new rend_t[w];
3739 3583
3740 text_t t0, t1, t2; 3584 text_t t0, t1, t2;
3741 rend_t r = OVERLAY_RSTYLE; 3585 rend_t r = OVERLAY_RSTYLE;
3742 3586
3743 if (y == 0) 3587 if (y == 0)
3762} 3606}
3763 3607
3764void 3608void
3765rxvt_term::scr_overlay_off () NOTHROW 3609rxvt_term::scr_overlay_off () NOTHROW
3766{ 3610{
3767 if (!ov_text) 3611 if (!ov.text)
3768 return; 3612 return;
3769 3613
3770 want_refresh = 1; 3614 want_refresh = 1;
3771 3615
3772 for (int y = 0; y < ov_h; y++) 3616 for (int y = 0; y < ov.h; y++)
3773 { 3617 {
3774 delete [] ov_text[y]; 3618 delete [] ov.text[y];
3775 delete [] ov_rend[y]; 3619 delete [] ov.rend[y];
3776 } 3620 }
3777 3621
3778 delete [] ov_text; ov_text = 0; 3622 delete [] ov.text; ov.text = 0;
3779 delete [] ov_rend; ov_rend = 0; 3623 delete [] ov.rend; ov.rend = 0;
3780} 3624}
3781 3625
3782void 3626void
3783rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) NOTHROW 3627rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) NOTHROW
3784{ 3628{
3785 if (!ov_text || x >= ov_w - 2 || y >= ov_h - 2) 3629 if (!ov.text || x >= ov.w - 2 || y >= ov.h - 2)
3786 return; 3630 return;
3787 3631
3788 x++, y++; 3632 x++, y++;
3789 3633
3790 ov_text[y][x] = text; 3634 ov.text[y][x] = text;
3791 ov_rend[y][x] = rend; 3635 ov.rend[y][x] = rend;
3792} 3636}
3793 3637
3794void 3638void
3795rxvt_term::scr_overlay_set (int x, int y, const char *s) NOTHROW 3639rxvt_term::scr_overlay_set (int x, int y, const char *s) NOTHROW
3796{ 3640{
3815} 3659}
3816 3660
3817void 3661void
3818rxvt_term::scr_swap_overlay () NOTHROW 3662rxvt_term::scr_swap_overlay () NOTHROW
3819{ 3663{
3820 if (!ov_text) 3664 if (!ov.text)
3821 return; 3665 return;
3822 3666
3667 // hide cursor if it is within the overlay area
3668 if (IN_RANGE_EXC (screen.cur.col - ov.x, 0, ov.w)
3669 && IN_RANGE_EXC (screen.cur.row - ov.y, 0, ov.h))
3670 screen.flags &= ~Screen_VisibleCursor;
3671
3823 // swap screen mem with overlay 3672 // swap screen mem with overlay
3824 for (int y = ov_h; y--; ) 3673 for (int y = ov.h; y--; )
3825 { 3674 {
3826 text_t *t1 = ov_text[y]; 3675 text_t *t1 = ov.text[y];
3827 rend_t *r1 = ov_rend[y]; 3676 rend_t *r1 = ov.rend[y];
3828 3677
3829 text_t *t2 = ROW(y + ov_y + view_start).t + ov_x; 3678 text_t *t2 = ROW(y + ov.y + view_start).t + ov.x;
3830 rend_t *r2 = ROW(y + ov_y + view_start).r + ov_x; 3679 rend_t *r2 = ROW(y + ov.y + view_start).r + ov.x;
3831 3680
3832 for (int x = ov_w; x--; ) 3681 for (int x = ov.w; x--; )
3833 { 3682 {
3834 text_t t = *t1; *t1++ = *t2; *t2++ = t; 3683 text_t t = *t1; *t1++ = *t2; *t2++ = t;
3835 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t)); 3684 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t));
3836 } 3685 }
3837 } 3686 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines