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