ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.457
Committed: Tue Jun 21 12:03:56 2016 UTC (7 years, 11 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.456: +1 -1 lines
Log Message:
24-bit direct color support (patch by Fengguang Wu)

Support directly setting RGB fg/bg colors via ISO-8613-3 24-bit
ANSI color escapes:

  ESC[38;2;<r>;<g>;<b>m Select RGB foreground color
  ESC[48;2;<r>;<g>;<b>m Select RGB background color

The killer applications for me are vim in tmux. It'll not only modernize
their look and feeling, but also bring more eye friendly color schemes.
Very helpful for long time programmers.

To avoid memory overheads and keep the patch non-intrusive, it takes the
approach to adapt the nearest color in an hidden 6x6x4 (88-color mode)
or 7x7x5 (256-color mode) color cube to the new 24-bit RGB color.

The pros/cons are:

+) least memory footprint (close to 0)
   comparing to konsole, gnome-terminal etc. real 24-bit arrays

+) exact colors and excellent user feelings
   comparing to xterm, mlterm, etc. approximating to 256 palette

+) usable in both the existing 88/256-color modes

   Most vim GUI color schemes show up the same as gvim in rxvt-unicode's
   88-color mode, not to mention the 256-color mode. Typical applications
   only use one or two dozens of colors at the same time.

-) may not be able to show 2+ close 24-bit colors

   RGB colors close to each other will likely fall into the same slot in
   the 6x6x4 or 7x7x5 color cube. If necessary, it could be improved
   effectively by implementing some collision avoidance logic, trying to
   find empty/eldest slot in the +1/-1 r/g/b indices (ie. 3-8 neighbors).

The CPU overheads of map_rgb24_color() look ignorable: I feel no
perceptible slow down when doing vim operations in 24-bit color mode.

A micro benchmark running a test script from [1]:

% time (for i in {1..100}; do 24-bit-color.sh; done)

vanilla rxvt-unicode
====================
  2.42s user 1.88s system 31% cpu 13.555 total
  2.59s user 1.74s system 31% cpu 13.615 total
  2.46s user 1.85s system 31% cpu 13.631 total

THIS PATCH (adapt hidden color cube to 24-bit)
==============================================
  2.33s user 1.97s system 31% cpu 13.598 total
  2.46s user 1.89s system 31% cpu 13.613 total
  2.51s user 1.82s system 31% cpu 13.556 total

https://github.com/spudowiar/rxvt-unicode (real 24-bit array)
=============================================================
  2.61s user 1.75s system 31% cpu 13.721 total
  2.48s user 1.82s system 31% cpu 13.566 total
  2.60s user 1.76s system 31% cpu 13.631 total

USE_256_COLORS is defined in all the above rxvt-unicode builds.

References:

[1] True Colour (16 million colours) support in various terminal
    applications and terminals
    https://gist.github.com/XVilka/8346728

[2] https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

File Contents

