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