ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.340
Committed: Sat Apr 17 23:00:45 2010 UTC (14 years, 1 month ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.339: +22 -17 lines
Log Message:
Disable colorRV resource.
Make OSC 17 apply to highlightColor.
Make highlightColor apply also to selected cells with reverse video.
Add highlightTextColor resource to change the foreground colour of
highlighted characters.

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