# User Rev Content
1 root 1.262 /*---------------------------------------------------------------------------*
2 pcg 1.71 * File: screen.C
3 pcg 1.1 *---------------------------------------------------------------------------*
4     *
5     * Copyright (c) 1997-2001 Geoff Wing <gcw@pobox.com>
6 root 1.376 * Copyright (c) 2003-2007 Marc Lehmann <schmorp@schmorp.de>
7 sf-exg 1.456 * Copyright (c) 2015 Emanuele Giaquinta <e.giaquinta@glauco.it>
8 pcg 1.1 *
9     * This program is free software; you can redistribute it and/or modify
10     * it under the terms of the GNU General Public License as published by
11 root 1.446 * the Free Software Foundation; either version 3 of the License, or
12 pcg 1.1 * (at your option) any later version.
13     *
14     * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18     *
19     * You should have received a copy of the GNU General Public License
20     * along with this program; if not, write to the Free Software
21     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22     *--------------------------------------------------------------------------*/
23 pcg 1.38
24 pcg 1.1 /*
25 pcg 1.38 * This file handles _all_ screen updates and selections
26 pcg 1.1 */
27    
28 pcg 1.4 #include "../config.h" /* NECESSARY */
29     #include "rxvt.h" /* NECESSARY */
30 root 1.204 #include "rxvtperl.h" /* NECESSARY */
31 pcg 1.1
32 root 1.78 #include <inttypes.h>
33 pcg 1.1
34 sf-exg 1.343 static inline void
35     fill_text (text_t *start, text_t value, int len)
36 pcg 1.1 {
37     while (len--)
38     *start++ = value;
39     }
40    
41     /* ------------------------------------------------------------------------- */
42 pcg 1.4 #define TABSIZE 8 /* default tab size */
43 pcg 1.1
44     /* ------------------------------------------------------------------------- *
45     * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
46     * ------------------------------------------------------------------------- */
47 pcg 1.21 #define ZERO_SCROLLBACK() \
48 root 1.268 if (option (Opt_scrollTtyOutput)) \
49 root 1.172 view_start = 0
50 pcg 1.21 #define CLEAR_SELECTION() \
51 root 1.77 selection.beg.row = selection.beg.col \
52 pcg 1.21 = selection.end.row = selection.end.col = 0
53 sf-exg 1.405 #define CLEAR_ALL_SELECTION() \
54     selection.beg.row = selection.beg.col \
55     = selection.mark.row = selection.mark.col \
56     = selection.end.row = selection.end.col = 0
57 pcg 1.1
58 root 1.77 #define ROW_AND_COL_IS_AFTER(A, B, C, D) \
59 pcg 1.1 (((A) > (C)) || (((A) == (C)) && ((B) > (D))))
60 root 1.77 #define ROW_AND_COL_IS_BEFORE(A, B, C, D) \
61 pcg 1.1 (((A) < (C)) || (((A) == (C)) && ((B) < (D))))
62 root 1.77 #define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D) \
63 pcg 1.1 (((A) == (C)) && ((B) > (D)))
64 root 1.77 #define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D) \
65 pcg 1.1 (((A) == (C)) && ((B) >= (D)))
66 root 1.77 #define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D) \
67 pcg 1.1 (((A) == (C)) && ((B) < (D)))
68 root 1.77 #define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D) \
69 pcg 1.1 (((A) == (C)) && ((B) <= (D)))
70    
71     /* these must be row_col_t */
72 root 1.77 #define ROWCOL_IS_AFTER(X, Y) \
73 pcg 1.30 ROW_AND_COL_IS_AFTER ((X).row, (X).col, (Y).row, (Y).col)
74 root 1.77 #define ROWCOL_IS_BEFORE(X, Y) \
75 pcg 1.30 ROW_AND_COL_IS_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
76 root 1.77 #define ROWCOL_IN_ROW_AFTER(X, Y) \
77 pcg 1.30 ROW_AND_COL_IN_ROW_AFTER ((X).row, (X).col, (Y).row, (Y).col)
78 root 1.77 #define ROWCOL_IN_ROW_BEFORE(X, Y) \
79 pcg 1.30 ROW_AND_COL_IN_ROW_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
80 root 1.77 #define ROWCOL_IN_ROW_AT_OR_AFTER(X, Y) \
81 pcg 1.30 ROW_AND_COL_IN_ROW_AT_OR_AFTER ((X).row, (X).col, (Y).row, (Y).col)
82 root 1.77 #define ROWCOL_IN_ROW_AT_OR_BEFORE(X, Y) \
83 pcg 1.30 ROW_AND_COL_IN_ROW_AT_OR_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
84 pcg 1.1
85     /*
86     * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
87     */
88 root 1.77 #define CLEAR_CHARS(x, y, num) \
89 root 1.299 if (mapped) \
90     XClearArea (dpy, vt, x, y, \
91 root 1.77 (unsigned int)Width2Pixel (num), \
92 pcg 1.30 (unsigned int)Height2Pixel (1), False)
93 pcg 1.4
94 pcg 1.1 /* ------------------------------------------------------------------------- *
95     * SCREEN `COMMON' ROUTINES *
96     * ------------------------------------------------------------------------- */
97 root 1.129
98 pcg 1.1 /* Fill part/all of a line with blanks. */
99     void
100 root 1.244 rxvt_term::scr_blank_line (line_t &l, unsigned int col, unsigned int width, rend_t efs) const NOTHROW
101 pcg 1.1 {
102 root 1.415 if (!l.valid ())
103 root 1.175 {
104 root 1.415 l.alloc ();
105 root 1.175 col = 0;
106     width = ncol;
107     }
108    
109 root 1.210 l.touch ();
110    
111 root 1.254 efs &= ~RS_baseattrMask; // remove italic etc. fontstyles
112 root 1.129 efs = SET_FONT (efs, FONTSET (efs)->find_font (' '));
113 pcg 1.1
114 root 1.172 text_t *et = l.t + col;
115     rend_t *er = l.r + col;
116    
117 pcg 1.8 while (width--)
118     {
119     *et++ = ' ';
120     *er++ = efs;
121     }
122 pcg 1.1 }
123    
124     /* ------------------------------------------------------------------------- */
125     /* Fill a full line with blanks - make sure it is allocated first */
126     void
127 root 1.244 rxvt_term::scr_blank_screen_mem (line_t &l, rend_t efs) const NOTHROW
128 pcg 1.1 {
129 root 1.172 scr_blank_line (l, 0, ncol, efs);
130 root 1.215
131     l.l = 0;
132     l.f = 0;
133 pcg 1.1 }
134    
135 root 1.313 // nuke a single wide character at the given column
136     void
137     rxvt_term::scr_kill_char (line_t &l, int col) const NOTHROW
138     {
139     // find begin
140     while (col > 0 && l.t[col] == NOCHAR)
141     col--;
142    
143     rend_t rend = l.r[col] & ~RS_baseattrMask;
144     rend = SET_FONT (rend, FONTSET (rend)->find_font (' '));
145    
146 root 1.352 l.touch ();
147    
148 root 1.316 // found start, nuke
149 root 1.313 do {
150     l.t[col] = ' ';
151     l.r[col] = rend;
152     col++;
153     } while (col < ncol && l.t[col] == NOCHAR);
154     }
155    
156 sf-exg 1.433 // set the rendition of a single wide character beginning at the given column
157     void
158     rxvt_term::scr_set_char_rend (line_t &l, int col, rend_t rend)
159     {
160     do {
161     l.r[col] = rend;
162     col++;
163     } while (col < ncol && l.t[col] == NOCHAR);
164     }
165    
166 pcg 1.1 /* ------------------------------------------------------------------------- *
167     * SCREEN INITIALISATION *
168     * ------------------------------------------------------------------------- */
169 root 1.186
170 pcg 1.1 void
171 root 1.417 rxvt_term::scr_alloc () NOTHROW
172 root 1.415 {
173     int tsize = sizeof (text_t) * ncol;
174     int rsize = sizeof (rend_t) * ncol;
175    
176     // we assume that rend_t size is a sufficient alignment
177 sf-exg 1.418 // factor for text_t and line_t values, and we only
178 root 1.415 // need to adjust tsize.
179     tsize = (tsize + sizeof (rend_t) - 1);
180     tsize -= tsize % sizeof (rend_t);
181    
182     int all_rows = total_rows + nrow + nrow;
183    
184     chunk_size = (sizeof (line_t) + rsize + tsize) * all_rows;
185 root 1.422 chunk = chunk_alloc (chunk_size, 0);
186 root 1.415
187     char *base = (char *)chunk + sizeof (line_t) * all_rows;
188    
189     for (int row = 0; row < all_rows; ++row)
190     {
191     line_t &l = ((line_t *)chunk) [row];
192    
193     l.t = (text_t *)base; base += tsize;
194     l.r = (rend_t *)base; base += rsize;
195     l.l = -1;
196     l.f = 0;
197     }
198    
199     drawn_buf = (line_t *)chunk;
200     swap_buf = drawn_buf + nrow;
201     row_buf = swap_buf + nrow;
202     }
203    
204 sf-exg 1.432 void
205     rxvt_term::copy_line (line_t &dst, line_t &src)
206     {
207     scr_blank_screen_mem (dst, DEFAULT_RSTYLE);
208     dst.l = min (src.l, ncol);
209     memcpy (dst.t, src.t, sizeof (text_t) * dst.l);
210     memcpy (dst.r, src.r, sizeof (rend_t) * dst.l);
211     dst.f = src.f;
212     }
213    
214 root 1.417 void ecb_cold
215 pcg 1.8 rxvt_term::scr_reset ()
216 pcg 1.1 {
217 sf-exg 1.379 #if ENABLE_OVERLAY
218     scr_overlay_off ();
219     #endif
220    
221 root 1.172 view_start = 0;
222 pcg 1.8 num_scr = 0;
223    
224 root 1.172 if (ncol == 0)
225     ncol = 80;
226 pcg 1.8
227 root 1.172 if (nrow == 0)
228     nrow = 24;
229 pcg 1.8
230     if (ncol == prev_ncol && nrow == prev_nrow)
231     return;
232    
233 root 1.89 // we need at least two lines for wrapping to work correctly
234 root 1.247 while (nrow + saveLines < 2)
235 root 1.89 {
236 root 1.186 //TODO//FIXME
237 root 1.172 saveLines++;
238 root 1.89 prev_nrow--;
239 root 1.228 top_row--;
240 root 1.89 }
241    
242 pcg 1.8 want_refresh = 1;
243    
244 root 1.172 int prev_total_rows = prev_nrow + saveLines;
245 root 1.175 total_rows = nrow + saveLines;
246 pcg 1.8
247     screen.tscroll = 0;
248     screen.bscroll = nrow - 1;
249    
250 root 1.415 void *prev_chunk = chunk;
251 sf-exg 1.423 size_t prev_chunk_size = chunk_size;
252 root 1.415 line_t *prev_drawn_buf = drawn_buf;
253     line_t *prev_swap_buf = swap_buf;
254     line_t *prev_row_buf = row_buf;
255    
256     scr_alloc ();
257    
258     if (!prev_row_buf)
259 pcg 1.8 {
260 root 1.247 top_row = 0;
261 root 1.172 term_start = 0;
262    
263 root 1.104 memset (charsets, 'B', sizeof (charsets));
264 pcg 1.8 rstyle = DEFAULT_RSTYLE;
265     screen.flags = Screen_DefaultFlags;
266     screen.cur.row = screen.cur.col = 0;
267     screen.charset = 0;
268     current_screen = PRIMARY;
269 pcg 1.21 scr_cursor (SAVE);
270 pcg 1.1
271     #if NSCREENS
272 pcg 1.8 swap.flags = Screen_DefaultFlags;
273     swap.cur.row = swap.cur.col = 0;
274     swap.charset = 0;
275     current_screen = SECONDARY;
276 pcg 1.21 scr_cursor (SAVE);
277 pcg 1.8 current_screen = PRIMARY;
278     #endif
279    
280     selection.text = NULL;
281     selection.len = 0;
282     selection.op = SELECTION_CLEAR;
283     selection.screen = PRIMARY;
284     selection.clicks = 0;
285 sf-exg 1.333 selection.clip_text = NULL;
286     selection.clip_len = 0;
287 pcg 1.8 }
288     else
289     {
290     /*
291     * add or delete rows as appropriate
292     */
293 root 1.172
294 sf-exg 1.435 int common_col = min (prev_ncol, ncol);
295    
296 root 1.186 for (int row = min (nrow, prev_nrow); row--; )
297 pcg 1.8 {
298 sf-exg 1.435 scr_blank_screen_mem (drawn_buf [row], DEFAULT_RSTYLE);
299     memcpy (drawn_buf [row].t, prev_drawn_buf [row].t, sizeof (text_t) * common_col);
300     memcpy (drawn_buf [row].r, prev_drawn_buf [row].r, sizeof (rend_t) * common_col);
301    
302 sf-exg 1.432 copy_line (swap_buf [row], prev_swap_buf [row]);
303 root 1.172 }
304    
305 root 1.187 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row
306 root 1.228 int pend = MOD (term_start + top_row , prev_total_rows);
307 root 1.186 int q = total_rows; // rewrapped row
308    
309 root 1.228 if (top_row)
310 root 1.186 {
311 root 1.247 // Re-wrap lines. This is rather ugly, possibly because I am too dumb
312 root 1.189 // to come up with a lean and mean algorithm.
313 root 1.325 // TODO: maybe optimise when width didn't change
314 root 1.189
315 root 1.190 row_col_t ocur = screen.cur;
316     ocur.row = MOD (term_start + ocur.row, prev_total_rows);
317    
318 root 1.192 do
319 root 1.189 {
320     p = MOD (p - 1, prev_total_rows);
321 root 1.415 assert (prev_row_buf [MOD (p, prev_total_rows)].t);
322 root 1.190 int plines = 1;
323 root 1.415 int llen = prev_row_buf [MOD (p, prev_total_rows)].l;
324 root 1.172
325 root 1.415 while (p != pend && prev_row_buf [MOD (p - 1, prev_total_rows)].is_longer ())
326 root 1.189 {
327     p = MOD (p - 1, prev_total_rows);
328 pcg 1.8
329 root 1.190 plines++;
330 root 1.189 llen += prev_ncol;
331     }
332 pcg 1.8
333 root 1.189 int qlines = max (0, (llen - 1) / ncol) + 1;
334 root 1.187
335 root 1.189 // drop partial lines completely
336     if (q < qlines)
337     break;
338 root 1.172
339 root 1.189 q -= qlines;
340 pcg 1.8
341 root 1.189 int lofs = 0;
342     line_t *qline;
343 pcg 1.8
344 root 1.189 // re-assemble the full line by destination lines
345     for (int qrow = q; qlines--; qrow++)
346     {
347     qline = row_buf + qrow;
348 root 1.415 qline->alloc (); // redundant with next line
349 root 1.210 qline->l = ncol;
350     qline->is_longer (1);
351 root 1.172
352 root 1.189 int qcol = 0;
353 root 1.172
354 root 1.239 // see below for cursor adjustment rationale
355     if (p == ocur.row)
356     screen.cur.row = q - (total_rows - nrow);
357 ayin 1.281
358 root 1.189 // fill a single destination line
359     while (lofs < llen && qcol < ncol)
360     {
361     int prow = lofs / prev_ncol;
362     int pcol = lofs % prev_ncol;
363 root 1.172
364 root 1.190 prow = MOD (p + prow, prev_total_rows);
365    
366 root 1.191 // we only adjust the cursor _row_ and put it into
367     // the topmost line of "long line" it was in, as
368     // this seems to upset applications/shells/readline
369     // least.
370 root 1.190 if (prow == ocur.row)
371 root 1.191 screen.cur.row = q - (total_rows - nrow);
372 root 1.190
373 root 1.415 line_t &pline = prev_row_buf [prow];
374 pcg 1.8
375 root 1.189 int len = min (min (prev_ncol - pcol, ncol - qcol), llen - lofs);
376 pcg 1.8
377 root 1.189 memcpy (qline->t + qcol, pline.t + pcol, len * sizeof (text_t));
378     memcpy (qline->r + qcol, pline.r + pcol, len * sizeof (rend_t));
379 root 1.172
380 root 1.189 lofs += len;
381     qcol += len;
382     }
383 root 1.187 }
384 root 1.189
385 root 1.196 qline->l = llen ? MOD (llen - 1, ncol) + 1 : 0;
386 root 1.210 qline->is_longer (0);
387 root 1.189 scr_blank_line (*qline, qline->l, ncol - qline->l, DEFAULT_RSTYLE);
388 root 1.187 }
389 root 1.192 while (p != pend && q > 0);
390 root 1.172
391 root 1.189 term_start = total_rows - nrow;
392 root 1.228 top_row = q - term_start;
393 ayin 1.281
394 root 1.189 // make sure all terminal lines exist
395 root 1.228 while (top_row > 0)
396     scr_blank_screen_mem (ROW (--top_row), DEFAULT_RSTYLE);
397 root 1.187 }
398 root 1.189 else
399     {
400     // if no scrollback exists (yet), wing, instead of wrap
401 ayin 1.281
402 root 1.189 for (int row = min (nrow, prev_nrow); row--; )
403     {
404 root 1.415 line_t &src = prev_row_buf [MOD (term_start + row, prev_total_rows)];
405     line_t &dst = row_buf [row];
406    
407 sf-exg 1.432 copy_line (dst, src);
408 root 1.189 }
409 root 1.172
410 root 1.189 for (int row = prev_nrow; row < nrow; row++)
411 root 1.415 scr_blank_screen_mem (row_buf [row], DEFAULT_RSTYLE);
412 root 1.172
413 root 1.189 term_start = 0;
414     }
415    
416     clamp_it (screen.cur.row, 0, nrow - 1);
417     clamp_it (screen.cur.col, 0, ncol - 1);
418 pcg 1.1 }
419    
420 root 1.415 for (int row = nrow; row--; )
421     {
422     if (!ROW (row).valid ()) scr_blank_screen_mem (ROW (row), DEFAULT_RSTYLE);
423     if (!swap_buf [row].valid ()) scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
424     if (!drawn_buf [row].valid ()) scr_blank_screen_mem (drawn_buf [row], DEFAULT_RSTYLE);
425     }
426    
427 sf-exg 1.423 chunk_free (prev_chunk, prev_chunk_size);
428 root 1.415
429 root 1.326 free (tabs);
430     tabs = (char *)rxvt_malloc (ncol);
431    
432 sf-exg 1.360 for (int col = ncol; col--; )
433 root 1.326 tabs [col] = col % TABSIZE == 0;
434    
435 sf-exg 1.405 CLEAR_ALL_SELECTION ();
436 root 1.241
437 pcg 1.8 prev_nrow = nrow;
438     prev_ncol = ncol;
439 pcg 1.1
440 pcg 1.8 tt_winch ();
441 root 1.204
442 root 1.211 HOOK_INVOKE ((this, HOOK_RESET, DT_END));
443 pcg 1.1 }
444    
445 root 1.417 void ecb_cold
446 root 1.244 rxvt_term::scr_release () NOTHROW
447 pcg 1.1 {
448 root 1.422 chunk_free (chunk, chunk_size);
449     chunk = 0;
450     row_buf = 0;
451    
452     free (tabs);
453     tabs = 0;
454 pcg 1.1 }
455    
456     /* ------------------------------------------------------------------------- */
457     /*
458 root 1.318 * Hard/Soft reset
459 pcg 1.1 */
460 root 1.417 void ecb_cold
461 root 1.247 rxvt_term::scr_poweron ()
462 pcg 1.1 {
463 pcg 1.21 scr_release ();
464 root 1.415
465 pcg 1.21 prev_nrow = prev_ncol = 0;
466 root 1.325 rvideo_mode = false;
467     scr_soft_reset ();
468 pcg 1.21 scr_reset ();
469 pcg 1.1
470 pcg 1.74 scr_clear (true);
471 root 1.235 scr_refresh ();
472 pcg 1.1 }
473    
474 root 1.417 void ecb_cold
475 root 1.413 rxvt_term::scr_soft_reset () NOTHROW
476 root 1.318 {
477     /* only affects modes, nothing drastic such as clearing the screen */
478     #if ENABLE_OVERLAY
479     scr_overlay_off ();
480     #endif
481    
482     if (current_screen != PRIMARY)
483     scr_swap_screen ();
484    
485     scr_scroll_region (0, MAX_ROWS - 1);
486     scr_rendition (0, ~RS_None);
487     scr_insert_mode (0);
488     }
489    
490 pcg 1.1 /* ------------------------------------------------------------------------- *
491     * PROCESS SCREEN COMMANDS *
492     * ------------------------------------------------------------------------- */
493     /*
494     * Save and Restore cursor
495     * XTERM_SEQ: Save cursor : ESC 7
496     * XTERM_SEQ: Restore cursor: ESC 8
497     */
498     void
499 root 1.244 rxvt_term::scr_cursor (cursor_mode mode) NOTHROW
500 pcg 1.1 {
501 pcg 1.66 screen_t *s;
502 pcg 1.1
503     #if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
504 pcg 1.25 if (current_screen == SECONDARY)
505 pcg 1.66 s = &swap;
506 pcg 1.25 else
507 pcg 1.1 #endif
508 pcg 1.66 s = &screen;
509    
510 pcg 1.25 switch (mode)
511     {
512     case SAVE:
513 root 1.129 s->s_cur.row = screen.cur.row;
514     s->s_cur.col = screen.cur.col;
515 pcg 1.21 s->s_rstyle = rstyle;
516 root 1.129 s->s_charset = screen.charset;
517     s->s_charset_char = charsets[screen.charset];
518 pcg 1.4 break;
519 pcg 1.71
520 pcg 1.25 case RESTORE:
521 pcg 1.21 want_refresh = 1;
522 root 1.129 screen.cur.row = s->s_cur.row;
523     screen.cur.col = s->s_cur.col;
524     screen.flags &= ~Screen_WrapNext;
525 pcg 1.21 rstyle = s->s_rstyle;
526 root 1.129 screen.charset = s->s_charset;
527     charsets[screen.charset] = s->s_charset_char;
528 pcg 1.21 set_font_style ();
529 pcg 1.4 break;
530 pcg 1.1 }
531 pcg 1.66
532 pcg 1.25 /* boundary check in case screen size changed between SAVE and RESTORE */
533 root 1.183 min_it (s->cur.row, nrow - 1);
534     min_it (s->cur.col, ncol - 1);
535 pcg 1.30 assert (s->cur.row >= 0);
536     assert (s->cur.col >= 0);
537 pcg 1.1 }
538    
539 root 1.247 void
540 root 1.413 rxvt_term::scr_swap_screen () NOTHROW
541 root 1.247 {
542 root 1.268 if (!option (Opt_secondaryScreen))
543 root 1.247 return;
544    
545     for (int i = prev_nrow; i--; )
546     ::swap (ROW(i), swap_buf [i]);
547    
548     ::swap (screen.cur, swap.cur);
549    
550     screen.cur.row = clamp (screen.cur.row, 0, prev_nrow - 1);
551     screen.cur.col = clamp (screen.cur.col, 0, prev_ncol - 1);
552     }
553    
554 pcg 1.1 /* ------------------------------------------------------------------------- */
555     /*
556     * Swap between primary and secondary screens
557     * XTERM_SEQ: Primary screen : ESC [ ? 4 7 h
558     * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
559     */
560 root 1.247 void
561     rxvt_term::scr_change_screen (int scrn)
562 pcg 1.1 {
563 root 1.247 if (scrn == current_screen)
564     return;
565    
566 pcg 1.25 want_refresh = 1;
567 root 1.172 view_start = 0;
568 pcg 1.1
569 sf-exg 1.407 /* check for boundary cross */
570     row_col_t pos;
571     pos.row = pos.col = 0;
572     if (ROWCOL_IS_BEFORE (selection.beg, pos)
573     && ROWCOL_IS_AFTER (selection.end, pos))
574     CLEAR_SELECTION ();
575 pcg 1.1
576 sf-exg 1.332 current_screen = scrn;
577 root 1.139
578 pcg 1.1 #if NSCREENS
579 root 1.268 if (option (Opt_secondaryScreen))
580 pcg 1.25 {
581 pcg 1.68 num_scr = 0;
582 root 1.139
583 root 1.247 scr_swap_screen ();
584 root 1.139
585 root 1.180 ::swap (screen.charset, swap.charset);
586 root 1.247 ::swap (screen.flags, swap.flags);
587 pcg 1.68 screen.flags |= Screen_VisibleCursor;
588 root 1.247 swap.flags |= Screen_VisibleCursor;
589 pcg 1.68 }
590     else
591 pcg 1.1 #endif
592 root 1.268 if (option (Opt_secondaryScroll))
593 root 1.176 scr_scroll_text (0, prev_nrow - 1, prev_nrow);
594 pcg 1.1 }
595    
596 root 1.104 // clear WrapNext indicator, solidifying position on next line
597     void
598 root 1.244 rxvt_term::scr_do_wrap () NOTHROW
599 root 1.104 {
600     if (!(screen.flags & Screen_WrapNext))
601     return;
602    
603     screen.flags &= ~Screen_WrapNext;
604    
605     screen.cur.col = 0;
606    
607     if (screen.cur.row == screen.bscroll)
608 root 1.176 scr_scroll_text (screen.tscroll, screen.bscroll, 1);
609 root 1.172 else if (screen.cur.row < nrow - 1)
610 root 1.104 screen.cur.row++;
611     }
612    
613 pcg 1.1 /* ------------------------------------------------------------------------- */
614     /*
615     * Change the colour for following text
616     */
617     void
618 root 1.244 rxvt_term::scr_color (unsigned int color, int fgbg) NOTHROW
619 pcg 1.1 {
620 sf-exg 1.457 if (!IN_RANGE_INC (color, minCOLOR, maxTermCOLOR24))
621 root 1.129 color = fgbg;
622    
623 pcg 1.25 if (fgbg == Color_fg)
624 pcg 1.30 rstyle = SET_FGCOLOR (rstyle, color);
625 pcg 1.25 else
626 pcg 1.30 rstyle = SET_BGCOLOR (rstyle, color);
627 pcg 1.1 }
628    
629     /* ------------------------------------------------------------------------- */
630     /*
631     * Change the rendition style for following text
632     */
633     void
634 root 1.244 rxvt_term::scr_rendition (int set, int style) NOTHROW
635 root 1.289 {
636     if (set)
637     rstyle |= style;
638     else if (style == ~RS_None)
639     rstyle = DEFAULT_RSTYLE;
640     else
641     rstyle &= ~style;
642     }
643 pcg 1.1
644     /* ------------------------------------------------------------------------- */
645     /*
646     * Scroll text between <row1> and <row2> inclusive, by <count> lines
647     * count positive ==> scroll up
648     * count negative ==> scroll down
649     */
650 root 1.417 int ecb_hot
651 root 1.244 rxvt_term::scr_scroll_text (int row1, int row2, int count) NOTHROW
652 pcg 1.1 {
653 pcg 1.8 if (count == 0 || (row1 > row2))
654     return 0;
655    
656     want_refresh = 1;
657 root 1.176 num_scr += count;
658 pcg 1.8
659 root 1.177 if (count > 0
660     && row1 == 0
661 root 1.268 && (current_screen == PRIMARY || option (Opt_secondaryScroll)))
662 pcg 1.8 {
663 root 1.388 min_it (count, total_rows - (nrow - (row2 + 1)));
664 root 1.386
665 root 1.228 top_row = max (top_row - count, -saveLines);
666 root 1.204
667 root 1.236 // sever bottommost line
668 root 1.227 {
669 root 1.391 line_t &l = ROW(row2);
670 root 1.236 l.is_longer (0);
671 root 1.227 l.touch ();
672     }
673    
674 root 1.388 // scroll everything up 'count' lines
675     term_start = (term_start + count) % total_rows;
676    
677     // now copy lines below the scroll region bottom to the
678     // bottom of the screen again, so they look as if they
679     // hadn't moved.
680     for (int i = nrow; --i > row2; )
681     {
682     line_t &l1 = ROW(i - count);
683     line_t &l2 = ROW(i);
684    
685     ::swap (l1, l2);
686     l2.touch ();
687     }
688    
689 root 1.236 // erase newly scrolled-in lines
690     for (int i = count; i--; )
691 root 1.254 {
692 root 1.388 line_t &l = ROW(row2 - i);
693 root 1.254
694 root 1.386 // optimise if already cleared, can be significant on slow machines
695 root 1.254 // could be rolled into scr_blank_screen_mem
696 root 1.259 if (l.r && l.l < ncol - 1 && !((l.r[l.l + 1] ^ rstyle) & (RS_fgMask | RS_bgMask)))
697 root 1.254 {
698     scr_blank_line (l, 0, l.l, rstyle);
699     l.l = 0;
700     l.f = 0;
701     }
702     else
703     scr_blank_screen_mem (l, rstyle);
704     }
705 root 1.227
706 sf-exg 1.400 // move and/or clear selection, if any
707 sf-exg 1.401 if (selection.op && current_screen == selection.screen
708 root 1.402 && selection.beg.row <= row2)
709 sf-exg 1.400 {
710     selection.beg.row -= count;
711     selection.end.row -= count;
712     selection.mark.row -= count;
713    
714     selection_check (0);
715     }
716    
717 root 1.227 // finally move the view window, if desired
718 root 1.268 if (option (Opt_scrollWithBuffer)
719 root 1.172 && view_start != 0
720 root 1.228 && view_start != -saveLines)
721 root 1.440 scr_page (count);
722 root 1.234
723     if (SHOULD_INVOKE (HOOK_SCROLL_BACK))
724     HOOK_INVOKE ((this, HOOK_SCROLL_BACK, DT_INT, count, DT_INT, top_row, DT_END));
725 pcg 1.8 }
726 root 1.175 else
727     {
728 sf-exg 1.400 if (selection.op && current_screen == selection.screen)
729     {
730     if ((selection.beg.row < row1 && selection.end.row > row1)
731     || (selection.beg.row < row2 && selection.end.row > row2)
732     || (selection.beg.row - count < row1 && selection.beg.row >= row1)
733     || (selection.beg.row - count > row2 && selection.beg.row <= row2)
734     || (selection.end.row - count < row1 && selection.end.row >= row1)
735     || (selection.end.row - count > row2 && selection.end.row <= row2))
736     {
737 sf-exg 1.405 CLEAR_ALL_SELECTION ();
738     selection.op = SELECTION_CLEAR;
739 sf-exg 1.400 }
740     else if (selection.end.row >= row1 && selection.end.row <= row2)
741     {
742     /* move selected region too */
743     selection.beg.row -= count;
744     selection.end.row -= count;
745     selection.mark.row -= count;
746    
747     selection_check (0);
748     }
749     }
750    
751 root 1.176 // use a simple and robust scrolling algorithm, this
752     // part of scr_scroll_text is not time-critical.
753 pcg 1.1
754 root 1.389 // sever line above scroll region
755     if (row1)
756     {
757     line_t &l = ROW(row1 - 1);
758     l.is_longer (0);
759     l.touch ();
760     }
761    
762 root 1.386 int rows = row2 - row1 + 1;
763    
764     min_it (count, rows);
765    
766 sf-exg 1.390 line_t *temp_buf = rxvt_temp_buf<line_t> (rows);
767 root 1.217
768 root 1.176 for (int row = 0; row < rows; row++)
769 root 1.175 {
770 root 1.186 temp_buf [row] = ROW(row1 + (row + count + rows) % rows);
771 pcg 1.74
772 root 1.176 if (!IN_RANGE_EXC (row + count, 0, rows))
773 root 1.186 scr_blank_screen_mem (temp_buf [row], rstyle);
774 root 1.175 }
775 root 1.172
776 root 1.176 for (int row = 0; row < rows; row++)
777 root 1.186 ROW(row1 + row) = temp_buf [row];
778 root 1.389
779     // sever bottommost line
780     {
781 root 1.392 line_t &l = ROW(row2);
782 root 1.389 l.is_longer (0);
783     l.touch ();
784     }
785 root 1.175 }
786 pcg 1.1
787 pcg 1.8 return count;
788 pcg 1.1 }
789    
790     /* ------------------------------------------------------------------------- */
791     /*
792     * Add text given in <str> of length <len> to screen struct
793     */
794 root 1.417 void ecb_hot
795 root 1.244 rxvt_term::scr_add_lines (const wchar_t *str, int len, int minlines) NOTHROW
796 pcg 1.1 {
797 root 1.165 if (len <= 0) /* sanity */
798     return;
799    
800 sf-exg 1.403 bool checksel;
801 pcg 1.59 unicode_t c;
802 root 1.210 int ncol = this->ncol;
803 root 1.213 const wchar_t *strend = str + len;
804 pcg 1.1
805 pcg 1.25 want_refresh = 1;
806 root 1.104 ZERO_SCROLLBACK ();
807 pcg 1.1
808 root 1.213 if (minlines > 0)
809 pcg 1.25 {
810 root 1.213 minlines += screen.cur.row - screen.bscroll;
811 root 1.248 min_it (minlines, screen.cur.row - top_row);
812 root 1.209
813 root 1.213 if (minlines > 0
814 root 1.186 && screen.tscroll == 0
815 root 1.210 && screen.bscroll == nrow - 1)
816 pcg 1.25 {
817     /* _at least_ this many lines need to be scrolled */
818 root 1.213 scr_scroll_text (screen.tscroll, screen.bscroll, minlines);
819     screen.cur.row -= minlines;
820 pcg 1.4 }
821 pcg 1.1 }
822 root 1.89
823 root 1.210 assert (screen.cur.col < ncol);
824 root 1.186 assert (screen.cur.row < nrow
825 root 1.228 && screen.cur.row >= top_row);
826 root 1.193 int row = screen.cur.row;
827 pcg 1.25
828 pcg 1.66 checksel = selection.op && current_screen == selection.screen ? 1 : 0;
829 pcg 1.25
830 root 1.175 line_t *line = &ROW(row);
831 pcg 1.25
832 root 1.165 while (str < strend)
833 pcg 1.25 {
834 root 1.213 c = (unicode_t)*str++; // convert to rxvt-unicodes representation
835 pcg 1.66
836 sf-exg 1.384 if (ecb_unlikely (c < 0x20))
837 root 1.165 if (c == C0_LF)
838 root 1.195 {
839 root 1.210 max_it (line->l, screen.cur.col);
840 root 1.165
841     screen.flags &= ~Screen_WrapNext;
842    
843     if (screen.cur.row == screen.bscroll)
844 root 1.176 scr_scroll_text (screen.tscroll, screen.bscroll, 1);
845 root 1.172 else if (screen.cur.row < (nrow - 1))
846 root 1.175 row = ++screen.cur.row;
847 root 1.165
848 root 1.175 line = &ROW(row); /* _must_ refresh */
849 root 1.165 continue;
850     }
851     else if (c == C0_CR)
852 pcg 1.66 {
853 root 1.210 max_it (line->l, screen.cur.col);
854 pcg 1.66
855 root 1.165 screen.flags &= ~Screen_WrapNext;
856     screen.cur.col = 0;
857     continue;
858     }
859     else if (c == C0_HT)
860     {
861     scr_tab (1, true);
862     continue;
863 pcg 1.66 }
864 pcg 1.4
865 sf-exg 1.384 if (ecb_unlikely (
866 root 1.309 checksel /* see if we're writing within selection */
867     && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
868     && ROWCOL_IS_BEFORE (screen.cur, selection.end)
869     ))
870 pcg 1.25 {
871     checksel = 0;
872 root 1.104 /*
873     * If we wrote anywhere in the selected area, kill the selection
874     * XXX: should we kill the mark too? Possibly, but maybe that
875     * should be a similar check.
876     */
877     CLEAR_SELECTION ();
878 pcg 1.4 }
879 pcg 1.54
880 sf-exg 1.384 if (ecb_unlikely (screen.flags & Screen_WrapNext))
881 pcg 1.25 {
882 root 1.236 scr_do_wrap ();
883 ayin 1.281
884 root 1.236 line->l = ncol;
885 root 1.210 line->is_longer (1);
886 root 1.104
887 root 1.175 row = screen.cur.row;
888     line = &ROW(row); /* _must_ refresh */
889 pcg 1.4 }
890 pcg 1.54
891 root 1.165 // some utf-8 decoders "decode" surrogate characters: let's fix this.
892 sf-exg 1.384 if (ecb_unlikely (IN_RANGE_INC (c, 0xd800, 0xdfff)))
893 root 1.165 c = 0xfffd;
894    
895 root 1.249 // rely on wcwidth to tell us the character width, do wcwidth before
896     // further replacements, as wcwidth might return -1 for the line
897     // drawing characters below as they might be invalid in the current
898 root 1.165 // locale.
899 root 1.249 int width = WCWIDTH (c);
900 pcg 1.54
901 sf-exg 1.384 if (ecb_unlikely (charsets [screen.charset] == '0')) // DEC SPECIAL
902 pcg 1.66 {
903     // vt100 special graphics and line drawing
904 root 1.129 // 5f-7e standard vt100
905     // 40-5e rxvt extension for extra curses acs chars
906 root 1.165 static uint16_t vt100_0[62] = { // 41 .. 7e
907     0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603, // 41-47 hi mr. snowman!
908     0, 0, 0, 0, 0, 0, 0, 0, // 48-4f
909     0, 0, 0, 0, 0, 0, 0, 0, // 50-57
910     0, 0, 0, 0, 0, 0, 0, 0x0020, // 58-5f
911 root 1.129 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, // 60-67
912     0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, // 68-6f
913     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, // 70-77
914     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
915 pcg 1.66 };
916    
917 root 1.165 if (c >= 0x41 && c <= 0x7e && vt100_0[c - 0x41])
918 pcg 1.66 {
919 root 1.165 c = vt100_0[c - 0x41];
920     width = 1; // vt100 line drawing characters are always single-width
921 pcg 1.66 }
922     }
923 pcg 1.1
924 sf-exg 1.384 if (ecb_unlikely (screen.flags & Screen_Insert))
925 root 1.143 scr_insdel_chars (width, INSERT);
926    
927 pcg 1.74 if (width != 0)
928 pcg 1.43 {
929 root 1.104 #if !UNICODE_3
930 pcg 1.54 // trim characters we can't store directly :(
931     if (c >= 0x10000)
932 root 1.104 # if ENABLE_COMBINING
933 pcg 1.54 c = rxvt_composite.compose (c); // map to lower 16 bits
934 root 1.104 # else
935     c = 0xfffd;
936     # endif
937 pcg 1.54 #endif
938 root 1.129
939     rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
940 pcg 1.54
941 root 1.165 // if the character doesn't fit into the remaining columns...
942 sf-exg 1.384 if (ecb_unlikely (screen.cur.col > ncol - width && ncol >= width))
943 root 1.165 {
944 sf-exg 1.348 if (screen.flags & Screen_Autowrap)
945     {
946     // ... artificially enlargen the previous one
947     c = NOCHAR;
948     // and try the same character next loop iteration
949     --str;
950     }
951     else
952     screen.cur.col = ncol - width;
953 root 1.165 }
954    
955 sf-exg 1.351 // nuke the character at this position, if required
956 sf-exg 1.355 // due to wonderful coincidences everywhere else in this loop
957 root 1.353 // we never have to check for overwriting a wide char itself,
958 root 1.354 // only its tail.
959 sf-exg 1.384 if (ecb_unlikely (line->t[screen.cur.col] == NOCHAR))
960 sf-exg 1.351 scr_kill_char (*line, screen.cur.col);
961    
962 root 1.210 line->touch ();
963    
964 pcg 1.43 do
965     {
966 root 1.172 line->t[screen.cur.col] = c;
967     line->r[screen.cur.col] = rend;
968 pcg 1.43
969 sf-exg 1.384 if (ecb_likely (screen.cur.col < ncol - 1))
970 pcg 1.43 screen.cur.col++;
971     else
972     {
973 root 1.210 line->l = ncol;
974 pcg 1.43 if (screen.flags & Screen_Autowrap)
975     screen.flags |= Screen_WrapNext;
976 root 1.352
977     goto end_of_line;
978 pcg 1.43 }
979 pcg 1.1
980 pcg 1.43 c = NOCHAR;
981     }
982 sf-exg 1.384 while (ecb_unlikely (--width > 0));
983 pcg 1.1
984 pcg 1.43 // pad with spaces when overwriting wide character with smaller one
985 sf-exg 1.384 for (int c = screen.cur.col; ecb_unlikely (c < ncol && line->t[c] == NOCHAR); c++)
986 root 1.210 {
987 root 1.352 line->t[c] = ' ';
988     line->r[c] = rend;
989     }
990 root 1.210
991 root 1.352 end_of_line:
992     ;
993 pcg 1.43 }
994 root 1.309 #if ENABLE_COMBINING
995 root 1.165 else // width == 0
996 pcg 1.54 {
997 root 1.309 if (c != 0xfeff) // ignore BOM
998     {
999     // handle combining characters
1000     // we just tag the accent on the previous on-screen character.
1001     // this is arguably not correct, but also arguably not wrong.
1002     // we don't handle double-width characters nicely yet.
1003     line_t *linep;
1004     text_t *tp;
1005     rend_t *rp;
1006 pcg 1.54
1007 root 1.309 if (screen.cur.col > 0)
1008     {
1009     linep = line;
1010     tp = line->t + screen.cur.col - 1;
1011     rp = line->r + screen.cur.col - 1;
1012     }
1013     else if (screen.cur.row > 0
1014     && ROW(screen.cur.row - 1).is_longer ())
1015     {
1016     linep = &ROW(screen.cur.row - 1);
1017 sf-exg 1.455 tp = linep->t + ncol - 1;
1018     rp = linep->r + ncol - 1;
1019 root 1.309 }
1020     else
1021     continue;
1022 pcg 1.54
1023 root 1.309 linep->touch ();
1024 root 1.210
1025 root 1.309 while (*tp == NOCHAR && tp > linep->t)
1026     tp--, rp--;
1027 root 1.210
1028 root 1.309 // first try to find a precomposed character
1029     unicode_t n = rxvt_compose (*tp, c);
1030     if (n == NOCHAR)
1031     n = rxvt_composite.compose (*tp, c);
1032 pcg 1.54
1033 root 1.309 *tp = n;
1034     *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
1035     }
1036     }
1037 pcg 1.54 #endif
1038 pcg 1.1 }
1039 pcg 1.17
1040 root 1.210 max_it (line->l, screen.cur.col);
1041 pcg 1.1
1042 pcg 1.30 assert (screen.cur.row >= 0);
1043 pcg 1.1 }
1044    
1045     /* ------------------------------------------------------------------------- */
1046     /*
1047     * Process Backspace. Move back the cursor back a position, wrap if have to
1048     * XTERM_SEQ: CTRL-H
1049     */
1050     void
1051 root 1.244 rxvt_term::scr_backspace () NOTHROW
1052 pcg 1.1 {
1053 pcg 1.25 if (screen.cur.col == 0)
1054     {
1055     if (screen.cur.row > 0)
1056     {
1057 pcg 1.1 #ifdef TERMCAP_HAS_BW
1058 root 1.172 screen.cur.col = ncol - 1;
1059 root 1.297 --screen.cur.row;
1060    
1061 root 1.296 want_refresh = 1;
1062 pcg 1.1 #endif
1063 pcg 1.4 }
1064 pcg 1.25 }
1065 root 1.349 else if (screen.flags & Screen_WrapNext)
1066     screen.flags &= ~Screen_WrapNext;
1067 root 1.294 else
1068 pcg 1.25 scr_gotorc (0, -1, RELATIVE);
1069 pcg 1.1 }
1070    
1071     /* ------------------------------------------------------------------------- */
1072     /*
1073     * Process Horizontal Tab
1074     * count: +ve = forward; -ve = backwards
1075     * XTERM_SEQ: CTRL-I
1076     */
1077     void
1078 root 1.244 rxvt_term::scr_tab (int count, bool ht) NOTHROW
1079 pcg 1.1 {
1080 pcg 1.66 int i, x;
1081 pcg 1.1
1082 pcg 1.25 want_refresh = 1;
1083     i = x = screen.cur.col;
1084 pcg 1.66
1085 pcg 1.25 if (count == 0)
1086     return;
1087     else if (count > 0)
1088     {
1089 root 1.193 line_t &l = ROW(screen.cur.row);
1090 root 1.172 rend_t base_rend = l.r[i];
1091     ht &= l.t[i] == ' ';
1092 root 1.129
1093 root 1.172 for (; ++i < ncol; )
1094 pcg 1.25 if (tabs[i])
1095     {
1096     x = i;
1097 root 1.210
1098 pcg 1.25 if (!--count)
1099     break;
1100     }
1101 ayin 1.281 else
1102 root 1.172 ht &= l.t[i] == ' '
1103     && RS_SAME (l.r[i], base_rend);
1104 pcg 1.66
1105 pcg 1.25 if (count)
1106 root 1.172 x = ncol - 1;
1107 root 1.129
1108     // store horizontal tab commands as characters inside the text
1109     // buffer so they can be selected and pasted.
1110 root 1.268 if (ht && option (Opt_pastableTabs))
1111 root 1.129 {
1112     base_rend = SET_FONT (base_rend, 0);
1113    
1114 root 1.210 l.touch (x);
1115 root 1.129
1116     i = screen.cur.col;
1117    
1118 root 1.172 l.t[i] = '\t';
1119     l.r[i] = base_rend;
1120 root 1.129
1121     while (++i < x)
1122     {
1123 root 1.172 l.t[i] = NOCHAR;
1124     l.r[i] = base_rend;
1125 root 1.129 }
1126     }
1127 pcg 1.25 }
1128     else /* if (count < 0) */
1129     {
1130     for (; --i >= 0; )
1131     if (tabs[i])
1132     {
1133     x = i;
1134     if (!++count)
1135     break;
1136     }
1137 pcg 1.66
1138 pcg 1.25 if (count)
1139     x = 0;
1140 pcg 1.1 }
1141 pcg 1.66
1142 pcg 1.25 if (x != screen.cur.col)
1143     scr_gotorc (0, x, R_RELATIVE);
1144 pcg 1.1 }
1145    
1146     /* ------------------------------------------------------------------------- */
1147     /*
1148     * Process DEC Back Index
1149     * XTERM_SEQ: ESC 6
1150     * Move cursor left in row. If we're at the left boundary, shift everything
1151     * in that row right. Clear left column.
1152     */
1153 root 1.256 #if !ENABLE_MINIMAL
1154 root 1.417 void ecb_cold
1155 root 1.244 rxvt_term::scr_backindex () NOTHROW
1156 pcg 1.1 {
1157 pcg 1.25 if (screen.cur.col > 0)
1158     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
1159     else
1160 root 1.175 scr_insdel_chars (1, INSERT);
1161 pcg 1.1 }
1162     #endif
1163     /* ------------------------------------------------------------------------- */
1164     /*
1165     * Process DEC Forward Index
1166     * XTERM_SEQ: ESC 9
1167     * Move cursor right in row. If we're at the right boundary, shift everything
1168     * in that row left. Clear right column.
1169     */
1170 root 1.256 #if !ENABLE_MINIMAL
1171 root 1.417 void ecb_cold
1172 root 1.244 rxvt_term::scr_forwardindex () NOTHROW
1173 pcg 1.1 {
1174 root 1.172 if (screen.cur.col < ncol - 1)
1175 pcg 1.25 scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
1176     else
1177     {
1178 root 1.210 line_t &l = ROW(screen.cur.row);
1179    
1180     l.touch ();
1181     l.is_longer (0);
1182 root 1.104
1183 pcg 1.25 scr_gotorc (0, 0, R_RELATIVE);
1184     scr_insdel_chars (1, DELETE);
1185 root 1.172 scr_gotorc (0, ncol - 1, R_RELATIVE);
1186 pcg 1.1 }
1187     }
1188     #endif
1189    
1190     /* ------------------------------------------------------------------------- */
1191     /*
1192     * Goto Row/Column
1193     */
1194     void
1195 root 1.244 rxvt_term::scr_gotorc (int row, int col, int relative) NOTHROW
1196 pcg 1.1 {
1197 pcg 1.25 want_refresh = 1;
1198 pcg 1.30 ZERO_SCROLLBACK ();
1199 pcg 1.1
1200 pcg 1.71 screen.cur.col = relative & C_RELATIVE ? screen.cur.col + col : col;
1201 root 1.186 clamp_it (screen.cur.col, 0, ncol - 1);
1202 pcg 1.25
1203     screen.flags &= ~Screen_WrapNext;
1204 root 1.104
1205 pcg 1.25 if (relative & R_RELATIVE)
1206     {
1207     if (row > 0)
1208     {
1209     if (screen.cur.row <= screen.bscroll
1210     && (screen.cur.row + row) > screen.bscroll)
1211     screen.cur.row = screen.bscroll;
1212     else
1213     screen.cur.row += row;
1214     }
1215     else if (row < 0)
1216     {
1217     if (screen.cur.row >= screen.tscroll
1218     && (screen.cur.row + row) < screen.tscroll)
1219     screen.cur.row = screen.tscroll;
1220     else
1221     screen.cur.row += row;
1222     }
1223     }
1224     else
1225     {
1226     if (screen.flags & Screen_Relative)
1227 ayin 1.284 {
1228     /* relative origin mode */
1229 pcg 1.25 screen.cur.row = row + screen.tscroll;
1230 root 1.183 min_it (screen.cur.row, screen.bscroll);
1231 pcg 1.4 }
1232 pcg 1.25 else
1233     screen.cur.row = row;
1234 pcg 1.1 }
1235 root 1.104
1236 root 1.186 clamp_it (screen.cur.row, 0, nrow - 1);
1237 pcg 1.1 }
1238    
1239     /* ------------------------------------------------------------------------- */
1240     /*
1241 root 1.104 * direction should be UP or DN
1242 pcg 1.1 */
1243     void
1244 root 1.244 rxvt_term::scr_index (enum page_dirn direction) NOTHROW
1245 pcg 1.1 {
1246 pcg 1.25 want_refresh = 1;
1247 root 1.104 ZERO_SCROLLBACK ();
1248    
1249     screen.flags &= ~Screen_WrapNext;
1250 pcg 1.1
1251 pcg 1.25 if ((screen.cur.row == screen.bscroll && direction == UP)
1252     || (screen.cur.row == screen.tscroll && direction == DN))
1253 sf-exg 1.441 scr_scroll_text (screen.tscroll, screen.bscroll, direction);
1254 pcg 1.25 else
1255 sf-exg 1.441 screen.cur.row += direction;
1256 root 1.104
1257 root 1.186 clamp_it (screen.cur.row, 0, nrow - 1);
1258 pcg 1.25 selection_check (0);
1259 pcg 1.1 }
1260    
1261     /* ------------------------------------------------------------------------- */
1262     /*
1263     * Erase part or whole of a line
1264     * XTERM_SEQ: Clear line to right: ESC [ 0 K
1265     * XTERM_SEQ: Clear line to left : ESC [ 1 K
1266     * XTERM_SEQ: Clear whole line : ESC [ 2 K
1267 root 1.306 * extension: clear to right unless wrapped: ESC [ 3 K
1268 pcg 1.1 */
1269     void
1270 root 1.244 rxvt_term::scr_erase_line (int mode) NOTHROW
1271 pcg 1.1 {
1272 root 1.193 unsigned int col, num;
1273 pcg 1.1
1274 pcg 1.21 want_refresh = 1;
1275     ZERO_SCROLLBACK ();
1276 pcg 1.1
1277 pcg 1.21 selection_check (1);
1278 pcg 1.1
1279 root 1.193 line_t &line = ROW(screen.cur.row);
1280 root 1.172
1281 root 1.210 line.touch ();
1282     line.is_longer (0);
1283    
1284 pcg 1.8 switch (mode)
1285     {
1286 root 1.306 case 3:
1287     if (screen.flags & Screen_WrapNext)
1288     return;
1289    
1290     /* fall through */
1291    
1292 pcg 1.8 case 0: /* erase to end of line */
1293 pcg 1.21 col = screen.cur.col;
1294 root 1.172 num = ncol - col;
1295 root 1.193 min_it (line.l, col);
1296 root 1.306
1297 pcg 1.30 if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)
1298     || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur))
1299     CLEAR_SELECTION ();
1300 pcg 1.4 break;
1301 root 1.306
1302 pcg 1.8 case 1: /* erase to beginning of line */
1303 pcg 1.4 col = 0;
1304 pcg 1.21 num = screen.cur.col + 1;
1305 root 1.306
1306 pcg 1.30 if (ROWCOL_IN_ROW_AT_OR_BEFORE (selection.beg, screen.cur)
1307     || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur))
1308     CLEAR_SELECTION ();
1309 pcg 1.4 break;
1310 root 1.306
1311 pcg 1.8 case 2: /* erase whole line */
1312 pcg 1.4 col = 0;
1313 root 1.172 num = ncol;
1314 root 1.193 line.l = 0;
1315 pcg 1.21 if (selection.beg.row <= screen.cur.row
1316     && selection.end.row >= screen.cur.row)
1317 pcg 1.30 CLEAR_SELECTION ();
1318 pcg 1.4 break;
1319 pcg 1.8 default:
1320 pcg 1.4 return;
1321 pcg 1.1 }
1322 pcg 1.8
1323 root 1.193 scr_blank_line (line, col, num, rstyle);
1324 pcg 1.1 }
1325    
1326     /* ------------------------------------------------------------------------- */
1327     /*
1328 sf-exg 1.408 * Erase part or whole of the screen
1329 pcg 1.1 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1330     * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1331     * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1332     */
1333     void
1334 root 1.244 rxvt_term::scr_erase_screen (int mode) NOTHROW
1335 pcg 1.1 {
1336 pcg 1.66 int num;
1337 root 1.176 int32_t row;
1338 pcg 1.66 rend_t ren;
1339     XGCValues gcvalue;
1340 pcg 1.25
1341     want_refresh = 1;
1342     ZERO_SCROLLBACK ();
1343 root 1.104
1344 pcg 1.25 switch (mode)
1345     {
1346     case 0: /* erase to end of screen */
1347 pcg 1.21 scr_erase_line (0);
1348 pcg 1.11 row = screen.cur.row + 1; /* possible OOB */
1349 root 1.172 num = nrow - row;
1350 pcg 1.4 break;
1351 pcg 1.25 case 1: /* erase to beginning of screen */
1352 pcg 1.21 scr_erase_line (1);
1353 pcg 1.4 row = 0;
1354 pcg 1.11 num = screen.cur.row;
1355 pcg 1.4 break;
1356 pcg 1.25 case 2: /* erase whole screen */
1357 pcg 1.4 row = 0;
1358 root 1.172 num = nrow;
1359 pcg 1.4 break;
1360 pcg 1.25 default:
1361 pcg 1.4 return;
1362 pcg 1.1 }
1363 pcg 1.66
1364 pcg 1.25 if (selection.op && current_screen == selection.screen
1365     && ((selection.beg.row >= row && selection.beg.row <= row + num)
1366     || (selection.end.row >= row
1367     && selection.end.row <= row + num)))
1368     CLEAR_SELECTION ();
1369 pcg 1.66
1370 root 1.172 if (row >= nrow) /* Out Of Bounds */
1371 pcg 1.25 return;
1372 pcg 1.66
1373 root 1.186 min_it (num, nrow - row);
1374 pcg 1.66
1375 root 1.342 if (rstyle & (RS_Blink | RS_RVid | RS_Uline))
1376 pcg 1.25 ren = (rend_t) ~RS_None;
1377 pcg 1.30 else if (GET_BASEBG (rstyle) == Color_bg)
1378 pcg 1.25 {
1379     ren = DEFAULT_RSTYLE;
1380 root 1.307
1381 sf-exg 1.347 if (mapped)
1382 root 1.307 XClearArea (dpy, vt, 0,
1383 sf-exg 1.411 Row2Pixel (row - view_start), (unsigned int)vt_width,
1384 root 1.307 (unsigned int)Height2Pixel (num), False);
1385 pcg 1.25 }
1386     else
1387     {
1388 root 1.139 ren = rstyle & (RS_fgMask | RS_bgMask);
1389 root 1.307
1390 sf-exg 1.347 if (mapped)
1391 root 1.323 {
1392     gcvalue.foreground = pix_colors[bgcolor_of (rstyle)];
1393     XChangeGC (dpy, gc, GCForeground, &gcvalue);
1394     XFillRectangle (dpy, vt, gc,
1395     0, Row2Pixel (row - view_start),
1396 sf-exg 1.411 (unsigned int)vt_width,
1397 root 1.323 (unsigned int)Height2Pixel (num));
1398     gcvalue.foreground = pix_colors[Color_fg];
1399     XChangeGC (dpy, gc, GCForeground, &gcvalue);
1400     }
1401 pcg 1.1 }
1402 pcg 1.66
1403 pcg 1.25 for (; num--; row++)
1404     {
1405 root 1.215 scr_blank_screen_mem (ROW(row), rstyle);
1406 root 1.324
1407 sf-exg 1.347 if (row - view_start < nrow)
1408     scr_blank_line (drawn_buf [row - view_start], 0, ncol, ren);
1409 pcg 1.1 }
1410     }
1411    
1412 root 1.256 #if !ENABLE_MINIMAL
1413 root 1.159 void
1414 root 1.244 rxvt_term::scr_erase_savelines () NOTHROW
1415 root 1.159 {
1416     want_refresh = 1;
1417     ZERO_SCROLLBACK ();
1418    
1419 root 1.228 top_row = 0;
1420 root 1.159 }
1421 root 1.160 #endif
1422 root 1.159
1423 pcg 1.1 /* ------------------------------------------------------------------------- */
1424     /*
1425     * Fill the screen with `E's
1426     * XTERM_SEQ: Screen Alignment Test: ESC # 8
1427     */
1428 root 1.417 void ecb_cold
1429 root 1.244 rxvt_term::scr_E () NOTHROW
1430 pcg 1.1 {
1431 root 1.176 rend_t fs;
1432 pcg 1.1
1433 pcg 1.25 want_refresh = 1;
1434 root 1.104 ZERO_SCROLLBACK ();
1435    
1436 pcg 1.25 num_scr_allow = 0;
1437 sf-exg 1.407
1438     row_col_t pos;
1439     pos.row = pos.col = 0;
1440     if (ROWCOL_IS_AFTER (selection.end, pos))
1441     CLEAR_SELECTION ();
1442 pcg 1.25
1443 root 1.129 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E'));
1444 root 1.176 for (int row = nrow; row--; )
1445 pcg 1.25 {
1446 root 1.176 line_t &line = ROW(row);
1447 root 1.174
1448     fill_text (line.t, 'E', ncol);
1449 root 1.176 rend_t *r1 = line.r;
1450 root 1.174
1451 root 1.176 for (int j = ncol; j--; )
1452 pcg 1.25 *r1++ = fs;
1453 root 1.174
1454 root 1.210 line.is_longer (0);
1455     line.touch (ncol);
1456 pcg 1.1 }
1457     }
1458    
1459     /* ------------------------------------------------------------------------- */
1460     /*
1461     * Insert/Delete <count> lines
1462     */
1463     void
1464 root 1.244 rxvt_term::scr_insdel_lines (int count, int insdel) NOTHROW
1465 pcg 1.1 {
1466 pcg 1.66 int end;
1467 pcg 1.1
1468 pcg 1.30 ZERO_SCROLLBACK ();
1469 pcg 1.1
1470 pcg 1.25 selection_check (1);
1471    
1472     if (screen.cur.row > screen.bscroll)
1473     return;
1474 pcg 1.1
1475 pcg 1.25 end = screen.bscroll - screen.cur.row + 1;
1476     if (count > end)
1477     {
1478     if (insdel == DELETE)
1479 pcg 1.4 return;
1480 pcg 1.25 else if (insdel == INSERT)
1481     count = end;
1482 pcg 1.1 }
1483 root 1.104
1484     scr_do_wrap ();
1485 pcg 1.1
1486 root 1.176 scr_scroll_text (screen.cur.row, screen.bscroll, insdel * count);
1487 pcg 1.1 }
1488    
1489     /* ------------------------------------------------------------------------- */
1490     /*
1491     * Insert/Delete <count> characters from the current position
1492     */
1493     void
1494 root 1.244 rxvt_term::scr_insdel_chars (int count, int insdel) NOTHROW
1495 pcg 1.1 {
1496 pcg 1.25 want_refresh = 1;
1497 pcg 1.30 ZERO_SCROLLBACK ();
1498 pcg 1.1
1499 pcg 1.25 if (count <= 0)
1500     return;
1501 pcg 1.1
1502 root 1.104 scr_do_wrap ();
1503    
1504 pcg 1.25 selection_check (1);
1505 root 1.186 min_it (count, ncol - screen.cur.col);
1506 pcg 1.1
1507 root 1.314 int row = screen.cur.row;
1508 pcg 1.1
1509 root 1.176 line_t *line = &ROW(row);
1510 pcg 1.66
1511 root 1.210 line->touch ();
1512     line->is_longer (0);
1513    
1514 root 1.316 // nuke wide spanning the start
1515 root 1.315 if (line->t[screen.cur.col] == NOCHAR)
1516     scr_kill_char (*line, screen.cur.col);
1517    
1518 pcg 1.25 switch (insdel)
1519     {
1520     case INSERT:
1521 root 1.314 line->l = min (line->l + count, ncol);
1522    
1523 root 1.315 if (line->t[screen.cur.col] == NOCHAR)
1524     scr_kill_char (*line, screen.cur.col);
1525    
1526 root 1.314 for (int col = ncol - 1; (col - count) >= screen.cur.col; col--)
1527 pcg 1.25 {
1528 root 1.172 line->t[col] = line->t[col - count];
1529     line->r[col] = line->r[col - count];
1530 pcg 1.25 }
1531 pcg 1.66
1532 pcg 1.21 if (selection.op && current_screen == selection.screen
1533 pcg 1.30 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1534 pcg 1.25 {
1535 pcg 1.21 if (selection.end.row != screen.cur.row
1536 root 1.172 || (selection.end.col + count >= ncol))
1537 pcg 1.30 CLEAR_SELECTION ();
1538 pcg 1.25 else
1539 ayin 1.284 {
1540     /* shift selection */
1541 root 1.136 selection.beg.col += count;
1542 pcg 1.21 selection.mark.col += count; /* XXX: yes? */
1543 root 1.136 selection.end.col += count;
1544 pcg 1.25 }
1545     }
1546 pcg 1.66
1547 root 1.176 scr_blank_line (*line, screen.cur.col, count, rstyle);
1548 pcg 1.4 break;
1549 pcg 1.66
1550 pcg 1.25 case ERASE:
1551 root 1.172 screen.cur.col += count; /* don't worry if > ncol */
1552 pcg 1.21 selection_check (1);
1553     screen.cur.col -= count;
1554 root 1.210
1555 root 1.315 // nuke wide char after the end
1556     if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR)
1557     scr_kill_char (*line, screen.cur.col + count);
1558    
1559 root 1.176 scr_blank_line (*line, screen.cur.col, count, rstyle);
1560 pcg 1.4 break;
1561 pcg 1.66
1562 pcg 1.25 case DELETE:
1563 root 1.316 line->l = max (line->l - count, 0);
1564 root 1.314
1565 root 1.316 // nuke wide char spanning the end
1566     if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR)
1567     scr_kill_char (*line, screen.cur.col + count);
1568 pcg 1.66
1569 root 1.316 for (int col = screen.cur.col; (col + count) < ncol; col++)
1570     {
1571     line->t[col] = line->t[col + count];
1572     line->r[col] = line->r[col + count];
1573     }
1574 root 1.314
1575 root 1.325 scr_blank_line (*line, ncol - count, count, rstyle);
1576 pcg 1.66
1577 root 1.316 if (selection.op && current_screen == selection.screen
1578     && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1579     {
1580     if (selection.end.row != screen.cur.row
1581     || (screen.cur.col >= selection.beg.col - count)
1582     || selection.end.col >= ncol)
1583     CLEAR_SELECTION ();
1584     else
1585     {
1586     /* shift selection */
1587     selection.beg.col -= count;
1588     selection.mark.col -= count; /* XXX: yes? */
1589     selection.end.col -= count;
1590     }
1591 pcg 1.25 }
1592 pcg 1.66
1593 pcg 1.4 break;
1594 pcg 1.1 }
1595     }
1596    
1597     /* ------------------------------------------------------------------------- */
1598     /*
1599     * Set the scrolling region
1600     * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1601     */
1602 root 1.417 void ecb_cold
1603 root 1.244 rxvt_term::scr_scroll_region (int top, int bot) NOTHROW
1604 pcg 1.1 {
1605 root 1.183 max_it (top, 0);
1606 root 1.186 min_it (bot, nrow - 1);
1607 pcg 1.66
1608 pcg 1.25 if (top > bot)
1609     return;
1610 pcg 1.66
1611 pcg 1.25 screen.tscroll = top;
1612     screen.bscroll = bot;
1613     scr_gotorc (0, 0, 0);
1614 pcg 1.1 }
1615    
1616     /* ------------------------------------------------------------------------- */
1617     /*
1618     * Make the cursor visible/invisible
1619     * XTERM_SEQ: Make cursor visible : ESC [ ? 25 h
1620     * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1621     */
1622 root 1.417 void ecb_cold
1623 root 1.244 rxvt_term::scr_cursor_visible (int mode) NOTHROW
1624 pcg 1.1 {
1625 pcg 1.25 want_refresh = 1;
1626 pcg 1.71
1627 pcg 1.25 if (mode)
1628     screen.flags |= Screen_VisibleCursor;
1629     else
1630     screen.flags &= ~Screen_VisibleCursor;
1631 pcg 1.1 }
1632    
1633     /* ------------------------------------------------------------------------- */
1634     /*
1635     * Set/unset automatic wrapping
1636     * XTERM_SEQ: Set Wraparound : ESC [ ? 7 h
1637     * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1638     */
1639 root 1.417 void ecb_cold
1640 root 1.244 rxvt_term::scr_autowrap (int mode) NOTHROW
1641 pcg 1.1 {
1642 pcg 1.25 if (mode)
1643     screen.flags |= Screen_Autowrap;
1644     else
1645 root 1.104 screen.flags &= ~(Screen_Autowrap | Screen_WrapNext);
1646 pcg 1.1 }
1647    
1648     /* ------------------------------------------------------------------------- */
1649     /*
1650     * Set/unset margin origin mode
1651     * Absolute mode: line numbers are counted relative to top margin of screen
1652     * and the cursor can be moved outside the scrolling region.
1653     * Relative mode: line numbers are relative to top margin of scrolling region
1654     * and the cursor cannot be moved outside.
1655     * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1656     * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1657     */
1658 root 1.417 void ecb_cold
1659 root 1.244 rxvt_term::scr_relative_origin (int mode) NOTHROW
1660 pcg 1.1 {
1661 pcg 1.25 if (mode)
1662     screen.flags |= Screen_Relative;
1663     else
1664     screen.flags &= ~Screen_Relative;
1665 root 1.129
1666 pcg 1.25 scr_gotorc (0, 0, 0);
1667 pcg 1.1 }
1668    
1669     /* ------------------------------------------------------------------------- */
1670     /*
1671     * Set insert/replace mode
1672     * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1673     * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1674     */
1675 root 1.417 void ecb_cold
1676 root 1.244 rxvt_term::scr_insert_mode (int mode) NOTHROW
1677 pcg 1.1 {
1678 pcg 1.25 if (mode)
1679     screen.flags |= Screen_Insert;
1680     else
1681     screen.flags &= ~Screen_Insert;
1682 pcg 1.1 }
1683    
1684     /* ------------------------------------------------------------------------- */
1685     /*
1686     * Set/Unset tabs
1687     * XTERM_SEQ: Set tab at current column : ESC H
1688     * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1689     * XTERM_SEQ: Clear all tabs : ESC [ 3 g
1690     */
1691 root 1.417 void ecb_cold
1692 root 1.244 rxvt_term::scr_set_tab (int mode) NOTHROW
1693 pcg 1.1 {
1694 pcg 1.25 if (mode < 0)
1695 ayin 1.277 memset (tabs, 0, ncol);
1696 root 1.172 else if (screen.cur.col < ncol)
1697 root 1.210 tabs [screen.cur.col] = !!mode;
1698 pcg 1.1 }
1699    
1700     /* ------------------------------------------------------------------------- */
1701     /*
1702     * Set reverse/normal video
1703     * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1704     * XTERM_SEQ: Normal video : ESC [ ? 5 l
1705     */
1706     void
1707 root 1.246 rxvt_term::scr_rvideo_mode (bool on) NOTHROW
1708 pcg 1.1 {
1709 root 1.246 rvideo_mode = on;
1710    
1711     #ifndef NO_BELL
1712     on ^= rvideo_bell;
1713     #endif
1714 pcg 1.1
1715 root 1.246 if (rvideo_state != on)
1716 pcg 1.25 {
1717 root 1.246 rvideo_state = on;
1718    
1719 root 1.181 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]);
1720 sf-exg 1.427 #ifdef HAVE_IMG
1721 sf-exg 1.421 if (bg_img == 0)
1722 pcg 1.1 #endif
1723 root 1.258 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
1724 pcg 1.1
1725 root 1.246 XGCValues gcvalue;
1726 root 1.104 gcvalue.foreground = pix_colors[Color_fg];
1727     gcvalue.background = pix_colors[Color_bg];
1728 root 1.258 XChangeGC (dpy, gc, GCBackground | GCForeground, &gcvalue);
1729 root 1.246
1730 pcg 1.25 scr_clear ();
1731     scr_touch (true);
1732 pcg 1.1 }
1733     }
1734    
1735     /* ------------------------------------------------------------------------- */
1736     /*
1737     * Report current cursor position
1738     * XTERM_SEQ: Report position: ESC [ 6 n
1739     */
1740 root 1.417 void ecb_cold
1741 root 1.244 rxvt_term::scr_report_position () NOTHROW
1742 pcg 1.1 {
1743 pcg 1.30 tt_printf ("\033[%d;%dR", screen.cur.row + 1, screen.cur.col + 1);
1744 pcg 1.1 }
1745 ayin 1.282
1746 pcg 1.1 /* ------------------------------------------------------------------------- *
1747     * FONTS *
1748     * ------------------------------------------------------------------------- */
1749    
1750     /*
1751     * Set font style
1752     */
1753 root 1.417 void ecb_cold
1754 root 1.244 rxvt_term::set_font_style () NOTHROW
1755 pcg 1.1 {
1756 root 1.210 #if 0
1757     switch (charsets [screen.charset])
1758 pcg 1.25 {
1759     case '0': /* DEC Special Character & Line Drawing Set */
1760 pcg 1.4 break;
1761 pcg 1.25 case 'A': /* United Kingdom (UK) */
1762 pcg 1.4 break;
1763 pcg 1.25 case 'B': /* United States (USASCII) */
1764 pcg 1.4 break;
1765 pcg 1.25 case '<': /* Multinational character set */
1766 pcg 1.4 break;
1767 pcg 1.25 case '5': /* Finnish character set */
1768 pcg 1.4 break;
1769 pcg 1.25 case 'C': /* Finnish character set */
1770 pcg 1.4 break;
1771 pcg 1.25 case 'K': /* German character set */
1772 pcg 1.4 break;
1773 pcg 1.1 }
1774 root 1.210 #endif
1775 pcg 1.1 }
1776    
1777     /* ------------------------------------------------------------------------- */
1778     /*
1779     * Choose a font
1780     * XTERM_SEQ: Invoke G0 character set: CTRL-O
1781     * XTERM_SEQ: Invoke G1 character set: CTRL-N
1782     * XTERM_SEQ: Invoke G2 character set: ESC N
1783     * XTERM_SEQ: Invoke G3 character set: ESC O
1784     */
1785 root 1.417 void ecb_cold
1786 root 1.244 rxvt_term::scr_charset_choose (int set) NOTHROW
1787 root 1.136 {
1788     screen.charset = set;
1789     set_font_style ();
1790     }
1791 pcg 1.1
1792     /* ------------------------------------------------------------------------- */
1793     /*
1794     * Set a font
1795     * XTERM_SEQ: Set G0 character set: ESC ( <C>
1796     * XTERM_SEQ: Set G1 character set: ESC ) <C>
1797     * XTERM_SEQ: Set G2 character set: ESC * <C>
1798     * XTERM_SEQ: Set G3 character set: ESC + <C>
1799     * See set_font_style for possible values for <C>
1800     */
1801     void
1802 root 1.244 rxvt_term::scr_charset_set (int set, unsigned int ch) NOTHROW
1803 root 1.136 {
1804     charsets[set] = (unsigned char)ch;
1805     set_font_style ();
1806     }
1807 pcg 1.1
1808 ayin 1.282
1809 pcg 1.1 /* ------------------------------------------------------------------------- *
1810     * MAJOR SCREEN MANIPULATION *
1811     * ------------------------------------------------------------------------- */
1812    
1813     /*
1814 pcg 1.19 * refresh matching text.
1815     */
1816 root 1.417 bool ecb_cold
1817 root 1.244 rxvt_term::scr_refresh_rend (rend_t mask, rend_t value) NOTHROW
1818 pcg 1.19 {
1819     bool found = false;
1820    
1821 root 1.172 for (int i = 0; i < nrow; i++)
1822 pcg 1.19 {
1823 root 1.186 rend_t *drp = drawn_buf[i].r;
1824 pcg 1.19
1825 root 1.255 for (int col = 0; col < ncol; col++, drp++)
1826 pcg 1.19 if ((*drp & mask) == value)
1827     {
1828     found = true;
1829     *drp = ~value;
1830     }
1831     }
1832    
1833     return found;
1834     }
1835    
1836     /*
1837 pcg 1.1 * Refresh an area
1838     */
1839     enum {
1840 pcg 1.25 PART_BEG = 0,
1841     PART_END,
1842     RC_COUNT
1843 pcg 1.1 };
1844    
1845 root 1.417 void ecb_hot
1846 root 1.244 rxvt_term::scr_expose (int x, int y, int ewidth, int eheight, bool refresh) NOTHROW
1847 pcg 1.1 {
1848 pcg 1.11 int i;
1849     row_col_t rc[RC_COUNT];
1850 pcg 1.1
1851 root 1.186 if (!drawn_buf) /* sanity check */
1852 pcg 1.11 return;
1853 pcg 1.1
1854 root 1.82 #ifndef NO_SLOW_LINK_SUPPORT
1855     if (refresh_type == FAST_REFRESH && !display->is_local)
1856     {
1857     y = 0;
1858 root 1.172 eheight = height;
1859 root 1.82 }
1860     #endif
1861    
1862 pcg 1.25 /* round down */
1863 pcg 1.30 rc[PART_BEG].col = Pixel2Col (x);
1864     rc[PART_BEG].row = Pixel2Row (y);
1865 pcg 1.25 /* round up */
1866 root 1.172 rc[PART_END].col = Pixel2Width (x + ewidth + fwidth - 1);
1867     rc[PART_END].row = Pixel2Row (y + eheight + fheight - 1);
1868 pcg 1.1
1869 pcg 1.25 /* sanity checks */
1870 pcg 1.11 for (i = PART_BEG; i < RC_COUNT; i++)
1871     {
1872 root 1.183 min_it (rc[i].col, ncol - 1);
1873     min_it (rc[i].row, nrow - 1);
1874 pcg 1.1 }
1875 sf-exg 1.334
1876 pcg 1.11 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1877 root 1.186 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
1878 pcg 1.1
1879 root 1.235 num_scr_allow = 0;
1880    
1881 pcg 1.11 if (refresh)
1882 root 1.235 scr_refresh ();
1883 pcg 1.1 }
1884    
1885     /* ------------------------------------------------------------------------- */
1886     /*
1887     * Refresh the entire screen
1888     */
1889     void
1890 root 1.244 rxvt_term::scr_touch (bool refresh) NOTHROW
1891 pcg 1.1 {
1892 sf-exg 1.411 scr_expose (0, 0, vt_width, vt_height, refresh);
1893 pcg 1.1 }
1894    
1895     /* ------------------------------------------------------------------------- */
1896     /*
1897     * Move the display so that the line represented by scrollbar value Y is at
1898     * the top of the screen
1899     */
1900 root 1.228 void
1901 root 1.244 rxvt_term::scr_move_to (int y, int len) NOTHROW
1902 pcg 1.1 {
1903 sf-exg 1.445 // lerp (y, 0, len, top_row, nrow - 1)
1904     scr_changeview (top_row + (nrow - 1 - top_row) * y / len);
1905 pcg 1.1 }
1906    
1907     /* ------------------------------------------------------------------------- */
1908     /*
1909     * Page the screen up/down nlines
1910     * direction should be UP or DN
1911     */
1912 root 1.228 bool
1913 root 1.440 rxvt_term::scr_page (int nlines) NOTHROW
1914 pcg 1.1 {
1915 root 1.440 return scr_changeview (view_start - nlines);
1916 pcg 1.1 }
1917    
1918 root 1.228 bool
1919 root 1.244 rxvt_term::scr_changeview (int new_view_start) NOTHROW
1920 pcg 1.1 {
1921 root 1.228 clamp_it (new_view_start, top_row, 0);
1922    
1923 root 1.229 if (new_view_start == view_start)
1924     return false;
1925    
1926     num_scr += new_view_start - view_start;
1927     view_start = new_view_start;
1928 root 1.234 want_refresh = 1;
1929    
1930 root 1.229 HOOK_INVOKE ((this, HOOK_VIEW_CHANGE, DT_INT, view_start, DT_END));
1931 root 1.210
1932 root 1.229 return true;
1933 pcg 1.1 }
1934    
1935 root 1.246 #ifndef NO_BELL
1936     void
1937 root 1.283 rxvt_term::bell_cb (ev::timer &w, int revents)
1938 root 1.246 {
1939     rvideo_bell = false;
1940     scr_rvideo_mode (rvideo_mode);
1941 root 1.291 refresh_check ();
1942 root 1.246 }
1943     #endif
1944    
1945 pcg 1.1 /* ------------------------------------------------------------------------- */
1946     void
1947 root 1.244 rxvt_term::scr_bell () NOTHROW
1948 pcg 1.1 {
1949     #ifndef NO_BELL
1950 root 1.167
1951 pcg 1.1 # ifndef NO_MAPALERT
1952     # ifdef MAPALERT_OPTION
1953 root 1.268 if (option (Opt_mapAlert))
1954 pcg 1.1 # endif
1955 sf-exg 1.380 XMapWindow (dpy, parent);
1956 pcg 1.1 # endif
1957 root 1.278
1958 ayin 1.269 # if ENABLE_FRILLS
1959     if (option (Opt_urgentOnBell))
1960 root 1.311 set_urgency (1);
1961 ayin 1.269 # endif
1962 root 1.167
1963 root 1.268 if (option (Opt_visualBell))
1964 pcg 1.25 {
1965 root 1.246 rvideo_bell = true;
1966     scr_rvideo_mode (rvideo_mode);
1967 root 1.290 flush ();
1968 root 1.246
1969 root 1.283 bell_ev.start (VISUAL_BELL_DURATION);
1970 pcg 1.25 }
1971     else
1972 root 1.258 XBell (dpy, 0);
1973 sf-exg 1.331 HOOK_INVOKE ((this, HOOK_BELL, DT_END));
1974 pcg 1.1 #endif
1975     }
1976    
1977     /* ------------------------------------------------------------------------- */
1978 root 1.417 void ecb_cold
1979 root 1.244 rxvt_term::scr_printscreen (int fullhist) NOTHROW
1980 pcg 1.1 {
1981     #ifdef PRINTPIPE
1982 root 1.176 int nrows, row_start;
1983 root 1.308 FILE *fd = popen_printer ();
1984 pcg 1.1
1985 root 1.308 if (!fd)
1986 pcg 1.25 return;
1987 root 1.104
1988 root 1.176 if (fullhist)
1989     {
1990 root 1.228 nrows = nrow - top_row;
1991     row_start = top_row;
1992 root 1.176 }
1993 pcg 1.25 else
1994     {
1995 root 1.176 nrows = nrow;
1996 root 1.228 row_start = view_start;
1997 pcg 1.1 }
1998    
1999 root 1.104 wctomb (0, 0);
2000    
2001 root 1.330 for (int r1 = row_start; r1 < row_start + nrows; r1++)
2002 pcg 1.25 {
2003 root 1.176 text_t *tp = ROW(r1).t;
2004     int len = ROW(r1).l;
2005 root 1.104
2006 root 1.176 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN
2007 root 1.104 {
2008     char mb[MB_LEN_MAX];
2009     text_t t = *tp++;
2010     if (t == NOCHAR)
2011     continue;
2012    
2013     len = wctomb (mb, t);
2014    
2015     if (len <= 0)
2016     {
2017     mb[0] = ' ';
2018     len = 1;
2019     }
2020    
2021     fwrite (mb, 1, len, fd);
2022     }
2023    
2024     fputc ('\n', fd);
2025 pcg 1.1 }
2026 root 1.104
2027 pcg 1.25 pclose_printer (fd);
2028 pcg 1.1 #endif
2029     }
2030    
2031     /* ------------------------------------------------------------------------- */
2032     /*
2033     * Refresh the screen
2034 pcg 1.21 * drawn_text/drawn_rend contain the screen information before the update.
2035     * screen.text/screen.rend contain what the screen will change to.
2036 pcg 1.1 */
2037 root 1.417 void ecb_hot
2038 root 1.244 rxvt_term::scr_refresh () NOTHROW
2039 pcg 1.1 {
2040 pcg 1.35 int16_t col, row, /* column/row we're processing */
2041     ocrow; /* old cursor row */
2042 root 1.179 int i; /* tmp */
2043 root 1.265 rend_t ccol1, /* Cursor colour */
2044     ccol2; /* Cursor colour2 */
2045 sf-exg 1.433 rend_t cur_rend;
2046     int cur_col;
2047 sf-exg 1.438 int cursorwidth;
2048 pcg 1.1
2049 root 1.136 want_refresh = 0; /* screen is current */
2050    
2051 root 1.172 if (refresh_type == NO_REFRESH || !mapped)
2052 pcg 1.25 return;
2053 pcg 1.1
2054 pcg 1.25 /*
2055     * A: set up vars
2056     */
2057     refresh_count = 0;
2058 pcg 1.1
2059 root 1.327 unsigned int old_screen_flags = screen.flags;
2060 sf-exg 1.404 bool have_bg = 0;
2061 sf-exg 1.427 #ifdef HAVE_IMG
2062 sf-exg 1.421 have_bg = bg_img != 0;
2063 pcg 1.1 #endif
2064 pcg 1.25 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
2065 pcg 1.1
2066 pcg 1.25 /*
2067     * B: reverse any characters which are selected
2068     */
2069     scr_reverse_selection ();
2070 pcg 1.1
2071 root 1.327 HOOK_INVOKE ((this, HOOK_REFRESH_BEGIN, DT_END));
2072     #if ENABLE_OVERLAY
2073     scr_swap_overlay ();
2074     #endif
2075    
2076 sf-exg 1.403 bool showcursor = screen.flags & Screen_VisibleCursor;
2077 root 1.327
2078 pcg 1.25 /*
2079 pcg 1.30 * C: set the cursor character (s)
2080 pcg 1.25 */
2081     {
2082 pcg 1.1 #ifdef CURSOR_BLINK
2083 pcg 1.25 if (hidden_cursor)
2084     showcursor = 0;
2085 pcg 1.1 #endif
2086    
2087 pcg 1.25 if (showcursor)
2088     {
2089 root 1.104 int col = screen.cur.col;
2090    
2091 root 1.175 while (col && ROW(screen.cur.row).t[col] == NOCHAR)
2092 root 1.104 col--;
2093    
2094 sf-exg 1.438 cursorwidth = 1;
2095     while (col + cursorwidth < ncol
2096     && ROW(screen.cur.row).t[col + cursorwidth] == NOCHAR)
2097     cursorwidth++;
2098    
2099 sf-exg 1.433 cur_rend = ROW(screen.cur.row).r[col];
2100     cur_col = col;
2101 pcg 1.1
2102 root 1.265 #ifndef NO_CURSORCOLOR
2103     if (ISSET_PIXCOLOR (Color_cursor))
2104     ccol1 = Color_cursor;
2105     else
2106     #endif
2107     #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2108     ccol1 = fgcolor_of (rstyle);
2109     #else
2110     ccol1 = Color_fg;
2111     #endif
2112    
2113     #ifndef NO_CURSORCOLOR
2114     if (ISSET_PIXCOLOR (Color_cursor2))
2115     ccol2 = Color_cursor2;
2116     else
2117     #endif
2118     #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2119     ccol2 = bgcolor_of (rstyle);
2120     #else
2121     ccol2 = Color_bg;
2122     #endif
2123    
2124 sf-exg 1.454 if (focus && cursor_type == 0)
2125 pcg 1.25 {
2126 sf-exg 1.433 rend_t rend = cur_rend;
2127    
2128 sf-exg 1.454 rend ^= RS_RVid;
2129     rend = SET_FGCOLOR (rend, ccol1);
2130     rend = SET_BGCOLOR (rend, ccol2);
2131 sf-exg 1.433
2132     scr_set_char_rend (ROW(screen.cur.row), cur_col, rend);
2133 pcg 1.1 }
2134 pcg 1.4 }
2135 pcg 1.1
2136 pcg 1.25 /* make sure no outline cursor is left around */
2137 root 1.452 if (ocrow != -1 && ocrow < nrow && oldcursor.col < ncol)
2138     drawn_buf[ocrow].r[oldcursor.col] ^= (RS_RVid | RS_Uline);
2139 pcg 1.66
2140 sf-exg 1.439 // save the current cursor coordinates if the cursor is visible
2141 sf-exg 1.447 // and either the window is unfocused or the cursor style is
2142 sf-exg 1.454 // underline or vertical bar, so as to clear the outline cursor in
2143     // the next refresh if the cursor moves or becomes invisible
2144     if (showcursor && (!focus || cursor_type != 0) && screen.cur.row - view_start < nrow)
2145 pcg 1.25 {
2146 sf-exg 1.439 oldcursor.row = screen.cur.row - view_start;
2147     oldcursor.col = screen.cur.col;
2148 pcg 1.25 }
2149 sf-exg 1.439 else
2150     oldcursor.row = -1;
2151 pcg 1.25 }
2152    
2153     #ifndef NO_SLOW_LINK_SUPPORT
2154     /*
2155     * D: CopyArea pass - very useful for slower links
2156     * This has been deliberately kept simple.
2157     */
2158 root 1.82 if (!display->is_local
2159 root 1.176 && refresh_type == FAST_REFRESH && num_scr_allow && num_scr
2160 root 1.260 && abs (num_scr) < nrow && !have_bg)
2161 pcg 1.25 {
2162 pcg 1.66 int16_t nits;
2163 root 1.261 int i = num_scr;
2164 pcg 1.66 int j;
2165     int len, wlen;
2166 pcg 1.25
2167 root 1.172 j = nrow;
2168 pcg 1.25 wlen = len = -1;
2169     row = i > 0 ? 0 : j - 1;
2170 root 1.261
2171 pcg 1.25 for (; j-- >= 0; row += (i > 0 ? 1 : -1))
2172     {
2173 root 1.172 if (row + i >= 0 && row + i < nrow && row + i != ocrow)
2174 pcg 1.25 {
2175 root 1.228 line_t s = ROW(view_start + row);
2176 root 1.186 line_t d = drawn_buf[row];
2177     line_t d2 = drawn_buf[row + i];
2178 pcg 1.25
2179 root 1.172 for (nits = 0, col = ncol; col--; )
2180     if (s.t[col] != d2.t[col] || s.r[col] != d2.r[col])
2181 pcg 1.25 nits--;
2182 root 1.172 else if (s.t[col] != d.t[col] || s.r[col] != d.r[col])
2183 pcg 1.25 nits++;
2184    
2185     if (nits > 8) /* XXX: arbitrary choice */
2186     {
2187 root 1.172 for (col = ncol; col--; )
2188 pcg 1.25 {
2189 root 1.172 *d.t++ = *d2.t++;
2190     *d.r++ = *d2.r++;
2191 pcg 1.25 }
2192    
2193     if (len == -1)
2194     len = row;
2195    
2196     wlen = row;
2197     continue;
2198     }
2199     }
2200    
2201 root 1.261 if (len >= 0)
2202 pcg 1.25 {
2203     /* also comes here at end if needed because of >= above */
2204     if (wlen < len)
2205 root 1.182 ::swap (wlen, len);
2206 pcg 1.25
2207 root 1.260 XGCValues gcv;
2208    
2209     gcv.graphics_exposures = 1; XChangeGC (dpy, gc, GCGraphicsExposures, &gcv);
2210 root 1.258 XCopyArea (dpy, vt, vt,
2211 root 1.172 gc, 0, Row2Pixel (len + i),
2212 root 1.207 (unsigned int)this->width,
2213 pcg 1.25 (unsigned int)Height2Pixel (wlen - len + 1),
2214     0, Row2Pixel (len));
2215 root 1.260 gcv.graphics_exposures = 0; XChangeGC (dpy, gc, GCGraphicsExposures, &gcv);
2216    
2217 pcg 1.25 len = -1;
2218     }
2219     }
2220 pcg 1.1 }
2221     #endif
2222    
2223 pcg 1.25 /*
2224     * E: main pass across every character
2225     */
2226 root 1.172 for (row = 0; row < nrow; row++)
2227 pcg 1.25 {
2228 root 1.228 text_t *stp = ROW(view_start + row).t;
2229     rend_t *srp = ROW(view_start + row).r;
2230 root 1.186 text_t *dtp = drawn_buf[row].t;
2231     rend_t *drp = drawn_buf[row].r;
2232 pcg 1.25
2233     /*
2234     * E2: OK, now the real pass
2235     */
2236 pcg 1.30 int ypixel = (int)Row2Pixel (row);
2237 pcg 1.25
2238 root 1.172 for (col = 0; col < ncol; col++)
2239 pcg 1.25 {
2240     /* compare new text with old - if exactly the same then continue */
2241 sf-exg 1.449 if (stp[col] == dtp[col] && RS_SAME (srp[col], drp[col]))
2242 pcg 1.25 continue;
2243 pcg 1.1
2244 pcg 1.43 // redraw one or more characters
2245    
2246 root 1.141 // seek to the beginning of wide characters
2247 sf-exg 1.384 while (ecb_unlikely (stp[col] == NOCHAR && col > 0))
2248 pcg 1.43 --col;
2249    
2250 sf-exg 1.339 rend_t rend = srp[col]; /* screen rendition (target rendition) */
2251 pcg 1.25 text_t *text = stp + col;
2252     int count = 1;
2253 pcg 1.1
2254 pcg 1.25 dtp[col] = stp[col];
2255     drp[col] = rend;
2256 pcg 1.1
2257 pcg 1.30 int xpixel = Col2Pixel (col);
2258 pcg 1.1
2259 root 1.172 for (i = 0; ++col < ncol; )
2260 pcg 1.25 {
2261     if (stp[col] == NOCHAR)
2262     {
2263     dtp[col] = stp[col];
2264 root 1.328 drp[col] = srp[col];
2265    
2266 pcg 1.25 count++;
2267 root 1.104 i++;
2268 pcg 1.1
2269 pcg 1.25 continue;
2270     }
2271 pcg 1.1
2272 root 1.129 if (!RS_SAME (rend, srp[col]))
2273 pcg 1.25 break;
2274 pcg 1.1
2275 pcg 1.25 count++;
2276 pcg 1.1
2277 pcg 1.25 if (stp[col] != dtp[col]
2278 root 1.129 || !RS_SAME (srp[col], drp[col]))
2279 pcg 1.25 {
2280 root 1.260 if (have_bg && (i++ > count / 2))
2281 pcg 1.25 break;
2282 pcg 1.1
2283 pcg 1.25 dtp[col] = stp[col];
2284     drp[col] = rend;
2285     i = 0;
2286     }
2287 root 1.260 else if (have_bg || (stp[col] != ' ' && ++i >= 16))
2288 pcg 1.25 break;
2289     }
2290 pcg 1.1
2291 pcg 1.25 col--; /* went one too far. move back */
2292     count -= i; /* dump any matching trailing chars */
2293 pcg 1.1
2294 root 1.104 // sometimes we optimize away the trailing NOCHAR's, add them back
2295 sf-exg 1.384 while (ecb_unlikely (i && text[count] == NOCHAR))
2296 root 1.104 count++, i--;
2297    
2298 pcg 1.25 /*
2299     * Determine the attributes for the string
2300     */
2301 root 1.201 int fore = fgcolor_of (rend); // desired foreground
2302     int back = bgcolor_of (rend); // desired background
2303 pcg 1.17
2304 root 1.197 // only do special processing if any attributes are set, which is unlikely
2305 sf-exg 1.384 if (ecb_unlikely (rend & (RS_baseattrMask | RS_Careful | RS_Sel)))
2306 root 1.129 {
2307     bool invert = rend & RS_RVid;
2308 pcg 1.1
2309 root 1.129 #ifndef NO_BOLD_UNDERLINE_REVERSE
2310 root 1.290 if (rend & RS_Bold && fore == Color_fg)
2311 root 1.129 {
2312     if (ISSET_PIXCOLOR (Color_BD))
2313     fore = Color_BD;
2314     # if !ENABLE_STYLES
2315     else
2316     invert = !invert;
2317     # endif
2318     }
2319 pcg 1.1
2320 root 1.290 if (rend & RS_Italic && fore == Color_fg)
2321 root 1.129 {
2322     if (ISSET_PIXCOLOR (Color_IT))
2323     fore = Color_IT;
2324     # if !ENABLE_STYLES
2325     else
2326     invert = !invert;
2327     # endif
2328     }
2329 pcg 1.36
2330 root 1.263 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL))
2331 root 1.129 fore = Color_UL;
2332 pcg 1.1 #endif
2333    
2334 sf-exg 1.340 #ifdef OPTION_HC
2335     if (rend & RS_Sel)
2336     {
2337     /* invert the column if no highlightColor is set or it is the
2338     * current cursor column */
2339     if (!(showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2340     && ISSET_PIXCOLOR (Color_HC))
2341     {
2342     if (ISSET_PIXCOLOR (Color_HTC))
2343     fore = Color_HTC;
2344     // if invert is 0 reverse video is set so we use bg color as fg color
2345     else if (!invert)
2346     fore = back;
2347 root 1.341
2348 sf-exg 1.340 back = Color_HC;
2349     invert = 0;
2350     }
2351     }
2352     #endif
2353    
2354 root 1.129 if (invert)
2355     {
2356 root 1.264 ::swap (fore, back);
2357 pcg 1.36
2358     #ifndef NO_BOLD_UNDERLINE_REVERSE
2359 root 1.168 if (fore == back)
2360     {
2361     fore = Color_bg;
2362     back = Color_fg;
2363     }
2364 pcg 1.36 #endif
2365 root 1.129 }
2366 pcg 1.36
2367 pcg 1.37 #ifdef TEXT_BLINK
2368 root 1.129 if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
2369 pcg 1.37 {
2370 root 1.287 if (!text_blink_ev.is_active ())
2371 root 1.129 {
2372 root 1.286 text_blink_ev.again ();
2373 root 1.129 hidden_text = 0;
2374     }
2375     else if (hidden_text)
2376     fore = back;
2377 pcg 1.37 }
2378 root 1.129 #endif
2379 root 1.264
2380     #if ENABLE_STYLES
2381     // "careful" (too wide) character handling
2382    
2383     // include previous careful character(s) if possible, looks nicer (best effort...)
2384     while (text > stp
2385     && srp[text - stp - 1] & RS_Careful
2386     && RS_SAME (rend, srp[text - stp - 1]))
2387     text--, count++, xpixel -= fwidth;
2388    
2389     // force redraw after "careful" characters to avoid pixel droppings
2390     for (int i = 0; srp[col + i] & RS_Careful && col + i < ncol - 1; i++)
2391     drp[col + i + 1] = srp[col + i + 1] ^ RS_redraw;
2392    
2393     // force redraw before "careful" characters to avoid pixel droppings
2394     for (int i = 0; srp[text - stp - i] & RS_Careful && text - i > stp; i++)
2395     drp[text - stp - i - 1] = srp[text - stp - i - 1] ^ RS_redraw;
2396     #endif
2397 pcg 1.37 }
2398    
2399 pcg 1.25 /*
2400     * Actually do the drawing of the string here
2401     */
2402 root 1.336 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)];
2403 pcg 1.25
2404 sf-exg 1.384 if (ecb_likely (have_bg && back == Color_bg))
2405 pcg 1.25 {
2406 root 1.260 // this is very ugly, maybe push it into ->draw?
2407    
2408     for (i = 0; i < count; i++) /* don't draw empty strings */
2409     if (text[i] != ' ')
2410     {
2411 root 1.267 font->draw (*drawable, xpixel, ypixel, text, count, fore, Color_transparent);
2412 root 1.260 goto did_clear;
2413     }
2414 pcg 1.25
2415 root 1.260 CLEAR_CHARS (xpixel, ypixel, count);
2416     did_clear: ;
2417 pcg 1.25 }
2418     else
2419 root 1.172 font->draw (*drawable, xpixel, ypixel, text, count, fore, back);
2420 pcg 1.1
2421 sf-exg 1.384 if (ecb_unlikely (rend & RS_Uline && font->descent > 1 && fore != back))
2422 root 1.147 {
2423 sf-exg 1.438 if (showcursor && focus && row == screen.cur.row
2424     && IN_RANGE_EXC (col, cur_col, cur_col + cursorwidth))
2425     XSetForeground (dpy, gc, pix_colors[ccol1]);
2426     else
2427 root 1.151 #if ENABLE_FRILLS
2428     if (ISSET_PIXCOLOR (Color_underline))
2429 root 1.258 XSetForeground (dpy, gc, pix_colors[Color_underline]);
2430 root 1.151 else
2431     #endif
2432 root 1.258 XSetForeground (dpy, gc, pix_colors[fore]);
2433 root 1.151
2434 root 1.299 XDrawLine (dpy, vt, gc,
2435 root 1.147 xpixel, ypixel + font->ascent + 1,
2436     xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2437     }
2438 pcg 1.25 } /* for (col....) */
2439     } /* for (row....) */
2440 pcg 1.1
2441 pcg 1.25 /*
2442     * G: cleanup cursor and display outline cursor if necessary
2443     */
2444     if (showcursor)
2445     {
2446 root 1.172 if (focus)
2447 sf-exg 1.447 {
2448 sf-exg 1.454 if (cursor_type == 0)
2449 sf-exg 1.447 scr_set_char_rend (ROW(screen.cur.row), cur_col, cur_rend);
2450     else if (oldcursor.row >= 0)
2451     {
2452     XSetForeground (dpy, gc, pix_colors[ccol1]);
2453 sf-exg 1.454 if (cursor_type == 1)
2454     XFillRectangle (dpy, vt, gc,
2455     Col2Pixel (cur_col),
2456     Row2Pixel (oldcursor.row + 1) - 2,
2457     Width2Pixel (1),
2458     2);
2459     else
2460     XFillRectangle (dpy, vt, gc,
2461     Col2Pixel (cur_col),
2462     Row2Pixel (oldcursor.row),
2463     2,
2464     Height2Pixel (1));
2465 sf-exg 1.447 }
2466     }
2467 pcg 1.25 else if (oldcursor.row >= 0)
2468     {
2469 sf-exg 1.437 XSetForeground (dpy, gc, pix_colors[ccol1]);
2470 pcg 1.35
2471 root 1.299 XDrawRectangle (dpy, vt, gc,
2472 sf-exg 1.438 Col2Pixel (cur_col),
2473 pcg 1.43 Row2Pixel (oldcursor.row),
2474     (unsigned int) (Width2Pixel (cursorwidth) - 1),
2475 sf-exg 1.414 (unsigned int) (Height2Pixel (1) - 1));
2476 pcg 1.4 }
2477 pcg 1.1 }
2478 pcg 1.12
2479 pcg 1.25 /*
2480     * H: cleanup selection
2481     */
2482 root 1.327 #if ENABLE_OVERLAY
2483     scr_swap_overlay ();
2484     #endif
2485     HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2486    
2487 pcg 1.25 scr_reverse_selection ();
2488    
2489 root 1.327 screen.flags = old_screen_flags;
2490 pcg 1.25 num_scr = 0;
2491     num_scr_allow = 1;
2492 pcg 1.1 }
2493 pcg 1.11
2494 root 1.417 void ecb_cold
2495 root 1.244 rxvt_term::scr_remap_chars (line_t &l) NOTHROW
2496 pcg 1.32 {
2497 root 1.415 if (!l.valid ())
2498 pcg 1.32 return;
2499    
2500 root 1.214 l.touch (); // maybe a bit of an overkill, but it's not performance-relevant
2501 root 1.210
2502 root 1.172 for (int i = ncol; i--; )
2503     l.r[i] = SET_FONT (l.r[i], FONTSET (l.r[i])->find_font (l.t[i]));
2504 pcg 1.32 }
2505    
2506 root 1.417 void ecb_cold
2507 root 1.244 rxvt_term::scr_remap_chars () NOTHROW
2508 pcg 1.32 {
2509 root 1.175 for (int i = total_rows; i--; )
2510 root 1.186 scr_remap_chars (row_buf [i]);
2511 pcg 1.32
2512 root 1.172 for (int i = nrow; i--; )
2513 pcg 1.32 {
2514 root 1.186 scr_remap_chars (drawn_buf [i]);
2515     scr_remap_chars (swap_buf [i]);
2516 pcg 1.32 }
2517     }
2518    
2519 root 1.417 void ecb_cold
2520 root 1.453 rxvt_term::scr_recolor (bool refresh) NOTHROW
2521 root 1.129 {
2522 sf-exg 1.364 bool transparent = false;
2523    
2524 sf-exg 1.427 #ifdef HAVE_IMG
2525 sf-exg 1.421 if (bg_img != 0)
2526 sf-exg 1.364 {
2527 root 1.420 # if ENABLE_TRANSPARENCY
2528 sf-exg 1.366 if (bg_flags & BG_IS_TRANSPARENT)
2529 sf-exg 1.364 {
2530 sf-exg 1.421 XSetWindowBackgroundPixmap (dpy, parent, bg_img->pm);
2531 sf-exg 1.364 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2532    
2533     transparent = true;
2534     }
2535     else
2536     # endif
2537     {
2538 sf-exg 1.380 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2539 sf-exg 1.421 XSetWindowBackgroundPixmap (dpy, vt, bg_img->pm);
2540 sf-exg 1.364 }
2541     }
2542     else
2543     #endif
2544     {
2545 sf-exg 1.380 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2546 sf-exg 1.364 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
2547     }
2548 root 1.290
2549 sf-exg 1.380 XClearWindow (dpy, parent);
2550 root 1.290
2551 mikachu 1.451 if (scrollBar.state && scrollBar.win)
2552 sf-exg 1.363 {
2553 sf-exg 1.364 if (transparent)
2554     XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
2555     else
2556 sf-exg 1.426 XSetWindowBackground (dpy, scrollBar.win, pix_colors[scrollBar.color ()]);
2557 sf-exg 1.394 scrollBar.state = SB_STATE_IDLE;
2558 sf-exg 1.363 scrollBar.show (0);
2559     }
2560 root 1.290
2561 sf-exg 1.364 if (refresh)
2562     {
2563     scr_clear ();
2564     scr_touch (true);
2565     }
2566 root 1.129 want_refresh = 1;
2567     }
2568    
2569 pcg 1.1 /* ------------------------------------------------------------------------- */
2570     void
2571 root 1.244 rxvt_term::scr_clear (bool really) NOTHROW
2572 pcg 1.1 {
2573 root 1.172 if (!mapped)
2574 pcg 1.11 return;
2575    
2576     num_scr_allow = 0;
2577     want_refresh = 1;
2578 pcg 1.43
2579     if (really)
2580 root 1.258 XClearWindow (dpy, vt);
2581 pcg 1.1 }
2582    
2583 root 1.219 void
2584 root 1.244 rxvt_term::scr_xor_rect (int beg_row, int beg_col, int end_row, int end_col, rend_t rstyle1, rend_t rstyle2) NOTHROW
2585 root 1.219 {
2586 root 1.228 int view_end = view_start + nrow;
2587 root 1.219 int row, col;
2588    
2589 root 1.228 for (row = max (beg_row, view_start); row <= min (end_row, view_end); row++)
2590 root 1.219 {
2591     text_t *stp = ROW(row).t;
2592     rend_t *srp = ROW(row).r;
2593    
2594     for (col = beg_col; col < end_col; col++)
2595     srp[col] ^= rstyle1;
2596    
2597     while (col-- > beg_col && (stp[col] == NOCHAR || unicode::is_space (stp[col])))
2598     srp[col] ^= rstyle2;
2599    
2600     if (++col < end_col)
2601     srp[col] ^= rstyle2;
2602     }
2603     }
2604    
2605     void
2606 root 1.244 rxvt_term::scr_xor_span (int beg_row, int beg_col, int end_row, int end_col, rend_t rstyle) NOTHROW
2607 root 1.219 {
2608 root 1.228 int view_end = view_start + nrow;
2609 root 1.219 int row, col;
2610    
2611 root 1.228 if (beg_row >= view_start)
2612 root 1.219 {
2613     col = beg_col;
2614     row = beg_row;
2615     }
2616     else
2617     {
2618     col = 0;
2619 root 1.228 row = view_start;
2620 root 1.219 }
2621    
2622     for (; row < min (end_row, view_end); row++, col = 0)
2623     for (rend_t *srp = ROW(row).r; col < ncol; col++)
2624 root 1.220 srp[col] ^= rstyle;
2625 root 1.219
2626     if (row == end_row)
2627     for (rend_t *srp = ROW(row).r; col < end_col; col++)
2628 root 1.220 srp[col] ^= rstyle;
2629 root 1.219 }
2630    
2631 pcg 1.1 /* ------------------------------------------------------------------------- */
2632 root 1.417 void ecb_hot
2633 root 1.244 rxvt_term::scr_reverse_selection () NOTHROW
2634 pcg 1.1 {
2635 root 1.175 if (selection.op
2636     && current_screen == selection.screen
2637 root 1.228 && selection.end.row >= view_start)
2638 pcg 1.25 {
2639 root 1.256 #if !ENABLE_MINIMAL
2640 root 1.136 if (selection.rect)
2641 root 1.219 scr_xor_rect (selection.beg.row, selection.beg.col,
2642     selection.end.row, selection.end.col,
2643 sf-exg 1.340 RS_Sel | RS_RVid, RS_Sel | RS_RVid | RS_Uline);
2644 pcg 1.25 else
2645 root 1.136 #endif
2646 root 1.219 scr_xor_span (selection.beg.row, selection.beg.col,
2647     selection.end.row, selection.end.col,
2648 sf-exg 1.340 RS_Sel | RS_RVid);
2649 pcg 1.1 }
2650     }
2651    
2652     /* ------------------------------------------------------------------------- */
2653     /*
2654     * Dump the whole scrollback and screen to the passed filedescriptor. The
2655     * invoking routine must close the fd.
2656     */
2657     #if 0
2658     void
2659 root 1.244 rxvt_term::scr_dump (int fd) NOTHROW
2660 pcg 1.1 {
2661 sf-exg 1.409 // if this method is needed, it can be implemented by factoring the
2662     // relevant code in scr_printscreen
2663 pcg 1.1 }
2664     #endif
2665 ayin 1.282
2666 pcg 1.1 /* ------------------------------------------------------------------------- *
2667     * CHARACTER SELECTION *
2668     * ------------------------------------------------------------------------- */
2669     void
2670 root 1.244 rxvt_term::selection_check (int check_more) NOTHROW
2671 pcg 1.1 {
2672 pcg 1.25 if (!selection.op)
2673     return;
2674 pcg 1.1
2675 root 1.228 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow)
2676 sf-exg 1.405 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow)
2677 root 1.228 || !IN_RANGE_EXC (selection.end.row, top_row, nrow)
2678 pcg 1.25 || (check_more == 1
2679     && current_screen == selection.screen
2680 pcg 1.30 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2681 sf-exg 1.407 && ROWCOL_IS_BEFORE (screen.cur, selection.end)))
2682 sf-exg 1.405 CLEAR_ALL_SELECTION ();
2683 pcg 1.1 }
2684    
2685 root 1.434 void
2686     rxvt_term::selection_changed () NOTHROW
2687     {
2688     line_t &r1 = ROW (selection.beg.row);
2689 sf-exg 1.444 while (selection.beg.col < r1.l && r1.t [selection.beg.col] == NOCHAR)
2690     ++selection.beg.col;
2691 root 1.434
2692     line_t &r2 = ROW (selection.end.row);
2693     while (selection.end.col < r2.l && r2.t [selection.end.col] == NOCHAR)
2694     ++selection.end.col;
2695    
2696     want_refresh = 1;
2697     }
2698    
2699 pcg 1.1 /* ------------------------------------------------------------------------- */
2700     /*
2701     * Paste a selection direct to the command fd
2702     */
2703     void
2704 sf-exg 1.345 rxvt_term::tt_paste (char *data, unsigned int len) NOTHROW
2705 pcg 1.1 {
2706 pcg 1.5 /* convert normal newline chars into common keyboard Return key sequence */
2707 root 1.150 for (unsigned int i = 0; i < len; i++)
2708     if (data[i] == C0_LF)
2709     data[i] = C0_CR;
2710 pcg 1.5
2711 ayin 1.298 if (priv_modes & PrivMode_BracketPaste)
2712 root 1.412 tt_printf ("\x1b[200~");
2713 ayin 1.298
2714 root 1.150 tt_write (data, len);
2715 ayin 1.298
2716     if (priv_modes & PrivMode_BracketPaste)
2717 root 1.412 tt_printf ("\x1b[201~");
2718 pcg 1.1 }
2719    
2720 sf-exg 1.345 void
2721     rxvt_term::paste (char *data, unsigned int len) NOTHROW
2722     {
2723     if (HOOK_INVOKE ((this, HOOK_TT_PASTE, DT_STR_LEN, data, len, DT_END)))
2724     return;
2725    
2726     tt_paste (data, len);
2727     }
2728    
2729 pcg 1.1 /* ------------------------------------------------------------------------- */
2730     /*
2731 sf-exg 1.382 * Request PRIMARY, SECONDARY or CLIPBOARD selection.
2732     * if the requested selection has no owner or is empty CUT_BUFFER0 is used
2733     * as fallback
2734 pcg 1.1 * EXT: button 2 release
2735     */
2736     void
2737 root 1.244 rxvt_term::selection_request (Time tm, int selnum) NOTHROW
2738 pcg 1.1 {
2739 sf-exg 1.378 if (!selection_req)
2740 pcg 1.25 {
2741 root 1.375 selection_req = new rxvt_selection (display, selnum, tm, vt, xa[XA_VT_SELECTION], this);
2742 sf-exg 1.373 selection_req->run ();
2743 pcg 1.1 }
2744     }
2745    
2746     /* ------------------------------------------------------------------------- */
2747     /*
2748     * Clear all selected text
2749     * EXT: SelectionClear
2750     */
2751     void
2752 sf-exg 1.333 rxvt_term::selection_clear (bool clipboard) NOTHROW
2753 pcg 1.1 {
2754 sf-exg 1.333 if (!clipboard)
2755     {
2756     want_refresh = 1;
2757     free (selection.text);
2758     selection.text = NULL;
2759     selection.len = 0;
2760     CLEAR_SELECTION ();
2761    
2762     if (display->selection_owner == this)
2763     display->selection_owner = 0;
2764     }
2765     else
2766     {
2767     free (selection.clip_text);
2768     selection.clip_text = NULL;
2769     selection.clip_len = 0;
2770    
2771     if (display->clipboard_owner == this)
2772     display->clipboard_owner = 0;
2773     }
2774     }
2775 pcg 1.66
2776 pcg 1.1 /* ------------------------------------------------------------------------- */
2777     /*
2778     * Copy a selection into the cut buffer
2779     * EXT: button 1 or 3 release
2780     */
2781     void
2782 pcg 1.21 rxvt_term::selection_make (Time tm)
2783 pcg 1.1 {
2784 sf-exg 1.357 int size;
2785 pcg 1.54 wchar_t *new_selection_text;
2786 pcg 1.43 text_t *t;
2787 pcg 1.1
2788 pcg 1.25 switch (selection.op)
2789     {
2790     case SELECTION_CONT:
2791 pcg 1.4 break;
2792 pcg 1.25 case SELECTION_INIT:
2793 pcg 1.30 CLEAR_SELECTION ();
2794 pcg 1.25 /* FALLTHROUGH */
2795     case SELECTION_BEGIN:
2796 pcg 1.21 selection.op = SELECTION_DONE;
2797 pcg 1.25 /* FALLTHROUGH */
2798     default:
2799 pcg 1.4 return;
2800 pcg 1.1 }
2801 pcg 1.39
2802 pcg 1.25 selection.op = SELECTION_DONE;
2803 pcg 1.1
2804 pcg 1.25 if (selection.clicks == 4)
2805     return; /* nothing selected, go away */
2806 pcg 1.1
2807 root 1.211 if (HOOK_INVOKE ((this, HOOK_SEL_MAKE, DT_LONG, (long)tm, DT_END)))
2808 root 1.204 return;
2809    
2810 sf-exg 1.357 size = (selection.end.row - selection.beg.row + 1) * (ncol + 1);
2811     new_selection_text = (wchar_t *)rxvt_malloc ((size + 4) * sizeof (wchar_t));
2812 pcg 1.1
2813 pcg 1.54 int ofs = 0;
2814     int extra = 0;
2815 pcg 1.1
2816 root 1.175 int col = selection.beg.col;
2817     int row = selection.beg.row;
2818    
2819     int end_col;
2820    
2821     for (; row <= selection.end.row; row++, col = 0)
2822 pcg 1.25 {
2823 root 1.256 #if !ENABLE_MINIMAL
2824 root 1.136 if (selection.rect)
2825     {
2826     col = selection.beg.col;
2827 sf-exg 1.359 end_col = selection.end.col;
2828 root 1.136 }
2829 root 1.173 else
2830 root 1.136 #endif
2831 root 1.210 end_col = ROW(row).l;
2832 pcg 1.1
2833 root 1.175 col = max (col, 0);
2834 pcg 1.1
2835 sf-exg 1.359 if (row == selection.end.row)
2836 root 1.199 min_it (end_col, selection.end.col);
2837 pcg 1.1
2838 root 1.175 t = ROW(row).t + col;
2839 root 1.210
2840 pcg 1.25 for (; col < end_col; col++)
2841 pcg 1.54 {
2842     if (*t == NOCHAR)
2843     t++;
2844 pcg 1.57 #if ENABLE_COMBINING
2845 pcg 1.54 else if (IS_COMPOSE (*t))
2846     {
2847     int len = rxvt_composite.expand (*t, 0);
2848    
2849     extra -= (len - 1);
2850    
2851     if (extra < 0)
2852     {
2853 sf-exg 1.357 extra += size;
2854     size += size;
2855     new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (size + 4) * sizeof (wchar_t));
2856 pcg 1.54 }
2857    
2858     ofs += rxvt_composite.expand (*t++, new_selection_text + ofs);
2859     }
2860 pcg 1.57 #endif
2861 pcg 1.54 else
2862     new_selection_text[ofs++] = *t++;
2863     }
2864 pcg 1.1
2865 root 1.256 #if !ENABLE_MINIMAL
2866 root 1.199 if (selection.rect)
2867     {
2868     while (ofs
2869     && new_selection_text[ofs - 1] != C0_LF
2870     && unicode::is_space (new_selection_text[ofs - 1]))
2871     --ofs;
2872    
2873     new_selection_text[ofs++] = C0_LF;
2874     }
2875     else
2876     #endif
2877 sf-exg 1.361 if (!ROW(row).is_longer ()
2878     && (row != selection.end.row || end_col != selection.end.col)
2879 sf-exg 1.358 && (row != selection.beg.row || selection.beg.col < ncol))
2880 root 1.199 new_selection_text[ofs++] = C0_LF;
2881 pcg 1.25 }
2882 pcg 1.1
2883 pcg 1.54 new_selection_text[ofs] = 0;
2884 pcg 1.1
2885 pcg 1.54 if (ofs == 0)
2886 pcg 1.25 {
2887     free (new_selection_text);
2888     return;
2889     }
2890 pcg 1.1
2891 pcg 1.54 free (selection.text);
2892 pcg 1.18
2893 pcg 1.54 // we usually allocate much more than necessary, so realloc it smaller again
2894     selection.len = ofs;
2895     selection.text = (wchar_t *)rxvt_realloc (new_selection_text, (ofs + 1) * sizeof (wchar_t));
2896 pcg 1.1
2897 root 1.211 if (HOOK_INVOKE ((this, HOOK_SEL_GRAB, DT_LONG, (long)tm, DT_END)))
2898 root 1.204 return;
2899    
2900     selection_grab (tm);
2901     }
2902    
2903     bool
2904 sf-exg 1.333 rxvt_term::selection_grab (Time tm, bool clipboard) NOTHROW
2905 root 1.204 {
2906 sf-exg 1.333 Atom sel;
2907    
2908     if (!clipboard)
2909     {
2910     selection_time = tm;
2911     sel = XA_PRIMARY;
2912     }
2913     else
2914     {
2915     clipboard_time = tm;
2916     sel = xa[XA_CLIPBOARD];
2917     }
2918 root 1.204
2919 sf-exg 1.333 XSetSelectionOwner (dpy, sel, vt, tm);
2920     if (XGetSelectionOwner (dpy, sel) == vt)
2921 root 1.204 {
2922 sf-exg 1.333 display->set_selection_owner (this, clipboard);
2923 root 1.204 return true;
2924     }
2925 pcg 1.28 else
2926 root 1.225 {
2927 sf-exg 1.333 selection_clear (clipboard);
2928 root 1.225 return false;
2929     }
2930 pcg 1.18
2931 pcg 1.54 #if 0
2932     XTextProperty ct;
2933 pcg 1.18
2934 root 1.258 if (XwcTextListToTextProperty (dpy, &selection.text, 1, XStringStyle, &ct) >= 0)
2935 pcg 1.54 {
2936 root 1.147 set_string_property (XA_CUT_BUFFER0, ct.value, ct.nitems);
2937 pcg 1.54 XFree (ct.value);
2938     }
2939     #endif
2940 pcg 1.1 }
2941    
2942     /* ------------------------------------------------------------------------- */
2943     /*
2944     * Mark or select text based upon number of clicks: 1, 2, or 3
2945     * EXT: button 1 press
2946     */
2947 root 1.417 void ecb_cold
2948 root 1.244 rxvt_term::selection_click (int clicks, int x, int y) NOTHROW
2949 pcg 1.1 {
2950 pcg 1.11 clicks = ((clicks - 1) % 3) + 1;
2951     selection.clicks = clicks; /* save clicks so extend will work */
2952 pcg 1.1
2953 root 1.224 if (clicks == 2 && !selection.rect
2954     && HOOK_INVOKE ((this, HOOK_SEL_EXTEND, DT_END)))
2955     {
2956     MEvent.clicks = 1; // what a mess
2957 root 1.226 selection.screen = current_screen;
2958     selection.op = SELECTION_CONT;
2959 root 1.224 return;
2960     }
2961    
2962 pcg 1.30 selection_start_colrow (Pixel2Col (x), Pixel2Row (y));
2963 pcg 1.11
2964     if (clicks == 2 || clicks == 3)
2965 pcg 1.21 selection_extend_colrow (selection.mark.col,
2966 root 1.228 selection.mark.row - view_start,
2967 pcg 1.25 0, /* button 3 */
2968     1, /* button press */
2969     0); /* click change */
2970 pcg 1.1 }
2971    
2972     /* ------------------------------------------------------------------------- */
2973     /*
2974     * Mark a selection at the specified col/row
2975     */
2976 root 1.417 void ecb_cold
2977 root 1.244 rxvt_term::selection_start_colrow (int col, int row) NOTHROW
2978 pcg 1.1 {
2979 pcg 1.25 want_refresh = 1;
2980 root 1.175
2981 root 1.228 selection.mark.row = row + view_start;
2982 pcg 1.25 selection.mark.col = col;
2983 pcg 1.59
2984 root 1.228 selection.mark.row = clamp (selection.mark.row, top_row, nrow - 1);
2985 root 1.180 selection.mark.col = clamp (selection.mark.col, 0, ncol - 1);
2986 pcg 1.25
2987 pcg 1.59 while (selection.mark.col > 0
2988 root 1.175 && ROW(selection.mark.row).t[selection.mark.col] == NOCHAR)
2989 pcg 1.59 --selection.mark.col;
2990 ayin 1.281
2991 pcg 1.25 if (selection.op)
2992 ayin 1.284 {
2993     /* clear the old selection */
2994 pcg 1.25 selection.beg.row = selection.end.row = selection.mark.row;
2995     selection.beg.col = selection.end.col = selection.mark.col;
2996 pcg 1.1 }
2997 pcg 1.59
2998 pcg 1.25 selection.op = SELECTION_INIT;
2999     selection.screen = current_screen;
3000 pcg 1.1 }
3001    
3002     /* ------------------------------------------------------------------------- */
3003     /*
3004     * Word select: select text for 2 clicks
3005     * We now only find out the boundary in one direction
3006     */
3007    
3008     /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
3009 root 1.434 #define DELIMIT_TEXT(x) \
3010 root 1.104 (unicode::is_space (x) ? 2 : (x) <= 0xff && !!strchr (rs[Rs_cutchars], (x)))
3011 pcg 1.7 #define DELIMIT_REND(x) 1
3012 pcg 1.1
3013 root 1.417 void ecb_cold
3014 root 1.244 rxvt_term::selection_delimit_word (enum page_dirn dirn, const row_col_t *mark, row_col_t *ret) NOTHROW
3015 pcg 1.1 {
3016 pcg 1.59 int col, row, dirnadd, tcol, trow, w1, w2;
3017     row_col_t bound;
3018     text_t *stp;
3019     rend_t *srp;
3020 pcg 1.25
3021     if (dirn == UP)
3022     {
3023 root 1.228 bound.row = top_row - 1;
3024 pcg 1.25 bound.col = 0;
3025     dirnadd = -1;
3026     }
3027     else
3028     {
3029 root 1.175 bound.row = nrow;
3030 root 1.172 bound.col = ncol - 1;
3031 pcg 1.25 dirnadd = 1;
3032     }
3033 pcg 1.59
3034 root 1.175 row = mark->row;
3035     col = max (mark->col, 0);
3036    
3037 pcg 1.25 /* find the edge of a word */
3038 root 1.175 stp = ROW(row).t + col; w1 = DELIMIT_TEXT (*stp);
3039     srp = ROW(row).r + col; w2 = DELIMIT_REND (*srp);
3040 pcg 1.25
3041     for (;;)
3042     {
3043     for (; col != bound.col; col += dirnadd)
3044     {
3045     stp += dirnadd;
3046 pcg 1.59 srp += dirnadd;
3047    
3048     if (*stp == NOCHAR)
3049     continue;
3050    
3051 pcg 1.30 if (DELIMIT_TEXT (*stp) != w1)
3052 pcg 1.25 break;
3053 pcg 1.30 if (DELIMIT_REND (*srp) != w2)
3054 pcg 1.25 break;
3055     }
3056 pcg 1.59
3057 pcg 1.25 if ((col == bound.col) && (row != bound.row))
3058     {
3059 root 1.175 if (ROW(row - (dirn == UP ? 1 : 0)).is_longer ())
3060 pcg 1.25 {
3061     trow = row + dirnadd;
3062 root 1.172 tcol = dirn == UP ? ncol - 1 : 0;
3063 pcg 1.59
3064 root 1.175 if (!ROW(trow).t)
3065 pcg 1.4 break;
3066 pcg 1.59
3067 root 1.175 stp = ROW(trow).t + tcol;
3068     srp = ROW(trow).r + tcol;
3069 pcg 1.59
3070 pcg 1.30 if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2)
3071 pcg 1.4 break;
3072 pcg 1.59
3073 pcg 1.25 row = trow;
3074     col = tcol;
3075     continue;
3076 pcg 1.4 }
3077     }
3078 pcg 1.25 break;
3079 pcg 1.1 }
3080 pcg 1.59
3081 pcg 1.25 if (dirn == DN)
3082     col++; /* put us on one past the end */
3083 pcg 1.1
3084 pcg 1.25 /* Poke the values back in */
3085 root 1.175 ret->row = row;
3086 pcg 1.25 ret->col = col;
3087 pcg 1.1 }
3088    
3089     /* ------------------------------------------------------------------------- */
3090     /*
3091     * Extend the selection to the specified x/y pixel location
3092     * EXT: button 3 press; button 1 or 3 drag
3093     * flag == 0 ==> button 1
3094     * flag == 1 ==> button 3 press
3095     * flag == 2 ==> button 3 motion
3096     */
3097 root 1.417 void ecb_cold
3098 root 1.244 rxvt_term::selection_extend (int x, int y, int flag) NOTHROW
3099 pcg 1.1 {
3100 root 1.180 int col = clamp (Pixel2Col (x), 0, ncol);
3101     int row = clamp (Pixel2Row (y), 0, nrow - 1);
3102 pcg 1.1
3103 pcg 1.11 /*
3104     * If we're selecting characters (single click) then we must check first
3105     * if we are at the same place as the original mark. If we are then
3106     * select nothing. Otherwise, if we're to the right of the mark, you have to
3107     * be _past_ a character for it to be selected.
3108     */
3109 pcg 1.59 if (((selection.clicks % 3) == 1) && !flag
3110     && (col == selection.mark.col
3111 root 1.228 && (row == selection.mark.row - view_start)))
3112 pcg 1.59 {
3113     /* select nothing */
3114     selection.beg.row = selection.end.row = 0;
3115     selection.beg.col = selection.end.col = 0;
3116     selection.clicks = 4;
3117     want_refresh = 1;
3118     return;
3119 pcg 1.1 }
3120 pcg 1.59
3121 pcg 1.11 if (selection.clicks == 4)
3122     selection.clicks = 1;
3123    
3124 pcg 1.21 selection_extend_colrow (col, row, !!flag, /* ? button 3 */
3125 pcg 1.25 flag == 1 ? 1 : 0, /* ? button press */
3126     0); /* no click change */
3127 pcg 1.1 }
3128    
3129     /* ------------------------------------------------------------------------- */
3130     /*
3131     * Extend the selection to the specified col/row
3132     */
3133 root 1.417 void ecb_cold
3134 root 1.244 rxvt_term::selection_extend_colrow (int32_t col, int32_t row, int button3, int buttonpress, int clickchange) NOTHROW
3135 pcg 1.1 {
3136 pcg 1.71 row_col_t pos;
3137 pcg 1.25 enum {
3138     LEFT, RIGHT
3139     } closeto = RIGHT;
3140    
3141     switch (selection.op)
3142     {
3143     case SELECTION_INIT:
3144 pcg 1.30 CLEAR_SELECTION ();
3145 pcg 1.21 selection.op = SELECTION_BEGIN;
3146 pcg 1.25 /* FALLTHROUGH */
3147     case SELECTION_BEGIN:
3148 pcg 1.21 if (row != selection.mark.row || col != selection.mark.col
3149 pcg 1.4 || (!button3 && buttonpress))
3150 pcg 1.25 selection.op = SELECTION_CONT;
3151 pcg 1.4 break;
3152 pcg 1.25 case SELECTION_DONE:
3153 pcg 1.21 selection.op = SELECTION_CONT;
3154 pcg 1.25 /* FALLTHROUGH */
3155     case SELECTION_CONT:
3156 pcg 1.4 break;
3157 pcg 1.25 case SELECTION_CLEAR:
3158 pcg 1.21 selection_start_colrow (col, row);
3159 pcg 1.25 /* FALLTHROUGH */
3160     default:
3161 pcg 1.4 return;
3162 pcg 1.1 }
3163 root 1.136
3164 pcg 1.25 if (selection.beg.col == selection.end.col
3165     && selection.beg.col != selection.mark.col
3166     && selection.beg.row == selection.end.row
3167     && selection.beg.row != selection.mark.row)
3168     {
3169     selection.beg.col = selection.end.col = selection.mark.col;
3170     selection.beg.row = selection.end.row = selection.mark.row;
3171 pcg 1.1 }
3172    
3173 pcg 1.25 pos.col = col;
3174 root 1.228 pos.row = view_start + row;
3175 pcg 1.1
3176 pcg 1.25 /*
3177     * This is mainly xterm style selection with a couple of differences, mainly
3178     * in the way button3 drag extension works.
3179     * We're either doing: button1 drag; button3 press; or button3 drag
3180     * a) button1 drag : select around a midpoint/word/line - that point/word/line
3181     * is always at the left/right edge of the selection.
3182     * b) button3 press: extend/contract character/word/line at whichever edge of
3183     * the selection we are closest to.
3184     * c) button3 drag : extend/contract character/word/line - we select around
3185     * a point/word/line which is either the start or end of the selection
3186     * and it was decided by whichever point/word/line was `fixed' at the
3187     * time of the most recent button3 press
3188     */
3189     if (button3 && buttonpress)
3190 ayin 1.284 {
3191     /* button3 press */
3192 pcg 1.25 /*
3193     * first determine which edge of the selection we are closest to
3194     */
3195 pcg 1.30 if (ROWCOL_IS_BEFORE (pos, selection.beg)
3196     || (!ROWCOL_IS_AFTER (pos, selection.end)
3197 pcg 1.25 && (((pos.col - selection.beg.col)
3198     + ((pos.row - selection.beg.row) * ncol))
3199     < ((selection.end.col - pos.col)
3200     + ((selection.end.row - pos.row) * ncol)))))
3201     closeto = LEFT;
3202 pcg 1.59
3203 pcg 1.25 if (closeto == LEFT)
3204     {
3205     selection.beg.row = pos.row;
3206     selection.beg.col = pos.col;
3207     selection.mark.row = selection.end.row;
3208 pcg 1.59 selection.mark.col = selection.end.col - (selection.clicks == 2);
3209 pcg 1.25 }
3210     else
3211     {
3212     selection.end.row = pos.row;
3213     selection.end.col = pos.col;
3214     selection.mark.row = selection.beg.row;
3215     selection.mark.col = selection.beg.col;
3216     }
3217     }
3218     else
3219 ayin 1.284 {
3220     /* button1 drag or button3 drag */
3221 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, pos))
3222 pcg 1.25 {
3223 root 1.136 if (selection.mark.row == selection.end.row
3224     && selection.mark.col == selection.end.col
3225     && clickchange
3226     && selection.clicks == 2)
3227 pcg 1.25 selection.mark.col--;
3228 pcg 1.59
3229 pcg 1.25 selection.beg.row = pos.row;
3230     selection.beg.col = pos.col;
3231     selection.end.row = selection.mark.row;
3232 pcg 1.59 selection.end.col = selection.mark.col + (selection.clicks == 2);
3233 pcg 1.25 }
3234     else
3235     {
3236     selection.beg.row = selection.mark.row;
3237     selection.beg.col = selection.mark.col;
3238     selection.end.row = pos.row;
3239     selection.end.col = pos.col;
3240 pcg 1.4 }
3241 pcg 1.1 }
3242    
3243 pcg 1.25 if (selection.clicks == 1)
3244     {
3245 root 1.175 if (selection.beg.col > ROW(selection.beg.row).l //TODO//FIXME//LEN
3246     && !ROW(selection.beg.row).is_longer ()
3247 root 1.256 #if !ENABLE_MINIMAL
3248 root 1.136 && !selection.rect
3249 pcg 1.4 #endif
3250 root 1.136 )
3251     selection.beg.col = ncol;
3252 pcg 1.25
3253 root 1.136 if (
3254 root 1.175 selection.end.col > ROW(selection.end.row).l //TODO//FIXME//LEN
3255     && !ROW(selection.end.row).is_longer ()
3256 root 1.256 #if !ENABLE_MINIMAL
3257 root 1.136 && !selection.rect
3258     #endif
3259     )
3260 pcg 1.25 selection.end.col = ncol;
3261     }
3262     else if (selection.clicks == 2)
3263     {
3264 pcg 1.30 if (ROWCOL_IS_AFTER (selection.end, selection.beg))
3265 pcg 1.25 selection.end.col--;
3266 pcg 1.59
3267 root 1.224 selection_delimit_word (UP, &selection.beg, &selection.beg);
3268     selection_delimit_word (DN, &selection.end, &selection.end);
3269 pcg 1.25 }
3270     else if (selection.clicks == 3)
3271     {
3272 root 1.104 #if ENABLE_FRILLS
3273 root 1.268 if (option (Opt_tripleclickwords))
3274 pcg 1.25 {
3275 root 1.139 selection_delimit_word (UP, &selection.beg, &selection.beg);
3276 pcg 1.59
3277 root 1.174 for (int end_row = selection.mark.row; end_row < nrow; end_row++)
3278 pcg 1.25 {
3279 root 1.175 if (!ROW(end_row).is_longer ())
3280 pcg 1.25 {
3281     selection.end.row = end_row;
3282 root 1.176 selection.end.col = ROW(end_row).l;
3283 root 1.256 # if !ENABLE_MINIMAL
3284 pcg 1.25 selection_remove_trailing_spaces ();
3285 root 1.256 # endif
3286 pcg 1.25 break;
3287 pcg 1.4 }
3288     }
3289 pcg 1.25 }
3290     else
3291 pcg 1.4 #endif
3292     {
3293 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, selection.beg))
3294 pcg 1.25 selection.mark.col++;
3295 root 1.136
3296 pcg 1.25 selection.beg.col = 0;
3297     selection.end.col = ncol;
3298 root 1.155
3299     // select a complete logical line
3300 root 1.172 while (selection.beg.row > -saveLines
3301 root 1.175 && ROW(selection.beg.row - 1).is_longer ())
3302 root 1.155 selection.beg.row--;
3303    
3304 root 1.172 while (selection.end.row < nrow
3305 root 1.175 && ROW(selection.end.row).is_longer ())
3306 root 1.155 selection.end.row++;
3307 pcg 1.4 }
3308     }
3309 pcg 1.59
3310 pcg 1.25 if (button3 && buttonpress)
3311 ayin 1.284 {
3312     /* mark may need to be changed */
3313 pcg 1.25 if (closeto == LEFT)
3314     {
3315     selection.mark.row = selection.end.row;
3316 root 1.104 selection.mark.col = selection.end.col - (selection.clicks == 2);
3317 pcg 1.25 }
3318     else
3319     {
3320     selection.mark.row = selection.beg.row;
3321     selection.mark.col = selection.beg.col;
3322 pcg 1.4 }
3323 pcg 1.1 }
3324 root 1.136
3325 root 1.256 #if !ENABLE_MINIMAL
3326 root 1.136 if (selection.rect && selection.beg.col > selection.end.col)
3327 root 1.182 ::swap (selection.beg.col, selection.end.col);
3328 root 1.136 #endif
3329 root 1.434
3330     selection_changed ();
3331 pcg 1.1 }
3332    
3333 root 1.256 #if !ENABLE_MINIMAL
3334 root 1.417 void ecb_cold
3335 root 1.244 rxvt_term::selection_remove_trailing_spaces () NOTHROW
3336 pcg 1.1 {
3337 root 1.136 int32_t end_col, end_row;
3338     text_t *stp;
3339 pcg 1.1
3340 pcg 1.25 end_col = selection.end.col;
3341     end_row = selection.end.row;
3342 root 1.136
3343 root 1.175 for (; end_row >= selection.beg.row; )
3344 pcg 1.25 {
3345 root 1.175 stp = ROW(end_row).t;
3346 root 1.136
3347 pcg 1.25 while (--end_col >= 0)
3348     {
3349 root 1.199 if (stp[end_col] != NOCHAR
3350     && !unicode::is_space (stp[end_col]))
3351 pcg 1.25 break;
3352 pcg 1.4 }
3353 root 1.136
3354 pcg 1.25 if (end_col >= 0
3355 root 1.175 || !ROW(end_row - 1).is_longer ())
3356 pcg 1.25 {
3357     selection.end.col = end_col + 1;
3358     selection.end.row = end_row;
3359     break;
3360 pcg 1.4 }
3361 root 1.136
3362 pcg 1.25 end_row--;
3363 root 1.172 end_col = ncol;
3364 pcg 1.25 }
3365 root 1.136
3366 pcg 1.25 if (selection.mark.row > selection.end.row)
3367     {
3368     selection.mark.row = selection.end.row;
3369     selection.mark.col = selection.end.col;
3370 pcg 1.1 }
3371 pcg 1.25 else if (selection.mark.row == selection.end.row
3372     && selection.mark.col > selection.end.col)
3373     selection.mark.col = selection.end.col;
3374 pcg 1.1 }
3375     #endif
3376    
3377     /* ------------------------------------------------------------------------- */
3378     /*
3379     * Double click on button 3 when already selected
3380     * EXT: button 3 double click
3381     */
3382 root 1.417 void ecb_cold
3383 root 1.244 rxvt_term::selection_rotate (int x, int y) NOTHROW
3384 pcg 1.1 {
3385 pcg 1.11 selection.clicks = selection.clicks % 3 + 1;
3386 pcg 1.30 selection_extend_colrow (Pixel2Col (x), Pixel2Row (y), 1, 0, 1);
3387 pcg 1.1 }
3388    
3389     /* ------------------------------------------------------------------------- */
3390     /*
3391     * Respond to a request for our current selection
3392     * EXT: SelectionRequest
3393     */
3394 root 1.417 void ecb_cold
3395 root 1.244 rxvt_term::selection_send (const XSelectionRequestEvent &rq) NOTHROW
3396 pcg 1.1 {
3397 sf-exg 1.381 Atom property = rq.property == None ? rq.target : rq.property;
3398 pcg 1.25 XSelectionEvent ev;
3399    
3400     ev.type = SelectionNotify;
3401     ev.property = None;
3402 pcg 1.27 ev.display = rq.display;
3403     ev.requestor = rq.requestor;
3404     ev.selection = rq.selection;
3405     ev.target = rq.target;
3406     ev.time = rq.time;
3407 pcg 1.25
3408 pcg 1.27 if (rq.target == xa[XA_TARGETS])
3409 pcg 1.25 {
3410 root 1.139 Atom target_list[6];
3411     Atom *target = target_list;
3412 pcg 1.1
3413 root 1.139 *target++ = xa[XA_TARGETS];
3414     *target++ = xa[XA_TIMESTAMP];
3415     *target++ = XA_STRING;
3416     *target++ = xa[XA_TEXT];
3417     *target++ = xa[XA_COMPOUND_TEXT];
3418 pcg 1.18 #if X_HAVE_UTF8_STRING
3419 root 1.139 *target++ = xa[XA_UTF8_STRING];
3420 pcg 1.1 #endif
3421 pcg 1.54
3422 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property, XA_ATOM,
3423 root 1.139 32, PropModeReplace,
3424     (unsigned char *)target_list, target - target_list);
3425 sf-exg 1.381 ev.property = property;
3426 pcg 1.25 }
3427 root 1.89 #if TODO // TODO
3428 pcg 1.27 else if (rq.target == xa[XA_MULTIPLE])
3429 pcg 1.25 {
3430     /* TODO: Handle MULTIPLE */
3431     }
3432 root 1.89 #endif
3433 sf-exg 1.333 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == XA_PRIMARY && selection.text)
3434 pcg 1.25 {
3435 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property, rq.target,
3436 root 1.139 32, PropModeReplace, (unsigned char *)&selection_time, 1);
3437 sf-exg 1.381 ev.property = property;
3438 pcg 1.25 }
3439 sf-exg 1.333 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3440     {
3441 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property, rq.target,
3442 sf-exg 1.333 32, PropModeReplace, (unsigned char *)&clipboard_time, 1);
3443 sf-exg 1.381 ev.property = property;
3444 sf-exg 1.333 }
3445 pcg 1.27 else if (rq.target == XA_STRING
3446     || rq.target == xa[XA_TEXT]
3447     || rq.target == xa[XA_COMPOUND_TEXT]
3448     || rq.target == xa[XA_UTF8_STRING]
3449 pcg 1.25 )
3450     {
3451 root 1.147 XTextProperty ct;
3452     Atom target = rq.target;
3453 pcg 1.25 short freect = 0;
3454     int selectlen;
3455 pcg 1.54 wchar_t *cl;
3456 root 1.147 enum {
3457     enc_string = XStringStyle,
3458     enc_text = XStdICCTextStyle,
3459     enc_compound_text = XCompoundTextStyle,
3460     #ifdef X_HAVE_UTF8_STRING
3461     enc_utf8 = XUTF8StringStyle,
3462     #else
3463     enc_utf8 = -1,
3464     #endif
3465     } style;
3466 pcg 1.25
3467     if (target == XA_STRING)
3468     // we actually don't do XA_STRING, but who cares, as i18n clients
3469     // will ask for another format anyways.
3470 root 1.147 style = enc_string;
3471 pcg 1.25 else if (target == xa[XA_TEXT])
3472 root 1.147 style = enc_text;
3473 pcg 1.25 else if (target == xa[XA_COMPOUND_TEXT])
3474 root 1.147 style = enc_compound_text;
3475 root 1.256 #if !ENABLE_MINIMAL
3476 pcg 1.25 else if (target == xa[XA_UTF8_STRING])
3477 root 1.147 style = enc_utf8;
3478 pcg 1.1 #endif
3479 pcg 1.25 else
3480     {
3481     target = xa[XA_COMPOUND_TEXT];
3482 root 1.147 style = enc_compound_text;
3483 pcg 1.25 }
3484 pcg 1.1
3485 sf-exg 1.333 if (rq.selection == XA_PRIMARY && selection.text)
3486 pcg 1.25 {
3487 pcg 1.54 cl = selection.text;
3488 pcg 1.25 selectlen = selection.len;
3489     }
3490 sf-exg 1.333 else if (rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3491     {
3492     cl = selection.clip_text;
3493     selectlen = selection.clip_len;
3494     }
3495 pcg 1.25 else
3496     {
3497 pcg 1.54 cl = L"";
3498 pcg 1.25 selectlen = 0;
3499 pcg 1.4 }
3500 pcg 1.18
3501 root 1.256 #if !ENABLE_MINIMAL
3502 root 1.147 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
3503     // so recode it manually
3504     if (style == enc_utf8)
3505     {
3506     freect = 1;
3507     ct.encoding = target;
3508     ct.format = 8;
3509     ct.value = (unsigned char *)rxvt_wcstoutf8 (cl, selectlen);
3510     ct.nitems = strlen ((char *)ct.value);
3511     }
3512     else
3513     #endif
3514 root 1.258 if (XwcTextListToTextProperty (dpy, &cl, 1, (XICCEncodingStyle) style, &ct) >= 0)
3515 pcg 1.25 freect = 1;
3516     else
3517     {
3518     /* if we failed to convert then send it raw */
3519     ct.value = (unsigned char *)cl;
3520     ct.nitems = selectlen;
3521 root 1.147 ct.encoding = target;
3522 pcg 1.25 }
3523 pcg 1.18
3524 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property,
3525 root 1.147 ct.encoding, 8, PropModeReplace,
3526 pcg 1.27 ct.value, (int)ct.nitems);
3527 sf-exg 1.381 ev.property = property;
3528 pcg 1.18
3529 pcg 1.25 if (freect)
3530     XFree (ct.value);
3531 pcg 1.1 }
3532 pcg 1.54
3533 root 1.258 XSendEvent (dpy, rq.requestor, False, 0L, (XEvent *)&ev);
3534 pcg 1.1 }
3535 ayin 1.281
3536 pcg 1.1 /* ------------------------------------------------------------------------- */
3537 root 1.420 #if USE_XIM
3538 root 1.417 void ecb_cold
3539 root 1.244 rxvt_term::im_set_position (XPoint &pos) NOTHROW
3540 pcg 1.1 {
3541 pcg 1.11 XWindowAttributes xwa;
3542 pcg 1.1
3543 root 1.258 XGetWindowAttributes (dpy, vt, &xwa);
3544 root 1.104
3545     pos.x = xwa.x + Col2Pixel (screen.cur.col);
3546 root 1.172 pos.y = xwa.y + Height2Pixel (screen.cur.row) + fbase;
3547 root 1.104 }
3548     #endif
3549    
3550     #if ENABLE_OVERLAY
3551     void
3552 root 1.244 rxvt_term::scr_overlay_new (int x, int y, int w, int h) NOTHROW
3553 root 1.104 {
3554 root 1.204 if (nrow < 1 || ncol < 1)
3555 root 1.104 return;
3556    
3557     want_refresh = 1;
3558    
3559     scr_overlay_off ();
3560    
3561 root 1.172 if (x < 0) x = ncol - w;
3562     if (y < 0) y = nrow - h;
3563 root 1.104
3564     // make space for border
3565 root 1.183 w += 2; min_it (w, ncol);
3566     h += 2; min_it (h, nrow);
3567 root 1.104
3568 root 1.186 x -= 1; clamp_it (x, 0, ncol - w);
3569     y -= 1; clamp_it (y, 0, nrow - h);
3570 root 1.104
3571 root 1.327 ov.x = x; ov.y = y;
3572     ov.w = w; ov.h = h;
3573 root 1.104
3574 root 1.327 ov.text = new text_t *[h];
3575     ov.rend = new rend_t *[h];
3576 root 1.104
3577     for (y = 0; y < h; y++)
3578     {
3579 root 1.327 text_t *tp = ov.text[y] = new text_t[w];
3580     rend_t *rp = ov.rend[y] = new rend_t[w];
3581 root 1.104
3582     text_t t0, t1, t2;
3583 root 1.129 rend_t r = OVERLAY_RSTYLE;
3584 root 1.104
3585     if (y == 0)
3586     t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
3587     else if (y < h - 1)
3588     t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
3589     else
3590     t0 = 0x255a, t1 = 0x2550, t2 = 0x255d;
3591    
3592     *tp++ = t0;
3593     *rp++ = r;
3594    
3595     for (x = w - 2; x > 0; --x)
3596     {
3597     *tp++ = t1;
3598     *rp++ = r;
3599     }
3600    
3601     *tp = t2;
3602     *rp = r;
3603     }
3604     }
3605    
3606     void
3607 root 1.244 rxvt_term::scr_overlay_off () NOTHROW
3608 root 1.104 {
3609 root 1.327 if (!ov.text)
3610 root 1.104 return;
3611    
3612     want_refresh = 1;
3613    
3614 root 1.327 for (int y = 0; y < ov.h; y++)
3615 root 1.104 {
3616 root 1.327 delete [] ov.text[y];
3617     delete [] ov.rend[y];
3618 root 1.104 }
3619    
3620 root 1.327 delete [] ov.text; ov.text = 0;
3621     delete [] ov.rend; ov.rend = 0;
3622 root 1.104 }
3623    
3624     void
3625 root 1.244 rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) NOTHROW
3626 root 1.104 {
3627 root 1.327 if (!ov.text || x >= ov.w - 2 || y >= ov.h - 2)
3628 root 1.104 return;
3629    
3630     x++, y++;
3631    
3632 root 1.327 ov.text[y][x] = text;
3633     ov.rend[y][x] = rend;
3634 root 1.104 }
3635    
3636     void
3637 root 1.244 rxvt_term::scr_overlay_set (int x, int y, const char *s) NOTHROW
3638 root 1.104 {
3639     while (*s)
3640     scr_overlay_set (x++, y, *s++);
3641     }
3642    
3643     void
3644 root 1.244 rxvt_term::scr_overlay_set (int x, int y, const wchar_t *s) NOTHROW
3645 root 1.163 {
3646     while (*s)
3647     {
3648     text_t t = *s++;
3649 root 1.250 int width = WCWIDTH (t);
3650 root 1.163
3651     while (width--)
3652     {
3653     scr_overlay_set (x++, y, t);
3654     t = NOCHAR;
3655     }
3656     }
3657     }
3658    
3659     void
3660 root 1.244 rxvt_term::scr_swap_overlay () NOTHROW
3661 root 1.104 {
3662 root 1.327 if (!ov.text)
3663 root 1.104 return;
3664    
3665 root 1.327 // hide cursor if it is within the overlay area
3666     if (IN_RANGE_EXC (screen.cur.col - ov.x, 0, ov.w)
3667     && IN_RANGE_EXC (screen.cur.row - ov.y, 0, ov.h))
3668     screen.flags &= ~Screen_VisibleCursor;
3669    
3670 root 1.104 // swap screen mem with overlay
3671 root 1.327 for (int y = ov.h; y--; )
3672 root 1.104 {
3673 root 1.327 text_t *t1 = ov.text[y];
3674     rend_t *r1 = ov.rend[y];
3675 root 1.104
3676 root 1.327 text_t *t2 = ROW(y + ov.y + view_start).t + ov.x;
3677     rend_t *r2 = ROW(y + ov.y + view_start).r + ov.x;
3678 root 1.104
3679 root 1.327 for (int x = ov.w; x--; )
3680 root 1.104 {
3681     text_t t = *t1; *t1++ = *t2; *t2++ = t;
3682 root 1.129 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t));
3683 root 1.104 }
3684     }
3685 pcg 1.1 }
3686 pcg 1.11
3687 pcg 1.1 #endif
3688     /* ------------------------------------------------------------------------- */
3689 root 1.175