ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.66
Committed: Sun Mar 28 02:07:08 2004 UTC (20 years, 2 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_5
Changes since 1.59: +113 -91 lines
Log Message:
*** empty log message ***

File Contents

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