ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.71
Committed: Thu Apr 8 20:31:45 2004 UTC (20 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_8
Changes since 1.68: +18 -14 lines
Log Message:
*** empty log message ***

File Contents

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