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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines