ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.82
Committed: Wed Aug 4 03:33:53 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_4
Changes since 1.78: +19 -7 lines
Log Message:
*** empty log message ***

File Contents

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