1 /*--------------------------------*-C-*---------------------------------*
2 * File: screen.c
3 *----------------------------------------------------------------------*
4 *
5 * All portions of code are copyright by their respective author/s.
6 * Copyright (c) 1997-2001 Geoff Wing <gcw@pobox.com>
7 * Copyright (C) 2000,2001 Teepanis Chachiyo <teepanis@physics.purdue.edu>
8 * Copyright (c) 2001 Marius Gedminas <marius.gedminas@uosis.mif.vu.lt>
9 * Copyright (c) 2003 David Hull
10 * Copyright (c) 2003 Yamanobe Kiichiro <yamky@cocoa.freemail.ne.jp>
11 * Copyright (c) 2003 Mamoru Komachi <usata@usata.org>
12 * Copyright (c) 2005 William P. Y. Hadisoeseno <williampoetra@users.sourceforge.net>
13 * Copyright (c) 2004-2005 Jingmin Zhou <jimmyzhou@users.sourceforge.net>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *----------------------------------------------------------------------*/
29 /*
30 ** $Id: screen.c,v 1.137 2005/06/24 04:26:55 cvs Exp $
31 */
32
33 #include "../config.h"
34 #define INTERN_SCREEN
35 #include "rxvt.h"
36
37
38 #ifdef DEBUG_VERBOSE
39 #define DEBUG_LEVEL 1
40 #else
41 #define DEBUG_LEVEL 0
42 #endif
43
44 #if DEBUG_LEVEL
45 #define DBG_MSG(d,x) if(d <= DEBUG_LEVEL) fprintf x
46 #else
47 #define DBG_MSG(d,x)
48 #endif
49
50
51 /* ------------------------------------------------------------------------- */
52 #ifdef MULTICHAR_SET
53 #define RESET_CHSTAT(R, P) \
54 if (PVTS((R),(P))->chstat == WBYTE) \
55 PVTS((R),(P))->chstat = SBYTE, PVTS((R),(P))->lost_multi = 1
56 #else
57 # define RESET_CHSTAT(R, P)
58 #endif
59
60 /* ------------------------------------------------------------------------- */
61 #define PROP_SIZE 16384
62
63 /* ------------------------------------------------------------------------- *
64 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
65 * ------------------------------------------------------------------------- */
66
67 /*
68 ** If hihibit scrolling on tty output, we should keep the view_start.
69 ** Otherwise, we set it to zero.
70 */
71 #define ZERO_SCROLLBACK(R, P) \
72 if (!((R)->Options & Opt_scrollTtyOutputInhibit)) \
73 (R)->vts[(P)]->view_start = 0
74
75 #define CLEAR_SELECTION(R) \
76 (R)->selection.beg.row = \
77 (R)->selection.beg.col = \
78 (R)->selection.end.row = \
79 (R)->selection.end.col = 0
80
81 #define CLEAR_ALL_SELECTION(R) \
82 (R)->selection.beg.row = \
83 (R)->selection.beg.col = \
84 (R)->selection.mark.row = \
85 (R)->selection.mark.col = \
86 (R)->selection.end.row = \
87 (R)->selection.end.col = 0
88
89 #define ROW_AND_COL_IS_AFTER(A, B, C, D) \
90 (((A) > (C)) || (((A) == (C)) && ((B) > (D))))
91 #define ROW_AND_COL_IS_BEFORE(A, B, C, D) \
92 (((A) < (C)) || (((A) == (C)) && ((B) < (D))))
93 #define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D) \
94 (((A) == (C)) && ((B) > (D)))
95 #define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D) \
96 (((A) == (C)) && ((B) >= (D)))
97 #define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D) \
98 (((A) == (C)) && ((B) < (D)))
99 #define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D) \
100 (((A) == (C)) && ((B) <= (D)))
101
102 /* these must be row_col_t */
103 #define RC_AFTER(X, Y) \
104 ROW_AND_COL_IS_AFTER((X).row, (X).col, (Y).row, (Y).col)
105 #define RC_BEFORE(X, Y) \
106 ROW_AND_COL_IS_BEFORE((X).row, (X).col, (Y).row, (Y).col)
107 #define RC_ROW_AFTER(X, Y) \
108 ROW_AND_COL_IN_ROW_AFTER((X).row, (X).col, (Y).row, (Y).col)
109 #define RC_ROW_BEFORE(X, Y) \
110 ROW_AND_COL_IN_ROW_BEFORE((X).row, (X).col, (Y).row, (Y).col)
111 #define RC_ROW_ATAFTER(X, Y) \
112 ROW_AND_COL_IN_ROW_AT_OR_AFTER((X).row, (X).col, (Y).row, (Y).col)
113 #define RC_ROW_ATBEFORE(X, Y) \
114 ROW_AND_COL_IN_ROW_AT_OR_BEFORE((X).row, (X).col, (Y).row, (Y).col)
115
116 /*
117 * CLEAR_ROWS : clear <num> rows starting from row <row>
118 * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
119 * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour
120 */
121 #define drawBuffer (PVTS(r, page)->vt)
122
123 #define CLEAR_ROWS(row, num) \
124 if (r->TermWin.mapped) \
125 rxvt_clear_area (r, page, \
126 r->TermWin.int_bwidth, Row2Pixel(row), \
127 VT_WIDTH(r), (unsigned int)Height2Pixel(num))
128
129
130 #define CLEAR_CHARS(x, y, num) \
131 if (r->TermWin.mapped) \
132 rxvt_clear_area (r, page, x, y, \
133 (unsigned int)Width2Pixel(num), \
134 (unsigned int)Height2Pixel(1))
135
136
137 #define ERASE_ROWS(row, num) \
138 rxvt_fill_rectangle (r, page, \
139 r->TermWin.int_bwidth, Row2Pixel(row), \
140 VT_WIDTH(r), (unsigned int)Height2Pixel(num))
141
142
143 #ifdef DONT_SELECT_TRAILING_SPACES
144 # define STRIP_TRAILING_SPACE(str, fence) \
145 while (str > fence && ' ' == str[-1]) \
146 str --;
147 #endif
148
149
150 /* Here are some simple macros for convenience */
151 #undef CURROW
152 #undef CURCOL
153 #undef SVLINES
154 #undef VSTART
155 #define CURROW (PSCR(r, page).cur.row)
156 #define CURCOL (PSCR(r, page).cur.col)
157 #define SVLINES (PVTS(r, page)->saveLines)
158 #define VSTART (PVTS(r, page)->view_start)
159
160
161 /*--------------------------------------------------------------------*
162 * BEGIN `INTERNAL' ROUTINE PROTOTYPES *
163 *--------------------------------------------------------------------*/
164 void rxvt_blank_line (text_t*, rend_t*, unsigned int, rend_t);
165 void rxvt_blank_screen_mem (rxvt_t*, int, text_t**, rend_t **, unsigned int, rend_t);
166 void rxvt_scr_reset_realloc (rxvt_t*, int);
167 void rxvt_scr_delete_row (rxvt_t*, int);
168 void rxvt_scr_add_row (rxvt_t*, int, unsigned int, unsigned int);
169 void inline rxvt_clear_area (rxvt_t*, int page, int x, int y, unsigned int w, unsigned int h);
170 void inline rxvt_fill_rectangle (rxvt_t*, int page, int x, int y, unsigned int w, unsigned int h);
171 void rxvt_scr_draw_string (rxvt_t* r, int page, int x, int y, char* str, int len, int drawfunc, RUINT16T fore, RUINT16T back);
172 void rxvt_scr_adjust_col (rxvt_t*, int, unsigned int);
173 void rxvt_set_font_style (rxvt_t*, int);
174 int rxvt_scr_change_view (rxvt_t*, int, RUINT16T);
175 void rxvt_scr_reverse_selection (rxvt_t*, int);
176 void rxvt_PasteIt (rxvt_t*, int, const unsigned char*, unsigned int);
177 int rxvt_selection_request_other (rxvt_t*, int, Atom, int);
178 void rxvt_selection_start_colrow (rxvt_t*, int, int, int);
179 void rxvt_selection_delimit_word (rxvt_t*, int, enum page_dirn, const row_col_t*, row_col_t*);
180 #ifdef MULTICHAR_SET
181 void rxvt_selection_adjust_kanji (rxvt_t*, int);
182 #endif
183 void rxvt_selection_extend_colrow (rxvt_t*, int, RINT32T, RINT32T, int, int, int);
184 #ifndef NO_FRILLS
185 void rxvt_selection_trim (rxvt_t*, int);
186 #endif
187 #ifdef TEXT_SHADOW
188 void rxvt_set_clipping (rxvt_t*, GC, int, int, int, int, int*, int*);
189 void rxvt_free_clipping (rxvt_t*, GC);
190 #endif
191 #ifdef XFT_SUPPORT
192 # ifndef NO_BOLDFONT
193 int rxvt_switch_bold_font (rxvt_t* r);
194 int rxvt_restore_bold_font (rxvt_t* r);
195 # endif
196 #endif /* XFT_SUPPORT */
197 /*--------------------------------------------------------------------*
198 * END `INTERNAL' ROUTINE PROTOTYPES *
199 *--------------------------------------------------------------------*/
200
201
202
203 /* ------------------------------------------------------------------------- *
204 * SCREEN `COMMON' ROUTINES *
205 * ------------------------------------------------------------------------- */
206 /* Fill part/all of a line with blanks. */
207 /* INTPROTO */
208 void
rxvt_blank_line(text_t * et,rend_t * er,unsigned int width,rend_t efs)209 rxvt_blank_line(text_t *et, rend_t *er, unsigned int width, rend_t efs)
210 {
211 MEMSET(et, ' ', (size_t)width);
212 efs &= ~RS_baseattrMask;
213 for (; width--;)
214 *er++ = efs;
215 }
216
217 /* ------------------------------------------------------------------------- */
218 /* Fill a full line with blanks - make sure it is allocated first */
219 /* INTPROTO */
220 void
rxvt_blank_screen_mem(rxvt_t * r,int page,text_t ** tp,rend_t ** rp,unsigned int row,rend_t efs)221 rxvt_blank_screen_mem(rxvt_t* r, int page, text_t **tp, rend_t **rp, unsigned int row, rend_t efs)
222 {
223 int width = r->TermWin.ncol;
224 rend_t *er;
225
226 assert ((tp[row] && rp[row]) ||
227 (tp[row] == NULL && rp[row] == NULL));
228
229 /* possible integer overflow? */
230 assert (width > 0);
231 assert (sizeof (text_t) * width > 0);
232 assert (sizeof (rend_t) * width > 0);
233
234 if (tp[row] == NULL) {
235 tp[row] = rxvt_malloc(sizeof(text_t) * width);
236 rp[row] = rxvt_malloc(sizeof(rend_t) * width);
237 }
238 MEMSET(tp[row], ' ', width);
239 efs &= ~RS_baseattrMask;
240 for (er = rp[row]; width--;)
241 *er++ = efs;
242 }
243
244
245
246 /* ------------------------------------------------------------------------- *
247 * SCREEN INITIALISATION *
248 * ------------------------------------------------------------------------- */
249 /* EXTPROTO */
250 void
rxvt_init_screen(rxvt_t * r)251 rxvt_init_screen (rxvt_t* r)
252 {
253 int p;
254 int ncol = r->TermWin.ncol;
255
256 /* first time, we don't have r->tabstop yet */
257 DBG_MSG(1, (stderr, "allocate r->tabstop as %d\n", ncol));
258 assert (ncol > 0); /* possible integer overflow? */
259 r->tabstop = rxvt_malloc(ncol * sizeof(char));
260 for (p = 0; p < ncol; p++)
261 r->tabstop[p] = (p % TABSTOP_SIZE == 0) ? 1 : 0;
262 }
263
264
265 void
rxvt_scr_alloc(rxvt_t * r,int page)266 rxvt_scr_alloc (rxvt_t* r, int page)
267 {
268 unsigned int ncol, nrow, total_rows;
269 unsigned int p, q;
270
271
272 DBG_MSG(1, (stderr, "rxvt_scr_alloc %d ()\n", page));
273 ncol = r->TermWin.ncol;
274 nrow = r->TermWin.nrow;
275 total_rows = nrow + SVLINES;
276
277 /*
278 ** First time called so just malloc everything : don't rely on
279 ** realloc
280 ** Note: this is still needed so that all the scrollback lines
281 ** are NULL
282 */
283 PVTS(r, page)->buf_text = rxvt_calloc(total_rows, sizeof(text_t*));
284 PVTS(r, page)->buf_rend = rxvt_calloc(total_rows, sizeof(rend_t*));
285
286 PVTS(r, page)->drawn_text = rxvt_calloc(nrow, sizeof(text_t*));
287 PVTS(r, page)->drawn_rend = rxvt_calloc(nrow, sizeof(rend_t*));
288
289 PSCR(r, page).text = rxvt_calloc(total_rows, sizeof(text_t*));
290 PSCR(r, page).tlen = rxvt_calloc(total_rows, sizeof(RINT16T));
291 PSCR(r, page).rend = rxvt_calloc(total_rows, sizeof(rend_t*));
292
293 #if NSCREENS
294 PVTS(r, page)->swap.text = rxvt_calloc(nrow, sizeof(text_t*));
295 PVTS(r, page)->swap.tlen = rxvt_calloc(nrow, sizeof(RINT16T));
296 PVTS(r, page)->swap.rend = rxvt_calloc(nrow, sizeof(rend_t*));
297 #endif
298
299 for (p = 0; p < nrow; p++) {
300 q = p + SVLINES;
301 rxvt_blank_screen_mem (r, page, PSCR(r, page).text,
302 PSCR(r, page).rend, q, DEFAULT_RSTYLE);
303 PSCR(r, page).tlen[q] = 0;
304 #if NSCREENS
305 rxvt_blank_screen_mem (r, page, PVTS(r, page)->swap.text,
306 PVTS(r, page)->swap.rend, p, DEFAULT_RSTYLE);
307 PVTS(r, page)->swap.tlen[p] = 0;
308 #endif
309
310 rxvt_blank_screen_mem (r, page, PVTS(r, page)->drawn_text,
311 PVTS(r, page)->drawn_rend, p, DEFAULT_RSTYLE);
312 }
313 PVTS(r, page)->nscrolled = 0; /* no saved lines */
314 PSCR(r, page).flags = Screen_DefaultFlags;
315 PSCR(r, page).cur.row = 0;
316 PSCR(r, page).cur.col = 0;
317 PSCR(r, page).charset = 0;
318 PVTS(r, page)->current_screen = PRIMARY;
319 rxvt_scr_cursor(r, page, SAVE);
320 #if NSCREENS
321 PVTS(r, page)->swap.flags = Screen_DefaultFlags;
322 PVTS(r, page)->swap.cur.row = 0;
323 PVTS(r, page)->swap.cur.col = 0;
324 PVTS(r, page)->swap.charset = 0;
325 PVTS(r, page)->current_screen = SECONDARY;
326 rxvt_scr_cursor(r, page, SAVE);
327 PVTS(r, page)->current_screen = PRIMARY;
328 #endif
329
330 PVTS(r, page)->rstyle = DEFAULT_RSTYLE;
331 PVTS(r, page)->rvideo = 0;
332 MEMSET(&(PVTS(r, page)->charsets), 'B', sizeof(PVTS(r, page)->charsets));
333 #ifdef MULTICHAR_SET
334 PVTS(r, page)->multi_byte = 0;
335 PVTS(r, page)->lost_multi = 0;
336 PVTS(r, page)->chstat = SBYTE;
337 #endif
338
339 /* Now set screen initialization flag */
340 PVTS(r, page)->init_screen = 1;
341 }
342
343
344
345 /* INTPROTO */
346 void
rxvt_scr_reset_realloc(rxvt_t * r,int page)347 rxvt_scr_reset_realloc(rxvt_t* r, int page)
348 {
349 unsigned int total_rows, nrow;
350
351
352 DBG_MSG(2, (stderr, "rxvt_scr_reset_realloc %d ()\n", page));
353 nrow = r->TermWin.nrow;
354 total_rows = nrow + SVLINES;
355
356 PSCR(r, page).text = rxvt_realloc (
357 PSCR(r, page).text, total_rows * sizeof(text_t *));
358 PSCR(r, page).tlen = rxvt_realloc (
359 PSCR(r, page).tlen, total_rows * sizeof(RINT16T));
360 PSCR(r, page).rend = rxvt_realloc (
361 PSCR(r, page).rend, total_rows * sizeof(rend_t *));
362
363 #if NSCREENS
364 PVTS(r, page)->swap.text = rxvt_realloc (
365 PVTS(r, page)->swap.text, nrow * sizeof(text_t *));
366 PVTS(r, page)->swap.tlen = rxvt_realloc (
367 PVTS(r, page)->swap.tlen , total_rows * sizeof(RINT16T));
368 PVTS(r, page)->swap.rend = rxvt_realloc (
369 PVTS(r, page)->swap.rend, nrow * sizeof(rend_t *));
370 #endif
371
372 PVTS(r, page)->buf_text = rxvt_realloc (
373 PVTS(r, page)->buf_text, total_rows * sizeof(text_t *));
374 PVTS(r, page)->buf_rend = rxvt_realloc (
375 PVTS(r, page)->buf_rend, total_rows * sizeof(rend_t *));
376
377 PVTS(r, page)->drawn_text = rxvt_realloc (
378 PVTS(r, page)->drawn_text, nrow * sizeof(text_t *));
379 PVTS(r, page)->drawn_rend = rxvt_realloc (
380 PVTS(r, page)->drawn_rend, nrow * sizeof(rend_t *));
381 }
382
383
384 /* INTPROTO */
385 void
rxvt_scr_delete_row(rxvt_t * r,int page)386 rxvt_scr_delete_row (rxvt_t* r, int page)
387 {
388 unsigned int nrow, prev_nrow;
389 unsigned int p, q;
390 register int i;
391
392
393 DBG_MSG(2, (stderr, "rxvt_scr_delete_row %d ()\n", page));
394 nrow = r->TermWin.nrow;
395 prev_nrow = PVTS(r, page)->prev_nrow;
396
397 /* delete rows */
398 i = min(PVTS(r, page)->nscrolled, prev_nrow - nrow);
399 rxvt_scroll_text(r, page, 0, (int)prev_nrow - 1, i, 1);
400
401 for (p = nrow; p < prev_nrow; p++) {
402 q = p + SVLINES;
403 if (PSCR(r, page).text[q]) {
404 assert(PSCR(r, page).rend[q]);
405 free(PSCR(r, page).text[q]);
406 PSCR(r, page).text[q] = NULL;
407 free(PSCR(r, page).rend[q]);
408 PSCR(r, page).rend[q] = NULL;
409 }
410 #if NSCREENS
411 if (PVTS(r, page)->swap.text[p]) {
412 assert(PVTS(r, page)->swap.rend[p]);
413 free(PVTS(r, page)->swap.text[p]);
414 PVTS(r, page)->swap.text[p] = NULL;
415 free(PVTS(r, page)->swap.rend[p]);
416 PVTS(r, page)->swap.rend[p] = NULL;
417 }
418 #endif
419 assert (PVTS(r, page)->drawn_text[p]);
420 assert (PVTS(r, page)->drawn_rend[p]);
421 free(PVTS(r, page)->drawn_text[p]);
422 PVTS(r, page)->drawn_text[p] = NULL;
423 free(PVTS(r, page)->drawn_rend[p]);
424 PVTS(r, page)->drawn_rend[p] = NULL;
425 }
426
427 /* we have fewer rows so fix up cursor position */
428 MIN_IT(PSCR(r, page).cur.row, (RINT32T)nrow - 1);
429 #if NSCREENS
430 MIN_IT(PVTS(r, page)->swap.cur.row, (RINT32T)nrow - 1);
431 #endif
432
433 rxvt_scr_reset_realloc (r, page); /* realloc _last_ */
434 }
435
436
437 /* INTPROTO */
438 void
rxvt_scr_add_row(rxvt_t * r,int page,unsigned int total_rows,unsigned int prev_total_rows)439 rxvt_scr_add_row (rxvt_t* r, int page, unsigned int total_rows, unsigned int prev_total_rows)
440 {
441 unsigned int nrow, prev_nrow;
442 unsigned int p;
443 register int i;
444
445
446 DBG_MSG(2, (stderr, "rxvt_scr_add_row %d ()\n", page));
447 nrow = r->TermWin.nrow;
448 prev_nrow = PVTS(r, page)->prev_nrow;
449
450 /* add rows */
451 rxvt_scr_reset_realloc(r, page); /* realloc _first_ */
452
453 i = min(PVTS(r, page)->nscrolled, nrow - prev_nrow);
454 for (p = prev_total_rows; p < total_rows; p++) {
455 PSCR(r, page).tlen[p] = 0;
456 PSCR(r, page).text[p] = NULL;
457 PSCR(r, page).rend[p] = NULL;
458 }
459
460 for (p = prev_total_rows; p < total_rows - i; p++)
461 rxvt_blank_screen_mem (r, page, PSCR(r, page).text,
462 PSCR(r, page).rend, p, DEFAULT_RSTYLE);
463
464 for (p = prev_nrow; p < nrow; p++) {
465 #if NSCREENS
466 PVTS(r, page)->swap.tlen[p] = 0;
467 PVTS(r, page)->swap.text[p] = NULL;
468 PVTS(r, page)->swap.rend[p] = NULL;
469 rxvt_blank_screen_mem (r, page, PVTS(r, page)->swap.text,
470 PVTS(r, page)->swap.rend, p, DEFAULT_RSTYLE);
471 #endif
472
473 PVTS(r, page)->drawn_text[p] = NULL;
474 PVTS(r, page)->drawn_rend[p] = NULL;
475 rxvt_blank_screen_mem (r, page, PVTS(r, page)->drawn_text,
476 PVTS(r, page)->drawn_rend, p, DEFAULT_RSTYLE);
477 }
478
479 if (i > 0) {
480 rxvt_scroll_text(r, page, 0, (int)nrow - 1, -i, 1);
481 PSCR(r, page).cur.row += i;
482 PSCR(r, page).s_cur.row += i;
483 PVTS(r, page)->nscrolled -= i;
484 }
485
486 assert(PSCR(r, page).cur.row < r->TermWin.nrow);
487 MIN_IT(PSCR(r, page).cur.row, nrow - 1);
488 #if NSCREENS
489 assert(PVTS(r, page)->swap.cur.row < r->TermWin.nrow);
490 MIN_IT(PVTS(r, page)->swap.cur.row, nrow - 1);
491 #endif
492 }
493
494
495
496 /* INTPROTO */
497 void
rxvt_scr_adjust_col(rxvt_t * r,int page,unsigned int total_rows)498 rxvt_scr_adjust_col (rxvt_t* r, int page, unsigned int total_rows)
499 {
500 unsigned int nrow, ncol, prev_ncol;
501 unsigned int p;
502
503
504 nrow = r->TermWin.nrow;
505 ncol = r->TermWin.ncol;
506 prev_ncol = PVTS(r, page)->prev_ncol;
507
508 DBG_MSG(2, (stderr, "rxvt_scr_adjust_col %d (ncol=%d, prev_ncol = %d, nrow=%d, total_row=%d)\n", page, ncol, prev_ncol, nrow, total_rows));
509
510 for (p = 0; p < total_rows; p++) {
511 if (PSCR(r, page).text[p]) {
512 PSCR(r, page).text[p] = rxvt_realloc (
513 PSCR(r, page).text[p], ncol * sizeof(text_t));
514 PSCR(r, page).rend[p] = rxvt_realloc (
515 PSCR(r, page).rend[p], ncol * sizeof(rend_t));
516 MIN_IT(PSCR(r, page).tlen[p], (RINT16T)ncol);
517 if (ncol > prev_ncol)
518 rxvt_blank_line (
519 &(PSCR(r, page).text[p][prev_ncol]),
520 &(PSCR(r, page).rend[p][prev_ncol]),
521 ncol - prev_ncol, DEFAULT_RSTYLE);
522 }
523 }
524
525 for (p = 0; p < nrow; p++) {
526 PVTS(r, page)->drawn_text[p] = rxvt_realloc (
527 PVTS(r, page)->drawn_text[p], ncol * sizeof(text_t));
528 PVTS(r, page)->drawn_rend[p] = rxvt_realloc (
529 PVTS(r, page)->drawn_rend[p], ncol * sizeof(rend_t));
530 #if NSCREENS
531 if (PVTS(r, page)->swap.text[p]) {
532 PVTS(r, page)->swap.text[p] = rxvt_realloc (
533 PVTS(r, page)->swap.text[p], ncol * sizeof(text_t));
534 PVTS(r, page)->swap.rend[p] = rxvt_realloc (
535 PVTS(r, page)->swap.rend[p], ncol * sizeof(rend_t));
536 MIN_IT(PVTS(r, page)->swap.tlen[p], (RINT16T)ncol);
537 if (ncol > prev_ncol)
538 rxvt_blank_line(
539 &(PVTS(r, page)->swap.text[p][prev_ncol]),
540 &(PVTS(r, page)->swap.rend[p][prev_ncol]),
541 ncol - prev_ncol, DEFAULT_RSTYLE);
542 }
543 #endif
544 if (ncol > prev_ncol)
545 rxvt_blank_line(
546 &(PVTS(r, page)->drawn_text[p][prev_ncol]),
547 &(PVTS(r, page)->drawn_rend[p][prev_ncol]),
548 ncol - prev_ncol, DEFAULT_RSTYLE);
549 }
550 MIN_IT(PSCR(r, page).cur.col, (RINT16T)ncol - 1);
551 #if NSCREENS
552 MIN_IT(PVTS(r, page)->swap.cur.col, (RINT16T)ncol - 1);
553 #endif
554
555
556 /*
557 ** Only reset tabstop if expanding columns, save realloc in
558 ** shrinking columns
559 */
560 if (r->tabstop && ncol > prev_ncol) {
561 DBG_MSG(1, (stderr, "expand r->tabstop to %d\n", ncol));
562 r->tabstop = rxvt_realloc(r->tabstop, ncol * sizeof(char));
563 for (p = prev_ncol; p < ncol; p++)
564 r->tabstop[p] = (p % TABSTOP_SIZE == 0) ? 1 : 0;
565 }
566 }
567
568
569
570 /* EXTPROTO */
571 void
rxvt_scr_reset(rxvt_t * r,int page)572 rxvt_scr_reset(rxvt_t* r, int page)
573 {
574 unsigned int ncol, nrow, prev_ncol, prev_nrow,
575 total_rows, prev_total_rows;
576
577
578 DBG_MSG(1,(stderr, "rxvt_scr_reset %d ()\n", page));
579
580 PVTS(r, page)->view_start = 0;
581 RESET_CHSTAT(r, page);
582 PVTS(r, page)->num_scr = 0; /* number of lines scrolled */
583
584 prev_ncol = PVTS(r, page)->prev_ncol;
585 prev_nrow = PVTS(r, page)->prev_nrow;
586 if (r->TermWin.ncol == 0)
587 r->TermWin.ncol = 80;
588 if (r->TermWin.nrow == 0)
589 r->TermWin.nrow = 24;
590 ncol = r->TermWin.ncol;
591 nrow = r->TermWin.nrow;
592 if (PVTS(r, page)->init_screen &&
593 ncol == prev_ncol && nrow == prev_nrow)
594 return;
595
596 DBG_MSG(1,(stderr, "rxvt_scr_reset %d () refresh screen\n", page));
597 r->h->want_refresh = 1;
598
599 total_rows = nrow + SVLINES;
600 prev_total_rows = prev_nrow + SVLINES;
601
602 PSCR(r, page).tscroll = 0;
603 PSCR(r, page).bscroll = nrow - 1;
604
605 if (PVTS(r, page)->init_screen == 0) {
606 /* Initialize the screen structures */
607 rxvt_scr_alloc (r, page);
608 }
609 else {
610 /* B1: resize rows */
611 if (nrow < prev_nrow) {
612 rxvt_scr_delete_row (r, page);
613 }
614 else if (nrow > prev_nrow) {
615 rxvt_scr_add_row (r, page, total_rows, prev_total_rows);
616 }
617 /* B2: resize columns */
618 if (ncol != prev_ncol) {
619 rxvt_scr_adjust_col (r, page, total_rows);
620 }
621 }
622
623 PVTS(r, page)->prev_nrow = nrow;
624 PVTS(r, page)->prev_ncol = ncol;
625
626 rxvt_tt_winsize(PVTS(r, page)->cmd_fd, r->TermWin.ncol, r->TermWin.nrow, PVTS(r, page)->cmd_pid);
627 }
628
629
630
631
632 /* ------------------------------------------------------------------------- */
633 /*
634 * Free everything. That way malloc debugging can find leakage.
635 */
636 /* EXTPROTO */
637 void
rxvt_scr_release(rxvt_t * r,int page)638 rxvt_scr_release(rxvt_t* r, int page)
639 {
640 unsigned int total_rows;
641 int i;
642
643
644 DBG_MSG(1, (stderr, "rxvt_scr_release %d ()\n", page));
645 total_rows = r->TermWin.nrow + SVLINES;
646
647 for (i = 0; i < total_rows; i++) {
648 if (PSCR(r, page).text[i]) {
649 /* then so is PSCR(r, page).rend[i] */
650 free(PSCR(r, page).text[i]);
651 PSCR(r, page).text[i] = NULL;
652 assert(PSCR(r, page).rend[i]);
653 free(PSCR(r, page).rend[i]);
654 PSCR(r, page).rend[i] = NULL;
655 }
656 }
657
658 for (i = 0; i < r->TermWin.nrow; i++) {
659 // if (PVTS(r, page)->drawn_text[i])
660 free(PVTS(r, page)->drawn_text[i]);
661 PVTS(r, page)->drawn_text[i] = NULL;
662 // if (PVTS(r, page)->drawn_rend[i])
663 free(PVTS(r, page)->drawn_rend[i]);
664 PVTS(r, page)->drawn_rend[i] = NULL;
665 #if NSCREENS
666 // if (PVTS(r, page)->swap.text[i])
667 free(PVTS(r, page)->swap.text[i]);
668 PVTS(r, page)->swap.text[i] = NULL;
669 // if (PVTS(r, page)->swap.rend[i]))
670 free(PVTS(r, page)->swap.rend[i]);
671 PVTS(r, page)->swap.rend[i] = NULL;
672 #endif
673 }
674
675 free(PSCR(r, page).text); PSCR(r, page).text = NULL;
676 free(PSCR(r, page).tlen); PSCR(r, page).tlen = NULL;
677 free(PSCR(r, page).rend); PSCR(r, page).rend = NULL;
678 free(PVTS(r, page)->drawn_text); PVTS(r, page)->drawn_text = NULL;
679 free(PVTS(r, page)->drawn_rend); PVTS(r, page)->drawn_rend = NULL;
680 #if NSCREENS
681 free(PVTS(r, page)->swap.text); PVTS(r, page)->swap.text = NULL;
682 free(PVTS(r, page)->swap.tlen); PVTS(r, page)->swap.tlen = NULL;
683 free(PVTS(r, page)->swap.rend); PVTS(r, page)->swap.rend = NULL;
684 #endif
685 free(PVTS(r, page)->buf_text); PVTS(r, page)->buf_text = NULL;
686 free(PVTS(r, page)->buf_rend); PVTS(r, page)->buf_rend = NULL;
687
688 /* next rxvt_scr_reset will be the first time initialization */
689 PVTS(r, page)->init_screen = 0;
690
691 /* clear selection if necessary */
692 if (page == r->selection.vt) {
693 rxvt_process_selectionclear (r, page);
694 }
695 }
696
697 /* ------------------------------------------------------------------------- */
698 /*
699 * Hard reset
700 */
701 /* EXTPROTO */
702 void
rxvt_scr_poweron(rxvt_t * r,int page)703 rxvt_scr_poweron(rxvt_t* r, int page)
704 {
705 DBG_MSG(1,(stderr, "rxvt_scr_poweron %d ()\n", page));
706
707 rxvt_scr_release(r, page);
708 PVTS(r, page)->prev_nrow = PVTS(r, page)->prev_ncol = 0;
709 rxvt_scr_reset(r, page);
710
711 rxvt_scr_clear(r, page);
712 rxvt_scr_refresh(r, page, SLOW_REFRESH);
713 }
714
715
716 /* ------------------------------------------------------------------------- *
717 * PROCESS SCREEN COMMANDS *
718 * ------------------------------------------------------------------------- */
719 /*
720 * Save and Restore cursor
721 * XTERM_SEQ: Save cursor : ESC 7
722 * XTERM_SEQ: Restore cursor: ESC 8
723 */
724 /* EXTPROTO */
725 void
rxvt_scr_cursor(rxvt_t * r,int page,int mode)726 rxvt_scr_cursor(rxvt_t* r, int page, int mode)
727 {
728 screen_t *s;
729
730 DBG_MSG(2,(stderr, "rxvt_scr_cursor %d (%c)\n", page, mode));
731
732 #if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
733 if (PVTS(r, page)->current_screen == SECONDARY)
734 s = &(PVTS(r, page)->swap);
735 else
736 #endif
737 s = &(PSCR(r, page));
738 switch (mode) {
739 case SAVE:
740 s->s_cur.row = s->cur.row;
741 s->s_cur.col = s->cur.col;
742 s->s_rstyle = PVTS(r, page)->rstyle;
743 s->s_charset = s->charset;
744 s->s_charset_char = PVTS(r, page)->charsets[s->charset];
745 break;
746 case RESTORE:
747 r->h->want_refresh = 1;
748 s->cur.row = s->s_cur.row;
749 s->cur.col = s->s_cur.col;
750 s->flags &= ~Screen_WrapNext;
751 PVTS(r, page)->rstyle = s->s_rstyle;
752 s->charset = s->s_charset;
753 PVTS(r, page)->charsets[s->charset] = s->s_charset_char;
754 rxvt_set_font_style(r, page);
755 break;
756 }
757 /* boundary check in case screen size changed between SAVE and RESTORE */
758 MIN_IT(s->cur.row, r->TermWin.nrow - 1);
759 MIN_IT(s->cur.col, r->TermWin.ncol - 1);
760 assert(s->cur.row >= 0);
761 assert(s->cur.col >= 0);
762 MAX_IT(s->cur.row, 0);
763 MAX_IT(s->cur.col, 0);
764 }
765
766 /* ------------------------------------------------------------------------- */
767 /*
768 * Swap between primary and secondary screens
769 * XTERM_SEQ: Primary screen : ESC [ ? 4 7 h
770 * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
771 */
772 /* EXTPROTO */
773 int
rxvt_scr_change_screen(rxvt_t * r,int page,int scrn)774 rxvt_scr_change_screen(rxvt_t* r, int page, int scrn)
775 {
776 #if NSCREENS
777 unsigned int i, offset;
778 #endif
779
780 r->h->want_refresh = 1;
781
782 DBG_MSG(1,(stderr, "rxvt_scr_change_screen %d (%d)\n", page, scrn));
783
784 VSTART = 0;
785 RESET_CHSTAT(r, page);
786
787 if (PVTS(r, page)->current_screen == scrn)
788 return PVTS(r, page)->current_screen;
789
790 rxvt_selection_check(r, page, 2); /* check for boundary cross */
791
792 SWAP_IT(PVTS(r, page)->current_screen, scrn, int);
793
794 #if NSCREENS
795 PVTS(r, page)->num_scr = 0;
796 offset = SVLINES;
797
798 for (i = PVTS(r, page)->prev_nrow; i--;) {
799 SWAP_IT(PSCR(r, page).text[i + offset],
800 PVTS(r, page)->swap.text[i], text_t *);
801 SWAP_IT(PSCR(r, page).tlen[i + offset],
802 PVTS(r, page)->swap.tlen[i], RINT16T);
803 SWAP_IT(PSCR(r, page).rend[i + offset],
804 PVTS(r, page)->swap.rend[i], rend_t *);
805 }
806 SWAP_IT(CURROW, PVTS(r, page)->swap.cur.row, RINT16T);
807 SWAP_IT(CURCOL, PVTS(r, page)->swap.cur.col, RINT16T);
808 assert (CURROW >= 0);
809 assert (CURROW < PVTS(r, page)->prev_nrow);
810 assert (CURCOL >= 0);
811 assert (CURCOL < PVTS(r, page)->prev_ncol);
812 MAX_IT(CURROW, 0);
813 MIN_IT(CURROW, (RINT32T)PVTS(r, page)->prev_nrow - 1);
814 MAX_IT(CURCOL, 0);
815 MIN_IT(CURCOL, (RINT32T)PVTS(r, page)->prev_ncol - 1);
816
817 SWAP_IT(PSCR(r, page).charset, PVTS(r, page)->swap.charset,
818 RINT16T);
819 SWAP_IT(PSCR(r, page).flags, PVTS(r, page)->swap.flags, int);
820 PSCR(r, page).flags |= Screen_VisibleCursor;
821 PVTS(r, page)->swap.flags |= Screen_VisibleCursor;
822
823 #else
824 # ifdef SCROLL_ON_NO_SECONDARY
825 if (PVTS(r, page)->current_screen == PRIMARY)
826 rxvt_scroll_text(r, page, 0, (PVTS(r, page)->prev_nrow - 1),
827 PVTS(r, page)->prev_nrow, 0);
828 # endif
829 #endif
830
831 /* Need to update tabbar buttons */
832 if (r->Options2 & Opt2_protectSecondary)
833 rxvt_tabbar_draw_buttons (r);
834
835 return scrn;
836 }
837
838 /* ------------------------------------------------------------------------- */
839 /*
840 * Change the colour for following text
841 */
842 /* EXTPROTO */
843 void
rxvt_scr_color(rxvt_t * r,int page,unsigned int color,int fgbg)844 rxvt_scr_color(rxvt_t* r, int page, unsigned int color, int fgbg)
845 {
846 color &= RS_fgMask;
847 if (Color_fg == fgbg)
848 PVTS(r, page)->rstyle=SET_FGCOLOR(PVTS(r, page)->rstyle, color);
849 else
850 PVTS(r, page)->rstyle=SET_BGCOLOR(PVTS(r, page)->rstyle, color);
851 }
852
853
854 /* ------------------------------------------------------------------------- */
855 /*
856 * Change the rendition style for following text
857 */
858 /* EXTPROTO */
859 void
rxvt_scr_rendition(rxvt_t * r,int page,int set,int style)860 rxvt_scr_rendition(rxvt_t* r, int page, int set, int style)
861 {
862 if (set)
863 PVTS(r, page)->rstyle |= style;
864 else if (style == ~RS_None)
865 PVTS(r, page)->rstyle = DEFAULT_RSTYLE | (PVTS(r, page)->rstyle & RS_fontMask);
866 else
867 PVTS(r, page)->rstyle &= ~style;
868 }
869
870 /* ------------------------------------------------------------------------- */
871 /*
872 * Scroll text between <row1> and <row2> inclusive, by <count> lines
873 * count positive ==> scroll up
874 * count negative ==> scroll down
875 * spec == 0 for normal routines
876 */
877 /* EXTPROTO */
878 int
rxvt_scroll_text(rxvt_t * r,int page,int row1,int row2,int count,int spec)879 rxvt_scroll_text(rxvt_t* r, int page, int row1, int row2, int count, int spec)
880 {
881 int i, j;
882 unsigned int nscrolled;
883
884 if (count == 0 || (row1 > row2))
885 return 0;
886
887 r->h->want_refresh = 1;
888 DBG_MSG(2,(stderr, "rxvt_scroll_text %d (%d,%d,%d,%d): %s\n", page, row1, row2, count, spec, (PVTS(r, page)->current_screen == PRIMARY) ? "Primary" : "Secondary"));
889
890 if ((count > 0) &&
891 (row1 == 0) &&
892 (PVTS(r, page)->current_screen == PRIMARY)) {
893 nscrolled = (unsigned int)PVTS(r, page)->nscrolled + (unsigned int)count;;
894 if (nscrolled > (unsigned int)SVLINES)
895 PVTS(r, page)->nscrolled = SVLINES;
896 else
897 PVTS(r, page)->nscrolled = (RUINT16T)nscrolled;
898 if ((r->Options & Opt_scrollWithBuffer) &&
899 VSTART != 0 &&
900 VSTART != SVLINES)
901 rxvt_scr_page(r, page, UP, count);
902 }
903 else if (!spec)
904 row1 += SVLINES;
905 row2 += SVLINES;
906
907 if (SEL(r).op &&
908 SEL(r).vt == page &&
909 PVTS(r, page)->current_screen == SEL(r).screen) {
910 i = SEL(r).beg.row + SVLINES;
911 j = SEL(r).end.row + SVLINES;
912 if ((i < row1 && j > row1) ||
913 (i < row2 && j > row2) ||
914 (i - count < row1 && i >= row1) ||
915 (i - count > row2 && i <= row2) ||
916 (j - count < row1 && j >= row1) ||
917 (j - count > row2 && j <= row2)) {
918 CLEAR_ALL_SELECTION(r);
919 /* XXX: too aggressive? */
920 SEL(r).op = SELECTION_CLEAR;
921 }
922 else if (j >= row1 && j <= row2) {
923 /* move selected region too */
924 SEL(r).beg.row -= count;
925 SEL(r).end.row -= count;
926 SEL(r).mark.row -= count;
927 }
928 }
929
930 /* _after_ PVTS(r, page)->nscrolled update */
931 rxvt_selection_check(r, page, 0);
932
933 PVTS(r, page)->num_scr += count;
934 j = count;
935 if (count < 0)
936 count = -count;
937 i = row2 - row1 + 1;
938 MIN_IT(count, i);
939
940 if (j > 0) {
941 /* A: scroll up */
942
943 /* A1: Copy lines that will get clobbered by the rotation */
944 for (i = 0, j = row1; i < count; i++, j++) {
945 PVTS(r, page)->buf_text[i] = PSCR(r, page).text[j];
946 PVTS(r, page)->buf_rend[i] = PSCR(r, page).rend[j];
947 }
948 /* A2: Rotate lines */
949 for (j = row1, i = j + count; i <= row2; i++, j++) {
950 PSCR(r, page).tlen[j] = PSCR(r, page).tlen[i];
951 PSCR(r, page).text[j] = PSCR(r, page).text[i];
952 PSCR(r, page).rend[j] = PSCR(r, page).rend[i];
953 }
954 j = row2 - count + 1, i = count;
955 }
956 else /* if (j < 0) */ {
957 /* B: scroll down */
958
959 /* B1: Copy lines that will get clobbered by the rotation */
960 for (i = 0, j = row2; i < count; i++, j--) {
961 PVTS(r, page)->buf_text[i] = PSCR(r, page).text[j];
962 PVTS(r, page)->buf_rend[i] = PSCR(r, page).rend[j];
963 }
964 /* B2: Rotate lines */
965 for (j = row2, i = j - count; i >= row1; i--, j--) {
966 PSCR(r, page).tlen[j] = PSCR(r, page).tlen[i];
967 PSCR(r, page).text[j] = PSCR(r, page).text[i];
968 PSCR(r, page).rend[j] = PSCR(r, page).rend[i];
969 }
970 j = row1, i = count;
971 count = -count;
972 }
973
974 /* C: Resurrect lines */
975 for (; i--; j++) {
976 PSCR(r, page).tlen[j] = 0;
977 PSCR(r, page).text[j] = PVTS(r, page)->buf_text[i];
978 PSCR(r, page).rend[j] = PVTS(r, page)->buf_rend[i];
979 if (!spec) /* line length may not equal TermWin.ncol */
980 rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
981 PSCR(r, page).rend, (unsigned int)j,
982 PVTS(r, page)->rstyle);
983 }
984
985 return count;
986 }
987
988 /* ------------------------------------------------------------------------- */
989 /*
990 * Add text given in <str> of length <len> to screen struct
991 */
992 /* EXTPROTO */
993 void
rxvt_scr_add_lines(rxvt_t * r,int page,const unsigned char * str,int nlines,int len)994 rxvt_scr_add_lines(rxvt_t* r, int page, const unsigned char *str, int nlines, int len)
995 {
996 unsigned char checksel, clearsel;
997 char c;
998 int i, row, last_col;
999 text_t *stp;
1000 rend_t *srp;
1001 struct rxvt_hidden *h = r->h;
1002
1003 if (len <= 0) /* sanity */
1004 return;
1005
1006 h->want_refresh = 1;
1007 last_col = r->TermWin.ncol;
1008
1009 DBG_MSG(2,(stderr, "rxvt_scr_add_lines %d (%d,%d)\n", page, nlines, len));
1010 ZERO_SCROLLBACK(r, page);
1011 if (nlines > 0) {
1012 nlines += (CURROW - PSCR(r, page).bscroll);
1013 if ((nlines > 0) &&
1014 (PSCR(r, page).tscroll == 0) &&
1015 (PSCR(r, page).bscroll == (r->TermWin.nrow - 1))) {
1016 /* _at least_ this many lines need to be scrolled */
1017 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1018 PSCR(r, page).bscroll, nlines, 0);
1019 CURROW -= nlines;
1020 }
1021 }
1022
1023 assert(CURCOL < last_col);
1024 assert((CURROW < r->TermWin.nrow) &&
1025 (CURROW >= -(RINT32T)PVTS(r, page)->nscrolled));
1026 MIN_IT(CURCOL, last_col - 1);
1027 MIN_IT(CURROW, (RINT32T)r->TermWin.nrow - 1);
1028 MAX_IT(CURROW, -(RINT32T)PVTS(r, page)->nscrolled);
1029
1030 row = CURROW + SVLINES;
1031
1032 checksel = (SEL(r).op && SEL(r).vt == page &&
1033 PVTS(r, page)->current_screen == SEL(r).screen) ? 1 : 0;
1034 clearsel = 0;
1035
1036 stp = PSCR(r, page).text[row];
1037 srp = PSCR(r, page).rend[row];
1038
1039 #ifdef MULTICHAR_SET
1040 if (PVTS(r, page)->lost_multi &&
1041 CURCOL > 0 &&
1042 IS_MULTI1(srp[CURCOL - 1]) &&
1043 *str != '\n' && *str != '\r' && *str != '\t')
1044 PVTS(r, page)->chstat = WBYTE;
1045 #endif
1046
1047 for (i = 0; i < len;) {
1048 c = str[i++];
1049 switch (c) {
1050 case '\t':
1051 rxvt_scr_tab(r, page, 1);
1052 continue;
1053
1054 case '\n':
1055 /* XXX: think about this */
1056 if (PSCR(r, page).tlen[row] != -1)
1057 MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1058 PSCR(r, page).flags &= ~Screen_WrapNext;
1059 if (CURROW == PSCR(r, page).bscroll)
1060 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1061 PSCR(r, page).bscroll, 1, 0);
1062 else if (CURROW < (r->TermWin.nrow - 1))
1063 row = (++CURROW) + SVLINES;
1064 stp = PSCR(r, page).text[row]; /* _must_ refresh */
1065 srp = PSCR(r, page).rend[row]; /* _must_ refresh */
1066 RESET_CHSTAT(r, page);
1067 continue;
1068
1069 case '\r':
1070 /* XXX: think about this */
1071 if (PSCR(r, page).tlen[row] != -1)
1072 MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1073 PSCR(r, page).flags &= ~Screen_WrapNext;
1074 CURCOL = 0;
1075 RESET_CHSTAT(r, page);
1076 continue;
1077
1078 default:
1079 #ifdef MULTICHAR_SET
1080 if (r->encoding_method == ENC_NOENC) {
1081 if (c == 127)
1082 continue;
1083 break;
1084 }
1085 PVTS(r, page)->rstyle &= ~RS_multiMask;
1086
1087 /* multibyte 2nd byte */
1088 if (PVTS(r, page)->chstat == WBYTE) {
1089 /* set flag of second byte in style */
1090 PVTS(r, page)->rstyle |= RS_multi2;
1091 /* switch back to single byte for next char */
1092 PVTS(r, page)->chstat = SBYTE;
1093 if ((r->encoding_method == ENC_EUCJ) &&
1094 ((char) stp[CURCOL-1] == (char) 0x8e)) {
1095 PVTS(r, page)->rstyle &= ~RS_multiMask;
1096 CURCOL --;
1097 }
1098 else
1099 /* maybe overkill, but makes it selectable */
1100 if ((r->encoding_method == ENC_EUCJ) ||
1101 (r->encoding_method == ENC_GBK) ||
1102 (r->encoding_method == ENC_GB))
1103 c |= 0x80;
1104 }
1105 /* multibyte 1st byte */
1106 else if (PVTS(r, page)->chstat == SBYTE) {
1107 if (r->encoding_method == ENC_SJIS) {
1108 if (PVTS(r, page)->multi_byte ||
1109 (((unsigned char) c >= (unsigned char) 0x81 &&
1110 (unsigned char) c <= (unsigned char) 0x9f) ||
1111 ((unsigned char) c >= (unsigned char) 0xe0 &&
1112 (unsigned char) c <= (unsigned char) 0xfc))
1113 ) {
1114 PVTS(r, page)->rstyle |= RS_multi1;
1115 PVTS(r, page)->chstat = WBYTE;
1116 }
1117 }
1118 else
1119 if (PVTS(r, page)->multi_byte || (c & 0x80)) {
1120 /* set flag of first byte in style */
1121 PVTS(r, page)->rstyle |= RS_multi1;
1122 /* switch to multiple byte for next char */
1123 PVTS(r, page)->chstat = WBYTE;
1124 /* maybe overkill, but makes selectable */
1125 if ((r->encoding_method == ENC_EUCJ) ||
1126 (r->encoding_method == ENC_GBK) ||
1127 (r->encoding_method == ENC_GB))
1128 c |= 0x80;
1129 }
1130 }
1131 else
1132 #endif
1133 if (c == 127)
1134 continue; /* yummmm..... */
1135 break;
1136 } /* switch */
1137
1138 if (checksel && /* see if we're writing within selection */
1139 !RC_BEFORE(PSCR(r, page).cur, SEL(r).beg) &&
1140 RC_BEFORE(PSCR(r, page).cur, SEL(r).end)) {
1141 checksel = 0;
1142 clearsel = 1;
1143 }
1144
1145 if (PSCR(r, page).flags & Screen_WrapNext) {
1146 PSCR(r, page).tlen[row] = -1;
1147 if (CURROW == PSCR(r, page).bscroll)
1148 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1149 PSCR(r, page).bscroll, 1, 0);
1150 else if (CURROW < (r->TermWin.nrow - 1))
1151 row = (++CURROW) + SVLINES;
1152 stp = PSCR(r, page).text[row]; /* _must_ refresh */
1153 srp = PSCR(r, page).rend[row]; /* _must_ refresh */
1154 CURCOL = 0;
1155 PSCR(r, page).flags &= ~Screen_WrapNext;
1156 }
1157
1158 if (PSCR(r, page).flags & Screen_Insert)
1159 rxvt_scr_insdel_chars(r, page, 1, INSERT);
1160
1161 #ifdef MULTICHAR_SET
1162 if (IS_MULTI1(PVTS(r, page)->rstyle) &&
1163 CURCOL > 0 &&
1164 IS_MULTI1(srp[CURCOL - 1])) {
1165 stp[CURCOL - 1] = ' ';
1166 srp[CURCOL - 1] &= ~RS_multiMask;
1167 }
1168 else if (IS_MULTI2(PVTS(r, page)->rstyle) &&
1169 CURCOL < (last_col - 1) &&
1170 IS_MULTI2(srp[CURCOL + 1])) {
1171 stp[CURCOL + 1] = ' ';
1172 srp[CURCOL + 1] &= ~RS_multiMask;
1173 }
1174 #endif
1175
1176 stp[CURCOL] = c;
1177 srp[CURCOL] = PVTS(r, page)->rstyle;
1178 if (CURCOL < (last_col - 1))
1179 CURCOL++;
1180 else {
1181 PSCR(r, page).tlen[row] = last_col;
1182 if (PSCR(r, page).flags & Screen_Autowrap)
1183 PSCR(r, page).flags |= Screen_WrapNext;
1184 }
1185 } /* for */
1186
1187 if (PSCR(r, page).tlen[row] != -1) /* XXX: think about this */
1188 MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1189
1190 /*
1191 ** If we wrote anywhere in the selected area, kill the selection
1192 ** XXX: should we kill the mark too? Possibly, but maybe that
1193 ** should be a similar check.
1194 */
1195 if (clearsel)
1196 CLEAR_SELECTION(r);
1197
1198 assert(CURROW >= 0);
1199 MAX_IT(CURROW, 0);
1200 }
1201
1202 /* ------------------------------------------------------------------------- */
1203 /*
1204 * Process Backspace. Move back the cursor back a position, wrap if have to
1205 * XTERM_SEQ: CTRL-H
1206 */
1207 /* EXTPROTO */
1208 void
rxvt_scr_backspace(rxvt_t * r,int page)1209 rxvt_scr_backspace(rxvt_t* r, int page)
1210 {
1211 RESET_CHSTAT(r, page);
1212 r->h->want_refresh = 1;
1213 if (CURCOL == 0) {
1214 if (CURROW > 0) {
1215 #ifdef TERMCAP_HAS_BW
1216 CURCOL = r->TermWin.ncol - 1;
1217 CURROW--;
1218 return;
1219 #endif
1220 }
1221 } else if ((PSCR(r, page).flags & Screen_WrapNext) == 0)
1222 rxvt_scr_gotorc(r, page, 0, -1, RELATIVE);
1223 PSCR(r, page).flags &= ~Screen_WrapNext;
1224 }
1225
1226 /* ------------------------------------------------------------------------- */
1227 /*
1228 * Process Horizontal Tab
1229 * count: +ve = forward; -ve = backwards
1230 * XTERM_SEQ: CTRL-I
1231 */
1232 /* EXTPROTO */
1233 void
rxvt_scr_tab(rxvt_t * r,int page,int count)1234 rxvt_scr_tab(rxvt_t* r, int page, int count)
1235 {
1236 int i, x;
1237
1238 DBG_MSG(3,(stderr, "rxvt_scr_tab %d (%d)\n", page, count));
1239 r->h->want_refresh = 1;
1240 RESET_CHSTAT(r, page);
1241 i = x = CURCOL;
1242 if (count == 0)
1243 return;
1244 else if (count > 0) {
1245 for (; ++i < r->TermWin.ncol; )
1246 if (r->tabstop[i]) {
1247 x = i;
1248 if (!--count)
1249 break;
1250 }
1251 if (count)
1252 x = r->TermWin.ncol - 1;
1253 }
1254 else /* if (count < 0) */ {
1255 for (; --i >= 0; )
1256 if (r->tabstop[i]) {
1257 x = i;
1258 if (!++count)
1259 break;
1260 }
1261 if (count)
1262 x = 0;
1263 }
1264 if (x != CURCOL)
1265 rxvt_scr_gotorc(r, page, 0, x, R_RELATIVE);
1266 }
1267
1268 /* ------------------------------------------------------------------------- */
1269 /*
1270 * Process DEC Back Index
1271 * XTERM_SEQ: ESC 6
1272 * Move cursor left in row. If we're at the left boundary, shift everything
1273 * in that row right. Clear left column.
1274 */
1275 #ifndef NO_FRILLS
1276 /* EXTPROTO */
1277 void
rxvt_scr_backindex(rxvt_t * r,int page)1278 rxvt_scr_backindex(rxvt_t* r, int page)
1279 {
1280 if (CURCOL > 0)
1281 rxvt_scr_gotorc(r, page, 0, -1, R_RELATIVE | C_RELATIVE);
1282 else {
1283 if (PSCR(r, page).tlen[CURROW + SVLINES] == 0)
1284 return; /* um, yeah? */
1285 rxvt_scr_insdel_chars(r, page, 1, INSERT);
1286 }
1287 }
1288 #endif
1289 /* ------------------------------------------------------------------------- */
1290 /*
1291 * Process DEC Forward Index
1292 * XTERM_SEQ: ESC 9
1293 * Move cursor right in row. If we're at the right boundary, shift everything
1294 * in that row left. Clear right column.
1295 */
1296 #ifndef NO_FRILLS
1297 /* EXTPROTO */
1298 void
rxvt_scr_forwardindex(rxvt_t * r,int page)1299 rxvt_scr_forwardindex(rxvt_t* r, int page)
1300 {
1301 int row;
1302
1303 if (CURCOL < r->TermWin.ncol - 1)
1304 rxvt_scr_gotorc(r, page, 0, 1, R_RELATIVE | C_RELATIVE);
1305 else {
1306 row = CURROW + SVLINES;
1307 if (PSCR(r, page).tlen[row] == 0)
1308 return; /* um, yeah? */
1309 else if (PSCR(r, page).tlen[row] == -1)
1310 PSCR(r, page).tlen[row] = r->TermWin.ncol;
1311 rxvt_scr_gotorc(r, page, 0, 0, R_RELATIVE);
1312 rxvt_scr_insdel_chars(r, page, 1, DELETE);
1313 rxvt_scr_gotorc(r, 0, page, r->TermWin.ncol - 1, R_RELATIVE);
1314 }
1315 }
1316 #endif
1317
1318 /* ------------------------------------------------------------------------- */
1319 /*
1320 * Goto Row/Column
1321 */
1322 /* EXTPROTO */
1323 void
rxvt_scr_gotorc(rxvt_t * r,int page,int row,int col,int relative)1324 rxvt_scr_gotorc(rxvt_t* r, int page, int row, int col, int relative)
1325 {
1326 r->h->want_refresh = 1;
1327 ZERO_SCROLLBACK(r, page);
1328 RESET_CHSTAT(r, page);
1329
1330 DBG_MSG(2,(stderr, "rxvt_scr_gotorc %d (r:%s%d,c:%s%d): from (r:%d,c:%d)\n", page, (relative & R_RELATIVE ? "+" : ""), row, (relative & C_RELATIVE ? "+" : ""), col, CURROW, CURCOL));
1331
1332 CURCOL = ((relative & C_RELATIVE) ? (CURCOL + col)
1333 : col);
1334 MAX_IT(CURCOL, 0);
1335 MIN_IT(CURCOL, (RINT32T)r->TermWin.ncol - 1);
1336
1337 PSCR(r, page).flags &= ~Screen_WrapNext;
1338 if (relative & R_RELATIVE) {
1339 if (row > 0) {
1340 if (CURROW <= PSCR(r, page).bscroll &&
1341 (CURROW + row) > PSCR(r, page).bscroll)
1342 CURROW = PSCR(r, page).bscroll;
1343 else
1344 CURROW += row;
1345 } else if (row < 0) {
1346 if (CURROW >= PSCR(r, page).tscroll &&
1347 (CURROW + row) < PSCR(r, page).tscroll)
1348 CURROW = PSCR(r, page).tscroll;
1349 else
1350 CURROW += row;
1351 }
1352 }
1353 else {
1354 if (PSCR(r, page).flags & Screen_Relative) {
1355 /* relative origin mode */
1356 CURROW = row + PSCR(r, page).tscroll;
1357 MIN_IT(CURROW, PSCR(r, page).bscroll);
1358 }
1359 else
1360 CURROW = row;
1361 }
1362 MAX_IT(CURROW, 0);
1363 MIN_IT(CURROW, (RINT32T)r->TermWin.nrow - 1);
1364 }
1365
1366 /* ------------------------------------------------------------------------- */
1367 /*
1368 * direction should be UP or DN
1369 */
1370 /* EXTPROTO */
1371 void
rxvt_scr_index(rxvt_t * r,int page,enum page_dirn direction)1372 rxvt_scr_index(rxvt_t* r, int page, enum page_dirn direction)
1373 {
1374 int dirn;
1375
1376 r->h->want_refresh = 1;
1377 dirn = ((direction == UP) ? 1 : -1);
1378 DBG_MSG(1,(stderr, "rxvt_scr_index %d (%d)\n", page, dirn));
1379
1380 ZERO_SCROLLBACK(r, page);
1381 RESET_CHSTAT(r, page);
1382
1383 PSCR(r, page).flags &= ~Screen_WrapNext;
1384 if ((CURROW == PSCR(r, page).bscroll && direction == UP) ||
1385 (CURROW == PSCR(r, page).tscroll && direction == DN))
1386 rxvt_scroll_text(r, page, PSCR(r, page).tscroll, PSCR(r, page).bscroll, dirn, 0);
1387 else
1388 CURROW += dirn;
1389 MAX_IT(CURROW, 0);
1390 MIN_IT(CURROW, (RINT32T)r->TermWin.nrow - 1);
1391 rxvt_selection_check(r, page, 0);
1392 }
1393
1394 /* ------------------------------------------------------------------------- */
1395 /*
1396 * Erase part or whole of a line
1397 * XTERM_SEQ: Clear line to right: ESC [ 0 K
1398 * XTERM_SEQ: Clear line to left : ESC [ 1 K
1399 * XTERM_SEQ: Clear whole line : ESC [ 2 K
1400 */
1401 /* EXTPROTO */
1402 void
rxvt_scr_erase_line(rxvt_t * r,int page,int mode)1403 rxvt_scr_erase_line(rxvt_t* r, int page, int mode)
1404 {
1405 unsigned int row, col, num;
1406
1407 r->h->want_refresh = 1;
1408 DBG_MSG(2,(stderr, "rxvt_scr_erase_line %d (%d) at screen row: %d\n", page, mode, CURROW));
1409 ZERO_SCROLLBACK(r, page);
1410 RESET_CHSTAT(r, page);
1411 rxvt_selection_check(r, page, 1);
1412
1413 PSCR(r, page).flags &= ~Screen_WrapNext;
1414
1415 row = SVLINES + CURROW;
1416 switch (mode) {
1417 case 0: /* erase to end of line */
1418 col = CURCOL;
1419 num = r->TermWin.ncol - col;
1420 MIN_IT(PSCR(r, page).tlen[row], (RINT16T)col);
1421 if (RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur) ||
1422 RC_ROW_ATAFTER(SEL(r).end, PSCR(r, page).cur))
1423 CLEAR_SELECTION(r);
1424 break;
1425 case 1: /* erase to beginning of line */
1426 col = 0;
1427 num = CURCOL + 1;
1428 if (RC_ROW_ATBEFORE(SEL(r).beg, PSCR(r, page).cur) ||
1429 RC_ROW_ATBEFORE(SEL(r).end, PSCR(r, page).cur))
1430 CLEAR_SELECTION(r);
1431 break;
1432 case 2: /* erase whole line */
1433 col = 0;
1434 num = r->TermWin.ncol;
1435 PSCR(r, page).tlen[row] = 0;
1436 if (SEL(r).beg.row <= CURROW && SEL(r).end.row >= CURROW)
1437 CLEAR_SELECTION(r);
1438 break;
1439 default:
1440 return;
1441 }
1442
1443 if (PSCR(r, page).text[row])
1444 rxvt_blank_line(&(PSCR(r, page).text[row][col]),
1445 &(PSCR(r, page).rend[row][col]), num, PVTS(r, page)->rstyle);
1446 else
1447 rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1448 PSCR(r, page).rend, row, PVTS(r, page)->rstyle);
1449 }
1450
1451 /* ------------------------------------------------------------------------- */
1452 /*
1453 * Erase part of whole of the screen
1454 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1455 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1456 * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1457 */
1458 /* EXTPROTO */
1459 void
rxvt_scr_erase_screen(rxvt_t * r,int page,int mode)1460 rxvt_scr_erase_screen(rxvt_t* r, int page, int mode)
1461 {
1462 int num;
1463 RINT32T row, row_offset;
1464 rend_t ren;
1465 XGCValues gcvalue;
1466
1467 r->h->want_refresh = 1;
1468 DBG_MSG(2,(stderr, "rxvt_scr_erase_screen %d (%d) at screen row: %d\n", page, mode, CURROW));
1469 ZERO_SCROLLBACK(r, page);
1470 RESET_CHSTAT(r, page);
1471 row_offset = (RINT32T)SVLINES;
1472
1473 switch (mode) {
1474 case 0: /* erase to end of screen */
1475 rxvt_selection_check(r, page, 1);
1476 rxvt_scr_erase_line(r, page, 0);
1477 row = CURROW + 1; /* possible OOB */
1478 num = r->TermWin.nrow - row;
1479 break;
1480 case 1: /* erase to beginning of screen */
1481 rxvt_selection_check(r, page, 3);
1482 rxvt_scr_erase_line(r, page, 1);
1483 row = 0;
1484 num = CURROW;
1485 break;
1486 case 2: /* erase whole screen */
1487 rxvt_selection_check(r, page, 3);
1488 row = 0;
1489 num = r->TermWin.nrow;
1490 break;
1491 default:
1492 return;
1493 }
1494 r->h->refresh_type |= REFRESH_BOUNDS;
1495 if (SEL(r).op &&
1496 SEL(r).vt == page &&
1497 PVTS(r, page)->current_screen == SEL(r).screen &&
1498 ((SEL(r).beg.row >= row && SEL(r).beg.row <= row + num) ||
1499 (SEL(r).end.row >= row && SEL(r).end.row <= row + num)))
1500 CLEAR_SELECTION(r);
1501 if (row >= r->TermWin.nrow) /* Out Of Bounds */
1502 return;
1503 MIN_IT(num, (r->TermWin.nrow - row));
1504 if (PVTS(r, page)->rstyle & (RS_RVid | RS_Uline))
1505 ren = (rend_t) ~RS_None;
1506 else if (GET_BASEBG(PVTS(r, page)->rstyle) == Color_bg) {
1507 ren = DEFAULT_RSTYLE;
1508 CLEAR_ROWS(row, num);
1509 } else {
1510 ren = (PVTS(r, page)->rstyle & (RS_fgMask | RS_bgMask));
1511 gcvalue.foreground = r->PixColors[GET_BGCOLOR(PVTS(r, page)->rstyle)];
1512 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
1513 ERASE_ROWS(row, num);
1514 gcvalue.foreground = r->PixColors[Color_fg];
1515 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
1516 }
1517 for (; num--; row++) {
1518 rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1519 PSCR(r, page).rend,
1520 (unsigned int)(row + row_offset), PVTS(r, page)->rstyle);
1521 PSCR(r, page).tlen[row + row_offset] = 0;
1522 rxvt_blank_line(PVTS(r, page)->drawn_text[row], PVTS(r, page)->drawn_rend[row],
1523 (unsigned int)r->TermWin.ncol, ren);
1524 }
1525 }
1526
1527 /* ------------------------------------------------------------------------- */
1528 /*
1529 * Fill the screen with `E's
1530 * XTERM_SEQ: Screen Alignment Test: ESC # 8
1531 */
1532 /* EXTPROTO */
1533 void
rxvt_scr_E(rxvt_t * r,int page)1534 rxvt_scr_E(rxvt_t* r, int page)
1535 {
1536 int i, j, k;
1537 rend_t *r1, fs;
1538
1539 r->h->want_refresh = 1;
1540 r->h->num_scr_allow = 0;
1541 ZERO_SCROLLBACK(r, page);
1542 RESET_CHSTAT(r, page);
1543 rxvt_selection_check(r, page, 3);
1544
1545 fs = PVTS(r, page)->rstyle;
1546 for (k = SVLINES, i = r->TermWin.nrow; i--; k++) {
1547 PSCR(r, page).tlen[k] = r->TermWin.ncol; /* make the `E's selectable */
1548 MEMSET(PSCR(r, page).text[k], 'E', r->TermWin.ncol);
1549 for (r1 = PSCR(r, page).rend[k], j = r->TermWin.ncol; j--; )
1550 *r1++ = fs;
1551 }
1552 }
1553
1554 /* ------------------------------------------------------------------------- */
1555 /*
1556 * Insert/Delete <count> lines
1557 */
1558 /* EXTPROTO */
1559 void
rxvt_scr_insdel_lines(rxvt_t * r,int page,int count,int insdel)1560 rxvt_scr_insdel_lines(rxvt_t* r, int page, int count, int insdel)
1561 {
1562 int end;
1563
1564 ZERO_SCROLLBACK(r, page);
1565 RESET_CHSTAT(r, page);
1566 rxvt_selection_check(r, page, 1);
1567
1568 if (CURROW > PSCR(r, page).bscroll)
1569 return;
1570
1571 end = PSCR(r, page).bscroll - CURROW + 1;
1572 if (count > end) {
1573 if (insdel == DELETE)
1574 return;
1575 else if (insdel == INSERT)
1576 count = end;
1577 }
1578 PSCR(r, page).flags &= ~Screen_WrapNext;
1579
1580 rxvt_scroll_text(r, page, CURROW,
1581 PSCR(r, page).bscroll, insdel * count, 0);
1582 }
1583
1584 /* ------------------------------------------------------------------------- */
1585 /*
1586 * Insert/Delete <count> characters from the current position
1587 */
1588 /* EXTPROTO */
1589 void
rxvt_scr_insdel_chars(rxvt_t * r,int page,int count,int insdel)1590 rxvt_scr_insdel_chars(rxvt_t* r, int page, int count, int insdel)
1591 {
1592 int col, row;
1593 rend_t tr;
1594 text_t* stp;
1595 rend_t* srp;
1596 RINT16T* slp;
1597
1598 r->h->want_refresh = 1;
1599 ZERO_SCROLLBACK(r, page);
1600 #if 0
1601 RESET_CHSTAT(r, page);
1602 #endif
1603 if (count <= 0)
1604 return;
1605
1606 rxvt_selection_check(r, page, 1);
1607 MIN_IT(count, (r->TermWin.ncol - CURCOL));
1608
1609 row = CURROW + SVLINES;
1610 PSCR(r, page).flags &= ~Screen_WrapNext;
1611
1612 stp = PSCR(r, page).text[row];
1613 srp = PSCR(r, page).rend[row];
1614 slp = &(PSCR(r, page).tlen[row]);
1615 switch (insdel) {
1616 case INSERT:
1617 for (col = r->TermWin.ncol - 1; (col - count) >= CURCOL; col--) {
1618 stp[col] = stp[col - count];
1619 srp[col] = srp[col - count];
1620 }
1621 if (*slp != -1) {
1622 *slp += count;
1623 MIN_IT(*slp, r->TermWin.ncol);
1624 }
1625 if (SEL(r).op &&
1626 SEL(r).vt == page &&
1627 PVTS(r, page)->current_screen == SEL(r).screen &&
1628 RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)) {
1629 if (SEL(r).end.row != CURROW ||
1630 (SEL(r).end.col + count >= r->TermWin.ncol))
1631 CLEAR_SELECTION(r);
1632 else { /* shift selection */
1633 SEL(r).beg.col += count;
1634 SEL(r).mark.col += count; /* XXX: yes? */
1635 SEL(r).end.col += count;
1636 }
1637 }
1638 rxvt_blank_line(&(stp[CURCOL]),
1639 &(srp[CURCOL]),
1640 (unsigned int)count, PVTS(r, page)->rstyle);
1641 break;
1642
1643 case ERASE:
1644 CURCOL += count; /* don't worry if > r->TermWin.ncol */
1645 rxvt_selection_check(r, page, 1);
1646 CURCOL -= count;
1647 rxvt_blank_line(&(stp[CURCOL]),
1648 &(srp[CURCOL]),
1649 (unsigned int)count, PVTS(r, page)->rstyle);
1650 break;
1651
1652 case DELETE:
1653 tr = srp[r->TermWin.ncol - 1]
1654 & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1655 for (col = CURCOL; (col + count) < r->TermWin.ncol; col++) {
1656 stp[col] = stp[col + count];
1657 srp[col] = srp[col + count];
1658 }
1659 rxvt_blank_line(&(stp[r->TermWin.ncol - count]),
1660 &(srp[r->TermWin.ncol - count]),
1661 (unsigned int)count, tr);
1662 if (*slp == -1) /* break line continuation */
1663 *slp = r->TermWin.ncol;
1664 *slp -= count;
1665 MAX_IT(*slp, 0);
1666 if (SEL(r).op &&
1667 SEL(r).vt == page &&
1668 PVTS(r, page)->current_screen == SEL(r).screen &&
1669 RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)) {
1670 if (SEL(r).end.row != CURROW ||
1671 (CURCOL >= SEL(r).beg.col - count) ||
1672 SEL(r).end.col >= r->TermWin.ncol)
1673 CLEAR_SELECTION(r);
1674 else {
1675 /* shift selection */
1676 SEL(r).beg.col -= count;
1677 SEL(r).mark.col -= count; /* XXX: yes? */
1678 SEL(r).end.col -= count;
1679 }
1680 }
1681 break;
1682 }
1683 #if 0
1684 if (IS_MULTI2(srp[0])) {
1685 srp[0] &= ~RS_multiMask;
1686 stp[0] = ' ';
1687 }
1688 if (IS_MULTI1(srp[r->TermWin.ncol - 1])) {
1689 srp[r->TermWin.ncol - 1] &= ~RS_multiMask;
1690 stp[r->TermWin.ncol - 1] = ' ';
1691 }
1692 #endif
1693 }
1694
1695 /* ------------------------------------------------------------------------- */
1696 /*
1697 * Set the scrolling region
1698 * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1699 */
1700 /* EXTPROTO */
1701 void
rxvt_scr_scroll_region(rxvt_t * r,int page,int top,int bot)1702 rxvt_scr_scroll_region(rxvt_t* r, int page, int top, int bot)
1703 {
1704 MAX_IT(top, 0);
1705 MIN_IT(bot, (int)r->TermWin.nrow - 1);
1706 if (top > bot)
1707 return;
1708 PSCR(r, page).tscroll = top;
1709 PSCR(r, page).bscroll = bot;
1710 rxvt_scr_gotorc(r, page, 0, 0, 0);
1711 }
1712
1713 /* ------------------------------------------------------------------------- */
1714 /*
1715 * Make the cursor visible/invisible
1716 * XTERM_SEQ: Make cursor visible : ESC [ ? 25 h
1717 * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1718 */
1719 /* EXTPROTO */
1720 void
rxvt_scr_cursor_visible(rxvt_t * r,int page,int mode)1721 rxvt_scr_cursor_visible(rxvt_t* r, int page, int mode)
1722 {
1723 r->h->want_refresh = 1;
1724 if (mode)
1725 PSCR(r, page).flags |= Screen_VisibleCursor;
1726 else
1727 PSCR(r, page).flags &= ~Screen_VisibleCursor;
1728 }
1729
1730 /* ------------------------------------------------------------------------- */
1731 /*
1732 * Set/unset automatic wrapping
1733 * XTERM_SEQ: Set Wraparound : ESC [ ? 7 h
1734 * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1735 */
1736 /* EXTPROTO */
1737 void
rxvt_scr_autowrap(rxvt_t * r,int page,int mode)1738 rxvt_scr_autowrap(rxvt_t* r, int page, int mode)
1739 {
1740 if (mode)
1741 PSCR(r, page).flags |= Screen_Autowrap;
1742 else
1743 PSCR(r, page).flags &= ~(Screen_Autowrap | Screen_WrapNext);
1744 }
1745
1746 /* ------------------------------------------------------------------------- */
1747 /*
1748 * Set/unset margin origin mode
1749 * Absolute mode: line numbers are counted relative to top margin of screen
1750 * and the cursor can be moved outside the scrolling region.
1751 * Relative mode: line numbers are relative to top margin of scrolling region
1752 * and the cursor cannot be moved outside.
1753 * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1754 * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1755 */
1756 /* EXTPROTO */
1757 void
rxvt_scr_relative_origin(rxvt_t * r,int page,int mode)1758 rxvt_scr_relative_origin(rxvt_t* r, int page, int mode)
1759 {
1760 if (mode)
1761 PSCR(r, page).flags |= Screen_Relative;
1762 else
1763 PSCR(r, page).flags &= ~Screen_Relative;
1764 rxvt_scr_gotorc(r, page, 0, 0, 0);
1765 }
1766
1767 /* ------------------------------------------------------------------------- */
1768 /*
1769 * Set insert/replace mode
1770 * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1771 * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1772 */
1773 /* EXTPROTO */
1774 void
rxvt_scr_insert_mode(rxvt_t * r,int page,int mode)1775 rxvt_scr_insert_mode(rxvt_t* r, int page, int mode)
1776 {
1777 if (mode)
1778 PSCR(r, page).flags |= Screen_Insert;
1779 else
1780 PSCR(r, page).flags &= ~Screen_Insert;
1781 }
1782
1783 /* ------------------------------------------------------------------------- */
1784 /*
1785 * Set/Unset tabs
1786 * XTERM_SEQ: Set tab at current column : ESC H
1787 * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1788 * XTERM_SEQ: Clear all tabs : ESC [ 3 g
1789 */
1790 /* EXTPROTO */
1791 void
rxvt_scr_set_tab(rxvt_t * r,int page,int mode)1792 rxvt_scr_set_tab(rxvt_t* r, int page, int mode)
1793 {
1794 if (mode < 0)
1795 MEMSET(r->tabstop, 0, r->TermWin.ncol * sizeof(char));
1796 else if (PSCR(r, page).cur.col < r->TermWin.ncol)
1797 r->tabstop[PSCR(r, page).cur.col] = (mode ? 1 : 0);
1798 }
1799
1800 /* ------------------------------------------------------------------------- */
1801 /*
1802 * Set reverse/normal video
1803 * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1804 * XTERM_SEQ: Normal video : ESC [ ? 5 l
1805 */
1806 /* EXTPROTO */
1807 void
rxvt_scr_rvideo_mode(rxvt_t * r,int page,int mode)1808 rxvt_scr_rvideo_mode(rxvt_t* r, int page, int mode)
1809 {
1810 if (PVTS(r, page)->rvideo != mode) {
1811 PVTS(r, page)->rvideo = mode;
1812 SWAP_IT(r->PixColors[Color_fg], r->PixColors[Color_bg],
1813 unsigned long);
1814 #if defined(BACKGROUND_IMAGE)
1815 if (PVTS(r, page)->bg.pixmap == None)
1816 #endif
1817 #if defined(TRANSPARENT)
1818 if (!(r->Options & Opt_transparent) ||
1819 r->h->am_transparent == 0)
1820 #endif
1821 XSetWindowBackground(r->Xdisplay, PVTS(r, page)->vt,
1822 r->PixColors[Color_bg]);
1823
1824 XSetForeground (r->Xdisplay, r->TermWin.gc, r->PixColors[Color_fg]);
1825 XSetBackground (r->Xdisplay, r->TermWin.gc, r->PixColors[Color_bg]);
1826 rxvt_scr_clear(r, page);
1827 rxvt_scr_touch(r, page, True);
1828 }
1829 }
1830
1831 /* ------------------------------------------------------------------------- */
1832 /*
1833 * Report current cursor position
1834 * XTERM_SEQ: Report position: ESC [ 6 n
1835 */
1836 /* EXTPROTO */
1837 void
rxvt_scr_report_position(rxvt_t * r,int page)1838 rxvt_scr_report_position(rxvt_t* r, int page)
1839 {
1840 rxvt_tt_printf(r, page, "\033[%d;%dR", CURROW + 1, CURCOL + 1);
1841 }
1842
1843 /* ------------------------------------------------------------------------- *
1844 * FONTS *
1845 * ------------------------------------------------------------------------- */
1846
1847 /*
1848 * Set font style
1849 */
1850 /* INTPROTO */
1851 void
rxvt_set_font_style(rxvt_t * r,int page)1852 rxvt_set_font_style(rxvt_t *r, int page)
1853 {
1854 PVTS(r, page)->rstyle &= ~RS_fontMask;
1855 switch (PVTS(r, page)->charsets[PSCR(r, page).charset]) {
1856 case '0': /* DEC Special Character & Line Drawing Set */
1857 PVTS(r, page)->rstyle |= RS_acsFont;
1858 break;
1859 case 'A': /* United Kingdom (UK) */
1860 PVTS(r, page)->rstyle |= RS_ukFont;
1861 break;
1862 case 'B': /* United States (USASCII) */
1863 break;
1864 case '<': /* Multinational character set */
1865 break;
1866 case '5': /* Finnish character set */
1867 break;
1868 case 'C': /* Finnish character set */
1869 break;
1870 case 'K': /* German character set */
1871 break;
1872 }
1873 }
1874
1875 /* ------------------------------------------------------------------------- */
1876 /*
1877 * Choose a font
1878 * XTERM_SEQ: Invoke G0 character set: CTRL-O
1879 * XTERM_SEQ: Invoke G1 character set: CTRL-N
1880 * XTERM_SEQ: Invoke G2 character set: ESC N
1881 * XTERM_SEQ: Invoke G3 character set: ESC O
1882 */
1883 /* EXTPROTO */
1884 void
rxvt_scr_charset_choose(rxvt_t * r,int page,int set)1885 rxvt_scr_charset_choose(rxvt_t* r, int page, int set)
1886 {
1887 PSCR(r, page).charset = set;
1888 rxvt_set_font_style(r, page);
1889 }
1890
1891 /* ------------------------------------------------------------------------- */
1892 /*
1893 * Set a font
1894 * XTERM_SEQ: Set G0 character set: ESC ( <C>
1895 * XTERM_SEQ: Set G1 character set: ESC ) <C>
1896 * XTERM_SEQ: Set G2 character set: ESC * <C>
1897 * XTERM_SEQ: Set G3 character set: ESC + <C>
1898 * See set_font_style for possible values for <C>
1899 */
1900 /* EXTPROTO */
1901 void
rxvt_scr_charset_set(rxvt_t * r,int page,int set,unsigned int ch)1902 rxvt_scr_charset_set(rxvt_t* r, int page, int set, unsigned int ch)
1903 {
1904 #ifdef MULTICHAR_SET
1905 PVTS(r, page)->multi_byte = !!(set < 0);
1906 set = abs(set);
1907 #endif
1908 PVTS(r, page)->charsets[set] = (unsigned char)ch;
1909 rxvt_set_font_style(r, page);
1910 }
1911
1912 /* ------------------------------------------------------------------------- *
1913 * MAJOR SCREEN MANIPULATION *
1914 * ------------------------------------------------------------------------- */
1915
1916 /*
1917 * Refresh an area
1918 */
1919 enum {
1920 PART_BEG = 0,
1921 PART_END,
1922 RC_COUNT
1923 };
1924
1925 /* EXTPROTO */
1926 void
rxvt_scr_expose(rxvt_t * r,int page,int x,int y,int width,int height,Bool refresh)1927 rxvt_scr_expose(rxvt_t* r, int page, int x, int y, int width, int height, Bool refresh)
1928 {
1929 int i;
1930 row_col_t rc[RC_COUNT];
1931
1932 if (PVTS(r, page)->drawn_text == NULL) /* sanity check */
1933 return;
1934
1935 x = max(x, (int)r->TermWin.int_bwidth);
1936 x = min(x, (int)r->szHint.width);
1937 y = max(y, (int)r->TermWin.int_bwidth);
1938 y = min(y, (int)r->szHint.height);
1939
1940 /* round down */
1941 rc[PART_BEG].col = Pixel2Col(x);
1942 rc[PART_BEG].row = Pixel2Row(y);
1943 /* round up */
1944 rc[PART_END].col = Pixel2Width(x + width + r->TermWin.fwidth - 1);
1945 rc[PART_END].row = Pixel2Row(y + height + r->TermWin.fheight - 1);
1946
1947 /* sanity checks */
1948 for (i = PART_BEG; i < RC_COUNT; i++) {
1949 MIN_IT(rc[i].col, r->TermWin.ncol - 1);
1950 MIN_IT(rc[i].row, r->TermWin.nrow - 1);
1951 }
1952
1953 DBG_MSG(2,(stderr, "rxvt_scr_expose %d (x:%d, y:%d, w:%d, h:%d) area (c:%d,r:%d)-(c:%d,r:%d)\n", page, x, y, width, height, rc[PART_BEG].col, rc[PART_BEG].row, rc[PART_END].col, rc[PART_END].row));
1954
1955 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++) {
1956 register int j = rc[PART_BEG].col;
1957 register int k = rc[PART_END].col - rc[PART_BEG].col + 1;
1958 DBG_MSG(2,(stderr, " memset drawn_text[%d][%d], len=%d\n", i, j, k));
1959 MEMSET(&(PVTS(r, page)->drawn_text[i][j]), 0, k);
1960 }
1961
1962 if (refresh)
1963 rxvt_scr_refresh(r, page, SLOW_REFRESH | REFRESH_BOUNDS);
1964 }
1965
1966 /* ------------------------------------------------------------------------- */
1967 /*
1968 * Refresh the entire screen
1969 */
1970 /* EXTPROTO */
1971 void
rxvt_scr_touch(rxvt_t * r,int page,Bool refresh)1972 rxvt_scr_touch(rxvt_t* r, int page, Bool refresh)
1973 {
1974 rxvt_scr_expose(r, page, 0, 0, VT_WIDTH(r), VT_HEIGHT(r), refresh);
1975 }
1976
1977 /* ------------------------------------------------------------------------- */
1978 /*
1979 * Move the display so that the line represented by scrollbar value Y is at
1980 * the top of the screen
1981 */
1982 /* EXTPROTO */
1983 int
rxvt_scr_move_to(rxvt_t * r,int page,int y,int len)1984 rxvt_scr_move_to(rxvt_t* r, int page, int y, int len)
1985 {
1986 long p = 0;
1987 RUINT16T oldviewstart;
1988
1989 oldviewstart = VSTART;
1990 if (y < len) {
1991 p = (r->TermWin.nrow + PVTS(r, page)->nscrolled) * (len - y) / len;
1992 p -= (long)(r->TermWin.nrow - 1);
1993 p = max(p, 0);
1994 }
1995 VSTART = (RUINT16T)min(p, PVTS(r, page)->nscrolled);
1996 DBG_MSG(2,(stderr, "rxvt_scr_move_to %d (%d, %d) view_start:%d\n", page, y, len, VSTART));
1997
1998 return rxvt_scr_change_view(r, page, oldviewstart);
1999 }
2000
2001 /* ------------------------------------------------------------------------- */
2002 /*
2003 * Page the screen up/down nlines
2004 * direction should be UP or DN
2005 */
2006 /* EXTPROTO */
2007 int
rxvt_scr_page(rxvt_t * r,int page,enum page_dirn direction,int nlines)2008 rxvt_scr_page(rxvt_t* r, int page, enum page_dirn direction, int nlines)
2009 {
2010 int n;
2011 RUINT16T oldviewstart;
2012
2013 DBG_MSG(2,(stderr, "rxvt_scr_page %d (%s, %d) view_start:%d\n", page, ((direction == UP) ? "UP" : "DN"), nlines, VSTART));
2014
2015 assert((nlines >= 0) && (nlines <= r->TermWin.nrow));
2016 oldviewstart = VSTART;
2017 if (direction == UP) {
2018 n = VSTART + nlines;
2019 VSTART = min(n, PVTS(r, page)->nscrolled);
2020 }
2021 else {
2022 n = VSTART - nlines;
2023 VSTART = max(n, 0);
2024 }
2025 return rxvt_scr_change_view(r, page, oldviewstart);
2026 }
2027
2028
2029 /* INTPROTO */
2030 int
rxvt_scr_change_view(rxvt_t * r,int page,RUINT16T oldviewstart)2031 rxvt_scr_change_view(rxvt_t* r, int page, RUINT16T oldviewstart)
2032 {
2033 if (VSTART != oldviewstart) {
2034 r->h->want_refresh = 1;
2035 PVTS(r, page)->num_scr -= (VSTART - oldviewstart);
2036 }
2037 return (int)(VSTART - oldviewstart);
2038 }
2039
2040
2041 /* ------------------------------------------------------------------------- */
2042 /* EXTPROTO */
2043 void
rxvt_scr_bell(rxvt_t * r)2044 rxvt_scr_bell(rxvt_t *r)
2045 {
2046 #ifndef NO_BELL
2047
2048 #if defined(THROTTLE_BELL_MSEC) && THROTTLE_BELL_MSEC > 0
2049 /* Maximal number of bell per pre-defined time interval */
2050 static int bellcount = 0;
2051 static struct timeval tvbase = {0, 0};
2052 struct timeval tvnow = {0, 0};
2053 long tminterval;
2054
2055 if (gettimeofday (&tvnow, NULL) >= 0) {
2056 if (0 == tvbase.tv_sec && 0 == tvbase.tv_usec) {
2057 /* first time bell, try avoid integer overflow */
2058 tvbase = tvnow;
2059 tminterval = 0;
2060 }
2061 else
2062 tminterval = (tvnow.tv_sec - tvbase.tv_sec) * 1000 +
2063 (tvnow.tv_usec - tvbase.tv_usec) / 1000;
2064 if (tminterval > THROTTLE_BELL_MSEC) {
2065 tvbase = tvnow;
2066 bellcount = 1;
2067 }
2068 else if (bellcount ++ >= THROTTLE_BELL_COUNT) {
2069 return;
2070 }
2071 }
2072 #endif /* THROTTLE_BELL_MSEC && THROTTLE_BELL_MSEC > 0 */
2073
2074 if (r->h->rs[Rs_bellCommand]) {
2075 /* execute bell command */
2076 system (r->h->rs[Rs_bellCommand]);
2077 return ;
2078 }
2079
2080 # ifndef NO_MAPALERT
2081 # ifdef MAPALERT_OPTION
2082 if (r->Options & Opt_mapAlert)
2083 # endif
2084 XMapWindow(r->Xdisplay, r->TermWin.parent);
2085 # endif
2086 if (r->Options & Opt_visualBell) {
2087 /* refresh also done */
2088 rxvt_scr_rvideo_mode(r, ATAB(r), !AVTS(r)->rvideo);
2089 rxvt_scr_rvideo_mode(r, ATAB(r), !AVTS(r)->rvideo);
2090 }
2091 else
2092 XBell(r->Xdisplay, 0);
2093 #endif
2094 }
2095
2096 /* ------------------------------------------------------------------------- */
2097 /* ARGSUSED */
2098 /* EXTPROTO */
2099 void
rxvt_scr_printscreen(rxvt_t * r,int page,int fullhist)2100 rxvt_scr_printscreen(rxvt_t* r, int page, int fullhist)
2101 {
2102 #ifdef PRINTPIPE
2103 int i, r1, nrows, row_offset;
2104 text_t* t;
2105 FILE* fd;
2106
2107 if ((fd = rxvt_popen_printer(r)) == NULL)
2108 return;
2109 nrows = r->TermWin.nrow;
2110 row_offset = SVLINES;
2111 if (!fullhist)
2112 row_offset -= VSTART;
2113 else {
2114 nrows += PVTS(r, page)->nscrolled;
2115 row_offset -= PVTS(r, page)->nscrolled;
2116 }
2117
2118 for (r1 = 0; r1 < nrows; r1++) {
2119 t = PSCR(r, page).text[r1 + row_offset];
2120 for (i = r->TermWin.ncol - 1; i >= 0; i--)
2121 if (!isspace(t[i]))
2122 break;
2123 fprintf(fd, "%.*s\n", (i + 1), t);
2124 }
2125 rxvt_pclose_printer(fd);
2126 #endif
2127 }
2128
2129
2130 #ifdef TEXT_SHADOW
2131 /* INTPROTO */
2132 void
rxvt_set_clipping(rxvt_t * r,GC gc,int x,int y,int len,int mfont,int * offx,int * offy)2133 rxvt_set_clipping (rxvt_t* r, GC gc, int x, int y, int len, int mfont, int* offx, int* offy)
2134 {
2135 /* mfont is a flag whether the output string is multi-byte.
2136 ** if so, we need to extend its length twice assuming string
2137 ** is 2-byte string */
2138 register unsigned int hx = Width2Pixel(1) * len * (mfont+1);
2139 register unsigned int hy = Height2Pixel(1) * 1;
2140 XRectangle rectangle;
2141
2142
2143 assert (offx); *offx = 0;
2144 assert (offy); *offy = 0;
2145
2146 if (SHADOW_NONE == r->TermWin.shadow_mode)
2147 return; /* shortcut */
2148
2149 DBG_MSG(3, (stderr, "rxvt_set_clipping (len=%d, mfont=%d)\n", len, mfont));
2150
2151 switch (r->TermWin.shadow_mode) {
2152 case SHADOW_TOP:
2153 rectangle.x = 0; rectangle.y = -1;
2154 *offx = 0; *offy = -1;
2155 break;
2156 case SHADOW_BOTTOM:
2157 rectangle.x = 0; rectangle.y = 1;
2158 *offx = 0; *offy = 1;
2159 break;
2160 case SHADOW_LEFT:
2161 rectangle.x = -1; rectangle.y = 0;
2162 *offx = -1; *offy = 0;
2163 break;
2164 case SHADOW_RIGHT:
2165 rectangle.x = 1; rectangle.y = 0;
2166 *offx = 1; *offy = 0;
2167 break;
2168 case SHADOW_TOPLEFT:
2169 rectangle.x = -1; rectangle.y = -1;
2170 *offx = -1; *offy = -1;
2171 break;
2172 case SHADOW_TOPRIGHT:
2173 rectangle.x = 1; rectangle.y = -1;
2174 *offx = 1; *offy = -1;
2175 break;
2176 case SHADOW_BOTLEFT:
2177 rectangle.x = -1; rectangle.y = 1;
2178 *offx = -1; *offy = 1;
2179 break;
2180 case SHADOW_BOTRIGHT:
2181 rectangle.x = 1; rectangle.y = 1;
2182 *offx = 1; *offy = 1;
2183 break;
2184 default:
2185 assert (0);
2186 break;
2187 }
2188 /*
2189 rectangle.x = 0;
2190 rectangle.y = 0;
2191 */
2192 rectangle.width = hx;
2193 rectangle.height = hy;
2194
2195 XSetClipRectangles (r->Xdisplay, gc, x, y-hy, &rectangle, 1, Unsorted);
2196 }
2197
2198
2199 /* INTPROTO */
2200 void
rxvt_free_clipping(rxvt_t * r,GC gc)2201 rxvt_free_clipping (rxvt_t* r, GC gc)
2202 {
2203 XRectangle rectangle;
2204
2205 if (SHADOW_NONE == r->TermWin.shadow_mode)
2206 return; /* shortcut */
2207
2208 rectangle.x = 0;
2209 rectangle.y = 0;
2210 if (gc == r->TermWin.gc) {
2211 rectangle.width = VT_WIDTH(r);
2212 rectangle.height = VT_HEIGHT(r);
2213 }
2214 else
2215 if (gc == r->tabBar.gc) {
2216 rectangle.width = TWIN_WIDTH(r);
2217 rectangle.height = rxvt_tabbar_rheight(r);
2218 }
2219 XSetClipRectangles (r->Xdisplay, gc, 0, 0, &rectangle, 1, Unsorted);
2220 }
2221 #endif /* TEXT_SHADOW */
2222
2223
2224 void inline
rxvt_clear_area(rxvt_t * r,int page,int x,int y,unsigned int w,unsigned int h)2225 rxvt_clear_area (rxvt_t* r, int page, int x, int y, unsigned int w, unsigned int h)
2226 {
2227 /*
2228 #ifdef XFT_SUPPORT
2229 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt) {
2230 XftDrawRect (PVTS(r, page)->xftvt, &(r->XftColors[Color_bg]),
2231 x, y, w, h);
2232 }
2233 else
2234 #endif
2235 */
2236 DBG_MSG(9, (stderr, "clear area (%d, %d, %d, %d)\n", x,y,w,h));
2237 XClearArea (r->Xdisplay, drawBuffer, x, y, w, h, False);
2238 }
2239
2240
2241 void inline
rxvt_fill_rectangle(rxvt_t * r,int page,int x,int y,unsigned int w,unsigned int h)2242 rxvt_fill_rectangle (rxvt_t* r, int page, int x, int y, unsigned int w, unsigned int h)
2243 {
2244 /*
2245 #ifdef XFT_SUPPORT
2246 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt) {
2247 XftDrawRect (PVTS(r, page)->xftvt, &(r->XftColors[Color_bg]),
2248 x, y, w, h);
2249 }
2250 else
2251 #endif
2252 */
2253 DBG_MSG(9, (stderr, "fill rectangle (%d, %d, %d, %d)\n", x,y,w,h));
2254 XFillRectangle (r->Xdisplay, drawBuffer, r->TermWin.gc, x, y, w, h);
2255 }
2256
2257
2258 /* ------------------------------------------------------------------------- */
2259 /*
2260 * Refresh the screen
2261 * PVTS(r, page)->drawn_text/PVTS(r, page)->drawn_rend contain the screen information before the update.
2262 * PSCR(r, page).text/PSCR(r, page).rend contain what the screen will change to.
2263 */
2264
2265
2266 #define X11_DRAW_STRING_8 (1)
2267 #define X11_DRAW_STRING_16 (2)
2268 #define X11_DRAW_IMAGE_STRING_8 (3)
2269 #define X11_DRAW_IMAGE_STRING_16 (4)
2270 #define XFT_DRAW_STRING_8 (5)
2271 #define XFT_DRAW_STRING_16 (6)
2272 #define XFT_DRAW_STRING_32 (7)
2273 #define XFT_DRAW_STRING_UTF8 (8)
2274 #define XFT_DRAW_IMAGE_STRING_8 (9)
2275 #define XFT_DRAW_IMAGE_STRING_16 (10)
2276 #define XFT_DRAW_IMAGE_STRING_32 (11)
2277 #define XFT_DRAW_IMAGE_STRING_UTF8 (12)
2278
2279
2280 #ifdef XFT_SUPPORT
2281 /*
2282 ** len: number of characters to draw. for UTF-8 string, it is the
2283 ** number of characters * 2 of the original 16-bits string
2284 */
2285 /* EXTPROTO */
2286 void
rxvt_draw_string_xft(rxvt_t * r,XftDraw * win,GC gc,XftColor * fore,int x,int y,char * str,int len,void (* xftdraw_string)())2287 rxvt_draw_string_xft (rxvt_t* r, XftDraw* win, GC gc, XftColor* fore, int x, int y, char* str, int len, void (*xftdraw_string)())
2288 {
2289 # ifdef TEXT_SHADOW
2290 if (r->h->rs[Rs_textShadow] &&
2291 SHADOW_NONE != r->TermWin.shadow_mode) {
2292 int sx, sy;
2293
2294 DBG_MSG(3, (stderr, "handling text shadow for %s (%d)\n", str, len));
2295
2296 rxvt_set_clipping (r, gc, x, y, len,
2297 (XftDrawString8 != xftdraw_string &&
2298 XftDrawStringUtf8 != xftdraw_string), &sx, &sy);
2299 # ifdef MULTICHAR_SET
2300 if (XftDrawStringUtf8 == xftdraw_string) {
2301 xftdraw_string (win, &(r->TermWin.xftshadow),
2302 r->TermWin.xftmfont, x+sx, y+sy, str, STRLEN(str));
2303 }
2304 else
2305 # endif /* MULTICHAR_SET */
2306 {
2307 xftdraw_string (win, &(r->TermWin.xftshadow),
2308 r->TermWin.xftfont, x+sx, y+sy, str, len);
2309 }
2310 /*
2311 ** We need to free clipping area, otherwise text on
2312 ** screen may be clipped unexpectedly. Is there a better
2313 ** way to unset it, say, XUnsetClipRectangles?
2314 */
2315 rxvt_free_clipping (r, gc);
2316 }
2317 # endif /* TEXT_SHADOW */
2318
2319 # ifdef MULTICHAR_SET
2320 if (XftDrawStringUtf8 == xftdraw_string) {
2321 xftdraw_string (win, fore, r->TermWin.xftmfont, x, y,
2322 str, STRLEN(str));
2323 }
2324 else
2325 # endif /* MULTICHAR_SET */
2326 {
2327 xftdraw_string (win, fore, r->TermWin.xftfont, x, y, str, len);
2328 }
2329 }
2330 #endif
2331
2332
2333 /*
2334 ** len : number of characters in the string
2335 */
2336 /* EXTPROTO */
2337 void
rxvt_draw_string_x11(rxvt_t * r,Window win,GC gc,int x,int y,char * str,int len,int (* draw_string)())2338 rxvt_draw_string_x11 (rxvt_t* r, Window win, GC gc, int x, int y, char* str, int len, int (*draw_string)())
2339 {
2340 # ifdef TEXT_SHADOW
2341 if (r->h->rs[Rs_textShadow] &&
2342 SHADOW_NONE != r->TermWin.shadow_mode) {
2343 int sx, sy;
2344 XGCValues gcvalue;
2345
2346 DBG_MSG(3, (stderr, "handling text shadow for %s (%d)\n", str, len));
2347
2348 XGetGCValues (r->Xdisplay, gc, GCForeground, &gcvalue);
2349 XSetForeground (r->Xdisplay, gc, r->TermWin.shadow);
2350 rxvt_set_clipping (r, gc, x, y, len,
2351 (XDrawString != draw_string &&
2352 XDrawImageString != draw_string), &sx, &sy);
2353 draw_string (r->Xdisplay, win, gc, x+sx, y+sy, str, len);
2354 XSetForeground (r->Xdisplay, gc, gcvalue.foreground);
2355 /*
2356 ** We need to free clipping area, otherwise text on
2357 ** screen may be clipped unexpectedly. Is there a better
2358 ** way to unset it, say, XUnsetClipRectangles?
2359 */
2360 rxvt_free_clipping (r, gc);
2361 }
2362 # endif /* TEXT_SHADOW */
2363
2364 DBG_MSG(3, (stderr, "output entire string: %s\n", str));
2365 draw_string (r->Xdisplay, win, gc, x, y, str, len);
2366 }
2367
2368
2369 /*
2370 ** Draw the string:
2371 ** x, y: top left corner of the string
2372 ** str : actual string to draw
2373 ** len : actual number of characters in the string. It is NOT
2374 ** the byte length!
2375 ** drawfunc: function to draw string
2376 ** fore, back: color index to r->PixColors array. It is only
2377 ** used by the XFT drawing, not X11 drawing
2378 */
2379 /* INTPROTO */
2380 void
rxvt_scr_draw_string(rxvt_t * r,int page,int x,int y,char * str,int len,int drawfunc,RUINT16T fore,RUINT16T back)2381 rxvt_scr_draw_string (rxvt_t* r, int page, int x, int y, char* str, int len, int drawfunc, RUINT16T fore, RUINT16T back)
2382 {
2383 #ifdef XFT_SUPPORT
2384 int fillback = 0;
2385 int adjust;
2386 void (*xftdraw_string) () = NULL;
2387
2388 switch (drawfunc) {
2389 case XFT_DRAW_IMAGE_STRING_8:
2390 fillback = 1;
2391 case XFT_DRAW_STRING_8:
2392 xftdraw_string = XftDrawString8; break;
2393
2394 case XFT_DRAW_IMAGE_STRING_16:
2395 fillback = 1;
2396 case XFT_DRAW_STRING_16:
2397 xftdraw_string = XftDrawString16; break;
2398 }
2399
2400 /*
2401 ** adjust is a variable that records whether each character of
2402 ** the string is 8 bits or 16 bits
2403 */
2404 adjust = (XftDrawString8 == xftdraw_string) ? 0 : 1;
2405
2406 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt &&
2407 xftdraw_string) {
2408 register int loop; /* loop iteration number */
2409 register int loopitem; /* each iteration increasing # */
2410 register int i;
2411 /*
2412 ** xft_draw_string_xft should call these two parameters
2413 */
2414 register char* pstr; /* string to print */
2415 register int plen; /* string length */
2416 char* newstr;
2417 #ifdef MULTICHAR_SET
2418 # ifdef HAVE_ICONV_H
2419 char pbuf[1024]; /* buffer to save UTF-8 string */
2420 # endif
2421 #endif
2422
2423
2424 /*
2425 ** Xft does not support XDrawImageString, so we need to
2426 ** clear the background of text by ourselves
2427 */
2428 if (fillback) {
2429 XGCValues gcvalue;
2430
2431 /* save current foreground color */
2432 XGetGCValues (r->Xdisplay, r->TermWin.gc, GCForeground,
2433 &gcvalue);
2434 /* fill background rectangle using background color */
2435 XSetForeground (r->Xdisplay, r->TermWin.gc,
2436 r->PixColors[back]);
2437 rxvt_fill_rectangle (r, page, x, y,
2438 Width2Pixel(len * (1 + adjust)), Height2Pixel(1));
2439 /* restore current foreground color */
2440 XSetForeground (r->Xdisplay, r->TermWin.gc,
2441 gcvalue.background);
2442 }
2443 /* We use TermWin.xftfont->ascent here */
2444 y += r->TermWin.xftfont->ascent;
2445
2446
2447 /*
2448 ** Xft does not support XftDrawString16, so we need to
2449 ** convert the string to UTF-8. Here we reencode the
2450 ** string before conversion
2451 */
2452 # ifdef MULTICHAR_SET
2453 # ifdef HAVE_ICONV_H
2454 if (adjust && (iconv_t) -1 != r->TermWin.xfticonv) {
2455 register int j, newlen = (len << 1);
2456 switch (r->encoding_method) {
2457 case ENC_EUCJ:
2458 case ENC_GB:
2459 for (j = 0; j < newlen; j ++)
2460 str[j] |= 0x80;
2461 break;
2462 case ENC_GBK: /* need to do nothing */
2463 case ENC_BIG5: /* need to do nothing */
2464 default:
2465 break;
2466 }
2467 /* we will use utf8 routine to draw string */
2468 xftdraw_string = XftDrawStringUtf8;
2469 }
2470 # endif
2471 # endif /* MULTICHAR_SET */
2472
2473
2474 /*
2475 ** If the font is monospace, we print the entire string once,
2476 ** otherwise, print the characters one by one
2477 */
2478 if (r->TermWin.xftmono) {
2479 /* print string once for mono font */
2480 loop = 1;
2481 loopitem = len;
2482 /*
2483 ** If XftDrawString8 == xftdraw_string
2484 ** string length == character number
2485 ** If XftDrawString16 == xftdraw_string
2486 ** string length == 2 * character number, but we do
2487 ** not need to multiply loopitem by 2 because the
2488 ** XftDrawString16 takes character numbers.
2489 **
2490 ** If XftDrawStringUtf8 == xftdraw_string
2491 ** string length == 2 * character number, but we need
2492 ** to multiply loopitem by 2 because iconv need string
2493 ** length as parameter, not character number.
2494 */
2495 if (XftDrawStringUtf8 == xftdraw_string)
2496 loopitem <<= 1;
2497 DBG_MSG(3, (stderr, "output entire mono string\n"));
2498 }
2499 /*
2500 ** Non monospace font, but still we can improve the performance
2501 ** by print it once under certain conditions
2502 */
2503 # ifdef MULTICHAR_SET
2504 else
2505 if (!(r->Options2 & Opt2_xftSlowOutput) &&
2506 (XftDrawStringUtf8 == xftdraw_string) &&
2507 (r->TermWin.xftmfont->max_advance_width ==
2508 (r->TermWin.fwidth << 1))) {
2509 /* print string once for multichar string */
2510 loop = 1;
2511 /*
2512 ** If XftDrawStringUtf8 == xftdraw_string
2513 ** string length == 2 * character number, but we need
2514 ** to multiply loopitem by 2 because iconv need string
2515 ** length as parameter, not character number.
2516 */
2517 loopitem = (len << 1);
2518 DBG_MSG(3, (stderr, "output entire UTF-8 string\n"));
2519 }
2520 else
2521 if (!(r->Options2 & Opt2_xftSlowOutput) &&
2522 (XftDrawString16 == xftdraw_string) &&
2523 (r->TermWin.xftmfont->max_advance_width ==
2524 (r->TermWin.fwidth << 1))) {
2525 /* print string once for 16-bits string */
2526 loop = 1;
2527 loopitem = len;
2528 DBG_MSG(3, (stderr, "output entire 16-bits string\n"));
2529 }
2530 # endif /* MULTICHAR_SET */
2531 else
2532 if (r->TermWin.xftfnmono &&
2533 (XftDrawString8 == xftdraw_string) &&
2534 (r->TermWin.xftfont->max_advance_width ==
2535 r->TermWin.fwidth)) {
2536 /* print string once for 8-bits string */
2537 loop = 1;
2538 loopitem = len;
2539 DBG_MSG(3, (stderr, "output entire 8-bits string\n"));
2540 }
2541 else {
2542 /* print string one by one character */
2543 loop = len;
2544 loopitem = 1 + adjust;
2545 DBG_MSG(3, (stderr, "output characters one by one\n"));
2546 }
2547
2548
2549 newstr = str; /* string beginning in each iteration */
2550 for (i = 0; i < loop; i ++) {
2551 # ifdef MULTICHAR_SET
2552 # ifdef HAVE_ICONV_H
2553 if (XftDrawStringUtf8 == xftdraw_string) {
2554 /* We should convert the string to UTF-8 */
2555 char* buf = pbuf; /* always init it */
2556 int buflen = sizeof(pbuf)-1;/* always init it */
2557 int newlen = loopitem; /* always init it */
2558 char* oldstr = newstr;
2559 iconv (r->TermWin.xfticonv, (char**)(&newstr),
2560 (size_t*) &newlen, &buf, (size_t*) &buflen);
2561 *buf = (char) 0; /* set end of string */
2562 pstr = pbuf;
2563 /*
2564 ** we should use the length of original string, not
2565 ** UTF-8 string here!!!
2566 */
2567 plen = loopitem;
2568 /*
2569 ** reset newstr to old position, we will increase it
2570 ** later
2571 */
2572 newstr = oldstr;
2573 }
2574 else
2575 # endif
2576 # endif /* MULTICHAR_SET */
2577 {
2578 /* We do not need to convert the string to UTF-8 */
2579 pstr = newstr;
2580 plen = loopitem;
2581 }
2582
2583 rxvt_draw_string_xft(r, PVTS(r, page)->xftvt,
2584 r->TermWin.gc, &(r->XftColors[fore]),
2585 x, y, pstr, plen, xftdraw_string);
2586
2587 x += Width2Pixel (loopitem);
2588 newstr += loopitem; /* next string to display */
2589 }
2590 }
2591 else
2592 #endif /* XFT_SUPPORT */
2593 {
2594 int (*draw_string) ();
2595 switch (drawfunc) {
2596 case X11_DRAW_STRING_8:
2597 draw_string = XDrawString; break;
2598 case X11_DRAW_STRING_16:
2599 draw_string = XDrawString16; break;
2600 case X11_DRAW_IMAGE_STRING_8:
2601 draw_string = XDrawImageString; break;
2602 case X11_DRAW_IMAGE_STRING_16:
2603 draw_string = XDrawImageString16; break;
2604
2605 case XFT_DRAW_STRING_8: /* fall back to X11 */
2606 draw_string = XDrawString; break;
2607 case XFT_DRAW_STRING_16: /* fall back to X11 */
2608 case XFT_DRAW_STRING_32: /* fall back to X11 */
2609 case XFT_DRAW_STRING_UTF8: /* fall back to X11 */
2610 draw_string = XDrawString16; break;
2611
2612 case XFT_DRAW_IMAGE_STRING_8: /* fall back to X11 */
2613 draw_string = XDrawImageString; break;
2614 case XFT_DRAW_IMAGE_STRING_16: /* fall back to X11 */
2615 case XFT_DRAW_IMAGE_STRING_32: /* fall back to X11 */
2616 case XFT_DRAW_IMAGE_STRING_UTF8: /* fall back to X11 */
2617 draw_string = XDrawImageString16; break;
2618
2619 default:
2620 draw_string = NULL; break;
2621 }
2622
2623 /* We use TermWin.font->ascent here */
2624 y += r->TermWin.font->ascent;
2625
2626 /* Now draw the string */
2627 if (draw_string)
2628 rxvt_draw_string_x11 (r, PVTS(r, page)->vt, r->TermWin.gc,
2629 x, y, str, len, draw_string);
2630 }
2631 }
2632
2633
2634
2635 #ifdef XFT_SUPPORT
2636 # ifndef NO_BOLDFONT
2637 /* INTPROTO */
2638 int
rxvt_switch_bold_font(rxvt_t * r)2639 rxvt_switch_bold_font (rxvt_t* r)
2640 {
2641 /* bold font is not loaded */
2642 if (NULL == r->TermWin.xftbfont)
2643 return 0;
2644 /* bold font is already switched */
2645 if (r->TermWin.bf_switched)
2646 return 0;
2647 /* now switch the bold font */
2648 SWAP_IT (r->TermWin.xftfont, r->TermWin.xftbfont, XftFont*);
2649 r->TermWin.bf_switched = 1;
2650 return 1;
2651 }
2652
2653 /* INTPROTO */
2654 int
rxvt_restore_bold_font(rxvt_t * r)2655 rxvt_restore_bold_font (rxvt_t* r)
2656 {
2657 /* bold font is not loaded */
2658 if (NULL == r->TermWin.xftbfont)
2659 return 0;
2660 /* bold font is not switched */
2661 if (!r->TermWin.bf_switched)
2662 return 0;
2663 /* now restore the bold font */
2664 SWAP_IT (r->TermWin.xftfont, r->TermWin.xftbfont, XftFont*);
2665 r->TermWin.bf_switched = 0;
2666 return 1;
2667 }
2668 # endif /* NO_BOLDFONT */
2669 #endif /* XFT_SUPPORT */
2670
2671 /*
2672 #if defined (NO_BRIGHTCOLOR) || defined (VERYBOLD)
2673 # define MONO_BOLD(x) ((x) & (RS_Bold|RS_Blink))
2674 # define MONO_BOLD_FG(x, fg) MONO_BOLD(x)
2675 #else
2676 # define MONO_BOLD(x) \
2677 (((x) & (RS_Bold | RS_fgMask)) == (RS_Bold | Color_fg))
2678 # define MONO_BOLD_FG(x, fg) (((x) & RS_Bold) && (fg) == Color_fg)
2679 #endif
2680 */
2681 /* Synchronize the macros to thai.c!!! */
2682 #ifdef NO_BRIGHTCOLOR
2683 # define MONO_BOLD(x) ((x) & (RS_Bold|RS_Blink))
2684 # define MONO_BOLD_FG(x, fg) MONO_BOLD(x)
2685 #else /* NO_BRIGHTCOLOR */
2686 # define MONO_BOLD(x) \
2687 ((r->Options2 & Opt2_veryBold) ? \
2688 ((x) & (RS_Bold|RS_Blink)) : \
2689 (((x) & (RS_Bold | RS_fgMask)) == (RS_Bold | Color_fg)) \
2690 )
2691 # define MONO_BOLD_FG(x, fg) \
2692 ((r->Options2 & Opt2_veryBold) ? \
2693 MONO_BOLD(x) : \
2694 (((x) & RS_Bold) && (fg) == Color_fg) \
2695 )
2696 #endif /* NO_BRIGHTCOLOR */
2697
2698
2699 #define FONT_WIDTH(X, Y) \
2700 (X)->per_char[(Y) - (X)->min_char_or_byte2].width
2701 #define FONT_RBEAR(X, Y) \
2702 (X)->per_char[(Y) - (X)->min_char_or_byte2].rbearing
2703 #define FONT_LBEAR(X, Y) \
2704 (X)->per_char[(Y) - (X)->min_char_or_byte2].lbearing
2705 #define IS_FONT_CHAR(X, Y) \
2706 ((Y) >= (X)->min_char_or_byte2 && (Y) <= (X)->max_char_or_byte2)
2707
2708 /* EXTPROTO */
2709 void
rxvt_scr_refresh(rxvt_t * r,int page,unsigned char refresh_type)2710 rxvt_scr_refresh(rxvt_t* r, int page, unsigned char refresh_type)
2711 {
2712 unsigned char
2713 clearfirst, /* first character writes before cell */
2714 clearlast, /* last character writes beyond cell */
2715 must_clear, /* use drawfunc not image_drawfunc */
2716 #ifndef NO_BOLDFONT
2717 bfont, /* we've changed font to bold font */
2718 #endif
2719 rvid, /* reverse video this position */
2720 wbyte, /* we're in multibyte */
2721 showcursor; /* show the cursor */
2722 char morecur = 0;/* */
2723 #ifdef TTY_256COLOR
2724 RUINT16T fore, back; /* desired foreground/background */
2725 #else
2726 unsigned char
2727 fore, back; /* desired foreground/background */
2728 #endif
2729 RINT16T col, row, /* column/row we're processing */
2730 ocrow, /* old cursor row */
2731 len, wlen; /* text length screen/buffer */
2732 int i, /* tmp */
2733 row_offset; /* basic offset in screen structure */
2734 #ifndef NO_CURSORCOLOR
2735 rend_t cc1; /* store colours at cursor position(s) */
2736 # ifdef MULTICHAR_SET
2737 rend_t cc2; /* store colours at cursor position(s) */
2738 # endif
2739 #endif
2740 XGCValues gcvalue; /* Graphics Context values */
2741 XFontStruct* wf; /* font structure */
2742 rend_t* drp; /* drawn_rend pointer */
2743 rend_t* srp; /* screen-rend-pointer */
2744 text_t* dtp; /* drawn-text pointer */
2745 text_t* stp; /* screen-text-pointer */
2746 char* buffer; /* local copy of r->h->buffer */
2747 #ifdef THAI
2748 int thaicol_stp_offset = 0;
2749 int thaicol_dtp_offset = 0;
2750 #endif /* THAI */
2751 /*
2752 int (*drawfunc) () = XDrawString;
2753 int (*image_drawfunc) () = XDrawImageString;
2754 */
2755 int drawfunc, image_drawfunc;
2756 struct rxvt_hidden *h = r->h;
2757
2758
2759 if (refresh_type == NO_REFRESH || !PVTS(r, page)->mapped)
2760 return;
2761
2762 DBG_MSG(3, (stderr, "rxvt_scr_refresh %d ()\n", page));
2763
2764 /*
2765 ** A: set up vars
2766 */
2767 #ifdef XFT_SUPPORT
2768 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt) {
2769 drawfunc = XFT_DRAW_STRING_8;
2770 image_drawfunc = XFT_DRAW_IMAGE_STRING_8;
2771 }
2772 else
2773 #endif
2774 {
2775 drawfunc = X11_DRAW_STRING_8;
2776 image_drawfunc = X11_DRAW_IMAGE_STRING_8;
2777 }
2778
2779 clearfirst = clearlast = must_clear = wbyte = 0;
2780 #ifndef NO_BOLDFONT
2781 bfont = 0;
2782 #endif
2783
2784 if (h->currmaxcol < r->TermWin.ncol) {
2785 h->currmaxcol = r->TermWin.ncol;
2786 h->buffer = rxvt_realloc(h->buffer, sizeof(char) * (h->currmaxcol + 1));
2787 }
2788 buffer = h->buffer;
2789 h->refresh_count = 0;
2790
2791 row_offset = SVLINES - VSTART;
2792 #ifdef XFT_SUPPORT
2793 if (!((r->Options & Opt_xft) && r->TermWin.xftfont))
2794 #endif
2795 {
2796 /* always go back to the base font - it's much safer */
2797 XSetFont(r->Xdisplay, r->TermWin.gc, r->TermWin.font->fid);
2798 wf = r->TermWin.font;
2799 }
2800
2801 if ((refresh_type & REFRESH_BOUNDS)) {
2802 clearfirst = clearlast = 1;
2803 h->refresh_type &= ~REFRESH_BOUNDS;
2804 }
2805 #if defined(BACKGROUND_IMAGE)
2806 must_clear |= (PVTS(r, page)->bg.pixmap != None);
2807 #endif
2808 #if defined(TRANSPARENT)
2809 must_clear |= ((r->Options & Opt_transparent) && h->am_transparent);
2810 #endif
2811 /* is there an old outline cursor on screen? */
2812 ocrow = h->oldcursor.row;
2813
2814 /* set base colours to avoid check in "single glyph writing"
2815 ** below
2816 */
2817 gcvalue.foreground = r->PixColors[Color_fg];
2818 gcvalue.background = r->PixColors[Color_bg];
2819
2820
2821 /*
2822 ** B: reverse any characters which are selected
2823 */
2824 rxvt_scr_reverse_selection(r, page);
2825
2826
2827 /*
2828 ** C: set the cursor character(s)
2829 */
2830 {
2831 unsigned char setoldcursor;
2832 rend_t ccol1, /* Cursor colour */
2833 ccol2; /* Cursor colour2 */
2834
2835 showcursor = (PSCR(r, page).flags & Screen_VisibleCursor);
2836 #ifdef CURSOR_BLINK
2837 if (r->h->hidden_cursor)
2838 showcursor = 0;
2839 #endif
2840 if (showcursor && r->TermWin.focus) {
2841 int currow = CURROW + SVLINES;
2842 srp = &(PSCR(r, page).rend[currow][CURCOL]);
2843
2844 #ifdef THAI
2845 if ((r->Options & Opt_thai) &&
2846 FONT_WIDTH(r->TermWin.font, PSCR(r, page).text[currow][CURCOL]) <= 0)
2847 *srp ^= RS_Bold;
2848 else if (!(r->Options & Opt_thai))
2849 #endif /* THAI */
2850 *srp ^= RS_RVid;
2851
2852 #ifndef NO_CURSORCOLOR
2853 cc1 = *srp & (RS_fgMask | RS_bgMask);
2854 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor))
2855 ccol1 = Color_cursor;
2856 else
2857 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2858 ccol1 = GET_FGCOLOR(
2859 PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
2860 /*
2861 ccol1 = GET_FGCOLOR(PVTS(r, page)->rstyle);
2862 */
2863 #else
2864 ccol1 = Color_fg;
2865 #endif
2866 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor))
2867 ccol2 = Color_cursor2;
2868 else
2869 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2870 # ifdef SIMULATE_LINUX_CONSOLE_CURSOR_COLOR
2871 ccol2 = GET_FGCOLOR(PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
2872 # else
2873 ccol2 = GET_BGCOLOR(PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
2874 # endif /* SIMULATE_LINUX_CONSOLE_CURSOR_COLOR */
2875 /*
2876 ccol2 = GET_BGCOLOR(PVTS(r, page)->rstyle);
2877 */
2878 #else
2879 ccol2 = Color_bg;
2880 #endif
2881 *srp = SET_FGCOLOR(*srp, ccol1);
2882 *srp = SET_BGCOLOR(*srp, ccol2);
2883 #endif
2884 #ifdef MULTICHAR_SET
2885 if (IS_MULTI1(*srp)) {
2886 if (CURCOL < r->TermWin.ncol - 2 && IS_MULTI2(*++srp))
2887 morecur = 1;
2888 }
2889 else if (IS_MULTI2(*srp)) {
2890 if (CURCOL > 0 && IS_MULTI1(*--srp))
2891 morecur = -1;
2892 }
2893 if (morecur) {
2894 *srp ^= RS_RVid;
2895 # ifndef NO_CURSORCOLOR
2896 cc2 = *srp & (RS_fgMask | RS_bgMask);
2897 *srp = SET_FGCOLOR(*srp, ccol1);
2898 *srp = SET_BGCOLOR(*srp, ccol2);
2899 # endif
2900 }
2901 #endif
2902 }
2903
2904 /* make sure no outline cursor is left around */
2905 setoldcursor = 0;
2906 if (ocrow != -1) {
2907 if (CURROW + VSTART != ocrow ||
2908 CURCOL != h->oldcursor.col) {
2909 if (ocrow < r->TermWin.nrow &&
2910 h->oldcursor.col < r->TermWin.ncol) {
2911 PVTS(r, page)->drawn_rend[ocrow][h->oldcursor.col] ^=
2912 (RS_RVid | RS_Uline);
2913 #ifdef MULTICHAR_SET
2914 if (h->oldcursormulti) {
2915 col = h->oldcursor.col + h->oldcursormulti;
2916 if (col < r->TermWin.ncol)
2917 PVTS(r, page)->drawn_rend[ocrow][col] ^=
2918 (RS_RVid | RS_Uline);
2919 }
2920 #endif
2921 }
2922 if (r->TermWin.focus || !showcursor)
2923 h->oldcursor.row = -1;
2924 else
2925 setoldcursor = 1;
2926 }
2927 }
2928 else if (!r->TermWin.focus)
2929 setoldcursor = 1;
2930 if (setoldcursor) {
2931 if (CURROW + VSTART >= r->TermWin.nrow)
2932 h->oldcursor.row = -1;
2933 else {
2934 h->oldcursor.row = CURROW + VSTART;
2935 h->oldcursor.col = CURCOL;
2936 #ifdef MULTICHAR_SET
2937 h->oldcursormulti = morecur;
2938 #endif
2939 }
2940 }
2941 }
2942 /* End of C */
2943
2944
2945 #ifndef NO_SLOW_LINK_SUPPORT
2946 /*
2947 ** D: CopyArea pass - very useful for slower links
2948 ** This has been deliberately kept simple.
2949 */
2950 i = PVTS(r, page)->num_scr;
2951 if (refresh_type == FAST_REFRESH &&
2952 h->num_scr_allow &&
2953 i &&
2954 abs(i) < r->TermWin.nrow &&
2955 !must_clear) {
2956 RINT16T nits;
2957 int j;
2958 rend_t *drp2;
2959 text_t *dtp2;
2960
2961 j = r->TermWin.nrow;
2962 wlen = len = -1;
2963 row = i > 0 ? 0 : j - 1;
2964 for (; j-- >= 0; row += (i > 0 ? 1 : -1)) {
2965 if (row + i >= 0 &&
2966 row + i < r->TermWin.nrow &&
2967 row + i != ocrow) {
2968 stp = PSCR(r, page).text[row + row_offset];
2969 srp = PSCR(r, page).rend[row + row_offset];
2970 dtp = PVTS(r, page)->drawn_text[row];
2971 dtp2 = PVTS(r, page)->drawn_text[row + i];
2972 drp = PVTS(r, page)->drawn_rend[row];
2973 drp2 = PVTS(r, page)->drawn_rend[row + i];
2974 for (nits = 0, col = r->TermWin.ncol; col--; )
2975 if (stp[col] != dtp2[col] ||
2976 srp[col] != drp2[col])
2977 nits--;
2978 else if (stp[col] != dtp[col] ||
2979 srp[col] != drp[col])
2980 nits++;
2981 if (nits > 8) { /* XXX: arbitrary choice */
2982 for (col = r->TermWin.ncol; col--; ) {
2983 *dtp++ = *dtp2++;
2984 *drp++ = *drp2++;
2985 }
2986 if (len == -1)
2987 len = row;
2988 wlen = row;
2989 continue;
2990 }
2991 }
2992
2993 if (len != -1) {
2994 /* also comes here at end if needed because of >= above */
2995 if (wlen < len)
2996 SWAP_IT(wlen, len, int);
2997 DBG_MSG(2,(stderr, "rxvt_scr_refresh %d (): XCopyArea: %d -> %d (height: %d)\n", page, len + i, len, wlen - len + 1));
2998 XCopyArea(r->Xdisplay, PVTS(r, page)->vt,
2999 PVTS(r, page)->vt, r->TermWin.gc,
3000 0, Row2Pixel(len + i),
3001 TWIN_WIDTH(r),
3002 (unsigned int)Height2Pixel(wlen-len+1),
3003 0, Row2Pixel(len));
3004 len = -1;
3005 }
3006 }
3007 } /* End of D */
3008 #endif /* !NO_SLOW_LINK_SUPPORT */
3009
3010
3011 /*
3012 ** E: main pass across every character
3013 */
3014 for (row = 0; row < r->TermWin.nrow; row++) {
3015 unsigned char clear_next = 0;
3016 int j,
3017 /* x offset for start of drawing (font) */
3018 xpixel,
3019 /* y offset for top of drawing */
3020 ypixelc;
3021 unsigned long gcmask; /* Graphics Context mask */
3022 #ifdef THAI
3023 char* thai_update = NULL;
3024 #endif /* THAI */
3025
3026
3027 stp = PSCR(r, page).text[row + row_offset];
3028 srp = PSCR(r, page).rend[row + row_offset];
3029 dtp = PVTS(r, page)->drawn_text[row];
3030 drp = PVTS(r, page)->drawn_rend[row];
3031
3032
3033 #ifdef THAI
3034 if (r->Options & Opt_thai) {
3035 /* possible integer overflow? */
3036 assert (r->TermWin.ncol > 0);
3037 thai_update = (char*) rxvt_malloc (r->TermWin.ncol);
3038 /* compare drawn_text and screen.text and check which to
3039 ** update */
3040 ThaiUpdateMap (PSCR(r, page).text[row + row_offset],
3041 PVTS(r, page)->drawn_text[row],
3042 PSCR(r, page).rend[row + row_offset],
3043 PVTS(r, page)->drawn_rend[row],
3044 thai_update, r->TermWin.ncol);
3045 /* TODO: Change this algo to scalefont compatible */
3046 thaicol_stp_offset = 0; /* records how many col deficit */
3047 thaicol_dtp_offset = r->TermWin.ncol - Thai_ColMaxPaint (dtp, r->TermWin.ncol);
3048 /* clean strings before redraw */
3049 for (col = 0; col < r->TermWin.ncol; col ++) {
3050 if (!ThaiIsMiddleLineCh (stp[col]))
3051 thaicol_stp_offset ++;
3052 }
3053 ypixelc = (int)Row2Pixel(row);
3054 if (thaicol_stp_offset > thaicol_dtp_offset) {
3055 CLEAR_CHARS(
3056 Col2Pixel (r->TermWin.ncol - thaicol_stp_offset),
3057 ypixelc,
3058 thaicol_stp_offset);
3059 }
3060 }
3061 #endif /* THAI */
3062
3063 #ifndef NO_PIXEL_DROPPING_AVOIDANCE
3064 /*
3065 ** E1: pixel dropping avoidance. Do this before the main
3066 ** refresh on the line. Require a refresh where pixels may
3067 ** have been dropped into our area by a neighbour character
3068 ** which has now changed
3069 ** TODO: this could be integrated into E2 but might be too
3070 ** messy
3071 */
3072 for (col = 0; col < r->TermWin.ncol; col++) {
3073 unsigned char is_font_char, is_same_char;
3074 text_t t;
3075
3076 t = dtp[col];
3077 is_same_char = (t == stp[col] && drp[col] == srp[col]);
3078 if (!clear_next &&
3079 (is_same_char || t == 0 || t == ' '))
3080 /* screen cleared elsewhere */
3081 continue;
3082
3083 if (clear_next) {
3084 /* previous char caused change here */
3085 clear_next = 0;
3086 dtp[col] = 0;
3087
3088 /* don't cascade into next char */
3089 if (is_same_char)
3090 continue;
3091 }
3092 j = MONO_BOLD(drp[col]) ? 1 : 0;
3093 # ifndef NO_BOLDFONT
3094 wf = (j && r->TermWin.bfont) ?
3095 r->TermWin.bfont : r->TermWin.font;
3096 # endif
3097
3098 /*
3099 ** TODO: consider if anything special needs to happen
3100 ** with:
3101 ** #if defined(MULTICHAR_SET) &&
3102 ** !defined(NO_BOLDOVERSTRIKE_MULTI)
3103 */
3104 is_font_char = (wf->per_char && IS_FONT_CHAR(wf, t)) ? 1:0;
3105 if (!is_font_char || FONT_LBEAR(wf, t) < 0) {
3106 if (col == 0)
3107 clearfirst = 1;
3108 else
3109 dtp[col - 1] = 0;
3110 }
3111 if (!is_font_char ||
3112 (FONT_WIDTH(wf, t) < (FONT_RBEAR(wf, t) + j))) {
3113 if (col == r->TermWin.ncol - 1)
3114 clearlast = 1;
3115 else
3116 clear_next = 1;
3117 }
3118 }
3119 #endif /* NO_PIXEL_DROPPING_AVOIDANCE */
3120 /* End of E1 */
3121
3122
3123 /*
3124 ** E2: OK, now the real pass
3125 */
3126 ypixelc = (int)Row2Pixel(row);
3127
3128 for (col = 0; col < r->TermWin.ncol; col++) {
3129 /* current font size != base font size */
3130 unsigned char fontdiff,
3131 /* proportional font used */
3132 fprop;
3133 /* rendition value */
3134 rend_t rend;
3135
3136 /* compare new text with old - if exactly the same then
3137 ** continue
3138 */
3139 /* screen rendition (target rendtion) */
3140 rend = srp[col];
3141 if (
3142 #ifdef THAI
3143 ((r->Options & Opt_thai) && !thai_update[col]) ||
3144 (!(r->Options & Opt_thai) &&
3145 #endif /* THAI */
3146 /* Must match characters to skip. */
3147 (stp[col] == dtp[col] &&
3148 /* Either rendition the same or */
3149 (rend == drp[col] ||
3150 /* space w/ no background change */
3151 (stp[col] == ' ' &&
3152 GET_BGATTR(rend) == GET_BGATTR(drp[col]))))
3153 #ifdef THAI
3154 ) /* need a match of ( */
3155 #endif /* THAI */
3156 ) { /* if */
3157 if (!IS_MULTI1(rend))
3158 continue;
3159 #ifdef MULTICHAR_SET
3160 else {
3161 /* first byte is Kanji so compare second bytes */
3162 if (stp[col + 1] == dtp[col + 1]) {
3163 /* assume no corrupt characters on the screen */
3164 col++;
3165 continue;
3166 }
3167 }
3168 #endif
3169 }
3170 /* redraw one or more characters */
3171
3172 fontdiff = 0;
3173 len = 0;
3174 #ifdef THAI
3175 if (!(r->Options & Opt_thai))
3176 #endif /* THAI */
3177 buffer[len++] = dtp[col] = stp[col];
3178 drp[col] = rend;
3179 #ifdef THAI
3180 if (r->Options & Opt_thai)
3181 xpixel = ThaiCol2Pixel (r, col, PSCR(r, page).text[row + row_offset]);
3182 else
3183 #endif /* THAI */
3184 xpixel = Col2Pixel(col);
3185
3186 /*
3187 ** Find out the longest string we can write out at once
3188 */
3189 #ifndef NO_BOLDFONT
3190 if (MONO_BOLD(rend) && r->TermWin.bfont != NULL)
3191 fprop = (r->TermWin.propfont & PROPFONT_BOLD);
3192 else
3193 #endif
3194 fprop = (r->TermWin.propfont & PROPFONT_NORMAL);
3195
3196 #ifdef MULTICHAR_SET
3197 if (IS_MULTI1(rend) &&
3198 col < r->TermWin.ncol - 1 && IS_MULTI2(srp[col + 1])) {
3199 if (!wbyte && r->TermWin.mfont) {
3200 wbyte = 1;
3201 XSetFont(r->Xdisplay, r->TermWin.gc,
3202 r->TermWin.mfont->fid);
3203 fontdiff = (r->TermWin.propfont & PROPFONT_MULTI);
3204 #ifdef XFT_SUPPORT
3205 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt){
3206 drawfunc = XFT_DRAW_STRING_16;
3207 image_drawfunc = XFT_DRAW_IMAGE_STRING_16;
3208 }
3209 else
3210 #endif
3211 {
3212 drawfunc = X11_DRAW_STRING_16;
3213 image_drawfunc = X11_DRAW_IMAGE_STRING_16;
3214 }
3215 }
3216
3217 if (r->TermWin.mfont == NULL) {
3218 buffer[0] = buffer[1] = ' ';
3219 len = 2;
3220 col++;
3221 }
3222 else {
3223 /* double stepping - we're in multibyte font mode */
3224 for (; ++col < r->TermWin.ncol;) {
3225 /* XXX: could check sanity on 2nd byte */
3226 dtp[col] = stp[col];
3227 drp[col] = srp[col];
3228 buffer[len++] = stp[col];
3229 col++;
3230 /* proportional multibyte font mode */
3231 if (fprop)
3232 break;
3233 if ((col == r->TermWin.ncol) ||
3234 (srp[col] != rend))
3235 break;
3236 if ((stp[col] == dtp[col]) &&
3237 (srp[col] == drp[col]) &&
3238 (stp[col + 1] == dtp[col + 1]))
3239 break;
3240 if (len == h->currmaxcol)
3241 break;
3242 dtp[col] = stp[col];
3243 drp[col] = srp[col];
3244 buffer[len++] = stp[col];
3245 }
3246 col--;
3247 }
3248
3249 if (buffer[0] & 0x80)
3250 (h->multichar_decode)(buffer, len);
3251 wlen = len / 2;
3252 }
3253 else {
3254 if (rend & RS_multi1) {
3255 /* corrupt character - you're outta there */
3256 rend &= ~RS_multiMask;
3257 drp[col] = rend; /* TODO check: may also want */
3258 dtp[col] = ' '; /* to poke into stp/srp */
3259 buffer[0] = ' ';
3260 }
3261 if (wbyte) {
3262 wbyte = 0;
3263 #ifdef XFT_SUPPORT
3264 if (!((r->Options & Opt_xft) && r->TermWin.xftfont))
3265 #endif
3266 XSetFont(r->Xdisplay, r->TermWin.gc,
3267 r->TermWin.font->fid);
3268 #ifdef XFT_SUPPORT
3269 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt){
3270 drawfunc = XFT_DRAW_STRING_8;
3271 image_drawfunc = XFT_DRAW_IMAGE_STRING_8;
3272 }
3273 else
3274 #endif
3275 {
3276 drawfunc = X11_DRAW_STRING_8;
3277 image_drawfunc = X11_DRAW_IMAGE_STRING_8;
3278 }
3279 } /* if (wbyte) */
3280 #else
3281 {
3282 #endif
3283 if (!fprop) {
3284 /* single stepping - `normal' mode */
3285 for (i = 0; ++col < r->TermWin.ncol - 1;) {
3286 if (rend != srp[col])
3287 break;
3288 buffer[len++] = stp[col];
3289 if ((stp[col] != dtp[col]) ||
3290 (srp[col] != drp[col])) {
3291 if (must_clear && (i++ > (len / 2)))
3292 break;
3293 dtp[col] = stp[col];
3294 drp[col] = srp[col];
3295 i = 0;
3296 }
3297 else if (must_clear ||
3298 (stp[col] != ' ' && ++i > 32))
3299 break;
3300 } /* for */
3301 col--; /* went one too far. move back */
3302 len -= i; /* dump any matching trailing chars */
3303 } /* if (!fprop) */
3304 wlen = len;
3305 }
3306 buffer[len] = '\0';
3307
3308 /*
3309 ** Determine the attributes for the string
3310 */
3311 fore = GET_FGCOLOR(rend);
3312 back = GET_BGCOLOR(rend);
3313 rend = GET_ATTR(rend);
3314
3315 switch (rend & RS_fontMask) {
3316 case RS_acsFont:
3317 for (i = 0; i < len; i++)
3318 if (buffer[i] == 0x5f)
3319 buffer[i] = 0x7f;
3320 else if (buffer[i] > 0x5f && buffer[i] < 0x7f)
3321 buffer[i] -= 0x5f;
3322 break;
3323 case RS_ukFont:
3324 for (i = 0; i < len; i++)
3325 if (buffer[i] == '#')
3326 buffer[i] = 0x1e; /* pound sign */
3327 break;
3328 }
3329
3330 rvid = (rend & RS_RVid) ? 1 : 0;
3331 #ifdef OPTION_HC
3332 if (!rvid && (rend & RS_Blink)) {
3333 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_HC) &&
3334 r->PixColors[fore] != r->PixColors[Color_HC] &&
3335 r->PixColors[back] != r->PixColors[Color_HC])
3336 back = Color_HC;
3337 else
3338 rvid = !rvid; /* fall back */
3339 }
3340 #endif
3341
3342 if (
3343 #ifdef THAI
3344 (rvid && (r->Options & Opt_thai) &&
3345 (FONT_WIDTH(wf, stp[col]) > 0)) ||
3346 (!(r->Options & Opt_thai) &&
3347 #endif /* THAI */
3348 rvid
3349 #ifdef THAI
3350 ) /* match the ( */
3351 #endif /* THAI */
3352 ) {
3353
3354 #ifdef TTY_256COLOR
3355 SWAP_IT(fore, back, RUINT16T);
3356 #else
3357 SWAP_IT(fore, back, unsigned char);
3358 #endif
3359 #ifndef NO_BOLD_UNDERLINE_REVERSE
3360 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_RV)
3361 # ifndef NO_CURSORCOLOR
3362 && (!ISSET_PIXCOLOR(h, Color_cursor) ||
3363 r->PixColors[back] != r->PixColors[Color_cursor])
3364 # endif
3365 && r->PixColors[fore] != r->PixColors[Color_RV])
3366 back = Color_RV;
3367 #endif
3368 }
3369 gcmask = 0;
3370 if (back != Color_bg) {
3371 gcvalue.background = r->PixColors[back];
3372 gcmask = GCBackground;
3373 }
3374 if (fore != Color_fg) {
3375 gcvalue.foreground = r->PixColors[fore];
3376 gcmask |= GCForeground;
3377 }
3378 #ifndef NO_BOLD_UNDERLINE_REVERSE
3379 else if (rend & RS_Bold) {
3380 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_BD) &&
3381 r->PixColors[fore] != r->PixColors[Color_BD] &&
3382 r->PixColors[back] != r->PixColors[Color_BD]) {
3383 gcvalue.foreground = r->PixColors[Color_BD];
3384 gcmask |= GCForeground;
3385 if (!(r->Options2 & Opt2_veryBold))
3386 rend &= ~RS_Bold; /* we've taken care of it */
3387 }
3388 }
3389 else if (rend & RS_Uline) {
3390 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_UL) &&
3391 r->PixColors[fore] != r->PixColors[Color_UL] &&
3392 r->PixColors[back] != r->PixColors[Color_UL]) {
3393 gcvalue.foreground = r->PixColors[Color_UL];
3394 gcmask |= GCForeground;
3395 rend &= ~RS_Uline; /* we've taken care of it */
3396 }
3397 }
3398 #endif
3399 if (gcmask)
3400 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3401 #ifndef NO_BOLDFONT
3402 if (!wbyte && MONO_BOLD_FG(rend, fore) &&
3403 r->TermWin.bfont != NULL) {
3404 bfont = 1;
3405 # ifdef XFT_SUPPORT
3406 if ((r->Options & Opt_xft) && r->TermWin.xftfont)
3407 rxvt_switch_bold_font (r);
3408 else
3409 # endif
3410 XSetFont(r->Xdisplay, r->TermWin.gc,
3411 r->TermWin.bfont->fid);
3412 fontdiff = (r->TermWin.propfont & PROPFONT_BOLD);
3413 rend &= ~RS_Bold; /* we've taken care of it */
3414 }
3415 else if (bfont) {
3416 bfont = 0;
3417 # ifdef XFT_SUPPORT
3418 if ((r->Options & Opt_xft) && r->TermWin.xftfont)
3419 rxvt_restore_bold_font (r);
3420 else
3421 # endif
3422 XSetFont(r->Xdisplay, r->TermWin.gc,
3423 r->TermWin.font->fid);
3424 }
3425 #endif
3426
3427 /*
3428 ** Actually do the drawing of the string here
3429 */
3430 if (back == Color_bg && must_clear) {
3431 #ifdef THAI
3432 if ((r->Options & Opt_thai) &&
3433 FONT_WIDTH(wf, stp[col]) > 0) {
3434 CLEAR_CHARS(xpixel, ypixelc, len);
3435 }
3436 else if (!(r->Options & Opt_thai))
3437 #endif /* THAI */
3438 {
3439 CLEAR_CHARS(xpixel, ypixelc, len);
3440 }
3441 for (i = 0; i < len; i++)
3442 /* don't draw empty strings */
3443 if (buffer[i] != ' ') {
3444 rxvt_scr_draw_string (r, page, xpixel, ypixelc, buffer, wlen, drawfunc, fore, back);
3445 break;
3446 }
3447 }
3448 else if (fprop || fontdiff) {
3449 /* single glyph writing */
3450 unsigned long pixel;
3451
3452 pixel = gcvalue.foreground;
3453 gcvalue.foreground = gcvalue.background;
3454 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
3455 rxvt_fill_rectangle (r, page, xpixel, ypixelc,
3456 (unsigned int) Width2Pixel(len),
3457 (unsigned int) (Height2Pixel(1)
3458 /* - r->TermWin.lineSpace */));
3459 gcvalue.foreground = pixel;
3460 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
3461 rxvt_scr_draw_string (r, page, xpixel, ypixelc, buffer, wlen, drawfunc, fore, back);
3462 }
3463 else {
3464 rxvt_scr_draw_string (r, page, xpixel, ypixelc, buffer, wlen, image_drawfunc, fore, back);
3465 }
3466
3467 #ifndef NO_BOLDOVERSTRIKE
3468 # ifdef NO_BOLDOVERSTRIKE_MULTI
3469 if (!wbyte)
3470 # endif
3471 if (MONO_BOLD_FG(rend, fore)) {
3472 rxvt_scr_draw_string (r, page, xpixel + 1, ypixelc, buffer, wlen, drawfunc, fore, back);
3473 }
3474 #endif
3475 if (rend & RS_Uline) {
3476 #ifdef XFT_SUPPORT
3477 if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt) {
3478 if (r->TermWin.xftfont->descent > 1)
3479 XDrawLine(r->Xdisplay, drawBuffer,
3480 r->TermWin.gc,
3481 xpixel,
3482 ypixelc + r->TermWin.xftfont->ascent + 1,
3483 xpixel + Width2Pixel(len) - 1,
3484 ypixelc + r->TermWin.xftfont->ascent + 1);
3485 }
3486 else
3487 #endif
3488 if (r->TermWin.font->descent > 1)
3489 XDrawLine(r->Xdisplay, drawBuffer, r->TermWin.gc,
3490 xpixel,
3491 ypixelc + r->TermWin.font->ascent + 1,
3492 xpixel + Width2Pixel(len) - 1,
3493 ypixelc + r->TermWin.font->ascent + 1);
3494 }
3495
3496 if (gcmask) { /* restore normal colours */
3497 gcvalue.foreground = r->PixColors[Color_fg];
3498 gcvalue.background = r->PixColors[Color_bg];
3499 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3500 }
3501 } /* for (col....) */
3502 /* End of E2 */
3503 } /* for (row....) */
3504 /* End of E */
3505
3506 #ifdef THAI
3507 if (r->Options & Opt_thai) {
3508 for (row = 0; row < r->TermWin.nrow; row ++) {
3509 stp = PSCR(r, page).text[row + row_offset];
3510 srp = PSCR(r, page).rend[row + row_offset];
3511 dtp = PVTS(r, page)->drawn_text[row];
3512 drp = PVTS(r, page)->drawn_rend[row];
3513
3514 for (col = 0; col < r->TermWin.ncol; col++) {
3515 dtp[col] = stp[col];
3516 drp[col] = srp[col];
3517 }
3518 }
3519 }
3520 #endif /* THAI */
3521
3522
3523 /*
3524 ** G: cleanup cursor and display outline cursor in necessary
3525 */
3526 if (showcursor) {
3527 if (r->TermWin.focus) {
3528 int currow = CURROW + SVLINES;
3529 srp = &(PSCR(r, page).rend[currow][CURCOL]);
3530 #ifdef THAI
3531 if ((r->Options & Opt_thai) &&
3532 FONT_WIDTH(wf, PSCR(r, page).text[currow][CURCOL]) <= 0)
3533 *srp ^= RS_Bold;
3534 else if (!(r->Options & Opt_thai))
3535 #endif /* THAI */
3536 *srp ^= RS_RVid;
3537
3538 #ifndef NO_CURSORCOLOR
3539 *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc1;
3540 #endif
3541 #ifdef MULTICHAR_SET
3542 if (morecur) {
3543 srp += morecur;
3544 *srp ^= RS_RVid;
3545 # ifndef NO_CURSORCOLOR
3546 *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc2;
3547 # endif
3548 }
3549 #endif
3550 }
3551 else if (h->oldcursor.row >= 0) {
3552 #ifndef NO_CURSORCOLOR
3553 unsigned long gcmask; /* Graphics Context mask */
3554
3555 gcmask = 0;
3556 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor)) {
3557 gcvalue.foreground = r->PixColors[Color_cursor];
3558 gcmask = GCForeground;
3559 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3560 gcvalue.foreground = r->PixColors[Color_fg];
3561 }
3562 #endif
3563
3564 #ifdef THAI
3565 if (r->Options & Opt_thai) {
3566 XDrawRectangle(r->Xdisplay, drawBuffer, r->TermWin.gc,
3567 ThaiCol2Pixel (r, h->oldcursor.col + morecur,
3568 PSCR(r, page).text[CURROW + SVLINES]),
3569 Row2Pixel(h->oldcursor.row),
3570 (unsigned int)(Width2Pixel(1 + (morecur?1:0)) - 1),
3571 (unsigned int)(Height2Pixel(1)
3572 /* - r->TermWin.lineSpace*/ - 1));
3573 }
3574 else
3575 #endif /* THAI */
3576 {
3577 XDrawRectangle(r->Xdisplay, drawBuffer, r->TermWin.gc,
3578 Col2Pixel(h->oldcursor.col + morecur),
3579 Row2Pixel(h->oldcursor.row),
3580 (unsigned int)(Width2Pixel(1 + (morecur?1:0)) - 1),
3581 (unsigned int)(Height2Pixel(1)
3582 /* - r->TermWin.lineSpace*/ - 1));
3583 }
3584
3585 #ifndef NO_CURSORCOLOR
3586 if (gcmask) /* restore normal colours */
3587 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3588 #endif
3589 }
3590 }
3591 /* End of G */
3592
3593
3594 /*
3595 ** H: cleanup selection
3596 */
3597 rxvt_scr_reverse_selection(r, page);
3598
3599
3600 /*
3601 ** I: other general cleanup
3602 */
3603 /*
3604 ** clear the whole screen height, note that width == 0 is treated
3605 ** specially by XClearArea
3606 */
3607 if (clearfirst && r->TermWin.int_bwidth)
3608 rxvt_clear_area (r, page, 0, 0,
3609 (unsigned int)r->TermWin.int_bwidth, VT_HEIGHT(r));
3610 /*
3611 ** clear the whole screen height, note that width == 0 is treated
3612 ** specially by XClearArea
3613 */
3614 if (clearlast && r->TermWin.int_bwidth)
3615 rxvt_clear_area (r, page,
3616 TWIN_WIDTH(r) + r->TermWin.int_bwidth, 0,
3617 (unsigned int)r->TermWin.int_bwidth, VT_HEIGHT(r));
3618
3619 if (refresh_type & SMOOTH_REFRESH)
3620 XSync(r->Xdisplay, False);
3621
3622 PVTS(r, page)->num_scr = 0;
3623 h->num_scr_allow = 1;
3624 h->want_refresh = 0; /* screen is current */
3625 }
3626
3627
3628 #undef X11_DRAW_STRING_8
3629 #undef X11_DRAW_STRING_16
3630 #undef X11_DRAW_IMAGE_STRING_8
3631 #undef X11_DRAW_IMAGE_STRING_16
3632 #undef XFT_DRAW_STRING_8
3633 #undef XFT_DRAW_STRING_16
3634 #undef XFT_DRAW_STRING_32
3635 #undef XFT_DRAW_STRING_UTF8
3636
3637 /* ------------------------------------------------------------------------- */
3638
3639
3640 /* EXTPROTO */
3641 void
3642 rxvt_scr_clear(rxvt_t* r, int page)
3643 {
3644 if (!PVTS(r, page)->mapped)
3645 return;
3646
3647 r->h->num_scr_allow = 0;
3648 r->h->want_refresh = 1;
3649 #ifdef TRANSPARENT
3650 if (r->Options & Opt_transparent) {
3651 if (r->TermWin.parent != None)
3652 XClearWindow(r->Xdisplay, r->TermWin.parent);
3653 }
3654 #endif
3655 XClearWindow(r->Xdisplay, PVTS(r, page)->vt);
3656 }
3657
3658 /* ------------------------------------------------------------------------- */
3659 /* INTPROTO */
3660 void
3661 rxvt_scr_reverse_selection(rxvt_t* r, int page)
3662 {
3663 int i, col, row, end_row;
3664 rend_t *srp;
3665
3666 if (SEL(r).op &&
3667 SEL(r).vt == page &&
3668 PVTS(r, page)->current_screen == SEL(r).screen) {
3669 end_row = SVLINES - VSTART;
3670
3671 i = SEL(r).beg.row + SVLINES;
3672 row = SEL(r).end.row + SVLINES;
3673
3674 if (i >= end_row)
3675 col = SEL(r).beg.col;
3676 else {
3677 col = 0;
3678 i = end_row;
3679 }
3680
3681 end_row += r->TermWin.nrow;
3682 for (; i < row && i < end_row; i++, col = 0)
3683 for (srp = PSCR(r, page).rend[i]; col < r->TermWin.ncol; col++)
3684 #ifndef OPTION_HC
3685 srp[col] ^= RS_RVid;
3686 #else
3687 srp[col] ^= RS_Blink;
3688 #endif
3689 if (i == row && i < end_row)
3690 for (srp = PSCR(r, page).rend[i]; col < SEL(r).end.col; col++)
3691 #ifndef OPTION_HC
3692 srp[col] ^= RS_RVid;
3693 #else
3694 srp[col] ^= RS_Blink;
3695 #endif
3696 }
3697 }
3698
3699 /* ------------------------------------------------------------------------- */
3700 /*
3701 * Dump the whole scrollback and screen to the passed filedescriptor. The
3702 * invoking routine must close the fd.
3703 */
3704 #if 0
3705 /* EXTPROTO */
3706 void
3707 rxvt_scr_dump(rxvt_t* r, int fd)
3708 {
3709 int row, wrote;
3710 unsigned int width, towrite;
3711 char r1[] = "\n";
3712
3713 for (row = SVLINES - PVTS(r, page)->nscrolled;
3714 row < SVLINES + r->TermWin.nrow - 1; row++) {
3715 width = PSCR(r, page).tlen[row] >= 0 ? PSCR(r, page).tlen[row]
3716 : r->TermWin.ncol;
3717 for (towrite = width; towrite; towrite -= wrote) {
3718 wrote = write(fd, &(PSCR(r, page).text[row][width - towrite]),
3719 towrite);
3720 if (wrote < 0)
3721 return; /* XXX: death, no report */
3722 }
3723 if (PSCR(r, page).tlen[row] >= 0)
3724 if (write(fd, r1, 1) <= 0)
3725 return; /* XXX: death, no report */
3726 }
3727 }
3728 #endif
3729
3730 /* ------------------------------------------------------------------------- *
3731 * CHARACTER SELECTION *
3732 * ------------------------------------------------------------------------- */
3733
3734 /*
3735 * -PVTS(r, page)->nscrolled <= (selection row) <= r->TermWin.nrow - 1
3736 */
3737 /* EXTPROTO */
3738 void
3739 rxvt_selection_check(rxvt_t* r, int page, int check_more)
3740 {
3741 row_col_t pos;
3742
3743 if (!SEL(r).op ||
3744 SEL(r).vt != page ||
3745 SEL(r).screen != PVTS(r, page)->current_screen)
3746 return;
3747
3748 pos.row = pos.col = 0;
3749 if ((SEL(r).beg.row < -(RINT32T)PVTS(r, page)->nscrolled) ||
3750 (SEL(r).beg.row >= r->TermWin.nrow) ||
3751 (SEL(r).mark.row < -(RINT32T)PVTS(r, page)->nscrolled) ||
3752 (SEL(r).mark.row >= r->TermWin.nrow) ||
3753 (SEL(r).end.row < -(RINT32T)PVTS(r, page)->nscrolled) ||
3754 (SEL(r).end.row >= r->TermWin.nrow) ||
3755 ( check_more == 1 &&
3756 PVTS(r, page)->current_screen == SEL(r).screen &&
3757 !RC_BEFORE(PSCR(r, page).cur, SEL(r).beg) &&
3758 RC_BEFORE(PSCR(r, page).cur, SEL(r).end)) ||
3759 ( check_more == 2 &&
3760 RC_BEFORE(SEL(r).beg, pos) &&
3761 RC_AFTER(SEL(r).end, pos)) ||
3762 ( check_more == 3 &&
3763 RC_AFTER(SEL(r).end, pos)) ||
3764 ( check_more == 4 /* screen width change */ &&
3765 ( SEL(r).beg.row != SEL(r).end.row ||
3766 SEL(r).end.col > r->TermWin.ncol)))
3767 CLEAR_SELECTION(r);
3768 }
3769
3770 /* ------------------------------------------------------------------------- */
3771 /*
3772 * Paste a selection direct to the command fd
3773 */
3774 /* INTPROTO */
3775 void
3776 rxvt_PasteIt(rxvt_t* r, int page, const unsigned char *data, unsigned int nitems)
3777 {
3778 unsigned int i, j, n;
3779 unsigned char *ds = rxvt_malloc(PROP_SIZE);
3780
3781 /*
3782 ** convert normal newline chars into common keyboard Return key
3783 ** sequence
3784 */
3785 for (i = 0; i < nitems; i += PROP_SIZE) {
3786 n = min(nitems - i, PROP_SIZE);
3787 MEMCPY(ds, data + i, n);
3788 for (j = 0; j < n; j++)
3789 if (ds[j] == '\n')
3790 ds[j] = '\r';
3791 rxvt_tt_write(r, page, ds, (int)n);
3792 }
3793 free(ds);
3794 }
3795
3796
3797 /* ------------------------------------------------------------------------- */
3798 /*
3799 * Respond to a notification that a primary selection has been sent
3800 * EXT: SelectionNotify
3801 */
3802 /* EXTPROTO */
3803 int
3804 rxvt_selection_paste(rxvt_t* r, Window win, Atom prop, Bool delete_prop)
3805 {
3806 long nread = 0;
3807 unsigned long bytes_after;
3808 XTextProperty ct;
3809 #ifdef MULTICHAR_SET
3810 int dummy_count;
3811 char** cl;
3812 #endif
3813
3814 DBG_MSG(2,(stderr, "rxvt_selection_paste (%08lx, %lu, %d), wait=%2x\n", win, (unsigned long)prop, (int)delete_prop, r->h->selection_wait));
3815
3816 if (prop == None) { /* check for failed XConvertSelection */
3817 #ifdef MULTICHAR_SET
3818 if ((r->h->selection_type & Sel_CompoundText)) {
3819 int selnum = r->h->selection_type & Sel_whereMask;
3820
3821 r->h->selection_type = 0;
3822 if (selnum != Sel_direct)
3823 rxvt_selection_request_other(r, ATAB(r), XA_STRING, selnum);
3824 }
3825 #endif
3826 return 0;
3827 }
3828
3829 for (;;) {
3830 if (XGetWindowProperty(r->Xdisplay, win, prop, (long)(nread/4),
3831 (long)(PROP_SIZE / 4), delete_prop, AnyPropertyType,
3832 &ct.encoding, &ct.format, &ct.nitems, &bytes_after,
3833 &ct.value) != Success)
3834 break;
3835 if (ct.encoding == None) {
3836 DBG_MSG(2,(stderr, "rxvt_selection_paste: property didn't exist!\n"));
3837 break;
3838 }
3839 if (ct.value == NULL) {
3840 DBG_MSG(2,(stderr, "rxvt_selection_paste: property shooting blanks!\n"));
3841 continue;
3842 }
3843 if (ct.nitems == 0) {
3844 DBG_MSG(2,(stderr, "rxvt_selection_paste: property empty - also INCR end\n"));
3845 if (r->h->selection_wait == Sel_normal && nread == 0) {
3846 /*
3847 ** pass through again trying CUT_BUFFER0 if we've come
3848 ** from XConvertSelection() but nothing was presented
3849 */
3850 DBG_MSG(2,(stderr, "rxvt_selection_request: pasting CUT_BUFFER0\n"));
3851 rxvt_selection_paste(r, XROOT, XA_CUT_BUFFER0, False);
3852 }
3853 nread = -1; /* discount any previous stuff */
3854 break;
3855 }
3856
3857 nread += ct.nitems;
3858 #ifdef MULTICHAR_SET
3859 if (XmbTextPropertyToTextList(r->Xdisplay, &ct, &cl,
3860 &dummy_count) == Success && cl) {
3861 rxvt_PasteIt(r, ATAB(r), cl[0], STRLEN(cl[0]));
3862 XFreeStringList(cl);
3863 }
3864 else
3865 #endif
3866 rxvt_PasteIt(r, ATAB(r), ct.value, (unsigned int)ct.nitems);
3867
3868 if (bytes_after == 0)
3869 break;
3870 XFree(ct.value);
3871 }
3872
3873 if (ct.value)
3874 XFree(ct.value);
3875 if (r->h->selection_wait == Sel_normal)
3876 r->h->selection_wait = Sel_none;
3877
3878 DBG_MSG(2,(stderr, "rxvt_selection_paste: bytes written: %ld\n", nread));
3879 return (int)nread;
3880 }
3881
3882
3883 /*
3884 * INCR support originally provided by Paul Sheer <psheer@obsidian.co.za>
3885 */
3886 /* EXTPROTO */
3887 void
3888 rxvt_selection_property(rxvt_t* r, Window win, Atom prop)
3889 {
3890 int reget_time = 0;
3891
3892 if (prop == None)
3893 return;
3894
3895 DBG_MSG(2,(stderr, "rxvt_selection_property(%08lx, %lu)\n", win, (unsigned long)prop));
3896 if (r->h->selection_wait == Sel_normal) {
3897 int a, afmt;
3898 Atom atype;
3899 unsigned long bytes_after, nitems;
3900 unsigned char *s = NULL;
3901
3902 a = XGetWindowProperty(r->Xdisplay, win, prop, 0L, 1L, False,
3903 r->h->xa[XA_INCR], &atype, &afmt, &nitems,
3904 &bytes_after, &s);
3905 if (s)
3906 XFree(s);
3907 if (a != Success)
3908 return;
3909 #ifndef OS_CYGWIN
3910 if (atype == r->h->xa[XA_INCR]) { /* start an INCR transfer */
3911 DBG_MSG(2,(stderr, "rxvt_selection_property: INCR: starting transfer\n"));
3912 XDeleteProperty(r->Xdisplay, win, prop);
3913 XFlush(r->Xdisplay);
3914 reget_time = 1;
3915 r->h->selection_wait = Sel_incr;
3916 }
3917 #endif
3918 }
3919 else if (r->h->selection_wait == Sel_incr) {
3920 reget_time = 1;
3921 if (rxvt_selection_paste(r, win, prop, True) == -1) {
3922 DBG_MSG(2,(stderr, "rxvt_selection_property: INCR: clean end\n"));
3923 r->h->selection_wait = Sel_none;
3924 r->h->timeout[TIMEOUT_INCR].tv_sec = 0; /* turn off timer */
3925 }
3926 }
3927 if (reget_time) { /* received more data so reget time */
3928 (void)gettimeofday(&(r->h->timeout[TIMEOUT_INCR]), NULL);
3929 /* ten seconds wait */
3930 r->h->timeout[TIMEOUT_INCR].tv_sec += 10;
3931 }
3932 }
3933
3934
3935 /* ------------------------------------------------------------------------- */
3936 /*
3937 * Request the current selection:
3938 * Order: > internal selection if available
3939 * > PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+)
3940 * > CUT_BUFFER0
3941 * (+) if ownership is claimed but property is empty, rxvt_selection_paste()
3942 * will auto fallback to CUT_BUFFER0
3943 * EXT: button 2 release
3944 */
3945 /* EXTPROTO */
3946 void
3947 rxvt_selection_request(rxvt_t* r, int page, Time tm, int x, int y)
3948 {
3949 DBG_MSG(2,(stderr, "rxvt_selection_request %d (%lu, %d, %d)\n", page, tm, x, y));
3950 if (x < 0 || x >= VT_WIDTH(r) || y < 0 || y >= VT_HEIGHT(r))
3951 return; /* outside window */
3952
3953 if (SEL(r).text != NULL) { /* internal selection */
3954 DBG_MSG(2,(stderr, "rxvt_selection_request %d: pasting internal\n", page));
3955 rxvt_PasteIt(r, page, SEL(r).text, SEL(r).len);
3956 return;
3957 }
3958 else {
3959 int i;
3960
3961 r->h->selection_request_time = tm;
3962 r->h->selection_wait = Sel_normal;
3963 for (i = Sel_Primary; i <= Sel_Clipboard; i++) {
3964 #ifdef MULTICHAR_SET
3965 r->h->selection_type = Sel_CompoundText;
3966 #else
3967 r->h->selection_type = 0;
3968 #endif
3969 if (rxvt_selection_request_other(r, page,
3970 #ifdef MULTICHAR_SET
3971 r->h->xa[XA_COMPOUND_TEXT],
3972 #else
3973 XA_STRING,
3974 #endif
3975 i))
3976 return;
3977 }
3978 }
3979 r->h->selection_wait = Sel_none; /* don't loop in rxvt_selection_paste() */
3980 DBG_MSG(2,(stderr, "rxvt_selection_request %d: pasting CUT_BUFFER0\n", page));
3981 rxvt_selection_paste(r, XROOT, XA_CUT_BUFFER0, False);
3982 }
3983
3984
3985 /* INTPROTO */
3986 int
3987 rxvt_selection_request_other(rxvt_t* r, int page, Atom target, int selnum)
3988 {
3989 Atom sel;
3990 #if DEBUG_LEVEL
3991 char *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
3992 #endif
3993
3994 r->h->selection_type |= selnum;
3995 if (selnum == Sel_Primary)
3996 sel = XA_PRIMARY;
3997 else if (selnum == Sel_Secondary)
3998 sel = XA_SECONDARY;
3999 else
4000 sel = r->h->xa[XA_CLIPBOARD];
4001 if (XGetSelectionOwner(r->Xdisplay, sel) != None) {
4002 DBG_MSG(2,(stderr, "rxvt_selection_request_other %d: pasting %s\n", page, debug_xa_names[selnum]));
4003
4004 XConvertSelection(r->Xdisplay, sel, target,
4005 r->h->xa[XA_VT_SELECTION], PVTS(r, page)->vt,
4006 r->h->selection_request_time);
4007 return 1;
4008 }
4009 return 0;
4010 }
4011
4012
4013 /* ------------------------------------------------------------------------- */
4014 /*
4015 * Clear all selected text
4016 * EXT: SelectionClear
4017 */
4018 /* EXTPROTO */
4019 void
4020 rxvt_process_selectionclear(rxvt_t* r, int page)
4021 {
4022 DBG_MSG(2,(stderr, "rxvt_process_selectionclear %d ()\n", page));
4023
4024 r->h->want_refresh = 1;
4025 if (SEL(r).text)
4026 free(SEL(r).text);
4027 SEL(r).text = NULL;
4028 SEL(r).len = 0;
4029 CLEAR_SELECTION(r);
4030 SEL(r).vt = -1;
4031
4032 SEL(r).op = SELECTION_CLEAR;
4033 SEL(r).screen = PRIMARY;
4034 SEL(r).clicks = 0;
4035 }
4036
4037
4038 /* ------------------------------------------------------------------------- */
4039 /*
4040 * Copy a selection into the cut buffer
4041 * EXT: button 1 or 3 release
4042 */
4043 /* EXTPROTO */
4044 void
4045 rxvt_selection_make(rxvt_t* r, int page, Time tm)
4046 {
4047 int i, col, end_col, row, end_row;
4048 unsigned char* new_selection_text;
4049 unsigned char* str;
4050 text_t* t;
4051 #ifdef MULTICHAR_SET
4052 rend_t* tr;
4053 #endif
4054 #ifdef ACS_ASCII
4055 rend_t* re;
4056 #endif
4057
4058 DBG_MSG(2,(stderr, "rxvt_selection_make %d (): sel.op=%d, sel.clicks=%d\n", page, SEL(r).op, SEL(r).clicks));
4059 switch (SEL(r).op) {
4060 case SELECTION_CONT:
4061 break;
4062 case SELECTION_INIT:
4063 CLEAR_SELECTION(r);
4064 /* FALLTHROUGH */
4065 case SELECTION_BEGIN:
4066 SEL(r).op = SELECTION_DONE;
4067 /* FALLTHROUGH */
4068 default:
4069 return;
4070 }
4071 SEL(r).op = SELECTION_DONE;
4072 SEL(r).vt = page; /* update selection vt */
4073
4074 if (SEL(r).clicks == 4)
4075 return; /* nothing selected, go away */
4076
4077 assert ((SEL(r).end.row - SEL(r).beg.row + 1) > 0);
4078 assert ((r->TermWin.ncol + 1) > 0);
4079 i = (SEL(r).end.row - SEL(r).beg.row + 1)
4080 * (r->TermWin.ncol + 1) + 1;
4081 /* possible integer overflow? */
4082 assert (i > 0);
4083 str = rxvt_malloc(i * sizeof(char));
4084
4085 new_selection_text = (unsigned char *)str;
4086
4087 col = SEL(r).beg.col;
4088 MAX_IT(col, 0);
4089 row = SEL(r).beg.row + SVLINES;
4090 end_row = SEL(r).end.row + SVLINES;
4091
4092 /*
4093 ** A: rows before end row
4094 */
4095 for (; row < end_row; row++, col = 0) {
4096 t = &(PSCR(r, page).text[row][col]);
4097 #ifdef MULTICHAR_SET
4098 tr = &(PSCR(r, page).rend[row][col]);
4099 #endif /* MULTICHAR_SET */
4100 #ifdef ACS_ASCII
4101 re = &(PSCR(r, page).rend[row][col]);
4102 #endif
4103 if ((end_col = PSCR(r, page).tlen[row]) == -1)
4104 end_col = r->TermWin.ncol;
4105
4106
4107 /*
4108 ** Looks like a completely mess. Think about the logic here
4109 ** carefully. ;-)
4110 ** Patch source:
4111 ** http://gentoo.nedlinux.nl/distfiles/rxvt-2.7.10-rk.patch
4112 */
4113 for (; col < end_col; col++, str++, t++) {
4114 #ifdef MULTICHAR_SET
4115 if ((ENC_EUCJ == r->encoding_method) &&
4116 (*t & 0x80) &&
4117 !(*tr & RS_multiMask)) {
4118 *str++ = 0x8E;
4119 tr ++;
4120 }
4121 #endif /* MULTICHAR_SET */
4122 #ifdef ACS_ASCII
4123 if ((*re++ & RS_acsFont) && *t >= 0x60 && *t < 0x80)
4124 *str = r->h->rs[Rs_acs_chars][(*t) - 0x60];
4125 else
4126 #endif /* ACS_ASCII */
4127 *str = *t;
4128 }
4129
4130
4131 if (PSCR(r, page).tlen[row] != -1) {
4132 #ifdef DONT_SELECT_TRAILING_SPACES
4133 STRIP_TRAILING_SPACE(str, new_selection_text);
4134 #endif
4135 *str++ = '\n';
4136 }
4137 }
4138
4139 /*
4140 ** B: end row
4141 */
4142 t = &(PSCR(r, page).text[row][col]);
4143 #ifdef MULTICHAR_SET
4144 tr = &(PSCR(r, page).rend[row][col]);
4145 #endif /* MULTICHAR_SET */
4146 #ifdef ACS_ASCII
4147 re = &(PSCR(r, page).rend[row][col]);
4148 #endif
4149 end_col = PSCR(r, page).tlen[row];
4150 if (end_col == -1 || SEL(r).end.col <= end_col)
4151 end_col = SEL(r).end.col;
4152 MIN_IT(end_col, r->TermWin.ncol); /* CHANGE */
4153
4154
4155 /*
4156 ** Looks like a completely mess. Think about the logic here
4157 ** carefully. ;-)
4158 ** Patch source:
4159 ** http://gentoo.nedlinux.nl/distfiles/rxvt-2.7.10-rk.patch
4160 */
4161 for (; col < end_col; col++, str++, t++) {
4162 #ifdef MULTICHAR_SET
4163 if ((ENC_EUCJ == r->encoding_method) &&
4164 (*t & 0x80) &&
4165 !(*tr & RS_multiMask)) {
4166 *str++ = 0x8E;
4167 tr ++;
4168 }
4169 #endif /* MULTICHAR_SET */
4170 #ifdef ACS_ASCII
4171 if ((*re++ & RS_acsFont) && *t >= 0x60 && *t < 0x80)
4172 *str = r->h->rs[Rs_acs_chars][(*t) - 0x60];
4173 else
4174 #endif /* ACS_ASCII */
4175 *str = *t;
4176 }
4177
4178 #ifdef DONT_SELECT_TRAILING_SPACES
4179 STRIP_TRAILING_SPACE(str, new_selection_text);
4180 #endif
4181
4182
4183 #ifndef NO_OLD_SELECTION
4184 if (r->selection_style == OLD_SELECT)
4185 if (end_col == r->TermWin.ncol) {
4186 *str++ = '\n';
4187 }
4188 #endif
4189 #ifndef NO_NEW_SELECTION
4190 if (r->selection_style != OLD_SELECT)
4191 if (end_col != SEL(r).end.col) {
4192 *str++ = '\n';
4193 }
4194 #endif
4195 *str = '\0';
4196 if ((i = STRLEN((char *)new_selection_text)) == 0) {
4197 free(new_selection_text);
4198 return;
4199 }
4200 SEL(r).len = i;
4201 if (SEL(r).text)
4202 free(SEL(r).text);
4203 SEL(r).text = new_selection_text;
4204
4205 XSetSelectionOwner(r->Xdisplay, XA_PRIMARY, PVTS(r, page)->vt, tm);
4206 if (XGetSelectionOwner(r->Xdisplay, XA_PRIMARY) != PVTS(r, page)->vt)
4207 rxvt_print_error("can't get primary selection");
4208 XChangeProperty(r->Xdisplay, XROOT, XA_CUT_BUFFER0, XA_STRING, 8,
4209 PropModeReplace, SEL(r).text, (int)SEL(r).len);
4210 r->h->selection_time = tm;
4211 DBG_MSG(2,(stderr, "rxvt_selection_make %d (): sel.len=%d\n", page, SEL(r).len));
4212 DBG_MSG(1,(stderr, "sel.text=%s\n", SEL(r).text));
4213 }
4214
4215
4216 /* ------------------------------------------------------------------------- */
4217 /*
4218 * Mark or select text based upon number of clicks: 1, 2, or 3
4219 * EXT: button 1 press
4220 */
4221 /* EXTPROTO */
4222 void
4223 rxvt_selection_click(rxvt_t* r, int page, int clicks, int x, int y)
4224 {
4225 DBG_MSG(2,(stderr, "rxvt_selection_click %d (%d, %d, %d)\n", page, clicks, x, y));
4226
4227 SEL(r).vt = page;
4228 clicks = ((clicks - 1) % 3) + 1;
4229 SEL(r).clicks = clicks; /* save clicks so extend will work */
4230
4231 #ifdef THAI
4232 if (r->Options & Opt_thai)
4233 rxvt_selection_start_colrow(r, page, ThaiPixel2Col(r, page, x,y), Pixel2Row(y));
4234 else
4235 #endif /* THAI */
4236 rxvt_selection_start_colrow(r, page, Pixel2Col(x), Pixel2Row(y));
4237
4238 if (clicks == 2 || clicks == 3)
4239 rxvt_selection_extend_colrow(r, page, SEL(r).mark.col,
4240 SEL(r).mark.row + VSTART,
4241 0, /* button 3 */
4242 1, /* button press */
4243 0); /* click change */
4244 }
4245
4246
4247 /* ------------------------------------------------------------------------- */
4248 /*
4249 * Mark a selection at the specified col/row
4250 */
4251 /* INTPROTO */
4252 void
4253 rxvt_selection_start_colrow(rxvt_t* r, int page, int col, int row)
4254 {
4255 r->h->want_refresh = 1;
4256 SEL(r).mark.col = col;
4257 SEL(r).mark.row = row - VSTART;
4258 MAX_IT(SEL(r).mark.row, -(RINT32T)PVTS(r, page)->nscrolled);
4259 MIN_IT(SEL(r).mark.row, (RINT32T)r->TermWin.nrow - 1);
4260 MAX_IT(SEL(r).mark.col, 0);
4261 MIN_IT(SEL(r).mark.col, (RINT32T)r->TermWin.ncol - 1);
4262
4263 if (SEL(r).op) {
4264 /* clear the old selection */
4265 SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
4266 SEL(r).beg.col = SEL(r).end.col = SEL(r).mark.col;
4267 }
4268 SEL(r).op = SELECTION_INIT;
4269 SEL(r).screen = PVTS(r, page)->current_screen;
4270 r->selection.vt = page;
4271 }
4272
4273
4274 /* ------------------------------------------------------------------------- */
4275 /*
4276 * Word select: select text for 2 clicks
4277 * We now only find out the boundary in one direction
4278 */
4279
4280 /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
4281 #define DELIMIT_TEXT(x) \
4282 (((x) == ' ' || (x) == '\t') ? 2 : (STRCHR(r->h->rs[Rs_cutchars], (x)) != NULL))
4283 #ifdef MULTICHAR_SET
4284 # define DELIMIT_REND(x) (((x) & RS_multiMask) ? 1 : 0)
4285 #else
4286 # define DELIMIT_REND(x) 1
4287 #endif
4288
4289 /* INTPROTO */
4290 void
4291 rxvt_selection_delimit_word(rxvt_t* r, int page, enum page_dirn dirn, const row_col_t *mark, row_col_t *ret)
4292 {
4293 int col, row, dirnadd, tcol, trow, w1, w2;
4294 row_col_t bound;
4295 text_t *stp;
4296 rend_t *srp;
4297
4298
4299 r->selection.vt = page; /* update selection vt */
4300
4301 if (dirn == UP) {
4302 bound.row = SVLINES - PVTS(r, page)->nscrolled - 1;
4303 bound.col = 0;
4304 dirnadd = -1;
4305 }
4306 else {
4307 bound.row = SVLINES + r->TermWin.nrow;
4308 bound.col = r->TermWin.ncol - 1;
4309 dirnadd = 1;
4310 }
4311 row = mark->row + SVLINES;
4312 col = mark->col;
4313 MAX_IT(col, 0);
4314 /* find the edge of a word */
4315 stp = &(PSCR(r, page).text[row][col]);
4316 w1 = DELIMIT_TEXT(*stp);
4317
4318 if (r->selection_style != NEW_SELECT) {
4319 if (w1 == 1) {
4320 stp += dirnadd;
4321 if (DELIMIT_TEXT(*stp) == 1)
4322 goto Old_Word_Selection_You_Die;
4323 col += dirnadd;
4324 }
4325 w1 = 0;
4326 }
4327 srp = (&PSCR(r, page).rend[row][col]);
4328 w2 = DELIMIT_REND(*srp);
4329
4330 for (;;) {
4331 for (; col != bound.col; col += dirnadd) {
4332 stp += dirnadd;
4333 if (DELIMIT_TEXT(*stp) != w1)
4334 break;
4335 srp += dirnadd;
4336 if (DELIMIT_REND(*srp) != w2)
4337 break;
4338 }
4339 if ((col == bound.col) && (row != bound.row)) {
4340 if (PSCR(r, page).tlen[(row - (dirn == UP ? 1 : 0))] == -1) {
4341 trow = row + dirnadd;
4342 tcol = dirn == UP ? r->TermWin.ncol - 1 : 0;
4343 if (PSCR(r, page).text[trow] == NULL)
4344 break;
4345 stp = &(PSCR(r, page).text[trow][tcol]);
4346 srp = &(PSCR(r, page).rend[trow][tcol]);
4347 if (DELIMIT_TEXT(*stp) != w1 ||
4348 DELIMIT_REND(*srp) != w2)
4349 break;
4350 row = trow;
4351 col = tcol;
4352 continue;
4353 }
4354 }
4355 break;
4356 }
4357
4358 Old_Word_Selection_You_Die:
4359 DBG_MSG(2,(stderr, "rxvt_selection_delimit_word %d (%s,...) @ (r:%3d, c:%3d) has boundary (r:%3d, c:%3d)\n", page, (dirn == UP ? "up " : "down"), mark->row, mark->col, row - SVLINES, col));
4360
4361 if (dirn == DN)
4362 col++; /* put us on one past the end */
4363
4364 /* Poke the values back in */
4365 ret->row = row - SVLINES;
4366 ret->col = col;
4367 }
4368
4369
4370 /* ------------------------------------------------------------------------- */
4371 /*
4372 * Extend the selection to the specified x/y pixel location
4373 * EXT: button 3 press; button 1 or 3 drag
4374 * flag == 0 ==> button 1
4375 * flag == 1 ==> button 3 press
4376 * flag == 2 ==> button 3 motion
4377 */
4378 /* EXTPROTO */
4379 void
4380 rxvt_selection_extend(rxvt_t* r, int page, int x, int y, int flag)
4381 {
4382 int col, row;
4383
4384 #ifdef THAI
4385 if (r->Options & Opt_thai)
4386 col = ThaiPixel2Col(r, page, x, y);
4387 else
4388 #endif /* THAI */
4389 col = Pixel2Col(x);
4390 row = Pixel2Row(y);
4391 MAX_IT(row, 0);
4392 MIN_IT(row, (int)r->TermWin.nrow - 1);
4393 MAX_IT(col, 0);
4394 MIN_IT(col, (int)r->TermWin.ncol);
4395
4396 #ifndef NO_NEW_SELECTION
4397 /*
4398 * If we're selecting characters (single click) then we must check first
4399 * if we are at the same place as the original mark. If we are then
4400 * select nothing. Otherwise, if we're to the right of the mark, you have to
4401 * be _past_ a character for it to be selected.
4402 */
4403 if (r->selection_style != OLD_SELECT) {
4404 if (((SEL(r).clicks % 3) == 1) &&
4405 !flag &&
4406 (col == SEL(r).mark.col && (row == SEL(r).mark.row + VSTART))) {
4407 /* select nothing */
4408 SEL(r).beg.row = SEL(r).end.row = 0;
4409 SEL(r).beg.col = SEL(r).end.col = 0;
4410 SEL(r).clicks = 4;
4411 r->h->want_refresh = 1;
4412 DBG_MSG(2,(stderr, "rxvt_selection_extend %d () sel.clicks = 4\n", page));
4413 return;
4414 }
4415 }
4416 #endif
4417 if (SEL(r).clicks == 4)
4418 SEL(r).clicks = 1;
4419 rxvt_selection_extend_colrow(r, page, col, row, !!flag,
4420 /* ? button 3 */
4421 flag == 1 ? 1 : 0, /* ? button press */
4422 0); /* no click change */
4423 }
4424
4425
4426 #ifdef MULTICHAR_SET
4427 /* INTPROTO */
4428 void
4429 rxvt_selection_adjust_kanji(rxvt_t* r, int page)
4430 {
4431 int c1, r1;
4432
4433 if (SEL(r).beg.col > 0) {
4434 r1 = SEL(r).beg.row + SVLINES;
4435 c1 = SEL(r).beg.col;
4436 if (IS_MULTI2(PSCR(r, page).rend[r1][c1]) &&
4437 IS_MULTI1(PSCR(r, page).rend[r1][c1 - 1]))
4438 SEL(r).beg.col--;
4439 }
4440 if (SEL(r).end.col < r->TermWin.ncol) {
4441 r1 = SEL(r).end.row + SVLINES;
4442 c1 = SEL(r).end.col;
4443 if (IS_MULTI1(PSCR(r, page).rend[r1][c1 - 1]) &&
4444 IS_MULTI2(PSCR(r, page).rend[r1][c1]))
4445 SEL(r).end.col++;
4446 }
4447 }
4448 #endif /* MULTICHAR_SET */
4449
4450
4451 /* ------------------------------------------------------------------------- */
4452 /*
4453 * Extend the selection to the specified col/row
4454 */
4455 /* INTPROTO */
4456 void
4457 rxvt_selection_extend_colrow(rxvt_t* r, int page, RINT32T col, RINT32T row, int button3, int buttonpress, int clickchange)
4458 {
4459 unsigned int ncol = r->TermWin.ncol;
4460 row_col_t pos;
4461 #ifndef NO_NEW_SELECTION
4462 int end_col;
4463 enum {
4464 LEFT, RIGHT
4465 } closeto = RIGHT;
4466 #endif
4467
4468
4469 DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d (c:%d, r:%d, %d, %d) clicks:%d, op:%d\n", page, col, row, button3, buttonpress, SEL(r).clicks, SEL(r).op));
4470 DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () ENT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4471
4472 r->h->want_refresh = 1;
4473 switch (SEL(r).op) {
4474 case SELECTION_INIT:
4475 CLEAR_SELECTION(r);
4476 SEL(r).op = SELECTION_BEGIN;
4477 /* FALLTHROUGH */
4478 case SELECTION_BEGIN:
4479 if (row != SEL(r).mark.row ||
4480 col != SEL(r).mark.col ||
4481 (!button3 && buttonpress))
4482 SEL(r).op = SELECTION_CONT;
4483 break;
4484 case SELECTION_DONE:
4485 SEL(r).op = SELECTION_CONT;
4486 /* FALLTHROUGH */
4487 case SELECTION_CONT:
4488 break;
4489 case SELECTION_CLEAR:
4490 rxvt_selection_start_colrow(r, page, col, row);
4491 /* FALLTHROUGH */
4492 default:
4493 return;
4494 }
4495
4496 if (SEL(r).beg.col == SEL(r).end.col &&
4497 SEL(r).beg.col != SEL(r).mark.col &&
4498 SEL(r).beg.row == SEL(r).end.row &&
4499 SEL(r).beg.row != SEL(r).mark.row) {
4500 SEL(r).beg.col = SEL(r).end.col = SEL(r).mark.col;
4501 SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
4502 DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () ENT2 b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4503 }
4504
4505 pos.col = col;
4506 pos.row = row;
4507
4508 pos.row -= VSTART; /* adjust for scroll */
4509
4510
4511 #ifndef NO_OLD_SELECTION
4512 /*
4513 ** This mimics some of the selection behaviour of version 2.20
4514 ** and before.
4515 ** There are no ``selection modes'', button3 is always character
4516 ** extension.
4517 ** Note: button3 drag is always available, c.f. v2.20
4518 ** Selection always terminates (left or right as appropriate) at
4519 ** the mark.
4520 */
4521 if (r->selection_style == OLD_SELECT) {
4522 if (SEL(r).clicks == 1 || button3) {
4523 if (r->h->hate_those_clicks) {
4524 r->h->hate_those_clicks = 0;
4525 if (SEL(r).clicks == 1) {
4526 SEL(r).beg.row = SEL(r).mark.row;
4527 SEL(r).beg.col = SEL(r).mark.col;
4528 }
4529 else {
4530 SEL(r).mark.row = SEL(r).beg.row;
4531 SEL(r).mark.col = SEL(r).beg.col;
4532 }
4533 }
4534
4535 if (RC_BEFORE(pos, SEL(r).mark)) {
4536 SEL(r).end.row = SEL(r).mark.row;
4537 SEL(r).end.col = SEL(r).mark.col + 1;
4538 SEL(r).beg.row = pos.row;
4539 SEL(r).beg.col = pos.col;
4540 }
4541 else {
4542 SEL(r).beg.row = SEL(r).mark.row;
4543 SEL(r).beg.col = SEL(r).mark.col;
4544 SEL(r).end.row = pos.row;
4545 SEL(r).end.col = pos.col + 1;
4546 }
4547 # ifdef MULTICHAR_SET
4548 rxvt_selection_adjust_kanji(r, page);
4549 # endif /* MULTICHAR_SET */
4550 }
4551 else if (SEL(r).clicks == 2) {
4552 rxvt_selection_delimit_word(r, page, UP, &(SEL(r).mark),
4553 &(SEL(r).beg));
4554 rxvt_selection_delimit_word(r, page, DN, &(SEL(r).mark),
4555 &(SEL(r).end));
4556 r->h->hate_those_clicks = 1;
4557 }
4558 else if (SEL(r).clicks == 3) {
4559 SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
4560 SEL(r).beg.col = 0;
4561 SEL(r).end.col = ncol;
4562 r->h->hate_those_clicks = 1;
4563 }
4564
4565 DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4566 return;
4567 }
4568 #endif /* ! NO_OLD_SELECTION */
4569
4570
4571 #ifndef NO_NEW_SELECTION
4572 /* selection_style must not be OLD_SELECT to get here */
4573 /*
4574 ** This is mainly xterm style selection with a couple of
4575 ** differences, mainly in the way button3 drag extension
4576 ** works.
4577 ** We're either doing: button1 drag; button3 press; or
4578 ** button3 drag
4579 ** a) button1 drag : select around a midpoint/word/line -
4580 ** that point/word/line is always at the left/right edge
4581 ** of the SEL(r).
4582 ** b) button3 press: extend/contract character/word/line
4583 ** at whichever edge of the selection we are closest to.
4584 ** c) button3 drag : extend/contract character/word/line
4585 ** - we select around a point/word/line which is either
4586 ** the start or end of the selection and it was decided
4587 ** by whichever point/word/line was `fixed' at the time
4588 ** of the most recent button3 press
4589 */
4590 if (button3 && buttonpress) { /* button3 press */
4591 /* first determine which edge of the selection we are
4592 ** closest to
4593 */
4594 if (RC_BEFORE(pos, SEL(r).beg) ||
4595 (!RC_AFTER(pos, SEL(r).end) &&
4596 (((pos.col - SEL(r).beg.col) +
4597 ((pos.row - SEL(r).beg.row) * ncol)) <
4598 ((SEL(r).end.col - pos.col) +
4599 ((SEL(r).end.row - pos.row) * ncol)))))
4600 closeto = LEFT;
4601
4602 if (closeto == LEFT) {
4603 SEL(r).beg.row = pos.row;
4604 SEL(r).beg.col = pos.col;
4605 SEL(r).mark.row = SEL(r).end.row;
4606 SEL(r).mark.col = SEL(r).end.col
4607 - (SEL(r).clicks == 2);
4608 }
4609 else {
4610 SEL(r).end.row = pos.row;
4611 SEL(r).end.col = pos.col;
4612 SEL(r).mark.row = SEL(r).beg.row;
4613 SEL(r).mark.col = SEL(r).beg.col;
4614 }
4615 }
4616 else { /* button1 drag or button3 drag */
4617 if (RC_AFTER(SEL(r).mark, pos)) {
4618 if ((SEL(r).mark.row == SEL(r).end.row) &&
4619 (SEL(r).mark.col == SEL(r).end.col) &&
4620 clickchange && SEL(r).clicks == 2)
4621 SEL(r).mark.col--;
4622 SEL(r).beg.row = pos.row;
4623 SEL(r).beg.col = pos.col;
4624 SEL(r).end.row = SEL(r).mark.row;
4625 SEL(r).end.col = SEL(r).mark.col
4626 + (SEL(r).clicks == 2);
4627 }
4628 else {
4629 SEL(r).beg.row = SEL(r).mark.row;
4630 SEL(r).beg.col = SEL(r).mark.col;
4631 SEL(r).end.row = pos.row;
4632 SEL(r).end.col = pos.col;
4633 }
4634 }
4635
4636
4637 if (SEL(r).clicks == 1) {
4638 end_col = PSCR(r, page).tlen[SEL(r).beg.row +
4639 SVLINES];
4640 if (end_col != -1 && SEL(r).beg.col > end_col) {
4641 #if 1
4642 SEL(r).beg.col = ncol;
4643 #else
4644 if (SEL(r).beg.row != SEL(r).end.row)
4645 SEL(r).beg.col = ncol;
4646 else
4647 SEL(r).beg.col = SEL(r).mark.col;
4648 #endif
4649 }
4650 end_col = PSCR(r, page).tlen[SEL(r).end.row +
4651 SVLINES];
4652 if (end_col != -1 && SEL(r).end.col > end_col)
4653 SEL(r).end.col = ncol;
4654
4655 # ifdef MULTICHAR_SET
4656 rxvt_selection_adjust_kanji(r, page);
4657 # endif /* MULTICHAR_SET */
4658 }
4659 else if (SEL(r).clicks == 2) {
4660 if (RC_AFTER(SEL(r).end, SEL(r).beg))
4661 SEL(r).end.col--;
4662 rxvt_selection_delimit_word(r, page, UP, &(SEL(r).beg),
4663 &(SEL(r).beg));
4664 rxvt_selection_delimit_word(r, page, DN, &(SEL(r).end),
4665 &(SEL(r).end));
4666 }
4667 else if (SEL(r).clicks == 3) {
4668 #ifndef NO_FRILLS
4669 if ((r->Options & Opt_tripleclickwords)) {
4670 int end_row;
4671
4672 rxvt_selection_delimit_word(r, page, UP, &(SEL(r).beg),
4673 &(SEL(r).beg));
4674 end_row = PSCR(r, page).tlen[SEL(r).mark.row +
4675 SVLINES];
4676 for (end_row = SEL(r).mark.row;
4677 end_row < r->TermWin.nrow; end_row++) {
4678 end_col = PSCR(r, page).tlen[end_row +
4679 SVLINES];
4680 if (end_col != -1) {
4681 SEL(r).end.row = end_row;
4682 SEL(r).end.col = end_col;
4683 rxvt_selection_trim(r, page);
4684 break;
4685 }
4686 } /* for */
4687 }
4688 else
4689 #endif
4690 {
4691 if (RC_AFTER(SEL(r).mark, SEL(r).beg))
4692 SEL(r).mark.col++;
4693 SEL(r).beg.col = 0;
4694 SEL(r).end.col = ncol;
4695 }
4696 } /* if ((r->Options & Opt_tripleclickwords)) */
4697
4698 if (button3 && buttonpress) {
4699 /* mark may need to be changed */
4700 if (closeto == LEFT) {
4701 SEL(r).mark.row = SEL(r).end.row;
4702 SEL(r).mark.col = SEL(r).end.col - (SEL(r).clicks == 2);
4703 }
4704 else {
4705 SEL(r).mark.row = SEL(r).beg.row;
4706 SEL(r).mark.col = SEL(r).beg.col;
4707 }
4708 }
4709
4710 DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4711
4712 #endif /* ! NO_NEW_SELECTION */
4713 }
4714
4715
4716 #ifndef NO_FRILLS
4717 /* INTPROTO */
4718 void
4719 rxvt_selection_trim(rxvt_t* r, int page)
4720 {
4721 RINT32T end_col, end_row;
4722 text_t *stp;
4723
4724 end_col = SEL(r).end.col;
4725 end_row = SEL(r).end.row;
4726 for ( ; end_row >= SEL(r).beg.row; ) {
4727 stp = PSCR(r, page).text[end_row + SVLINES];
4728 while (--end_col >= 0) {
4729 if (stp[end_col] != ' ' && stp[end_col] != '\t')
4730 break;
4731 }
4732 if (end_col >= 0 ||
4733 PSCR(r, page).tlen[end_row - 1 + SVLINES] != -1) {
4734 SEL(r).end.col = end_col + 1;
4735 SEL(r).end.row = end_row;
4736 break;
4737 }
4738 end_row--;
4739 end_col = r->TermWin.ncol;
4740 }
4741
4742 if (SEL(r).mark.row > SEL(r).end.row) {
4743 SEL(r).mark.row = SEL(r).end.row;
4744 SEL(r).mark.col = SEL(r).end.col;
4745 }
4746 else if (SEL(r).mark.row == SEL(r).end.row &&
4747 SEL(r).mark.col > SEL(r).end.col)
4748 SEL(r).mark.col = SEL(r).end.col;
4749 }
4750 #endif
4751
4752
4753 /* ------------------------------------------------------------------------- */
4754 /*
4755 * Double click on button 3 when already selected
4756 * EXT: button 3 double click
4757 */
4758 /* EXTPROTO */
4759 void
4760 rxvt_selection_rotate(rxvt_t* r, int page, int x, int y)
4761 {
4762 SEL(r).clicks = SEL(r).clicks % 3 + 1;
4763
4764 #ifdef THAI
4765 if (r->Options & Opt_thai)
4766 rxvt_selection_extend_colrow(r, page,
4767 ThaiPixel2Col (r, page, x, y), Pixel2Row (y), 1, 0, 1);
4768 else
4769 #endif /* THAI */
4770 rxvt_selection_extend_colrow (r, page, Pixel2Col(x),
4771 Pixel2Row(y), 1, 0, 1);
4772 }
4773
4774
4775
4776 /* ------------------------------------------------------------------------- */
4777 /*
4778 * Respond to a request for our current selection
4779 * EXT: SelectionRequest
4780 */
4781 /* EXTPROTO */
4782 void
4783 rxvt_process_selectionrequest (rxvt_t* r, int page, const XSelectionRequestEvent *rq)
4784 {
4785 XSelectionEvent ev;
4786 #ifdef USE_XIM
4787 Atom target_list[4];
4788 #else
4789 Atom target_list[3];
4790 #endif
4791 Atom target;
4792 XTextProperty ct;
4793 XICCEncodingStyle style;
4794 char *cl[2], dummy[1];
4795
4796 ev.type = SelectionNotify;
4797 ev.property = None;
4798 ev.display = rq->display;
4799 ev.requestor = rq->requestor;
4800 ev.selection = rq->selection;
4801 ev.target = rq->target;
4802 ev.time = rq->time;
4803
4804 if (rq->target == r->h->xa[XA_TARGETS]) {
4805 target_list[0] = r->h->xa[XA_TARGETS];
4806 target_list[1] = XA_STRING;
4807 target_list[2] = r->h->xa[XA_TEXT];
4808 #ifdef USE_XIM
4809 target_list[3] = r->h->xa[XA_COMPOUND_TEXT];
4810 #endif
4811 XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
4812 XA_ATOM, 32, PropModeReplace,
4813 (unsigned char *)target_list,
4814 (sizeof(target_list) / sizeof(target_list[0])));
4815 ev.property = rq->property;
4816 }
4817 else if (rq->target == r->h->xa[XA_MULTIPLE]) {
4818 /* TODO: Handle MULTIPLE */
4819 }
4820 else if (rq->target == r->h->xa[XA_TIMESTAMP] && SEL(r).text) {
4821 XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
4822 XA_INTEGER,
4823 sizeof(Time) > 4 ? 32 : (8 * sizeof(Time)),
4824 PropModeReplace, (unsigned char*)&r->h->selection_time,
4825 sizeof(Time) > 4 ? sizeof(Time)/4 : 1);
4826 ev.property = rq->property;
4827 }
4828 else if (rq->target == XA_STRING ||
4829 rq->target == r->h->xa[XA_COMPOUND_TEXT] ||
4830 rq->target == r->h->xa[XA_TEXT]) {
4831 #ifdef USE_XIM
4832 short freect = 0;
4833 #endif
4834 int selectlen;
4835
4836 #ifdef USE_XIM
4837 if (rq->target != XA_STRING) {
4838 target = r->h->xa[XA_COMPOUND_TEXT];
4839 style = (rq->target == r->h->xa[XA_COMPOUND_TEXT])
4840 ? XCompoundTextStyle : XStdICCTextStyle;
4841 } else
4842 #endif
4843 {
4844 target = XA_STRING;
4845 style = XStringStyle;
4846 }
4847 if (SEL(r).text) {
4848 cl[0] = (char *)SEL(r).text;
4849 selectlen = SEL(r).len;
4850 }
4851 else {
4852 cl[0] = dummy;
4853 *dummy = '\0';
4854 selectlen = 0;
4855 }
4856 #ifdef USE_XIM
4857 if (XmbTextListToTextProperty(r->Xdisplay, cl, 1, style, &ct) == Success) /* if we failed to convert then send it raw */
4858 freect = 1;
4859 else
4860 #endif
4861 {
4862 ct.value = (unsigned char *)cl[0];
4863 ct.nitems = selectlen;
4864 }
4865 XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
4866 target, 8, PropModeReplace,
4867 ct.value, (int)ct.nitems);
4868 ev.property = rq->property;
4869 #ifdef USE_XIM
4870 if (freect)
4871 XFree(ct.value);
4872 #endif
4873 }
4874 XSendEvent(r->Xdisplay, rq->requestor, False, 0L, (XEvent *)&ev);
4875 }
4876
4877 /* ------------------------------------------------------------------------- *
4878 * MOUSE ROUTINES *
4879 * ------------------------------------------------------------------------- */
4880
4881 /*
4882 * return col/row values corresponding to x/y pixel values
4883 */
4884 /* EXTPROTO */
4885 void
4886 rxvt_pixel_position(rxvt_t* r, int *x, int *y)
4887 {
4888 #ifdef THAI
4889 if (r->Options & Opt_thai)
4890 *x = ThaiPixel2Col(r, ATAB(r), *x, *y);
4891 else
4892 #endif /* THAI */
4893 *x = Pixel2Col(*x);
4894 /* MAX_IT(*x, 0); MIN_IT(*x, (int)r->TermWin.ncol - 1); */
4895 *y = Pixel2Row(*y);
4896 /* MAX_IT(*y, 0); MIN_IT(*y, (int)r->TermWin.nrow - 1); */
4897 }
4898
4899
4900 /* ------------------------------------------------------------------------- */
4901 #ifdef USE_XIM
4902 /* EXTPROTO */
4903 void
4904 rxvt_setPosition(rxvt_t* r, XPoint *pos)
4905 {
4906 XWindowAttributes xwa;
4907
4908 XGetWindowAttributes(r->Xdisplay, AVTS(r)->vt, &xwa);
4909 pos->x = Col2Pixel(ASCR(r).cur.col) + xwa.x;
4910 pos->y = Height2Pixel((ASCR(r).cur.row + 1)) + xwa.y;
4911 #ifndef NO_LINESPACE
4912 pos->y -= r->TermWin.lineSpace;
4913 #endif
4914 }
4915 #endif
4916 /* ------------------------------------------------------------------------- */
4917
4918 /* ------------------------------------------------------------------------- *
4919 * DEBUG ROUTINES *
4920 * ------------------------------------------------------------------------- */
4921 #if 0
4922 /* INTPROTO */
4923 void
4924 rxvt_debug_colors(void)
4925 {
4926 int color;
4927 const char *name[] = {
4928 "fg", "bg",
4929 "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"
4930 };
4931
4932 fprintf(stderr, "Color ( ");
4933 if (PVTS(r, page)->rstyle & RS_RVid)
4934 fprintf(stderr, "rvid ");
4935 if (PVTS(r, page)->rstyle & RS_Bold)
4936 fprintf(stderr, "bold ");
4937 if (PVTS(r, page)->rstyle & RS_Blink)
4938 fprintf(stderr, "blink ");
4939 if (PVTS(r, page)->rstyle & RS_Uline)
4940 fprintf(stderr, "uline ");
4941 fprintf(stderr, "): ");
4942
4943 color = GET_FGCOLOR(PVTS(r, page)->rstyle);
4944 #ifndef NO_BRIGHTCOLOR
4945 if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
4946 color -= (minBrightCOLOR - minCOLOR);
4947 fprintf(stderr, "bright ");
4948 }
4949 #endif
4950 fprintf(stderr, "%s on ", name[color]);
4951
4952 color = GET_BGCOLOR(PVTS(r, page)->rstyle);
4953 #ifndef NO_BRIGHTCOLOR
4954 if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
4955 color -= (minBrightCOLOR - minCOLOR);
4956 fprintf(stderr, "bright ");
4957 }
4958 #endif
4959 fprintf(stderr, "%s\n", name[color]);
4960 }
4961 #endif
4962 /*----------------------- end-of-file (C source) -----------------------*/
4963