ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
Revision: 1.89
Committed: Fri Aug 13 22:38:57 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_6
Changes since 1.85: +27 -44 lines
Log Message:
*** empty log message ***

File Contents

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