ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.78
Committed: Fri Jul 30 18:35:11 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_3
Changes since 1.77: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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