ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.74
Committed: Sun May 9 18:19:49 2004 UTC (20 years ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_0
Changes since 1.71: +28 -74 lines
Log Message:
*** empty log message ***

File Contents

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