ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.428
Committed: Sun Jan 13 17:42:24 2013 UTC (11 years, 4 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.427: +1 -0 lines
Log Message:
Fix bug introduced in 2012-05-28 change.

If no scrollback exists and the terminal is resized, the lengths of the
lines copied from the old screen buffer the new one are not properly
initialized, causing artifacts on scrolling if saveLines is 0 (due to an
optimization in scr_scroll_text). Bug reported by Bert Münnich.

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 pcg 1.1 *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *--------------------------------------------------------------------------*/
22 pcg 1.38
23 pcg 1.1 /*
24 pcg 1.38 * This file handles _all_ screen updates and selections
25 pcg 1.1 */
26    
27 pcg 1.4 #include "../config.h" /* NECESSARY */
28     #include "rxvt.h" /* NECESSARY */
29 root 1.204 #include "rxvtperl.h" /* NECESSARY */
30 pcg 1.1
31 root 1.78 #include <inttypes.h>
32 pcg 1.1
33 sf-exg 1.343 static inline void
34     fill_text (text_t *start, text_t value, int len)
35 pcg 1.1 {
36     while (len--)
37     *start++ = value;
38     }
39    
40     /* ------------------------------------------------------------------------- */
41 pcg 1.4 #define TABSIZE 8 /* default tab size */
42 pcg 1.1
43     /* ------------------------------------------------------------------------- *
44     * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
45     * ------------------------------------------------------------------------- */
46 pcg 1.21 #define ZERO_SCROLLBACK() \
47 root 1.268 if (option (Opt_scrollTtyOutput)) \
48 root 1.172 view_start = 0
49 pcg 1.21 #define CLEAR_SELECTION() \
50 root 1.77 selection.beg.row = selection.beg.col \
51 pcg 1.21 = selection.end.row = selection.end.col = 0
52 sf-exg 1.405 #define CLEAR_ALL_SELECTION() \
53     selection.beg.row = selection.beg.col \
54     = selection.mark.row = selection.mark.col \
55     = selection.end.row = selection.end.col = 0
56 pcg 1.1
57 root 1.77 #define ROW_AND_COL_IS_AFTER(A, B, C, D) \
58 pcg 1.1 (((A) > (C)) || (((A) == (C)) && ((B) > (D))))
59 root 1.77 #define ROW_AND_COL_IS_BEFORE(A, B, C, D) \
60 pcg 1.1 (((A) < (C)) || (((A) == (C)) && ((B) < (D))))
61 root 1.77 #define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D) \
62 pcg 1.1 (((A) == (C)) && ((B) > (D)))
63 root 1.77 #define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D) \
64 pcg 1.1 (((A) == (C)) && ((B) >= (D)))
65 root 1.77 #define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D) \
66 pcg 1.1 (((A) == (C)) && ((B) < (D)))
67 root 1.77 #define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D) \
68 pcg 1.1 (((A) == (C)) && ((B) <= (D)))
69    
70     /* these must be row_col_t */
71 root 1.77 #define ROWCOL_IS_AFTER(X, Y) \
72 pcg 1.30 ROW_AND_COL_IS_AFTER ((X).row, (X).col, (Y).row, (Y).col)
73 root 1.77 #define ROWCOL_IS_BEFORE(X, Y) \
74 pcg 1.30 ROW_AND_COL_IS_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
75 root 1.77 #define ROWCOL_IN_ROW_AFTER(X, Y) \
76 pcg 1.30 ROW_AND_COL_IN_ROW_AFTER ((X).row, (X).col, (Y).row, (Y).col)
77 root 1.77 #define ROWCOL_IN_ROW_BEFORE(X, Y) \
78 pcg 1.30 ROW_AND_COL_IN_ROW_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
79 root 1.77 #define ROWCOL_IN_ROW_AT_OR_AFTER(X, Y) \
80 pcg 1.30 ROW_AND_COL_IN_ROW_AT_OR_AFTER ((X).row, (X).col, (Y).row, (Y).col)
81 root 1.77 #define ROWCOL_IN_ROW_AT_OR_BEFORE(X, Y) \
82 pcg 1.30 ROW_AND_COL_IN_ROW_AT_OR_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
83 pcg 1.1
84     /*
85     * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
86     */
87 root 1.77 #define CLEAR_CHARS(x, y, num) \
88 root 1.299 if (mapped) \
89     XClearArea (dpy, vt, x, y, \
90 root 1.77 (unsigned int)Width2Pixel (num), \
91 pcg 1.30 (unsigned int)Height2Pixel (1), False)
92 pcg 1.4
93 pcg 1.1 /* ------------------------------------------------------------------------- *
94     * SCREEN `COMMON' ROUTINES *
95     * ------------------------------------------------------------------------- */
96 root 1.129
97 pcg 1.1 /* Fill part/all of a line with blanks. */
98     void
99 root 1.244 rxvt_term::scr_blank_line (line_t &l, unsigned int col, unsigned int width, rend_t efs) const NOTHROW
100 pcg 1.1 {
101 root 1.415 if (!l.valid ())
102 root 1.175 {
103 root 1.415 l.alloc ();
104 root 1.175 col = 0;
105     width = ncol;
106     }
107    
108 root 1.210 l.touch ();
109    
110 root 1.254 efs &= ~RS_baseattrMask; // remove italic etc. fontstyles
111 root 1.129 efs = SET_FONT (efs, FONTSET (efs)->find_font (' '));
112 pcg 1.1
113 root 1.172 text_t *et = l.t + col;
114     rend_t *er = l.r + col;
115    
116 pcg 1.8 while (width--)
117     {
118     *et++ = ' ';
119     *er++ = efs;
120     }
121 pcg 1.1 }
122    
123     /* ------------------------------------------------------------------------- */
124     /* Fill a full line with blanks - make sure it is allocated first */
125     void
126 root 1.244 rxvt_term::scr_blank_screen_mem (line_t &l, rend_t efs) const NOTHROW
127 pcg 1.1 {
128 root 1.172 scr_blank_line (l, 0, ncol, efs);
129 root 1.215
130     l.l = 0;
131     l.f = 0;
132 pcg 1.1 }
133    
134 root 1.313 // nuke a single wide character at the given column
135     void
136     rxvt_term::scr_kill_char (line_t &l, int col) const NOTHROW
137     {
138     // find begin
139     while (col > 0 && l.t[col] == NOCHAR)
140     col--;
141    
142     rend_t rend = l.r[col] & ~RS_baseattrMask;
143     rend = SET_FONT (rend, FONTSET (rend)->find_font (' '));
144    
145 root 1.352 l.touch ();
146    
147 root 1.316 // found start, nuke
148 root 1.313 do {
149     l.t[col] = ' ';
150     l.r[col] = rend;
151     col++;
152     } while (col < ncol && l.t[col] == NOCHAR);
153     }
154    
155 pcg 1.1 /* ------------------------------------------------------------------------- *
156     * SCREEN INITIALISATION *
157     * ------------------------------------------------------------------------- */
158 root 1.186
159 pcg 1.1 void
160 root 1.417 rxvt_term::scr_alloc () NOTHROW
161 root 1.415 {
162     int tsize = sizeof (text_t) * ncol;
163     int rsize = sizeof (rend_t) * ncol;
164    
165     // we assume that rend_t size is a sufficient alignment
166 sf-exg 1.418 // factor for text_t and line_t values, and we only
167 root 1.415 // need to adjust tsize.
168     tsize = (tsize + sizeof (rend_t) - 1);
169     tsize -= tsize % sizeof (rend_t);
170    
171     int all_rows = total_rows + nrow + nrow;
172    
173     chunk_size = (sizeof (line_t) + rsize + tsize) * all_rows;
174 root 1.422 chunk = chunk_alloc (chunk_size, 0);
175 root 1.415
176     char *base = (char *)chunk + sizeof (line_t) * all_rows;
177    
178     for (int row = 0; row < all_rows; ++row)
179     {
180     line_t &l = ((line_t *)chunk) [row];
181    
182     l.t = (text_t *)base; base += tsize;
183     l.r = (rend_t *)base; base += rsize;
184     l.l = -1;
185     l.f = 0;
186     }
187    
188     drawn_buf = (line_t *)chunk;
189     swap_buf = drawn_buf + nrow;
190     row_buf = swap_buf + nrow;
191     }
192    
193 root 1.417 void ecb_cold
194 pcg 1.8 rxvt_term::scr_reset ()
195 pcg 1.1 {
196 sf-exg 1.379 #if ENABLE_OVERLAY
197     scr_overlay_off ();
198     #endif
199    
200 root 1.172 view_start = 0;
201 pcg 1.8 num_scr = 0;
202    
203 root 1.172 if (ncol == 0)
204     ncol = 80;
205 pcg 1.8
206 root 1.172 if (nrow == 0)
207     nrow = 24;
208 pcg 1.8
209     if (ncol == prev_ncol && nrow == prev_nrow)
210     return;
211    
212 root 1.89 // we need at least two lines for wrapping to work correctly
213 root 1.247 while (nrow + saveLines < 2)
214 root 1.89 {
215 root 1.186 //TODO//FIXME
216 root 1.172 saveLines++;
217 root 1.89 prev_nrow--;
218 root 1.228 top_row--;
219 root 1.89 }
220    
221 pcg 1.8 want_refresh = 1;
222    
223 root 1.172 int prev_total_rows = prev_nrow + saveLines;
224 root 1.175 total_rows = nrow + saveLines;
225 pcg 1.8
226     screen.tscroll = 0;
227     screen.bscroll = nrow - 1;
228    
229 root 1.415 void *prev_chunk = chunk;
230 sf-exg 1.423 size_t prev_chunk_size = chunk_size;
231 root 1.415 line_t *prev_drawn_buf = drawn_buf;
232     line_t *prev_swap_buf = swap_buf;
233     line_t *prev_row_buf = row_buf;
234    
235     int common_col = min (prev_ncol, ncol);
236    
237     scr_alloc ();
238    
239     if (!prev_row_buf)
240 pcg 1.8 {
241     /*
242 root 1.419 * first time called (or after scr_release) so just malloc everything: don't rely on realloc
243 pcg 1.8 */
244 root 1.247 top_row = 0;
245 root 1.172 term_start = 0;
246    
247 root 1.104 memset (charsets, 'B', sizeof (charsets));
248 pcg 1.8 rstyle = DEFAULT_RSTYLE;
249     screen.flags = Screen_DefaultFlags;
250     screen.cur.row = screen.cur.col = 0;
251     screen.charset = 0;
252     current_screen = PRIMARY;
253 pcg 1.21 scr_cursor (SAVE);
254 pcg 1.1
255     #if NSCREENS
256 pcg 1.8 swap.flags = Screen_DefaultFlags;
257     swap.cur.row = swap.cur.col = 0;
258     swap.charset = 0;
259     current_screen = SECONDARY;
260 pcg 1.21 scr_cursor (SAVE);
261 pcg 1.8 current_screen = PRIMARY;
262     #endif
263    
264     selection.text = NULL;
265     selection.len = 0;
266     selection.op = SELECTION_CLEAR;
267     selection.screen = PRIMARY;
268     selection.clicks = 0;
269 sf-exg 1.333 selection.clip_text = NULL;
270     selection.clip_len = 0;
271 pcg 1.8 }
272     else
273     {
274     /*
275     * add or delete rows as appropriate
276     */
277 root 1.172
278 root 1.186 for (int row = min (nrow, prev_nrow); row--; )
279 pcg 1.8 {
280 root 1.415 scr_blank_screen_mem (drawn_buf [row], DEFAULT_RSTYLE);
281     scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
282 pcg 1.8
283 root 1.415 memcpy (drawn_buf [row].t, prev_drawn_buf [row].t, sizeof (text_t) * common_col);
284     memcpy (drawn_buf [row].r, prev_drawn_buf [row].r, sizeof (rend_t) * common_col);
285     memcpy (swap_buf [row].t, prev_swap_buf [row].t, sizeof (text_t) * common_col);
286     memcpy (swap_buf [row].r, prev_swap_buf [row].r, sizeof (rend_t) * common_col);
287 root 1.172 }
288    
289 root 1.187 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row
290 root 1.228 int pend = MOD (term_start + top_row , prev_total_rows);
291 root 1.186 int q = total_rows; // rewrapped row
292    
293 root 1.228 if (top_row)
294 root 1.186 {
295 root 1.247 // Re-wrap lines. This is rather ugly, possibly because I am too dumb
296 root 1.189 // to come up with a lean and mean algorithm.
297 root 1.325 // TODO: maybe optimise when width didn't change
298 root 1.189
299 root 1.190 row_col_t ocur = screen.cur;
300     ocur.row = MOD (term_start + ocur.row, prev_total_rows);
301    
302 root 1.192 do
303 root 1.189 {
304     p = MOD (p - 1, prev_total_rows);
305 root 1.415 assert (prev_row_buf [MOD (p, prev_total_rows)].t);
306 root 1.190 int plines = 1;
307 root 1.415 int llen = prev_row_buf [MOD (p, prev_total_rows)].l;
308 root 1.172
309 root 1.415 while (p != pend && prev_row_buf [MOD (p - 1, prev_total_rows)].is_longer ())
310 root 1.189 {
311     p = MOD (p - 1, prev_total_rows);
312 pcg 1.8
313 root 1.190 plines++;
314 root 1.189 llen += prev_ncol;
315     }
316 pcg 1.8
317 root 1.189 int qlines = max (0, (llen - 1) / ncol) + 1;
318 root 1.187
319 root 1.189 // drop partial lines completely
320     if (q < qlines)
321     break;
322 root 1.172
323 root 1.189 q -= qlines;
324 pcg 1.8
325 root 1.189 int lofs = 0;
326     line_t *qline;
327 pcg 1.8
328 root 1.189 // re-assemble the full line by destination lines
329     for (int qrow = q; qlines--; qrow++)
330     {
331     qline = row_buf + qrow;
332 root 1.415 qline->alloc (); // redundant with next line
333 root 1.210 qline->l = ncol;
334     qline->is_longer (1);
335 root 1.172
336 root 1.189 int qcol = 0;
337 root 1.172
338 root 1.239 // see below for cursor adjustment rationale
339     if (p == ocur.row)
340     screen.cur.row = q - (total_rows - nrow);
341 ayin 1.281
342 root 1.189 // fill a single destination line
343     while (lofs < llen && qcol < ncol)
344     {
345     int prow = lofs / prev_ncol;
346     int pcol = lofs % prev_ncol;
347 root 1.172
348 root 1.190 prow = MOD (p + prow, prev_total_rows);
349    
350 root 1.191 // we only adjust the cursor _row_ and put it into
351     // the topmost line of "long line" it was in, as
352     // this seems to upset applications/shells/readline
353     // least.
354 root 1.190 if (prow == ocur.row)
355 root 1.191 screen.cur.row = q - (total_rows - nrow);
356 root 1.190
357 root 1.415 line_t &pline = prev_row_buf [prow];
358 pcg 1.8
359 root 1.189 int len = min (min (prev_ncol - pcol, ncol - qcol), llen - lofs);
360 pcg 1.8
361 root 1.189 memcpy (qline->t + qcol, pline.t + pcol, len * sizeof (text_t));
362     memcpy (qline->r + qcol, pline.r + pcol, len * sizeof (rend_t));
363 root 1.172
364 root 1.189 lofs += len;
365     qcol += len;
366     }
367 root 1.187 }
368 root 1.189
369 root 1.196 qline->l = llen ? MOD (llen - 1, ncol) + 1 : 0;
370 root 1.210 qline->is_longer (0);
371 root 1.189 scr_blank_line (*qline, qline->l, ncol - qline->l, DEFAULT_RSTYLE);
372 root 1.187 }
373 root 1.192 while (p != pend && q > 0);
374 root 1.172
375 root 1.189 term_start = total_rows - nrow;
376 root 1.228 top_row = q - term_start;
377 ayin 1.281
378 root 1.189 // make sure all terminal lines exist
379 root 1.228 while (top_row > 0)
380     scr_blank_screen_mem (ROW (--top_row), DEFAULT_RSTYLE);
381 root 1.187 }
382 root 1.189 else
383     {
384     // if no scrollback exists (yet), wing, instead of wrap
385 ayin 1.281
386 root 1.189 for (int row = min (nrow, prev_nrow); row--; )
387     {
388 root 1.415 line_t &src = prev_row_buf [MOD (term_start + row, prev_total_rows)];
389     line_t &dst = row_buf [row];
390    
391     scr_blank_screen_mem (dst, DEFAULT_RSTYLE);
392 root 1.172
393 root 1.415 memcpy (dst.t, src.t, sizeof (text_t) * common_col);
394     memcpy (dst.r, src.r, sizeof (rend_t) * common_col);
395 sf-exg 1.428 dst.l = common_col;
396 root 1.189 }
397 root 1.172
398 root 1.189 for (int row = prev_nrow; row < nrow; row++)
399 root 1.415 scr_blank_screen_mem (row_buf [row], DEFAULT_RSTYLE);
400 root 1.172
401 root 1.189 term_start = 0;
402     }
403    
404     clamp_it (screen.cur.row, 0, nrow - 1);
405     clamp_it (screen.cur.col, 0, ncol - 1);
406 pcg 1.1 }
407    
408 root 1.415 for (int row = nrow; row--; )
409     {
410     if (!ROW (row).valid ()) scr_blank_screen_mem (ROW (row), DEFAULT_RSTYLE);
411     if (!swap_buf [row].valid ()) scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
412     if (!drawn_buf [row].valid ()) scr_blank_screen_mem (drawn_buf [row], DEFAULT_RSTYLE);
413     }
414    
415 sf-exg 1.423 chunk_free (prev_chunk, prev_chunk_size);
416 root 1.415
417 root 1.326 free (tabs);
418     tabs = (char *)rxvt_malloc (ncol);
419    
420 sf-exg 1.360 for (int col = ncol; col--; )
421 root 1.326 tabs [col] = col % TABSIZE == 0;
422    
423 sf-exg 1.405 CLEAR_ALL_SELECTION ();
424 root 1.241
425 pcg 1.8 prev_nrow = nrow;
426     prev_ncol = ncol;
427 pcg 1.1
428 pcg 1.8 tt_winch ();
429 root 1.204
430 root 1.211 HOOK_INVOKE ((this, HOOK_RESET, DT_END));
431 pcg 1.1 }
432    
433 root 1.417 void ecb_cold
434 root 1.244 rxvt_term::scr_release () NOTHROW
435 pcg 1.1 {
436 root 1.422 chunk_free (chunk, chunk_size);
437     chunk = 0;
438     row_buf = 0;
439    
440     free (tabs);
441     tabs = 0;
442 pcg 1.1 }
443    
444     /* ------------------------------------------------------------------------- */
445     /*
446 root 1.318 * Hard/Soft reset
447 pcg 1.1 */
448 root 1.417 void ecb_cold
449 root 1.247 rxvt_term::scr_poweron ()
450 pcg 1.1 {
451 pcg 1.21 scr_release ();
452 root 1.415
453 pcg 1.21 prev_nrow = prev_ncol = 0;
454 root 1.325 rvideo_mode = false;
455     scr_soft_reset ();
456 pcg 1.21 scr_reset ();
457 pcg 1.1
458 pcg 1.74 scr_clear (true);
459 root 1.235 scr_refresh ();
460 pcg 1.1 }
461    
462 root 1.417 void ecb_cold
463 root 1.413 rxvt_term::scr_soft_reset () NOTHROW
464 root 1.318 {
465     /* only affects modes, nothing drastic such as clearing the screen */
466     #if ENABLE_OVERLAY
467     scr_overlay_off ();
468     #endif
469    
470     if (current_screen != PRIMARY)
471     scr_swap_screen ();
472    
473     scr_scroll_region (0, MAX_ROWS - 1);
474     scr_rendition (0, ~RS_None);
475     scr_insert_mode (0);
476     }
477    
478 pcg 1.1 /* ------------------------------------------------------------------------- *
479     * PROCESS SCREEN COMMANDS *
480     * ------------------------------------------------------------------------- */
481     /*
482     * Save and Restore cursor
483     * XTERM_SEQ: Save cursor : ESC 7
484     * XTERM_SEQ: Restore cursor: ESC 8
485     */
486     void
487 root 1.244 rxvt_term::scr_cursor (cursor_mode mode) NOTHROW
488 pcg 1.1 {
489 pcg 1.66 screen_t *s;
490 pcg 1.1
491     #if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
492 pcg 1.25 if (current_screen == SECONDARY)
493 pcg 1.66 s = &swap;
494 pcg 1.25 else
495 pcg 1.1 #endif
496 pcg 1.66 s = &screen;
497    
498 pcg 1.25 switch (mode)
499     {
500     case SAVE:
501 root 1.129 s->s_cur.row = screen.cur.row;
502     s->s_cur.col = screen.cur.col;
503 pcg 1.21 s->s_rstyle = rstyle;
504 root 1.129 s->s_charset = screen.charset;
505     s->s_charset_char = charsets[screen.charset];
506 pcg 1.4 break;
507 pcg 1.71
508 pcg 1.25 case RESTORE:
509 pcg 1.21 want_refresh = 1;
510 root 1.129 screen.cur.row = s->s_cur.row;
511     screen.cur.col = s->s_cur.col;
512     screen.flags &= ~Screen_WrapNext;
513 pcg 1.21 rstyle = s->s_rstyle;
514 root 1.129 screen.charset = s->s_charset;
515     charsets[screen.charset] = s->s_charset_char;
516 pcg 1.21 set_font_style ();
517 pcg 1.4 break;
518 pcg 1.1 }
519 pcg 1.66
520 pcg 1.25 /* boundary check in case screen size changed between SAVE and RESTORE */
521 root 1.183 min_it (s->cur.row, nrow - 1);
522     min_it (s->cur.col, ncol - 1);
523 pcg 1.30 assert (s->cur.row >= 0);
524     assert (s->cur.col >= 0);
525 pcg 1.1 }
526    
527 root 1.247 void
528 root 1.413 rxvt_term::scr_swap_screen () NOTHROW
529 root 1.247 {
530 root 1.268 if (!option (Opt_secondaryScreen))
531 root 1.247 return;
532    
533     for (int i = prev_nrow; i--; )
534     ::swap (ROW(i), swap_buf [i]);
535    
536     ::swap (screen.cur, swap.cur);
537    
538     screen.cur.row = clamp (screen.cur.row, 0, prev_nrow - 1);
539     screen.cur.col = clamp (screen.cur.col, 0, prev_ncol - 1);
540     }
541    
542 pcg 1.1 /* ------------------------------------------------------------------------- */
543     /*
544     * Swap between primary and secondary screens
545     * XTERM_SEQ: Primary screen : ESC [ ? 4 7 h
546     * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
547     */
548 root 1.247 void
549     rxvt_term::scr_change_screen (int scrn)
550 pcg 1.1 {
551 root 1.247 if (scrn == current_screen)
552     return;
553    
554 pcg 1.25 want_refresh = 1;
555 root 1.172 view_start = 0;
556 pcg 1.1
557 sf-exg 1.407 /* check for boundary cross */
558     row_col_t pos;
559     pos.row = pos.col = 0;
560     if (ROWCOL_IS_BEFORE (selection.beg, pos)
561     && ROWCOL_IS_AFTER (selection.end, pos))
562     CLEAR_SELECTION ();
563 pcg 1.1
564 sf-exg 1.332 current_screen = scrn;
565 root 1.139
566 pcg 1.1 #if NSCREENS
567 root 1.268 if (option (Opt_secondaryScreen))
568 pcg 1.25 {
569 pcg 1.68 num_scr = 0;
570 root 1.139
571 root 1.247 scr_swap_screen ();
572 root 1.139
573 root 1.180 ::swap (screen.charset, swap.charset);
574 root 1.247 ::swap (screen.flags, swap.flags);
575 pcg 1.68 screen.flags |= Screen_VisibleCursor;
576 root 1.247 swap.flags |= Screen_VisibleCursor;
577 pcg 1.68 }
578     else
579 pcg 1.1 #endif
580 root 1.268 if (option (Opt_secondaryScroll))
581 root 1.176 scr_scroll_text (0, prev_nrow - 1, prev_nrow);
582 pcg 1.1 }
583    
584 root 1.104 // clear WrapNext indicator, solidifying position on next line
585     void
586 root 1.244 rxvt_term::scr_do_wrap () NOTHROW
587 root 1.104 {
588     if (!(screen.flags & Screen_WrapNext))
589     return;
590    
591     screen.flags &= ~Screen_WrapNext;
592    
593     screen.cur.col = 0;
594    
595     if (screen.cur.row == screen.bscroll)
596 root 1.176 scr_scroll_text (screen.tscroll, screen.bscroll, 1);
597 root 1.172 else if (screen.cur.row < nrow - 1)
598 root 1.104 screen.cur.row++;
599     }
600    
601 pcg 1.1 /* ------------------------------------------------------------------------- */
602     /*
603     * Change the colour for following text
604     */
605     void
606 root 1.244 rxvt_term::scr_color (unsigned int color, int fgbg) NOTHROW
607 pcg 1.1 {
608 root 1.223 if (!IN_RANGE_INC (color, minCOLOR, maxTermCOLOR))
609 root 1.129 color = fgbg;
610    
611 pcg 1.25 if (fgbg == Color_fg)
612 pcg 1.30 rstyle = SET_FGCOLOR (rstyle, color);
613 pcg 1.25 else
614 pcg 1.30 rstyle = SET_BGCOLOR (rstyle, color);
615 pcg 1.1 }
616    
617     /* ------------------------------------------------------------------------- */
618     /*
619     * Change the rendition style for following text
620     */
621     void
622 root 1.244 rxvt_term::scr_rendition (int set, int style) NOTHROW
623 root 1.289 {
624     if (set)
625     rstyle |= style;
626     else if (style == ~RS_None)
627     rstyle = DEFAULT_RSTYLE;
628     else
629     rstyle &= ~style;
630     }
631 pcg 1.1
632     /* ------------------------------------------------------------------------- */
633     /*
634     * Scroll text between <row1> and <row2> inclusive, by <count> lines
635     * count positive ==> scroll up
636     * count negative ==> scroll down
637     */
638 root 1.417 int ecb_hot
639 root 1.244 rxvt_term::scr_scroll_text (int row1, int row2, int count) NOTHROW
640 pcg 1.1 {
641 pcg 1.8 if (count == 0 || (row1 > row2))
642     return 0;
643    
644     want_refresh = 1;
645 root 1.176 num_scr += count;
646 pcg 1.8
647 root 1.177 if (count > 0
648     && row1 == 0
649 root 1.268 && (current_screen == PRIMARY || option (Opt_secondaryScroll)))
650 pcg 1.8 {
651 root 1.388 min_it (count, total_rows - (nrow - (row2 + 1)));
652 root 1.386
653 root 1.228 top_row = max (top_row - count, -saveLines);
654 root 1.204
655 root 1.236 // sever bottommost line
656 root 1.227 {
657 root 1.391 line_t &l = ROW(row2);
658 root 1.236 l.is_longer (0);
659 root 1.227 l.touch ();
660     }
661    
662 root 1.388 // scroll everything up 'count' lines
663     term_start = (term_start + count) % total_rows;
664    
665     // now copy lines below the scroll region bottom to the
666     // bottom of the screen again, so they look as if they
667     // hadn't moved.
668     for (int i = nrow; --i > row2; )
669     {
670     line_t &l1 = ROW(i - count);
671     line_t &l2 = ROW(i);
672    
673     ::swap (l1, l2);
674     l2.touch ();
675     }
676    
677 root 1.236 // erase newly scrolled-in lines
678     for (int i = count; i--; )
679 root 1.254 {
680 root 1.388 line_t &l = ROW(row2 - i);
681 root 1.254
682 root 1.386 // optimise if already cleared, can be significant on slow machines
683 root 1.254 // could be rolled into scr_blank_screen_mem
684 root 1.259 if (l.r && l.l < ncol - 1 && !((l.r[l.l + 1] ^ rstyle) & (RS_fgMask | RS_bgMask)))
685 root 1.254 {
686     scr_blank_line (l, 0, l.l, rstyle);
687     l.l = 0;
688     l.f = 0;
689     }
690     else
691     scr_blank_screen_mem (l, rstyle);
692     }
693 root 1.227
694 sf-exg 1.400 // move and/or clear selection, if any
695 sf-exg 1.401 if (selection.op && current_screen == selection.screen
696 root 1.402 && selection.beg.row <= row2)
697 sf-exg 1.400 {
698     selection.beg.row -= count;
699     selection.end.row -= count;
700     selection.mark.row -= count;
701    
702     selection_check (0);
703     }
704    
705 root 1.227 // finally move the view window, if desired
706 root 1.268 if (option (Opt_scrollWithBuffer)
707 root 1.172 && view_start != 0
708 root 1.228 && view_start != -saveLines)
709 pcg 1.21 scr_page (UP, count);
710 root 1.234
711     if (SHOULD_INVOKE (HOOK_SCROLL_BACK))
712     HOOK_INVOKE ((this, HOOK_SCROLL_BACK, DT_INT, count, DT_INT, top_row, DT_END));
713 pcg 1.8 }
714 root 1.175 else
715     {
716 sf-exg 1.400 if (selection.op && current_screen == selection.screen)
717     {
718     if ((selection.beg.row < row1 && selection.end.row > row1)
719     || (selection.beg.row < row2 && selection.end.row > row2)
720     || (selection.beg.row - count < row1 && selection.beg.row >= row1)
721     || (selection.beg.row - count > row2 && selection.beg.row <= row2)
722     || (selection.end.row - count < row1 && selection.end.row >= row1)
723     || (selection.end.row - count > row2 && selection.end.row <= row2))
724     {
725 sf-exg 1.405 CLEAR_ALL_SELECTION ();
726     selection.op = SELECTION_CLEAR;
727 sf-exg 1.400 }
728     else if (selection.end.row >= row1 && selection.end.row <= row2)
729     {
730     /* move selected region too */
731     selection.beg.row -= count;
732     selection.end.row -= count;
733     selection.mark.row -= count;
734    
735     selection_check (0);
736     }
737     }
738    
739 root 1.176 // use a simple and robust scrolling algorithm, this
740     // part of scr_scroll_text is not time-critical.
741 pcg 1.1
742 root 1.389 // sever line above scroll region
743     if (row1)
744     {
745     line_t &l = ROW(row1 - 1);
746     l.is_longer (0);
747     l.touch ();
748     }
749    
750 root 1.386 int rows = row2 - row1 + 1;
751    
752     min_it (count, rows);
753    
754 sf-exg 1.390 line_t *temp_buf = rxvt_temp_buf<line_t> (rows);
755 root 1.217
756 root 1.176 for (int row = 0; row < rows; row++)
757 root 1.175 {
758 root 1.186 temp_buf [row] = ROW(row1 + (row + count + rows) % rows);
759 pcg 1.74
760 root 1.176 if (!IN_RANGE_EXC (row + count, 0, rows))
761 root 1.186 scr_blank_screen_mem (temp_buf [row], rstyle);
762 root 1.175 }
763 root 1.172
764 root 1.176 for (int row = 0; row < rows; row++)
765 root 1.186 ROW(row1 + row) = temp_buf [row];
766 root 1.389
767     // sever bottommost line
768     {
769 root 1.392 line_t &l = ROW(row2);
770 root 1.389 l.is_longer (0);
771     l.touch ();
772     }
773 root 1.175 }
774 pcg 1.1
775 pcg 1.8 return count;
776 pcg 1.1 }
777    
778     /* ------------------------------------------------------------------------- */
779     /*
780     * Add text given in <str> of length <len> to screen struct
781     */
782 root 1.417 void ecb_hot
783 root 1.244 rxvt_term::scr_add_lines (const wchar_t *str, int len, int minlines) NOTHROW
784 pcg 1.1 {
785 root 1.165 if (len <= 0) /* sanity */
786     return;
787    
788 sf-exg 1.403 bool checksel;
789 pcg 1.59 unicode_t c;
790 root 1.210 int ncol = this->ncol;
791 root 1.213 const wchar_t *strend = str + len;
792 pcg 1.1
793 pcg 1.25 want_refresh = 1;
794 root 1.104 ZERO_SCROLLBACK ();
795 pcg 1.1
796 root 1.213 if (minlines > 0)
797 pcg 1.25 {
798 root 1.213 minlines += screen.cur.row - screen.bscroll;
799 root 1.248 min_it (minlines, screen.cur.row - top_row);
800 root 1.209
801 root 1.213 if (minlines > 0
802 root 1.186 && screen.tscroll == 0
803 root 1.210 && screen.bscroll == nrow - 1)
804 pcg 1.25 {
805     /* _at least_ this many lines need to be scrolled */
806 root 1.213 scr_scroll_text (screen.tscroll, screen.bscroll, minlines);
807     screen.cur.row -= minlines;
808 pcg 1.4 }
809 pcg 1.1 }
810 root 1.89
811 root 1.210 assert (screen.cur.col < ncol);
812 root 1.186 assert (screen.cur.row < nrow
813 root 1.228 && screen.cur.row >= top_row);
814 root 1.193 int row = screen.cur.row;
815 pcg 1.25
816 pcg 1.66 checksel = selection.op && current_screen == selection.screen ? 1 : 0;
817 pcg 1.25
818 root 1.175 line_t *line = &ROW(row);
819 pcg 1.25
820 root 1.165 while (str < strend)
821 pcg 1.25 {
822 root 1.213 c = (unicode_t)*str++; // convert to rxvt-unicodes representation
823 pcg 1.66
824 sf-exg 1.384 if (ecb_unlikely (c < 0x20))
825 root 1.165 if (c == C0_LF)
826 root 1.195 {
827 root 1.210 max_it (line->l, screen.cur.col);
828 root 1.165
829     screen.flags &= ~Screen_WrapNext;
830    
831     if (screen.cur.row == screen.bscroll)
832 root 1.176 scr_scroll_text (screen.tscroll, screen.bscroll, 1);
833 root 1.172 else if (screen.cur.row < (nrow - 1))
834 root 1.175 row = ++screen.cur.row;
835 root 1.165
836 root 1.175 line = &ROW(row); /* _must_ refresh */
837 root 1.165 continue;
838     }
839     else if (c == C0_CR)
840 pcg 1.66 {
841 root 1.210 max_it (line->l, screen.cur.col);
842 pcg 1.66
843 root 1.165 screen.flags &= ~Screen_WrapNext;
844     screen.cur.col = 0;
845     continue;
846     }
847     else if (c == C0_HT)
848     {
849     scr_tab (1, true);
850     continue;
851 pcg 1.66 }
852 pcg 1.4
853 sf-exg 1.384 if (ecb_unlikely (
854 root 1.309 checksel /* see if we're writing within selection */
855     && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
856     && ROWCOL_IS_BEFORE (screen.cur, selection.end)
857     ))
858 pcg 1.25 {
859     checksel = 0;
860 root 1.104 /*
861     * If we wrote anywhere in the selected area, kill the selection
862     * XXX: should we kill the mark too? Possibly, but maybe that
863     * should be a similar check.
864     */
865     CLEAR_SELECTION ();
866 pcg 1.4 }
867 pcg 1.54
868 sf-exg 1.384 if (ecb_unlikely (screen.flags & Screen_WrapNext))
869 pcg 1.25 {
870 root 1.236 scr_do_wrap ();
871 ayin 1.281
872 root 1.236 line->l = ncol;
873 root 1.210 line->is_longer (1);
874 root 1.104
875 root 1.175 row = screen.cur.row;
876     line = &ROW(row); /* _must_ refresh */
877 pcg 1.4 }
878 pcg 1.54
879 root 1.165 // some utf-8 decoders "decode" surrogate characters: let's fix this.
880 sf-exg 1.384 if (ecb_unlikely (IN_RANGE_INC (c, 0xd800, 0xdfff)))
881 root 1.165 c = 0xfffd;
882    
883 root 1.249 // rely on wcwidth to tell us the character width, do wcwidth before
884     // further replacements, as wcwidth might return -1 for the line
885     // drawing characters below as they might be invalid in the current
886 root 1.165 // locale.
887 root 1.249 int width = WCWIDTH (c);
888 pcg 1.54
889 sf-exg 1.384 if (ecb_unlikely (charsets [screen.charset] == '0')) // DEC SPECIAL
890 pcg 1.66 {
891     // vt100 special graphics and line drawing
892 root 1.129 // 5f-7e standard vt100
893     // 40-5e rxvt extension for extra curses acs chars
894 root 1.165 static uint16_t vt100_0[62] = { // 41 .. 7e
895     0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603, // 41-47 hi mr. snowman!
896     0, 0, 0, 0, 0, 0, 0, 0, // 48-4f
897     0, 0, 0, 0, 0, 0, 0, 0, // 50-57
898     0, 0, 0, 0, 0, 0, 0, 0x0020, // 58-5f
899 root 1.129 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, // 60-67
900     0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, // 68-6f
901     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, // 70-77
902     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
903 pcg 1.66 };
904    
905 root 1.165 if (c >= 0x41 && c <= 0x7e && vt100_0[c - 0x41])
906 pcg 1.66 {
907 root 1.165 c = vt100_0[c - 0x41];
908     width = 1; // vt100 line drawing characters are always single-width
909 pcg 1.66 }
910     }
911 pcg 1.1
912 sf-exg 1.384 if (ecb_unlikely (screen.flags & Screen_Insert))
913 root 1.143 scr_insdel_chars (width, INSERT);
914    
915 pcg 1.74 if (width != 0)
916 pcg 1.43 {
917 root 1.104 #if !UNICODE_3
918 pcg 1.54 // trim characters we can't store directly :(
919     if (c >= 0x10000)
920 root 1.104 # if ENABLE_COMBINING
921 pcg 1.54 c = rxvt_composite.compose (c); // map to lower 16 bits
922 root 1.104 # else
923     c = 0xfffd;
924     # endif
925 pcg 1.54 #endif
926 root 1.129
927     rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
928 pcg 1.54
929 root 1.165 // if the character doesn't fit into the remaining columns...
930 sf-exg 1.384 if (ecb_unlikely (screen.cur.col > ncol - width && ncol >= width))
931 root 1.165 {
932 sf-exg 1.348 if (screen.flags & Screen_Autowrap)
933     {
934     // ... artificially enlargen the previous one
935     c = NOCHAR;
936     // and try the same character next loop iteration
937     --str;
938     }
939     else
940     screen.cur.col = ncol - width;
941 root 1.165 }
942    
943 sf-exg 1.351 // nuke the character at this position, if required
944 sf-exg 1.355 // due to wonderful coincidences everywhere else in this loop
945 root 1.353 // we never have to check for overwriting a wide char itself,
946 root 1.354 // only its tail.
947 sf-exg 1.384 if (ecb_unlikely (line->t[screen.cur.col] == NOCHAR))
948 sf-exg 1.351 scr_kill_char (*line, screen.cur.col);
949    
950 root 1.210 line->touch ();
951    
952 pcg 1.43 do
953     {
954 root 1.172 line->t[screen.cur.col] = c;
955     line->r[screen.cur.col] = rend;
956 pcg 1.43
957 sf-exg 1.384 if (ecb_likely (screen.cur.col < ncol - 1))
958 pcg 1.43 screen.cur.col++;
959     else
960     {
961 root 1.210 line->l = ncol;
962 pcg 1.43 if (screen.flags & Screen_Autowrap)
963     screen.flags |= Screen_WrapNext;
964 root 1.352
965     goto end_of_line;
966 pcg 1.43 }
967 pcg 1.1
968 pcg 1.43 c = NOCHAR;
969     }
970 sf-exg 1.384 while (ecb_unlikely (--width > 0));
971 pcg 1.1
972 pcg 1.43 // pad with spaces when overwriting wide character with smaller one
973 sf-exg 1.384 for (int c = screen.cur.col; ecb_unlikely (c < ncol && line->t[c] == NOCHAR); c++)
974 root 1.210 {
975 root 1.352 line->t[c] = ' ';
976     line->r[c] = rend;
977     }
978 root 1.210
979 root 1.352 end_of_line:
980     ;
981 pcg 1.43 }
982 root 1.309 #if ENABLE_COMBINING
983 root 1.165 else // width == 0
984 pcg 1.54 {
985 root 1.309 if (c != 0xfeff) // ignore BOM
986     {
987     // handle combining characters
988     // we just tag the accent on the previous on-screen character.
989     // this is arguably not correct, but also arguably not wrong.
990     // we don't handle double-width characters nicely yet.
991     line_t *linep;
992     text_t *tp;
993     rend_t *rp;
994 pcg 1.54
995 root 1.309 if (screen.cur.col > 0)
996     {
997     linep = line;
998     tp = line->t + screen.cur.col - 1;
999     rp = line->r + screen.cur.col - 1;
1000     }
1001     else if (screen.cur.row > 0
1002     && ROW(screen.cur.row - 1).is_longer ())
1003     {
1004     linep = &ROW(screen.cur.row - 1);
1005     tp = line->t + ncol - 1;
1006     rp = line->r + ncol - 1;
1007     }
1008     else
1009     continue;
1010 pcg 1.54
1011 root 1.309 linep->touch ();
1012 root 1.210
1013 root 1.309 while (*tp == NOCHAR && tp > linep->t)
1014     tp--, rp--;
1015 root 1.210
1016 root 1.309 // first try to find a precomposed character
1017     unicode_t n = rxvt_compose (*tp, c);
1018     if (n == NOCHAR)
1019     n = rxvt_composite.compose (*tp, c);
1020 pcg 1.54
1021 root 1.309 *tp = n;
1022     *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
1023     }
1024     }
1025 pcg 1.54 #endif
1026 pcg 1.1 }
1027 pcg 1.17
1028 root 1.210 max_it (line->l, screen.cur.col);
1029 pcg 1.1
1030 pcg 1.30 assert (screen.cur.row >= 0);
1031 pcg 1.1 }
1032    
1033     /* ------------------------------------------------------------------------- */
1034     /*
1035     * Process Backspace. Move back the cursor back a position, wrap if have to
1036     * XTERM_SEQ: CTRL-H
1037     */
1038     void
1039 root 1.244 rxvt_term::scr_backspace () NOTHROW
1040 pcg 1.1 {
1041 pcg 1.25 if (screen.cur.col == 0)
1042     {
1043     if (screen.cur.row > 0)
1044     {
1045 pcg 1.1 #ifdef TERMCAP_HAS_BW
1046 root 1.172 screen.cur.col = ncol - 1;
1047 root 1.297 --screen.cur.row;
1048    
1049 root 1.296 want_refresh = 1;
1050 pcg 1.1 #endif
1051 pcg 1.4 }
1052 pcg 1.25 }
1053 root 1.349 else if (screen.flags & Screen_WrapNext)
1054     screen.flags &= ~Screen_WrapNext;
1055 root 1.294 else
1056 pcg 1.25 scr_gotorc (0, -1, RELATIVE);
1057 pcg 1.1 }
1058    
1059     /* ------------------------------------------------------------------------- */
1060     /*
1061     * Process Horizontal Tab
1062     * count: +ve = forward; -ve = backwards
1063     * XTERM_SEQ: CTRL-I
1064     */
1065     void
1066 root 1.244 rxvt_term::scr_tab (int count, bool ht) NOTHROW
1067 pcg 1.1 {
1068 pcg 1.66 int i, x;
1069 pcg 1.1
1070 pcg 1.25 want_refresh = 1;
1071     i = x = screen.cur.col;
1072 pcg 1.66
1073 pcg 1.25 if (count == 0)
1074     return;
1075     else if (count > 0)
1076     {
1077 root 1.193 line_t &l = ROW(screen.cur.row);
1078 root 1.172 rend_t base_rend = l.r[i];
1079     ht &= l.t[i] == ' ';
1080 root 1.129
1081 root 1.172 for (; ++i < ncol; )
1082 pcg 1.25 if (tabs[i])
1083     {
1084     x = i;
1085 root 1.210
1086 pcg 1.25 if (!--count)
1087     break;
1088     }
1089 ayin 1.281 else
1090 root 1.172 ht &= l.t[i] == ' '
1091     && RS_SAME (l.r[i], base_rend);
1092 pcg 1.66
1093 pcg 1.25 if (count)
1094 root 1.172 x = ncol - 1;
1095 root 1.129
1096     // store horizontal tab commands as characters inside the text
1097     // buffer so they can be selected and pasted.
1098 root 1.268 if (ht && option (Opt_pastableTabs))
1099 root 1.129 {
1100     base_rend = SET_FONT (base_rend, 0);
1101    
1102 root 1.210 l.touch (x);
1103 root 1.129
1104     i = screen.cur.col;
1105    
1106 root 1.172 l.t[i] = '\t';
1107     l.r[i] = base_rend;
1108 root 1.129
1109     while (++i < x)
1110     {
1111 root 1.172 l.t[i] = NOCHAR;
1112     l.r[i] = base_rend;
1113 root 1.129 }
1114     }
1115 pcg 1.25 }
1116     else /* if (count < 0) */
1117     {
1118     for (; --i >= 0; )
1119     if (tabs[i])
1120     {
1121     x = i;
1122     if (!++count)
1123     break;
1124     }
1125 pcg 1.66
1126 pcg 1.25 if (count)
1127     x = 0;
1128 pcg 1.1 }
1129 pcg 1.66
1130 pcg 1.25 if (x != screen.cur.col)
1131     scr_gotorc (0, x, R_RELATIVE);
1132 pcg 1.1 }
1133    
1134     /* ------------------------------------------------------------------------- */
1135     /*
1136     * Process DEC Back Index
1137     * XTERM_SEQ: ESC 6
1138     * Move cursor left in row. If we're at the left boundary, shift everything
1139     * in that row right. Clear left column.
1140     */
1141 root 1.256 #if !ENABLE_MINIMAL
1142 root 1.417 void ecb_cold
1143 root 1.244 rxvt_term::scr_backindex () NOTHROW
1144 pcg 1.1 {
1145 pcg 1.25 if (screen.cur.col > 0)
1146     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
1147     else
1148 root 1.175 scr_insdel_chars (1, INSERT);
1149 pcg 1.1 }
1150     #endif
1151     /* ------------------------------------------------------------------------- */
1152     /*
1153     * Process DEC Forward Index
1154     * XTERM_SEQ: ESC 9
1155     * Move cursor right in row. If we're at the right boundary, shift everything
1156     * in that row left. Clear right column.
1157     */
1158 root 1.256 #if !ENABLE_MINIMAL
1159 root 1.417 void ecb_cold
1160 root 1.244 rxvt_term::scr_forwardindex () NOTHROW
1161 pcg 1.1 {
1162 root 1.172 if (screen.cur.col < ncol - 1)
1163 pcg 1.25 scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
1164     else
1165     {
1166 root 1.210 line_t &l = ROW(screen.cur.row);
1167    
1168     l.touch ();
1169     l.is_longer (0);
1170 root 1.104
1171 pcg 1.25 scr_gotorc (0, 0, R_RELATIVE);
1172     scr_insdel_chars (1, DELETE);
1173 root 1.172 scr_gotorc (0, ncol - 1, R_RELATIVE);
1174 pcg 1.1 }
1175     }
1176     #endif
1177    
1178     /* ------------------------------------------------------------------------- */
1179     /*
1180     * Goto Row/Column
1181     */
1182     void
1183 root 1.244 rxvt_term::scr_gotorc (int row, int col, int relative) NOTHROW
1184 pcg 1.1 {
1185 pcg 1.25 want_refresh = 1;
1186 pcg 1.30 ZERO_SCROLLBACK ();
1187 pcg 1.1
1188 pcg 1.71 screen.cur.col = relative & C_RELATIVE ? screen.cur.col + col : col;
1189 root 1.186 clamp_it (screen.cur.col, 0, ncol - 1);
1190 pcg 1.25
1191     screen.flags &= ~Screen_WrapNext;
1192 root 1.104
1193 pcg 1.25 if (relative & R_RELATIVE)
1194     {
1195     if (row > 0)
1196     {
1197     if (screen.cur.row <= screen.bscroll
1198     && (screen.cur.row + row) > screen.bscroll)
1199     screen.cur.row = screen.bscroll;
1200     else
1201     screen.cur.row += row;
1202     }
1203     else if (row < 0)
1204     {
1205     if (screen.cur.row >= screen.tscroll
1206     && (screen.cur.row + row) < screen.tscroll)
1207     screen.cur.row = screen.tscroll;
1208     else
1209     screen.cur.row += row;
1210     }
1211     }
1212     else
1213     {
1214     if (screen.flags & Screen_Relative)
1215 ayin 1.284 {
1216     /* relative origin mode */
1217 pcg 1.25 screen.cur.row = row + screen.tscroll;
1218 root 1.183 min_it (screen.cur.row, screen.bscroll);
1219 pcg 1.4 }
1220 pcg 1.25 else
1221     screen.cur.row = row;
1222 pcg 1.1 }
1223 root 1.104
1224 root 1.186 clamp_it (screen.cur.row, 0, nrow - 1);
1225 pcg 1.1 }
1226    
1227     /* ------------------------------------------------------------------------- */
1228     /*
1229 root 1.104 * direction should be UP or DN
1230 pcg 1.1 */
1231     void
1232 root 1.244 rxvt_term::scr_index (enum page_dirn direction) NOTHROW
1233 pcg 1.1 {
1234 pcg 1.71 int dirn;
1235 pcg 1.1
1236 pcg 1.25 want_refresh = 1;
1237 root 1.104 ZERO_SCROLLBACK ();
1238    
1239 pcg 1.25 dirn = ((direction == UP) ? 1 : -1);
1240 pcg 1.1
1241 root 1.104 screen.flags &= ~Screen_WrapNext;
1242 pcg 1.1
1243 pcg 1.25 if ((screen.cur.row == screen.bscroll && direction == UP)
1244     || (screen.cur.row == screen.tscroll && direction == DN))
1245 root 1.176 scr_scroll_text (screen.tscroll, screen.bscroll, dirn);
1246 pcg 1.25 else
1247     screen.cur.row += dirn;
1248 root 1.104
1249 root 1.186 clamp_it (screen.cur.row, 0, nrow - 1);
1250 pcg 1.25 selection_check (0);
1251 pcg 1.1 }
1252    
1253     /* ------------------------------------------------------------------------- */
1254     /*
1255     * Erase part or whole of a line
1256     * XTERM_SEQ: Clear line to right: ESC [ 0 K
1257     * XTERM_SEQ: Clear line to left : ESC [ 1 K
1258     * XTERM_SEQ: Clear whole line : ESC [ 2 K
1259 root 1.306 * extension: clear to right unless wrapped: ESC [ 3 K
1260 pcg 1.1 */
1261     void
1262 root 1.244 rxvt_term::scr_erase_line (int mode) NOTHROW
1263 pcg 1.1 {
1264 root 1.193 unsigned int col, num;
1265 pcg 1.1
1266 pcg 1.21 want_refresh = 1;
1267     ZERO_SCROLLBACK ();
1268 pcg 1.1
1269 pcg 1.21 selection_check (1);
1270 pcg 1.1
1271 root 1.193 line_t &line = ROW(screen.cur.row);
1272 root 1.172
1273 root 1.210 line.touch ();
1274     line.is_longer (0);
1275    
1276 pcg 1.8 switch (mode)
1277     {
1278 root 1.306 case 3:
1279     if (screen.flags & Screen_WrapNext)
1280     return;
1281    
1282     /* fall through */
1283    
1284 pcg 1.8 case 0: /* erase to end of line */
1285 pcg 1.21 col = screen.cur.col;
1286 root 1.172 num = ncol - col;
1287 root 1.193 min_it (line.l, col);
1288 root 1.306
1289 pcg 1.30 if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)
1290     || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur))
1291     CLEAR_SELECTION ();
1292 pcg 1.4 break;
1293 root 1.306
1294 pcg 1.8 case 1: /* erase to beginning of line */
1295 pcg 1.4 col = 0;
1296 pcg 1.21 num = screen.cur.col + 1;
1297 root 1.306
1298 pcg 1.30 if (ROWCOL_IN_ROW_AT_OR_BEFORE (selection.beg, screen.cur)
1299     || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur))
1300     CLEAR_SELECTION ();
1301 pcg 1.4 break;
1302 root 1.306
1303 pcg 1.8 case 2: /* erase whole line */
1304 pcg 1.4 col = 0;
1305 root 1.172 num = ncol;
1306 root 1.193 line.l = 0;
1307 pcg 1.21 if (selection.beg.row <= screen.cur.row
1308     && selection.end.row >= screen.cur.row)
1309 pcg 1.30 CLEAR_SELECTION ();
1310 pcg 1.4 break;
1311 pcg 1.8 default:
1312 pcg 1.4 return;
1313 pcg 1.1 }
1314 pcg 1.8
1315 root 1.193 scr_blank_line (line, col, num, rstyle);
1316 pcg 1.1 }
1317    
1318     /* ------------------------------------------------------------------------- */
1319     /*
1320 sf-exg 1.408 * Erase part or whole of the screen
1321 pcg 1.1 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1322     * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1323     * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1324     */
1325     void
1326 root 1.244 rxvt_term::scr_erase_screen (int mode) NOTHROW
1327 pcg 1.1 {
1328 pcg 1.66 int num;
1329 root 1.176 int32_t row;
1330 pcg 1.66 rend_t ren;
1331     XGCValues gcvalue;
1332 pcg 1.25
1333     want_refresh = 1;
1334     ZERO_SCROLLBACK ();
1335 root 1.104
1336 pcg 1.25 switch (mode)
1337     {
1338     case 0: /* erase to end of screen */
1339 pcg 1.21 scr_erase_line (0);
1340 pcg 1.11 row = screen.cur.row + 1; /* possible OOB */
1341 root 1.172 num = nrow - row;
1342 pcg 1.4 break;
1343 pcg 1.25 case 1: /* erase to beginning of screen */
1344 pcg 1.21 scr_erase_line (1);
1345 pcg 1.4 row = 0;
1346 pcg 1.11 num = screen.cur.row;
1347 pcg 1.4 break;
1348 pcg 1.25 case 2: /* erase whole screen */
1349 pcg 1.4 row = 0;
1350 root 1.172 num = nrow;
1351 pcg 1.4 break;
1352 pcg 1.25 default:
1353 pcg 1.4 return;
1354 pcg 1.1 }
1355 pcg 1.66
1356 pcg 1.25 if (selection.op && current_screen == selection.screen
1357     && ((selection.beg.row >= row && selection.beg.row <= row + num)
1358     || (selection.end.row >= row
1359     && selection.end.row <= row + num)))
1360     CLEAR_SELECTION ();
1361 pcg 1.66
1362 root 1.172 if (row >= nrow) /* Out Of Bounds */
1363 pcg 1.25 return;
1364 pcg 1.66
1365 root 1.186 min_it (num, nrow - row);
1366 pcg 1.66
1367 root 1.342 if (rstyle & (RS_Blink | RS_RVid | RS_Uline))
1368 pcg 1.25 ren = (rend_t) ~RS_None;
1369 pcg 1.30 else if (GET_BASEBG (rstyle) == Color_bg)
1370 pcg 1.25 {
1371     ren = DEFAULT_RSTYLE;
1372 root 1.307
1373 sf-exg 1.347 if (mapped)
1374 root 1.307 XClearArea (dpy, vt, 0,
1375 sf-exg 1.411 Row2Pixel (row - view_start), (unsigned int)vt_width,
1376 root 1.307 (unsigned int)Height2Pixel (num), False);
1377 pcg 1.25 }
1378     else
1379     {
1380 root 1.139 ren = rstyle & (RS_fgMask | RS_bgMask);
1381 root 1.307
1382 sf-exg 1.347 if (mapped)
1383 root 1.323 {
1384     gcvalue.foreground = pix_colors[bgcolor_of (rstyle)];
1385     XChangeGC (dpy, gc, GCForeground, &gcvalue);
1386     XFillRectangle (dpy, vt, gc,
1387     0, Row2Pixel (row - view_start),
1388 sf-exg 1.411 (unsigned int)vt_width,
1389 root 1.323 (unsigned int)Height2Pixel (num));
1390     gcvalue.foreground = pix_colors[Color_fg];
1391     XChangeGC (dpy, gc, GCForeground, &gcvalue);
1392     }
1393 pcg 1.1 }
1394 pcg 1.66
1395 pcg 1.25 for (; num--; row++)
1396     {
1397 root 1.215 scr_blank_screen_mem (ROW(row), rstyle);
1398 root 1.324
1399 sf-exg 1.347 if (row - view_start < nrow)
1400     scr_blank_line (drawn_buf [row - view_start], 0, ncol, ren);
1401 pcg 1.1 }
1402     }
1403    
1404 root 1.256 #if !ENABLE_MINIMAL
1405 root 1.159 void
1406 root 1.244 rxvt_term::scr_erase_savelines () NOTHROW
1407 root 1.159 {
1408     want_refresh = 1;
1409     ZERO_SCROLLBACK ();
1410    
1411 root 1.228 top_row = 0;
1412 root 1.159 }
1413 root 1.160 #endif
1414 root 1.159
1415 pcg 1.1 /* ------------------------------------------------------------------------- */
1416     /*
1417     * Fill the screen with `E's
1418     * XTERM_SEQ: Screen Alignment Test: ESC # 8
1419     */
1420 root 1.417 void ecb_cold
1421 root 1.244 rxvt_term::scr_E () NOTHROW
1422 pcg 1.1 {
1423 root 1.176 rend_t fs;
1424 pcg 1.1
1425 pcg 1.25 want_refresh = 1;
1426 root 1.104 ZERO_SCROLLBACK ();
1427    
1428 pcg 1.25 num_scr_allow = 0;
1429 sf-exg 1.407
1430     row_col_t pos;
1431     pos.row = pos.col = 0;
1432     if (ROWCOL_IS_AFTER (selection.end, pos))
1433     CLEAR_SELECTION ();
1434 pcg 1.25
1435 root 1.129 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E'));
1436 root 1.176 for (int row = nrow; row--; )
1437 pcg 1.25 {
1438 root 1.176 line_t &line = ROW(row);
1439 root 1.174
1440     fill_text (line.t, 'E', ncol);
1441 root 1.176 rend_t *r1 = line.r;
1442 root 1.174
1443 root 1.176 for (int j = ncol; j--; )
1444 pcg 1.25 *r1++ = fs;
1445 root 1.174
1446 root 1.210 line.is_longer (0);
1447     line.touch (ncol);
1448 pcg 1.1 }
1449     }
1450    
1451     /* ------------------------------------------------------------------------- */
1452     /*
1453     * Insert/Delete <count> lines
1454     */
1455     void
1456 root 1.244 rxvt_term::scr_insdel_lines (int count, int insdel) NOTHROW
1457 pcg 1.1 {
1458 pcg 1.66 int end;
1459 pcg 1.1
1460 pcg 1.30 ZERO_SCROLLBACK ();
1461 pcg 1.1
1462 pcg 1.25 selection_check (1);
1463    
1464     if (screen.cur.row > screen.bscroll)
1465     return;
1466 pcg 1.1
1467 pcg 1.25 end = screen.bscroll - screen.cur.row + 1;
1468     if (count > end)
1469     {
1470     if (insdel == DELETE)
1471 pcg 1.4 return;
1472 pcg 1.25 else if (insdel == INSERT)
1473     count = end;
1474 pcg 1.1 }
1475 root 1.104
1476     scr_do_wrap ();
1477 pcg 1.1
1478 root 1.176 scr_scroll_text (screen.cur.row, screen.bscroll, insdel * count);
1479 pcg 1.1 }
1480    
1481     /* ------------------------------------------------------------------------- */
1482     /*
1483     * Insert/Delete <count> characters from the current position
1484     */
1485     void
1486 root 1.244 rxvt_term::scr_insdel_chars (int count, int insdel) NOTHROW
1487 pcg 1.1 {
1488 pcg 1.25 want_refresh = 1;
1489 pcg 1.30 ZERO_SCROLLBACK ();
1490 pcg 1.1
1491 pcg 1.25 if (count <= 0)
1492     return;
1493 pcg 1.1
1494 root 1.104 scr_do_wrap ();
1495    
1496 pcg 1.25 selection_check (1);
1497 root 1.186 min_it (count, ncol - screen.cur.col);
1498 pcg 1.1
1499 root 1.314 int row = screen.cur.row;
1500 pcg 1.1
1501 root 1.176 line_t *line = &ROW(row);
1502 pcg 1.66
1503 root 1.210 line->touch ();
1504     line->is_longer (0);
1505    
1506 root 1.316 // nuke wide spanning the start
1507 root 1.315 if (line->t[screen.cur.col] == NOCHAR)
1508     scr_kill_char (*line, screen.cur.col);
1509    
1510 pcg 1.25 switch (insdel)
1511     {
1512     case INSERT:
1513 root 1.314 line->l = min (line->l + count, ncol);
1514    
1515 root 1.315 if (line->t[screen.cur.col] == NOCHAR)
1516     scr_kill_char (*line, screen.cur.col);
1517    
1518 root 1.314 for (int col = ncol - 1; (col - count) >= screen.cur.col; col--)
1519 pcg 1.25 {
1520 root 1.172 line->t[col] = line->t[col - count];
1521     line->r[col] = line->r[col - count];
1522 pcg 1.25 }
1523 pcg 1.66
1524 pcg 1.21 if (selection.op && current_screen == selection.screen
1525 pcg 1.30 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1526 pcg 1.25 {
1527 pcg 1.21 if (selection.end.row != screen.cur.row
1528 root 1.172 || (selection.end.col + count >= ncol))
1529 pcg 1.30 CLEAR_SELECTION ();
1530 pcg 1.25 else
1531 ayin 1.284 {
1532     /* shift selection */
1533 root 1.136 selection.beg.col += count;
1534 pcg 1.21 selection.mark.col += count; /* XXX: yes? */
1535 root 1.136 selection.end.col += count;
1536 pcg 1.25 }
1537     }
1538 pcg 1.66
1539 root 1.176 scr_blank_line (*line, screen.cur.col, count, rstyle);
1540 pcg 1.4 break;
1541 pcg 1.66
1542 pcg 1.25 case ERASE:
1543 root 1.172 screen.cur.col += count; /* don't worry if > ncol */
1544 pcg 1.21 selection_check (1);
1545     screen.cur.col -= count;
1546 root 1.210
1547 root 1.315 // nuke wide char after the end
1548     if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR)
1549     scr_kill_char (*line, screen.cur.col + count);
1550    
1551 root 1.176 scr_blank_line (*line, screen.cur.col, count, rstyle);
1552 pcg 1.4 break;
1553 pcg 1.66
1554 pcg 1.25 case DELETE:
1555 root 1.316 line->l = max (line->l - count, 0);
1556 root 1.314
1557 root 1.316 // nuke wide char spanning the end
1558     if (screen.cur.col + count < ncol && line->t[screen.cur.col + count] == NOCHAR)
1559     scr_kill_char (*line, screen.cur.col + count);
1560 pcg 1.66
1561 root 1.316 for (int col = screen.cur.col; (col + count) < ncol; col++)
1562     {
1563     line->t[col] = line->t[col + count];
1564     line->r[col] = line->r[col + count];
1565     }
1566 root 1.314
1567 root 1.325 scr_blank_line (*line, ncol - count, count, rstyle);
1568 pcg 1.66
1569 root 1.316 if (selection.op && current_screen == selection.screen
1570     && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1571     {
1572     if (selection.end.row != screen.cur.row
1573     || (screen.cur.col >= selection.beg.col - count)
1574     || selection.end.col >= ncol)
1575     CLEAR_SELECTION ();
1576     else
1577     {
1578     /* shift selection */
1579     selection.beg.col -= count;
1580     selection.mark.col -= count; /* XXX: yes? */
1581     selection.end.col -= count;
1582     }
1583 pcg 1.25 }
1584 pcg 1.66
1585 pcg 1.4 break;
1586 pcg 1.1 }
1587     }
1588    
1589     /* ------------------------------------------------------------------------- */
1590     /*
1591     * Set the scrolling region
1592     * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1593     */
1594 root 1.417 void ecb_cold
1595 root 1.244 rxvt_term::scr_scroll_region (int top, int bot) NOTHROW
1596 pcg 1.1 {
1597 root 1.183 max_it (top, 0);
1598 root 1.186 min_it (bot, nrow - 1);
1599 pcg 1.66
1600 pcg 1.25 if (top > bot)
1601     return;
1602 pcg 1.66
1603 pcg 1.25 screen.tscroll = top;
1604     screen.bscroll = bot;
1605     scr_gotorc (0, 0, 0);
1606 pcg 1.1 }
1607    
1608     /* ------------------------------------------------------------------------- */
1609     /*
1610     * Make the cursor visible/invisible
1611     * XTERM_SEQ: Make cursor visible : ESC [ ? 25 h
1612     * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1613     */
1614 root 1.417 void ecb_cold
1615 root 1.244 rxvt_term::scr_cursor_visible (int mode) NOTHROW
1616 pcg 1.1 {
1617 pcg 1.25 want_refresh = 1;
1618 pcg 1.71
1619 pcg 1.25 if (mode)
1620     screen.flags |= Screen_VisibleCursor;
1621     else
1622     screen.flags &= ~Screen_VisibleCursor;
1623 pcg 1.1 }
1624    
1625     /* ------------------------------------------------------------------------- */
1626     /*
1627     * Set/unset automatic wrapping
1628     * XTERM_SEQ: Set Wraparound : ESC [ ? 7 h
1629     * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1630     */
1631 root 1.417 void ecb_cold
1632 root 1.244 rxvt_term::scr_autowrap (int mode) NOTHROW
1633 pcg 1.1 {
1634 pcg 1.25 if (mode)
1635     screen.flags |= Screen_Autowrap;
1636     else
1637 root 1.104 screen.flags &= ~(Screen_Autowrap | Screen_WrapNext);
1638 pcg 1.1 }
1639    
1640     /* ------------------------------------------------------------------------- */
1641     /*
1642     * Set/unset margin origin mode
1643     * Absolute mode: line numbers are counted relative to top margin of screen
1644     * and the cursor can be moved outside the scrolling region.
1645     * Relative mode: line numbers are relative to top margin of scrolling region
1646     * and the cursor cannot be moved outside.
1647     * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1648     * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1649     */
1650 root 1.417 void ecb_cold
1651 root 1.244 rxvt_term::scr_relative_origin (int mode) NOTHROW
1652 pcg 1.1 {
1653 pcg 1.25 if (mode)
1654     screen.flags |= Screen_Relative;
1655     else
1656     screen.flags &= ~Screen_Relative;
1657 root 1.129
1658 pcg 1.25 scr_gotorc (0, 0, 0);
1659 pcg 1.1 }
1660    
1661     /* ------------------------------------------------------------------------- */
1662     /*
1663     * Set insert/replace mode
1664     * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1665     * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1666     */
1667 root 1.417 void ecb_cold
1668 root 1.244 rxvt_term::scr_insert_mode (int mode) NOTHROW
1669 pcg 1.1 {
1670 pcg 1.25 if (mode)
1671     screen.flags |= Screen_Insert;
1672     else
1673     screen.flags &= ~Screen_Insert;
1674 pcg 1.1 }
1675    
1676     /* ------------------------------------------------------------------------- */
1677     /*
1678     * Set/Unset tabs
1679     * XTERM_SEQ: Set tab at current column : ESC H
1680     * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1681     * XTERM_SEQ: Clear all tabs : ESC [ 3 g
1682     */
1683 root 1.417 void ecb_cold
1684 root 1.244 rxvt_term::scr_set_tab (int mode) NOTHROW
1685 pcg 1.1 {
1686 pcg 1.25 if (mode < 0)
1687 ayin 1.277 memset (tabs, 0, ncol);
1688 root 1.172 else if (screen.cur.col < ncol)
1689 root 1.210 tabs [screen.cur.col] = !!mode;
1690 pcg 1.1 }
1691    
1692     /* ------------------------------------------------------------------------- */
1693     /*
1694     * Set reverse/normal video
1695     * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1696     * XTERM_SEQ: Normal video : ESC [ ? 5 l
1697     */
1698     void
1699 root 1.246 rxvt_term::scr_rvideo_mode (bool on) NOTHROW
1700 pcg 1.1 {
1701 root 1.246 rvideo_mode = on;
1702    
1703     #ifndef NO_BELL
1704     on ^= rvideo_bell;
1705     #endif
1706 pcg 1.1
1707 root 1.246 if (rvideo_state != on)
1708 pcg 1.25 {
1709 root 1.246 rvideo_state = on;
1710    
1711 root 1.181 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]);
1712 sf-exg 1.427 #ifdef HAVE_IMG
1713 sf-exg 1.421 if (bg_img == 0)
1714 pcg 1.1 #endif
1715 root 1.258 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
1716 pcg 1.1
1717 root 1.246 XGCValues gcvalue;
1718 root 1.104 gcvalue.foreground = pix_colors[Color_fg];
1719     gcvalue.background = pix_colors[Color_bg];
1720 root 1.258 XChangeGC (dpy, gc, GCBackground | GCForeground, &gcvalue);
1721 root 1.246
1722 pcg 1.25 scr_clear ();
1723     scr_touch (true);
1724 pcg 1.1 }
1725     }
1726    
1727     /* ------------------------------------------------------------------------- */
1728     /*
1729     * Report current cursor position
1730     * XTERM_SEQ: Report position: ESC [ 6 n
1731     */
1732 root 1.417 void ecb_cold
1733 root 1.244 rxvt_term::scr_report_position () NOTHROW
1734 pcg 1.1 {
1735 pcg 1.30 tt_printf ("\033[%d;%dR", screen.cur.row + 1, screen.cur.col + 1);
1736 pcg 1.1 }
1737 ayin 1.282
1738 pcg 1.1 /* ------------------------------------------------------------------------- *
1739     * FONTS *
1740     * ------------------------------------------------------------------------- */
1741    
1742     /*
1743     * Set font style
1744     */
1745 root 1.417 void ecb_cold
1746 root 1.244 rxvt_term::set_font_style () NOTHROW
1747 pcg 1.1 {
1748 root 1.210 #if 0
1749     switch (charsets [screen.charset])
1750 pcg 1.25 {
1751     case '0': /* DEC Special Character & Line Drawing Set */
1752 pcg 1.4 break;
1753 pcg 1.25 case 'A': /* United Kingdom (UK) */
1754 pcg 1.4 break;
1755 pcg 1.25 case 'B': /* United States (USASCII) */
1756 pcg 1.4 break;
1757 pcg 1.25 case '<': /* Multinational character set */
1758 pcg 1.4 break;
1759 pcg 1.25 case '5': /* Finnish character set */
1760 pcg 1.4 break;
1761 pcg 1.25 case 'C': /* Finnish character set */
1762 pcg 1.4 break;
1763 pcg 1.25 case 'K': /* German character set */
1764 pcg 1.4 break;
1765 pcg 1.1 }
1766 root 1.210 #endif
1767 pcg 1.1 }
1768    
1769     /* ------------------------------------------------------------------------- */
1770     /*
1771     * Choose a font
1772     * XTERM_SEQ: Invoke G0 character set: CTRL-O
1773     * XTERM_SEQ: Invoke G1 character set: CTRL-N
1774     * XTERM_SEQ: Invoke G2 character set: ESC N
1775     * XTERM_SEQ: Invoke G3 character set: ESC O
1776     */
1777 root 1.417 void ecb_cold
1778 root 1.244 rxvt_term::scr_charset_choose (int set) NOTHROW
1779 root 1.136 {
1780     screen.charset = set;
1781     set_font_style ();
1782     }
1783 pcg 1.1
1784     /* ------------------------------------------------------------------------- */
1785     /*
1786     * Set a font
1787     * XTERM_SEQ: Set G0 character set: ESC ( <C>
1788     * XTERM_SEQ: Set G1 character set: ESC ) <C>
1789     * XTERM_SEQ: Set G2 character set: ESC * <C>
1790     * XTERM_SEQ: Set G3 character set: ESC + <C>
1791     * See set_font_style for possible values for <C>
1792     */
1793     void
1794 root 1.244 rxvt_term::scr_charset_set (int set, unsigned int ch) NOTHROW
1795 root 1.136 {
1796     charsets[set] = (unsigned char)ch;
1797     set_font_style ();
1798     }
1799 pcg 1.1
1800 ayin 1.282
1801 pcg 1.1 /* ------------------------------------------------------------------------- *
1802     * MAJOR SCREEN MANIPULATION *
1803     * ------------------------------------------------------------------------- */
1804    
1805     /*
1806 pcg 1.19 * refresh matching text.
1807     */
1808 root 1.417 bool ecb_cold
1809 root 1.244 rxvt_term::scr_refresh_rend (rend_t mask, rend_t value) NOTHROW
1810 pcg 1.19 {
1811     bool found = false;
1812    
1813 root 1.172 for (int i = 0; i < nrow; i++)
1814 pcg 1.19 {
1815 root 1.186 rend_t *drp = drawn_buf[i].r;
1816 pcg 1.19
1817 root 1.255 for (int col = 0; col < ncol; col++, drp++)
1818 pcg 1.19 if ((*drp & mask) == value)
1819     {
1820     found = true;
1821     *drp = ~value;
1822     }
1823     }
1824    
1825     return found;
1826     }
1827    
1828     /*
1829 pcg 1.1 * Refresh an area
1830     */
1831     enum {
1832 pcg 1.25 PART_BEG = 0,
1833     PART_END,
1834     RC_COUNT
1835 pcg 1.1 };
1836    
1837 root 1.417 void ecb_hot
1838 root 1.244 rxvt_term::scr_expose (int x, int y, int ewidth, int eheight, bool refresh) NOTHROW
1839 pcg 1.1 {
1840 pcg 1.11 int i;
1841     row_col_t rc[RC_COUNT];
1842 pcg 1.1
1843 root 1.186 if (!drawn_buf) /* sanity check */
1844 pcg 1.11 return;
1845 pcg 1.1
1846 root 1.82 #ifndef NO_SLOW_LINK_SUPPORT
1847     if (refresh_type == FAST_REFRESH && !display->is_local)
1848     {
1849     y = 0;
1850 root 1.172 eheight = height;
1851 root 1.82 }
1852     #endif
1853    
1854 pcg 1.25 /* round down */
1855 pcg 1.30 rc[PART_BEG].col = Pixel2Col (x);
1856     rc[PART_BEG].row = Pixel2Row (y);
1857 pcg 1.25 /* round up */
1858 root 1.172 rc[PART_END].col = Pixel2Width (x + ewidth + fwidth - 1);
1859     rc[PART_END].row = Pixel2Row (y + eheight + fheight - 1);
1860 pcg 1.1
1861 pcg 1.25 /* sanity checks */
1862 pcg 1.11 for (i = PART_BEG; i < RC_COUNT; i++)
1863     {
1864 root 1.183 min_it (rc[i].col, ncol - 1);
1865     min_it (rc[i].row, nrow - 1);
1866 pcg 1.1 }
1867 sf-exg 1.334
1868 pcg 1.11 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1869 root 1.186 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
1870 pcg 1.1
1871 root 1.235 num_scr_allow = 0;
1872    
1873 pcg 1.11 if (refresh)
1874 root 1.235 scr_refresh ();
1875 pcg 1.1 }
1876    
1877     /* ------------------------------------------------------------------------- */
1878     /*
1879     * Refresh the entire screen
1880     */
1881     void
1882 root 1.244 rxvt_term::scr_touch (bool refresh) NOTHROW
1883 pcg 1.1 {
1884 sf-exg 1.411 scr_expose (0, 0, vt_width, vt_height, refresh);
1885 pcg 1.1 }
1886    
1887     /* ------------------------------------------------------------------------- */
1888     /*
1889     * Move the display so that the line represented by scrollbar value Y is at
1890     * the top of the screen
1891     */
1892 root 1.228 void
1893 root 1.244 rxvt_term::scr_move_to (int y, int len) NOTHROW
1894 pcg 1.1 {
1895 root 1.232 scr_changeview ((top_row - nrow) * (len - y) / len + (nrow - 1));
1896 pcg 1.1 }
1897    
1898     /* ------------------------------------------------------------------------- */
1899     /*
1900     * Page the screen up/down nlines
1901     * direction should be UP or DN
1902     */
1903 root 1.228 bool
1904 root 1.244 rxvt_term::scr_page (enum page_dirn direction, int nlines) NOTHROW
1905 pcg 1.1 {
1906 root 1.228 int new_view_start =
1907     direction == UP ? view_start - nlines
1908     : view_start + nlines;
1909 root 1.158
1910 root 1.228 return scr_changeview (new_view_start);
1911 pcg 1.1 }
1912    
1913 root 1.228 bool
1914 root 1.244 rxvt_term::scr_changeview (int new_view_start) NOTHROW
1915 pcg 1.1 {
1916 root 1.228 clamp_it (new_view_start, top_row, 0);
1917    
1918 root 1.229 if (new_view_start == view_start)
1919     return false;
1920    
1921     num_scr += new_view_start - view_start;
1922     view_start = new_view_start;
1923 root 1.234 want_refresh = 1;
1924    
1925 root 1.229 HOOK_INVOKE ((this, HOOK_VIEW_CHANGE, DT_INT, view_start, DT_END));
1926 root 1.210
1927 root 1.229 return true;
1928 pcg 1.1 }
1929    
1930 root 1.246 #ifndef NO_BELL
1931     void
1932 root 1.283 rxvt_term::bell_cb (ev::timer &w, int revents)
1933 root 1.246 {
1934     rvideo_bell = false;
1935     scr_rvideo_mode (rvideo_mode);
1936 root 1.291 refresh_check ();
1937 root 1.246 }
1938     #endif
1939    
1940 pcg 1.1 /* ------------------------------------------------------------------------- */
1941     void
1942 root 1.244 rxvt_term::scr_bell () NOTHROW
1943 pcg 1.1 {
1944     #ifndef NO_BELL
1945 root 1.167
1946 pcg 1.1 # ifndef NO_MAPALERT
1947     # ifdef MAPALERT_OPTION
1948 root 1.268 if (option (Opt_mapAlert))
1949 pcg 1.1 # endif
1950 sf-exg 1.380 XMapWindow (dpy, parent);
1951 pcg 1.1 # endif
1952 root 1.278
1953 ayin 1.269 # if ENABLE_FRILLS
1954     if (option (Opt_urgentOnBell))
1955 root 1.311 set_urgency (1);
1956 ayin 1.269 # endif
1957 root 1.167
1958 root 1.268 if (option (Opt_visualBell))
1959 pcg 1.25 {
1960 root 1.246 rvideo_bell = true;
1961     scr_rvideo_mode (rvideo_mode);
1962 root 1.290 flush ();
1963 root 1.246
1964 root 1.283 bell_ev.start (VISUAL_BELL_DURATION);
1965 pcg 1.25 }
1966     else
1967 root 1.258 XBell (dpy, 0);
1968 sf-exg 1.331 HOOK_INVOKE ((this, HOOK_BELL, DT_END));
1969 pcg 1.1 #endif
1970     }
1971    
1972     /* ------------------------------------------------------------------------- */
1973 root 1.417 void ecb_cold
1974 root 1.244 rxvt_term::scr_printscreen (int fullhist) NOTHROW
1975 pcg 1.1 {
1976     #ifdef PRINTPIPE
1977 root 1.176 int nrows, row_start;
1978 root 1.308 FILE *fd = popen_printer ();
1979 pcg 1.1
1980 root 1.308 if (!fd)
1981 pcg 1.25 return;
1982 root 1.104
1983 root 1.176 if (fullhist)
1984     {
1985 root 1.228 nrows = nrow - top_row;
1986     row_start = top_row;
1987 root 1.176 }
1988 pcg 1.25 else
1989     {
1990 root 1.176 nrows = nrow;
1991 root 1.228 row_start = view_start;
1992 pcg 1.1 }
1993    
1994 root 1.104 wctomb (0, 0);
1995    
1996 root 1.330 for (int r1 = row_start; r1 < row_start + nrows; r1++)
1997 pcg 1.25 {
1998 root 1.176 text_t *tp = ROW(r1).t;
1999     int len = ROW(r1).l;
2000 root 1.104
2001 root 1.176 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN
2002 root 1.104 {
2003     char mb[MB_LEN_MAX];
2004     text_t t = *tp++;
2005     if (t == NOCHAR)
2006     continue;
2007    
2008     len = wctomb (mb, t);
2009    
2010     if (len <= 0)
2011     {
2012     mb[0] = ' ';
2013     len = 1;
2014     }
2015    
2016     fwrite (mb, 1, len, fd);
2017     }
2018    
2019     fputc ('\n', fd);
2020 pcg 1.1 }
2021 root 1.104
2022 pcg 1.25 pclose_printer (fd);
2023 pcg 1.1 #endif
2024     }
2025    
2026     /* ------------------------------------------------------------------------- */
2027     /*
2028     * Refresh the screen
2029 pcg 1.21 * drawn_text/drawn_rend contain the screen information before the update.
2030     * screen.text/screen.rend contain what the screen will change to.
2031 pcg 1.1 */
2032 root 1.417 void ecb_hot
2033 root 1.244 rxvt_term::scr_refresh () NOTHROW
2034 pcg 1.1 {
2035 pcg 1.35 int16_t col, row, /* column/row we're processing */
2036     ocrow; /* old cursor row */
2037 root 1.179 int i; /* tmp */
2038 pcg 1.1 #ifndef NO_CURSORCOLOR
2039 pcg 1.35 rend_t cc1; /* store colours at cursor position (s) */
2040 pcg 1.1 #endif
2041 root 1.104 rend_t *crp; // cursor rendition pointer
2042 root 1.265 rend_t ccol1, /* Cursor colour */
2043     ccol2; /* Cursor colour2 */
2044 pcg 1.1
2045 root 1.136 want_refresh = 0; /* screen is current */
2046    
2047 root 1.172 if (refresh_type == NO_REFRESH || !mapped)
2048 pcg 1.25 return;
2049 pcg 1.1
2050 pcg 1.25 /*
2051     * A: set up vars
2052     */
2053     refresh_count = 0;
2054 pcg 1.1
2055 root 1.327 unsigned int old_screen_flags = screen.flags;
2056 sf-exg 1.404 bool have_bg = 0;
2057 sf-exg 1.427 #ifdef HAVE_IMG
2058 sf-exg 1.421 have_bg = bg_img != 0;
2059 pcg 1.1 #endif
2060 pcg 1.25 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
2061 pcg 1.1
2062 pcg 1.25 /*
2063     * B: reverse any characters which are selected
2064     */
2065     scr_reverse_selection ();
2066 pcg 1.1
2067 root 1.327 HOOK_INVOKE ((this, HOOK_REFRESH_BEGIN, DT_END));
2068     #if ENABLE_OVERLAY
2069     scr_swap_overlay ();
2070     #endif
2071    
2072 sf-exg 1.403 bool showcursor = screen.flags & Screen_VisibleCursor;
2073 root 1.327
2074 pcg 1.25 /*
2075 pcg 1.30 * C: set the cursor character (s)
2076 pcg 1.25 */
2077     {
2078 sf-exg 1.403 bool setoldcursor;
2079 pcg 1.1
2080     #ifdef CURSOR_BLINK
2081 pcg 1.25 if (hidden_cursor)
2082     showcursor = 0;
2083 pcg 1.1 #endif
2084    
2085 pcg 1.25 if (showcursor)
2086     {
2087 root 1.104 int col = screen.cur.col;
2088    
2089 root 1.175 while (col && ROW(screen.cur.row).t[col] == NOCHAR)
2090 root 1.104 col--;
2091    
2092 root 1.175 crp = &ROW(screen.cur.row).r[col];
2093 pcg 1.1
2094 root 1.265 #ifndef NO_CURSORCOLOR
2095     cc1 = *crp & (RS_fgMask | RS_bgMask);
2096     if (ISSET_PIXCOLOR (Color_cursor))
2097     ccol1 = Color_cursor;
2098     else
2099     #endif
2100     #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2101     ccol1 = fgcolor_of (rstyle);
2102     #else
2103     ccol1 = Color_fg;
2104     #endif
2105    
2106     #ifndef NO_CURSORCOLOR
2107     if (ISSET_PIXCOLOR (Color_cursor2))
2108     ccol2 = Color_cursor2;
2109     else
2110     #endif
2111     #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2112     ccol2 = bgcolor_of (rstyle);
2113     #else
2114     ccol2 = Color_bg;
2115     #endif
2116    
2117 root 1.337 if (focus)
2118 pcg 1.25 {
2119 root 1.268 if (option (Opt_cursorUnderline))
2120 root 1.162 *crp ^= RS_Uline;
2121     else
2122     {
2123     *crp ^= RS_RVid;
2124     *crp = SET_FGCOLOR (*crp, ccol1);
2125     *crp = SET_BGCOLOR (*crp, ccol2);
2126     }
2127 pcg 1.1 }
2128 pcg 1.4 }
2129 pcg 1.1
2130 pcg 1.25 /* make sure no outline cursor is left around */
2131     setoldcursor = 0;
2132     if (ocrow != -1)
2133 pcg 1.4 {
2134 root 1.228 if (screen.cur.row - view_start != ocrow
2135 pcg 1.25 || screen.cur.col != oldcursor.col)
2136 pcg 1.4 {
2137 root 1.172 if (ocrow < nrow
2138     && oldcursor.col < ncol)
2139 root 1.186 drawn_buf[ocrow].r[oldcursor.col] ^= (RS_RVid | RS_Uline);
2140 pcg 1.66
2141 root 1.172 if (focus || !showcursor)
2142 pcg 1.25 oldcursor.row = -1;
2143     else
2144     setoldcursor = 1;
2145 pcg 1.4 }
2146 pcg 1.25 }
2147 root 1.172 else if (!focus)
2148 pcg 1.25 setoldcursor = 1;
2149 pcg 1.66
2150 pcg 1.25 if (setoldcursor)
2151     {
2152 root 1.228 if (screen.cur.row - view_start >= nrow)
2153 pcg 1.25 oldcursor.row = -1;
2154     else
2155     {
2156 root 1.228 oldcursor.row = screen.cur.row - view_start;
2157 pcg 1.25 oldcursor.col = screen.cur.col;
2158     }
2159     }
2160     }
2161    
2162     #ifndef NO_SLOW_LINK_SUPPORT
2163     /*
2164     * D: CopyArea pass - very useful for slower links
2165     * This has been deliberately kept simple.
2166     */
2167 root 1.82 if (!display->is_local
2168 root 1.176 && refresh_type == FAST_REFRESH && num_scr_allow && num_scr
2169 root 1.260 && abs (num_scr) < nrow && !have_bg)
2170 pcg 1.25 {
2171 pcg 1.66 int16_t nits;
2172 root 1.261 int i = num_scr;
2173 pcg 1.66 int j;
2174     int len, wlen;
2175 pcg 1.25
2176 root 1.172 j = nrow;
2177 pcg 1.25 wlen = len = -1;
2178     row = i > 0 ? 0 : j - 1;
2179 root 1.261
2180 pcg 1.25 for (; j-- >= 0; row += (i > 0 ? 1 : -1))
2181     {
2182 root 1.172 if (row + i >= 0 && row + i < nrow && row + i != ocrow)
2183 pcg 1.25 {
2184 root 1.228 line_t s = ROW(view_start + row);
2185 root 1.186 line_t d = drawn_buf[row];
2186     line_t d2 = drawn_buf[row + i];
2187 pcg 1.25
2188 root 1.172 for (nits = 0, col = ncol; col--; )
2189     if (s.t[col] != d2.t[col] || s.r[col] != d2.r[col])
2190 pcg 1.25 nits--;
2191 root 1.172 else if (s.t[col] != d.t[col] || s.r[col] != d.r[col])
2192 pcg 1.25 nits++;
2193    
2194     if (nits > 8) /* XXX: arbitrary choice */
2195     {
2196 root 1.172 for (col = ncol; col--; )
2197 pcg 1.25 {
2198 root 1.172 *d.t++ = *d2.t++;
2199     *d.r++ = *d2.r++;
2200 pcg 1.25 }
2201    
2202     if (len == -1)
2203     len = row;
2204    
2205     wlen = row;
2206     continue;
2207     }
2208     }
2209    
2210 root 1.261 if (len >= 0)
2211 pcg 1.25 {
2212     /* also comes here at end if needed because of >= above */
2213     if (wlen < len)
2214 root 1.182 ::swap (wlen, len);
2215 pcg 1.25
2216 root 1.260 XGCValues gcv;
2217    
2218     gcv.graphics_exposures = 1; XChangeGC (dpy, gc, GCGraphicsExposures, &gcv);
2219 root 1.258 XCopyArea (dpy, vt, vt,
2220 root 1.172 gc, 0, Row2Pixel (len + i),
2221 root 1.207 (unsigned int)this->width,
2222 pcg 1.25 (unsigned int)Height2Pixel (wlen - len + 1),
2223     0, Row2Pixel (len));
2224 root 1.260 gcv.graphics_exposures = 0; XChangeGC (dpy, gc, GCGraphicsExposures, &gcv);
2225    
2226 pcg 1.25 len = -1;
2227     }
2228     }
2229 pcg 1.1 }
2230     #endif
2231    
2232 pcg 1.25 /*
2233     * E: main pass across every character
2234     */
2235 root 1.172 for (row = 0; row < nrow; row++)
2236 pcg 1.25 {
2237 root 1.228 text_t *stp = ROW(view_start + row).t;
2238     rend_t *srp = ROW(view_start + row).r;
2239 root 1.186 text_t *dtp = drawn_buf[row].t;
2240     rend_t *drp = drawn_buf[row].r;
2241 pcg 1.25
2242     /*
2243     * E2: OK, now the real pass
2244     */
2245 pcg 1.30 int ypixel = (int)Row2Pixel (row);
2246 pcg 1.25
2247 root 1.172 for (col = 0; col < ncol; col++)
2248 pcg 1.25 {
2249     /* compare new text with old - if exactly the same then continue */
2250     if (stp[col] == dtp[col] /* Must match characters to skip. */
2251 root 1.129 && (RS_SAME (srp[col], drp[col]) /* Either rendition the same or */
2252 pcg 1.25 || (stp[col] == ' ' /* space w/ no background change */
2253 pcg 1.43 && GET_BGATTR (srp[col]) == GET_BGATTR (drp[col]))))
2254 pcg 1.25 continue;
2255 pcg 1.1
2256 pcg 1.43 // redraw one or more characters
2257    
2258 root 1.141 // seek to the beginning of wide characters
2259 sf-exg 1.384 while (ecb_unlikely (stp[col] == NOCHAR && col > 0))
2260 pcg 1.43 --col;
2261    
2262 sf-exg 1.339 rend_t rend = srp[col]; /* screen rendition (target rendition) */
2263 pcg 1.25 text_t *text = stp + col;
2264     int count = 1;
2265 pcg 1.1
2266 pcg 1.25 dtp[col] = stp[col];
2267     drp[col] = rend;
2268 pcg 1.1
2269 pcg 1.30 int xpixel = Col2Pixel (col);
2270 pcg 1.1
2271 root 1.172 for (i = 0; ++col < ncol; )
2272 pcg 1.25 {
2273     if (stp[col] == NOCHAR)
2274     {
2275     dtp[col] = stp[col];
2276 root 1.328 drp[col] = srp[col];
2277    
2278 pcg 1.25 count++;
2279 root 1.104 i++;
2280 pcg 1.1
2281 pcg 1.25 continue;
2282     }
2283 pcg 1.1
2284 root 1.129 if (!RS_SAME (rend, srp[col]))
2285 pcg 1.25 break;
2286 pcg 1.1
2287 pcg 1.25 count++;
2288 pcg 1.1
2289 pcg 1.25 if (stp[col] != dtp[col]
2290 root 1.129 || !RS_SAME (srp[col], drp[col]))
2291 pcg 1.25 {
2292 root 1.260 if (have_bg && (i++ > count / 2))
2293 pcg 1.25 break;
2294 pcg 1.1
2295 pcg 1.25 dtp[col] = stp[col];
2296     drp[col] = rend;
2297     i = 0;
2298     }
2299 root 1.260 else if (have_bg || (stp[col] != ' ' && ++i >= 16))
2300 pcg 1.25 break;
2301     }
2302 pcg 1.1
2303 pcg 1.25 col--; /* went one too far. move back */
2304     count -= i; /* dump any matching trailing chars */
2305 pcg 1.1
2306 root 1.104 // sometimes we optimize away the trailing NOCHAR's, add them back
2307 sf-exg 1.384 while (ecb_unlikely (i && text[count] == NOCHAR))
2308 root 1.104 count++, i--;
2309    
2310 pcg 1.25 /*
2311     * Determine the attributes for the string
2312     */
2313 root 1.201 int fore = fgcolor_of (rend); // desired foreground
2314     int back = bgcolor_of (rend); // desired background
2315 pcg 1.17
2316 root 1.197 // only do special processing if any attributes are set, which is unlikely
2317 sf-exg 1.384 if (ecb_unlikely (rend & (RS_baseattrMask | RS_Careful | RS_Sel)))
2318 root 1.129 {
2319     bool invert = rend & RS_RVid;
2320 pcg 1.1
2321 root 1.129 #ifndef NO_BOLD_UNDERLINE_REVERSE
2322 root 1.290 if (rend & RS_Bold && fore == Color_fg)
2323 root 1.129 {
2324     if (ISSET_PIXCOLOR (Color_BD))
2325     fore = Color_BD;
2326     # if !ENABLE_STYLES
2327     else
2328     invert = !invert;
2329     # endif
2330     }
2331 pcg 1.1
2332 root 1.290 if (rend & RS_Italic && fore == Color_fg)
2333 root 1.129 {
2334     if (ISSET_PIXCOLOR (Color_IT))
2335     fore = Color_IT;
2336     # if !ENABLE_STYLES
2337     else
2338     invert = !invert;
2339     # endif
2340     }
2341 pcg 1.36
2342 root 1.263 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL))
2343 root 1.129 fore = Color_UL;
2344 pcg 1.1 #endif
2345    
2346 sf-exg 1.340 #ifdef OPTION_HC
2347     if (rend & RS_Sel)
2348     {
2349     /* invert the column if no highlightColor is set or it is the
2350     * current cursor column */
2351     if (!(showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2352     && ISSET_PIXCOLOR (Color_HC))
2353     {
2354     if (ISSET_PIXCOLOR (Color_HTC))
2355     fore = Color_HTC;
2356     // if invert is 0 reverse video is set so we use bg color as fg color
2357     else if (!invert)
2358     fore = back;
2359 root 1.341
2360 sf-exg 1.340 back = Color_HC;
2361     invert = 0;
2362     }
2363     }
2364     #endif
2365    
2366 root 1.129 if (invert)
2367     {
2368 root 1.264 ::swap (fore, back);
2369 pcg 1.36
2370     #ifndef NO_BOLD_UNDERLINE_REVERSE
2371 root 1.168 if (fore == back)
2372     {
2373     fore = Color_bg;
2374     back = Color_fg;
2375     }
2376 pcg 1.36 #endif
2377 root 1.129 }
2378 pcg 1.36
2379 pcg 1.37 #ifdef TEXT_BLINK
2380 root 1.129 if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
2381 pcg 1.37 {
2382 root 1.287 if (!text_blink_ev.is_active ())
2383 root 1.129 {
2384 root 1.286 text_blink_ev.again ();
2385 root 1.129 hidden_text = 0;
2386     }
2387     else if (hidden_text)
2388     fore = back;
2389 pcg 1.37 }
2390 root 1.129 #endif
2391 root 1.264
2392     #if ENABLE_STYLES
2393     // "careful" (too wide) character handling
2394    
2395     // include previous careful character(s) if possible, looks nicer (best effort...)
2396     while (text > stp
2397     && srp[text - stp - 1] & RS_Careful
2398     && RS_SAME (rend, srp[text - stp - 1]))
2399     text--, count++, xpixel -= fwidth;
2400    
2401     // force redraw after "careful" characters to avoid pixel droppings
2402     for (int i = 0; srp[col + i] & RS_Careful && col + i < ncol - 1; i++)
2403     drp[col + i + 1] = srp[col + i + 1] ^ RS_redraw;
2404    
2405     // force redraw before "careful" characters to avoid pixel droppings
2406     for (int i = 0; srp[text - stp - i] & RS_Careful && text - i > stp; i++)
2407     drp[text - stp - i - 1] = srp[text - stp - i - 1] ^ RS_redraw;
2408     #endif
2409 pcg 1.37 }
2410    
2411 pcg 1.25 /*
2412     * Actually do the drawing of the string here
2413     */
2414 root 1.336 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)];
2415 pcg 1.25
2416 sf-exg 1.384 if (ecb_likely (have_bg && back == Color_bg))
2417 pcg 1.25 {
2418 root 1.260 // this is very ugly, maybe push it into ->draw?
2419    
2420     for (i = 0; i < count; i++) /* don't draw empty strings */
2421     if (text[i] != ' ')
2422     {
2423 root 1.267 font->draw (*drawable, xpixel, ypixel, text, count, fore, Color_transparent);
2424 root 1.260 goto did_clear;
2425     }
2426 pcg 1.25
2427 root 1.260 CLEAR_CHARS (xpixel, ypixel, count);
2428     did_clear: ;
2429 pcg 1.25 }
2430     else
2431 root 1.172 font->draw (*drawable, xpixel, ypixel, text, count, fore, back);
2432 pcg 1.1
2433 sf-exg 1.384 if (ecb_unlikely (rend & RS_Uline && font->descent > 1 && fore != back))
2434 root 1.147 {
2435 root 1.151 #if ENABLE_FRILLS
2436     if (ISSET_PIXCOLOR (Color_underline))
2437 root 1.258 XSetForeground (dpy, gc, pix_colors[Color_underline]);
2438 root 1.151 else
2439     #endif
2440 root 1.258 XSetForeground (dpy, gc, pix_colors[fore]);
2441 root 1.151
2442 root 1.299 XDrawLine (dpy, vt, gc,
2443 root 1.147 xpixel, ypixel + font->ascent + 1,
2444     xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2445     }
2446 pcg 1.25 } /* for (col....) */
2447     } /* for (row....) */
2448 pcg 1.1
2449 pcg 1.25 /*
2450     * G: cleanup cursor and display outline cursor if necessary
2451     */
2452     if (showcursor)
2453     {
2454 root 1.172 if (focus)
2455 pcg 1.25 {
2456 root 1.268 if (option (Opt_cursorUnderline))
2457 root 1.162 *crp ^= RS_Uline;
2458     else
2459     {
2460     *crp ^= RS_RVid;
2461 pcg 1.1 #ifndef NO_CURSORCOLOR
2462 root 1.162 *crp = (*crp & ~ (RS_fgMask | RS_bgMask)) | cc1;
2463 pcg 1.1 #endif
2464 root 1.162 }
2465 pcg 1.25 }
2466     else if (oldcursor.row >= 0)
2467     {
2468 root 1.164 int cursorwidth = 1;
2469     int col = oldcursor.col;
2470    
2471 root 1.175 while (col && ROW(screen.cur.row).t[col] == NOCHAR)
2472 root 1.164 col--;
2473    
2474 root 1.172 while (col + cursorwidth < ncol
2475 root 1.186 && drawn_buf[oldcursor.row].t[col + cursorwidth] == NOCHAR)
2476 root 1.164 cursorwidth++;
2477    
2478 pcg 1.1 #ifndef NO_CURSORCOLOR
2479 pcg 1.25 if (ISSET_PIXCOLOR (Color_cursor))
2480 root 1.258 XSetForeground (dpy, gc, pix_colors[Color_cursor]);
2481 root 1.265 else
2482 pcg 1.1 #endif
2483 root 1.265 XSetForeground (dpy, gc, pix_colors[ccol1]);
2484 pcg 1.35
2485 root 1.299 XDrawRectangle (dpy, vt, gc,
2486 root 1.164 Col2Pixel (col),
2487 pcg 1.43 Row2Pixel (oldcursor.row),
2488     (unsigned int) (Width2Pixel (cursorwidth) - 1),
2489 sf-exg 1.414 (unsigned int) (Height2Pixel (1) - 1));
2490 pcg 1.4 }
2491 pcg 1.1 }
2492 pcg 1.12
2493 pcg 1.25 /*
2494     * H: cleanup selection
2495     */
2496 root 1.327 #if ENABLE_OVERLAY
2497     scr_swap_overlay ();
2498     #endif
2499     HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2500    
2501 pcg 1.25 scr_reverse_selection ();
2502    
2503 root 1.327 screen.flags = old_screen_flags;
2504 pcg 1.25 num_scr = 0;
2505     num_scr_allow = 1;
2506 pcg 1.1 }
2507 pcg 1.11
2508 root 1.417 void ecb_cold
2509 root 1.244 rxvt_term::scr_remap_chars (line_t &l) NOTHROW
2510 pcg 1.32 {
2511 root 1.415 if (!l.valid ())
2512 pcg 1.32 return;
2513    
2514 root 1.214 l.touch (); // maybe a bit of an overkill, but it's not performance-relevant
2515 root 1.210
2516 root 1.172 for (int i = ncol; i--; )
2517     l.r[i] = SET_FONT (l.r[i], FONTSET (l.r[i])->find_font (l.t[i]));
2518 pcg 1.32 }
2519    
2520 root 1.417 void ecb_cold
2521 root 1.244 rxvt_term::scr_remap_chars () NOTHROW
2522 pcg 1.32 {
2523 root 1.175 for (int i = total_rows; i--; )
2524 root 1.186 scr_remap_chars (row_buf [i]);
2525 pcg 1.32
2526 root 1.172 for (int i = nrow; i--; )
2527 pcg 1.32 {
2528 root 1.186 scr_remap_chars (drawn_buf [i]);
2529     scr_remap_chars (swap_buf [i]);
2530 pcg 1.32 }
2531     }
2532    
2533 root 1.417 void ecb_cold
2534 sf-exg 1.364 rxvt_term::scr_recolour (bool refresh) NOTHROW
2535 root 1.129 {
2536 sf-exg 1.364 bool transparent = false;
2537    
2538 sf-exg 1.427 #ifdef HAVE_IMG
2539 sf-exg 1.421 if (bg_img != 0)
2540 sf-exg 1.364 {
2541 root 1.420 # if ENABLE_TRANSPARENCY
2542 sf-exg 1.366 if (bg_flags & BG_IS_TRANSPARENT)
2543 sf-exg 1.364 {
2544 sf-exg 1.421 XSetWindowBackgroundPixmap (dpy, parent, bg_img->pm);
2545 sf-exg 1.364 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2546    
2547     transparent = true;
2548     }
2549     else
2550     # endif
2551     {
2552 sf-exg 1.380 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2553 sf-exg 1.421 XSetWindowBackgroundPixmap (dpy, vt, bg_img->pm);
2554 sf-exg 1.364 }
2555     }
2556     else
2557     #endif
2558     {
2559 sf-exg 1.380 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2560 sf-exg 1.364 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
2561     }
2562 root 1.290
2563 sf-exg 1.380 XClearWindow (dpy, parent);
2564 root 1.290
2565 sasha 1.274 if (scrollBar.win)
2566 sf-exg 1.363 {
2567 sf-exg 1.364 if (transparent)
2568     XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
2569     else
2570 sf-exg 1.426 XSetWindowBackground (dpy, scrollBar.win, pix_colors[scrollBar.color ()]);
2571 sf-exg 1.394 scrollBar.state = SB_STATE_IDLE;
2572 sf-exg 1.363 scrollBar.show (0);
2573     }
2574 root 1.290
2575 sf-exg 1.364 if (refresh)
2576     {
2577     scr_clear ();
2578     scr_touch (true);
2579     }
2580 root 1.129 want_refresh = 1;
2581     }
2582    
2583 pcg 1.1 /* ------------------------------------------------------------------------- */
2584     void
2585 root 1.244 rxvt_term::scr_clear (bool really) NOTHROW
2586 pcg 1.1 {
2587 root 1.172 if (!mapped)
2588 pcg 1.11 return;
2589    
2590     num_scr_allow = 0;
2591     want_refresh = 1;
2592 pcg 1.43
2593     if (really)
2594 root 1.258 XClearWindow (dpy, vt);
2595 pcg 1.1 }
2596    
2597 root 1.219 void
2598 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
2599 root 1.219 {
2600 root 1.228 int view_end = view_start + nrow;
2601 root 1.219 int row, col;
2602    
2603 root 1.228 for (row = max (beg_row, view_start); row <= min (end_row, view_end); row++)
2604 root 1.219 {
2605     text_t *stp = ROW(row).t;
2606     rend_t *srp = ROW(row).r;
2607    
2608     for (col = beg_col; col < end_col; col++)
2609     srp[col] ^= rstyle1;
2610    
2611     while (col-- > beg_col && (stp[col] == NOCHAR || unicode::is_space (stp[col])))
2612     srp[col] ^= rstyle2;
2613    
2614     if (++col < end_col)
2615     srp[col] ^= rstyle2;
2616     }
2617     }
2618    
2619     void
2620 root 1.244 rxvt_term::scr_xor_span (int beg_row, int beg_col, int end_row, int end_col, rend_t rstyle) NOTHROW
2621 root 1.219 {
2622 root 1.228 int view_end = view_start + nrow;
2623 root 1.219 int row, col;
2624    
2625 root 1.228 if (beg_row >= view_start)
2626 root 1.219 {
2627     col = beg_col;
2628     row = beg_row;
2629     }
2630     else
2631     {
2632     col = 0;
2633 root 1.228 row = view_start;
2634 root 1.219 }
2635    
2636     for (; row < min (end_row, view_end); row++, col = 0)
2637     for (rend_t *srp = ROW(row).r; col < ncol; col++)
2638 root 1.220 srp[col] ^= rstyle;
2639 root 1.219
2640     if (row == end_row)
2641     for (rend_t *srp = ROW(row).r; col < end_col; col++)
2642 root 1.220 srp[col] ^= rstyle;
2643 root 1.219 }
2644    
2645 pcg 1.1 /* ------------------------------------------------------------------------- */
2646 root 1.417 void ecb_hot
2647 root 1.244 rxvt_term::scr_reverse_selection () NOTHROW
2648 pcg 1.1 {
2649 root 1.175 if (selection.op
2650     && current_screen == selection.screen
2651 root 1.228 && selection.end.row >= view_start)
2652 pcg 1.25 {
2653 root 1.256 #if !ENABLE_MINIMAL
2654 root 1.136 if (selection.rect)
2655 root 1.219 scr_xor_rect (selection.beg.row, selection.beg.col,
2656     selection.end.row, selection.end.col,
2657 sf-exg 1.340 RS_Sel | RS_RVid, RS_Sel | RS_RVid | RS_Uline);
2658 pcg 1.25 else
2659 root 1.136 #endif
2660 root 1.219 scr_xor_span (selection.beg.row, selection.beg.col,
2661     selection.end.row, selection.end.col,
2662 sf-exg 1.340 RS_Sel | RS_RVid);
2663 pcg 1.1 }
2664     }
2665    
2666     /* ------------------------------------------------------------------------- */
2667     /*
2668     * Dump the whole scrollback and screen to the passed filedescriptor. The
2669     * invoking routine must close the fd.
2670     */
2671     #if 0
2672     void
2673 root 1.244 rxvt_term::scr_dump (int fd) NOTHROW
2674 pcg 1.1 {
2675 sf-exg 1.409 // if this method is needed, it can be implemented by factoring the
2676     // relevant code in scr_printscreen
2677 pcg 1.1 }
2678     #endif
2679 ayin 1.282
2680 pcg 1.1 /* ------------------------------------------------------------------------- *
2681     * CHARACTER SELECTION *
2682     * ------------------------------------------------------------------------- */
2683     void
2684 root 1.244 rxvt_term::selection_check (int check_more) NOTHROW
2685 pcg 1.1 {
2686 pcg 1.25 if (!selection.op)
2687     return;
2688 pcg 1.1
2689 root 1.228 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow)
2690 sf-exg 1.405 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow)
2691 root 1.228 || !IN_RANGE_EXC (selection.end.row, top_row, nrow)
2692 pcg 1.25 || (check_more == 1
2693     && current_screen == selection.screen
2694 pcg 1.30 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2695 sf-exg 1.407 && ROWCOL_IS_BEFORE (screen.cur, selection.end)))
2696 sf-exg 1.405 CLEAR_ALL_SELECTION ();
2697 pcg 1.1 }
2698    
2699     /* ------------------------------------------------------------------------- */
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 pcg 1.59 #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     want_refresh = 1;
3142 root 1.136
3143 pcg 1.25 switch (selection.op)
3144     {
3145     case SELECTION_INIT:
3146 pcg 1.30 CLEAR_SELECTION ();
3147 pcg 1.21 selection.op = SELECTION_BEGIN;
3148 pcg 1.25 /* FALLTHROUGH */
3149     case SELECTION_BEGIN:
3150 pcg 1.21 if (row != selection.mark.row || col != selection.mark.col
3151 pcg 1.4 || (!button3 && buttonpress))
3152 pcg 1.25 selection.op = SELECTION_CONT;
3153 pcg 1.4 break;
3154 pcg 1.25 case SELECTION_DONE:
3155 pcg 1.21 selection.op = SELECTION_CONT;
3156 pcg 1.25 /* FALLTHROUGH */
3157     case SELECTION_CONT:
3158 pcg 1.4 break;
3159 pcg 1.25 case SELECTION_CLEAR:
3160 pcg 1.21 selection_start_colrow (col, row);
3161 pcg 1.25 /* FALLTHROUGH */
3162     default:
3163 pcg 1.4 return;
3164 pcg 1.1 }
3165 root 1.136
3166 pcg 1.25 if (selection.beg.col == selection.end.col
3167     && selection.beg.col != selection.mark.col
3168     && selection.beg.row == selection.end.row
3169     && selection.beg.row != selection.mark.row)
3170     {
3171     selection.beg.col = selection.end.col = selection.mark.col;
3172     selection.beg.row = selection.end.row = selection.mark.row;
3173 pcg 1.1 }
3174    
3175 pcg 1.25 pos.col = col;
3176 root 1.228 pos.row = view_start + row;
3177 pcg 1.1
3178 pcg 1.25 /*
3179     * This is mainly xterm style selection with a couple of differences, mainly
3180     * in the way button3 drag extension works.
3181     * We're either doing: button1 drag; button3 press; or button3 drag
3182     * a) button1 drag : select around a midpoint/word/line - that point/word/line
3183     * is always at the left/right edge of the selection.
3184     * b) button3 press: extend/contract character/word/line at whichever edge of
3185     * the selection we are closest to.
3186     * c) button3 drag : extend/contract character/word/line - we select around
3187     * a point/word/line which is either the start or end of the selection
3188     * and it was decided by whichever point/word/line was `fixed' at the
3189     * time of the most recent button3 press
3190     */
3191     if (button3 && buttonpress)
3192 ayin 1.284 {
3193     /* button3 press */
3194 pcg 1.25 /*
3195     * first determine which edge of the selection we are closest to
3196     */
3197 pcg 1.30 if (ROWCOL_IS_BEFORE (pos, selection.beg)
3198     || (!ROWCOL_IS_AFTER (pos, selection.end)
3199 pcg 1.25 && (((pos.col - selection.beg.col)
3200     + ((pos.row - selection.beg.row) * ncol))
3201     < ((selection.end.col - pos.col)
3202     + ((selection.end.row - pos.row) * ncol)))))
3203     closeto = LEFT;
3204 pcg 1.59
3205 pcg 1.25 if (closeto == LEFT)
3206     {
3207     selection.beg.row = pos.row;
3208     selection.beg.col = pos.col;
3209     selection.mark.row = selection.end.row;
3210 pcg 1.59 selection.mark.col = selection.end.col - (selection.clicks == 2);
3211 pcg 1.25 }
3212     else
3213     {
3214     selection.end.row = pos.row;
3215     selection.end.col = pos.col;
3216     selection.mark.row = selection.beg.row;
3217     selection.mark.col = selection.beg.col;
3218     }
3219     }
3220     else
3221 ayin 1.284 {
3222     /* button1 drag or button3 drag */
3223 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, pos))
3224 pcg 1.25 {
3225 root 1.136 if (selection.mark.row == selection.end.row
3226     && selection.mark.col == selection.end.col
3227     && clickchange
3228     && selection.clicks == 2)
3229 pcg 1.25 selection.mark.col--;
3230 pcg 1.59
3231 pcg 1.25 selection.beg.row = pos.row;
3232     selection.beg.col = pos.col;
3233     selection.end.row = selection.mark.row;
3234 pcg 1.59 selection.end.col = selection.mark.col + (selection.clicks == 2);
3235 pcg 1.25 }
3236     else
3237     {
3238     selection.beg.row = selection.mark.row;
3239     selection.beg.col = selection.mark.col;
3240     selection.end.row = pos.row;
3241     selection.end.col = pos.col;
3242 pcg 1.4 }
3243 pcg 1.1 }
3244    
3245 pcg 1.25 if (selection.clicks == 1)
3246     {
3247 root 1.175 if (selection.beg.col > ROW(selection.beg.row).l //TODO//FIXME//LEN
3248     && !ROW(selection.beg.row).is_longer ()
3249 root 1.256 #if !ENABLE_MINIMAL
3250 root 1.136 && !selection.rect
3251 pcg 1.4 #endif
3252 root 1.136 )
3253     selection.beg.col = ncol;
3254 pcg 1.25
3255 root 1.136 if (
3256 root 1.175 selection.end.col > ROW(selection.end.row).l //TODO//FIXME//LEN
3257     && !ROW(selection.end.row).is_longer ()
3258 root 1.256 #if !ENABLE_MINIMAL
3259 root 1.136 && !selection.rect
3260     #endif
3261     )
3262 pcg 1.25 selection.end.col = ncol;
3263     }
3264     else if (selection.clicks == 2)
3265     {
3266 pcg 1.30 if (ROWCOL_IS_AFTER (selection.end, selection.beg))
3267 pcg 1.25 selection.end.col--;
3268 pcg 1.59
3269 root 1.224 selection_delimit_word (UP, &selection.beg, &selection.beg);
3270     selection_delimit_word (DN, &selection.end, &selection.end);
3271 pcg 1.25 }
3272     else if (selection.clicks == 3)
3273     {
3274 root 1.104 #if ENABLE_FRILLS
3275 root 1.268 if (option (Opt_tripleclickwords))
3276 pcg 1.25 {
3277 root 1.139 selection_delimit_word (UP, &selection.beg, &selection.beg);
3278 pcg 1.59
3279 root 1.174 for (int end_row = selection.mark.row; end_row < nrow; end_row++)
3280 pcg 1.25 {
3281 root 1.175 if (!ROW(end_row).is_longer ())
3282 pcg 1.25 {
3283     selection.end.row = end_row;
3284 root 1.176 selection.end.col = ROW(end_row).l;
3285 root 1.256 # if !ENABLE_MINIMAL
3286 pcg 1.25 selection_remove_trailing_spaces ();
3287 root 1.256 # endif
3288 pcg 1.25 break;
3289 pcg 1.4 }
3290     }
3291 pcg 1.25 }
3292     else
3293 pcg 1.4 #endif
3294     {
3295 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, selection.beg))
3296 pcg 1.25 selection.mark.col++;
3297 root 1.136
3298 pcg 1.25 selection.beg.col = 0;
3299     selection.end.col = ncol;
3300 root 1.155
3301     // select a complete logical line
3302 root 1.172 while (selection.beg.row > -saveLines
3303 root 1.175 && ROW(selection.beg.row - 1).is_longer ())
3304 root 1.155 selection.beg.row--;
3305    
3306 root 1.172 while (selection.end.row < nrow
3307 root 1.175 && ROW(selection.end.row).is_longer ())
3308 root 1.155 selection.end.row++;
3309 pcg 1.4 }
3310     }
3311 pcg 1.59
3312 pcg 1.25 if (button3 && buttonpress)
3313 ayin 1.284 {
3314     /* mark may need to be changed */
3315 pcg 1.25 if (closeto == LEFT)
3316     {
3317     selection.mark.row = selection.end.row;
3318 root 1.104 selection.mark.col = selection.end.col - (selection.clicks == 2);
3319 pcg 1.25 }
3320     else
3321     {
3322     selection.mark.row = selection.beg.row;
3323     selection.mark.col = selection.beg.col;
3324 pcg 1.4 }
3325 pcg 1.1 }
3326 root 1.136
3327 root 1.256 #if !ENABLE_MINIMAL
3328 root 1.136 if (selection.rect && selection.beg.col > selection.end.col)
3329 root 1.182 ::swap (selection.beg.col, selection.end.col);
3330 root 1.136 #endif
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