ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
(Generate patch)

Comparing rxvt-unicode/src/screen.C (file contents):
Revision 1.68 by pcg, Sun Apr 4 14:35:00 2004 UTC vs.
Revision 1.237 by root, Wed Jan 18 11:07:30 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines