ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.406
Committed: Wed Nov 16 18:26:47 2011 UTC (12 years, 6 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.405: +0 -3 lines
Log Message:
Remove useless selection checks in scr_erase_screen.

The check below the switch already clears the selection if it overlaps
with the screen area to be erased. Moreover, the selection check used in
the 'clear screen before the cursor' case was incorrect as it cleared
the selection even when outside of the relevant screen area.

File Contents

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