ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.85
Committed: Sun Aug 8 16:43:21 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_5
Changes since 1.82: +19 -61 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 root 1.85 memcpy (buf_text, screen.text + row1, count * sizeof (text_t *));
711     memcpy (buf_rend, screen.rend + row1, count * sizeof (rend_t *));
712 pcg 1.74
713 pcg 1.8 /* A2: Rotate lines */
714 root 1.85 i = row2 - row1 - count + 1;
715     memmove (screen.tlen + row1, screen.tlen + row1 + count, i * sizeof (int16_t));
716     memmove (screen.text + row1, screen.text + row1 + count, i * sizeof (text_t *));
717     memmove (screen.rend + row1, screen.rend + row1 + count, i * sizeof (rend_t *));
718 pcg 1.74
719 pcg 1.8 j = row2 - count + 1, i = count;
720     }
721     else /* if (j < 0) */
722     {
723     /* B: scroll down */
724    
725     /* B1: Copy lines that will get clobbered by the rotation */
726     for (i = 0, j = row2; i < count; i++, j--)
727     {
728     buf_text[i] = screen.text[j];
729     buf_rend[i] = screen.rend[j];
730     }
731 pcg 1.74
732 pcg 1.8 /* B2: Rotate lines */
733     for (j = row2, i = j - count; i >= row1; i--, j--)
734     {
735     screen.tlen[j] = screen.tlen[i];
736     screen.text[j] = screen.text[i];
737     screen.rend[j] = screen.rend[i];
738     }
739 pcg 1.74
740 pcg 1.8 j = row1, i = count;
741     count = -count;
742     }
743 pcg 1.1
744 pcg 1.8 /* C: Resurrect lines */
745 root 1.85 memset (screen.tlen + j, 0, i * sizeof (int16_t));
746     memcpy (screen.text + j, buf_text, i * sizeof (text_t *));
747     memcpy (screen.rend + j, buf_rend, i * sizeof (text_t *));
748     if (!spec) /* line length may not equal TermWin.ncol */
749     for (; i--; j++)
750     scr_blank_screen_mem (screen.text, screen.rend, (unsigned int)j, rstyle);
751 pcg 1.1
752 pcg 1.8 return count;
753 pcg 1.1 }
754    
755     /* ------------------------------------------------------------------------- */
756     /*
757     * Add text given in <str> of length <len> to screen struct
758     */
759     void
760 pcg 1.59 rxvt_term::scr_add_lines (const unicode_t *str, int nlines, int len)
761 pcg 1.1 {
762 pcg 1.54 unsigned char checksel, clearsel;
763 pcg 1.59 unicode_t c;
764 pcg 1.54 int i, row, last_col;
765     text_t *stp;
766     rend_t *srp;
767 pcg 1.1
768 pcg 1.25 if (len <= 0) /* sanity */
769     return;
770 pcg 1.1
771 pcg 1.25 want_refresh = 1;
772     last_col = TermWin.ncol;
773 pcg 1.1
774 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_add_lines (%d,%d)", nlines, len));
775     ZERO_SCROLLBACK ();
776 pcg 1.25 if (nlines > 0)
777     {
778 root 1.85 nlines += screen.cur.row - screen.bscroll;
779 pcg 1.25 if ((nlines > 0)
780     && (screen.tscroll == 0)
781     && (screen.bscroll == (TermWin.nrow - 1)))
782     {
783     /* _at least_ this many lines need to be scrolled */
784 pcg 1.30 scr_scroll_text (screen.tscroll, screen.bscroll, nlines, 0);
785 pcg 1.25 screen.cur.row -= nlines;
786 pcg 1.4 }
787 pcg 1.1 }
788     #ifdef DEBUG_STRICT
789 pcg 1.30 assert (screen.cur.col < last_col);
790     assert ((screen.cur.row < TermWin.nrow)
791 root 1.82 && (screen.cur.row >= - (int32_t)TermWin.nscrolled));
792 pcg 1.4 #else /* drive with your eyes closed */
793 pcg 1.30 MIN_IT (screen.cur.col, last_col - 1);
794     MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
795     MAX_IT (screen.cur.row, - (int32_t)TermWin.nscrolled);
796 pcg 1.25 #endif
797     row = screen.cur.row + TermWin.saveLines;
798    
799 pcg 1.66 checksel = selection.op && current_screen == selection.screen ? 1 : 0;
800 pcg 1.25 clearsel = 0;
801    
802     stp = screen.text[row];
803     srp = screen.rend[row];
804    
805 pcg 1.66 while (len--)
806 pcg 1.25 {
807 pcg 1.66 c = *str++;
808    
809     if (c < 0x20)
810     switch (c)
811     {
812 pcg 1.71 case C0_HT:
813 pcg 1.66 scr_tab (1);
814     continue;
815    
816 pcg 1.71 case C0_LF:
817 pcg 1.66 if (screen.tlen[row] != -1) /* XXX: think about this */
818     MAX_IT (screen.tlen[row], screen.cur.col);
819    
820     screen.flags &= ~Screen_WrapNext;
821    
822     if (screen.cur.row == screen.bscroll)
823     scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
824     else if (screen.cur.row < (TermWin.nrow - 1))
825     row = (++screen.cur.row) + TermWin.saveLines;
826    
827     stp = screen.text[row]; /* _must_ refresh */
828     srp = screen.rend[row]; /* _must_ refresh */
829     continue;
830    
831 pcg 1.71 case C0_CR:
832 pcg 1.66 if (screen.tlen[row] != -1) /* XXX: think about this */
833     MAX_IT (screen.tlen[row], screen.cur.col);
834    
835     screen.flags &= ~Screen_WrapNext;
836     screen.cur.col = 0;
837     continue;
838     }
839 pcg 1.4
840 pcg 1.25 if (checksel /* see if we're writing within selection */
841 pcg 1.30 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
842     && ROWCOL_IS_BEFORE (screen.cur, selection.end))
843 pcg 1.25 {
844     checksel = 0;
845     clearsel = 1;
846 pcg 1.4 }
847 pcg 1.54
848 pcg 1.25 if (screen.flags & Screen_WrapNext)
849     {
850     screen.tlen[row] = -1;
851     if (screen.cur.row == screen.bscroll)
852 pcg 1.30 scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
853 pcg 1.25 else if (screen.cur.row < (TermWin.nrow - 1))
854     row = (++screen.cur.row) + TermWin.saveLines;
855 pcg 1.54
856 pcg 1.25 stp = screen.text[row]; /* _must_ refresh */
857     srp = screen.rend[row]; /* _must_ refresh */
858     screen.cur.col = 0;
859     screen.flags &= ~Screen_WrapNext;
860 pcg 1.4 }
861 pcg 1.54
862 pcg 1.25 if (screen.flags & Screen_Insert)
863     scr_insdel_chars (1, INSERT);
864 pcg 1.1
865 pcg 1.54 // rely on wcwidth to tell us the character width, at least for non-latin1
866     // do wcwidth before further replacements, as wcwidth says that line-drawing
867 pcg 1.66 // characters have width -1 (DOH!) on GNU/Linux sometimes.
868 root 1.85 int width = c < 0x100 ? 1 : wcwidth (c);
869 pcg 1.54
870 pcg 1.25 if (charsets[screen.charset] == '0') // DEC SPECIAL
871 pcg 1.66 {
872     // vt100 special graphics and line drawing
873     static uint16_t vt100_0[32] = { // 5f .. 7e
874     0x0020, 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
875     0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
876     0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534,
877     0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7,
878     };
879    
880     if (c >= 0x5f && c <= 0x7e)
881     {
882     c = vt100_0[c - 0x5f];
883     width = 1;
884     }
885     }
886 pcg 1.1
887 pcg 1.74 if (width != 0)
888 pcg 1.43 {
889 pcg 1.57 #if !UNICODE_3 && ENABLE_COMBINING
890 pcg 1.54 // trim characters we can't store directly :(
891     if (c >= 0x10000)
892     c = rxvt_composite.compose (c); // map to lower 16 bits
893     #endif
894 root 1.77 bool bold = (Options & Opt_realBold) && ((rstyle & RS_Bold) != 0);
895 root 1.82 rend_t rend = SET_FONT (rstyle,
896     c > 0x7f || bold || c < 0x20
897     ? TermWin.fontset->find_font (c, bold)
898     : TermWin.ascii_map [c - 0x20]);
899 pcg 1.54
900 pcg 1.43 do
901     {
902     stp[screen.cur.col] = c;
903     srp[screen.cur.col] = rend;
904    
905     if (screen.cur.col < last_col - 1)
906     screen.cur.col++;
907     else
908     {
909     screen.tlen[row] = last_col;
910     if (screen.flags & Screen_Autowrap)
911     screen.flags |= Screen_WrapNext;
912     break;
913     }
914 pcg 1.1
915 pcg 1.43 c = NOCHAR;
916     }
917     while (--width > 0);
918 pcg 1.1
919 pcg 1.43 // pad with spaces when overwriting wide character with smaller one
920 pcg 1.54 for (int c = screen.cur.col; c < last_col && stp[c] == NOCHAR; c++)
921 pcg 1.43 {
922     stp[c] = ' ';
923     srp[c] = rend;
924     }
925     }
926 pcg 1.54 else if (width == 0)
927     {
928 pcg 1.57 #if ENABLE_COMBINING
929 pcg 1.54 // handle combining characters
930     // we just tag the accent on the previous on-screen character.
931     // this is arguably not correct, but also arguably not wrong.
932     // we don't handle double-width characters nicely yet.
933    
934     text_t *tp;
935     rend_t *rp;
936    
937     if (screen.cur.col > 0)
938     {
939     tp = stp + screen.cur.col - 1;
940     rp = srp + screen.cur.col - 1;
941     }
942     else if (screen.cur.row > 0
943     && screen.tlen [screen.cur.row - 1 + TermWin.saveLines] == -1)
944     {
945     tp = screen.text[screen.cur.row - 1 + TermWin.saveLines] + last_col - 1;
946     rp = screen.rend[screen.cur.row - 1 + TermWin.saveLines] + last_col - 1;
947     }
948     else
949     continue;
950    
951     // handle double-width-chars by making them look extremely ugly
952     if (*tp == NOCHAR)
953     *tp = ' '; // hack //D //TODO //--tp, --rp;
954    
955     // first try to find a precomposed character
956 pcg 1.59 unicode_t n = rxvt_compose (*tp, c);
957 pcg 1.54 if (n == NOCHAR)
958     n = rxvt_composite.compose (*tp, c);
959    
960     *tp = n;
961     *rp = SET_FONT (*rp, TermWin.fontset->find_font (*tp));
962     #endif
963     }
964 pcg 1.1 }
965 pcg 1.17
966 pcg 1.25 if (screen.tlen[row] != -1) /* XXX: think about this */
967 pcg 1.30 MAX_IT (screen.tlen[row], screen.cur.col);
968 pcg 1.1
969 pcg 1.25 /*
970     * If we wrote anywhere in the selected area, kill the selection
971     * XXX: should we kill the mark too? Possibly, but maybe that
972     * should be a similar check.
973     */
974     if (clearsel)
975 pcg 1.30 CLEAR_SELECTION ();
976 pcg 1.1
977     #ifdef DEBUG_STRICT
978 pcg 1.30 assert (screen.cur.row >= 0);
979 pcg 1.4 #else /* drive with your eyes closed */
980 pcg 1.30 MAX_IT (screen.cur.row, 0);
981 pcg 1.1 #endif
982     }
983    
984     /* ------------------------------------------------------------------------- */
985     /*
986     * Process Backspace. Move back the cursor back a position, wrap if have to
987     * XTERM_SEQ: CTRL-H
988     */
989     void
990 pcg 1.21 rxvt_term::scr_backspace ()
991 pcg 1.1 {
992 pcg 1.25 want_refresh = 1;
993 pcg 1.71
994 pcg 1.25 if (screen.cur.col == 0)
995     {
996     if (screen.cur.row > 0)
997     {
998 pcg 1.1 #ifdef TERMCAP_HAS_BW
999 pcg 1.25 screen.cur.col = TermWin.ncol - 1;
1000     screen.cur.row--;
1001     return;
1002 pcg 1.1 #endif
1003 pcg 1.25
1004 pcg 1.4 }
1005 pcg 1.25 }
1006     else if ((screen.flags & Screen_WrapNext) == 0)
1007     scr_gotorc (0, -1, RELATIVE);
1008 pcg 1.71
1009 pcg 1.25 screen.flags &= ~Screen_WrapNext;
1010 pcg 1.1 }
1011    
1012     /* ------------------------------------------------------------------------- */
1013     /*
1014     * Process Horizontal Tab
1015     * count: +ve = forward; -ve = backwards
1016     * XTERM_SEQ: CTRL-I
1017     */
1018     void
1019 pcg 1.21 rxvt_term::scr_tab (int count)
1020 pcg 1.1 {
1021 pcg 1.66 int i, x;
1022 pcg 1.1
1023 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_tab (%d)", count));
1024 pcg 1.25 want_refresh = 1;
1025     i = x = screen.cur.col;
1026 pcg 1.66
1027 pcg 1.25 if (count == 0)
1028     return;
1029     else if (count > 0)
1030     {
1031     for (; ++i < TermWin.ncol; )
1032     if (tabs[i])
1033     {
1034     x = i;
1035     if (!--count)
1036     break;
1037     }
1038 pcg 1.66
1039 pcg 1.25 if (count)
1040     x = TermWin.ncol - 1;
1041     }
1042     else /* if (count < 0) */
1043     {
1044     for (; --i >= 0; )
1045     if (tabs[i])
1046     {
1047     x = i;
1048     if (!++count)
1049     break;
1050     }
1051 pcg 1.66
1052 pcg 1.25 if (count)
1053     x = 0;
1054 pcg 1.1 }
1055 pcg 1.66
1056 pcg 1.25 if (x != screen.cur.col)
1057     scr_gotorc (0, x, R_RELATIVE);
1058 pcg 1.1 }
1059    
1060     /* ------------------------------------------------------------------------- */
1061     /*
1062     * Process DEC Back Index
1063     * XTERM_SEQ: ESC 6
1064     * Move cursor left in row. If we're at the left boundary, shift everything
1065     * in that row right. Clear left column.
1066     */
1067     #ifndef NO_FRILLS
1068     void
1069 pcg 1.21 rxvt_term::scr_backindex ()
1070 pcg 1.1 {
1071 pcg 1.25 if (screen.cur.col > 0)
1072     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
1073     else
1074     {
1075     if (screen.tlen[screen.cur.row + TermWin.saveLines] == 0)
1076     return; /* um, yeah? */
1077     scr_insdel_chars (1, INSERT);
1078 pcg 1.1 }
1079     }
1080     #endif
1081     /* ------------------------------------------------------------------------- */
1082     /*
1083     * Process DEC Forward Index
1084     * XTERM_SEQ: ESC 9
1085     * Move cursor right in row. If we're at the right boundary, shift everything
1086     * in that row left. Clear right column.
1087     */
1088     #ifndef NO_FRILLS
1089     void
1090 pcg 1.21 rxvt_term::scr_forwardindex ()
1091 pcg 1.1 {
1092 pcg 1.25 int row;
1093 pcg 1.1
1094 pcg 1.25 if (screen.cur.col < TermWin.ncol - 1)
1095     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
1096     else
1097     {
1098     row = screen.cur.row + TermWin.saveLines;
1099     if (screen.tlen[row] == 0)
1100     return; /* um, yeah? */
1101     else if (screen.tlen[row] == -1)
1102     screen.tlen[row] = TermWin.ncol;
1103     scr_gotorc (0, 0, R_RELATIVE);
1104     scr_insdel_chars (1, DELETE);
1105     scr_gotorc (0, TermWin.ncol - 1, R_RELATIVE);
1106 pcg 1.1 }
1107     }
1108     #endif
1109    
1110     /* ------------------------------------------------------------------------- */
1111     /*
1112     * Goto Row/Column
1113     */
1114     void
1115 pcg 1.21 rxvt_term::scr_gotorc (int row, int col, int relative)
1116 pcg 1.1 {
1117 pcg 1.25 want_refresh = 1;
1118 pcg 1.30 ZERO_SCROLLBACK ();
1119 pcg 1.1
1120 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));
1121 pcg 1.1
1122 pcg 1.71 screen.cur.col = relative & C_RELATIVE ? screen.cur.col + col : col;
1123 pcg 1.30 MAX_IT (screen.cur.col, 0);
1124     MIN_IT (screen.cur.col, (int32_t)TermWin.ncol - 1);
1125 pcg 1.25
1126     screen.flags &= ~Screen_WrapNext;
1127     if (relative & R_RELATIVE)
1128     {
1129     if (row > 0)
1130     {
1131     if (screen.cur.row <= screen.bscroll
1132     && (screen.cur.row + row) > screen.bscroll)
1133     screen.cur.row = screen.bscroll;
1134     else
1135     screen.cur.row += row;
1136     }
1137     else if (row < 0)
1138     {
1139     if (screen.cur.row >= screen.tscroll
1140     && (screen.cur.row + row) < screen.tscroll)
1141     screen.cur.row = screen.tscroll;
1142     else
1143     screen.cur.row += row;
1144     }
1145     }
1146     else
1147     {
1148     if (screen.flags & Screen_Relative)
1149     { /* relative origin mode */
1150     screen.cur.row = row + screen.tscroll;
1151 pcg 1.30 MIN_IT (screen.cur.row, screen.bscroll);
1152 pcg 1.4 }
1153 pcg 1.25 else
1154     screen.cur.row = row;
1155 pcg 1.1 }
1156 pcg 1.30 MAX_IT (screen.cur.row, 0);
1157     MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
1158 pcg 1.43
1159     while (screen.cur.col > 0
1160     && screen.text[screen.cur.row + TermWin.saveLines][screen.cur.col] == NOCHAR)
1161     screen.cur.col--;
1162 pcg 1.1 }
1163    
1164     /* ------------------------------------------------------------------------- */
1165     /*
1166     * direction should be UP or DN
1167     */
1168     void
1169 pcg 1.21 rxvt_term::scr_index (enum page_dirn direction)
1170 pcg 1.1 {
1171 pcg 1.71 int dirn;
1172 pcg 1.1
1173 pcg 1.25 want_refresh = 1;
1174     dirn = ((direction == UP) ? 1 : -1);
1175 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_index (%d)", dirn));
1176 pcg 1.1
1177 pcg 1.30 ZERO_SCROLLBACK ();
1178 pcg 1.1
1179 pcg 1.25 screen.flags &= ~Screen_WrapNext;
1180     if ((screen.cur.row == screen.bscroll && direction == UP)
1181     || (screen.cur.row == screen.tscroll && direction == DN))
1182 pcg 1.30 scr_scroll_text (screen.tscroll, screen.bscroll, dirn, 0);
1183 pcg 1.25 else
1184     screen.cur.row += dirn;
1185 pcg 1.30 MAX_IT (screen.cur.row, 0);
1186     MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
1187 pcg 1.25 selection_check (0);
1188 pcg 1.1 }
1189    
1190     /* ------------------------------------------------------------------------- */
1191     /*
1192     * Erase part or whole of a line
1193     * XTERM_SEQ: Clear line to right: ESC [ 0 K
1194     * XTERM_SEQ: Clear line to left : ESC [ 1 K
1195     * XTERM_SEQ: Clear whole line : ESC [ 2 K
1196     */
1197     void
1198 pcg 1.21 rxvt_term::scr_erase_line (int mode)
1199 pcg 1.1 {
1200 pcg 1.8 unsigned int row, col, num;
1201 pcg 1.1
1202 pcg 1.21 want_refresh = 1;
1203 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_erase_line (%d) at screen row: %d", mode, screen.cur.row));
1204 pcg 1.21 ZERO_SCROLLBACK ();
1205 pcg 1.1
1206 pcg 1.21 selection_check (1);
1207 pcg 1.1
1208 pcg 1.21 screen.flags &= ~Screen_WrapNext;
1209 pcg 1.1
1210 pcg 1.21 row = TermWin.saveLines + screen.cur.row;
1211 pcg 1.8 switch (mode)
1212     {
1213     case 0: /* erase to end of line */
1214 pcg 1.21 col = screen.cur.col;
1215     num = TermWin.ncol - col;
1216 pcg 1.30 MIN_IT (screen.tlen[row], (int16_t)col);
1217     if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)
1218     || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur))
1219     CLEAR_SELECTION ();
1220 pcg 1.4 break;
1221 pcg 1.8 case 1: /* erase to beginning of line */
1222 pcg 1.4 col = 0;
1223 pcg 1.21 num = screen.cur.col + 1;
1224 pcg 1.30 if (ROWCOL_IN_ROW_AT_OR_BEFORE (selection.beg, screen.cur)
1225     || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur))
1226     CLEAR_SELECTION ();
1227 pcg 1.4 break;
1228 pcg 1.8 case 2: /* erase whole line */
1229 pcg 1.4 col = 0;
1230 pcg 1.21 num = TermWin.ncol;
1231     screen.tlen[row] = 0;
1232     if (selection.beg.row <= screen.cur.row
1233     && selection.end.row >= screen.cur.row)
1234 pcg 1.30 CLEAR_SELECTION ();
1235 pcg 1.4 break;
1236 pcg 1.8 default:
1237 pcg 1.4 return;
1238 pcg 1.1 }
1239 pcg 1.8
1240 pcg 1.21 if (screen.text[row])
1241 pcg 1.74 scr_blank_line (&screen.text[row][col], &screen.rend[row][col], num, rstyle);
1242 pcg 1.8 else
1243 pcg 1.21 scr_blank_screen_mem (screen.text, screen.rend, row, rstyle);
1244 pcg 1.1 }
1245    
1246     /* ------------------------------------------------------------------------- */
1247     /*
1248     * Erase part of whole of the screen
1249     * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1250     * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1251     * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1252     */
1253     void
1254 pcg 1.11 rxvt_term::scr_erase_screen (int mode)
1255 pcg 1.1 {
1256 pcg 1.66 int num;
1257     int32_t row, row_offset;
1258     rend_t ren;
1259     XGCValues gcvalue;
1260 pcg 1.25
1261     want_refresh = 1;
1262 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_erase_screen (%d) at screen row: %d", mode, screen.cur.row));
1263 pcg 1.25 ZERO_SCROLLBACK ();
1264     row_offset = (int32_t)TermWin.saveLines;
1265 pcg 1.1
1266 pcg 1.25 switch (mode)
1267     {
1268     case 0: /* erase to end of screen */
1269 pcg 1.21 selection_check (1);
1270     scr_erase_line (0);
1271 pcg 1.11 row = screen.cur.row + 1; /* possible OOB */
1272     num = TermWin.nrow - row;
1273 pcg 1.4 break;
1274 pcg 1.25 case 1: /* erase to beginning of screen */
1275 pcg 1.21 selection_check (3);
1276     scr_erase_line (1);
1277 pcg 1.4 row = 0;
1278 pcg 1.11 num = screen.cur.row;
1279 pcg 1.4 break;
1280 pcg 1.25 case 2: /* erase whole screen */
1281 pcg 1.21 selection_check (3);
1282 pcg 1.4 row = 0;
1283 pcg 1.11 num = TermWin.nrow;
1284 pcg 1.4 break;
1285 pcg 1.25 default:
1286 pcg 1.4 return;
1287 pcg 1.1 }
1288 pcg 1.66
1289 pcg 1.25 if (selection.op && current_screen == selection.screen
1290     && ((selection.beg.row >= row && selection.beg.row <= row + num)
1291     || (selection.end.row >= row
1292     && selection.end.row <= row + num)))
1293     CLEAR_SELECTION ();
1294 pcg 1.66
1295 pcg 1.25 if (row >= TermWin.nrow) /* Out Of Bounds */
1296     return;
1297 pcg 1.66
1298 pcg 1.30 MIN_IT (num, (TermWin.nrow - row));
1299 pcg 1.66
1300 pcg 1.25 if (rstyle & (RS_RVid | RS_Uline))
1301     ren = (rend_t) ~RS_None;
1302 pcg 1.30 else if (GET_BASEBG (rstyle) == Color_bg)
1303 pcg 1.25 {
1304     ren = DEFAULT_RSTYLE;
1305 pcg 1.30 CLEAR_ROWS (row, num);
1306 pcg 1.25 }
1307     else
1308     {
1309     ren = (rstyle & (RS_fgMask | RS_bgMask));
1310 pcg 1.30 gcvalue.foreground = PixColors[GET_BGCOLOR (rstyle)];
1311     XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue);
1312     ERASE_ROWS (row, num);
1313 pcg 1.25 gcvalue.foreground = PixColors[Color_fg];
1314 pcg 1.30 XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue);
1315 pcg 1.1 }
1316 pcg 1.66
1317 pcg 1.25 for (; num--; row++)
1318     {
1319     scr_blank_screen_mem (screen.text, screen.rend,
1320 pcg 1.30 (unsigned int) (row + row_offset), rstyle);
1321 pcg 1.25 screen.tlen[row + row_offset] = 0;
1322     scr_blank_line (drawn_text[row], drawn_rend[row],
1323     (unsigned int)TermWin.ncol, ren);
1324 pcg 1.1 }
1325     }
1326    
1327     /* ------------------------------------------------------------------------- */
1328     /*
1329     * Fill the screen with `E's
1330     * XTERM_SEQ: Screen Alignment Test: ESC # 8
1331     */
1332     void
1333 pcg 1.21 rxvt_term::scr_E ()
1334 pcg 1.1 {
1335 pcg 1.25 int i, j, k;
1336     rend_t *r1, fs;
1337 pcg 1.1
1338 pcg 1.25 want_refresh = 1;
1339     num_scr_allow = 0;
1340 pcg 1.30 ZERO_SCROLLBACK ();
1341 pcg 1.25 selection_check (3);
1342    
1343     fs = SET_FONT (rstyle, TermWin.fontset->find_font ('E'));
1344     for (k = TermWin.saveLines, i = TermWin.nrow; i--; k++)
1345     {
1346     screen.tlen[k] = TermWin.ncol; /* make the `E's selectable */
1347     fill_text (screen.text[k], 'E', TermWin.ncol);
1348     for (r1 = screen.rend[k], j = TermWin.ncol; j--; )
1349     *r1++ = fs;
1350 pcg 1.1 }
1351     }
1352    
1353     /* ------------------------------------------------------------------------- */
1354     /*
1355     * Insert/Delete <count> lines
1356     */
1357     void
1358 pcg 1.21 rxvt_term::scr_insdel_lines (int count, int insdel)
1359 pcg 1.1 {
1360 pcg 1.66 int end;
1361 pcg 1.1
1362 pcg 1.30 ZERO_SCROLLBACK ();
1363 pcg 1.1
1364 pcg 1.25 selection_check (1);
1365    
1366     if (screen.cur.row > screen.bscroll)
1367     return;
1368 pcg 1.1
1369 pcg 1.25 end = screen.bscroll - screen.cur.row + 1;
1370     if (count > end)
1371     {
1372     if (insdel == DELETE)
1373 pcg 1.4 return;
1374 pcg 1.25 else if (insdel == INSERT)
1375     count = end;
1376 pcg 1.1 }
1377 pcg 1.25 screen.flags &= ~Screen_WrapNext;
1378 pcg 1.1
1379 pcg 1.30 scr_scroll_text (screen.cur.row, screen.bscroll, insdel * count, 0);
1380 pcg 1.1 }
1381    
1382     /* ------------------------------------------------------------------------- */
1383     /*
1384     * Insert/Delete <count> characters from the current position
1385     */
1386     void
1387 pcg 1.21 rxvt_term::scr_insdel_chars (int count, int insdel)
1388 pcg 1.1 {
1389 pcg 1.66 int col, row;
1390     rend_t tr;
1391     text_t *stp;
1392     rend_t *srp;
1393     int16_t *slp;
1394 pcg 1.1
1395 pcg 1.25 want_refresh = 1;
1396 pcg 1.30 ZERO_SCROLLBACK ();
1397 pcg 1.1
1398 pcg 1.25 if (count <= 0)
1399     return;
1400 pcg 1.1
1401 pcg 1.25 selection_check (1);
1402 pcg 1.30 MIN_IT (count, (TermWin.ncol - screen.cur.col));
1403 pcg 1.1
1404 pcg 1.25 row = screen.cur.row + TermWin.saveLines;
1405     screen.flags &= ~Screen_WrapNext;
1406 pcg 1.1
1407 pcg 1.25 stp = screen.text[row];
1408     srp = screen.rend[row];
1409 pcg 1.30 slp = & (screen.tlen[row]);
1410 pcg 1.66
1411 pcg 1.25 switch (insdel)
1412     {
1413     case INSERT:
1414 pcg 1.21 for (col = TermWin.ncol - 1; (col - count) >= screen.cur.col;
1415 pcg 1.25 col--)
1416     {
1417 pcg 1.4 stp[col] = stp[col - count];
1418     srp[col] = srp[col - count];
1419 pcg 1.25 }
1420 pcg 1.66
1421 pcg 1.25 if (*slp != -1)
1422     {
1423 pcg 1.4 *slp += count;
1424 pcg 1.30 MIN_IT (*slp, TermWin.ncol);
1425 pcg 1.25 }
1426 pcg 1.66
1427 pcg 1.21 if (selection.op && current_screen == selection.screen
1428 pcg 1.30 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1429 pcg 1.25 {
1430 pcg 1.21 if (selection.end.row != screen.cur.row
1431     || (selection.end.col + count >= TermWin.ncol))
1432 pcg 1.30 CLEAR_SELECTION ();
1433 pcg 1.25 else
1434     { /* shift selection */
1435 pcg 1.21 selection.beg.col += count;
1436     selection.mark.col += count; /* XXX: yes? */
1437     selection.end.col += count;
1438 pcg 1.25 }
1439     }
1440 pcg 1.66
1441 pcg 1.30 scr_blank_line (& (stp[screen.cur.col]), & (srp[screen.cur.col]),
1442 pcg 1.25 (unsigned int)count, rstyle);
1443 pcg 1.4 break;
1444 pcg 1.66
1445 pcg 1.25 case ERASE:
1446 pcg 1.21 screen.cur.col += count; /* don't worry if > TermWin.ncol */
1447     selection_check (1);
1448     screen.cur.col -= count;
1449 pcg 1.30 scr_blank_line (& (stp[screen.cur.col]), & (srp[screen.cur.col]),
1450 pcg 1.25 (unsigned int)count, rstyle);
1451 pcg 1.4 break;
1452 pcg 1.66
1453 pcg 1.25 case DELETE:
1454 pcg 1.66 tr = srp[TermWin.ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1455    
1456 pcg 1.25 for (col = screen.cur.col; (col + count) < TermWin.ncol; col++)
1457     {
1458 pcg 1.4 stp[col] = stp[col + count];
1459     srp[col] = srp[col + count];
1460 pcg 1.25 }
1461 pcg 1.66
1462 pcg 1.30 scr_blank_line (& (stp[TermWin.ncol - count]),
1463     & (srp[TermWin.ncol - count]),
1464 pcg 1.25 (unsigned int)count, tr);
1465 pcg 1.66
1466 pcg 1.4 if (*slp == -1) /* break line continuation */
1467 pcg 1.25 *slp = TermWin.ncol;
1468 pcg 1.66
1469 pcg 1.4 *slp -= count;
1470 pcg 1.30 MAX_IT (*slp, 0);
1471 pcg 1.66
1472 pcg 1.21 if (selection.op && current_screen == selection.screen
1473 pcg 1.30 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1474 pcg 1.25 {
1475 pcg 1.21 if (selection.end.row != screen.cur.row
1476     || (screen.cur.col >= selection.beg.col - count)
1477     || selection.end.col >= TermWin.ncol)
1478 pcg 1.30 CLEAR_SELECTION ();
1479 pcg 1.25 else
1480     {
1481 pcg 1.4 /* shift selection */
1482 pcg 1.21 selection.beg.col -= count;
1483     selection.mark.col -= count; /* XXX: yes? */
1484     selection.end.col -= count;
1485 pcg 1.25 }
1486     }
1487 pcg 1.66
1488 pcg 1.4 break;
1489 pcg 1.1 }
1490     }
1491    
1492     /* ------------------------------------------------------------------------- */
1493     /*
1494     * Set the scrolling region
1495     * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1496     */
1497     void
1498 pcg 1.21 rxvt_term::scr_scroll_region (int top, int bot)
1499 pcg 1.1 {
1500 pcg 1.30 MAX_IT (top, 0);
1501     MIN_IT (bot, (int)TermWin.nrow - 1);
1502 pcg 1.66
1503 pcg 1.25 if (top > bot)
1504     return;
1505 pcg 1.66
1506 pcg 1.25 screen.tscroll = top;
1507     screen.bscroll = bot;
1508     scr_gotorc (0, 0, 0);
1509 pcg 1.1 }
1510    
1511     /* ------------------------------------------------------------------------- */
1512     /*
1513     * Make the cursor visible/invisible
1514     * XTERM_SEQ: Make cursor visible : ESC [ ? 25 h
1515     * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1516     */
1517     void
1518 pcg 1.21 rxvt_term::scr_cursor_visible (int mode)
1519 pcg 1.1 {
1520 pcg 1.25 want_refresh = 1;
1521 pcg 1.71
1522 pcg 1.25 if (mode)
1523     screen.flags |= Screen_VisibleCursor;
1524     else
1525     screen.flags &= ~Screen_VisibleCursor;
1526 pcg 1.1 }
1527    
1528     /* ------------------------------------------------------------------------- */
1529     /*
1530     * Set/unset automatic wrapping
1531     * XTERM_SEQ: Set Wraparound : ESC [ ? 7 h
1532     * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1533     */
1534     void
1535 pcg 1.21 rxvt_term::scr_autowrap (int mode)
1536 pcg 1.1 {
1537 pcg 1.25 if (mode)
1538     screen.flags |= Screen_Autowrap;
1539     else
1540 pcg 1.30 screen.flags &= ~ (Screen_Autowrap | Screen_WrapNext);
1541 pcg 1.1 }
1542    
1543     /* ------------------------------------------------------------------------- */
1544     /*
1545     * Set/unset margin origin mode
1546     * Absolute mode: line numbers are counted relative to top margin of screen
1547     * and the cursor can be moved outside the scrolling region.
1548     * Relative mode: line numbers are relative to top margin of scrolling region
1549     * and the cursor cannot be moved outside.
1550     * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1551     * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1552     */
1553     void
1554 pcg 1.21 rxvt_term::scr_relative_origin (int mode)
1555 pcg 1.1 {
1556 pcg 1.25 if (mode)
1557     screen.flags |= Screen_Relative;
1558     else
1559     screen.flags &= ~Screen_Relative;
1560     scr_gotorc (0, 0, 0);
1561 pcg 1.1 }
1562    
1563     /* ------------------------------------------------------------------------- */
1564     /*
1565     * Set insert/replace mode
1566     * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1567     * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1568     */
1569     void
1570 pcg 1.21 rxvt_term::scr_insert_mode (int mode)
1571 pcg 1.1 {
1572 pcg 1.25 if (mode)
1573     screen.flags |= Screen_Insert;
1574     else
1575     screen.flags &= ~Screen_Insert;
1576 pcg 1.1 }
1577    
1578     /* ------------------------------------------------------------------------- */
1579     /*
1580     * Set/Unset tabs
1581     * XTERM_SEQ: Set tab at current column : ESC H
1582     * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1583     * XTERM_SEQ: Clear all tabs : ESC [ 3 g
1584     */
1585     void
1586 pcg 1.21 rxvt_term::scr_set_tab (int mode)
1587 pcg 1.1 {
1588 pcg 1.25 if (mode < 0)
1589 pcg 1.30 MEMSET (tabs, 0, TermWin.ncol * sizeof (char));
1590 pcg 1.25 else if (screen.cur.col < TermWin.ncol)
1591     tabs[screen.cur.col] = (mode ? 1 : 0);
1592 pcg 1.1 }
1593    
1594     /* ------------------------------------------------------------------------- */
1595     /*
1596     * Set reverse/normal video
1597     * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1598     * XTERM_SEQ: Normal video : ESC [ ? 5 l
1599     */
1600     void
1601 pcg 1.21 rxvt_term::scr_rvideo_mode (int mode)
1602 pcg 1.1 {
1603 pcg 1.25 XGCValues gcvalue;
1604 pcg 1.1
1605 pcg 1.25 if (rvideo != mode)
1606     {
1607     rvideo = mode;
1608 pcg 1.30 SWAP_IT (PixColors[Color_fg], PixColors[Color_bg], rxvt_color);
1609 pcg 1.1 #if defined(XPM_BACKGROUND)
1610 pcg 1.25 if (bgPixmap.pixmap == None)
1611 pcg 1.1 #endif
1612     #if defined(TRANSPARENT)
1613 pcg 1.30 if (! (Options & Opt_transparent) || am_transparent == 0)
1614 pcg 1.1 #endif
1615 pcg 1.30 XSetWindowBackground (display->display, TermWin.vt,
1616 pcg 1.25 PixColors[Color_bg]);
1617 pcg 1.1
1618 pcg 1.25 gcvalue.foreground = PixColors[Color_fg];
1619     gcvalue.background = PixColors[Color_bg];
1620 pcg 1.30 XChangeGC (display->display, TermWin.gc, GCBackground | GCForeground,
1621 pcg 1.25 &gcvalue);
1622     scr_clear ();
1623     scr_touch (true);
1624 pcg 1.1 }
1625     }
1626    
1627     /* ------------------------------------------------------------------------- */
1628     /*
1629     * Report current cursor position
1630     * XTERM_SEQ: Report position: ESC [ 6 n
1631     */
1632     void
1633 pcg 1.21 rxvt_term::scr_report_position ()
1634 pcg 1.1 {
1635 pcg 1.30 tt_printf ("\033[%d;%dR", screen.cur.row + 1, screen.cur.col + 1);
1636 pcg 1.1 }
1637    
1638     /* ------------------------------------------------------------------------- *
1639     * FONTS *
1640     * ------------------------------------------------------------------------- */
1641    
1642     /*
1643     * Set font style
1644     */
1645     void
1646 pcg 1.21 rxvt_term::set_font_style ()
1647 pcg 1.1 {
1648 pcg 1.25 switch (charsets[screen.charset])
1649     {
1650     case '0': /* DEC Special Character & Line Drawing Set */
1651 pcg 1.4 break;
1652 pcg 1.25 case 'A': /* United Kingdom (UK) */
1653 pcg 1.4 break;
1654 pcg 1.25 case 'B': /* United States (USASCII) */
1655 pcg 1.4 break;
1656 pcg 1.25 case '<': /* Multinational character set */
1657 pcg 1.4 break;
1658 pcg 1.25 case '5': /* Finnish character set */
1659 pcg 1.4 break;
1660 pcg 1.25 case 'C': /* Finnish character set */
1661 pcg 1.4 break;
1662 pcg 1.25 case 'K': /* German character set */
1663 pcg 1.4 break;
1664 pcg 1.1 }
1665     }
1666    
1667     /* ------------------------------------------------------------------------- */
1668     /*
1669     * Choose a font
1670     * XTERM_SEQ: Invoke G0 character set: CTRL-O
1671     * XTERM_SEQ: Invoke G1 character set: CTRL-N
1672     * XTERM_SEQ: Invoke G2 character set: ESC N
1673     * XTERM_SEQ: Invoke G3 character set: ESC O
1674     */
1675     void
1676 pcg 1.21 rxvt_term::scr_charset_choose (int set)
1677 pcg 1.25 {
1678 pcg 1.21 screen.charset = set;
1679     set_font_style ();
1680 pcg 1.25 }
1681 pcg 1.1
1682     /* ------------------------------------------------------------------------- */
1683     /*
1684     * Set a font
1685     * XTERM_SEQ: Set G0 character set: ESC ( <C>
1686     * XTERM_SEQ: Set G1 character set: ESC ) <C>
1687     * XTERM_SEQ: Set G2 character set: ESC * <C>
1688     * XTERM_SEQ: Set G3 character set: ESC + <C>
1689     * See set_font_style for possible values for <C>
1690     */
1691     void
1692 pcg 1.21 rxvt_term::scr_charset_set (int set, unsigned int ch)
1693 pcg 1.25 {
1694 pcg 1.21 charsets[set] = (unsigned char)ch;
1695     set_font_style ();
1696 pcg 1.25 }
1697 pcg 1.1
1698    
1699     /* ------------------------------------------------------------------------- *
1700     * MAJOR SCREEN MANIPULATION *
1701     * ------------------------------------------------------------------------- */
1702    
1703     /*
1704 pcg 1.19 * refresh matching text.
1705     */
1706     bool
1707     rxvt_term::scr_refresh_rend (rend_t mask, rend_t value)
1708     {
1709     bool found = false;
1710    
1711     for (int i = 0; i < TermWin.nrow; i++)
1712     {
1713     int col = 0;
1714     rend_t *drp = drawn_rend [i];
1715    
1716     for (; col < TermWin.ncol; col++, drp++)
1717     if ((*drp & mask) == value)
1718     {
1719     found = true;
1720     *drp = ~value;
1721     }
1722     }
1723    
1724     return found;
1725     }
1726    
1727     /*
1728 pcg 1.1 * Refresh an area
1729     */
1730     enum {
1731 pcg 1.25 PART_BEG = 0,
1732     PART_END,
1733     RC_COUNT
1734 pcg 1.1 };
1735    
1736     void
1737 pcg 1.11 rxvt_term::scr_expose (int x, int y, int width, int height, bool refresh)
1738 pcg 1.1 {
1739 pcg 1.11 int i;
1740     row_col_t rc[RC_COUNT];
1741 pcg 1.1
1742 pcg 1.11 if (drawn_text == NULL) /* sanity check */
1743     return;
1744 pcg 1.1
1745 root 1.82 #ifndef NO_SLOW_LINK_SUPPORT
1746     if (refresh_type == FAST_REFRESH && !display->is_local)
1747     {
1748     y = 0;
1749     height = TermWin.height;
1750     }
1751     #endif
1752    
1753 pcg 1.1 #ifdef DEBUG_STRICT
1754 root 1.77 x = max (x, 0);
1755 pcg 1.30 x = min (x, (int)TermWin.width);
1756 root 1.77 y = max (y, 0);
1757 pcg 1.30 y = min (y, (int)TermWin.height);
1758 pcg 1.1 #endif
1759    
1760 pcg 1.25 /* round down */
1761 pcg 1.30 rc[PART_BEG].col = Pixel2Col (x);
1762     rc[PART_BEG].row = Pixel2Row (y);
1763 pcg 1.25 /* round up */
1764 pcg 1.30 rc[PART_END].col = Pixel2Width (x + width + TermWin.fwidth - 1);
1765     rc[PART_END].row = Pixel2Row (y + height + TermWin.fheight - 1);
1766 pcg 1.1
1767 pcg 1.25 /* sanity checks */
1768 pcg 1.11 for (i = PART_BEG; i < RC_COUNT; i++)
1769     {
1770 pcg 1.30 MIN_IT (rc[i].col, TermWin.ncol - 1);
1771     MIN_IT (rc[i].row, TermWin.nrow - 1);
1772 pcg 1.1 }
1773    
1774 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));
1775 pcg 1.1
1776 pcg 1.11 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1777 pcg 1.74 fill_text (&drawn_text[i][rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
1778 pcg 1.1
1779 pcg 1.11 if (refresh)
1780 root 1.85 scr_refresh (SLOW_REFRESH);
1781 pcg 1.1 }
1782    
1783     /* ------------------------------------------------------------------------- */
1784     /*
1785     * Refresh the entire screen
1786     */
1787     void
1788 pcg 1.11 rxvt_term::scr_touch (bool refresh)
1789 pcg 1.1 {
1790 pcg 1.11 scr_expose (0, 0, TermWin.width, TermWin.height, refresh);
1791 pcg 1.1 }
1792    
1793     /* ------------------------------------------------------------------------- */
1794     /*
1795     * Move the display so that the line represented by scrollbar value Y is at
1796     * the top of the screen
1797     */
1798     int
1799 pcg 1.21 rxvt_term::scr_move_to (int y, int len)
1800 pcg 1.1 {
1801 pcg 1.25 long p = 0;
1802     uint16_t oldviewstart;
1803 pcg 1.1
1804 pcg 1.25 oldviewstart = TermWin.view_start;
1805     if (y < len)
1806     {
1807     p = (TermWin.nrow + TermWin.nscrolled) * (len - y) / len;
1808 pcg 1.30 p -= (long) (TermWin.nrow - 1);
1809     p = max (p, 0);
1810 pcg 1.1 }
1811 pcg 1.30 TermWin.view_start = (uint16_t)min (p, TermWin.nscrolled);
1812     D_SCREEN ((stderr, "rxvt_scr_move_to (%d, %d) view_start:%d", y, len, TermWin.view_start));
1813 pcg 1.1
1814 pcg 1.25 return scr_changeview (oldviewstart);
1815 pcg 1.1 }
1816    
1817     /* ------------------------------------------------------------------------- */
1818     /*
1819     * Page the screen up/down nlines
1820     * direction should be UP or DN
1821     */
1822     int
1823 pcg 1.21 rxvt_term::scr_page (enum page_dirn direction, int nlines)
1824 pcg 1.1 {
1825 root 1.85 int n;
1826     uint16_t oldviewstart;
1827 pcg 1.1
1828 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_page (%s, %d) view_start:%d", ((direction == UP) ? "UP" : "DN"), nlines, TermWin.view_start));
1829 pcg 1.1 #ifdef DEBUG_STRICT
1830 pcg 1.30 assert ((nlines >= 0) && (nlines <= TermWin.nrow));
1831 pcg 1.1 #endif
1832 pcg 1.25 oldviewstart = TermWin.view_start;
1833     if (direction == UP)
1834     {
1835     n = TermWin.view_start + nlines;
1836 pcg 1.30 TermWin.view_start = min (n, TermWin.nscrolled);
1837 pcg 1.25 }
1838     else
1839     {
1840     n = TermWin.view_start - nlines;
1841 pcg 1.30 TermWin.view_start = max (n, 0);
1842 pcg 1.1 }
1843 pcg 1.25 return scr_changeview (oldviewstart);
1844 pcg 1.1 }
1845    
1846     int
1847 pcg 1.21 rxvt_term::scr_changeview (uint16_t oldviewstart)
1848 pcg 1.1 {
1849 pcg 1.25 if (TermWin.view_start != oldviewstart)
1850     {
1851     want_refresh = 1;
1852     num_scr -= (TermWin.view_start - oldviewstart);
1853 pcg 1.1 }
1854 pcg 1.71
1855 pcg 1.30 return (int) (TermWin.view_start - oldviewstart);
1856 pcg 1.1 }
1857    
1858     /* ------------------------------------------------------------------------- */
1859     void
1860 pcg 1.21 rxvt_term::scr_bell ()
1861 pcg 1.1 {
1862     #ifndef NO_BELL
1863     # ifndef NO_MAPALERT
1864     # ifdef MAPALERT_OPTION
1865 pcg 1.25 if (Options & Opt_mapAlert)
1866 pcg 1.1 # endif
1867 pcg 1.30 XMapWindow (display->display, TermWin.parent[0]);
1868 pcg 1.1 # endif
1869 pcg 1.25 if (Options & Opt_visualBell)
1870     {
1871     scr_rvideo_mode (!rvideo); /* refresh also done */
1872     scr_rvideo_mode (!rvideo); /* refresh also done */
1873     }
1874     else
1875 pcg 1.30 XBell (display->display, 0);
1876 pcg 1.1 #endif
1877     }
1878    
1879     /* ------------------------------------------------------------------------- */
1880     /* ARGSUSED */
1881     void
1882 pcg 1.21 rxvt_term::scr_printscreen (int fullhist)
1883 pcg 1.1 {
1884     #ifdef PRINTPIPE
1885 pcg 1.25 int i, r1, nrows, row_offset;
1886     text_t *t;
1887     FILE *fd;
1888 pcg 1.1
1889 pcg 1.25 if ((fd = popen_printer ()) == NULL)
1890     return;
1891     nrows = TermWin.nrow;
1892     row_offset = TermWin.saveLines;
1893     if (!fullhist)
1894     row_offset -= TermWin.view_start;
1895     else
1896     {
1897     nrows += TermWin.nscrolled;
1898     row_offset -= TermWin.nscrolled;
1899 pcg 1.1 }
1900    
1901 pcg 1.25 for (r1 = 0; r1 < nrows; r1++)
1902     {
1903     t = screen.text[r1 + row_offset];
1904     for (i = TermWin.ncol - 1; i >= 0; i--)
1905 pcg 1.30 if (!isspace (t[i]))
1906 pcg 1.25 break;
1907 pcg 1.30 fprintf (fd, "%.*s\n", (i + 1), t);
1908 pcg 1.1 }
1909 pcg 1.25 pclose_printer (fd);
1910 pcg 1.1 #endif
1911     }
1912    
1913     /* ------------------------------------------------------------------------- */
1914     /*
1915     * Refresh the screen
1916 pcg 1.21 * drawn_text/drawn_rend contain the screen information before the update.
1917     * screen.text/screen.rend contain what the screen will change to.
1918 pcg 1.1 */
1919    
1920 pcg 1.4 #define FONT_WIDTH(X, Y) \
1921 pcg 1.30 (X)->per_char[ (Y) - (X)->min_char_or_byte2].width
1922 pcg 1.4 #define FONT_RBEAR(X, Y) \
1923 pcg 1.30 (X)->per_char[ (Y) - (X)->min_char_or_byte2].rbearing
1924 pcg 1.4 #define FONT_LBEAR(X, Y) \
1925 pcg 1.30 (X)->per_char[ (Y) - (X)->min_char_or_byte2].lbearing
1926 pcg 1.4 #define IS_FONT_CHAR(X, Y) \
1927 pcg 1.1 ((Y) >= (X)->min_char_or_byte2 && (Y) <= (X)->max_char_or_byte2)
1928    
1929     void
1930 pcg 1.11 rxvt_term::scr_refresh (unsigned char refresh_type)
1931 pcg 1.1 {
1932 root 1.85 unsigned char must_clear, /* use draw_string not draw_image_string */
1933 pcg 1.35 rvid, /* reverse video this position */
1934     showcursor; /* show the cursor */
1935     int16_t col, row, /* column/row we're processing */
1936     ocrow; /* old cursor row */
1937     int i, /* tmp */
1938     row_offset; /* basic offset in screen structure */
1939 pcg 1.1 #ifndef NO_CURSORCOLOR
1940 pcg 1.35 rend_t cc1; /* store colours at cursor position (s) */
1941 pcg 1.1 #endif
1942 pcg 1.35 rend_t *drp, *srp; /* drawn-rend-pointer, screen-rend-pointer */
1943     text_t *dtp, *stp; /* drawn-text-pointer, screen-text-pointer */
1944 pcg 1.1
1945 pcg 1.25 if (refresh_type == NO_REFRESH || !TermWin.mapped)
1946     return;
1947 pcg 1.1
1948 pcg 1.25 /*
1949     * A: set up vars
1950     */
1951 root 1.85 must_clear = 0;
1952 pcg 1.1
1953 pcg 1.25 refresh_count = 0;
1954 pcg 1.1
1955 pcg 1.25 row_offset = TermWin.saveLines - TermWin.view_start;
1956 pcg 1.1
1957 pcg 1.22 #ifdef XPM_BACKGROUND
1958 pcg 1.25 must_clear |= (bgPixmap.pixmap != None);
1959 pcg 1.1 #endif
1960 pcg 1.22 #ifdef TRANSPARENT
1961 pcg 1.25 must_clear |= ((Options & Opt_transparent) && am_transparent);
1962 pcg 1.1 #endif
1963 pcg 1.25 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
1964 pcg 1.1
1965 pcg 1.25 /*
1966     * B: reverse any characters which are selected
1967     */
1968     scr_reverse_selection ();
1969 pcg 1.1
1970 pcg 1.25 /*
1971 pcg 1.30 * C: set the cursor character (s)
1972 pcg 1.25 */
1973     {
1974 pcg 1.66 unsigned char setoldcursor;
1975     rend_t ccol1, /* Cursor colour */
1976     ccol2; /* Cursor colour2 */
1977 pcg 1.1
1978 pcg 1.25 showcursor = (screen.flags & Screen_VisibleCursor);
1979 pcg 1.1 #ifdef CURSOR_BLINK
1980 pcg 1.25 if (hidden_cursor)
1981     showcursor = 0;
1982 pcg 1.1 #endif
1983    
1984 pcg 1.25 if (showcursor)
1985     {
1986 pcg 1.66 srp = &(screen.rend[screen.cur.row + TermWin.saveLines][screen.cur.col]);
1987 pcg 1.1
1988 pcg 1.25 if (showcursor && TermWin.focus)
1989     {
1990     *srp ^= RS_RVid;
1991 pcg 1.1 #ifndef NO_CURSORCOLOR
1992 pcg 1.25 cc1 = *srp & (RS_fgMask | RS_bgMask);
1993     if (ISSET_PIXCOLOR (Color_cursor))
1994     ccol1 = Color_cursor;
1995     else
1996 pcg 1.1 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
1997 pcg 1.30 ccol1 = GET_FGCOLOR (rstyle);
1998 pcg 1.1 #else
1999 pcg 1.25 ccol1 = Color_fg;
2000 pcg 1.1 #endif
2001 pcg 1.25 if (ISSET_PIXCOLOR (Color_cursor2))
2002     ccol2 = Color_cursor2;
2003     else
2004 pcg 1.1 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2005 pcg 1.30 ccol2 = GET_BGCOLOR (rstyle);
2006 pcg 1.1 #else
2007 pcg 1.25 ccol2 = Color_bg;
2008 pcg 1.1 #endif
2009 pcg 1.30 *srp = SET_FGCOLOR (*srp, ccol1);
2010     *srp = SET_BGCOLOR (*srp, ccol2);
2011 pcg 1.1 #endif
2012     }
2013 pcg 1.4 }
2014 pcg 1.1
2015 pcg 1.25 /* make sure no outline cursor is left around */
2016     setoldcursor = 0;
2017     if (ocrow != -1)
2018 pcg 1.4 {
2019 pcg 1.25 if (screen.cur.row + TermWin.view_start != ocrow
2020     || screen.cur.col != oldcursor.col)
2021 pcg 1.4 {
2022 pcg 1.25 if (ocrow < TermWin.nrow
2023     && oldcursor.col < TermWin.ncol)
2024 pcg 1.66 drawn_rend[ocrow][oldcursor.col] ^= (RS_RVid | RS_Uline);
2025    
2026 pcg 1.25 if (TermWin.focus || !showcursor)
2027     oldcursor.row = -1;
2028     else
2029     setoldcursor = 1;
2030 pcg 1.4 }
2031 pcg 1.25 }
2032     else if (!TermWin.focus)
2033     setoldcursor = 1;
2034 pcg 1.66
2035 pcg 1.25 if (setoldcursor)
2036     {
2037     if (screen.cur.row + TermWin.view_start >= TermWin.nrow)
2038     oldcursor.row = -1;
2039     else
2040     {
2041     oldcursor.row = screen.cur.row + TermWin.view_start;
2042     oldcursor.col = screen.cur.col;
2043     }
2044     }
2045     }
2046    
2047     #ifndef NO_SLOW_LINK_SUPPORT
2048     /*
2049     * D: CopyArea pass - very useful for slower links
2050     * This has been deliberately kept simple.
2051     */
2052     i = num_scr;
2053 root 1.82 if (!display->is_local
2054     && refresh_type == FAST_REFRESH && num_scr_allow && i
2055 pcg 1.30 && abs (i) < TermWin.nrow && !must_clear)
2056 pcg 1.25 {
2057 pcg 1.66 int16_t nits;
2058     int j;
2059     rend_t *drp2;
2060     text_t *dtp2;
2061     int len, wlen;
2062 pcg 1.25
2063     j = TermWin.nrow;
2064     wlen = len = -1;
2065     row = i > 0 ? 0 : j - 1;
2066     for (; j-- >= 0; row += (i > 0 ? 1 : -1))
2067     {
2068     if (row + i >= 0 && row + i < TermWin.nrow && row + i != ocrow)
2069     {
2070     stp = screen.text[row + row_offset];
2071     srp = screen.rend[row + row_offset];
2072     dtp = drawn_text[row];
2073     dtp2 = drawn_text[row + i];
2074     drp = drawn_rend[row];
2075     drp2 = drawn_rend[row + i];
2076    
2077     for (nits = 0, col = TermWin.ncol; col--; )
2078     if (stp[col] != dtp2[col] || srp[col] != drp2[col])
2079     nits--;
2080     else if (stp[col] != dtp[col] || srp[col] != drp[col])
2081     nits++;
2082    
2083     if (nits > 8) /* XXX: arbitrary choice */
2084     {
2085     for (col = TermWin.ncol; col--; )
2086     {
2087     *dtp++ = *dtp2++;
2088     *drp++ = *drp2++;
2089     }
2090    
2091     if (len == -1)
2092     len = row;
2093    
2094     wlen = row;
2095     continue;
2096     }
2097     }
2098    
2099     if (len != -1)
2100     {
2101     /* also comes here at end if needed because of >= above */
2102     if (wlen < len)
2103 pcg 1.30 SWAP_IT (wlen, len, int);
2104 pcg 1.25
2105 pcg 1.30 D_SCREEN ((stderr, "rxvt_scr_refresh (): XCopyArea: %d -> %d (height: %d)", len + i, len, wlen - len + 1));
2106 pcg 1.27 XCopyArea (display->display, TermWin.vt, TermWin.vt,
2107 pcg 1.25 TermWin.gc, 0, Row2Pixel (len + i),
2108     (unsigned int)TermWin_TotalWidth (),
2109     (unsigned int)Height2Pixel (wlen - len + 1),
2110     0, Row2Pixel (len));
2111     len = -1;
2112     }
2113     }
2114 pcg 1.1 }
2115     #endif
2116    
2117 pcg 1.25 /*
2118     * E: main pass across every character
2119     */
2120     for (row = 0; row < TermWin.nrow; row++)
2121     {
2122     stp = screen.text[row + row_offset];
2123     srp = screen.rend[row + row_offset];
2124     dtp = drawn_text[row];
2125     drp = drawn_rend[row];
2126    
2127     /*
2128     * E2: OK, now the real pass
2129     */
2130 pcg 1.30 int ypixel = (int)Row2Pixel (row);
2131 pcg 1.25
2132     for (col = 0; col < TermWin.ncol; col++)
2133     {
2134     /* compare new text with old - if exactly the same then continue */
2135     if (stp[col] == dtp[col] /* Must match characters to skip. */
2136 pcg 1.43 && (srp[col] == drp[col] /* Either rendition the same or */
2137 pcg 1.25 || (stp[col] == ' ' /* space w/ no background change */
2138 pcg 1.43 && GET_BGATTR (srp[col]) == GET_BGATTR (drp[col]))))
2139 pcg 1.25 continue;
2140 pcg 1.1
2141 pcg 1.43 // redraw one or more characters
2142    
2143     // seek to the beginning if wide characters
2144     while (stp[col] == NOCHAR && col > 0)
2145     --col;
2146    
2147     rend_t rend = srp[col]; /* screen rendition (target rendtion) */
2148 pcg 1.25 text_t *text = stp + col;
2149     int count = 1;
2150 pcg 1.1
2151 pcg 1.25 dtp[col] = stp[col];
2152     drp[col] = rend;
2153 pcg 1.1
2154 pcg 1.30 int xpixel = Col2Pixel (col);
2155 pcg 1.1
2156 pcg 1.25 // this loop looks very messy, it can probably be optimized
2157     // and cleaned a bit by you?
2158     for (i = 0; ++col < TermWin.ncol; )
2159     {
2160     if (stp[col] == NOCHAR)
2161     {
2162     dtp[col] = stp[col];
2163     drp[col] = rend;
2164     count++;
2165 pcg 1.1
2166 pcg 1.25 if (i) // only possible skip if char unchanged
2167     i++;
2168 pcg 1.1
2169 pcg 1.25 continue;
2170     }
2171 pcg 1.1
2172 pcg 1.25 if (rend != srp[col])
2173     break;
2174 pcg 1.1
2175 pcg 1.25 count++;
2176 pcg 1.1
2177 pcg 1.25 if (stp[col] != dtp[col]
2178     || srp[col] != drp[col])
2179     {
2180     if (must_clear && (i++ > (count / 2)))
2181     break;
2182 pcg 1.1
2183 pcg 1.25 dtp[col] = stp[col];
2184     drp[col] = rend;
2185     i = 0;
2186     }
2187     else if (must_clear || (stp[col] != ' ' && ++i >= 32))
2188     break;
2189     }
2190 pcg 1.1
2191 pcg 1.25 col--; /* went one too far. move back */
2192     count -= i; /* dump any matching trailing chars */
2193 pcg 1.1
2194 pcg 1.25 /*
2195     * Determine the attributes for the string
2196     */
2197     int fid = GET_FONT (rend);
2198     int fore = GET_FGCOLOR (rend); // desired foreground
2199     int back = GET_BGCOLOR (rend); // desired background
2200 pcg 1.17
2201 pcg 1.25 rend = GET_ATTR (rend);
2202 pcg 1.1
2203 pcg 1.36 rvid = !!(rend & RS_RVid);
2204 pcg 1.1
2205     #ifndef NO_BOLD_UNDERLINE_REVERSE
2206 root 1.77 if (rend & RS_Bold && fore == Color_fg && !(Options & Opt_realBold))
2207 pcg 1.25 {
2208     if (ISSET_PIXCOLOR (Color_BD))
2209     fore = Color_BD;
2210 pcg 1.36 else
2211     rvid = !rvid;
2212 pcg 1.25 }
2213 pcg 1.36
2214     if (rend & RS_Uline)
2215 pcg 1.57 if (ISSET_PIXCOLOR (Color_UL))
2216     fore = Color_UL;
2217 pcg 1.1 #endif
2218    
2219 pcg 1.36 if (rvid)
2220     {
2221     SWAP_IT (fore, back, int);
2222    
2223     #ifndef NO_BOLD_UNDERLINE_REVERSE
2224     if (ISSET_PIXCOLOR (Color_RV)
2225     # ifndef NO_CURSORCOLOR
2226     && !ISSET_PIXCOLOR (Color_cursor)
2227     # endif
2228     )
2229     back = Color_RV;
2230     #endif
2231     }
2232    
2233 pcg 1.37 #ifdef TEXT_BLINK
2234 root 1.82 if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
2235 pcg 1.37 {
2236     if (!text_blink_ev.active)
2237     {
2238     text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
2239     hidden_text = 0;
2240     }
2241     else if (hidden_text)
2242     fore = back;
2243     }
2244     #endif
2245    
2246 pcg 1.25 /*
2247     * Actually do the drawing of the string here
2248     */
2249     rxvt_font *font = (*TermWin.fontset)[fid];
2250    
2251     if (back == fore)
2252 pcg 1.34 font->clear_rect (*TermWin.drawable, xpixel, ypixel,
2253 pcg 1.25 TermWin.fwidth * count, TermWin.fheight,
2254     back);
2255     else if (back == Color_bg)
2256     {
2257     if (must_clear)
2258     {
2259     CLEAR_CHARS (xpixel, ypixel, count);
2260    
2261     for (i = 0; i < count; i++) /* don't draw empty strings */
2262     if (text[i] != ' ')
2263     {
2264 pcg 1.34 font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, -1);
2265 pcg 1.25 break;
2266     }
2267     }
2268     else
2269 pcg 1.34 font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, Color_bg);
2270 pcg 1.25 }
2271     else
2272 pcg 1.34 font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, back);
2273 pcg 1.1
2274 root 1.82 if (rend & RS_Uline && font->descent > 1 && fore != back)
2275 pcg 1.30 XDrawLine (display->display, drawBuffer, TermWin.gc,
2276 pcg 1.43 xpixel, ypixel + font->ascent + 1,
2277     xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2278 pcg 1.25 } /* for (col....) */
2279     } /* for (row....) */
2280 pcg 1.1
2281 pcg 1.25 /*
2282     * G: cleanup cursor and display outline cursor if necessary
2283     */
2284     if (showcursor)
2285     {
2286     if (TermWin.focus)
2287     {
2288 pcg 1.30 srp = & (screen.rend[screen.cur.row + TermWin.saveLines]
2289 pcg 1.25 [screen.cur.col]);
2290     *srp ^= RS_RVid;
2291 pcg 1.1 #ifndef NO_CURSORCOLOR
2292 pcg 1.30 *srp = (*srp & ~ (RS_fgMask | RS_bgMask)) | cc1;
2293 pcg 1.1 #endif
2294 pcg 1.25 }
2295     else if (oldcursor.row >= 0)
2296     {
2297 pcg 1.1 #ifndef NO_CURSORCOLOR
2298 pcg 1.25 if (ISSET_PIXCOLOR (Color_cursor))
2299 pcg 1.27 XSetForeground (display->display, TermWin.gc, PixColors[Color_cursor]);
2300 pcg 1.1 #endif
2301 pcg 1.35 int cursorwidth = 1;
2302     while (oldcursor.col + cursorwidth < TermWin.ncol
2303     && drawn_text[oldcursor.row][oldcursor.col + cursorwidth] == NOCHAR)
2304     cursorwidth++;
2305    
2306 pcg 1.30 XDrawRectangle (display->display, drawBuffer, TermWin.gc,
2307 pcg 1.43 Col2Pixel (oldcursor.col),
2308     Row2Pixel (oldcursor.row),
2309     (unsigned int) (Width2Pixel (cursorwidth) - 1),
2310     (unsigned int) (Height2Pixel (1) - TermWin.lineSpace - 1));
2311 pcg 1.4 }
2312 pcg 1.1 }
2313 pcg 1.12
2314 pcg 1.25 /*
2315     * H: cleanup selection
2316     */
2317     scr_reverse_selection ();
2318    
2319     if (refresh_type & SMOOTH_REFRESH)
2320 root 1.82 XFlush (display->display);
2321 pcg 1.25
2322     num_scr = 0;
2323     num_scr_allow = 1;
2324     want_refresh = 0; /* screen is current */
2325 pcg 1.1 }
2326 pcg 1.11
2327 pcg 1.32 void
2328     rxvt_term::scr_remap_chars (text_t *tp, rend_t *rp)
2329     {
2330     if (!rp || !tp)
2331     return;
2332    
2333     for (int i = TermWin.ncol; i; i--, rp++, tp++)
2334     *rp = SET_FONT (*rp, TermWin.fontset->find_font (*tp));
2335     }
2336    
2337     void
2338     rxvt_term::scr_remap_chars ()
2339     {
2340     for (int i = TermWin.nrow + TermWin.saveLines; i--; )
2341     scr_remap_chars (screen.text[i], screen.rend[i]);
2342    
2343     for (int i = TermWin.nrow; i--; )
2344     {
2345     scr_remap_chars (drawn_text[i], drawn_rend[i]);
2346     scr_remap_chars (swap.text[i], swap.rend[i]);
2347     }
2348     }
2349    
2350 pcg 1.1 /* ------------------------------------------------------------------------- */
2351     void
2352 pcg 1.43 rxvt_term::scr_clear (bool really)
2353 pcg 1.1 {
2354 pcg 1.11 if (!TermWin.mapped)
2355     return;
2356    
2357     num_scr_allow = 0;
2358     want_refresh = 1;
2359 pcg 1.43
2360 pcg 1.1 #ifdef TRANSPARENT
2361 pcg 1.11 if ((Options & Opt_transparent) && (am_pixmap_trans == 0))
2362     {
2363     int i;
2364    
2365 pcg 1.30 if (! (Options & Opt_transparent_all))
2366 pcg 1.11 i = 0;
2367     else
2368 pcg 1.30 i = (int) (sizeof (TermWin.parent) / sizeof (Window));
2369 pcg 1.1
2370 pcg 1.11 while (i--)
2371     if (TermWin.parent[i] != None)
2372 pcg 1.30 XClearWindow (display->display, TermWin.parent[i]);
2373 pcg 1.1 }
2374     #endif
2375 pcg 1.11
2376 pcg 1.43 if (really)
2377     XClearWindow (display->display, TermWin.vt);
2378 pcg 1.1 }
2379    
2380     /* ------------------------------------------------------------------------- */
2381     void
2382 pcg 1.21 rxvt_term::scr_reverse_selection ()
2383 pcg 1.1 {
2384 pcg 1.25 if (selection.op && current_screen == selection.screen)
2385     {
2386 pcg 1.43 int end_row = TermWin.saveLines - TermWin.view_start;
2387     int i = selection.beg.row + TermWin.saveLines;
2388     int col, row = selection.end.row + TermWin.saveLines;
2389     rend_t *srp;
2390    
2391 pcg 1.25 if (i >= end_row)
2392     col = selection.beg.col;
2393     else
2394     {
2395     col = 0;
2396     i = end_row;
2397     }
2398 pcg 1.43
2399 pcg 1.25 end_row += TermWin.nrow;
2400     for (; i < row && i < end_row; i++, col = 0)
2401     for (srp = screen.rend[i]; col < TermWin.ncol; col++)
2402     srp[col] ^= RS_RVid;
2403 pcg 1.43
2404 pcg 1.25 if (i == row && i < end_row)
2405     for (srp = screen.rend[i]; col < selection.end.col; col++)
2406     srp[col] ^= RS_RVid;
2407 pcg 1.1 }
2408     }
2409    
2410     /* ------------------------------------------------------------------------- */
2411     /*
2412     * Dump the whole scrollback and screen to the passed filedescriptor. The
2413     * invoking routine must close the fd.
2414     */
2415     #if 0
2416     void
2417 pcg 1.21 rxvt_term::scr_dump (int fd)
2418 pcg 1.1 {
2419 pcg 1.25 int row, wrote;
2420     unsigned int width, towrite;
2421     char r1[] = "\n";
2422    
2423     for (row = TermWin.saveLines - TermWin.nscrolled;
2424     row < TermWin.saveLines + TermWin.nrow - 1; row++)
2425     {
2426     width = screen.tlen[row] >= 0 ? screen.tlen[row]
2427     : TermWin.ncol;
2428     for (towrite = width; towrite; towrite -= wrote)
2429     {
2430 pcg 1.30 wrote = write (fd, & (screen.text[row][width - towrite]),
2431 pcg 1.25 towrite);
2432     if (wrote < 0)
2433     return; /* XXX: death, no report */
2434     }
2435     if (screen.tlen[row] >= 0)
2436 pcg 1.30 if (write (fd, r1, 1) <= 0)
2437 pcg 1.25 return; /* XXX: death, no report */
2438 pcg 1.1 }
2439     }
2440     #endif
2441    
2442     /* ------------------------------------------------------------------------- *
2443     * CHARACTER SELECTION *
2444     * ------------------------------------------------------------------------- */
2445    
2446     /*
2447 pcg 1.21 * -TermWin.nscrolled <= (selection row) <= TermWin.nrow - 1
2448 pcg 1.1 */
2449     void
2450 pcg 1.21 rxvt_term::selection_check (int check_more)
2451 pcg 1.1 {
2452 pcg 1.25 row_col_t pos;
2453 pcg 1.1
2454 pcg 1.25 if (!selection.op)
2455     return;
2456 pcg 1.1
2457 pcg 1.25 pos.row = pos.col = 0;
2458 pcg 1.30 if ((selection.beg.row < - (int32_t)TermWin.nscrolled)
2459 pcg 1.25 || (selection.beg.row >= TermWin.nrow)
2460 pcg 1.30 || (selection.mark.row < - (int32_t)TermWin.nscrolled)
2461 pcg 1.25 || (selection.mark.row >= TermWin.nrow)
2462 pcg 1.30 || (selection.end.row < - (int32_t)TermWin.nscrolled)
2463 pcg 1.25 || (selection.end.row >= TermWin.nrow)
2464     || (check_more == 1
2465     && current_screen == selection.screen
2466 pcg 1.30 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2467     && ROWCOL_IS_BEFORE (screen.cur, selection.end))
2468 pcg 1.25 || (check_more == 2
2469 pcg 1.30 && ROWCOL_IS_BEFORE (selection.beg, pos)
2470     && ROWCOL_IS_AFTER (selection.end, pos))
2471 pcg 1.25 || (check_more == 3
2472 pcg 1.30 && ROWCOL_IS_AFTER (selection.end, pos))
2473 pcg 1.25 || (check_more == 4 /* screen width change */
2474     && (selection.beg.row != selection.end.row
2475     || selection.end.col > TermWin.ncol)))
2476 pcg 1.30 CLEAR_SELECTION ();
2477 pcg 1.1 }
2478    
2479     /* ------------------------------------------------------------------------- */
2480     /*
2481     * Paste a selection direct to the command fd
2482     */
2483     void
2484 pcg 1.7 rxvt_term::paste (const unsigned char *data, unsigned int len)
2485 pcg 1.1 {
2486 pcg 1.5 unsigned int i, j, n;
2487     unsigned char *ds = (unsigned char *)rxvt_malloc (PROP_SIZE);
2488 pcg 1.25
2489 pcg 1.10 #if 0
2490     /* a paste should act like the user is typing, so check scrollTtyKeypress */
2491     ZERO_SCROLLBACK (r);
2492     #endif
2493    
2494 pcg 1.5 /* convert normal newline chars into common keyboard Return key sequence */
2495 pcg 1.7 for (i = 0; i < len; i += PROP_SIZE)
2496 pcg 1.5 {
2497 pcg 1.7 n = min (len - i, PROP_SIZE);
2498 pcg 1.5 MEMCPY (ds, data + i, n);
2499 pcg 1.7
2500 pcg 1.5 for (j = 0; j < n; j++)
2501 pcg 1.71 if (ds[j] == C0_LF)
2502     ds[j] = C0_CR;
2503 pcg 1.7
2504     tt_write (ds, (int)n);
2505 pcg 1.1 }
2506 pcg 1.5
2507 pcg 1.30 free (ds);
2508 pcg 1.1 }
2509    
2510     /* ------------------------------------------------------------------------- */
2511     /*
2512     * Respond to a notification that a primary selection has been sent
2513     * EXT: SelectionNotify
2514     */
2515     int
2516 pcg 1.21 rxvt_term::selection_paste (Window win, Atom prop, bool delete_prop)
2517 pcg 1.1 {
2518 pcg 1.7 long nread = 0;
2519     unsigned long bytes_after;
2520     XTextProperty ct;
2521    
2522 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_paste (%08lx, %lu, %d), wait=%2x", win, (unsigned long)prop, (int)delete_prop, selection_wait));
2523 pcg 1.7
2524     if (prop == None) /* check for failed XConvertSelection */
2525     {
2526 pcg 1.21 if ((selection_type & Sel_CompoundText))
2527 pcg 1.7 {
2528 pcg 1.21 int selnum = selection_type & Sel_whereMask;
2529 pcg 1.7
2530 pcg 1.21 selection_type = 0;
2531 pcg 1.7 if (selnum != Sel_direct)
2532 pcg 1.21 selection_request_other (XA_STRING, selnum);
2533 pcg 1.4 }
2534 pcg 1.25
2535 pcg 1.21 if ((selection_type & Sel_UTF8String))
2536 pcg 1.18 {
2537 pcg 1.21 int selnum = selection_type & Sel_whereMask;
2538 pcg 1.18
2539 pcg 1.21 selection_type = Sel_CompoundText;
2540 pcg 1.18 if (selnum != Sel_direct)
2541 pcg 1.21 selection_request_other (xa[XA_COMPOUND_TEXT], selnum);
2542 pcg 1.18 else
2543 pcg 1.21 selection_type = 0;
2544 pcg 1.18 }
2545 pcg 1.25
2546 pcg 1.7 return 0;
2547 pcg 1.1 }
2548 pcg 1.7
2549     for (;;)
2550     {
2551 pcg 1.30 if (XGetWindowProperty (display->display, win, prop, (long) (nread / 4),
2552 pcg 1.38 (long) (PROP_SIZE / 4), delete_prop,
2553     AnyPropertyType, &ct.encoding, &ct.format,
2554     &ct.nitems, &bytes_after,
2555     &ct.value) != Success)
2556 pcg 1.7 break;
2557    
2558     if (ct.encoding == 0)
2559     {
2560 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_paste: property didn't exist!"));
2561 pcg 1.7 break;
2562 pcg 1.4 }
2563 pcg 1.7
2564     if (ct.value == NULL)
2565     {
2566 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_paste: property shooting blanks!"));
2567 pcg 1.7 continue;
2568 pcg 1.4 }
2569 pcg 1.7
2570     if (ct.nitems == 0)
2571     {
2572 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_paste: property empty - also INCR end"));
2573 pcg 1.54
2574 pcg 1.38 if (selection_wait == Sel_normal && nread == 0
2575     && (win != display->root || prop != XA_CUT_BUFFER0)) // avoid recursion
2576 pcg 1.7 {
2577     /*
2578     * pass through again trying CUT_BUFFER0 if we've come from
2579 pcg 1.30 * XConvertSelection () but nothing was presented
2580 pcg 1.7 */
2581 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_request: pasting CUT_BUFFER0"));
2582 pcg 1.27 selection_paste (display->root, XA_CUT_BUFFER0, False);
2583 pcg 1.4 }
2584 pcg 1.7
2585     nread = -1; /* discount any previous stuff */
2586     break;
2587     }
2588    
2589     nread += ct.nitems;
2590 pcg 1.18
2591     char **cl;
2592     int cr;
2593 pcg 1.74 if (XmbTextPropertyToTextList (display->display, &ct, &cl, &cr) >= 0 && cl)
2594 pcg 1.7 {
2595 pcg 1.18 for (int i = 0; i < cr; i++)
2596 pcg 1.21 paste ((unsigned char *)cl[i], STRLEN (cl[i]));
2597 pcg 1.18
2598 pcg 1.7 XFreeStringList (cl);
2599 pcg 1.4 }
2600 pcg 1.7 else
2601 pcg 1.21 paste (ct.value, ct.nitems);
2602 pcg 1.7
2603     if (bytes_after == 0)
2604     break;
2605    
2606     XFree (ct.value);
2607 pcg 1.1 }
2608 pcg 1.7
2609     if (ct.value)
2610     XFree (ct.value);
2611    
2612 pcg 1.21 if (selection_wait == Sel_normal)
2613     selection_wait = Sel_none;
2614 pcg 1.7
2615 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_paste: bytes written: %ld", nread));
2616 pcg 1.7 return (int)nread;
2617     }
2618    
2619     void
2620     rxvt_term::incr_cb (time_watcher &w)
2621     {
2622     selection_wait = Sel_none;
2623    
2624 pcg 1.66 rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
2625 pcg 1.1 }
2626    
2627     /*
2628     * INCR support originally provided by Paul Sheer <psheer@obsidian.co.za>
2629     */
2630     void
2631 pcg 1.21 rxvt_term::selection_property (Window win, Atom prop)
2632 pcg 1.1 {
2633 pcg 1.25 int reget_time = 0;
2634 pcg 1.1
2635 pcg 1.25 if (prop == None)
2636     return;
2637 pcg 1.54
2638 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_property (%08lx, %lu)", win, (unsigned long)prop));
2639 pcg 1.25 if (selection_wait == Sel_normal)
2640     {
2641 pcg 1.54 int a, afmt;
2642     Atom atype;
2643     unsigned long bytes_after, nitems;
2644     unsigned char *s = NULL;
2645 pcg 1.25
2646 pcg 1.30 a = XGetWindowProperty (display->display, win, prop, 0L, 1L, False,
2647 pcg 1.25 xa[XA_INCR], &atype, &afmt, &nitems,
2648     &bytes_after, &s);
2649     if (s)
2650 pcg 1.30 XFree (s);
2651 pcg 1.25 if (a != Success)
2652 pcg 1.4 return;
2653 pcg 1.54
2654 pcg 1.1 #ifndef __CYGWIN32__
2655 pcg 1.25 if (atype == xa[XA_INCR])
2656     { /* start an INCR transfer */
2657 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_property: INCR: starting transfer"));
2658     XDeleteProperty (display->display, win, prop);
2659     XFlush (display->display);
2660 pcg 1.25 reget_time = 1;
2661     selection_wait = Sel_incr;
2662     }
2663     #endif
2664    
2665     }
2666     else if (selection_wait == Sel_incr)
2667     {
2668     reget_time = 1;
2669 pcg 1.54
2670 pcg 1.25 if (selection_paste (win, prop, True) == -1)
2671     {
2672 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_property: INCR: clean end"));
2673 pcg 1.25 selection_wait = Sel_none;
2674     incr_ev.stop ();
2675 pcg 1.4 }
2676     }
2677 pcg 1.25 if (reget_time) /* received more data so reget time */
2678     incr_ev.start (NOW + 10);
2679 pcg 1.1 }
2680 pcg 1.54
2681 pcg 1.1 /* ------------------------------------------------------------------------- */
2682     /*
2683     * Request the current selection:
2684     * Order: > internal selection if available
2685     * > PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+)
2686     * > CUT_BUFFER0
2687 pcg 1.30 * (+) if ownership is claimed but property is empty, rxvt_selection_paste ()
2688 pcg 1.1 * will auto fallback to CUT_BUFFER0
2689     * EXT: button 2 release
2690     */
2691     void
2692 pcg 1.21 rxvt_term::selection_request (Time tm, int x, int y)
2693 pcg 1.1 {
2694 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_request (%lu, %d, %d)", tm, x, y));
2695 pcg 1.54
2696 pcg 1.25 if (x < 0 || x >= TermWin.width || y < 0 || y >= TermWin.height)
2697     return; /* outside window */
2698    
2699 pcg 1.54 if (selection.text)
2700     { /* internal selection */
2701 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_request: pasting internal"));
2702 pcg 1.54 char *str = rxvt_wcstombs (selection.text, selection.len);
2703     paste ((unsigned char *)str, strlen (str));
2704     free (str);
2705 pcg 1.25 return;
2706     }
2707     else
2708     {
2709 pcg 1.54 int i;
2710 pcg 1.1
2711 pcg 1.25 selection_request_time = tm;
2712     selection_wait = Sel_normal;
2713 pcg 1.66
2714 pcg 1.25 for (i = Sel_Primary; i <= Sel_Clipboard; i++)
2715     {
2716 pcg 1.18 #if X_HAVE_UTF8_STRING
2717 pcg 1.25 selection_type = Sel_UTF8String;
2718     if (selection_request_other (xa[XA_UTF8_STRING], i))
2719     return;
2720 pcg 1.18 #else
2721 pcg 1.25 selection_type = Sel_CompoundText;
2722     if (selection_request_other (xa[XA_COMPOUND_TEXT], i))
2723     return;
2724 pcg 1.18 #endif
2725 pcg 1.25
2726 pcg 1.4 }
2727 pcg 1.1 }
2728 pcg 1.54
2729 pcg 1.30 selection_wait = Sel_none; /* don't loop in rxvt_selection_paste () */
2730     D_SELECT ((stderr, "rxvt_selection_request: pasting CUT_BUFFER0"));
2731 pcg 1.27 selection_paste (display->root, XA_CUT_BUFFER0, False);
2732 pcg 1.1 }
2733    
2734     int
2735 pcg 1.21 rxvt_term::selection_request_other (Atom target, int selnum)
2736 pcg 1.1 {
2737 pcg 1.54 Atom sel;
2738 pcg 1.1 #ifdef DEBUG_SELECT
2739 pcg 1.54 char *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
2740 pcg 1.1 #endif
2741    
2742 pcg 1.25 selection_type |= selnum;
2743 pcg 1.54
2744 pcg 1.25 if (selnum == Sel_Primary)
2745     sel = XA_PRIMARY;
2746     else if (selnum == Sel_Secondary)
2747     sel = XA_SECONDARY;
2748     else
2749     sel = xa[XA_CLIPBOARD];
2750 pcg 1.54
2751 pcg 1.30 if (XGetSelectionOwner (display->display, sel) != None)
2752 pcg 1.25 {
2753 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_request_other: pasting %s", debug_xa_names[selnum]));
2754     XConvertSelection (display->display, sel, target, xa[XA_VT_SELECTION],
2755 pcg 1.54 TermWin.vt, selection_request_time);
2756 pcg 1.25 return 1;
2757 pcg 1.1 }
2758 pcg 1.54
2759 pcg 1.25 return 0;
2760 pcg 1.1 }
2761    
2762     /* ------------------------------------------------------------------------- */
2763     /*
2764     * Clear all selected text
2765     * EXT: SelectionClear
2766     */
2767     void
2768 pcg 1.21 rxvt_term::selection_clear ()
2769 pcg 1.1 {
2770 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_clear ()"));
2771 pcg 1.1
2772 pcg 1.25 want_refresh = 1;
2773 pcg 1.33 free (selection.text);
2774 pcg 1.25 selection.text = NULL;
2775     selection.len = 0;
2776 pcg 1.30 CLEAR_SELECTION ();
2777 pcg 1.66
2778     if (display->selection_owner == this)
2779     display->selection_owner = 0;
2780 pcg 1.1 }
2781    
2782     /* ------------------------------------------------------------------------- */
2783     /*
2784     * Copy a selection into the cut buffer
2785     * EXT: button 1 or 3 release
2786     */
2787     void
2788 pcg 1.21 rxvt_term::selection_make (Time tm)
2789 pcg 1.1 {
2790 pcg 1.43 int i, col, end_col, row, end_row;
2791 pcg 1.54 wchar_t *new_selection_text;
2792 pcg 1.43 text_t *t;
2793 pcg 1.1
2794 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_make (): selection.op=%d, selection.clicks=%d", selection.op, selection.clicks));
2795 pcg 1.25 switch (selection.op)
2796     {
2797     case SELECTION_CONT:
2798 pcg 1.4 break;
2799 pcg 1.25 case SELECTION_INIT:
2800 pcg 1.30 CLEAR_SELECTION ();
2801 pcg 1.25 /* FALLTHROUGH */
2802     case SELECTION_BEGIN:
2803 pcg 1.21 selection.op = SELECTION_DONE;
2804 pcg 1.25 /* FALLTHROUGH */
2805     default:
2806 pcg 1.4 return;
2807 pcg 1.1 }
2808 pcg 1.39
2809 pcg 1.25 selection.op = SELECTION_DONE;
2810 pcg 1.1
2811 pcg 1.25 if (selection.clicks == 4)
2812     return; /* nothing selected, go away */
2813 pcg 1.1
2814 pcg 1.54 i = (selection.end.row - selection.beg.row + 1) * (TermWin.ncol + 1);
2815     new_selection_text = (wchar_t *)rxvt_malloc ((i + 4) * sizeof (wchar_t));
2816 pcg 1.1
2817 pcg 1.25 col = selection.beg.col;
2818 pcg 1.30 MAX_IT (col, 0);
2819 pcg 1.25 row = selection.beg.row + TermWin.saveLines;
2820     end_row = selection.end.row + TermWin.saveLines;
2821 pcg 1.54 int ofs = 0;
2822     int extra = 0;
2823 pcg 1.1
2824 pcg 1.25 for (; row <= end_row; row++, col = 0)
2825     {
2826 pcg 1.54 t = &(screen.text[row][col]);
2827 pcg 1.1
2828 pcg 1.25 end_col = screen.tlen[row];
2829 pcg 1.1
2830 pcg 1.25 if (end_col == -1)
2831     end_col = TermWin.ncol;
2832 pcg 1.1
2833 pcg 1.25 if (row == end_row)
2834     MIN_IT (end_col, selection.end.col);
2835 pcg 1.1
2836 pcg 1.25 for (; col < end_col; col++)
2837 pcg 1.54 {
2838     if (*t == NOCHAR)
2839     t++;
2840 pcg 1.57 #if ENABLE_COMBINING
2841 pcg 1.54 else if (IS_COMPOSE (*t))
2842     {
2843     int len = rxvt_composite.expand (*t, 0);
2844    
2845     extra -= (len - 1);
2846    
2847     if (extra < 0)
2848     {
2849     extra += i;
2850     i += i;
2851     new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (i + 4) * sizeof (wchar_t));
2852     }
2853    
2854     ofs += rxvt_composite.expand (*t++, new_selection_text + ofs);
2855     }
2856 pcg 1.57 #endif
2857 pcg 1.54 else
2858     new_selection_text[ofs++] = *t++;
2859     }
2860 pcg 1.1
2861 pcg 1.25 if (screen.tlen[row] != -1 && row != end_row)
2862 pcg 1.71 new_selection_text[ofs++] = C0_LF;
2863 pcg 1.25 }
2864 pcg 1.1
2865 pcg 1.59 if (end_col != selection.end.col)
2866 pcg 1.71 new_selection_text[ofs++] = C0_LF;
2867 pcg 1.59
2868 pcg 1.54 new_selection_text[ofs] = 0;
2869 pcg 1.1
2870 pcg 1.54 if (ofs == 0)
2871 pcg 1.25 {
2872     free (new_selection_text);
2873     return;
2874     }
2875 pcg 1.1
2876 pcg 1.54 free (selection.text);
2877 pcg 1.18
2878 pcg 1.54 // we usually allocate much more than necessary, so realloc it smaller again
2879     selection.len = ofs;
2880     selection.text = (wchar_t *)rxvt_realloc (new_selection_text, (ofs + 1) * sizeof (wchar_t));
2881 pcg 1.1
2882 pcg 1.28 XSetSelectionOwner (display->display, XA_PRIMARY, TermWin.vt, tm);
2883     if (XGetSelectionOwner (display->display, XA_PRIMARY) == TermWin.vt)
2884     display->set_selection_owner (this);
2885     else
2886 pcg 1.66 rxvt_warn ("can't get primary selection, ignoring.\n");
2887 pcg 1.18
2888 pcg 1.54 #if 0
2889     XTextProperty ct;
2890 pcg 1.18
2891 pcg 1.54 if (XwcTextListToTextProperty (display->display, &selection.text, 1, XStringStyle, &ct) >= 0)
2892     {
2893 pcg 1.30 XChangeProperty (display->display, display->root, XA_CUT_BUFFER0, XA_STRING, 8,
2894 pcg 1.54 PropModeReplace, ct.value, ct.nitems);
2895     XFree (ct.value);
2896     }
2897     #endif
2898 pcg 1.18
2899 pcg 1.25 selection_time = tm;
2900 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_make (): selection.len=%d", selection.len));
2901 pcg 1.1 }
2902    
2903     /* ------------------------------------------------------------------------- */
2904     /*
2905     * Mark or select text based upon number of clicks: 1, 2, or 3
2906     * EXT: button 1 press
2907     */
2908     void
2909 pcg 1.11 rxvt_term::selection_click (int clicks, int x, int y)
2910 pcg 1.1 {
2911 pcg 1.30 D_SELECT ((stderr, "rxvt_selection_click (%d, %d, %d)", clicks, x, y));
2912 pcg 1.1
2913 pcg 1.11 clicks = ((clicks - 1) % 3) + 1;
2914     selection.clicks = clicks; /* save clicks so extend will work */
2915 pcg 1.1
2916 pcg 1.30 selection_start_colrow (Pixel2Col (x), Pixel2Row (y));
2917 pcg 1.11
2918     if (clicks == 2 || clicks == 3)
2919 pcg 1.21 selection_extend_colrow (selection.mark.col,
2920 pcg 1.25 selection.mark.row + TermWin.view_start,
2921     0, /* button 3 */
2922     1, /* button press */
2923     0); /* click change */
2924 pcg 1.1 }
2925    
2926     /* ------------------------------------------------------------------------- */
2927     /*
2928     * Mark a selection at the specified col/row
2929     */
2930     void
2931 pcg 1.21 rxvt_term::selection_start_colrow (int col, int row)
2932 pcg 1.1 {
2933 pcg 1.25 want_refresh = 1;
2934     selection.mark.col = col;
2935     selection.mark.row = row - TermWin.view_start;
2936 pcg 1.59
2937 pcg 1.30 MAX_IT (selection.mark.row, - (int32_t)TermWin.nscrolled);
2938     MIN_IT (selection.mark.row, (int32_t)TermWin.nrow - 1);
2939     MAX_IT (selection.mark.col, 0);
2940     MIN_IT (selection.mark.col, (int32_t)TermWin.ncol - 1);
2941 pcg 1.25
2942 pcg 1.59 while (selection.mark.col > 0
2943     && screen.text[selection.mark.row + TermWin.saveLines][selection.mark.col] == NOCHAR)
2944     --selection.mark.col;
2945    
2946 pcg 1.25 if (selection.op)
2947     { /* clear the old selection */
2948     selection.beg.row = selection.end.row = selection.mark.row;
2949     selection.beg.col = selection.end.col = selection.mark.col;
2950 pcg 1.1 }
2951 pcg 1.59
2952 pcg 1.25 selection.op = SELECTION_INIT;
2953     selection.screen = current_screen;
2954 pcg 1.1 }
2955    
2956     /* ------------------------------------------------------------------------- */
2957     /*
2958     * Word select: select text for 2 clicks
2959     * We now only find out the boundary in one direction
2960     */
2961    
2962     /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
2963 pcg 1.59 #define DELIMIT_TEXT(x) \
2964     (unicode::is_space (x) ? 2 : (x) <= 0xff && !!STRCHR (rs[Rs_cutchars], (x)))
2965 pcg 1.7 #define DELIMIT_REND(x) 1
2966 pcg 1.1
2967     void
2968 pcg 1.21 rxvt_term::selection_delimit_word (enum page_dirn dirn, const row_col_t *mark, row_col_t *ret)
2969 pcg 1.1 {
2970 pcg 1.59 int col, row, dirnadd, tcol, trow, w1, w2;
2971     row_col_t bound;
2972     text_t *stp;
2973     rend_t *srp;
2974 pcg 1.25
2975     if (dirn == UP)
2976     {
2977     bound.row = TermWin.saveLines - TermWin.nscrolled - 1;
2978     bound.col = 0;
2979     dirnadd = -1;
2980     }
2981     else
2982     {
2983     bound.row = TermWin.saveLines + TermWin.nrow;
2984     bound.col = TermWin.ncol - 1;
2985     dirnadd = 1;
2986     }
2987 pcg 1.59
2988 pcg 1.25 row = mark->row + TermWin.saveLines;
2989     col = mark->col;
2990 pcg 1.30 MAX_IT (col, 0);
2991 pcg 1.25 /* find the edge of a word */
2992 pcg 1.30 stp = & (screen.text[row][col]);
2993     w1 = DELIMIT_TEXT (*stp);
2994 pcg 1.25
2995     srp = (&screen.rend[row][col]);
2996 pcg 1.30 w2 = DELIMIT_REND (*srp);
2997 pcg 1.25
2998     for (;;)
2999     {
3000     for (; col != bound.col; col += dirnadd)
3001     {
3002     stp += dirnadd;
3003 pcg 1.59 srp += dirnadd;
3004    
3005     if (*stp == NOCHAR)
3006     continue;
3007    
3008 pcg 1.30 if (DELIMIT_TEXT (*stp) != w1)
3009 pcg 1.25 break;
3010 pcg 1.30 if (DELIMIT_REND (*srp) != w2)
3011 pcg 1.25 break;
3012     }
3013 pcg 1.59
3014 pcg 1.25 if ((col == bound.col) && (row != bound.row))
3015     {
3016 pcg 1.30 if (screen.tlen[ (row - (dirn == UP ? 1 : 0))] == -1)
3017 pcg 1.25 {
3018     trow = row + dirnadd;
3019     tcol = dirn == UP ? TermWin.ncol - 1 : 0;
3020 pcg 1.59
3021 pcg 1.25 if (screen.text[trow] == NULL)
3022 pcg 1.4 break;
3023 pcg 1.59
3024 pcg 1.30 stp = & (screen.text[trow][tcol]);
3025     srp = & (screen.rend[trow][tcol]);
3026 pcg 1.59
3027 pcg 1.30 if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2)
3028 pcg 1.4 break;
3029 pcg 1.59
3030 pcg 1.25 row = trow;
3031     col = tcol;
3032     continue;
3033 pcg 1.4 }
3034     }
3035 pcg 1.25 break;
3036 pcg 1.1 }
3037 pcg 1.59
3038 pcg 1.25 Old_Word_Selection_You_Die:
3039 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));
3040 pcg 1.1
3041 pcg 1.25 if (dirn == DN)
3042     col++; /* put us on one past the end */
3043 pcg 1.1
3044 pcg 1.25 /* Poke the values back in */
3045     ret->row = row - TermWin.saveLines;
3046     ret->col = col;
3047 pcg 1.1 }
3048    
3049     /* ------------------------------------------------------------------------- */
3050     /*
3051     * Extend the selection to the specified x/y pixel location
3052     * EXT: button 3 press; button 1 or 3 drag
3053     * flag == 0 ==> button 1
3054     * flag == 1 ==> button 3 press
3055     * flag == 2 ==> button 3 motion
3056     */
3057     void
3058 pcg 1.11 rxvt_term::selection_extend (int x, int y, int flag)
3059 pcg 1.1 {
3060 pcg 1.11 int col, row;
3061    
3062 pcg 1.30 col = Pixel2Col (x);
3063     row = Pixel2Row (y);
3064     MAX_IT (row, 0);
3065     MIN_IT (row, (int)TermWin.nrow - 1);
3066     MAX_IT (col, 0);
3067     MIN_IT (col, (int)TermWin.ncol);
3068 pcg 1.1
3069 pcg 1.11 /*
3070     * If we're selecting characters (single click) then we must check first
3071     * if we are at the same place as the original mark. If we are then
3072     * select nothing. Otherwise, if we're to the right of the mark, you have to
3073     * be _past_ a character for it to be selected.
3074     */
3075 pcg 1.59 if (((selection.clicks % 3) == 1) && !flag
3076     && (col == selection.mark.col
3077     && (row == selection.mark.row + TermWin.view_start)))
3078     {
3079     /* select nothing */
3080     selection.beg.row = selection.end.row = 0;
3081     selection.beg.col = selection.end.col = 0;
3082     selection.clicks = 4;
3083     want_refresh = 1;
3084     D_SELECT ((stderr, "rxvt_selection_extend () selection.clicks = 4"));
3085     return;
3086 pcg 1.1 }
3087 pcg 1.59
3088 pcg 1.11 if (selection.clicks == 4)
3089     selection.clicks = 1;
3090    
3091 pcg 1.21 selection_extend_colrow (col, row, !!flag, /* ? button 3 */
3092 pcg 1.25 flag == 1 ? 1 : 0, /* ? button press */
3093     0); /* no click change */
3094 pcg 1.1 }
3095    
3096     /* ------------------------------------------------------------------------- */
3097     /*
3098     * Extend the selection to the specified col/row
3099     */
3100     void
3101 pcg 1.21 rxvt_term::selection_extend_colrow (int32_t col, int32_t row, int button3, int buttonpress, int clickchange)
3102 pcg 1.1 {
3103 pcg 1.71 int16_t ncol = TermWin.ncol;
3104     int end_col;
3105     row_col_t pos;
3106 pcg 1.25 enum {
3107     LEFT, RIGHT
3108     } closeto = RIGHT;
3109    
3110 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));
3111     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));
3112 pcg 1.25
3113     want_refresh = 1;
3114     switch (selection.op)
3115     {
3116     case SELECTION_INIT:
3117 pcg 1.30 CLEAR_SELECTION ();
3118 pcg 1.21 selection.op = SELECTION_BEGIN;
3119 pcg 1.25 /* FALLTHROUGH */
3120     case SELECTION_BEGIN:
3121 pcg 1.21 if (row != selection.mark.row || col != selection.mark.col
3122 pcg 1.4 || (!button3 && buttonpress))
3123 pcg 1.25 selection.op = SELECTION_CONT;
3124 pcg 1.4 break;
3125 pcg 1.25 case SELECTION_DONE:
3126 pcg 1.21 selection.op = SELECTION_CONT;
3127 pcg 1.25 /* FALLTHROUGH */
3128     case SELECTION_CONT:
3129 pcg 1.4 break;
3130 pcg 1.25 case SELECTION_CLEAR:
3131 pcg 1.21 selection_start_colrow (col, row);
3132 pcg 1.25 /* FALLTHROUGH */
3133     default:
3134 pcg 1.4 return;
3135 pcg 1.1 }
3136 pcg 1.25 if (selection.beg.col == selection.end.col
3137     && selection.beg.col != selection.mark.col
3138     && selection.beg.row == selection.end.row
3139     && selection.beg.row != selection.mark.row)
3140     {
3141     selection.beg.col = selection.end.col = selection.mark.col;
3142     selection.beg.row = selection.end.row = selection.mark.row;
3143 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));
3144 pcg 1.1 }
3145    
3146 pcg 1.25 pos.col = col;
3147     pos.row = row;
3148 pcg 1.1
3149 pcg 1.25 pos.row -= TermWin.view_start; /* adjust for scroll */
3150 pcg 1.1
3151 pcg 1.25 /*
3152     * This is mainly xterm style selection with a couple of differences, mainly
3153     * in the way button3 drag extension works.
3154     * We're either doing: button1 drag; button3 press; or button3 drag
3155     * a) button1 drag : select around a midpoint/word/line - that point/word/line
3156     * is always at the left/right edge of the selection.
3157     * b) button3 press: extend/contract character/word/line at whichever edge of
3158     * the selection we are closest to.
3159     * c) button3 drag : extend/contract character/word/line - we select around
3160     * a point/word/line which is either the start or end of the selection
3161     * and it was decided by whichever point/word/line was `fixed' at the
3162     * time of the most recent button3 press
3163     */
3164     if (button3 && buttonpress)
3165 pcg 1.59 { /* button3 press */
3166 pcg 1.25 /*
3167     * first determine which edge of the selection we are closest to
3168     */
3169 pcg 1.30 if (ROWCOL_IS_BEFORE (pos, selection.beg)
3170     || (!ROWCOL_IS_AFTER (pos, selection.end)
3171 pcg 1.25 && (((pos.col - selection.beg.col)
3172     + ((pos.row - selection.beg.row) * ncol))
3173     < ((selection.end.col - pos.col)
3174     + ((selection.end.row - pos.row) * ncol)))))
3175     closeto = LEFT;
3176 pcg 1.59
3177 pcg 1.25 if (closeto == LEFT)
3178     {
3179     selection.beg.row = pos.row;
3180     selection.beg.col = pos.col;
3181     selection.mark.row = selection.end.row;
3182 pcg 1.59 selection.mark.col = selection.end.col - (selection.clicks == 2);
3183 pcg 1.25 }
3184     else
3185     {
3186     selection.end.row = pos.row;
3187     selection.end.col = pos.col;
3188     selection.mark.row = selection.beg.row;
3189     selection.mark.col = selection.beg.col;
3190     }
3191     }
3192     else
3193 pcg 1.59 { /* button1 drag or button3 drag */
3194 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, pos))
3195 pcg 1.25 {
3196     if ((selection.mark.row == selection.end.row)
3197     && (selection.mark.col == selection.end.col)
3198     && clickchange && selection.clicks == 2)
3199     selection.mark.col--;
3200 pcg 1.59
3201 pcg 1.25 selection.beg.row = pos.row;
3202     selection.beg.col = pos.col;
3203     selection.end.row = selection.mark.row;
3204 pcg 1.59 selection.end.col = selection.mark.col + (selection.clicks == 2);
3205 pcg 1.25 }
3206     else
3207     {
3208     selection.beg.row = selection.mark.row;
3209     selection.beg.col = selection.mark.col;
3210     selection.end.row = pos.row;
3211     selection.end.col = pos.col;
3212 pcg 1.4 }
3213 pcg 1.1 }
3214    
3215 pcg 1.25 if (selection.clicks == 1)
3216     {
3217     end_col = screen.tlen[selection.beg.row + TermWin.saveLines];
3218 pcg 1.59
3219 pcg 1.25 if (end_col != -1 && selection.beg.col > end_col)
3220     {
3221 pcg 1.1 #if 1
3222 pcg 1.25 selection.beg.col = ncol;
3223     #else
3224     if (selection.beg.row != selection.end.row)
3225 pcg 1.21 selection.beg.col = ncol;
3226 pcg 1.25 else
3227     selection.beg.col = selection.mark.col;
3228 pcg 1.4 #endif
3229 pcg 1.59 }
3230 pcg 1.25
3231     end_col = screen.tlen[selection.end.row + TermWin.saveLines];
3232 pcg 1.59
3233 pcg 1.25 if (end_col != -1 && selection.end.col > end_col)
3234     selection.end.col = ncol;
3235     }
3236     else if (selection.clicks == 2)
3237     {
3238 pcg 1.30 if (ROWCOL_IS_AFTER (selection.end, selection.beg))
3239 pcg 1.25 selection.end.col--;
3240 pcg 1.59
3241     selection_delimit_word (UP, & (selection.beg), & (selection.beg));
3242     selection_delimit_word (DN, & (selection.end), & (selection.end));
3243 pcg 1.25 }
3244     else if (selection.clicks == 3)
3245     {
3246 pcg 1.1 #ifndef NO_FRILLS
3247 pcg 1.25 if ((Options & Opt_tripleclickwords))
3248     {
3249 pcg 1.59 int end_row;
3250 pcg 1.1
3251 pcg 1.59 selection_delimit_word (UP, & (selection.beg), & (selection.beg));
3252     end_row = screen.tlen[selection.mark.row + TermWin.saveLines];
3253    
3254     for (end_row = selection.mark.row; end_row < TermWin.nrow; end_row++)
3255 pcg 1.25 {
3256     end_col = screen.tlen[end_row + TermWin.saveLines];
3257 pcg 1.59
3258 pcg 1.25 if (end_col != -1)
3259     {
3260     selection.end.row = end_row;
3261     selection.end.col = end_col;
3262     selection_remove_trailing_spaces ();
3263     break;
3264 pcg 1.4 }
3265     }
3266 pcg 1.25 }
3267     else
3268 pcg 1.4 #endif
3269     {
3270 pcg 1.30 if (ROWCOL_IS_AFTER (selection.mark, selection.beg))
3271 pcg 1.25 selection.mark.col++;
3272     selection.beg.col = 0;
3273     selection.end.col = ncol;
3274 pcg 1.4 }
3275     }
3276 pcg 1.59
3277 pcg 1.25 if (button3 && buttonpress)
3278 pcg 1.59 { /* mark may need to be changed */
3279 pcg 1.25 if (closeto == LEFT)
3280     {
3281     selection.mark.row = selection.end.row;
3282     selection.mark.col = selection.end.col
3283     - (selection.clicks == 2);
3284     }
3285     else
3286     {
3287     selection.mark.row = selection.beg.row;
3288     selection.mark.col = selection.beg.col;
3289 pcg 1.4 }
3290 pcg 1.1 }
3291 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));
3292 pcg 1.1 }
3293    
3294     #ifndef NO_FRILLS
3295     void
3296 pcg 1.21 rxvt_term::selection_remove_trailing_spaces ()
3297 pcg 1.1 {
3298 pcg 1.25 int32_t end_col, end_row;
3299     text_t *stp;
3300 pcg 1.1
3301 pcg 1.25 end_col = selection.end.col;
3302     end_row = selection.end.row;
3303     for ( ; end_row >= selection.beg.row; )
3304     {
3305     stp = screen.text[end_row + TermWin.saveLines];
3306     while (--end_col >= 0)
3307     {
3308     if (stp[end_col] != ' ' && stp[end_col] != '\t')
3309     break;
3310 pcg 1.4 }
3311 pcg 1.25 if (end_col >= 0
3312     || screen.tlen[end_row - 1 + TermWin.saveLines] != -1)
3313     {
3314     selection.end.col = end_col + 1;
3315     selection.end.row = end_row;
3316     break;
3317 pcg 1.4 }
3318 pcg 1.25 end_row--;
3319     end_col = TermWin.ncol;
3320     }
3321     if (selection.mark.row > selection.end.row)
3322     {
3323     selection.mark.row = selection.end.row;
3324     selection.mark.col = selection.end.col;
3325 pcg 1.1 }
3326 pcg 1.25 else if (selection.mark.row == selection.end.row
3327     && selection.mark.col > selection.end.col)
3328     selection.mark.col = selection.end.col;
3329 pcg 1.1 }
3330     #endif
3331    
3332     /* ------------------------------------------------------------------------- */
3333     /*
3334     * Double click on button 3 when already selected
3335     * EXT: button 3 double click
3336     */
3337     void
3338 pcg 1.11 rxvt_term::selection_rotate (int x, int y)
3339 pcg 1.1 {
3340 pcg 1.11 selection.clicks = selection.clicks % 3 + 1;
3341 pcg 1.30 selection_extend_colrow (Pixel2Col (x), Pixel2Row (y), 1, 0, 1);
3342 pcg 1.1 }
3343    
3344     /* ------------------------------------------------------------------------- */
3345     /*
3346     * On some systems, the Atom typedef is 64 bits wide. We need to have a type
3347     * that is exactly 32 bits wide, because a format of 64 is not allowed by
3348     * the X11 protocol.
3349     */
3350 pcg 1.18 typedef CARD32 Atom32;
3351 pcg 1.1
3352     /* ------------------------------------------------------------------------- */
3353     /*
3354     * Respond to a request for our current selection
3355     * EXT: SelectionRequest
3356     */
3357     void
3358 pcg 1.27 rxvt_term::selection_send (const XSelectionRequestEvent &rq)
3359 pcg 1.1 {
3360 pcg 1.25 XSelectionEvent ev;
3361     XTextProperty ct;
3362     XICCEncodingStyle style;
3363     Atom target;
3364    
3365     ev.type = SelectionNotify;
3366     ev.property = None;
3367 pcg 1.27 ev.display = rq.display;
3368     ev.requestor = rq.requestor;
3369     ev.selection = rq.selection;
3370     ev.target = rq.target;
3371     ev.time = rq.time;
3372 pcg 1.25
3373 pcg 1.27 if (rq.target == xa[XA_TARGETS])
3374 pcg 1.25 {
3375 pcg 1.54 Atom32 target_list[6];
3376 pcg 1.25 Atom32 *target = target_list;
3377 pcg 1.1
3378 pcg 1.25 *target++ = (Atom32) xa[XA_TARGETS];
3379 pcg 1.54 *target++ = (Atom32) xa[XA_TIMESTAMP];
3380 pcg 1.25 *target++ = (Atom32) XA_STRING;
3381     *target++ = (Atom32) xa[XA_TEXT];
3382     *target++ = (Atom32) xa[XA_COMPOUND_TEXT];
3383 pcg 1.18 #if X_HAVE_UTF8_STRING
3384 pcg 1.25 *target++ = (Atom32) xa[XA_UTF8_STRING];
3385 pcg 1.1 #endif
3386 pcg 1.54
3387 pcg 1.30 XChangeProperty (display->display, rq.requestor, rq.property, XA_ATOM,
3388 pcg 1.54 (8 * sizeof (target_list[0])), PropModeReplace,
3389     (unsigned char *)target_list,
3390     target - target_list);
3391 pcg 1.27 ev.property = rq.property;
3392 pcg 1.25 }
3393 pcg 1.27 else if (rq.target == xa[XA_MULTIPLE])
3394 pcg 1.25 {
3395     /* TODO: Handle MULTIPLE */
3396     }
3397 pcg 1.27 else if (rq.target == xa[XA_TIMESTAMP] && selection.text)
3398 pcg 1.25 {
3399 pcg 1.30 XChangeProperty (display->display, rq.requestor, rq.property, XA_INTEGER,
3400 pcg 1.66 (8 * sizeof (Time)), PropModeReplace,
3401     (unsigned char *)&selection_time, 1);
3402 pcg 1.27 ev.property = rq.property;
3403 pcg 1.25 }
3404 pcg 1.27 else if (rq.target == XA_STRING
3405     || rq.target == xa[XA_TEXT]
3406     || rq.target == xa[XA_COMPOUND_TEXT]
3407     || rq.target == xa[XA_UTF8_STRING]
3408 pcg 1.25 )
3409     {
3410     short freect = 0;
3411     int selectlen;
3412 pcg 1.54 wchar_t *cl;
3413 pcg 1.25
3414 pcg 1.27 target = rq.target;
3415 pcg 1.25
3416     if (target == XA_STRING)
3417     // we actually don't do XA_STRING, but who cares, as i18n clients
3418     // will ask for another format anyways.
3419     style = XStringStyle;
3420     else if (target == xa[XA_TEXT])
3421 pcg 1.54 style = XStdICCTextStyle;
3422 pcg 1.25 else if (target == xa[XA_COMPOUND_TEXT])
3423     style = XCompoundTextStyle;
3424 pcg 1.18 #if X_HAVE_UTF8_STRING
3425 pcg 1.25 else if (target == xa[XA_UTF8_STRING])
3426     style = XUTF8StringStyle;
3427 pcg 1.1 #endif
3428 pcg 1.25 else
3429     {
3430     target = xa[XA_COMPOUND_TEXT];
3431     style = XCompoundTextStyle;
3432     }
3433 pcg 1.1
3434 pcg 1.25 if (selection.text)
3435     {
3436 pcg 1.54 cl = selection.text;
3437 pcg 1.25 selectlen = selection.len;
3438     }
3439     else
3440     {
3441 pcg 1.54 cl = L"";
3442 pcg 1.25 selectlen = 0;
3443 pcg 1.4 }
3444 pcg 1.18
3445 pcg 1.54 // Xwc doesn't handle iso-10646 in wchar_t gracefully, so maybe recode it
3446     // manually for XUTF8StringStyle.
3447     if (XwcTextListToTextProperty (display->display, &cl, 1, style, &ct) >= 0)
3448 pcg 1.25 freect = 1;
3449     else
3450     {
3451     /* if we failed to convert then send it raw */
3452     ct.value = (unsigned char *)cl;
3453     ct.nitems = selectlen;
3454     }
3455 pcg 1.18
3456 pcg 1.27 XChangeProperty (display->display, rq.requestor, rq.property,
3457     target, 8, PropModeReplace,
3458     ct.value, (int)ct.nitems);
3459     ev.property = rq.property;
3460 pcg 1.18
3461 pcg 1.25 if (freect)
3462     XFree (ct.value);
3463 pcg 1.1 }
3464 pcg 1.54
3465 pcg 1.27 XSendEvent (display->display, rq.requestor, False, 0L, (XEvent *)&ev);
3466 pcg 1.1 }
3467    
3468     /* ------------------------------------------------------------------------- *
3469     * MOUSE ROUTINES *
3470     * ------------------------------------------------------------------------- */
3471    
3472     /*
3473     * return col/row values corresponding to x/y pixel values
3474     */
3475     void
3476 pcg 1.11 rxvt_term::pixel_position (int *x, int *y)
3477 pcg 1.1 {
3478 pcg 1.30 *x = Pixel2Col (*x);
3479     /* MAX_IT (*x, 0); MIN_IT (*x, (int)TermWin.ncol - 1); */
3480     *y = Pixel2Row (*y);
3481     /* MAX_IT (*y, 0); MIN_IT (*y, (int)TermWin.nrow - 1); */
3482 pcg 1.1 }
3483 pcg 1.11
3484 pcg 1.1 /* ------------------------------------------------------------------------- */
3485     #ifdef USE_XIM
3486     void
3487 pcg 1.29 rxvt_term::im_set_position (XPoint *pos)
3488 pcg 1.1 {
3489 pcg 1.11 XWindowAttributes xwa;
3490 pcg 1.1
3491 pcg 1.27 XGetWindowAttributes (display->display, TermWin.vt, &xwa);
3492 pcg 1.11 pos->x = Col2Pixel (screen.cur.col) + xwa.x;
3493     pos->y = Height2Pixel ((screen.cur.row + 1)) + xwa.y - TermWin.lineSpace;
3494 pcg 1.1 }
3495 pcg 1.11
3496 pcg 1.1 #endif
3497     /* ------------------------------------------------------------------------- */