ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.448
Committed: Thu Oct 30 09:53:05 2014 UTC (9 years, 6 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.447: +1 -1 lines
Log Message:
Fix optimization in refresh for cells containing a space.

scr_refresh skips refresh for cells containing a space and whose
rendition attributes defining the bg color have not changed. However,
the computation of such attributes erroneously assumes that, if reverse
video is set, the bg color is given by the fg color, which is not true
in the case where bg == fg. This causes cells with a space and bg == fg
not being refreshed also when the reverse video attribute has changed,
as observed in red hat bug #830236. Fix the bug by amending the
attributes test so that the refresh of such a cell is performed if the
reverse video attribute has changed.

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     tp = line->t + ncol - 1;
1017     rp = line->r + ncol - 1;
1018     }
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.447 if (focus && cursor_type != 2)
2124 pcg 1.25 {
2125 sf-exg 1.433 rend_t rend = cur_rend;
2126    
2127 sf-exg 1.447 if (cursor_type == 1)
2128 sf-exg 1.433 rend ^= RS_Uline;
2129 root 1.162 else
2130     {
2131 sf-exg 1.433 rend ^= RS_RVid;
2132     rend = SET_FGCOLOR (rend, ccol1);
2133     rend = SET_BGCOLOR (rend, ccol2);
2134 root 1.162 }
2135 sf-exg 1.433
2136     scr_set_char_rend (ROW(screen.cur.row), cur_col, rend);
2137 pcg 1.1 }
2138 pcg 1.4 }
2139 pcg 1.1
2140 pcg 1.25 /* make sure no outline cursor is left around */
2141     if (ocrow != -1)
2142 pcg 1.4 {
2143 root 1.228 if (screen.cur.row - view_start != ocrow
2144 sf-exg 1.447 || screen.cur.col != oldcursor.col || !showcursor)
2145 pcg 1.4 {
2146 root 1.172 if (ocrow < nrow
2147     && oldcursor.col < ncol)
2148 root 1.186 drawn_buf[ocrow].r[oldcursor.col] ^= (RS_RVid | RS_Uline);
2149 pcg 1.4 }
2150 pcg 1.25 }
2151 pcg 1.66
2152 sf-exg 1.439 // save the current cursor coordinates if the cursor is visible
2153 sf-exg 1.447 // and either the window is unfocused or the cursor style is
2154     // vertical bar, so as to clear the outline cursor in the next
2155     // refresh if the cursor moves or becomes invisible
2156     if (showcursor && (!focus || cursor_type == 2) && screen.cur.row - view_start < nrow)
2157 pcg 1.25 {
2158 sf-exg 1.439 oldcursor.row = screen.cur.row - view_start;
2159     oldcursor.col = screen.cur.col;
2160 pcg 1.25 }
2161 sf-exg 1.439 else
2162     oldcursor.row = -1;
2163 pcg 1.25 }
2164    
2165     #ifndef NO_SLOW_LINK_SUPPORT
2166     /*
2167     * D: CopyArea pass - very useful for slower links
2168     * This has been deliberately kept simple.
2169     */
2170 root 1.82 if (!display->is_local
2171 root 1.176 && refresh_type == FAST_REFRESH && num_scr_allow && num_scr
2172 root 1.260 && abs (num_scr) < nrow && !have_bg)
2173 pcg 1.25 {
2174 pcg 1.66 int16_t nits;
2175 root 1.261 int i = num_scr;
2176 pcg 1.66 int j;
2177     int len, wlen;
2178 pcg 1.25
2179 root 1.172 j = nrow;
2180 pcg 1.25 wlen = len = -1;
2181     row = i > 0 ? 0 : j - 1;
2182 root 1.261
2183 pcg 1.25 for (; j-- >= 0; row += (i > 0 ? 1 : -1))
2184     {
2185 root 1.172 if (row + i >= 0 && row + i < nrow && row + i != ocrow)
2186 pcg 1.25 {
2187 root 1.228 line_t s = ROW(view_start + row);
2188 root 1.186 line_t d = drawn_buf[row];
2189     line_t d2 = drawn_buf[row + i];
2190 pcg 1.25
2191 root 1.172 for (nits = 0, col = ncol; col--; )
2192     if (s.t[col] != d2.t[col] || s.r[col] != d2.r[col])
2193 pcg 1.25 nits--;
2194 root 1.172 else if (s.t[col] != d.t[col] || s.r[col] != d.r[col])
2195 pcg 1.25 nits++;
2196    
2197     if (nits > 8) /* XXX: arbitrary choice */
2198     {
2199 root 1.172 for (col = ncol; col--; )
2200 pcg 1.25 {
2201 root 1.172 *d.t++ = *d2.t++;
2202     *d.r++ = *d2.r++;
2203 pcg 1.25 }
2204    
2205     if (len == -1)
2206     len = row;
2207    
2208     wlen = row;
2209     continue;
2210     }
2211     }
2212    
2213 root 1.261 if (len >= 0)
2214 pcg 1.25 {
2215     /* also comes here at end if needed because of >= above */
2216     if (wlen < len)
2217 root 1.182 ::swap (wlen, len);
2218 pcg 1.25
2219 root 1.260 XGCValues gcv;
2220    
2221     gcv.graphics_exposures = 1; XChangeGC (dpy, gc, GCGraphicsExposures, &gcv);
2222 root 1.258 XCopyArea (dpy, vt, vt,
2223 root 1.172 gc, 0, Row2Pixel (len + i),
2224 root 1.207 (unsigned int)this->width,
2225 pcg 1.25 (unsigned int)Height2Pixel (wlen - len + 1),
2226     0, Row2Pixel (len));
2227 root 1.260 gcv.graphics_exposures = 0; XChangeGC (dpy, gc, GCGraphicsExposures, &gcv);
2228    
2229 pcg 1.25 len = -1;
2230     }
2231     }
2232 pcg 1.1 }
2233     #endif
2234    
2235 pcg 1.25 /*
2236     * E: main pass across every character
2237     */
2238 root 1.172 for (row = 0; row < nrow; row++)
2239 pcg 1.25 {
2240 root 1.228 text_t *stp = ROW(view_start + row).t;
2241     rend_t *srp = ROW(view_start + row).r;
2242 root 1.186 text_t *dtp = drawn_buf[row].t;
2243     rend_t *drp = drawn_buf[row].r;
2244 pcg 1.25
2245     /*
2246     * E2: OK, now the real pass
2247     */
2248 pcg 1.30 int ypixel = (int)Row2Pixel (row);
2249 pcg 1.25
2250 root 1.172 for (col = 0; col < ncol; col++)
2251 pcg 1.25 {
2252     /* compare new text with old - if exactly the same then continue */
2253     if (stp[col] == dtp[col] /* Must match characters to skip. */
2254 root 1.129 && (RS_SAME (srp[col], drp[col]) /* Either rendition the same or */
2255 pcg 1.25 || (stp[col] == ' ' /* space w/ no background change */
2256 sf-exg 1.448 && !((srp[col] ^ drp[col]) & (RS_attrMask | RS_bgMask)))))
2257 pcg 1.25 continue;
2258 pcg 1.1
2259 pcg 1.43 // redraw one or more characters
2260    
2261 root 1.141 // seek to the beginning of wide characters
2262 sf-exg 1.384 while (ecb_unlikely (stp[col] == NOCHAR && col > 0))
2263 pcg 1.43 --col;
2264    
2265 sf-exg 1.339 rend_t rend = srp[col]; /* screen rendition (target rendition) */
2266 pcg 1.25 text_t *text = stp + col;
2267     int count = 1;
2268 pcg 1.1
2269 pcg 1.25 dtp[col] = stp[col];
2270     drp[col] = rend;
2271 pcg 1.1
2272 pcg 1.30 int xpixel = Col2Pixel (col);
2273 pcg 1.1
2274 root 1.172 for (i = 0; ++col < ncol; )
2275 pcg 1.25 {
2276     if (stp[col] == NOCHAR)
2277     {
2278     dtp[col] = stp[col];
2279 root 1.328 drp[col] = srp[col];
2280    
2281 pcg 1.25 count++;
2282 root 1.104 i++;
2283 pcg 1.1
2284 pcg 1.25 continue;
2285     }
2286 pcg 1.1
2287 root 1.129 if (!RS_SAME (rend, srp[col]))
2288 pcg 1.25 break;
2289 pcg 1.1
2290 pcg 1.25 count++;
2291 pcg 1.1
2292 pcg 1.25 if (stp[col] != dtp[col]
2293 root 1.129 || !RS_SAME (srp[col], drp[col]))
2294 pcg 1.25 {
2295 root 1.260 if (have_bg && (i++ > count / 2))
2296 pcg 1.25 break;
2297 pcg 1.1
2298 pcg 1.25 dtp[col] = stp[col];
2299     drp[col] = rend;
2300     i = 0;
2301     }
2302 root 1.260 else if (have_bg || (stp[col] != ' ' && ++i >= 16))
2303 pcg 1.25 break;
2304     }
2305 pcg 1.1
2306 pcg 1.25 col--; /* went one too far. move back */
2307     count -= i; /* dump any matching trailing chars */
2308 pcg 1.1
2309 root 1.104 // sometimes we optimize away the trailing NOCHAR's, add them back
2310 sf-exg 1.384 while (ecb_unlikely (i && text[count] == NOCHAR))
2311 root 1.104 count++, i--;
2312    
2313 pcg 1.25 /*
2314     * Determine the attributes for the string
2315     */
2316 root 1.201 int fore = fgcolor_of (rend); // desired foreground
2317     int back = bgcolor_of (rend); // desired background
2318 pcg 1.17
2319 root 1.197 // only do special processing if any attributes are set, which is unlikely
2320 sf-exg 1.384 if (ecb_unlikely (rend & (RS_baseattrMask | RS_Careful | RS_Sel)))
2321 root 1.129 {
2322     bool invert = rend & RS_RVid;
2323 pcg 1.1
2324 root 1.129 #ifndef NO_BOLD_UNDERLINE_REVERSE
2325 root 1.290 if (rend & RS_Bold && fore == Color_fg)
2326 root 1.129 {
2327     if (ISSET_PIXCOLOR (Color_BD))
2328     fore = Color_BD;
2329     # if !ENABLE_STYLES
2330     else
2331     invert = !invert;
2332     # endif
2333     }
2334 pcg 1.1
2335 root 1.290 if (rend & RS_Italic && fore == Color_fg)
2336 root 1.129 {
2337     if (ISSET_PIXCOLOR (Color_IT))
2338     fore = Color_IT;
2339     # if !ENABLE_STYLES
2340     else
2341     invert = !invert;
2342     # endif
2343     }
2344 pcg 1.36
2345 root 1.263 if (rend & RS_Uline && fore == Color_fg && ISSET_PIXCOLOR (Color_UL))
2346 root 1.129 fore = Color_UL;
2347 pcg 1.1 #endif
2348    
2349 sf-exg 1.340 #ifdef OPTION_HC
2350     if (rend & RS_Sel)
2351     {
2352     /* invert the column if no highlightColor is set or it is the
2353     * current cursor column */
2354     if (!(showcursor && row == screen.cur.row && text - stp == screen.cur.col)
2355     && ISSET_PIXCOLOR (Color_HC))
2356     {
2357     if (ISSET_PIXCOLOR (Color_HTC))
2358     fore = Color_HTC;
2359     // if invert is 0 reverse video is set so we use bg color as fg color
2360     else if (!invert)
2361     fore = back;
2362 root 1.341
2363 sf-exg 1.340 back = Color_HC;
2364     invert = 0;
2365     }
2366     }
2367     #endif
2368    
2369 root 1.129 if (invert)
2370     {
2371 root 1.264 ::swap (fore, back);
2372 pcg 1.36
2373     #ifndef NO_BOLD_UNDERLINE_REVERSE
2374 root 1.168 if (fore == back)
2375     {
2376     fore = Color_bg;
2377     back = Color_fg;
2378     }
2379 pcg 1.36 #endif
2380 root 1.129 }
2381 pcg 1.36
2382 pcg 1.37 #ifdef TEXT_BLINK
2383 root 1.129 if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
2384 pcg 1.37 {
2385 root 1.287 if (!text_blink_ev.is_active ())
2386 root 1.129 {
2387 root 1.286 text_blink_ev.again ();
2388 root 1.129 hidden_text = 0;
2389     }
2390     else if (hidden_text)
2391     fore = back;
2392 pcg 1.37 }
2393 root 1.129 #endif
2394 root 1.264
2395     #if ENABLE_STYLES
2396     // "careful" (too wide) character handling
2397    
2398     // include previous careful character(s) if possible, looks nicer (best effort...)
2399     while (text > stp
2400     && srp[text - stp - 1] & RS_Careful
2401     && RS_SAME (rend, srp[text - stp - 1]))
2402     text--, count++, xpixel -= fwidth;
2403    
2404     // force redraw after "careful" characters to avoid pixel droppings
2405     for (int i = 0; srp[col + i] & RS_Careful && col + i < ncol - 1; i++)
2406     drp[col + i + 1] = srp[col + i + 1] ^ RS_redraw;
2407    
2408     // force redraw before "careful" characters to avoid pixel droppings
2409     for (int i = 0; srp[text - stp - i] & RS_Careful && text - i > stp; i++)
2410     drp[text - stp - i - 1] = srp[text - stp - i - 1] ^ RS_redraw;
2411     #endif
2412 pcg 1.37 }
2413    
2414 pcg 1.25 /*
2415     * Actually do the drawing of the string here
2416     */
2417 root 1.336 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)];
2418 pcg 1.25
2419 sf-exg 1.384 if (ecb_likely (have_bg && back == Color_bg))
2420 pcg 1.25 {
2421 root 1.260 // this is very ugly, maybe push it into ->draw?
2422    
2423     for (i = 0; i < count; i++) /* don't draw empty strings */
2424     if (text[i] != ' ')
2425     {
2426 root 1.267 font->draw (*drawable, xpixel, ypixel, text, count, fore, Color_transparent);
2427 root 1.260 goto did_clear;
2428     }
2429 pcg 1.25
2430 root 1.260 CLEAR_CHARS (xpixel, ypixel, count);
2431     did_clear: ;
2432 pcg 1.25 }
2433     else
2434 root 1.172 font->draw (*drawable, xpixel, ypixel, text, count, fore, back);
2435 pcg 1.1
2436 sf-exg 1.384 if (ecb_unlikely (rend & RS_Uline && font->descent > 1 && fore != back))
2437 root 1.147 {
2438 sf-exg 1.438 if (showcursor && focus && row == screen.cur.row
2439     && IN_RANGE_EXC (col, cur_col, cur_col + cursorwidth))
2440     XSetForeground (dpy, gc, pix_colors[ccol1]);
2441     else
2442 root 1.151 #if ENABLE_FRILLS
2443     if (ISSET_PIXCOLOR (Color_underline))
2444 root 1.258 XSetForeground (dpy, gc, pix_colors[Color_underline]);
2445 root 1.151 else
2446     #endif
2447 root 1.258 XSetForeground (dpy, gc, pix_colors[fore]);
2448 root 1.151
2449 root 1.299 XDrawLine (dpy, vt, gc,
2450 root 1.147 xpixel, ypixel + font->ascent + 1,
2451     xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2452     }
2453 pcg 1.25 } /* for (col....) */
2454     } /* for (row....) */
2455 pcg 1.1
2456 pcg 1.25 /*
2457     * G: cleanup cursor and display outline cursor if necessary
2458     */
2459     if (showcursor)
2460     {
2461 root 1.172 if (focus)
2462 sf-exg 1.447 {
2463     if (cursor_type != 2)
2464     scr_set_char_rend (ROW(screen.cur.row), cur_col, cur_rend);
2465     else if (oldcursor.row >= 0)
2466     {
2467     XSetForeground (dpy, gc, pix_colors[ccol1]);
2468     XFillRectangle (dpy, vt, gc,
2469     Col2Pixel (cur_col),
2470     Row2Pixel (oldcursor.row),
2471     1,
2472     Height2Pixel (1));
2473     }
2474     }
2475 pcg 1.25 else if (oldcursor.row >= 0)
2476     {
2477 sf-exg 1.437 XSetForeground (dpy, gc, pix_colors[ccol1]);
2478 pcg 1.35
2479 root 1.299 XDrawRectangle (dpy, vt, gc,
2480 sf-exg 1.438 Col2Pixel (cur_col),
2481 pcg 1.43 Row2Pixel (oldcursor.row),
2482     (unsigned int) (Width2Pixel (cursorwidth) - 1),
2483 sf-exg 1.414 (unsigned int) (Height2Pixel (1) - 1));
2484 pcg 1.4 }
2485 pcg 1.1 }
2486 pcg 1.12
2487 pcg 1.25 /*
2488     * H: cleanup selection
2489     */
2490 root 1.327 #if ENABLE_OVERLAY
2491     scr_swap_overlay ();
2492     #endif
2493     HOOK_INVOKE ((this, HOOK_REFRESH_END, DT_END));
2494    
2495 pcg 1.25 scr_reverse_selection ();
2496    
2497 root 1.327 screen.flags = old_screen_flags;
2498 pcg 1.25 num_scr = 0;
2499     num_scr_allow = 1;
2500 pcg 1.1 }
2501 pcg 1.11
2502 root 1.417 void ecb_cold
2503 root 1.244 rxvt_term::scr_remap_chars (line_t &l) NOTHROW
2504 pcg 1.32 {
2505 root 1.415 if (!l.valid ())
2506 pcg 1.32 return;
2507    
2508 root 1.214 l.touch (); // maybe a bit of an overkill, but it's not performance-relevant
2509 root 1.210
2510 root 1.172 for (int i = ncol; i--; )
2511     l.r[i] = SET_FONT (l.r[i], FONTSET (l.r[i])->find_font (l.t[i]));
2512 pcg 1.32 }
2513    
2514 root 1.417 void ecb_cold
2515 root 1.244 rxvt_term::scr_remap_chars () NOTHROW
2516 pcg 1.32 {
2517 root 1.175 for (int i = total_rows; i--; )
2518 root 1.186 scr_remap_chars (row_buf [i]);
2519 pcg 1.32
2520 root 1.172 for (int i = nrow; i--; )
2521 pcg 1.32 {
2522 root 1.186 scr_remap_chars (drawn_buf [i]);
2523     scr_remap_chars (swap_buf [i]);
2524 pcg 1.32 }
2525     }
2526    
2527 root 1.417 void ecb_cold
2528 sf-exg 1.364 rxvt_term::scr_recolour (bool refresh) NOTHROW
2529 root 1.129 {
2530 sf-exg 1.364 bool transparent = false;
2531    
2532 sf-exg 1.427 #ifdef HAVE_IMG
2533 sf-exg 1.421 if (bg_img != 0)
2534 sf-exg 1.364 {
2535 root 1.420 # if ENABLE_TRANSPARENCY
2536 sf-exg 1.366 if (bg_flags & BG_IS_TRANSPARENT)
2537 sf-exg 1.364 {
2538 sf-exg 1.421 XSetWindowBackgroundPixmap (dpy, parent, bg_img->pm);
2539 sf-exg 1.364 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2540    
2541     transparent = true;
2542     }
2543     else
2544     # endif
2545     {
2546 sf-exg 1.380 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2547 sf-exg 1.421 XSetWindowBackgroundPixmap (dpy, vt, bg_img->pm);
2548 sf-exg 1.364 }
2549     }
2550     else
2551     #endif
2552     {
2553 sf-exg 1.380 XSetWindowBackground (dpy, parent, pix_colors[Color_border]);
2554 sf-exg 1.364 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
2555     }
2556 root 1.290
2557 sf-exg 1.380 XClearWindow (dpy, parent);
2558 root 1.290
2559 sasha 1.274 if (scrollBar.win)
2560 sf-exg 1.363 {
2561 sf-exg 1.364 if (transparent)
2562     XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
2563     else
2564 sf-exg 1.426 XSetWindowBackground (dpy, scrollBar.win, pix_colors[scrollBar.color ()]);
2565 sf-exg 1.394 scrollBar.state = SB_STATE_IDLE;
2566 sf-exg 1.363 scrollBar.show (0);
2567     }
2568 root 1.290
2569 sf-exg 1.364 if (refresh)
2570     {
2571     scr_clear ();
2572     scr_touch (true);
2573     }
2574 root 1.129 want_refresh = 1;
2575     }
2576    
2577 pcg 1.1 /* ------------------------------------------------------------------------- */
2578     void
2579 root 1.244 rxvt_term::scr_clear (bool really) NOTHROW
2580 pcg 1.1 {
2581 root 1.172 if (!mapped)
2582 pcg 1.11 return;
2583    
2584     num_scr_allow = 0;
2585     want_refresh = 1;
2586 pcg 1.43
2587     if (really)
2588 root 1.258 XClearWindow (dpy, vt);
2589 pcg 1.1 }
2590    
2591 root 1.219 void
2592 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
2593 root 1.219 {
2594 root 1.228 int view_end = view_start + nrow;
2595 root 1.219 int row, col;
2596    
2597 root 1.228 for (row = max (beg_row, view_start); row <= min (end_row, view_end); row++)
2598 root 1.219 {
2599     text_t *stp = ROW(row).t;
2600     rend_t *srp = ROW(row).r;
2601    
2602     for (col = beg_col; col < end_col; col++)
2603     srp[col] ^= rstyle1;
2604    
2605     while (col-- > beg_col && (stp[col] == NOCHAR || unicode::is_space (stp[col])))
2606     srp[col] ^= rstyle2;
2607    
2608     if (++col < end_col)
2609     srp[col] ^= rstyle2;
2610     }
2611     }
2612    
2613     void
2614 root 1.244 rxvt_term::scr_xor_span (int beg_row, int beg_col, int end_row, int end_col, rend_t rstyle) NOTHROW
2615 root 1.219 {
2616 root 1.228 int view_end = view_start + nrow;
2617 root 1.219 int row, col;
2618    
2619 root 1.228 if (beg_row >= view_start)
2620 root 1.219 {
2621     col = beg_col;
2622     row = beg_row;
2623     }
2624     else
2625     {
2626     col = 0;
2627 root 1.228 row = view_start;
2628 root 1.219 }
2629    
2630     for (; row < min (end_row, view_end); row++, col = 0)
2631     for (rend_t *srp = ROW(row).r; col < ncol; col++)
2632 root 1.220 srp[col] ^= rstyle;
2633 root 1.219
2634     if (row == end_row)
2635     for (rend_t *srp = ROW(row).r; col < end_col; col++)
2636 root 1.220 srp[col] ^= rstyle;
2637 root 1.219 }
2638    
2639 pcg 1.1 /* ------------------------------------------------------------------------- */
2640 root 1.417 void ecb_hot
2641 root 1.244 rxvt_term::scr_reverse_selection () NOTHROW
2642 pcg 1.1 {
2643 root 1.175 if (selection.op
2644     && current_screen == selection.screen
2645 root 1.228 && selection.end.row >= view_start)
2646 pcg 1.25 {
2647 root 1.256 #if !ENABLE_MINIMAL
2648 root 1.136 if (selection.rect)
2649 root 1.219 scr_xor_rect (selection.beg.row, selection.beg.col,
2650     selection.end.row, selection.end.col,
2651 sf-exg 1.340 RS_Sel | RS_RVid, RS_Sel | RS_RVid | RS_Uline);
2652 pcg 1.25 else
2653 root 1.136 #endif
2654 root 1.219 scr_xor_span (selection.beg.row, selection.beg.col,
2655     selection.end.row, selection.end.col,
2656 sf-exg 1.340 RS_Sel | RS_RVid);
2657 pcg 1.1 }
2658     }
2659    
2660     /* ------------------------------------------------------------------------- */
2661     /*
2662     * Dump the whole scrollback and screen to the passed filedescriptor. The
2663     * invoking routine must close the fd.
2664     */
2665     #if 0
2666     void
2667 root 1.244 rxvt_term::scr_dump (int fd) NOTHROW
2668 pcg 1.1 {
2669 sf-exg 1.409 // if this method is needed, it can be implemented by factoring the
2670     // relevant code in scr_printscreen
2671 pcg 1.1 }
2672     #endif
2673 ayin 1.282
2674 pcg 1.1 /* ------------------------------------------------------------------------- *
2675     * CHARACTER SELECTION *
2676     * ------------------------------------------------------------------------- */
2677     void
2678 root 1.244 rxvt_term::selection_check (int check_more) NOTHROW
2679 pcg 1.1 {
2680 pcg 1.25 if (!selection.op)
2681     return;
2682 pcg 1.1
2683 root 1.228 if (!IN_RANGE_EXC (selection.beg.row, top_row, nrow)
2684 sf-exg 1.405 || !IN_RANGE_EXC (selection.mark.row, top_row, nrow)
2685 root 1.228 || !IN_RANGE_EXC (selection.end.row, top_row, nrow)
2686 pcg 1.25 || (check_more == 1
2687     && current_screen == selection.screen
2688 pcg 1.30 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2689 sf-exg 1.407 && ROWCOL_IS_BEFORE (screen.cur, selection.end)))
2690 sf-exg 1.405 CLEAR_ALL_SELECTION ();
2691 pcg 1.1 }
2692    
2693 root 1.434 void
2694     rxvt_term::selection_changed () NOTHROW
2695     {
2696     line_t &r1 = ROW (selection.beg.row);
2697 sf-exg 1.444 while (selection.beg.col < r1.l && r1.t [selection.beg.col] == NOCHAR)
2698     ++selection.beg.col;
2699 root 1.434
2700     line_t &r2 = ROW (selection.end.row);
2701     while (selection.end.col < r2.l && r2.t [selection.end.col] == NOCHAR)
2702     ++selection.end.col;
2703    
2704     want_refresh = 1;
2705     }
2706    
2707 pcg 1.1 /* ------------------------------------------------------------------------- */
2708     /*
2709     * Paste a selection direct to the command fd
2710     */
2711     void
2712 sf-exg 1.345 rxvt_term::tt_paste (char *data, unsigned int len) NOTHROW
2713 pcg 1.1 {
2714 pcg 1.5 /* convert normal newline chars into common keyboard Return key sequence */
2715 root 1.150 for (unsigned int i = 0; i < len; i++)
2716     if (data[i] == C0_LF)
2717     data[i] = C0_CR;
2718 pcg 1.5
2719 ayin 1.298 if (priv_modes & PrivMode_BracketPaste)
2720 root 1.412 tt_printf ("\x1b[200~");
2721 ayin 1.298
2722 root 1.150 tt_write (data, len);
2723 ayin 1.298
2724     if (priv_modes & PrivMode_BracketPaste)
2725 root 1.412 tt_printf ("\x1b[201~");
2726 pcg 1.1 }
2727    
2728 sf-exg 1.345 void
2729     rxvt_term::paste (char *data, unsigned int len) NOTHROW
2730     {
2731     if (HOOK_INVOKE ((this, HOOK_TT_PASTE, DT_STR_LEN, data, len, DT_END)))
2732     return;
2733    
2734     tt_paste (data, len);
2735     }
2736    
2737 pcg 1.1 /* ------------------------------------------------------------------------- */
2738     /*
2739 sf-exg 1.382 * Request PRIMARY, SECONDARY or CLIPBOARD selection.
2740     * if the requested selection has no owner or is empty CUT_BUFFER0 is used
2741     * as fallback
2742 pcg 1.1 * EXT: button 2 release
2743     */
2744     void
2745 root 1.244 rxvt_term::selection_request (Time tm, int selnum) NOTHROW
2746 pcg 1.1 {
2747 sf-exg 1.378 if (!selection_req)
2748 pcg 1.25 {
2749 root 1.375 selection_req = new rxvt_selection (display, selnum, tm, vt, xa[XA_VT_SELECTION], this);
2750 sf-exg 1.373 selection_req->run ();
2751 pcg 1.1 }
2752     }
2753    
2754     /* ------------------------------------------------------------------------- */
2755     /*
2756     * Clear all selected text
2757     * EXT: SelectionClear
2758     */
2759     void
2760 sf-exg 1.333 rxvt_term::selection_clear (bool clipboard) NOTHROW
2761 pcg 1.1 {
2762 sf-exg 1.333 if (!clipboard)
2763     {
2764     want_refresh = 1;
2765     free (selection.text);
2766     selection.text = NULL;
2767     selection.len = 0;
2768     CLEAR_SELECTION ();
2769    
2770     if (display->selection_owner == this)
2771     display->selection_owner = 0;
2772     }
2773     else
2774     {
2775     free (selection.clip_text);
2776     selection.clip_text = NULL;
2777     selection.clip_len = 0;
2778    
2779     if (display->clipboard_owner == this)
2780     display->clipboard_owner = 0;
2781     }
2782     }
2783 pcg 1.66
2784 pcg 1.1 /* ------------------------------------------------------------------------- */
2785     /*
2786     * Copy a selection into the cut buffer
2787     * EXT: button 1 or 3 release
2788     */
2789     void
2790 pcg 1.21 rxvt_term::selection_make (Time tm)
2791 pcg 1.1 {
2792 sf-exg 1.357 int size;
2793 pcg 1.54 wchar_t *new_selection_text;
2794 pcg 1.43 text_t *t;
2795 pcg 1.1
2796 pcg 1.25 switch (selection.op)
2797     {
2798     case SELECTION_CONT:
2799 pcg 1.4 break;
2800 pcg 1.25 case SELECTION_INIT:
2801 pcg 1.30 CLEAR_SELECTION ();
2802 pcg 1.25 /* FALLTHROUGH */
2803     case SELECTION_BEGIN:
2804 pcg 1.21 selection.op = SELECTION_DONE;
2805 pcg 1.25 /* FALLTHROUGH */
2806     default:
2807 pcg 1.4 return;
2808 pcg 1.1 }
2809 pcg 1.39
2810 pcg 1.25 selection.op = SELECTION_DONE;
2811 pcg 1.1
2812 pcg 1.25 if (selection.clicks == 4)
2813     return; /* nothing selected, go away */
2814 pcg 1.1
2815 root 1.211 if (HOOK_INVOKE ((this, HOOK_SEL_MAKE, DT_LONG, (long)tm, DT_END)))
2816 root 1.204 return;
2817    
2818 sf-exg 1.357 size = (selection.end.row - selection.beg.row + 1) * (ncol + 1);
2819     new_selection_text = (wchar_t *)rxvt_malloc ((size + 4) * sizeof (wchar_t));
2820 pcg 1.1
2821 pcg 1.54 int ofs = 0;
2822     int extra = 0;
2823 pcg 1.1
2824 root 1.175 int col = selection.beg.col;
2825     int row = selection.beg.row;
2826    
2827     int end_col;
2828    
2829     for (; row <= selection.end.row; row++, col = 0)
2830 pcg 1.25 {
2831 root 1.256 #if !ENABLE_MINIMAL
2832 root 1.136 if (selection.rect)
2833     {
2834     col = selection.beg.col;
2835 sf-exg 1.359 end_col = selection.end.col;
2836 root 1.136 }
2837 root 1.173 else
2838 root 1.136 #endif
2839 root 1.210 end_col = ROW(row).l;
2840 pcg 1.1
2841 root 1.175 col = max (col, 0);
2842 pcg 1.1
2843 sf-exg 1.359 if (row == selection.end.row)
2844 root 1.199 min_it (end_col, selection.end.col);
2845 pcg 1.1
2846 root 1.175 t = ROW(row).t + col;
2847 root 1.210
2848 pcg 1.25 for (; col < end_col; col++)
2849 pcg 1.54 {
2850     if (*t == NOCHAR)
2851     t++;
2852 pcg 1.57 #if ENABLE_COMBINING
2853 pcg 1.54 else if (IS_COMPOSE (*t))
2854     {
2855     int len = rxvt_composite.expand (*t, 0);
2856    
2857     extra -= (len - 1);
2858    
2859     if (extra < 0)
2860     {
2861 sf-exg 1.357 extra += size;
2862     size += size;
2863     new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (size + 4) * sizeof (wchar_t));
2864 pcg 1.54 }
2865    
2866     ofs += rxvt_composite.expand (*t++, new_selection_text + ofs);
2867     }
2868 pcg 1.57 #endif
2869 pcg 1.54 else
2870     new_selection_text[ofs++] = *t++;
2871     }
2872 pcg 1.1
2873 root 1.256 #if !ENABLE_MINIMAL
2874 root 1.199 if (selection.rect)
2875     {
2876     while (ofs
2877     && new_selection_text[ofs - 1] != C0_LF
2878     && unicode::is_space (new_selection_text[ofs - 1]))
2879     --ofs;
2880    
2881     new_selection_text[ofs++] = C0_LF;
2882     }
2883     else
2884     #endif
2885 sf-exg 1.361 if (!ROW(row).is_longer ()
2886     && (row != selection.end.row || end_col != selection.end.col)
2887 sf-exg 1.358 && (row != selection.beg.row || selection.beg.col < ncol))
2888 root 1.199 new_selection_text[ofs++] = C0_LF;
2889 pcg 1.25 }
2890 pcg 1.1
2891 pcg 1.54 new_selection_text[ofs] = 0;
2892 pcg 1.1
2893 pcg 1.54 if (ofs == 0)
2894 pcg 1.25 {
2895     free (new_selection_text);
2896     return;
2897     }
2898 pcg 1.1
2899 pcg 1.54 free (selection.text);
2900 pcg 1.18
2901 pcg 1.54 // we usually allocate much more than necessary, so realloc it smaller again
2902     selection.len = ofs;
2903     selection.text = (wchar_t *)rxvt_realloc (new_selection_text, (ofs + 1) * sizeof (wchar_t));
2904 pcg 1.1
2905 root 1.211 if (HOOK_INVOKE ((this, HOOK_SEL_GRAB, DT_LONG, (long)tm, DT_END)))
2906 root 1.204 return;
2907    
2908     selection_grab (tm);
2909     }
2910    
2911     bool
2912 sf-exg 1.333 rxvt_term::selection_grab (Time tm, bool clipboard) NOTHROW
2913 root 1.204 {
2914 sf-exg 1.333 Atom sel;
2915    
2916     if (!clipboard)
2917     {
2918     selection_time = tm;
2919     sel = XA_PRIMARY;
2920     }
2921     else
2922     {
2923     clipboard_time = tm;
2924     sel = xa[XA_CLIPBOARD];
2925     }
2926 root 1.204
2927 sf-exg 1.333 XSetSelectionOwner (dpy, sel, vt, tm);
2928     if (XGetSelectionOwner (dpy, sel) == vt)
2929 root 1.204 {
2930 sf-exg 1.333 display->set_selection_owner (this, clipboard);
2931 root 1.204 return true;
2932     }
2933 pcg 1.28 else
2934 root 1.225 {
2935 sf-exg 1.333 selection_clear (clipboard);
2936 root 1.225 return false;
2937     }
2938 pcg 1.18
2939 pcg 1.54 #if 0
2940     XTextProperty ct;
2941 pcg 1.18
2942 root 1.258 if (XwcTextListToTextProperty (dpy, &selection.text, 1, XStringStyle, &ct) >= 0)
2943 pcg 1.54 {
2944 root 1.147 set_string_property (XA_CUT_BUFFER0, ct.value, ct.nitems);
2945 pcg 1.54 XFree (ct.value);
2946     }
2947     #endif
2948 pcg 1.1 }
2949    
2950     /* ------------------------------------------------------------------------- */
2951     /*
2952     * Mark or select text based upon number of clicks: 1, 2, or 3
2953     * EXT: button 1 press
2954     */
2955 root 1.417 void ecb_cold
2956 root 1.244 rxvt_term::selection_click (int clicks, int x, int y) NOTHROW
2957 pcg 1.1 {
2958 pcg 1.11 clicks = ((clicks - 1) % 3) + 1;
2959     selection.clicks = clicks; /* save clicks so extend will work */
2960 pcg 1.1
2961 root 1.224 if (clicks == 2 && !selection.rect
2962     && HOOK_INVOKE ((this, HOOK_SEL_EXTEND, DT_END)))
2963     {
2964     MEvent.clicks = 1; // what a mess
2965 root 1.226 selection.screen = current_screen;
2966     selection.op = SELECTION_CONT;
2967 root 1.224 return;
2968     }
2969    
2970 pcg 1.30 selection_start_colrow (Pixel2Col (x), Pixel2Row (y));
2971 pcg 1.11
2972     if (clicks == 2 || clicks == 3)
2973 pcg 1.21 selection_extend_colrow (selection.mark.col,
2974 root 1.228 selection.mark.row - view_start,
2975 pcg 1.25 0, /* button 3 */
2976     1, /* button press */
2977     0); /* click change */
2978 pcg 1.1 }
2979    
2980     /* ------------------------------------------------------------------------- */
2981     /*
2982     * Mark a selection at the specified col/row
2983     */
2984 root 1.417 void ecb_cold
2985 root 1.244 rxvt_term::selection_start_colrow (int col, int row) NOTHROW
2986 pcg 1.1 {
2987 pcg 1.25 want_refresh = 1;
2988 root 1.175
2989 root 1.228 selection.mark.row = row + view_start;
2990 pcg 1.25 selection.mark.col = col;
2991 pcg 1.59
2992 root 1.228 selection.mark.row = clamp (selection.mark.row, top_row, nrow - 1);
2993 root 1.180 selection.mark.col = clamp (selection.mark.col, 0, ncol - 1);
2994 pcg 1.25
2995 pcg 1.59 while (selection.mark.col > 0
2996 root 1.175 && ROW(selection.mark.row).t[selection.mark.col] == NOCHAR)
2997 pcg 1.59 --selection.mark.col;
2998 ayin 1.281
2999 pcg 1.25 if (selection.op)
3000 ayin 1.284 {
3001     /* clear the old selection */
3002 pcg 1.25 selection.beg.row = selection.end.row = selection.mark.row;
3003     selection.beg.col = selection.end.col = selection.mark.col;
3004 pcg 1.1 }
3005 pcg 1.59
3006 pcg 1.25 selection.op = SELECTION_INIT;
3007     selection.screen = current_screen;
3008 pcg 1.1 }
3009    
3010     /* ------------------------------------------------------------------------- */
3011     /*
3012     * Word select: select text for 2 clicks
3013     * We now only find out the boundary in one direction
3014     */
3015    
3016     /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
3017 root 1.434 #define DELIMIT_TEXT(x) \
3018 root 1.104 (unicode::is_space (x) ? 2 : (x) <= 0xff && !!strchr (rs[Rs_cutchars], (x)))
3019 pcg 1.7 #define DELIMIT_REND(x) 1
3020 pcg 1.1
3021 root 1.417 void ecb_cold
3022 root 1.244 rxvt_term::selection_delimit_word (enum page_dirn dirn, const row_col_t *mark, row_col_t *ret) NOTHROW
3023 pcg 1.1 {
3024 pcg 1.59 int col, row, dirnadd, tcol, trow, w1, w2;
3025     row_col_t bound;
3026     text_t *stp;
3027     rend_t *srp;
3028 pcg 1.25
3029     if (dirn == UP)
3030     {
3031 root 1.228 bound.row = top_row - 1;
3032 pcg 1.25 bound.col = 0;
3033     dirnadd = -1;
3034     }
3035     else
3036     {
3037 root 1.175 bound.row = nrow;
3038 root 1.172 bound.col = ncol - 1;
3039 pcg 1.25 dirnadd = 1;
3040     }
3041 pcg 1.59
3042 root 1.175 row = mark->row;
3043     col = max (mark->col, 0);
3044    
3045 pcg 1.25 /* find the edge of a word */
3046 root 1.175 stp = ROW(row).t + col; w1 = DELIMIT_TEXT (*stp);
3047     srp = ROW(row).r + col; w2 = DELIMIT_REND (*srp);
3048 pcg 1.25
3049     for (;;)
3050     {
3051     for (; col != bound.col; col += dirnadd)
3052     {
3053     stp += dirnadd;
3054 pcg 1.59 srp += dirnadd;
3055    
3056     if (*stp == NOCHAR)
3057     continue;
3058    
3059 pcg 1.30 if (DELIMIT_TEXT (*stp) != w1)
3060 pcg 1.25 break;
3061 pcg 1.30 if (DELIMIT_REND (*srp) != w2)
3062 pcg 1.25 break;
3063     }
3064 pcg 1.59
3065 pcg 1.25 if ((col == bound.col) && (row != bound.row))
3066     {
3067 root 1.175 if (ROW(row - (dirn == UP ? 1 : 0)).is_longer ())
3068 pcg 1.25 {
3069     trow = row + dirnadd;
3070 root 1.172 tcol = dirn == UP ? ncol - 1 : 0;
3071 pcg 1.59
3072 root 1.175 if (!ROW(trow).t)
3073 pcg 1.4 break;
3074 pcg 1.59
3075 root 1.175 stp = ROW(trow).t + tcol;
3076     srp = ROW(trow).r + tcol;
3077 pcg 1.59
3078 pcg 1.30 if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2)
3079 pcg 1.4 break;
3080 pcg 1.59
3081 pcg 1.25 row = trow;
3082     col = tcol;
3083     continue;
3084 pcg 1.4 }
3085     }
3086 pcg 1.25 break;
3087 pcg 1.1 }
3088 pcg 1.59
3089 pcg 1.25 if (dirn == DN)
3090     col++; /* put us on one past the end */
3091 pcg 1.1
3092 pcg 1.25 /* Poke the values back in */
3093 root 1.175 ret->row = row;
3094 pcg 1.25 ret->col = col;
3095 pcg 1.1 }
3096    
3097     /* ------------------------------------------------------------------------- */
3098     /*
3099     * Extend the selection to the specified x/y pixel location
3100     * EXT: button 3 press; button 1 or 3 drag
3101     * flag == 0 ==> button 1
3102     * flag == 1 ==> button 3 press
3103     * flag == 2 ==> button 3 motion
3104     */
3105 root 1.417 void ecb_cold
3106 root 1.244 rxvt_term::selection_extend (int x, int y, int flag) NOTHROW
3107 pcg 1.1 {
3108 root 1.180 int col = clamp (Pixel2Col (x), 0, ncol);
3109     int row = clamp (Pixel2Row (y), 0, nrow - 1);
3110 pcg 1.1
3111 pcg 1.11 /*
3112     * If we're selecting characters (single click) then we must check first
3113     * if we are at the same place as the original mark. If we are then
3114     * select nothing. Otherwise, if we're to the right of the mark, you have to
3115     * be _past_ a character for it to be selected.
3116     */
3117 pcg 1.59 if (((selection.clicks % 3) == 1) && !flag
3118     && (col == selection.mark.col
3119 root 1.228 && (row == selection.mark.row - view_start)))
3120 pcg 1.59 {
3121     /* select nothing */
3122     selection.beg.row = selection.end.row = 0;
3123     selection.beg.col = selection.end.col = 0;
3124     selection.clicks = 4;
3125     want_refresh = 1;
3126     return;
3127 pcg 1.1 }
3128 pcg 1.59
3129 pcg 1.11 if (selection.clicks == 4)
3130     selection.clicks = 1;
3131    
3132 pcg 1.21 selection_extend_colrow (col, row, !!flag, /* ? button 3 */
3133 pcg 1.25 flag == 1 ? 1 : 0, /* ? button press */
3134     0); /* no click change */
3135 pcg 1.1 }
3136    
3137     /* ------------------------------------------------------------------------- */
3138     /*
3139     * Extend the selection to the specified col/row
3140     */
3141 root 1.417 void ecb_cold
3142 root 1.244 rxvt_term::selection_extend_colrow (int32_t col, int32_t row, int button3, int buttonpress, int clickchange) NOTHROW
3143 pcg 1.1 {
3144 pcg 1.71 row_col_t pos;
3145 pcg 1.25 enum {
3146     LEFT, RIGHT
3147     } closeto = RIGHT;
3148    
3149     switch (selection.op)
3150     {
3151     case SELECTION_INIT:
3152 pcg 1.30 CLEAR_SELECTION ();
3153 pcg 1.21 selection.op = SELECTION_BEGIN;
3154 pcg 1.25 /* FALLTHROUGH */
3155     case SELECTION_BEGIN:
3156 pcg 1.21 if (row != selection.mark.row || col != selection.mark.col
3157 pcg 1.4 || (!button3 && buttonpress))
3158 pcg 1.25 selection.op = SELECTION_CONT;
3159 pcg 1.4 break;
3160 pcg 1.25 case SELECTION_DONE:
3161 pcg 1.21 selection.op = SELECTION_CONT;
3162 pcg 1.25 /* FALLTHROUGH */
3163     case SELECTION_CONT:
3164 pcg 1.4 break;
3165 pcg 1.25 case SELECTION_CLEAR:
3166 pcg 1.21 selection_start_colrow (col, row);
3167 pcg 1.25 /* FALLTHROUGH */
3168     default:
3169 pcg 1.4 return;
3170 pcg 1.1 }
3171 root 1.136
3172 pcg 1.25 if (selection.beg.col == selection.end.col
3173     && selection.beg.col != selection.mark.col
3174     && selection.beg.row == selection.end.row
3175     && selection.beg.row != selection.mark.row)
3176     {
3177     selection.beg.col = selection.end.col = selection.mark.col;
3178     selection.beg.row = selection.end.row = selection.mark.row;
3179 pcg 1.1 }
3180    
3181 pcg 1.25 pos.col = col;
3182 root 1.228 pos.row = view_start + row;
3183 pcg 1.1
3184 pcg 1.25 /*
3185     * This is mainly xterm style selection with a couple of differences, mainly
3186     * in the way button3 drag extension works.
3187     * We're either doing: button1 drag; button3 press; or button3 drag
3188     * a) button1 drag : select around a midpoint/word/line - that point/word/line
3189     * is always at the left/right edge of the selection.
3190     * b) button3 press: extend/contract character/word/line at whichever edge of
3191     * the selection we are closest to.
3192     * c) button3 drag : extend/contract character/word/line - we select around
3193     * a point/word/line which is either the start or end of the selection
3194     * and it was decided by whichever point/word/line was `fixed' at the
3195     * time of the most recent button3 press
3196     */
3197     if (button3 && buttonpress)
3198 ayin 1.284 {
3199     /* button3 press */
3200 pcg 1.25 /*
3201     * first determine which edge of the selection we are closest to
3202     */
3203 pcg 1.30 if (ROWCOL_IS_BEFORE (pos, selection.beg)
3204     || (!ROWCOL_IS_AFTER (pos, selection.end)
3205 pcg 1.25 && (((pos.col - selection.beg.col)
3206     + ((pos.row - selection.beg.row) * ncol))
3207     < ((selection.end.col - pos.col)
3208     + ((selection.end.row - pos.row) * ncol)))))
3209     closeto = LEFT;
3210 pcg 1.59
3211 pcg 1.25 if (closeto == LEFT)
3212     {
3213     selection.beg.row = pos.row;
3214     selection.beg.col = pos.col;
3215     selection.mark.row = selection.end.row;
3216 pcg 1.59 selection.mark.col = selection.end.col - (selection.clicks == 2);
3217 pcg 1.25 }
3218     else
3219     {
3220     selection.end.row = pos.row;
3221     selection.end.col = pos.col;
3222     selection.mark.row = selection.beg.row;
3223     selection.mark.col = selection.beg.col;
3224     }
3225     }
3226     else
3227 ayin 1.284 {
3228     /* button1 drag or button3 drag */
3229 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, pos))
3230 pcg 1.25 {
3231 root 1.136 if (selection.mark.row == selection.end.row
3232     && selection.mark.col == selection.end.col
3233     && clickchange
3234     && selection.clicks == 2)
3235 pcg 1.25 selection.mark.col--;
3236 pcg 1.59
3237 pcg 1.25 selection.beg.row = pos.row;
3238     selection.beg.col = pos.col;
3239     selection.end.row = selection.mark.row;
3240 pcg 1.59 selection.end.col = selection.mark.col + (selection.clicks == 2);
3241 pcg 1.25 }
3242     else
3243     {
3244     selection.beg.row = selection.mark.row;
3245     selection.beg.col = selection.mark.col;
3246     selection.end.row = pos.row;
3247     selection.end.col = pos.col;
3248 pcg 1.4 }
3249 pcg 1.1 }
3250    
3251 pcg 1.25 if (selection.clicks == 1)
3252     {
3253 root 1.175 if (selection.beg.col > ROW(selection.beg.row).l //TODO//FIXME//LEN
3254     && !ROW(selection.beg.row).is_longer ()
3255 root 1.256 #if !ENABLE_MINIMAL
3256 root 1.136 && !selection.rect
3257 pcg 1.4 #endif
3258 root 1.136 )
3259     selection.beg.col = ncol;
3260 pcg 1.25
3261 root 1.136 if (
3262 root 1.175 selection.end.col > ROW(selection.end.row).l //TODO//FIXME//LEN
3263     && !ROW(selection.end.row).is_longer ()
3264 root 1.256 #if !ENABLE_MINIMAL
3265 root 1.136 && !selection.rect
3266     #endif
3267     )
3268 pcg 1.25 selection.end.col = ncol;
3269     }
3270     else if (selection.clicks == 2)
3271     {
3272 pcg 1.30 if (ROWCOL_IS_AFTER (selection.end, selection.beg))
3273 pcg 1.25 selection.end.col--;
3274 pcg 1.59
3275 root 1.224 selection_delimit_word (UP, &selection.beg, &selection.beg);
3276     selection_delimit_word (DN, &selection.end, &selection.end);
3277 pcg 1.25 }
3278     else if (selection.clicks == 3)
3279     {
3280 root 1.104 #if ENABLE_FRILLS
3281 root 1.268 if (option (Opt_tripleclickwords))
3282 pcg 1.25 {
3283 root 1.139 selection_delimit_word (UP, &selection.beg, &selection.beg);
3284 pcg 1.59
3285 root 1.174 for (int end_row = selection.mark.row; end_row < nrow; end_row++)
3286 pcg 1.25 {
3287 root 1.175 if (!ROW(end_row).is_longer ())
3288 pcg 1.25 {
3289     selection.end.row = end_row;
3290 root 1.176 selection.end.col = ROW(end_row).l;
3291 root 1.256 # if !ENABLE_MINIMAL
3292 pcg 1.25 selection_remove_trailing_spaces ();
3293 root 1.256 # endif
3294 pcg 1.25 break;
3295 pcg 1.4 }
3296     }
3297 pcg 1.25 }
3298     else
3299 pcg 1.4 #endif
3300     {
3301 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, selection.beg))
3302 pcg 1.25 selection.mark.col++;
3303 root 1.136
3304 pcg 1.25 selection.beg.col = 0;
3305     selection.end.col = ncol;
3306 root 1.155
3307     // select a complete logical line
3308 root 1.172 while (selection.beg.row > -saveLines
3309 root 1.175 && ROW(selection.beg.row - 1).is_longer ())
3310 root 1.155 selection.beg.row--;
3311    
3312 root 1.172 while (selection.end.row < nrow
3313 root 1.175 && ROW(selection.end.row).is_longer ())
3314 root 1.155 selection.end.row++;
3315 pcg 1.4 }
3316     }
3317 pcg 1.59
3318 pcg 1.25 if (button3 && buttonpress)
3319 ayin 1.284 {
3320     /* mark may need to be changed */
3321 pcg 1.25 if (closeto == LEFT)
3322     {
3323     selection.mark.row = selection.end.row;
3324 root 1.104 selection.mark.col = selection.end.col - (selection.clicks == 2);
3325 pcg 1.25 }
3326     else
3327     {
3328     selection.mark.row = selection.beg.row;
3329     selection.mark.col = selection.beg.col;
3330 pcg 1.4 }
3331 pcg 1.1 }
3332 root 1.136
3333 root 1.256 #if !ENABLE_MINIMAL
3334 root 1.136 if (selection.rect && selection.beg.col > selection.end.col)
3335 root 1.182 ::swap (selection.beg.col, selection.end.col);
3336 root 1.136 #endif
3337 root 1.434
3338     selection_changed ();
3339 pcg 1.1 }
3340    
3341 root 1.256 #if !ENABLE_MINIMAL
3342 root 1.417 void ecb_cold
3343 root 1.244 rxvt_term::selection_remove_trailing_spaces () NOTHROW
3344 pcg 1.1 {
3345 root 1.136 int32_t end_col, end_row;
3346     text_t *stp;
3347 pcg 1.1
3348 pcg 1.25 end_col = selection.end.col;
3349     end_row = selection.end.row;
3350 root 1.136
3351 root 1.175 for (; end_row >= selection.beg.row; )
3352 pcg 1.25 {
3353 root 1.175 stp = ROW(end_row).t;
3354 root 1.136
3355 pcg 1.25 while (--end_col >= 0)
3356     {
3357 root 1.199 if (stp[end_col] != NOCHAR
3358     && !unicode::is_space (stp[end_col]))
3359 pcg 1.25 break;
3360 pcg 1.4 }
3361 root 1.136
3362 pcg 1.25 if (end_col >= 0
3363 root 1.175 || !ROW(end_row - 1).is_longer ())
3364 pcg 1.25 {
3365     selection.end.col = end_col + 1;
3366     selection.end.row = end_row;
3367     break;
3368 pcg 1.4 }
3369 root 1.136
3370 pcg 1.25 end_row--;
3371 root 1.172 end_col = ncol;
3372 pcg 1.25 }
3373 root 1.136
3374 pcg 1.25 if (selection.mark.row > selection.end.row)
3375     {
3376     selection.mark.row = selection.end.row;
3377     selection.mark.col = selection.end.col;
3378 pcg 1.1 }
3379 pcg 1.25 else if (selection.mark.row == selection.end.row
3380     && selection.mark.col > selection.end.col)
3381     selection.mark.col = selection.end.col;
3382 pcg 1.1 }
3383     #endif
3384    
3385     /* ------------------------------------------------------------------------- */
3386     /*
3387     * Double click on button 3 when already selected
3388     * EXT: button 3 double click
3389     */
3390 root 1.417 void ecb_cold
3391 root 1.244 rxvt_term::selection_rotate (int x, int y) NOTHROW
3392 pcg 1.1 {
3393 pcg 1.11 selection.clicks = selection.clicks % 3 + 1;
3394 pcg 1.30 selection_extend_colrow (Pixel2Col (x), Pixel2Row (y), 1, 0, 1);
3395 pcg 1.1 }
3396    
3397     /* ------------------------------------------------------------------------- */
3398     /*
3399     * Respond to a request for our current selection
3400     * EXT: SelectionRequest
3401     */
3402 root 1.417 void ecb_cold
3403 root 1.244 rxvt_term::selection_send (const XSelectionRequestEvent &rq) NOTHROW
3404 pcg 1.1 {
3405 sf-exg 1.381 Atom property = rq.property == None ? rq.target : rq.property;
3406 pcg 1.25 XSelectionEvent ev;
3407    
3408     ev.type = SelectionNotify;
3409     ev.property = None;
3410 pcg 1.27 ev.display = rq.display;
3411     ev.requestor = rq.requestor;
3412     ev.selection = rq.selection;
3413     ev.target = rq.target;
3414     ev.time = rq.time;
3415 pcg 1.25
3416 pcg 1.27 if (rq.target == xa[XA_TARGETS])
3417 pcg 1.25 {
3418 root 1.139 Atom target_list[6];
3419     Atom *target = target_list;
3420 pcg 1.1
3421 root 1.139 *target++ = xa[XA_TARGETS];
3422     *target++ = xa[XA_TIMESTAMP];
3423     *target++ = XA_STRING;
3424     *target++ = xa[XA_TEXT];
3425     *target++ = xa[XA_COMPOUND_TEXT];
3426 pcg 1.18 #if X_HAVE_UTF8_STRING
3427 root 1.139 *target++ = xa[XA_UTF8_STRING];
3428 pcg 1.1 #endif
3429 pcg 1.54
3430 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property, XA_ATOM,
3431 root 1.139 32, PropModeReplace,
3432     (unsigned char *)target_list, target - target_list);
3433 sf-exg 1.381 ev.property = property;
3434 pcg 1.25 }
3435 root 1.89 #if TODO // TODO
3436 pcg 1.27 else if (rq.target == xa[XA_MULTIPLE])
3437 pcg 1.25 {
3438     /* TODO: Handle MULTIPLE */
3439     }
3440 root 1.89 #endif
3441 sf-exg 1.333 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == XA_PRIMARY && selection.text)
3442 pcg 1.25 {
3443 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property, rq.target,
3444 root 1.139 32, PropModeReplace, (unsigned char *)&selection_time, 1);
3445 sf-exg 1.381 ev.property = property;
3446 pcg 1.25 }
3447 sf-exg 1.333 else if (rq.target == xa[XA_TIMESTAMP] && rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3448     {
3449 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property, rq.target,
3450 sf-exg 1.333 32, PropModeReplace, (unsigned char *)&clipboard_time, 1);
3451 sf-exg 1.381 ev.property = property;
3452 sf-exg 1.333 }
3453 pcg 1.27 else if (rq.target == XA_STRING
3454     || rq.target == xa[XA_TEXT]
3455     || rq.target == xa[XA_COMPOUND_TEXT]
3456     || rq.target == xa[XA_UTF8_STRING]
3457 pcg 1.25 )
3458     {
3459 root 1.147 XTextProperty ct;
3460     Atom target = rq.target;
3461 pcg 1.25 short freect = 0;
3462     int selectlen;
3463 pcg 1.54 wchar_t *cl;
3464 root 1.147 enum {
3465     enc_string = XStringStyle,
3466     enc_text = XStdICCTextStyle,
3467     enc_compound_text = XCompoundTextStyle,
3468     #ifdef X_HAVE_UTF8_STRING
3469     enc_utf8 = XUTF8StringStyle,
3470     #else
3471     enc_utf8 = -1,
3472     #endif
3473     } style;
3474 pcg 1.25
3475     if (target == XA_STRING)
3476     // we actually don't do XA_STRING, but who cares, as i18n clients
3477     // will ask for another format anyways.
3478 root 1.147 style = enc_string;
3479 pcg 1.25 else if (target == xa[XA_TEXT])
3480 root 1.147 style = enc_text;
3481 pcg 1.25 else if (target == xa[XA_COMPOUND_TEXT])
3482 root 1.147 style = enc_compound_text;
3483 root 1.256 #if !ENABLE_MINIMAL
3484 pcg 1.25 else if (target == xa[XA_UTF8_STRING])
3485 root 1.147 style = enc_utf8;
3486 pcg 1.1 #endif
3487 pcg 1.25 else
3488     {
3489     target = xa[XA_COMPOUND_TEXT];
3490 root 1.147 style = enc_compound_text;
3491 pcg 1.25 }
3492 pcg 1.1
3493 sf-exg 1.333 if (rq.selection == XA_PRIMARY && selection.text)
3494 pcg 1.25 {
3495 pcg 1.54 cl = selection.text;
3496 pcg 1.25 selectlen = selection.len;
3497     }
3498 sf-exg 1.333 else if (rq.selection == xa[XA_CLIPBOARD] && selection.clip_text)
3499     {
3500     cl = selection.clip_text;
3501     selectlen = selection.clip_len;
3502     }
3503 pcg 1.25 else
3504     {
3505 pcg 1.54 cl = L"";
3506 pcg 1.25 selectlen = 0;
3507 pcg 1.4 }
3508 pcg 1.18
3509 root 1.256 #if !ENABLE_MINIMAL
3510 root 1.147 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
3511     // so recode it manually
3512     if (style == enc_utf8)
3513     {
3514     freect = 1;
3515     ct.encoding = target;
3516     ct.format = 8;
3517     ct.value = (unsigned char *)rxvt_wcstoutf8 (cl, selectlen);
3518     ct.nitems = strlen ((char *)ct.value);
3519     }
3520     else
3521     #endif
3522 root 1.258 if (XwcTextListToTextProperty (dpy, &cl, 1, (XICCEncodingStyle) style, &ct) >= 0)
3523 pcg 1.25 freect = 1;
3524     else
3525     {
3526     /* if we failed to convert then send it raw */
3527     ct.value = (unsigned char *)cl;
3528     ct.nitems = selectlen;
3529 root 1.147 ct.encoding = target;
3530 pcg 1.25 }
3531 pcg 1.18
3532 sf-exg 1.381 XChangeProperty (dpy, rq.requestor, property,
3533 root 1.147 ct.encoding, 8, PropModeReplace,
3534 pcg 1.27 ct.value, (int)ct.nitems);
3535 sf-exg 1.381 ev.property = property;
3536 pcg 1.18
3537 pcg 1.25 if (freect)
3538     XFree (ct.value);
3539 pcg 1.1 }
3540 pcg 1.54
3541 root 1.258 XSendEvent (dpy, rq.requestor, False, 0L, (XEvent *)&ev);
3542 pcg 1.1 }
3543 ayin 1.281
3544 pcg 1.1 /* ------------------------------------------------------------------------- */
3545 root 1.420 #if USE_XIM
3546 root 1.417 void ecb_cold
3547 root 1.244 rxvt_term::im_set_position (XPoint &pos) NOTHROW
3548 pcg 1.1 {
3549 pcg 1.11 XWindowAttributes xwa;
3550 pcg 1.1
3551 root 1.258 XGetWindowAttributes (dpy, vt, &xwa);
3552 root 1.104
3553     pos.x = xwa.x + Col2Pixel (screen.cur.col);
3554 root 1.172 pos.y = xwa.y + Height2Pixel (screen.cur.row) + fbase;
3555 root 1.104 }
3556     #endif
3557    
3558     #if ENABLE_OVERLAY
3559     void
3560 root 1.244 rxvt_term::scr_overlay_new (int x, int y, int w, int h) NOTHROW
3561 root 1.104 {
3562 root 1.204 if (nrow < 1 || ncol < 1)
3563 root 1.104 return;
3564    
3565     want_refresh = 1;
3566    
3567     scr_overlay_off ();
3568    
3569 root 1.172 if (x < 0) x = ncol - w;
3570     if (y < 0) y = nrow - h;
3571 root 1.104
3572     // make space for border
3573 root 1.183 w += 2; min_it (w, ncol);
3574     h += 2; min_it (h, nrow);
3575 root 1.104
3576 root 1.186 x -= 1; clamp_it (x, 0, ncol - w);
3577     y -= 1; clamp_it (y, 0, nrow - h);
3578 root 1.104
3579 root 1.327 ov.x = x; ov.y = y;
3580     ov.w = w; ov.h = h;
3581 root 1.104
3582 root 1.327 ov.text = new text_t *[h];
3583     ov.rend = new rend_t *[h];
3584 root 1.104
3585     for (y = 0; y < h; y++)
3586     {
3587 root 1.327 text_t *tp = ov.text[y] = new text_t[w];
3588     rend_t *rp = ov.rend[y] = new rend_t[w];
3589 root 1.104
3590     text_t t0, t1, t2;
3591 root 1.129 rend_t r = OVERLAY_RSTYLE;
3592 root 1.104
3593     if (y == 0)
3594     t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
3595     else if (y < h - 1)
3596     t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
3597     else
3598     t0 = 0x255a, t1 = 0x2550, t2 = 0x255d;
3599    
3600     *tp++ = t0;
3601     *rp++ = r;
3602    
3603     for (x = w - 2; x > 0; --x)
3604     {
3605     *tp++ = t1;
3606     *rp++ = r;
3607     }
3608    
3609     *tp = t2;
3610     *rp = r;
3611     }
3612     }
3613    
3614     void
3615 root 1.244 rxvt_term::scr_overlay_off () NOTHROW
3616 root 1.104 {
3617 root 1.327 if (!ov.text)
3618 root 1.104 return;
3619    
3620     want_refresh = 1;
3621    
3622 root 1.327 for (int y = 0; y < ov.h; y++)
3623 root 1.104 {
3624 root 1.327 delete [] ov.text[y];
3625     delete [] ov.rend[y];
3626 root 1.104 }
3627    
3628 root 1.327 delete [] ov.text; ov.text = 0;
3629     delete [] ov.rend; ov.rend = 0;
3630 root 1.104 }
3631    
3632     void
3633 root 1.244 rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) NOTHROW
3634 root 1.104 {
3635 root 1.327 if (!ov.text || x >= ov.w - 2 || y >= ov.h - 2)
3636 root 1.104 return;
3637    
3638     x++, y++;
3639    
3640 root 1.327 ov.text[y][x] = text;
3641     ov.rend[y][x] = rend;
3642 root 1.104 }
3643    
3644     void
3645 root 1.244 rxvt_term::scr_overlay_set (int x, int y, const char *s) NOTHROW
3646 root 1.104 {
3647     while (*s)
3648     scr_overlay_set (x++, y, *s++);
3649     }
3650    
3651     void
3652 root 1.244 rxvt_term::scr_overlay_set (int x, int y, const wchar_t *s) NOTHROW
3653 root 1.163 {
3654     while (*s)
3655     {
3656     text_t t = *s++;
3657 root 1.250 int width = WCWIDTH (t);
3658 root 1.163
3659     while (width--)
3660     {
3661     scr_overlay_set (x++, y, t);
3662     t = NOCHAR;
3663     }
3664     }
3665     }
3666    
3667     void
3668 root 1.244 rxvt_term::scr_swap_overlay () NOTHROW
3669 root 1.104 {
3670 root 1.327 if (!ov.text)
3671 root 1.104 return;
3672    
3673 root 1.327 // hide cursor if it is within the overlay area
3674     if (IN_RANGE_EXC (screen.cur.col - ov.x, 0, ov.w)
3675     && IN_RANGE_EXC (screen.cur.row - ov.y, 0, ov.h))
3676     screen.flags &= ~Screen_VisibleCursor;
3677    
3678 root 1.104 // swap screen mem with overlay
3679 root 1.327 for (int y = ov.h; y--; )
3680 root 1.104 {
3681 root 1.327 text_t *t1 = ov.text[y];
3682     rend_t *r1 = ov.rend[y];
3683 root 1.104
3684 root 1.327 text_t *t2 = ROW(y + ov.y + view_start).t + ov.x;
3685     rend_t *r2 = ROW(y + ov.y + view_start).r + ov.x;
3686 root 1.104
3687 root 1.327 for (int x = ov.w; x--; )
3688 root 1.104 {
3689     text_t t = *t1; *t1++ = *t2; *t2++ = t;
3690 root 1.129 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t));
3691 root 1.104 }
3692     }
3693 pcg 1.1 }
3694 pcg 1.11
3695 pcg 1.1 #endif
3696     /* ------------------------------------------------------------------------- */
3697 root 1.175