ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.442
Committed: Sat Mar 30 08:47:06 2013 UTC (11 years, 1 month ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.441: +8 -0 lines
Log Message:
Fix bug in core double-click word selection.

selection_delimit_word does not account for (left) delimiters with width > 1.
In such a case, it sets the starting position of the selection to the
second column of the delimiter (thereby including the delimiter in the
selection) rather than to the first column of the character next to it.
This bug was masked before by 'selection_make' but a recent fix to the
selection code revealed it.

File Contents

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