ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.455
Committed: Wed Sep 30 12:57:04 2015 UTC (8 years, 7 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.454: +2 -2 lines
Log Message:
Fix crash when the number of columns is 1 and a 0 width character is inserted.

In scr_add_lines, in the case when a 0 width character must be inserted
in the first column of the current row, the calculation of the previous
character (i.e., the last character of the previous row) is bogus. In
particular, if the number of columns is 1, the 'tp' pointer points to
either the first or third byte (depending on the size of text_t) of the
rendition of the previous character, which is therefore corrupted by the
assignment '*tp = n'. This triggers a crash if the font id in the
rendition gets changed to the id of a font which is not loaded. Bug
reported by Kuang-che Wu.

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