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-2006 Jingmin Zhou <jimmyzhou@users.sourceforge.net>
14 * Copyright (c) 2005-2006 Gautam Iyer <gi1242@users.sourceforge.net>
15 * Copyright (c) 2007 Jehan Hysseo <hysseo@users.sourceforge.net>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 *----------------------------------------------------------------------*/
31
32 #include "../config.h"
33 #define INTERN_SCREEN
34 #include "rxvt.h"
35
36 #ifdef XFT_SUPPORT
37 # include <xftacs.h>
38 #endif
39
40 #ifdef HAVE_WORDEXP_H
41 # include <wordexp.h>
42 #endif
43
44 /* ------------------------------------------------------------------------- */
45 #ifdef MULTICHAR_SET
46 #define RESET_CHSTAT(R, P) \
47 if (PVTS((R),(P))->chstat == WBYTE) \
48 PVTS((R),(P))->chstat = SBYTE, PVTS((R),(P))->lost_multi = 1
49 #else
50 # define RESET_CHSTAT(R, P)
51 #endif
52
53 /* ------------------------------------------------------------------------- */
54 #define PROP_SIZE 16384
55
56 /* ------------------------------------------------------------------------- *
57 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
58 * ------------------------------------------------------------------------- */
59
60 /*
61 ** If inhibit scrolling on tty output, we should keep the view_start.
62 ** Otherwise, we set it to zero.
63 */
64 #define ZERO_SCROLLBACK(R, P) \
65 if (NOTSET_OPTION(R, Opt_scrollTtyOutputInhibit)) \
66 (R)->vts[(P)]->view_start = 0
67
68 #define CLEAR_SELECTION(R) \
69 (R)->selection.beg.row = \
70 (R)->selection.beg.col = \
71 (R)->selection.end.row = \
72 (R)->selection.end.col = 0
73
74 #define CLEAR_ALL_SELECTION(R) \
75 (R)->selection.beg.row = \
76 (R)->selection.beg.col = \
77 (R)->selection.mark.row = \
78 (R)->selection.mark.col = \
79 (R)->selection.end.row = \
80 (R)->selection.end.col = 0
81
82 #define ROW_AND_COL_IS_AFTER(A, B, C, D) \
83 (((A) > (C)) || (((A) == (C)) && ((B) > (D))))
84 #define ROW_AND_COL_IS_BEFORE(A, B, C, D) \
85 (((A) < (C)) || (((A) == (C)) && ((B) < (D))))
86 #define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D) \
87 (((A) == (C)) && ((B) > (D)))
88 #define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D) \
89 (((A) == (C)) && ((B) >= (D)))
90 #define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D) \
91 (((A) == (C)) && ((B) < (D)))
92 #define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D) \
93 (((A) == (C)) && ((B) <= (D)))
94
95 /* these must be row_col_t */
96 #define RC_AFTER(X, Y) \
97 ROW_AND_COL_IS_AFTER((X).row, (X).col, (Y).row, (Y).col)
98 #define RC_BEFORE(X, Y) \
99 ROW_AND_COL_IS_BEFORE((X).row, (X).col, (Y).row, (Y).col)
100 #define RC_ROW_AFTER(X, Y) \
101 ROW_AND_COL_IN_ROW_AFTER((X).row, (X).col, (Y).row, (Y).col)
102 #define RC_ROW_BEFORE(X, Y) \
103 ROW_AND_COL_IN_ROW_BEFORE((X).row, (X).col, (Y).row, (Y).col)
104 #define RC_ROW_ATAFTER(X, Y) \
105 ROW_AND_COL_IN_ROW_AT_OR_AFTER((X).row, (X).col, (Y).row, (Y).col)
106 #define RC_ROW_ATBEFORE(X, Y) \
107 ROW_AND_COL_IN_ROW_AT_OR_BEFORE((X).row, (X).col, (Y).row, (Y).col)
108
109 /*
110 * CLEAR_ROWS : clear <num> rows starting from row <row>
111 * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
112 * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour
113 */
114 #define drawBuffer (PVTS(r, page)->vt)
115
116 #define CLEAR_ROWS(row, num) \
117 if (r->TermWin.mapped) \
118 rxvt_clear_area (r, page, \
119 r->TermWin.int_bwidth, Row2Pixel(row), \
120 VT_WIDTH(r), (unsigned int)Height2Pixel(num))
121
122
123 /*
124 * If already_cleared, then we got here during a clipped refresh. In this case,
125 * areas we draw into are already cleared by the server. We don't need to clear
126 * it ourself. (Doing so will cause problems under transparency: E.g. We want to
127 * clear an entire character cell, but an expose event was generated for only
128 * half the character cell. By our wonderful clippings, we redraw only half the
129 * char cell. However requests to this function will clear an ENTIRE char cell,
130 * causing problems.
131 *
132 * If garbage is found due to clipped refreshes, then we should explicitly call
133 * XClearArea before generating a clipped refresh.
134 */
135 #define CLEAR_CHARS(r, page, already_cleared, x, y, num) \
136 if( !already_cleared ) \
137 rxvt_clear_area( (r), (page), (x), (y), \
138 (unsigned) Width2Pixel((num)), \
139 (unsigned) Height2Pixel(1));
140
141
142 #define ERASE_ROWS(row, num) \
143 rxvt_fill_rectangle (r, page, \
144 r->TermWin.int_bwidth, Row2Pixel(row), \
145 VT_WIDTH(r), (unsigned int)Height2Pixel(num))
146
147
148 #ifdef DONT_SELECT_TRAILING_SPACES
149 # define STRIP_TRAILING_SPACE(str, fence) \
150 while (str > fence && ' ' == str[-1]) \
151 str --;
152 #endif
153
154
155 /* Here are some simple macros for convenience */
156 #undef CURROW
157 #undef CURCOL
158 #undef SVLINES
159 #undef VSTART
160 #define CURROW (PSCR(r, page).cur.row)
161 #define CURCOL (PSCR(r, page).cur.col)
162 #define SVLINES (PVTS(r, page)->saveLines)
163 #define VSTART (PVTS(r, page)->view_start)
164
165
166 /*--------------------------------------------------------------------*
167 * BEGIN `INTERNAL' ROUTINE PROTOTYPES *
168 *--------------------------------------------------------------------*/
169 void rxvt_blank_line (text_t*, rend_t*, unsigned int, rend_t);
170 void rxvt_blank_screen_mem (rxvt_t*, int, text_t**, rend_t **, unsigned int, rend_t);
171 void rxvt_scr_reset_realloc (rxvt_t*, int);
172 void rxvt_scr_delete_row (rxvt_t*, int);
173 void rxvt_scr_add_row (rxvt_t*, int, unsigned int, unsigned int);
174 void static inline rxvt_clear_area (rxvt_t*, int page, int x, int y, unsigned int w, unsigned int h);
175 void static inline rxvt_fill_rectangle (rxvt_t*, int page, int x, int y, unsigned int w, unsigned int h);
176 void
177 rxvt_scr_draw_string (rxvt_t* r, int page,
178 int x, int y, char* str, int len, int drawfunc,
179 uint16_t fore, uint16_t back,
180 __attribute__((unused)) rend_t rend, Region refreshRegion);
181 void rxvt_scr_adjust_col (rxvt_t*, int, unsigned int);
182 void rxvt_set_font_style (rxvt_t*, int);
183 int rxvt_scr_change_view (rxvt_t*, int, uint16_t);
184 void rxvt_scr_reverse_selection (rxvt_t*, int);
185 void rxvt_paste_str (rxvt_t*, int, const unsigned char*, unsigned int);
186 int rxvt_selection_request_other (rxvt_t*, int, Atom, int);
187 void rxvt_selection_start_colrow (rxvt_t*, int, int, int);
188 void rxvt_selection_delimit_word (rxvt_t*, int, enum page_dirn, const row_col_t*, row_col_t*);
189 #ifdef MULTICHAR_SET
190 void rxvt_selection_adjust_kanji (rxvt_t*, int);
191 #endif
192 void rxvt_selection_extend_colrow (rxvt_t*, int, int32_t, int32_t, int, int, int);
193 #ifndef NO_FRILLS
194 void rxvt_selection_trim (rxvt_t*, int);
195 #endif
196 #ifdef TEXT_SHADOW
197 # ifdef XFT_SUPPORT
198 void rxvt_set_clipping (rxvt_t*, XftDraw*, GC, Region, int, int, unsigned, unsigned, int*, int*);
199 void rxvt_free_clipping (rxvt_t*, XftDraw*, GC, Region);
200 # else
201 void rxvt_set_clipping (rxvt_t*, __attribute__((unused)) void*, GC, Region, int, int, unsigned, unsigned, int*, int*);
202 void rxvt_free_clipping (rxvt_t*, __attribute__((unused)) void*, GC, Region);
203 # endif
204 #endif
205 #ifdef XFT_SUPPORT
206 #endif /* XFT_SUPPORT */
207 /*--------------------------------------------------------------------*
208 * END `INTERNAL' ROUTINE PROTOTYPES *
209 *--------------------------------------------------------------------*/
210
211
212
213 /* ------------------------------------------------------------------------- *
214 * SCREEN `COMMON' ROUTINES *
215 * ------------------------------------------------------------------------- */
216
217 /* Fill part/all of a line with blanks. */
218 /* INTPROTO */
219 void
rxvt_blank_line(text_t * et,rend_t * er,unsigned int width,rend_t efs)220 rxvt_blank_line(text_t *et, rend_t *er, unsigned int width, rend_t efs)
221 {
222 MEMSET(et, ' ', (size_t)width);
223 efs &= ~RS_baseattrMask;
224 for (; width--;)
225 *er++ = efs;
226 }
227
228 /* ------------------------------------------------------------------------- */
229 /* Fill a full line with blanks - make sure it is allocated first */
230 /* INTPROTO */
231 void
rxvt_blank_screen_mem(rxvt_t * r,int page,text_t ** tp,rend_t ** rp,unsigned int row,rend_t efs)232 rxvt_blank_screen_mem(rxvt_t* r, int page, text_t **tp, rend_t **rp,
233 unsigned int row, rend_t efs)
234 {
235 int width = r->TermWin.ncol;
236 rend_t *er;
237
238 assert ((tp[row] && rp[row]) ||
239 (tp[row] == NULL && rp[row] == NULL));
240
241 /* possible integer overflow? */
242 assert (width > 0);
243 assert (sizeof (text_t) * width > 0);
244 assert (sizeof (rend_t) * width > 0);
245
246 if (tp[row] == NULL)
247 {
248 tp[row] = rxvt_malloc(sizeof(text_t) * width);
249 rp[row] = rxvt_malloc(sizeof(rend_t) * width);
250 }
251 MEMSET(tp[row], ' ', width);
252 efs &= ~RS_baseattrMask;
253 for (er = rp[row]; width--;)
254 *er++ = efs;
255 }
256
257
258
259 /* ------------------------------------------------------------------------- *
260 * SCREEN INITIALISATION *
261 * ------------------------------------------------------------------------- */
262 /* EXTPROTO */
263 void
rxvt_init_screen(rxvt_t * r)264 rxvt_init_screen (rxvt_t* r)
265 {
266 int p;
267 int ncol = r->TermWin.ncol;
268
269 /* first time, we don't have r->tabstop yet */
270 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "allocate r->tabstop as %d\n", ncol));
271 assert (ncol > 0); /* possible integer overflow? */
272 r->tabstop = rxvt_malloc(ncol * sizeof(char));
273 for (p = 0; p < ncol; p++)
274 r->tabstop[p] = (p % TABSTOP_SIZE == 0) ? 1 : 0;
275 }
276
277
278 void
rxvt_scr_alloc(rxvt_t * r,int page)279 rxvt_scr_alloc (rxvt_t* r, int page)
280 {
281 unsigned int ncol, nrow, total_rows;
282 unsigned int p, q;
283
284
285 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_alloc %d ()\n", page));
286 ncol = r->TermWin.ncol;
287 nrow = r->TermWin.nrow;
288 total_rows = nrow + SVLINES;
289
290 /*
291 ** First time called so just malloc everything : don't rely on
292 ** realloc
293 ** Note: this is still needed so that all the scrollback lines
294 ** are NULL
295 */
296 PVTS(r, page)->buf_text = rxvt_calloc(total_rows, sizeof(text_t*));
297 PVTS(r, page)->buf_rend = rxvt_calloc(total_rows, sizeof(rend_t*));
298
299 PVTS(r, page)->drawn_text = rxvt_calloc(nrow, sizeof(text_t*));
300 PVTS(r, page)->drawn_rend = rxvt_calloc(nrow, sizeof(rend_t*));
301
302 PSCR(r, page).text = rxvt_calloc(total_rows, sizeof(text_t*));
303 PSCR(r, page).tlen = rxvt_calloc(total_rows, sizeof(int16_t));
304 PSCR(r, page).rend = rxvt_calloc(total_rows, sizeof(rend_t*));
305
306 #if NSCREENS
307 PVTS(r, page)->swap.text = rxvt_calloc(nrow, sizeof(text_t*));
308 PVTS(r, page)->swap.tlen = rxvt_calloc(nrow, sizeof(int16_t));
309 PVTS(r, page)->swap.rend = rxvt_calloc(nrow, sizeof(rend_t*));
310 #endif
311
312 for (p = 0; p < nrow; p++)
313 {
314 q = p + SVLINES;
315 rxvt_blank_screen_mem (r, page, PSCR(r, page).text,
316 PSCR(r, page).rend, q, DEFAULT_RSTYLE);
317 PSCR(r, page).tlen[q] = 0;
318 #if NSCREENS
319 rxvt_blank_screen_mem (r, page, PVTS(r, page)->swap.text,
320 PVTS(r, page)->swap.rend, p, DEFAULT_RSTYLE);
321 PVTS(r, page)->swap.tlen[p] = 0;
322 #endif
323
324 rxvt_blank_screen_mem (r, page, PVTS(r, page)->drawn_text,
325 PVTS(r, page)->drawn_rend, p, DEFAULT_RSTYLE);
326 }
327 PVTS(r, page)->nscrolled = 0; /* no saved lines */
328 PSCR(r, page).flags = Screen_DefaultFlags;
329 PSCR(r, page).cur.row = 0;
330 PSCR(r, page).cur.col = 0;
331 PSCR(r, page).charset = 0;
332 PVTS(r, page)->current_screen = PRIMARY;
333 rxvt_scr_cursor(r, page, SAVE);
334 #if NSCREENS
335 PVTS(r, page)->swap.flags = Screen_DefaultFlags;
336 PVTS(r, page)->swap.cur.row = 0;
337 PVTS(r, page)->swap.cur.col = 0;
338 PVTS(r, page)->swap.charset = 0;
339 PVTS(r, page)->current_screen = SECONDARY;
340 rxvt_scr_cursor(r, page, SAVE);
341 PVTS(r, page)->current_screen = PRIMARY;
342 #endif
343
344 PVTS(r, page)->rstyle = DEFAULT_RSTYLE;
345 PVTS(r, page)->rvideo = 0;
346 MEMSET(&(PVTS(r, page)->charsets), 'B', sizeof(PVTS(r, page)->charsets));
347 #ifdef MULTICHAR_SET
348 PVTS(r, page)->multi_byte = 0;
349 PVTS(r, page)->lost_multi = 0;
350 PVTS(r, page)->chstat = SBYTE;
351 #endif
352
353 /* Now set screen initialization flag */
354 PVTS(r, page)->init_screen = 1;
355 }
356
357
358
359 /* INTPROTO */
360 void
rxvt_scr_reset_realloc(rxvt_t * r,int page)361 rxvt_scr_reset_realloc(rxvt_t* r, int page)
362 {
363 unsigned int total_rows, nrow;
364
365
366 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_reset_realloc %d ()\n", page));
367 nrow = r->TermWin.nrow;
368 total_rows = nrow + SVLINES;
369
370 PSCR(r, page).text = rxvt_realloc (
371 PSCR(r, page).text, total_rows * sizeof(text_t *));
372 PSCR(r, page).tlen = rxvt_realloc (
373 PSCR(r, page).tlen, total_rows * sizeof(int16_t));
374 PSCR(r, page).rend = rxvt_realloc (
375 PSCR(r, page).rend, total_rows * sizeof(rend_t *));
376
377 #if NSCREENS
378 PVTS(r, page)->swap.text = rxvt_realloc (
379 PVTS(r, page)->swap.text, nrow * sizeof(text_t *));
380 PVTS(r, page)->swap.tlen = rxvt_realloc (
381 PVTS(r, page)->swap.tlen , total_rows * sizeof(int16_t));
382 PVTS(r, page)->swap.rend = rxvt_realloc (
383 PVTS(r, page)->swap.rend, nrow * sizeof(rend_t *));
384 #endif
385
386 PVTS(r, page)->buf_text = rxvt_realloc (
387 PVTS(r, page)->buf_text, total_rows * sizeof(text_t *));
388 PVTS(r, page)->buf_rend = rxvt_realloc (
389 PVTS(r, page)->buf_rend, total_rows * sizeof(rend_t *));
390
391 PVTS(r, page)->drawn_text = rxvt_realloc (
392 PVTS(r, page)->drawn_text, nrow * sizeof(text_t *));
393 PVTS(r, page)->drawn_rend = rxvt_realloc (
394 PVTS(r, page)->drawn_rend, nrow * sizeof(rend_t *));
395 }
396
397
398 /* INTPROTO */
399 void
rxvt_scr_delete_row(rxvt_t * r,int page)400 rxvt_scr_delete_row (rxvt_t* r, int page)
401 {
402 unsigned int nrow, prev_nrow;
403 unsigned int p, q;
404 register int i;
405
406
407 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_delete_row %d ()\n", page));
408 nrow = r->TermWin.nrow;
409 prev_nrow = PVTS(r, page)->prev_nrow;
410
411 /* delete rows */
412 i = min(PVTS(r, page)->nscrolled, prev_nrow - nrow);
413 rxvt_scroll_text(r, page, 0, (int)prev_nrow - 1, i, 1);
414
415 for (p = nrow; p < prev_nrow; p++)
416 {
417 q = p + SVLINES;
418 if (PSCR(r, page).text[q])
419 {
420 assert(PSCR(r, page).rend[q]);
421 rxvt_free(PSCR(r, page).text[q]);
422 PSCR(r, page).text[q] = NULL;
423 rxvt_free(PSCR(r, page).rend[q]);
424 PSCR(r, page).rend[q] = NULL;
425 }
426 #if NSCREENS
427 if (PVTS(r, page)->swap.text[p])
428 {
429 assert(PVTS(r, page)->swap.rend[p]);
430 rxvt_free(PVTS(r, page)->swap.text[p]);
431 PVTS(r, page)->swap.text[p] = NULL;
432 rxvt_free(PVTS(r, page)->swap.rend[p]);
433 PVTS(r, page)->swap.rend[p] = NULL;
434 }
435 #endif
436 assert (PVTS(r, page)->drawn_text[p]);
437 assert (PVTS(r, page)->drawn_rend[p]);
438 rxvt_free(PVTS(r, page)->drawn_text[p]);
439 PVTS(r, page)->drawn_text[p] = NULL;
440 rxvt_free(PVTS(r, page)->drawn_rend[p]);
441 PVTS(r, page)->drawn_rend[p] = NULL;
442 }
443
444 /* we have fewer rows so fix up cursor position */
445 MIN_IT(PSCR(r, page).cur.row, (int32_t)nrow - 1);
446 #if NSCREENS
447 MIN_IT(PVTS(r, page)->swap.cur.row, (int32_t)nrow - 1);
448 #endif
449
450 rxvt_scr_reset_realloc (r, page); /* realloc _last_ */
451 }
452
453
454 /* INTPROTO */
455 void
rxvt_scr_add_row(rxvt_t * r,int page,unsigned int total_rows,unsigned int prev_total_rows)456 rxvt_scr_add_row (rxvt_t* r, int page, unsigned int total_rows, unsigned int prev_total_rows)
457 {
458 unsigned int nrow, prev_nrow;
459 unsigned int p;
460 register int i;
461
462
463 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "%s( page=%d, total_rows=%u, prev_total_rows=%u )\n", __func__, page, total_rows, prev_total_rows ));
464
465 nrow = r->TermWin.nrow;
466 prev_nrow = PVTS(r, page)->prev_nrow;
467
468 /* add rows */
469 rxvt_scr_reset_realloc(r, page); /* realloc _first_ */
470
471 i = min(PVTS(r, page)->nscrolled, nrow - prev_nrow);
472 for (p = prev_total_rows; p < total_rows; p++)
473 {
474 PSCR(r, page).tlen[p] = 0;
475 PSCR(r, page).text[p] = NULL;
476 PSCR(r, page).rend[p] = NULL;
477 }
478
479 for (p = prev_total_rows; p < total_rows - i; p++)
480 rxvt_blank_screen_mem (r, page, PSCR(r, page).text,
481 PSCR(r, page).rend, p, DEFAULT_RSTYLE);
482
483 for (p = prev_nrow; p < nrow; p++)
484 {
485 #if NSCREENS
486 PVTS(r, page)->swap.tlen[p] = 0;
487 PVTS(r, page)->swap.text[p] = NULL;
488 PVTS(r, page)->swap.rend[p] = NULL;
489 rxvt_blank_screen_mem (r, page, PVTS(r, page)->swap.text,
490 PVTS(r, page)->swap.rend, p, DEFAULT_RSTYLE);
491 #endif
492
493 PVTS(r, page)->drawn_text[p] = NULL;
494 PVTS(r, page)->drawn_rend[p] = NULL;
495 rxvt_blank_screen_mem (r, page, PVTS(r, page)->drawn_text,
496 PVTS(r, page)->drawn_rend, p, DEFAULT_RSTYLE);
497 }
498
499 if (i > 0)
500 {
501 rxvt_scroll_text(r, page, 0, (int)nrow - 1, -i, 1);
502 PSCR(r, page).cur.row += i;
503 PSCR(r, page).s_cur.row += i;
504 PVTS(r, page)->nscrolled -= i;
505 }
506
507 assert(PSCR(r, page).cur.row < r->TermWin.nrow);
508 MIN_IT(PSCR(r, page).cur.row, nrow - 1);
509 #if NSCREENS
510 assert(PVTS(r, page)->swap.cur.row < r->TermWin.nrow);
511 MIN_IT(PVTS(r, page)->swap.cur.row, nrow - 1);
512 #endif
513 }
514
515
516
517 /* INTPROTO */
518 void
rxvt_scr_adjust_col(rxvt_t * r,int page,unsigned int total_rows)519 rxvt_scr_adjust_col (rxvt_t* r, int page, unsigned int total_rows)
520 {
521 unsigned int nrow, ncol, prev_ncol;
522 unsigned int p;
523
524
525 nrow = r->TermWin.nrow;
526 ncol = r->TermWin.ncol;
527 prev_ncol = PVTS(r, page)->prev_ncol;
528
529 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "%s( r, page=%d, total_rows=%u ):" "ncol=%d, prev_ncol=%d, nrow=%d\n", __func__, page, total_rows, ncol, prev_ncol, nrow ));
530
531
532 for (p = 0; p < total_rows; p++)
533 {
534 if (PSCR(r, page).text[p])
535 {
536 PSCR(r, page).text[p] = rxvt_realloc (
537 PSCR(r, page).text[p], ncol * sizeof(text_t));
538 PSCR(r, page).rend[p] = rxvt_realloc (
539 PSCR(r, page).rend[p], ncol * sizeof(rend_t));
540 MIN_IT(PSCR(r, page).tlen[p], (int16_t)ncol);
541 if (ncol > prev_ncol)
542 rxvt_blank_line (
543 &(PSCR(r, page).text[p][prev_ncol]),
544 &(PSCR(r, page).rend[p][prev_ncol]),
545 ncol - prev_ncol, DEFAULT_RSTYLE);
546 }
547 }
548
549 for (p = 0; p < nrow; p++)
550 {
551 PVTS(r, page)->drawn_text[p] = rxvt_realloc (
552 PVTS(r, page)->drawn_text[p], ncol * sizeof(text_t));
553 PVTS(r, page)->drawn_rend[p] = rxvt_realloc (
554 PVTS(r, page)->drawn_rend[p], ncol * sizeof(rend_t));
555 #if NSCREENS
556 if (PVTS(r, page)->swap.text[p])
557 {
558 PVTS(r, page)->swap.text[p] = rxvt_realloc (
559 PVTS(r, page)->swap.text[p], ncol * sizeof(text_t));
560 PVTS(r, page)->swap.rend[p] = rxvt_realloc (
561 PVTS(r, page)->swap.rend[p], ncol * sizeof(rend_t));
562 MIN_IT(PVTS(r, page)->swap.tlen[p], (int16_t)ncol);
563 if (ncol > prev_ncol)
564 rxvt_blank_line(
565 &(PVTS(r, page)->swap.text[p][prev_ncol]),
566 &(PVTS(r, page)->swap.rend[p][prev_ncol]),
567 ncol - prev_ncol, DEFAULT_RSTYLE);
568 }
569 #endif
570 if (ncol > prev_ncol)
571 rxvt_blank_line(
572 &(PVTS(r, page)->drawn_text[p][prev_ncol]),
573 &(PVTS(r, page)->drawn_rend[p][prev_ncol]),
574 ncol - prev_ncol, DEFAULT_RSTYLE);
575 }
576 MIN_IT(PSCR(r, page).cur.col, (int16_t)ncol - 1);
577 #if NSCREENS
578 MIN_IT(PVTS(r, page)->swap.cur.col, (int16_t)ncol - 1);
579 #endif
580
581
582 /*
583 ** Only reset tabstop if expanding columns, save realloc in
584 ** shrinking columns
585 */
586 if (r->tabstop && ncol > prev_ncol)
587 {
588 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "expand r->tabstop to %d\n", ncol));
589 r->tabstop = rxvt_realloc(r->tabstop, ncol * sizeof(char));
590 for (p = prev_ncol; p < ncol; p++)
591 r->tabstop[p] = (p % TABSTOP_SIZE == 0) ? 1 : 0;
592 }
593 }
594
595
596
597 /* EXTPROTO */
598 void
rxvt_scr_reset(rxvt_t * r,int page)599 rxvt_scr_reset(rxvt_t* r, int page)
600 {
601 unsigned int ncol, nrow, prev_ncol, prev_nrow,
602 total_rows, prev_total_rows;
603
604
605 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_reset %d ()\n", page));
606
607 VSTART = 0;
608 RESET_CHSTAT(r, page);
609 PVTS(r, page)->num_scr = 0; /* number of lines scrolled */
610
611 prev_ncol = PVTS(r, page)->prev_ncol;
612 prev_nrow = PVTS(r, page)->prev_nrow;
613 if (r->TermWin.ncol == 0)
614 r->TermWin.ncol = 80;
615 if (r->TermWin.nrow == 0)
616 r->TermWin.nrow = 24;
617 ncol = r->TermWin.ncol;
618 nrow = r->TermWin.nrow;
619 if (PVTS(r, page)->init_screen &&
620 ncol == prev_ncol && nrow == prev_nrow)
621 return;
622
623 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_reset %d () refresh screen\n", page));
624 PVTS(r, page)->want_refresh = 1;
625
626 total_rows = nrow + SVLINES;
627 prev_total_rows = prev_nrow + SVLINES;
628
629 PSCR(r, page).tscroll = 0;
630 PSCR(r, page).bscroll = nrow - 1;
631
632 if (PVTS(r, page)->init_screen == 0)
633 {
634 /* Initialize the screen structures */
635 rxvt_scr_alloc (r, page);
636 }
637 else
638 {
639 /* B1: resize rows */
640 if (nrow < prev_nrow)
641 {
642 rxvt_scr_delete_row (r, page);
643 }
644 else if (nrow > prev_nrow)
645 {
646 rxvt_scr_add_row (r, page, total_rows, prev_total_rows);
647 }
648 /* B2: resize columns */
649 if (ncol != prev_ncol)
650 {
651 rxvt_scr_adjust_col (r, page, total_rows);
652 }
653 }
654
655 PVTS(r, page)->prev_nrow = nrow;
656 PVTS(r, page)->prev_ncol = ncol;
657
658 rxvt_tt_winsize(PVTS(r, page)->cmd_fd, r->TermWin.ncol, r->TermWin.nrow, PVTS(r, page)->cmd_pid);
659 }
660
661
662
663
664 /* ------------------------------------------------------------------------- */
665 /*
666 * Free everything. That way malloc debugging can find leakage.
667 */
668 /* EXTPROTO */
669 void
rxvt_scr_release(rxvt_t * r,int page)670 rxvt_scr_release(rxvt_t* r, int page)
671 {
672 unsigned int total_rows;
673 int i;
674
675
676 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_release %d ()\n", page));
677 total_rows = r->TermWin.nrow + SVLINES;
678
679 for (i = 0; i < total_rows; i++)
680 {
681 if (PSCR(r, page).text[i])
682 {
683 /* then so is PSCR(r, page).rend[i] */
684 rxvt_free(PSCR(r, page).text[i]);
685 PSCR(r, page).text[i] = NULL;
686 assert(PSCR(r, page).rend[i]);
687 rxvt_free(PSCR(r, page).rend[i]);
688 PSCR(r, page).rend[i] = NULL;
689 }
690 }
691
692 for (i = 0; i < r->TermWin.nrow; i++)
693 {
694 /* if (PVTS(r, page)->drawn_text[i]) */
695 rxvt_free(PVTS(r, page)->drawn_text[i]);
696 PVTS(r, page)->drawn_text[i] = NULL;
697 /* if (PVTS(r, page)->drawn_rend[i]) */
698 rxvt_free(PVTS(r, page)->drawn_rend[i]);
699 PVTS(r, page)->drawn_rend[i] = NULL;
700 #if NSCREENS
701 /* if (PVTS(r, page)->swap.text[i]) */
702 rxvt_free(PVTS(r, page)->swap.text[i]);
703 PVTS(r, page)->swap.text[i] = NULL;
704 /* if (PVTS(r, page)->swap.rend[i])) */
705 rxvt_free(PVTS(r, page)->swap.rend[i]);
706 PVTS(r, page)->swap.rend[i] = NULL;
707 #endif
708 }
709
710 rxvt_free(PSCR(r, page).text); PSCR(r, page).text = NULL;
711 rxvt_free(PSCR(r, page).tlen); PSCR(r, page).tlen = NULL;
712 rxvt_free(PSCR(r, page).rend); PSCR(r, page).rend = NULL;
713 rxvt_free(PVTS(r, page)->drawn_text); PVTS(r, page)->drawn_text = NULL;
714 rxvt_free(PVTS(r, page)->drawn_rend); PVTS(r, page)->drawn_rend = NULL;
715 #if NSCREENS
716 rxvt_free(PVTS(r, page)->swap.text); PVTS(r, page)->swap.text = NULL;
717 rxvt_free(PVTS(r, page)->swap.tlen); PVTS(r, page)->swap.tlen = NULL;
718 rxvt_free(PVTS(r, page)->swap.rend); PVTS(r, page)->swap.rend = NULL;
719 #endif
720 rxvt_free(PVTS(r, page)->buf_text); PVTS(r, page)->buf_text = NULL;
721 rxvt_free(PVTS(r, page)->buf_rend); PVTS(r, page)->buf_rend = NULL;
722
723 /* next rxvt_scr_reset will be the first time initialization */
724 PVTS(r, page)->init_screen = 0;
725
726 /* clear selection if necessary */
727 if (page == r->selection.vt)
728 {
729 rxvt_process_selectionclear (r, page);
730 }
731 }
732
733 /* ------------------------------------------------------------------------- */
734 /*
735 * Hard reset
736 */
737 /* EXTPROTO */
738 void
rxvt_scr_poweron(rxvt_t * r,int page)739 rxvt_scr_poweron(rxvt_t* r, int page)
740 {
741 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_poweron %d ()\n", page));
742
743 rxvt_scr_release(r, page);
744 PVTS(r, page)->prev_nrow = PVTS(r, page)->prev_ncol = 0;
745 rxvt_scr_reset(r, page);
746
747 rxvt_scr_clear(r, page);
748 rxvt_scr_refresh(r, page, SLOW_REFRESH);
749 }
750
751
752 /* ------------------------------------------------------------------------- *
753 * PROCESS SCREEN COMMANDS *
754 * ------------------------------------------------------------------------- */
755 /*
756 * Save and Restore cursor
757 * XTERM_SEQ: Save cursor : ESC 7
758 * XTERM_SEQ: Restore cursor: ESC 8
759 */
760 /* EXTPROTO */
761 void
rxvt_scr_cursor(rxvt_t * r,int page,int mode)762 rxvt_scr_cursor(rxvt_t* r, int page, int mode)
763 {
764 screen_t *s;
765
766 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_cursor %d (%c)\n", page, mode));
767
768 #if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
769 if (PVTS(r, page)->current_screen == SECONDARY)
770 s = &(PVTS(r, page)->swap);
771 else
772 #endif
773 s = &(PSCR(r, page));
774 switch (mode)
775 {
776 case SAVE:
777 s->s_cur.row = s->cur.row;
778 s->s_cur.col = s->cur.col;
779 s->s_rstyle = PVTS(r, page)->rstyle;
780 s->s_charset = s->charset;
781 s->s_charset_char = PVTS(r, page)->charsets[s->charset];
782 break;
783 case RESTORE:
784 PVTS(r, page)->want_refresh = 1;
785 s->cur.row = s->s_cur.row;
786 s->cur.col = s->s_cur.col;
787 s->flags &= ~Screen_WrapNext;
788 PVTS(r, page)->rstyle = s->s_rstyle;
789 s->charset = s->s_charset;
790 PVTS(r, page)->charsets[s->charset] = s->s_charset_char;
791 rxvt_set_font_style(r, page);
792 break;
793 }
794 /* boundary check in case screen size changed between SAVE and RESTORE */
795 MIN_IT(s->cur.row, r->TermWin.nrow - 1);
796 MIN_IT(s->cur.col, r->TermWin.ncol - 1);
797 assert(s->cur.row >= 0);
798 assert(s->cur.col >= 0);
799 MAX_IT(s->cur.row, 0);
800 MAX_IT(s->cur.col, 0);
801 }
802
803 /* ------------------------------------------------------------------------- */
804 /*
805 * Swap between primary and secondary screens
806 * XTERM_SEQ: Primary screen : ESC [ ? 4 7 h
807 * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
808 */
809 /* EXTPROTO */
810 int
rxvt_scr_change_screen(rxvt_t * r,int page,int scrn)811 rxvt_scr_change_screen(rxvt_t* r, int page, int scrn)
812 {
813 #if NSCREENS
814 unsigned int i, offset;
815 #endif
816
817 PVTS(r, page)->want_refresh = 1;
818
819 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_change_screen %d (%d)\n", page, scrn));
820
821 VSTART = 0;
822 RESET_CHSTAT(r, page);
823
824 if (PVTS(r, page)->current_screen == scrn)
825 return PVTS(r, page)->current_screen;
826
827 rxvt_selection_check(r, page, 2); /* check for boundary cross */
828
829 SWAP_IT(PVTS(r, page)->current_screen, scrn, int);
830
831 #if NSCREENS
832 PVTS(r, page)->num_scr = 0;
833 offset = SVLINES;
834
835 for (i = PVTS(r, page)->prev_nrow; i--;)
836 {
837 SWAP_IT(PSCR(r, page).text[i + offset],
838 PVTS(r, page)->swap.text[i], text_t *);
839 SWAP_IT(PSCR(r, page).tlen[i + offset],
840 PVTS(r, page)->swap.tlen[i], int16_t);
841 SWAP_IT(PSCR(r, page).rend[i + offset],
842 PVTS(r, page)->swap.rend[i], rend_t *);
843 }
844 SWAP_IT(CURROW, PVTS(r, page)->swap.cur.row, int16_t);
845 SWAP_IT(CURCOL, PVTS(r, page)->swap.cur.col, int16_t);
846 assert (CURROW >= 0);
847 assert (CURROW < PVTS(r, page)->prev_nrow);
848 assert (CURCOL >= 0);
849 assert (CURCOL < PVTS(r, page)->prev_ncol);
850 MAX_IT(CURROW, 0);
851 MIN_IT(CURROW, (int32_t)PVTS(r, page)->prev_nrow - 1);
852 MAX_IT(CURCOL, 0);
853 MIN_IT(CURCOL, (int32_t)PVTS(r, page)->prev_ncol - 1);
854
855 SWAP_IT(PSCR(r, page).charset, PVTS(r, page)->swap.charset,
856 int16_t);
857 SWAP_IT(PSCR(r, page).flags, PVTS(r, page)->swap.flags, int);
858 PSCR(r, page).flags |= Screen_VisibleCursor;
859 PVTS(r, page)->swap.flags |= Screen_VisibleCursor;
860
861 #else
862 # ifdef SCROLL_ON_NO_SECONDARY
863 if (PVTS(r, page)->current_screen == PRIMARY)
864 rxvt_scroll_text(r, page, 0, (PVTS(r, page)->prev_nrow - 1),
865 PVTS(r, page)->prev_nrow, 0);
866 # endif
867 #endif
868
869 /* Need to update tabbar buttons */
870 if (ISSET_OPTION(r, Opt2_protectSecondary))
871 rxvt_tabbar_draw_buttons (r);
872
873 return scrn;
874 }
875
876 /* ------------------------------------------------------------------------- */
877 /*
878 * Change the colour for following text
879 */
880 /* EXTPROTO */
881 void
rxvt_scr_color(rxvt_t * r,int page,unsigned int color,int fgbg)882 rxvt_scr_color(rxvt_t* r, int page, unsigned int color, int fgbg)
883 {
884 color &= RS_fgMask;
885 if (Color_fg == fgbg)
886 PVTS(r, page)->rstyle=SET_FGCOLOR(PVTS(r, page)->rstyle, color);
887 else
888 PVTS(r, page)->rstyle=SET_BGCOLOR(PVTS(r, page)->rstyle, color);
889 }
890
891
892 /* ------------------------------------------------------------------------- */
893 /*
894 * Change the rendition style for following text
895 */
896 /* EXTPROTO */
897 void
rxvt_scr_rendition(rxvt_t * r,int page,int set,int style)898 rxvt_scr_rendition(rxvt_t* r, int page, int set, int style)
899 {
900 if (set)
901 PVTS(r, page)->rstyle |= style;
902 else if (style == ~RS_None)
903 PVTS(r, page)->rstyle = DEFAULT_RSTYLE | (PVTS(r, page)->rstyle & RS_fontMask);
904 else
905 PVTS(r, page)->rstyle &= ~style;
906 }
907
908 /* ------------------------------------------------------------------------- */
909 /*
910 * Scroll text between <row1> and <row2> inclusive, by <count> lines
911 * count positive ==> scroll up
912 * count negative ==> scroll down
913 * spec == 0 for normal routines
914 */
915 /* EXTPROTO */
916 int
rxvt_scroll_text(rxvt_t * r,int page,int row1,int row2,int count,int spec)917 rxvt_scroll_text(rxvt_t* r, int page, int row1, int row2, int count, int spec)
918 {
919 int i, j, ret;
920 unsigned int nscrolled;
921 size_t size;
922
923 if (count == 0 || (row1 > row2))
924 return 0;
925
926 PVTS(r, page)->want_refresh = 1;
927 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN,
928 "rxvt_scroll_text %d (%d,%d,%d,%d): %s\n", page, row1, row2,
929 count, spec, (PVTS(r, page)->current_screen == PRIMARY) ?
930 "Primary" : "Secondary" ));
931
932 if (
933 (count > 0)
934 && (row1 == 0)
935 && (PVTS(r, page)->current_screen == PRIMARY)
936 )
937 {
938 nscrolled = (unsigned int) PVTS(r, page)->nscrolled
939 + (unsigned int) count;
940
941 if (nscrolled > (unsigned int)SVLINES)
942 PVTS(r, page)->nscrolled = SVLINES;
943 else
944 PVTS(r, page)->nscrolled = (uint16_t)nscrolled;
945 }
946 else if (!spec)
947 row1 += SVLINES;
948 row2 += SVLINES;
949
950 if (
951 SEL(r).op
952 && SEL(r).vt == page
953 && PVTS(r, page)->current_screen == SEL(r).screen
954 )
955 {
956 i = SEL(r).beg.row + SVLINES;
957 j = SEL(r).end.row + SVLINES;
958 if (
959 (i < row1 && j > row1)
960 || (i < row2 && j > row2)
961 || (i - count < row1 && i >= row1)
962 || (i - count > row2 && i <= row2)
963 || (j - count < row1 && j >= row1)
964 || (j - count > row2 && j <= row2)
965 )
966 {
967 CLEAR_ALL_SELECTION(r);
968 /* XXX: too aggressive? */
969 SEL(r).op = SELECTION_CLEAR;
970 }
971 else if (j >= row1 && j <= row2)
972 {
973 /* move selected region too */
974 SEL(r).beg.row -= count;
975 SEL(r).end.row -= count;
976 SEL(r).mark.row -= count;
977 }
978 }
979
980 /* _after_ PVTS(r, page)->nscrolled update */
981 rxvt_selection_check(r, page, 0);
982
983 PVTS(r, page)->num_scr += count;
984 j = count;
985 if (count < 0)
986 count = -count;
987 i = row2 - row1 + 1;
988 MIN_IT(count, i);
989
990 if (j > 0)
991 {
992 /* A: scroll up */
993
994 /* A1: Copy lines that will get clobbered by the rotation */
995 for (i = count - 1, j = row1; i >= 0; i--, j++)
996 {
997 PVTS(r, page)->buf_text[i] = PSCR(r, page).text[j];
998 PVTS(r, page)->buf_rend[i] = PSCR(r, page).rend[j];
999 }
1000
1001 /* A2: Rotate lines */
1002 size = sizeof(*PSCR(r, page).tlen);
1003 MEMMOVE(&(PSCR(r, page).tlen[row1]), &(PSCR(r, page).tlen[row1+count]),
1004 (row2 - row1 - count + 1) * size);
1005 size = sizeof(*PSCR(r, page).text);
1006 MEMMOVE(&(PSCR(r, page).text[row1]), &(PSCR(r, page).text[row1+count]),
1007 (row2 - row1 - count + 1) * size);
1008 size = sizeof(*PSCR(r, page).rend);
1009 MEMMOVE(&(PSCR(r, page).rend[row1]), &(PSCR(r, page).rend[row1+count]),
1010 (row2 - row1 - count + 1) * size);
1011
1012 j = row2 - count + 1;
1013 ret = i = count;
1014 }
1015 else /* if (j < 0) */
1016 {
1017 /* B: scroll down */
1018
1019 /* B1: Copy lines that will get clobbered by the rotation */
1020 size = sizeof(*PSCR(r, page).text);
1021 MEMCPY(PVTS(r, page)->buf_text, &PSCR(r, page).text[row2 - count + 1], count * size);
1022 size = sizeof(*PSCR(r, page).rend);
1023 MEMCPY(PVTS(r, page)->buf_rend, &PSCR(r, page).rend[row2 - count + 1], count * size);
1024
1025 /* B2: Rotate lines */
1026 size = sizeof(*PSCR(r, page).tlen);
1027 MEMMOVE(&(PSCR(r, page).tlen[row1 + count]), &(PSCR(r, page).tlen[row1]),
1028 (row2 - row1 - count + 1) * size);
1029 size = sizeof(*PSCR(r, page).text);
1030 MEMMOVE(&(PSCR(r, page).text[row1 + count]), &(PSCR(r, page).text[row1]),
1031 (row2 - row1 - count + 1) * size);
1032 size = sizeof(*PSCR(r, page).rend);
1033 MEMMOVE(&(PSCR(r, page).rend[row1 + count]), &(PSCR(r, page).rend[row1]),
1034 (row2 - row1 - count + 1) * size);
1035
1036 j = row1, i = count;
1037 ret = -count;
1038 }
1039
1040 /* C: Resurrect lines */
1041 size = sizeof(*PSCR(r, page).tlen);
1042 MEMSET(&PSCR(r, page).tlen[j], 0, count * size);
1043 size = sizeof(*PSCR(r, page).text);
1044 MEMCPY(&PSCR(r, page).text[j], PVTS(r, page)->buf_text, count * size);
1045 size = sizeof(*PSCR(r, page).rend);
1046 MEMCPY(&PSCR(r, page).rend[j], PVTS(r, page)->buf_rend, count * size);
1047
1048 for (; i--; j++)
1049 {
1050 if (!spec) /* line length may not equal TermWin.ncol */
1051 rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1052 PSCR(r, page).rend, (unsigned int)j,
1053 PVTS(r, page)->rstyle);
1054 }
1055
1056 return ret;
1057 }
1058
1059 /* ------------------------------------------------------------------------- */
1060 /*
1061 * Adjust the PVTS(r, page)->view_start so that the if nlines of text are added,
1062 * the view will not change.
1063 */
1064 void static inline
adjust_view_start(rxvt_t * r,int page,int nlines)1065 adjust_view_start( rxvt_t *r, int page, int nlines)
1066 {
1067 if(
1068 ISSET_OPTION( r, Opt_scrollTtyOutputInhibit) &&
1069 VSTART != 0 && VSTART + nlines <= PVTS( r, page)->nscrolled
1070 )
1071 VSTART += nlines;
1072 }
1073
1074 /*
1075 * Add text given in <str> of length <len> to screen struct
1076 */
1077 /* EXTPROTO */
1078 void
rxvt_scr_add_lines(rxvt_t * r,int page,const unsigned char * str,int nlines,int len)1079 rxvt_scr_add_lines(rxvt_t* r, int page, const unsigned char *str, int nlines,
1080 int len)
1081 {
1082 unsigned char checksel, clearsel;
1083 char c;
1084 int i, row, last_col;
1085 text_t *stp;
1086 rend_t *srp;
1087
1088 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_add_lines( r, %d, %.*s, %d, %d)\n", page, min(len, 36), str, nlines, len ));
1089
1090 if (len <= 0) /* sanity */
1091 return;
1092
1093 PVTS(r, page)->want_refresh = 1;
1094 last_col = r->TermWin.ncol;
1095
1096 ZERO_SCROLLBACK(r, page);
1097 if (nlines > 0)
1098 {
1099 /*
1100 * 2006-09-02 gi1242 TODO: The code below is *horrible*. When we call
1101 * rxvt_scroll_text(), we might end up with a negative CURROW. We try
1102 * and be clever using this information, but rxvt_scr_gotorc() will
1103 * reset this information!
1104 */
1105 nlines += (CURROW - PSCR(r, page).bscroll);
1106 if (
1107 (nlines > 0)
1108 && (PSCR(r, page).tscroll == 0)
1109 && (PSCR(r, page).bscroll == (r->TermWin.nrow - 1))
1110 )
1111 {
1112 /* _at least_ this many lines need to be scrolled */
1113 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1114 PSCR(r, page).bscroll, nlines, 0);
1115 adjust_view_start(r, page, nlines );
1116
1117 CURROW -= nlines;
1118
1119 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "\e[32mScrolling %d lines. CURROW=%d\e[0m\n", nlines, CURROW ));
1120 }
1121 }
1122
1123 assert(CURCOL < last_col);
1124 assert(CURROW < r->TermWin.nrow);
1125
1126 #if 0 /*{{{ Possibly incorrection assertion */
1127 /*
1128 * XXX 2006-09-12 gi1242: I think this assertion is wrong! Note that a few
1129 * lines later we set CURROW to be the max of CURROW and -PVTS()->nscrolled
1130 */
1131 assert(CURROW >= -(int32_t)PVTS(r, page)->nscrolled);
1132 #endif /*}}}*/
1133
1134 MIN_IT(CURCOL, last_col - 1);
1135 MIN_IT(CURROW, (int32_t)r->TermWin.nrow - 1);
1136 MAX_IT(CURROW, -(int32_t)PVTS(r, page)->nscrolled);
1137
1138 row = CURROW + SVLINES;
1139
1140 checksel = (SEL(r).op && SEL(r).vt == page &&
1141 PVTS(r, page)->current_screen == SEL(r).screen) ? 1 : 0;
1142 clearsel = 0;
1143
1144 stp = PSCR(r, page).text[row];
1145 srp = PSCR(r, page).rend[row];
1146
1147 #ifdef MULTICHAR_SET
1148 if(
1149 PVTS(r, page)->lost_multi && CURCOL > 0 &&
1150 IS_MULTI1(srp[CURCOL - 1]) &&
1151 *str != '\n' && *str != '\r' && *str != '\t'
1152 )
1153 {
1154 PVTS(r, page)->chstat = WBYTE;
1155 }
1156 #endif
1157
1158 for (i = 0; i < len;)
1159 {
1160 c = str[i++];
1161 switch (c)
1162 {
1163 case '\t':
1164 rxvt_scr_tab(r, page, 1);
1165 continue;
1166
1167 case '\n':
1168 /* XXX: think about this */
1169 if( PSCR(r, page).tlen[row] != -1 )
1170 MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1171
1172 PSCR(r, page).flags &= ~Screen_WrapNext;
1173 if (CURROW == PSCR(r, page).bscroll)
1174 {
1175 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "%s:%d ",
1176 __FILE__, __LINE__ ));
1177 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1178 PSCR(r, page).bscroll, 1, 0);
1179 adjust_view_start( r, page, 1 );
1180 }
1181 else if (CURROW < (r->TermWin.nrow - 1))
1182 row = (++CURROW) + SVLINES;
1183
1184 stp = PSCR(r, page).text[row]; /* _must_ refresh */
1185 srp = PSCR(r, page).rend[row]; /* _must_ refresh */
1186 RESET_CHSTAT(r, page);
1187 continue;
1188
1189 case '\r':
1190 /* XXX: think about this */
1191 if (PSCR(r, page).tlen[row] != -1)
1192 MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1193 PSCR(r, page).flags &= ~Screen_WrapNext;
1194 CURCOL = 0;
1195 RESET_CHSTAT(r, page);
1196 continue;
1197
1198 default:
1199 #ifdef MULTICHAR_SET
1200 if (r->encoding_method == ENC_NOENC)
1201 {
1202 if (c == 127)
1203 continue;
1204 break;
1205 }
1206 PVTS(r, page)->rstyle &= ~RS_multiMask;
1207
1208 /* multibyte 2nd byte */
1209 if (PVTS(r, page)->chstat == WBYTE)
1210 {
1211 /* set flag of second byte in style */
1212 PVTS(r, page)->rstyle |= RS_multi2;
1213 /* switch back to single byte for next char */
1214 PVTS(r, page)->chstat = SBYTE;
1215 if (
1216 (r->encoding_method == ENC_EUCJ)
1217 && ((char) stp[CURCOL-1] == (char) 0x8e)
1218 )
1219 {
1220 PVTS(r, page)->rstyle &= ~RS_multiMask;
1221 CURCOL --;
1222 }
1223 else
1224 /* maybe overkill, but makes it selectable */
1225 if ((r->encoding_method == ENC_EUCJ) ||
1226 (r->encoding_method == ENC_GBK) ||
1227 (r->encoding_method == ENC_GB))
1228 c |= 0x80;
1229 }
1230 /* multibyte 1st byte */
1231 else if (PVTS(r, page)->chstat == SBYTE)
1232 {
1233 if (r->encoding_method == ENC_SJIS)
1234 {
1235 if (
1236 PVTS(r, page)->multi_byte
1237 || (
1238 (
1239 (unsigned char) c >= (unsigned char) 0x81
1240 && (unsigned char) c <= (unsigned char) 0x9f
1241 )
1242 ||
1243 (
1244 (unsigned char) c >= (unsigned char) 0xe0
1245 && (unsigned char) c <= (unsigned char) 0xfc
1246 )
1247 )
1248 )
1249 {
1250 PVTS(r, page)->rstyle |= RS_multi1;
1251 PVTS(r, page)->chstat = WBYTE;
1252 }
1253 }
1254 else if (PVTS(r, page)->multi_byte || (c & 0x80))
1255 {
1256 /* set flag of first byte in style */
1257 PVTS(r, page)->rstyle |= RS_multi1;
1258 /* switch to multiple byte for next char */
1259 PVTS(r, page)->chstat = WBYTE;
1260 /* maybe overkill, but makes selectable */
1261 if (
1262 (r->encoding_method == ENC_EUCJ)
1263 || (r->encoding_method == ENC_GBK)
1264 || (r->encoding_method == ENC_GB)
1265 )
1266 c |= 0x80;
1267 }
1268 }
1269 else
1270 #endif
1271 if (c == 127)
1272 continue; /* yummmm..... */
1273 break;
1274 } /* switch */
1275
1276 if (
1277 checksel /* see if we're writing within selection */
1278 && !RC_BEFORE(PSCR(r, page).cur, SEL(r).beg)
1279 && RC_BEFORE(PSCR(r, page).cur, SEL(r).end)
1280 )
1281 {
1282 checksel = 0;
1283 clearsel = 1;
1284 }
1285
1286 if (PSCR(r, page).flags & Screen_WrapNext)
1287 {
1288 PSCR(r, page).tlen[row] = -1;
1289 if (CURROW == PSCR(r, page).bscroll)
1290 {
1291 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1292 PSCR(r, page).bscroll, 1, 0);
1293 adjust_view_start( r, page, 1 );
1294 }
1295 else if (CURROW < (r->TermWin.nrow - 1))
1296 row = (++CURROW) + SVLINES;
1297 stp = PSCR(r, page).text[row]; /* _must_ refresh */
1298 srp = PSCR(r, page).rend[row]; /* _must_ refresh */
1299 CURCOL = 0;
1300 PSCR(r, page).flags &= ~Screen_WrapNext;
1301 }
1302
1303 if (PSCR(r, page).flags & Screen_Insert)
1304 rxvt_scr_insdel_chars(r, page, 1, INSERT);
1305
1306 #ifdef MULTICHAR_SET
1307 if (
1308 IS_MULTI1(PVTS(r, page)->rstyle)
1309 && CURCOL > 0
1310 && IS_MULTI1(srp[CURCOL - 1])
1311 )
1312 {
1313 stp[CURCOL - 1] = ' ';
1314 srp[CURCOL - 1] &= ~RS_multiMask;
1315 }
1316 else if (
1317 IS_MULTI2(PVTS(r, page)->rstyle)
1318 && CURCOL < (last_col - 1)
1319 && IS_MULTI2(srp[CURCOL + 1])
1320 )
1321 {
1322 stp[CURCOL + 1] = ' ';
1323 srp[CURCOL + 1] &= ~RS_multiMask;
1324 }
1325 #endif
1326
1327 stp[CURCOL] = c;
1328 srp[CURCOL] = PVTS(r, page)->rstyle;
1329 if (CURCOL < (last_col - 1))
1330 CURCOL++;
1331 else
1332 {
1333 PSCR(r, page).tlen[row] = last_col;
1334 if (PSCR(r, page).flags & Screen_Autowrap)
1335 PSCR(r, page).flags |= Screen_WrapNext;
1336 }
1337 } /* for */
1338
1339 if (PSCR(r, page).tlen[row] != -1) /* XXX: think about this */
1340 MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1341
1342 /*
1343 ** If we wrote anywhere in the selected area, kill the selection
1344 ** XXX: should we kill the mark too? Possibly, but maybe that
1345 ** should be a similar check.
1346 */
1347 if (clearsel)
1348 CLEAR_SELECTION(r);
1349
1350 assert(CURROW >= 0);
1351 MAX_IT(CURROW, 0);
1352 }
1353
1354 /* ------------------------------------------------------------------------- */
1355 /*
1356 * Process Backspace. Move back the cursor back a position, wrap if have to
1357 * XTERM_SEQ: CTRL-H
1358 */
1359 /* EXTPROTO */
1360 void
rxvt_scr_backspace(rxvt_t * r,int page)1361 rxvt_scr_backspace(rxvt_t* r, int page)
1362 {
1363 RESET_CHSTAT(r, page);
1364 PVTS(r, page)->want_refresh = 1;
1365 if (CURCOL == 0)
1366 {
1367 if (CURROW > 0)
1368 {
1369 #ifdef TERMCAP_HAS_BW
1370 CURCOL = r->TermWin.ncol - 1;
1371 CURROW--;
1372 return;
1373 #endif
1374 }
1375 } else if ((PSCR(r, page).flags & Screen_WrapNext) == 0)
1376 rxvt_scr_gotorc(r, page, 0, -1, RELATIVE);
1377 PSCR(r, page).flags &= ~Screen_WrapNext;
1378 }
1379
1380 /* ------------------------------------------------------------------------- */
1381 /*
1382 * Process Horizontal Tab
1383 * count: +ve = forward; -ve = backwards
1384 * XTERM_SEQ: CTRL-I
1385 */
1386 /* EXTPROTO */
1387 void
rxvt_scr_tab(rxvt_t * r,int page,int count)1388 rxvt_scr_tab(rxvt_t* r, int page, int count)
1389 {
1390 int i, x;
1391
1392 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_tab %d (%d)\n", page, count));
1393 PVTS(r, page)->want_refresh = 1;
1394 RESET_CHSTAT(r, page);
1395 i = x = CURCOL;
1396 if (count == 0)
1397 return;
1398 else if (count > 0)
1399 {
1400 for (; ++i < r->TermWin.ncol; )
1401 if (r->tabstop[i])
1402 {
1403 x = i;
1404 if (!--count)
1405 break;
1406 }
1407 ;
1408 if (count)
1409 x = r->TermWin.ncol - 1;
1410 }
1411 else /* if (count < 0) */
1412 {
1413 for (; --i >= 0; )
1414 if (r->tabstop[i])
1415 {
1416 x = i;
1417 if (!++count)
1418 break;
1419 }
1420 ;
1421 if (count)
1422 x = 0;
1423 }
1424
1425 #if 0
1426 if (x != CURCOL)
1427 rxvt_scr_gotorc(r, page, 0, x, R_RELATIVE);
1428 #else
1429 /*
1430 * 2006-09-02 gi1242: Don't call rxvt_scr_gotorc() because that might change
1431 * CURROW (if it was negative). If we're adding lines to the screen
1432 * structure, then CURROW is allowed to be negative.
1433 */
1434 CURCOL = x;
1435 #endif
1436 }
1437
1438 /* ------------------------------------------------------------------------- */
1439 /*
1440 * Process DEC Back Index
1441 * XTERM_SEQ: ESC 6
1442 * Move cursor left in row. If we're at the left boundary, shift everything
1443 * in that row right. Clear left column.
1444 */
1445 #ifndef NO_FRILLS
1446 /* EXTPROTO */
1447 void
rxvt_scr_backindex(rxvt_t * r,int page)1448 rxvt_scr_backindex(rxvt_t* r, int page)
1449 {
1450 if (CURCOL > 0)
1451 rxvt_scr_gotorc(r, page, 0, -1, R_RELATIVE | C_RELATIVE);
1452 else
1453 {
1454 if (PSCR(r, page).tlen[CURROW + SVLINES] == 0)
1455 return; /* um, yeah? */
1456 rxvt_scr_insdel_chars(r, page, 1, INSERT);
1457 }
1458 }
1459 #endif
1460 /* ------------------------------------------------------------------------- */
1461 /*
1462 * Process DEC Forward Index
1463 * XTERM_SEQ: ESC 9
1464 * Move cursor right in row. If we're at the right boundary, shift everything
1465 * in that row left. Clear right column.
1466 */
1467 #ifndef NO_FRILLS
1468 /* EXTPROTO */
1469 void
rxvt_scr_forwardindex(rxvt_t * r,int page)1470 rxvt_scr_forwardindex(rxvt_t* r, int page)
1471 {
1472 int row;
1473
1474 if (CURCOL < r->TermWin.ncol - 1)
1475 rxvt_scr_gotorc(r, page, 0, 1, R_RELATIVE | C_RELATIVE);
1476 else
1477 {
1478 row = CURROW + SVLINES;
1479 if (PSCR(r, page).tlen[row] == 0)
1480 return; /* um, yeah? */
1481 else if (PSCR(r, page).tlen[row] == -1)
1482 PSCR(r, page).tlen[row] = r->TermWin.ncol;
1483 rxvt_scr_gotorc(r, page, 0, 0, R_RELATIVE);
1484 rxvt_scr_insdel_chars(r, page, 1, DELETE);
1485 rxvt_scr_gotorc(r, 0, page, r->TermWin.ncol - 1, R_RELATIVE);
1486 }
1487 }
1488 #endif
1489
1490 /* ------------------------------------------------------------------------- */
1491 /*
1492 * Goto Row/Column
1493 */
1494 /* EXTPROTO */
1495 void
rxvt_scr_gotorc(rxvt_t * r,int page,int row,int col,int relative)1496 rxvt_scr_gotorc(rxvt_t* r, int page, int row, int col, int relative)
1497 {
1498 PVTS(r, page)->want_refresh = 1;
1499 ZERO_SCROLLBACK(r, page);
1500 RESET_CHSTAT(r, page);
1501
1502 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
1503
1504 CURCOL = ((relative & C_RELATIVE) ? (CURCOL + col)
1505 : col);
1506 MAX_IT(CURCOL, 0);
1507 MIN_IT(CURCOL, (int32_t)r->TermWin.ncol - 1);
1508
1509 PSCR(r, page).flags &= ~Screen_WrapNext;
1510 if (relative & R_RELATIVE)
1511 {
1512 if (row > 0)
1513 {
1514 if (CURROW <= PSCR(r, page).bscroll &&
1515 (CURROW + row) > PSCR(r, page).bscroll)
1516 CURROW = PSCR(r, page).bscroll;
1517 else
1518 CURROW += row;
1519 }
1520
1521 else if (row < 0)
1522 {
1523 if (CURROW >= PSCR(r, page).tscroll &&
1524 (CURROW + row) < PSCR(r, page).tscroll)
1525 CURROW = PSCR(r, page).tscroll;
1526 else
1527 CURROW += row;
1528 }
1529 }
1530 else
1531 {
1532 if (PSCR(r, page).flags & Screen_Relative)
1533 {
1534 /* relative origin mode */
1535 CURROW = row + PSCR(r, page).tscroll;
1536 MIN_IT(CURROW, PSCR(r, page).bscroll);
1537 }
1538 else
1539 CURROW = row;
1540 }
1541 MAX_IT(CURROW, 0);
1542 MIN_IT(CURROW, (int32_t)r->TermWin.nrow - 1);
1543 }
1544
1545 /* ------------------------------------------------------------------------- */
1546 /*
1547 * direction should be UP or DN
1548 */
1549 /* EXTPROTO */
1550 void
rxvt_scr_index(rxvt_t * r,int page,enum page_dirn direction)1551 rxvt_scr_index(rxvt_t* r, int page, enum page_dirn direction)
1552 {
1553 int dirn;
1554
1555 PVTS(r, page)->want_refresh = 1;
1556 dirn = ((direction == UP) ? 1 : -1);
1557 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_index %d (%d)\n", page, dirn));
1558
1559 ZERO_SCROLLBACK(r, page);
1560 RESET_CHSTAT(r, page);
1561
1562 PSCR(r, page).flags &= ~Screen_WrapNext;
1563 if ((CURROW == PSCR(r, page).bscroll && direction == UP) ||
1564 (CURROW == PSCR(r, page).tscroll && direction == DN))
1565 rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1566 PSCR(r, page).bscroll, dirn, 0);
1567 else
1568 CURROW += dirn;
1569 MAX_IT(CURROW, 0);
1570 MIN_IT(CURROW, (int32_t)r->TermWin.nrow - 1);
1571 rxvt_selection_check(r, page, 0);
1572 }
1573
1574 /* ------------------------------------------------------------------------- */
1575 /*
1576 * Erase part or whole of a line
1577 * XTERM_SEQ: Clear line to right: ESC [ 0 K
1578 * XTERM_SEQ: Clear line to left : ESC [ 1 K
1579 * XTERM_SEQ: Clear whole line : ESC [ 2 K
1580 */
1581 /* EXTPROTO */
1582 void
rxvt_scr_erase_line(rxvt_t * r,int page,int mode)1583 rxvt_scr_erase_line(rxvt_t* r, int page, int mode)
1584 {
1585 unsigned int row, col, num;
1586
1587 PVTS(r, page)->want_refresh = 1;
1588 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_erase_line %d (%d) at screen row: %d\n", page, mode, CURROW));
1589 ZERO_SCROLLBACK(r, page);
1590 RESET_CHSTAT(r, page);
1591 rxvt_selection_check(r, page, 1);
1592
1593 PSCR(r, page).flags &= ~Screen_WrapNext;
1594
1595 row = SVLINES + CURROW;
1596 switch (mode)
1597 {
1598 case 0: /* erase to end of line */
1599 col = CURCOL;
1600 num = r->TermWin.ncol - col;
1601 MIN_IT(PSCR(r, page).tlen[row], (int16_t)col);
1602 if (
1603 RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)
1604 || RC_ROW_ATAFTER(SEL(r).end, PSCR(r, page).cur)
1605 )
1606 CLEAR_SELECTION(r);
1607 break;
1608 case 1: /* erase to beginning of line */
1609 col = 0;
1610 num = CURCOL + 1;
1611 if (
1612 RC_ROW_ATBEFORE(SEL(r).beg, PSCR(r, page).cur)
1613 || RC_ROW_ATBEFORE(SEL(r).end, PSCR(r, page).cur)
1614 )
1615 CLEAR_SELECTION(r);
1616 break;
1617 case 2: /* erase whole line */
1618 col = 0;
1619 num = r->TermWin.ncol;
1620 PSCR(r, page).tlen[row] = 0;
1621 if (SEL(r).beg.row <= CURROW && SEL(r).end.row >= CURROW)
1622 CLEAR_SELECTION(r);
1623 break;
1624 default:
1625 return;
1626 }
1627
1628 if (PSCR(r, page).text[row])
1629 rxvt_blank_line(&(PSCR(r, page).text[row][col]),
1630 &(PSCR(r, page).rend[row][col]), num, PVTS(r, page)->rstyle);
1631 else
1632 rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1633 PSCR(r, page).rend, row, PVTS(r, page)->rstyle);
1634 }
1635
1636 /* ------------------------------------------------------------------------- */
1637 /*
1638 * Erase part of whole of the screen
1639 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1640 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1641 * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1642 */
1643 /* EXTPROTO */
1644 void
rxvt_scr_erase_screen(rxvt_t * r,int page,int mode)1645 rxvt_scr_erase_screen(rxvt_t* r, int page, int mode)
1646 {
1647 int num;
1648 int32_t row, row_offset;
1649 rend_t ren;
1650 XGCValues gcvalue;
1651
1652 PVTS(r, page)->want_refresh = 1;
1653 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_erase_screen %d (%d) at screen row: %d\n", page, mode, CURROW));
1654 ZERO_SCROLLBACK(r, page);
1655 RESET_CHSTAT(r, page);
1656 row_offset = (int32_t)SVLINES;
1657
1658 switch (mode)
1659 {
1660 case 0: /* erase to end of screen */
1661 rxvt_selection_check(r, page, 1);
1662 rxvt_scr_erase_line(r, page, 0);
1663 row = CURROW + 1; /* possible OOB */
1664 num = r->TermWin.nrow - row;
1665 break;
1666 case 1: /* erase to beginning of screen */
1667 rxvt_selection_check(r, page, 3);
1668 rxvt_scr_erase_line(r, page, 1);
1669 row = 0;
1670 num = CURROW;
1671 break;
1672 case 2: /* erase whole screen */
1673 /*
1674 * 2006-02-15 gi1242: As pointed out by Sabit Sayeed, Gnome terminal
1675 * scrolls the text off screen, instead of wiping it out completely.
1676 * That's seems much better so let's do it here.
1677 */
1678 if( PVTS(r, page)->current_screen == PRIMARY )
1679 {
1680 /*
1681 * Only scroll if the primary screen is bieng cleared.
1682 */
1683 int sr;
1684
1685 /*
1686 * Find the last non-empty line to save.
1687 */
1688 for( sr = SVLINES + r->TermWin.nrow - 1; sr >= SVLINES; sr--)
1689 {
1690 int non_empty = 0, sc;
1691
1692 for( sc = 0; sc < PSCR( r, page).tlen[sr]; sc++)
1693 if (
1694 PSCR( r, page).text[sr][sc] != '\0'
1695 && PSCR( r, page).text[sr][sc] != ' '
1696 )
1697 {
1698 non_empty = 1;
1699 break;
1700 }
1701 ;
1702 if( non_empty ) break;
1703 }
1704
1705 sr -= SVLINES /* - 1 */; /* Dump last non-empty line */
1706 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "Saving %d lines\n", sr));
1707
1708 if( sr > 0)
1709 rxvt_scroll_text(r, page,
1710 PSCR(r, page).tscroll, PSCR(r, page).bscroll,
1711 sr, 0);
1712 }
1713 else rxvt_selection_check(r, page, 3);
1714
1715 row = 0;
1716 num = r->TermWin.nrow;
1717 break;
1718 default:
1719 return;
1720 }
1721
1722 r->h->refresh_type |= REFRESH_BOUNDS;
1723 if(
1724 SEL(r).op && SEL(r).vt == page &&
1725 PVTS(r, page)->current_screen == SEL(r).screen &&
1726 (
1727 (SEL(r).beg.row >= row && SEL(r).beg.row <= row + num) ||
1728 (SEL(r).end.row >= row && SEL(r).end.row <= row + num)
1729 )
1730 )
1731 {
1732 CLEAR_SELECTION(r);
1733 }
1734
1735 if (row >= r->TermWin.nrow) /* Out Of Bounds */
1736 return;
1737
1738 MIN_IT(num, (r->TermWin.nrow - row));
1739 if (PVTS(r, page)->rstyle & (RS_RVid | RS_Uline))
1740 ren = (rend_t) ~RS_None;
1741
1742 else if (GET_BASEBG(PVTS(r, page)->rstyle) == Color_bg)
1743 {
1744 ren = DEFAULT_RSTYLE;
1745 CLEAR_ROWS(row, num);
1746 }
1747
1748 else
1749 {
1750 ren = (PVTS(r, page)->rstyle & (RS_fgMask | RS_bgMask));
1751
1752 gcvalue.foreground = r->pixColors[GET_BGCOLOR(PVTS(r, page)->rstyle)];
1753 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
1754 ERASE_ROWS(row, num);
1755
1756 gcvalue.foreground = r->pixColors[Color_fg];
1757 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
1758 }
1759
1760 for (; num--; row++)
1761 {
1762 rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1763 PSCR(r, page).rend,
1764 (unsigned int)(row + row_offset), PVTS(r, page)->rstyle);
1765 PSCR(r, page).tlen[row + row_offset] = 0;
1766 rxvt_blank_line(PVTS(r, page)->drawn_text[row],
1767 PVTS(r, page)->drawn_rend[row],
1768 (unsigned int) r->TermWin.ncol, ren);
1769 }
1770 }
1771
1772 /* ------------------------------------------------------------------------- */
1773 /*
1774 * Fill the screen with `E's
1775 * XTERM_SEQ: Screen Alignment Test: ESC # 8
1776 */
1777 /* EXTPROTO */
1778 void
rxvt_scr_E(rxvt_t * r,int page)1779 rxvt_scr_E(rxvt_t* r, int page)
1780 {
1781 int i, j, k;
1782 rend_t *r1, fs;
1783
1784 PVTS(r, page)->want_refresh = 1;
1785 r->h->num_scr_allow = 0;
1786 ZERO_SCROLLBACK(r, page);
1787 RESET_CHSTAT(r, page);
1788 rxvt_selection_check(r, page, 3);
1789
1790 fs = PVTS(r, page)->rstyle;
1791 for (k = SVLINES, i = r->TermWin.nrow; i--; k++)
1792 {
1793 /* make the `E's selectable */
1794 PSCR(r, page).tlen[k] = r->TermWin.ncol;
1795 MEMSET(PSCR(r, page).text[k], 'E', r->TermWin.ncol);
1796 for (r1 = PSCR(r, page).rend[k], j = r->TermWin.ncol; j--; )
1797 *r1++ = fs;
1798 }
1799 }
1800
1801 /* ------------------------------------------------------------------------- */
1802 /*
1803 * Insert/Delete <count> lines
1804 */
1805 /* EXTPROTO */
1806 void
rxvt_scr_insdel_lines(rxvt_t * r,int page,int count,int insdel)1807 rxvt_scr_insdel_lines(rxvt_t* r, int page, int count, int insdel)
1808 {
1809 int end;
1810
1811 ZERO_SCROLLBACK(r, page);
1812 RESET_CHSTAT(r, page);
1813 rxvt_selection_check(r, page, 1);
1814
1815 if (CURROW > PSCR(r, page).bscroll)
1816 return;
1817
1818 end = PSCR(r, page).bscroll - CURROW + 1;
1819 if (count > end)
1820 {
1821 if (insdel == DELETE)
1822 return;
1823 else if (insdel == INSERT)
1824 count = end;
1825 }
1826 PSCR(r, page).flags &= ~Screen_WrapNext;
1827
1828 rxvt_scroll_text(r, page, CURROW,
1829 PSCR(r, page).bscroll, insdel * count, 0);
1830 }
1831
1832 /* ------------------------------------------------------------------------- */
1833 /*
1834 * Insert/Delete <count> characters from the current position
1835 */
1836 /* EXTPROTO */
1837 void
rxvt_scr_insdel_chars(rxvt_t * r,int page,int count,int insdel)1838 rxvt_scr_insdel_chars(rxvt_t* r, int page, int count, int insdel)
1839 {
1840 int col, row;
1841 rend_t tr;
1842 text_t* stp;
1843 rend_t* srp;
1844 int16_t* slp;
1845
1846 PVTS(r, page)->want_refresh = 1;
1847 ZERO_SCROLLBACK(r, page);
1848 #if 0
1849 RESET_CHSTAT(r, page);
1850 #endif
1851 if (count <= 0)
1852 return;
1853
1854 rxvt_selection_check(r, page, 1);
1855 MIN_IT(count, (r->TermWin.ncol - CURCOL));
1856
1857 row = CURROW + SVLINES;
1858 PSCR(r, page).flags &= ~Screen_WrapNext;
1859
1860 stp = PSCR(r, page).text[row];
1861 srp = PSCR(r, page).rend[row];
1862 slp = &(PSCR(r, page).tlen[row]);
1863 switch (insdel)
1864 {
1865 case INSERT:
1866 for (col = r->TermWin.ncol - 1; (col - count) >= CURCOL; col--)
1867 {
1868 stp[col] = stp[col - count];
1869 srp[col] = srp[col - count];
1870 }
1871 if (*slp != -1)
1872 {
1873 *slp += count;
1874 MIN_IT(*slp, r->TermWin.ncol);
1875 }
1876 if (
1877 SEL(r).op && SEL(r).vt == page
1878 && PVTS(r, page)->current_screen == SEL(r).screen
1879 && RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)
1880 )
1881 {
1882 if (
1883 SEL(r).end.row != CURROW
1884 || (SEL(r).end.col + count >= r->TermWin.ncol)
1885 )
1886 CLEAR_SELECTION(r);
1887 else /* shift selection */
1888 {
1889 SEL(r).beg.col += count;
1890 SEL(r).mark.col += count; /* XXX: yes? */
1891 SEL(r).end.col += count;
1892 }
1893 }
1894 rxvt_blank_line(&(stp[CURCOL]),
1895 &(srp[CURCOL]),
1896 (unsigned int)count, PVTS(r, page)->rstyle);
1897 break;
1898
1899 case ERASE:
1900 CURCOL += count; /* don't worry if > r->TermWin.ncol */
1901 rxvt_selection_check(r, page, 1);
1902 CURCOL -= count;
1903 rxvt_blank_line(&(stp[CURCOL]),
1904 &(srp[CURCOL]),
1905 (unsigned int)count, PVTS(r, page)->rstyle);
1906 break;
1907
1908 case DELETE:
1909 tr = srp[r->TermWin.ncol - 1]
1910 & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1911 for (col = CURCOL; (col + count) < r->TermWin.ncol; col++)
1912 {
1913 stp[col] = stp[col + count];
1914 srp[col] = srp[col + count];
1915 }
1916 rxvt_blank_line(&(stp[r->TermWin.ncol - count]),
1917 &(srp[r->TermWin.ncol - count]),
1918 (unsigned int)count, tr);
1919 if (*slp == -1) /* break line continuation */
1920 *slp = r->TermWin.ncol;
1921 *slp -= count;
1922 MAX_IT(*slp, 0);
1923 if (
1924 SEL(r).op && SEL(r).vt == page
1925 && PVTS(r, page)->current_screen == SEL(r).screen
1926 && RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)
1927 )
1928 {
1929 if (
1930 SEL(r).end.row != CURROW
1931 || (CURCOL >= SEL(r).beg.col - count)
1932 || SEL(r).end.col >= r->TermWin.ncol
1933 )
1934 CLEAR_SELECTION(r);
1935 else
1936 {
1937 /* shift selection */
1938 SEL(r).beg.col -= count;
1939 SEL(r).mark.col -= count; /* XXX: yes? */
1940 SEL(r).end.col -= count;
1941 }
1942 }
1943 break;
1944 }
1945 #if 0
1946 if (IS_MULTI2(srp[0]))
1947 {
1948 srp[0] &= ~RS_multiMask;
1949 stp[0] = ' ';
1950 }
1951 if (IS_MULTI1(srp[r->TermWin.ncol - 1]))
1952 {
1953 srp[r->TermWin.ncol - 1] &= ~RS_multiMask;
1954 stp[r->TermWin.ncol - 1] = ' ';
1955 }
1956 #endif
1957 }
1958
1959 /* ------------------------------------------------------------------------- */
1960 /*
1961 * Set the scrolling region
1962 * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1963 */
1964 /* EXTPROTO */
1965 void
rxvt_scr_scroll_region(rxvt_t * r,int page,int top,int bot)1966 rxvt_scr_scroll_region(rxvt_t* r, int page, int top, int bot)
1967 {
1968 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN,
1969 "rxvt_scr_scroll_region( %d, %d, %d)\n", page, top, bot));
1970
1971 MAX_IT(top, 0);
1972 MIN_IT(bot, (int)r->TermWin.nrow - 1);
1973 if (top > bot)
1974 return;
1975 PSCR(r, page).tscroll = top;
1976 PSCR(r, page).bscroll = bot;
1977 rxvt_scr_gotorc(r, page, 0, 0, 0);
1978 }
1979
1980 /* ------------------------------------------------------------------------- */
1981 /*
1982 * Make the cursor visible/invisible
1983 * XTERM_SEQ: Make cursor visible : ESC [ ? 25 h
1984 * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1985 */
1986 /* EXTPROTO */
1987 void
rxvt_scr_cursor_visible(rxvt_t * r,int page,int mode)1988 rxvt_scr_cursor_visible(rxvt_t* r, int page, int mode)
1989 {
1990 PVTS(r, page)->want_refresh = 1;
1991 if (mode)
1992 PSCR(r, page).flags |= Screen_VisibleCursor;
1993 else
1994 PSCR(r, page).flags &= ~Screen_VisibleCursor;
1995 }
1996
1997 /* ------------------------------------------------------------------------- */
1998 /*
1999 * Set/unset automatic wrapping
2000 * XTERM_SEQ: Set Wraparound : ESC [ ? 7 h
2001 * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
2002 */
2003 /* EXTPROTO */
2004 void
rxvt_scr_autowrap(rxvt_t * r,int page,int mode)2005 rxvt_scr_autowrap(rxvt_t* r, int page, int mode)
2006 {
2007 if (mode)
2008 PSCR(r, page).flags |= Screen_Autowrap;
2009 else
2010 PSCR(r, page).flags &= ~(Screen_Autowrap | Screen_WrapNext);
2011 }
2012
2013 /* ------------------------------------------------------------------------- */
2014 /*
2015 * Set/unset margin origin mode
2016 * Absolute mode: line numbers are counted relative to top margin of screen
2017 * and the cursor can be moved outside the scrolling region.
2018 * Relative mode: line numbers are relative to top margin of scrolling region
2019 * and the cursor cannot be moved outside.
2020 * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
2021 * XTERM_SEQ: Set Relative: ESC [ ? 6 l
2022 */
2023 /* EXTPROTO */
2024 void
rxvt_scr_relative_origin(rxvt_t * r,int page,int mode)2025 rxvt_scr_relative_origin(rxvt_t* r, int page, int mode)
2026 {
2027 if (mode)
2028 PSCR(r, page).flags |= Screen_Relative;
2029 else
2030 PSCR(r, page).flags &= ~Screen_Relative;
2031 rxvt_scr_gotorc(r, page, 0, 0, 0);
2032 }
2033
2034 /* ------------------------------------------------------------------------- */
2035 /*
2036 * Set insert/replace mode
2037 * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
2038 * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
2039 */
2040 /* EXTPROTO */
2041 void
rxvt_scr_insert_mode(rxvt_t * r,int page,int mode)2042 rxvt_scr_insert_mode(rxvt_t* r, int page, int mode)
2043 {
2044 if (mode)
2045 PSCR(r, page).flags |= Screen_Insert;
2046 else
2047 PSCR(r, page).flags &= ~Screen_Insert;
2048 }
2049
2050 /* ------------------------------------------------------------------------- */
2051 /*
2052 * Set/Unset tabs
2053 * XTERM_SEQ: Set tab at current column : ESC H
2054 * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
2055 * XTERM_SEQ: Clear all tabs : ESC [ 3 g
2056 */
2057 /* EXTPROTO */
2058 void
rxvt_scr_set_tab(rxvt_t * r,int page,int mode)2059 rxvt_scr_set_tab(rxvt_t* r, int page, int mode)
2060 {
2061 if (mode < 0)
2062 MEMSET(r->tabstop, 0, r->TermWin.ncol * sizeof(char));
2063 else if (PSCR(r, page).cur.col < r->TermWin.ncol)
2064 r->tabstop[PSCR(r, page).cur.col] = (mode ? 1 : 0);
2065 }
2066
2067 /* ------------------------------------------------------------------------- */
2068 /*
2069 * Set reverse/normal video
2070 * XTERM_SEQ: Reverse video: ESC [ ? 5 h
2071 * XTERM_SEQ: Normal video : ESC [ ? 5 l
2072 */
2073 /* EXTPROTO */
2074 void
rxvt_scr_rvideo_mode(rxvt_t * r,int page,int mode)2075 rxvt_scr_rvideo_mode(rxvt_t* r, int page, int mode)
2076 {
2077 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "%s(r, page=%d, mode=%d)\n", __func__, page, mode ));
2078
2079 if (PVTS(r, page)->rvideo != mode)
2080 {
2081 PVTS(r, page)->rvideo = mode;
2082
2083 SWAP_IT( PVTS(r, page)->p_fg, PVTS(r, page)->p_bg, unsigned long );
2084 #ifdef XFT_SUPPORT
2085 if( ISSET_OPTION( r, Opt_xft ) )
2086 SWAP_IT( PVTS(r, page)->p_xftfg, PVTS(r, page)->p_xftbg, XftColor );
2087 #endif
2088 if( r->TermWin.fade )
2089 {
2090 SWAP_IT( PVTS(r, page)->p_fgfade, PVTS(r, page)->p_bgfade,
2091 unsigned long );
2092 #ifdef XFT_SUPPORT
2093 if( ISSET_OPTION( r, Opt_xft ) )
2094 SWAP_IT( PVTS(r, page)->p_xftfgfade, PVTS(r, page)->p_xftbgfade,
2095 XftColor );
2096 #endif
2097 }
2098
2099 if( page == ATAB(r) )
2100 {
2101 /* Background colors need to be forcibly reset */
2102 r->fgbg_tabnum = -1;
2103 rxvt_set_vt_colors( r, ATAB(r) );
2104 }
2105
2106 rxvt_scr_clear( r, page );
2107 rxvt_scr_touch( r, page, True );
2108 }
2109 }
2110
2111 /* ------------------------------------------------------------------------- */
2112 /*
2113 * Report current cursor position
2114 * XTERM_SEQ: Report position: ESC [ 6 n
2115 */
2116 /* EXTPROTO */
2117 void
rxvt_scr_report_position(rxvt_t * r,int page)2118 rxvt_scr_report_position(rxvt_t* r, int page)
2119 {
2120 rxvt_tt_printf(r, page, "\033[%d;%dR", CURROW + 1, CURCOL + 1);
2121 }
2122
2123 /* ------------------------------------------------------------------------- *
2124 * FONTS *
2125 * ------------------------------------------------------------------------- */
2126
2127 /*
2128 * Set font style
2129 */
2130 /* INTPROTO */
2131 void
rxvt_set_font_style(rxvt_t * r,int page)2132 rxvt_set_font_style(rxvt_t *r, int page)
2133 {
2134 PVTS(r, page)->rstyle &= ~RS_fontMask;
2135 switch (PVTS(r, page)->charsets[PSCR(r, page).charset])
2136 {
2137 case '0': /* DEC Special Character & Line Drawing Set */
2138 PVTS(r, page)->rstyle |= RS_acsFont;
2139 break;
2140 case 'A': /* United Kingdom (UK) */
2141 PVTS(r, page)->rstyle |= RS_ukFont;
2142 break;
2143 case 'B': /* United States (USASCII) */
2144 break;
2145 case '<': /* Multinational character set */
2146 break;
2147 case '5': /* Finnish character set */
2148 break;
2149 case 'C': /* Finnish character set */
2150 break;
2151 case 'K': /* German character set */
2152 break;
2153 }
2154 }
2155
2156 /* ------------------------------------------------------------------------- */
2157 /*
2158 * Choose a font
2159 * XTERM_SEQ: Invoke G0 character set: CTRL-O
2160 * XTERM_SEQ: Invoke G1 character set: CTRL-N
2161 * XTERM_SEQ: Invoke G2 character set: ESC N
2162 * XTERM_SEQ: Invoke G3 character set: ESC O
2163 */
2164 /* EXTPROTO */
2165 void
rxvt_scr_charset_choose(rxvt_t * r,int page,int set)2166 rxvt_scr_charset_choose(rxvt_t* r, int page, int set)
2167 {
2168 PSCR(r, page).charset = set;
2169 rxvt_set_font_style(r, page);
2170 }
2171
2172 /* ------------------------------------------------------------------------- */
2173 /*
2174 * Set a font
2175 * XTERM_SEQ: Set G0 character set: ESC ( <C>
2176 * XTERM_SEQ: Set G1 character set: ESC ) <C>
2177 * XTERM_SEQ: Set G2 character set: ESC * <C>
2178 * XTERM_SEQ: Set G3 character set: ESC + <C>
2179 * See set_font_style for possible values for <C>
2180 */
2181 /* EXTPROTO */
2182 void
rxvt_scr_charset_set(rxvt_t * r,int page,int set,unsigned int ch)2183 rxvt_scr_charset_set(rxvt_t* r, int page, int set, unsigned int ch)
2184 {
2185 #ifdef MULTICHAR_SET
2186 PVTS(r, page)->multi_byte = !!(set < 0);
2187 set = abs(set);
2188 #endif
2189 PVTS(r, page)->charsets[set] = (unsigned char)ch;
2190 rxvt_set_font_style(r, page);
2191 }
2192
2193
2194 /* ------------------------------------------------------------------------- *
2195 * MAJOR SCREEN MANIPULATION *
2196 * ------------------------------------------------------------------------- */
2197
2198 /*
2199 * Refresh an area
2200 */
2201 enum
2202 {
2203 PART_BEG = 0,
2204 PART_END,
2205 RC_COUNT
2206 };
2207
2208 /* EXTPROTO */
2209 void
rxvt_scr_expose(rxvt_t * r,int page,int x,int y,int width,int height,Bool refresh)2210 rxvt_scr_expose(rxvt_t* r, int page,
2211 int x, int y, int width, int height,
2212 Bool refresh)
2213 {
2214 int i;
2215 row_col_t rc[RC_COUNT];
2216
2217 if (PVTS(r, page)->drawn_text == NULL) /* sanity check */
2218 return;
2219
2220 x = max(x, (int)r->TermWin.int_bwidth);
2221 x = min(x, (int)r->szHint.width);
2222 y = max(y, (int)r->TermWin.int_bwidth);
2223 y = min(y, (int)r->szHint.height);
2224
2225 /* round down */
2226 rc[PART_BEG].col = Pixel2Col(x);
2227 rc[PART_BEG].row = Pixel2Row(y);
2228 /* round up */
2229 rc[PART_END].col = Pixel2Width(x + width + r->TermWin.fwidth - 1);
2230 rc[PART_END].row = Pixel2Row(y + height + r->TermWin.fheight - 1);
2231
2232 /* sanity checks */
2233 for (i = PART_BEG; i < RC_COUNT; i++)
2234 {
2235 MIN_IT(rc[i].col, r->TermWin.ncol - 1);
2236 MIN_IT(rc[i].row, r->TermWin.nrow - 1);
2237 }
2238
2239 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
2240
2241 {
2242 register int j = rc[PART_BEG].col;
2243 register int k = rc[PART_END].col - rc[PART_BEG].col + 1;
2244
2245 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
2246 {
2247 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, " memset drawn_text[%d][%d], len=%d\n", i, j, k));
2248 MEMSET(&(PVTS(r, page)->drawn_text[i][j]), 0, k);
2249 }
2250 }
2251
2252 if (refresh)
2253 {
2254 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "Forcing immediate screen refresh"));
2255 rxvt_scr_refresh(r, page, SLOW_REFRESH | REFRESH_BOUNDS);
2256 }
2257 }
2258
2259
2260 /* ------------------------------------------------------------------------- */
2261 /*
2262 * Refresh the entire screen
2263 */
2264 /* EXTPROTO */
2265 void
rxvt_scr_touch(rxvt_t * r,int page,Bool refresh)2266 rxvt_scr_touch(rxvt_t* r, int page, Bool refresh)
2267 {
2268 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_touch\n"));
2269 rxvt_scr_expose(r, page, 0, 0, VT_WIDTH(r), VT_HEIGHT(r), refresh);
2270 }
2271
2272 /* ------------------------------------------------------------------------- */
2273 /*
2274 * Move the display so that the line represented by scrollbar value Y is at
2275 * the top of the screen
2276 */
2277 /* EXTPROTO */
2278 int
rxvt_scr_move_to(rxvt_t * r,int page,int y,int len)2279 rxvt_scr_move_to(rxvt_t* r, int page, int y, int len)
2280 {
2281 long p = 0;
2282 uint16_t oldviewstart;
2283
2284 oldviewstart = VSTART;
2285 if (y < len)
2286 {
2287 p = (r->TermWin.nrow + PVTS(r, page)->nscrolled) * (len - y) / len;
2288 p -= (long)(r->TermWin.nrow - 1);
2289 p = max(p, 0);
2290 }
2291 VSTART = (uint16_t)min(p, PVTS(r, page)->nscrolled);
2292 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_move_to %d (%d, %d) view_start:%d\n", page, y, len, VSTART));
2293
2294 return rxvt_scr_change_view(r, page, oldviewstart);
2295 }
2296
2297 /* ------------------------------------------------------------------------- */
2298 /*
2299 * Page the screen up/down nlines
2300 * direction should be UP or DN
2301 */
2302 /* EXTPROTO */
2303 int
rxvt_scr_page(rxvt_t * r,int page,enum page_dirn direction,int nlines)2304 rxvt_scr_page(rxvt_t* r, int page, enum page_dirn direction, int nlines)
2305 {
2306 int n;
2307 uint16_t oldviewstart;
2308
2309 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_page %d (%s, %d) view_start:%d\n", page, ((direction == UP) ? "UP" : "DN"), nlines, VSTART));
2310
2311 oldviewstart = VSTART;
2312 if (direction == UP)
2313 {
2314 n = VSTART + nlines;
2315 VSTART = min(n, PVTS(r, page)->nscrolled);
2316 }
2317 else
2318 {
2319 n = VSTART - nlines;
2320 VSTART = max(n, 0);
2321 }
2322 return rxvt_scr_change_view(r, page, oldviewstart);
2323 }
2324
2325
2326 /* INTPROTO */
2327 int
rxvt_scr_change_view(rxvt_t * r,int page,uint16_t oldviewstart)2328 rxvt_scr_change_view(rxvt_t* r, int page, uint16_t oldviewstart)
2329 {
2330 if (VSTART != oldviewstart)
2331 {
2332 PVTS(r, page)->want_refresh = 1;
2333 PVTS(r, page)->num_scr -= (VSTART - oldviewstart);
2334 }
2335 return (int)(VSTART - oldviewstart);
2336 }
2337
2338
2339 /* ------------------------------------------------------------------------- */
2340 /* EXTPROTO */
2341 void
rxvt_scr_bell(rxvt_t * r,int page)2342 rxvt_scr_bell(rxvt_t *r, int page)
2343 {
2344 #ifndef NO_BELL
2345
2346 #if defined(THROTTLE_BELL_MSEC) && THROTTLE_BELL_MSEC > 0
2347 /* Maximal number of bell per pre-defined time interval */
2348 static int bellcount = 0;
2349 static struct timeval lastBell = {0, 0};
2350 struct timeval tvnow = {0, 0};
2351 long tminterval;
2352
2353 #ifdef HAVE_NANOSLEEP
2354 struct timespec rqt;
2355
2356 rqt.tv_sec = r->TermWin.vBellDuration / 1000000000ul;
2357 rqt.tv_nsec = r->TermWin.vBellDuration % 1000000000ul;
2358 #endif
2359
2360 if (gettimeofday (&tvnow, NULL) >= 0)
2361 {
2362 if (0 == lastBell.tv_sec && 0 == lastBell.tv_usec)
2363 /* first time bell, try avoid integer overflow */
2364 tminterval = 0;
2365
2366 else
2367 tminterval = (tvnow.tv_sec - lastBell.tv_sec) * 1000 +
2368 (tvnow.tv_usec - lastBell.tv_usec) / 1000;
2369
2370 lastBell = tvnow;
2371 if (tminterval > THROTTLE_BELL_MSEC)
2372 bellcount = 1;
2373
2374 else if (bellcount ++ >= THROTTLE_BELL_COUNT)
2375 return;
2376 }
2377 #endif /* THROTTLE_BELL_MSEC && THROTTLE_BELL_MSEC > 0 */
2378
2379 # ifndef NO_MAPALERT
2380 # ifdef MAPALERT_OPTION
2381 if (ISSET_OPTION(r, Opt_mapAlert))
2382 # endif
2383 XMapWindow(r->Xdisplay, r->TermWin.parent);
2384 # endif
2385 if(
2386 ISSET_OPTION(r, Opt_visualBell) ||
2387 (
2388 ISSET_OPTION( r, Opt_currentTabVBell ) && APAGE(r) == page
2389 && r->TermWin.focus
2390 )
2391 )
2392 {
2393 /*
2394 * Visual bells don't need to be rung on windows which are not visible.
2395 */
2396 if( APAGE(r) != page || r->h->refresh_type == NO_REFRESH )
2397 return;
2398
2399 #if defined(TRANSPARENT) || defined(BACKGROUND_IMAGE)
2400 /*
2401 * Reverse video bell doesn't look so good with transparency or a
2402 * background pixmap. Flash screen ourselves.
2403 */
2404 if (
2405 # ifdef TRANSPARENT
2406 r->h->am_transparent || r->h->am_pixmap_trans
2407 # ifdef BACKGROUND_IMAGE
2408 ||
2409 # endif
2410 # endif
2411 # ifdef BACKGROUND_IMAGE
2412 IS_PIXMAP(PVTS(r, page)->pixmap)
2413 # endif
2414 )
2415 {
2416 XGCValues values;
2417
2418 XGetGCValues( r->Xdisplay, r->TermWin.gc,
2419 GCForeground | GCFillStyle, &values);
2420
2421 XSetForeground( r->Xdisplay, r->TermWin.gc,
2422 r->pixColors[Color_fg] );
2423 XSetFillStyle( r->Xdisplay, r->TermWin.gc, FillSolid);
2424
2425 XFillRectangle( r->Xdisplay, PVTS(r, page)->vt, r->TermWin.gc,
2426 Row2Pixel(0), Col2Pixel(0),
2427 Width2Pixel( r->TermWin.ncol),
2428 Height2Pixel( r->TermWin.nrow) );
2429
2430 XChangeGC( r->Xdisplay, r->TermWin.gc,
2431 GCForeground | GCFillStyle, &values);
2432
2433 XSync( r->Xdisplay, False);
2434
2435 #ifdef HAVE_NANOSLEEP
2436 if( r->TermWin.vBellDuration )
2437 nanosleep(&rqt, NULL);
2438 #endif
2439
2440 XClearArea( r->Xdisplay, PVTS(r, page)->vt, 0, 0, 0, 0, True);
2441 }
2442 else
2443 #endif /* TRANSPARENT || BACKGROUND_IMAGE */
2444 {
2445 /* refresh also done */
2446 rxvt_scr_rvideo_mode(r, page, !PVTS(r, page)->rvideo);
2447
2448 #ifdef HAVE_NANOSLEEP
2449 rxvt_scr_refresh( r, page, r->h->refresh_type );
2450 XSync( r->Xdisplay, False );
2451 if( r->TermWin.vBellDuration )
2452 nanosleep(&rqt, NULL);
2453 #endif
2454 rxvt_scr_rvideo_mode(r, page, !PVTS(r, page)->rvideo);
2455 }
2456 }
2457
2458 else if( r->h->rs[Rs_bellCommand] && *r->h->rs[Rs_bellCommand] )
2459 rxvt_async_exec( r, r->h->rs[Rs_bellCommand] );
2460
2461 else
2462 XBell(r->Xdisplay, 0);
2463 #endif /* NO_BELL */
2464 }
2465
2466 /* ------------------------------------------------------------------------- */
2467
2468 #ifdef PRINTPIPE
2469 /*
2470 * Generate escape sequences (not including the "\e[0") to reproduce screen
2471 * rendition attributes for the foreground / background color. If "fg" is true,
2472 * then sequences for the foreground color are generated, otherwise sequences
2473 * for setting the background color are generated.
2474 *
2475 * Returns a pointer to the character after the escape sequence written. If no
2476 * further attributes are to be added, strip the trailing ";".
2477 */
2478 /* INTPROTO */
2479 char *
escSetColor(char * s,int color,int fg)2480 escSetColor( char *s, int color, int fg)
2481 {
2482 if( color >= minCOLOR && color < minCOLOR + 8 )
2483 s += sprintf( s, "%c%d;", fg ? '3' : '4', color - minCOLOR );
2484 #ifndef NO_BRIGHTCOLOR
2485 else if( color >= minBrightCOLOR && color <= maxBrightCOLOR )
2486 s += sprintf( s, "%s%d;", fg ? "9" : "10", color - minBrightCOLOR );
2487 #endif
2488 #ifdef TTY_256COLOR
2489 else if( color >= min256COLOR && color <= max256COLOR )
2490 s += sprintf( s, "%c8;5;%d;", fg ? '3' : '4',
2491 color - min256COLOR + 16 );
2492 #endif
2493 else
2494 assert(0);
2495
2496 return s;
2497 }
2498 #endif
2499
2500 /*
2501 * Print the screen into the printer pipe. If fullhist != 0, then the entire
2502 * scroll back buffer is also dumped.
2503 */
2504 /* EXTPROTO */
2505 void
rxvt_scr_printscreen(rxvt_t * r,int page,int fullhist,int pretty,int linecont,const char * pipeName)2506 rxvt_scr_printscreen(rxvt_t* r, int page, int fullhist, int pretty,
2507 int linecont, const char *pipeName )
2508 {
2509 #ifdef PRINTPIPE
2510 int row, col, nrows, row_offset;
2511 text_t *txt;
2512 rend_t *rnd;
2513
2514 FILE* fd;
2515
2516
2517 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_printscreen( r, %d, %d, %d, %s )\n", page, fullhist, pretty, pipeName ));
2518
2519 if ( ( fd = rxvt_popen_printer( r, pipeName ) ) == NULL )
2520 return;
2521
2522 nrows = r->TermWin.nrow;
2523 row_offset = SVLINES;
2524 if (!fullhist)
2525 row_offset -= VSTART;
2526 else
2527 {
2528 nrows += PVTS(r, page)->nscrolled;
2529 row_offset -= PVTS(r, page)->nscrolled;
2530 }
2531
2532 for( row=0; row < nrows && !ferror( fd ); row++ )
2533 {
2534 int lineEnd;
2535
2536 txt = PSCR( r, page ).text[ row + row_offset ];
2537 rnd = PSCR( r, page ).rend[ row + row_offset ];
2538
2539 if( linecont && PSCR(r, page).tlen[row+row_offset] == -1 )
2540 /* Line continues over. Don't trim trailing spaces */
2541 lineEnd = r->TermWin.ncol - 1;
2542 else
2543 {
2544 /* Trim trailing spaces */
2545 for(
2546 lineEnd = r->TermWin.ncol - 1;
2547 lineEnd >= 0 && isspace( txt[lineEnd] );
2548 lineEnd--
2549 )
2550 ;
2551 }
2552
2553 if( pretty )
2554 {
2555 /* Print colors as escape sequences */
2556
2557 for( col=0; col <= lineEnd; )
2558 {
2559 char escsq[32]; /* Buffer to hold the escape sequence. 29
2560 bytes are enough. */
2561 char *s, *t;
2562 int start = col;
2563 int color;
2564
2565 rend_t rend = rnd[start];
2566
2567 /* Get longest string with constant rendition attrs */
2568
2569 do
2570 {
2571 col++;
2572 }
2573 while( col <= lineEnd && rnd[col] == rend );
2574
2575
2576 t = s = escsq + sprintf( escsq, "\e[" );
2577
2578 if( rend & RS_Bold ) s += sprintf( s, "1;" );
2579 if( rend & RS_Uline ) s += sprintf( s, "4;" );
2580 if( rend & RS_Blink ) s += sprintf( s, "5;" );
2581 if( rend & RS_RVid ) s += sprintf( s, "7;" );
2582
2583 color = GET_BASEFG( rend );
2584 if( color != Color_fg )
2585 s = escSetColor( s, color, 1 );
2586
2587 color = GET_BASEBG( rend );
2588 if( color != Color_bg )
2589 s = escSetColor( s, color, 0 );
2590
2591 if( s != t )
2592 {
2593 /*
2594 * Some esc seq has been set. Null terminate and Replace
2595 * trailing ';' with 'm'
2596 */
2597 *(s--) = '\0';
2598 *s = 'm';
2599
2600 fprintf( fd, "%s%.*s\e[0m", escsq, col-start, txt+start );
2601 }
2602
2603 else
2604 fprintf( fd, "%.*s", col - start, txt + start );
2605
2606 }
2607 } /* if( pretty ) */
2608
2609 else
2610 /* Vanilla text */
2611 fprintf( fd, "%.*s", (lineEnd + 1), txt );
2612
2613 if( !linecont || PSCR(r, page).tlen[row+row_offset] != -1 )
2614 fputc( '\n', fd );
2615
2616 } /* for( row ... ) */
2617
2618 rxvt_pclose_printer(fd);
2619 #endif
2620 }
2621
2622
2623 #ifdef TEXT_SHADOW
2624 /*
2625 * If refreshRegion is not None, then we should intersect our clipping with it.
2626 */
2627 /* INTPROTO */
2628 # ifdef XFT_SUPPORT
2629 void
rxvt_set_clipping(rxvt_t * r,XftDraw * xftdraw,GC gc,Region refreshRegion,int x,int y,unsigned width,unsigned height,int * offx,int * offy)2630 rxvt_set_clipping (rxvt_t* r, XftDraw *xftdraw, GC gc, Region refreshRegion,
2631 int x, int y, unsigned width, unsigned height,
2632 int* offx, int* offy)
2633 # else
2634 void
2635 rxvt_set_clipping (rxvt_t* r, __attribute__((unused)) void *xftdraw,
2636 GC gc, Region refreshRegion,
2637 int x, int y, unsigned width, unsigned height,
2638 int* offx, int* offy)
2639 # endif
2640 {
2641 /*
2642 * mfont is a flag whether the output string is multi-byte. if so, we need
2643 * to extend its length twice assuming string is 2-byte string
2644 */
2645 XRectangle rect;
2646 Region region;
2647
2648 /* Sanity check */
2649 assert (offx);
2650 assert (offy);
2651
2652 if (SHADOW_NONE == r->TermWin.shadow_mode)
2653 {
2654 *offx = *offy = 0;
2655 return; /* shortcut */
2656 }
2657
2658 switch (r->TermWin.shadow_mode)
2659 {
2660 case SHADOW_TOP:
2661 *offx = 0;
2662 *offy = -1;
2663 break;
2664 case SHADOW_BOTTOM:
2665 *offx = 0;
2666 *offy = 1;
2667 break;
2668 case SHADOW_LEFT:
2669 *offx = -1;
2670 *offy = 0;
2671 break;
2672 case SHADOW_RIGHT:
2673 *offx = 1;
2674 *offy = 0;
2675 break;
2676 case SHADOW_TOPLEFT:
2677 *offx = -1;
2678 *offy = -1;
2679 break;
2680 case SHADOW_TOPRIGHT:
2681 *offx = 1;
2682 *offy = -1;
2683 break;
2684 case SHADOW_BOTLEFT:
2685 *offx = -1;
2686 *offy = 1;
2687 break;
2688 case SHADOW_BOTRIGHT:
2689 *offx = 1;
2690 *offy = 1;
2691 break;
2692 default:
2693 assert (0);
2694 break;
2695 }
2696
2697 #if 0
2698 rect.width = Width2Pixel(1) * len * (mfont+1);
2699 rect.height = Height2Pixel(1) * 1;
2700
2701 rect.x += x;
2702 rect.y += (y - rect.height);
2703 #endif
2704
2705 /*
2706 * Left / right dropped pixels are cleaned up by pixel dropping avoidance
2707 * under Xft, so we can add that to our offset.
2708 */
2709 rect.x =
2710 #ifdef XFT_SUPPORT
2711 (ISSET_OPTION(r, Opt_xft) && xftdraw) ? x + *offx :
2712 #endif
2713 x;
2714 rect.y = y;
2715 rect.width = width;
2716 rect.height = height;
2717
2718 region = XCreateRegion();
2719 XUnionRectWithRegion( &rect, region, region);
2720 if (IS_REGION(refreshRegion))
2721 XIntersectRegion( region, refreshRegion, region);
2722
2723 XSetRegion( r->Xdisplay, gc, region);
2724 /*
2725 * XSetClipRectangles (r->Xdisplay, gc, x, y-hy, &rectangle, 1, Unsorted);
2726 */
2727 #ifdef XFT_SUPPORT
2728 if( ISSET_OPTION(r, Opt_xft) && xftdraw )
2729 XftDrawSetClip( xftdraw, region);
2730 #endif
2731
2732 XDestroyRegion( region );
2733 }
2734
2735
2736 /* INTPROTO */
2737 void
2738 # ifdef XFT_SUPPORT
rxvt_free_clipping(rxvt_t * r,XftDraw * xftdraw,GC gc,Region refreshRegion)2739 rxvt_free_clipping (rxvt_t* r, XftDraw* xftdraw, GC gc, Region refreshRegion)
2740 # else
2741 rxvt_free_clipping (rxvt_t* r, void* xftdraw, GC gc, Region refreshRegion)
2742 # endif
2743 {
2744
2745 if (SHADOW_NONE == r->TermWin.shadow_mode)
2746 return; /* shortcut */
2747
2748 if (IS_REGION(refreshRegion))
2749 XSetRegion( r->Xdisplay, gc, refreshRegion );
2750 else
2751 XSetClipMask( r->Xdisplay, gc, None);
2752
2753 # ifdef XFT_SUPPORT
2754 if( ISSET_OPTION(r, Opt_xft) && xftdraw)
2755 XftDrawSetClip( xftdraw, refreshRegion );
2756 # endif /* XFT_SUPPORT */
2757 }
2758 #endif /* TEXT_SHADOW */
2759
2760
2761 void static inline
rxvt_clear_area(rxvt_t * r,int page,int x,int y,unsigned int w,unsigned int h)2762 rxvt_clear_area (rxvt_t* r, int page, int x, int y, unsigned int w, unsigned int h)
2763 {
2764 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "clear area (%d, %d, %d, %d)\n", x,y,w,h));
2765
2766 XClearArea (r->Xdisplay, drawBuffer, x, y, w, h, False);
2767 }
2768
2769
2770 void static inline
rxvt_fill_rectangle(rxvt_t * r,int page,int x,int y,unsigned int w,unsigned int h)2771 rxvt_fill_rectangle (rxvt_t* r, int page, int x, int y, unsigned int w, unsigned int h)
2772 {
2773 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "fill rectangle (%d, %d, %d, %d)\n", x,y,w,h));
2774 XFillRectangle (r->Xdisplay, drawBuffer, r->TermWin.gc, x, y, w, h);
2775 }
2776
2777
2778 /* ------------------------------------------------------------------------- */
2779 /*
2780 * Refresh the screen
2781 * PVTS(r, page)->drawn_text/PVTS(r, page)->drawn_rend contain the screen information before the update.
2782 * PSCR(r, page).text/PSCR(r, page).rend contain what the screen will change to.
2783 */
2784
2785
2786 #define X11_DRAW_STRING_8 (1)
2787 #define X11_DRAW_STRING_16 (2)
2788 #define X11_DRAW_IMAGE_STRING_8 (3)
2789 #define X11_DRAW_IMAGE_STRING_16 (4)
2790 #define XFT_DRAW_STRING_8 (5)
2791 #define XFT_DRAW_STRING_16 (6)
2792 #define XFT_DRAW_STRING_32 (7)
2793 #define XFT_DRAW_STRING_UTF8 (8)
2794 #define XFT_DRAW_IMAGE_STRING_8 (9)
2795 #define XFT_DRAW_IMAGE_STRING_16 (10)
2796 #define XFT_DRAW_IMAGE_STRING_32 (11)
2797 #define XFT_DRAW_IMAGE_STRING_UTF8 (12)
2798
2799 #ifdef XFT_SUPPORT
2800 #define XFTDRAW_STRING(xdraw, color, font, x, y, str, len) \
2801 ( ( rend & RS_acsFont) ? \
2802 (xftDrawACSString( r->Xdisplay, d, gc, \
2803 xftdraw_string, \
2804 (xdraw), (color), (font), (x), (y), \
2805 (unsigned char*) (str), (len))) : \
2806 (xftdraw_string( (xdraw), (color), (font), (x), (y), (str), (len))))
2807 /*
2808 * len: number of characters to draw. for UTF-8 string, it is the
2809 * number of characters * 2 of the original 16-bits string
2810 *
2811 * pfont: Weather to use xftpfn (if defined) or not.
2812 *
2813 * refreshRegion: If set, then any changes made to clipping are undone by
2814 * resetting them to this. (Pass None for no region).
2815 */
2816 /* EXTPROTO */
2817 void
rxvt_draw_string_xft(rxvt_t * r,Drawable d,GC gc,Region refreshRegion,rend_t rend,int pfont,XftDraw * win,XftColor * fore,int x,int y,char * str,int len,void (* xftdraw_string)())2818 rxvt_draw_string_xft (rxvt_t* r, Drawable d, GC gc, Region refreshRegion,
2819 rend_t rend, int pfont,
2820 XftDraw* win, XftColor* fore, int x, int y, char* str, int len,
2821 void (*xftdraw_string)())
2822 {
2823 XftFont *font;
2824
2825 /*
2826 * If "multichar" stuff is needed in tab titles etc, then xftpfont /
2827 * xftPfont must be multichar capable. If that's not an option, then set
2828 * xftpfont to NULL, and the correct multichar font will be used.
2829 */
2830 if( pfont && r->TermWin.xftpfont )
2831 {
2832 font = ( pfont == USE_BOLD_PFONT) ?
2833 r->TermWin.xftPfont : r->TermWin.xftpfont;
2834 }
2835 #ifdef MULTICHAR_SET
2836 else if( xftdraw_string == XftDrawStringUtf8 )
2837 font = r->TermWin.xftmfont;
2838 #endif
2839 else font = r->TermWin.xftfont;
2840
2841 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "Draw: 0x%8x %p: '%.40s'\n", rend, font, str ));
2842
2843 #ifdef MULTICHAR_SET
2844 if( xftdraw_string == XftDrawStringUtf8 )
2845 len = STRLEN( str);
2846 #endif
2847
2848 # ifdef TEXT_SHADOW
2849 if (r->h->rs[Rs_textShadow] && SHADOW_NONE != r->TermWin.shadow_mode)
2850 {
2851 /*
2852 * Get the bounding box of the rectangle we would draw, and clip to it.
2853 */
2854 void (*xftTextExtents)() = NULL; /* Suppress compile warning */
2855 XGlyphInfo extents;
2856
2857 int sx, sy; /* Shadow offsets */
2858
2859 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "handling text shadow for %s (%d)\n", str, len));
2860
2861 if( xftdraw_string == XftDrawString8 )
2862 xftTextExtents = XftTextExtents8;
2863 else if( xftdraw_string == XftDrawString16)
2864 xftTextExtents = XftTextExtents16;
2865 else if( xftdraw_string == XftDrawString32)
2866 xftTextExtents = XftTextExtents32;
2867 else if( xftdraw_string == XftDrawStringUtf8)
2868 xftTextExtents = XftTextExtentsUtf8;
2869 else
2870 assert(0); /* Shouldn't happen */
2871
2872 xftTextExtents( r->Xdisplay, font, str, len, &extents);
2873
2874 /*
2875 * We should ignore extents.height. The height of the drawn text might
2876 * be much smaller than the height of the font (which is really what
2877 * we've reserved space for.
2878 */
2879 rxvt_set_clipping( r, win, gc, refreshRegion,
2880 x, y - font->ascent, extents.width - extents.x, font->height,
2881 &sx, &sy);
2882
2883 XFTDRAW_STRING (win, &(r->TermWin.xftshadow),
2884 font, x+sx, y+sy, str, len);
2885 /*
2886 * We need to free clipping area, otherwise text on screen may be
2887 * clipped unexpectedly. Is there a better way to unset it, say,
2888 * XUnsetClipRectangles?
2889 */
2890 rxvt_free_clipping (r, win, gc, refreshRegion);
2891 }
2892 # endif /* TEXT_SHADOW */
2893
2894 XFTDRAW_STRING (win, fore, font, x, y, str, len);
2895 }
2896 #undef XFTDRAW_STRING
2897 #endif /* XFT_SUPPORT */
2898
2899
2900 /*
2901 * len : number of characters in the string
2902 */
2903 /* EXTPROTO */
2904 void
rxvt_draw_string_x11(rxvt_t * r,Window win,GC gc,Region refreshRegion,int x,int y,char * str,int len,int (* draw_string)())2905 rxvt_draw_string_x11 (rxvt_t* r, Window win, GC gc, Region refreshRegion,
2906 int x, int y, char* str, int len, int (*draw_string)())
2907 {
2908 # ifdef TEXT_SHADOW
2909 while (r->h->rs[Rs_textShadow] && SHADOW_NONE != r->TermWin.shadow_mode)
2910 {
2911 int sx, sy;
2912 XGCValues gcvalue;
2913
2914 int (*xtextextents)();
2915 int unused_dir, ascent, descent;
2916 XCharStruct charstruct;
2917 GContext gid = XGContextFromGC( gc );
2918 XFontStruct *font = XQueryFont( r->Xdisplay, gid);
2919
2920 if( font == NULL ) break;
2921 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "handling text shadow for %s (%d)\n", str, len));
2922
2923 /*
2924 * Save the old GC values foreground.
2925 */
2926 XGetGCValues (r->Xdisplay, gc,
2927 GCForeground | GCBackground | GCFillStyle, &gcvalue);
2928
2929 /*
2930 * Get the bounding box of the rectangle we would draw, and clip to it.
2931 */
2932 if( draw_string == XDrawImageString || draw_string == XDrawString)
2933 xtextextents = XTextExtents;
2934 else if ( draw_string == XDrawImageString16 ||
2935 draw_string == XDrawString16)
2936 xtextextents = XTextExtents16;
2937 else
2938 assert(0); /* Shouldn't happen */
2939
2940 xtextextents( font, str, len,
2941 &unused_dir, &ascent, &descent, &charstruct);
2942
2943 /*
2944 * If we're using XDrawImageString, then when we draw the actual text,
2945 * the shadow will be erased. Clear the rectangle ourselves, and change
2946 * to XDrawString.
2947 */
2948 if( draw_string == XDrawImageString ||
2949 draw_string == XDrawImageString16)
2950 {
2951 XSetForeground( r->Xdisplay, gc, gcvalue.background);
2952 XSetFillStyle( r->Xdisplay, gc, FillSolid);
2953 XFillRectangle( r->Xdisplay, win, gc,
2954 x, y - font->ascent,
2955 charstruct.width, font->ascent + font->descent);
2956
2957 if( draw_string == XDrawImageString )
2958 draw_string = XDrawString;
2959 else draw_string = XDrawString16;
2960 }
2961
2962
2963 /*
2964 * Restrict output to the above bounding box.
2965 */
2966 rxvt_set_clipping( r, NULL, gc, refreshRegion,
2967 x, y - font->ascent,
2968 charstruct.width, font->ascent + font->descent,
2969 &sx, &sy);
2970
2971 /*
2972 * Draw the shadow at the appropriate offset.
2973 */
2974 XSetForeground (r->Xdisplay, gc, r->TermWin.shadow);
2975 draw_string (r->Xdisplay, win, gc, x+sx, y+sy, str, len);
2976
2977 /*
2978 * Restore old GC values.
2979 */
2980 XChangeGC( r->Xdisplay, gc,
2981 GCForeground | GCBackground | GCFillStyle,
2982 &gcvalue);
2983
2984 /*
2985 * Unclip drawing for remaining drawing.
2986 */
2987 rxvt_free_clipping (r, NULL, gc, refreshRegion);
2988
2989 XFreeFontInfo( NULL, font, 1);
2990 break;
2991 }
2992 # endif /* TEXT_SHADOW */
2993
2994 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "output entire string: %s\n", str));
2995 draw_string (r->Xdisplay, win, gc, x, y, str, len);
2996 }
2997
2998
2999 /*
3000 ** Draw the string:
3001 ** x, y: top left corner of the string
3002 ** str : actual string to draw
3003 ** len : actual number of characters in the string. It is NOT
3004 ** the byte length!
3005 ** drawfunc: function to draw string
3006 ** fore, back: color index to r->pixColors array. It is only
3007 ** used by the XFT drawing, not X11 drawing
3008 ** rend: rendition value (text attributes). Only used for the RS_acsFont
3009 ** attribute with Xft for correct drawing of ACS graphics characters.
3010 */
3011 /* INTPROTO */
3012 void
rxvt_scr_draw_string(rxvt_t * r,int page,int x,int y,char * str,int len,int drawfunc,uint16_t fore,uint16_t back,rend_t rend,Region refreshRegion)3013 rxvt_scr_draw_string (rxvt_t* r, int page,
3014 int x, int y, char* str, int len, int drawfunc,
3015 uint16_t fore, uint16_t back,
3016 __attribute__((unused)) rend_t rend, Region refreshRegion)
3017 {
3018 #ifdef XFT_SUPPORT
3019 int fillback = 0;
3020 int adjust;
3021 void (*xftdraw_string) () = NULL;
3022
3023 switch (drawfunc)
3024 {
3025 case XFT_DRAW_IMAGE_STRING_8:
3026 fillback = 1;
3027 case XFT_DRAW_STRING_8:
3028 xftdraw_string = XftDrawString8; break;
3029
3030 case XFT_DRAW_IMAGE_STRING_16:
3031 fillback = 1;
3032 case XFT_DRAW_STRING_16:
3033 xftdraw_string = XftDrawString16; break;
3034 }
3035
3036 /*
3037 * adjust is a variable that records whether each character of the string is
3038 * 8 bits or 16 bits
3039 */
3040 adjust = (XftDrawString8 == xftdraw_string) ? 0 : 1;
3041
3042 if (ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt && xftdraw_string)
3043 {
3044 register int loop; /* loop iteration number */
3045 register int loopitem; /* each iteration increasing # */
3046 register int i;
3047 /*
3048 ** xft_draw_string_xft should call these two parameters
3049 */
3050 register char* pstr; /* string to print */
3051 register int plen; /* string length */
3052 char* newstr;
3053 #ifdef MULTICHAR_SET
3054 # ifdef HAVE_ICONV_H
3055 char pbuf[1024]; /* buffer to save UTF-8 string */
3056 # endif
3057 #endif
3058
3059
3060 /*
3061 * Xft does not support XDrawImageString, so we need to clear the
3062 * background of text by ourselves.
3063 */
3064 if (fillback)
3065 XftDrawRect( PVTS(r, page)->xftvt, &(r->xftColors[back]),
3066 x, y, Width2Pixel(len * (1 + adjust)), Height2Pixel(1));
3067
3068 /* We use TermWin.xftfont->ascent here */
3069 y += r->TermWin.xftfont->ascent;
3070
3071 /*
3072 * Xft does not support XftDrawString16, so we need to convert the
3073 * string to UTF-8. Here we reencode the string before conversion
3074 */
3075 # ifdef MULTICHAR_SET
3076 # ifdef HAVE_ICONV_H
3077 if (adjust && (iconv_t) -1 != r->TermWin.xfticonv)
3078 {
3079 register int j, newlen = (len << 1);
3080 switch (r->encoding_method)
3081 {
3082 case ENC_EUCJ:
3083 case ENC_GB:
3084 for (j = 0; j < newlen; j ++)
3085 str[j] |= 0x80;
3086 break;
3087 case ENC_GBK: /* need to do nothing */
3088 case ENC_BIG5: /* need to do nothing */
3089 default:
3090 break;
3091 }
3092 /* we will use utf8 routine to draw string */
3093 xftdraw_string = XftDrawStringUtf8;
3094 }
3095 # endif
3096 # endif /* MULTICHAR_SET */
3097
3098
3099 /*
3100 ** If the font is monospace, we print the entire string once,
3101 ** otherwise, print the characters one by one
3102 */
3103 if (r->TermWin.xftmono)
3104 {
3105 /* print string once for mono font */
3106 loop = 1;
3107 loopitem = len;
3108 /*
3109 ** If XftDrawString8 == xftdraw_string
3110 ** string length == character number
3111 ** If XftDrawString16 == xftdraw_string
3112 ** string length == 2 * character number, but we do
3113 ** not need to multiply loopitem by 2 because the
3114 ** XftDrawString16 takes character numbers.
3115 **
3116 ** If XftDrawStringUtf8 == xftdraw_string
3117 ** string length == 2 * character number, but we need
3118 ** to multiply loopitem by 2 because iconv need string
3119 ** length as parameter, not character number.
3120 */
3121 if (XftDrawStringUtf8 == xftdraw_string)
3122 loopitem <<= 1;
3123 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "output entire mono string\n"));
3124 }
3125 /*
3126 ** Non monospace font, but still we can improve the performance
3127 ** by print it once under certain conditions
3128 */
3129 # ifdef MULTICHAR_SET
3130 else
3131 if (
3132 NOTSET_OPTION(r, Opt2_xftSlowOutput)
3133 && (XftDrawStringUtf8 == xftdraw_string)
3134 && (
3135 r->TermWin.xftmfont->max_advance_width ==
3136 (r->TermWin.fwidth << 1)
3137 )
3138 )
3139 {
3140 /* print string once for multichar string */
3141 loop = 1;
3142 /*
3143 ** If XftDrawStringUtf8 == xftdraw_string
3144 ** string length == 2 * character number, but we need
3145 ** to multiply loopitem by 2 because iconv need string
3146 ** length as parameter, not character number.
3147 */
3148 loopitem = (len << 1);
3149 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "output entire UTF-8 string\n"));
3150 }
3151 else
3152 if (
3153 NOTSET_OPTION(r, Opt2_xftSlowOutput)
3154 && (XftDrawString16 == xftdraw_string)
3155 && (
3156 r->TermWin.xftmfont->max_advance_width ==
3157 (r->TermWin.fwidth << 1)
3158 )
3159 )
3160 {
3161 /* print string once for 16-bits string */
3162 loop = 1;
3163 loopitem = len;
3164 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "output entire 16-bits string\n"));
3165 }
3166 # endif /* MULTICHAR_SET */
3167 else
3168 if (
3169 r->TermWin.xftfnmono && (XftDrawString8 == xftdraw_string)
3170 && (r->TermWin.xftfont->max_advance_width == r->TermWin.fwidth)
3171 )
3172 {
3173 /* print string once for 8-bits string */
3174 loop = 1;
3175 loopitem = len;
3176 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "output entire 8-bits string\n"));
3177 }
3178 else
3179 {
3180 /* print string one by one character */
3181 loop = len;
3182 loopitem = 1 + adjust;
3183 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "output characters one by one\n"));
3184 }
3185
3186
3187 newstr = str; /* string beginning in each iteration */
3188 for (i = 0; i < loop; i ++)
3189 {
3190 # ifdef MULTICHAR_SET
3191 # ifdef HAVE_ICONV_H
3192 if (XftDrawStringUtf8 == xftdraw_string)
3193 {
3194 /* We should convert the string to UTF-8 */
3195 char* buf = pbuf; /* always init it */
3196 int buflen = sizeof(pbuf)-1;/* always init it */
3197 int newlen = loopitem; /* always init it */
3198 char* oldstr = newstr;
3199 iconv (r->TermWin.xfticonv, (char**)(&newstr),
3200 (size_t*) &newlen, &buf, (size_t*) &buflen);
3201 *buf = (char) 0; /* set end of string */
3202 pstr = pbuf;
3203 /*
3204 * we should use the length of original string, not UTF-8 string
3205 * here!!!
3206 */
3207 plen = loopitem;
3208 /*
3209 * reset newstr to old position, we will increase it later
3210 */
3211 newstr = oldstr;
3212 }
3213 else
3214 # endif
3215 # endif /* MULTICHAR_SET */
3216 {
3217 /* We do not need to convert the string to UTF-8 */
3218 pstr = newstr;
3219 plen = loopitem;
3220 }
3221
3222 rxvt_draw_string_xft(r, PVTS( r, page)->vt, r->TermWin.gc,
3223 refreshRegion, rend, NO_PFONT,
3224 PVTS(r, page)->xftvt, &(r->xftColors[fore]),
3225 x, y, pstr, plen, xftdraw_string);
3226
3227 x += Width2Pixel (loopitem);
3228 newstr += loopitem; /* next string to display */
3229 }
3230 }
3231 else
3232 #endif /* XFT_SUPPORT */
3233 {
3234 int (*draw_string) ();
3235 switch (drawfunc)
3236 {
3237 case X11_DRAW_STRING_8:
3238 draw_string = XDrawString; break;
3239 case X11_DRAW_STRING_16:
3240 draw_string = XDrawString16; break;
3241 case X11_DRAW_IMAGE_STRING_8:
3242 draw_string = XDrawImageString; break;
3243 case X11_DRAW_IMAGE_STRING_16:
3244 draw_string = XDrawImageString16; break;
3245
3246 case XFT_DRAW_STRING_8: /* fall back to X11 */
3247 draw_string = XDrawString; break;
3248 case XFT_DRAW_STRING_16: /* fall back to X11 */
3249 case XFT_DRAW_STRING_32: /* fall back to X11 */
3250 case XFT_DRAW_STRING_UTF8: /* fall back to X11 */
3251 draw_string = XDrawString16; break;
3252
3253 case XFT_DRAW_IMAGE_STRING_8: /* fall back to X11 */
3254 draw_string = XDrawImageString; break;
3255 case XFT_DRAW_IMAGE_STRING_16: /* fall back to X11 */
3256 case XFT_DRAW_IMAGE_STRING_32: /* fall back to X11 */
3257 case XFT_DRAW_IMAGE_STRING_UTF8: /* fall back to X11 */
3258 draw_string = XDrawImageString16; break;
3259
3260 default:
3261 draw_string = NULL; break;
3262 }
3263
3264 /* We use TermWin.font->ascent here */
3265 y += r->TermWin.font->ascent;
3266
3267 /* Now draw the string */
3268 if (draw_string)
3269 rxvt_draw_string_x11 (r, PVTS(r, page)->vt, r->TermWin.gc,
3270 refreshRegion, x, y, str, len, draw_string);
3271 }
3272 }
3273
3274
3275 /*
3276 * 2006-08-19 gi1242: Don't display blinking text with the bold attribute. This
3277 * causes problems all over the code: When we unset the bold attribute, thinking
3278 * "we've taken care of it", the blink attribute might cause us to do over
3279 * striking. Plus it causes trouble in the pixel dropping avoidance stuff.
3280 */
3281 #define MONO_BOLD(x) \
3282 (ISSET_OPTION(r, Opt2_veryBold) ? \
3283 ((x) & RS_Bold) : \
3284 (((x) & (RS_Bold | RS_fgMask)) == (RS_Bold | Color_fg)) \
3285 )
3286 #define MONO_BOLD_FG(x, fg) \
3287 (ISSET_OPTION(r, Opt2_veryBold) ? \
3288 ((x) & RS_Bold) : \
3289 (((x) & RS_Bold) && (fg) == Color_fg) \
3290 )
3291
3292
3293 #define FONT_WIDTH(X, Y) \
3294 (X)->per_char[(Y) - (X)->min_char_or_byte2].width
3295 #define FONT_RBEAR(X, Y) \
3296 (X)->per_char[(Y) - (X)->min_char_or_byte2].rbearing
3297 #define FONT_LBEAR(X, Y) \
3298 (X)->per_char[(Y) - (X)->min_char_or_byte2].lbearing
3299 #define IS_FONT_CHAR(X, Y) \
3300 ((Y) >= (X)->min_char_or_byte2 && (Y) <= (X)->max_char_or_byte2)
3301
3302 /*
3303 * This function needs to be optimized and sped up more
3304 *
3305 * 2006-02-11 gi1242: Added a CLIPPED_REFRESH option. If set, only clipped areas
3306 * are redrawn. This adds a TREMENDOUS speedup when dragging some window over
3307 * mrxvt's window. (Not to mention got rid of that annoying flicker).
3308 */
3309 /* EXTPROTO */
3310 void
rxvt_scr_refresh(rxvt_t * r,int page,unsigned char refresh_type)3311 rxvt_scr_refresh(rxvt_t* r, int page, unsigned char refresh_type)
3312 {
3313 unsigned char
3314 clearfirst, /* first character writes before cell */
3315 clearlast, /* last character writes beyond cell */
3316 must_clear, /* use drawfunc not image_drawfunc */
3317 already_cleared=0, /* Use XClearArea or no-op */
3318 #ifndef NO_BOLDFONT
3319 usingBoldFt, /* we've changed font to bold font */
3320 loadedBoldFt, /* If a bold font is loaded */
3321 #endif
3322 rvid, /* reverse video this position */
3323 wbyte, /* we're in multibyte */
3324 showcursor; /* show the cursor */
3325
3326
3327 signed char morecur = 0;/* */
3328 #ifdef TTY_256COLOR
3329 uint16_t fore, back; /* desired foreground/background */
3330 #else
3331 unsigned char
3332 fore, back; /* desired foreground/background */
3333 #endif
3334 int16_t col, row, /* column/row we're processing */
3335 ocrow, /* old cursor row */
3336 len, wlen; /* text length screen/buffer */
3337 int i, /* tmp */
3338 row_offset; /* basic offset in screen structure */
3339 #ifndef NO_CURSORCOLOR
3340 rend_t cc1 = 0; /* store colours at cursor position(s) */
3341 # ifdef MULTICHAR_SET
3342 rend_t cc2 = 0; /* store colours at cursor position(s) */
3343 /* 2007-07-30 gi1242: NULL assignment to suppress
3344 * compile warning. */
3345 # endif
3346 #endif
3347 XGCValues gcvalue; /* Graphics Context values */
3348 XFontStruct* wf; /* font structure */
3349 rend_t* drp; /* drawn_rend pointer */
3350 rend_t* srp; /* screen-rend-pointer */
3351 text_t* dtp; /* drawn-text pointer */
3352 text_t* stp; /* screen-text-pointer */
3353 char* buffer; /* local copy of r->h->buffer */
3354 /*
3355 int (*drawfunc) () = XDrawString;
3356 int (*image_drawfunc) () = XDrawImageString;
3357 */
3358 int drawfunc, image_drawfunc;
3359 struct rxvt_hidden *h = r->h;
3360
3361 if( !(refresh_type & CLIPPED_REFRESH) )
3362 PVTS( r, page)->scrolled_lines = 0;
3363
3364 if (refresh_type == NO_REFRESH || !PVTS(r, page)->mapped)
3365 {
3366 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "Skipping refresh (%d, %d)\n", refresh_type, PVTS(r, page)->mapped));
3367
3368 return;
3369 }
3370
3371 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_refresh %d ()\n", page));
3372
3373 /*
3374 ** A: set up vars
3375 */
3376 #ifdef XFT_SUPPORT
3377 if (ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt)
3378 {
3379 drawfunc = XFT_DRAW_STRING_8;
3380 image_drawfunc = XFT_DRAW_IMAGE_STRING_8;
3381 }
3382 else
3383 #endif
3384 {
3385 drawfunc = X11_DRAW_STRING_8;
3386 image_drawfunc = X11_DRAW_IMAGE_STRING_8;
3387 }
3388
3389 clearfirst = clearlast = must_clear = wbyte = 0;
3390 #ifndef NO_BOLDFONT
3391 usingBoldFt = 0;
3392
3393 /* Determine if we have a bold font loaded or not */
3394 if(
3395 # ifdef XFT_SUPPORT
3396 ISSET_OPTION( r, Opt_xft ) ?
3397 NOT_NULL( r->TermWin.xftbfont ) :
3398 NOT_NULL( r->TermWin.bfont )
3399 # else
3400 NOT_NULL( r->TermWin.bfont )
3401 # endif
3402 )
3403 loadedBoldFt = 1;
3404 else
3405 loadedBoldFt = 0;
3406 #endif /* NO_BOLDFONT */
3407
3408 if (h->currmaxcol < r->TermWin.ncol)
3409 {
3410 h->currmaxcol = r->TermWin.ncol;
3411 h->buffer = rxvt_realloc(h->buffer, sizeof(char) * (h->currmaxcol + 1));
3412 }
3413 buffer = h->buffer;
3414
3415 row_offset = SVLINES - VSTART;
3416 #ifdef XFT_SUPPORT
3417 if (!(ISSET_OPTION(r, Opt_xft) && r->TermWin.xftfont))
3418 #endif
3419 {
3420 /* always go back to the base font - it's much safer */
3421 XSetFont(r->Xdisplay, r->TermWin.gc, r->TermWin.font->fid);
3422 wf = r->TermWin.font;
3423 }
3424
3425 if ((refresh_type & REFRESH_BOUNDS))
3426 {
3427 clearfirst = clearlast = 1;
3428 h->refresh_type &= ~REFRESH_BOUNDS;
3429 }
3430 #ifdef BACKGROUND_IMAGE
3431 must_clear |= IS_PIXMAP(PVTS(r, page)->bg.pixmap);
3432 #endif
3433 #ifdef TRANSPARENT
3434 must_clear |= ( h->am_transparent || h->am_pixmap_trans );
3435 #endif
3436 /* is there an old outline cursor on screen? */
3437 ocrow = h->oldcursor.row;
3438
3439 /*
3440 * set base colours to avoid check in "single glyph writing" below
3441 */
3442 gcvalue.foreground = r->pixColors[Color_fg];
3443 gcvalue.background = r->pixColors[Color_bg];
3444
3445 /*
3446 * Set clippings on our XftDrawables and GC's to make sure we don't waste
3447 * time drawing pixels outside this clipping. (This probably happened
3448 * because of an expose event).
3449 */
3450 if( (refresh_type & CLIPPED_REFRESH) && IS_REGION(h->refreshRegion))
3451 {
3452 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "Doing clipped refresh (Region %p)\n", h->refreshRegion));
3453
3454 /*
3455 * We must wait till refresh is complete before destroying the
3456 * region because the clipping is reset when text shadow is used.
3457 */
3458 XSetRegion( r->Xdisplay, r->TermWin.gc, h->refreshRegion);
3459 #ifdef XFT_SUPPORT
3460 if( ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt )
3461 XftDrawSetClip( PVTS(r, page)->xftvt, h->refreshRegion);
3462 #endif
3463 /* Remember we don't need to call XClearArea on exposed regions */
3464 if( must_clear ) already_cleared = 1;
3465 }
3466
3467 /*
3468 ** B: reverse any characters which are selected
3469 */
3470 rxvt_scr_reverse_selection(r, page);
3471
3472
3473 /*
3474 ** C: set the cursor character(s)
3475 */
3476 {
3477 unsigned char setoldcursor;
3478 rend_t ccol1, /* Cursor colour */
3479 ccol2; /* Cursor colour2 */
3480
3481 showcursor = (PSCR(r, page).flags & Screen_VisibleCursor);
3482 #ifdef CURSOR_BLINK
3483 if (h->hidden_cursor)
3484 showcursor = 0;
3485 #endif
3486 if (showcursor && r->TermWin.focus)
3487 {
3488 int currow = CURROW + SVLINES;
3489 srp = &(PSCR(r, page).rend[currow][CURCOL]);
3490
3491 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "Setting solid cursor\n"));
3492
3493 *srp ^= RS_RVid;
3494
3495 #ifndef NO_CURSORCOLOR
3496 cc1 = *srp & (RS_fgMask | RS_bgMask);
3497 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor))
3498 ccol1 = Color_cursor;
3499 else
3500 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
3501 ccol1 = GET_FGCOLOR(
3502 PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
3503 /*
3504 ccol1 = GET_FGCOLOR(PVTS(r, page)->rstyle);
3505 */
3506 #else
3507 ccol1 = Color_fg;
3508 #endif
3509 if(
3510 XDEPTH > 2
3511 && ISSET_PIXCOLOR( h, Color_cursor )
3512 && ISSET_PIXCOLOR( h, Color_cursor2 )
3513 )
3514 ccol2 = Color_cursor2;
3515 else
3516 {
3517 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
3518 # ifdef SIMULATE_LINUX_CONSOLE_CURSOR_COLOR
3519 ccol2 = GET_FGCOLOR(PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
3520 # else
3521 ccol2 = GET_BGCOLOR(PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
3522 # endif /* SIMULATE_LINUX_CONSOLE_CURSOR_COLOR */
3523 /*
3524 ccol2 = GET_BGCOLOR(PVTS(r, page)->rstyle);
3525 */
3526 #else
3527 ccol2 = Color_bg;
3528 #endif
3529 }
3530
3531 *srp = SET_FGCOLOR(*srp, ccol1);
3532 *srp = SET_BGCOLOR(*srp, ccol2);
3533 #endif /* NO_CURSORCOLOR */
3534
3535 #ifdef MULTICHAR_SET
3536 if (IS_MULTI1(*srp))
3537 {
3538 if (CURCOL < r->TermWin.ncol - 2 && IS_MULTI2(*++srp))
3539 morecur = 1;
3540 }
3541 else if (IS_MULTI2(*srp))
3542 {
3543 if (CURCOL > 0 && IS_MULTI1(*--srp))
3544 morecur = -1;
3545 }
3546 if (morecur)
3547 {
3548 *srp ^= RS_RVid;
3549 # ifndef NO_CURSORCOLOR
3550 cc2 = *srp & (RS_fgMask | RS_bgMask);
3551 *srp = SET_FGCOLOR(*srp, ccol1);
3552 *srp = SET_BGCOLOR(*srp, ccol2);
3553 # endif
3554 }
3555 #endif
3556 }
3557
3558 /* make sure no outline cursor is left around */
3559 setoldcursor = 0;
3560 if (ocrow != -1)
3561 {
3562 if (CURROW + VSTART != ocrow || CURCOL != h->oldcursor.col)
3563 {
3564 if (
3565 ocrow < r->TermWin.nrow
3566 && h->oldcursor.col < r->TermWin.ncol
3567 )
3568 {
3569 PVTS(r, page)->drawn_rend[ocrow][h->oldcursor.col] ^=
3570 (RS_RVid | RS_Uline);
3571 #ifdef MULTICHAR_SET
3572 if (h->oldcursormulti)
3573 {
3574 col = h->oldcursor.col + h->oldcursormulti;
3575 if (col < r->TermWin.ncol)
3576 PVTS(r, page)->drawn_rend[ocrow][col] ^=
3577 (RS_RVid | RS_Uline);
3578 }
3579 #endif
3580 }
3581 if (r->TermWin.focus || !showcursor)
3582 h->oldcursor.row = -1;
3583 else
3584 setoldcursor = 1;
3585 }
3586 }
3587 else if (!r->TermWin.focus)
3588 setoldcursor = 1;
3589
3590 if (setoldcursor)
3591 {
3592 if (CURROW + VSTART >= r->TermWin.nrow)
3593 h->oldcursor.row = -1;
3594 else
3595 {
3596 h->oldcursor.row = CURROW + VSTART;
3597 h->oldcursor.col = CURCOL;
3598 #ifdef MULTICHAR_SET
3599 h->oldcursormulti = morecur;
3600 #endif
3601 }
3602 }
3603 }
3604 /* End of C */
3605
3606
3607 #ifndef NO_SLOW_LINK_SUPPORT
3608 /*
3609 ** D: CopyArea pass - very useful for slower links
3610 ** This has been deliberately kept simple.
3611 */
3612 i = PVTS(r, page)->num_scr;
3613 if (refresh_type == FAST_REFRESH &&
3614 h->num_scr_allow &&
3615 i &&
3616 abs(i) < r->TermWin.nrow &&
3617 !must_clear)
3618 {
3619 int16_t nits;
3620 int j;
3621 rend_t *drp2;
3622 text_t *dtp2;
3623
3624 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "Trying slowlink copyarea pass\n"));
3625
3626 j = r->TermWin.nrow;
3627 wlen = len = -1;
3628 row = i > 0 ? 0 : j - 1;
3629 for (; j-- >= 0; row += (i > 0 ? 1 : -1))
3630 {
3631 if (row + i >= 0 && row + i < r->TermWin.nrow && row + i != ocrow)
3632 {
3633 stp = PSCR(r, page).text[row + row_offset];
3634 srp = PSCR(r, page).rend[row + row_offset];
3635 dtp = PVTS(r, page)->drawn_text[row];
3636 dtp2 = PVTS(r, page)->drawn_text[row + i];
3637 drp = PVTS(r, page)->drawn_rend[row];
3638 drp2 = PVTS(r, page)->drawn_rend[row + i];
3639 for (nits = 0, col = r->TermWin.ncol; col--; )
3640 if (stp[col] != dtp2[col] ||
3641 srp[col] != drp2[col])
3642 nits--;
3643 else if (stp[col] != dtp[col] ||
3644 srp[col] != drp[col])
3645 nits++;
3646 if (nits > 8) /* XXX: arbitrary choice */
3647 {
3648 for (col = r->TermWin.ncol; col--; )
3649 {
3650 *dtp++ = *dtp2++;
3651 *drp++ = *drp2++;
3652 }
3653 if (len == -1)
3654 len = row;
3655 wlen = row;
3656 continue;
3657 }
3658 }
3659
3660 if (len != -1)
3661 {
3662 /* also comes here at end if needed because of >= above */
3663 if (wlen < len)
3664 SWAP_IT(wlen, len, int);
3665
3666 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_scr_refresh %d (): " "XCopyArea: %d -> %d (height: %d)\n", page, len + i, len, wlen - len + 1));
3667 XCopyArea(r->Xdisplay, PVTS(r, page)->vt,
3668 PVTS(r, page)->vt, r->TermWin.gc,
3669 0, Row2Pixel(len + i),
3670 TWIN_WIDTH(r),
3671 (unsigned int)Height2Pixel(wlen-len+1),
3672 0, Row2Pixel(len));
3673 len = -1;
3674 }
3675 }
3676 } /* End of D */
3677 #endif /* !NO_SLOW_LINK_SUPPORT */
3678
3679
3680 /*
3681 ** E: main pass across every character
3682 */
3683 for (row = 0; row < r->TermWin.nrow; row++)
3684 {
3685 unsigned char clear_next = 0;
3686 int j,
3687 /* x offset for start of drawing (font) */
3688 xpixel,
3689 /* y offset for top of drawing */
3690 ypixelc;
3691 unsigned long gcmask; /* Graphics Context mask */
3692
3693
3694 stp = PSCR(r, page).text[row + row_offset];
3695 srp = PSCR(r, page).rend[row + row_offset];
3696 dtp = PVTS(r, page)->drawn_text[row];
3697 drp = PVTS(r, page)->drawn_rend[row];
3698
3699
3700 #ifndef NO_PIXEL_DROPPING_AVOIDANCE
3701 /*
3702 * E1: Pixel dropping avoidance. Do this before the main refresh on the
3703 * line. Require a refresh where pixels may have been dropped into our
3704 * area by a neighbour character which has now changed
3705 *
3706 * TODO: This could be integrated into E2 but might be too messy
3707 */
3708 for (col = 0; col < r->TermWin.ncol; col++)
3709 {
3710 unsigned char is_font_char, is_same_char;
3711 text_t t;
3712
3713 t = dtp[col];
3714 is_same_char = (t == stp[col] && drp[col] == srp[col]);
3715 if (!clear_next &&
3716 (is_same_char || t == 0 || t == ' '))
3717 /* screen cleared elsewhere */
3718 continue;
3719
3720 if (clear_next)
3721 {
3722 /* previous char caused change here */
3723 clear_next = 0;
3724 dtp[col] = 0;
3725
3726 /* don't cascade into next char */
3727 if (is_same_char)
3728 continue;
3729 }
3730
3731 #ifdef XFT_SUPPORT
3732 if( ISSET_OPTION(r, Opt_xft) )
3733 {
3734 /*
3735 * Only text drawn by over striking needs to be watched for
3736 * "dropped pixels".
3737 *
3738 * XXX This does not take into account Color_BD
3739 */
3740 if( !loadedBoldFt && ( drp[col] & RS_Bold ) )
3741 {
3742 if( col == r->TermWin.ncol - 1 ) clearlast = 1;
3743 else clear_next = 1;
3744 }
3745 # ifdef TEXT_SHADOW
3746 /*
3747 * Xft with shadow drops pixels into the next / prev char.
3748 */
3749 else if (
3750 h->rs[Rs_textShadow]
3751 && r->TermWin.shadow_mode != SHADOW_NONE
3752 )
3753 {
3754 switch( r->TermWin.shadow_mode )
3755 {
3756 case SHADOW_TOPRIGHT:
3757 case SHADOW_RIGHT:
3758 case SHADOW_BOTRIGHT:
3759 /* Clear next char */
3760 if( col == r->TermWin.ncol - 1) clearlast = 1;
3761 else clear_next = 1;
3762 break;
3763
3764 case SHADOW_TOPLEFT:
3765 case SHADOW_LEFT:
3766 case SHADOW_BOTLEFT:
3767 /* Clear prev char */
3768 if( col == 0 ) clearfirst = 1;
3769 else dtp[col-1] = 0;
3770 break;
3771
3772 default:
3773 /* Nothing to be done here */
3774 break;
3775 }
3776 }
3777 # endif /* TEXT_SHADOW */
3778 }
3779 else
3780 #endif
3781 {
3782 j = MONO_BOLD(drp[col]) ? 1 : 0;
3783 # ifndef NO_BOLDFONT
3784 wf = (j && r->TermWin.bfont) ?
3785 r->TermWin.bfont : r->TermWin.font;
3786 # endif
3787
3788 /*
3789 ** TODO: consider if anything special needs to happen
3790 ** with:
3791 ** #if defined(MULTICHAR_SET) &&
3792 ** !defined(NO_BOLDOVERSTRIKE_MULTI)
3793 */
3794 is_font_char = (wf->per_char && IS_FONT_CHAR(wf, t)) ? 1:0;
3795 if (!is_font_char || FONT_LBEAR(wf, t) < 0)
3796 {
3797 if (col == 0)
3798 clearfirst = 1;
3799 else
3800 dtp[col - 1] = 0;
3801 }
3802 if (!is_font_char ||
3803 (FONT_WIDTH(wf, t) < (FONT_RBEAR(wf, t) + j)))
3804 {
3805 if (col == r->TermWin.ncol - 1)
3806 clearlast = 1;
3807 else
3808 clear_next = 1;
3809 }
3810 }
3811 }
3812 #endif /* NO_PIXEL_DROPPING_AVOIDANCE */
3813 /* End of E1 */
3814
3815
3816 /*
3817 ** E2: OK, now the real pass
3818 */
3819 ypixelc = (int)Row2Pixel(row);
3820
3821 for (col = 0; col < r->TermWin.ncol; col++)
3822 {
3823 /* current font size != base font size */
3824 unsigned char fontdiff,
3825 /* proportional font used */
3826 fprop;
3827 /* rendition value */
3828 rend_t rend;
3829
3830 /* screen rendition (target rendtion) */
3831 rend = srp[col];
3832
3833 /*
3834 * compare new text with old - if exactly the same then continue
3835 */
3836 if (
3837 /* Must match characters to skip. */
3838 stp[col] == dtp[col] &&
3839 /* Either rendition the same or */
3840 (
3841 rend == drp[col] ||
3842 /* space w/ no background change */
3843 (
3844 stp[col] == ' ' &&
3845 GET_BGATTR(rend) == GET_BGATTR(drp[col])
3846 )
3847 )
3848 ) /* if */
3849 {
3850 if (!IS_MULTI1(rend))
3851 continue;
3852 #ifdef MULTICHAR_SET
3853 else
3854 {
3855 /* first byte is Kanji so compare second bytes */
3856 if (stp[col + 1] == dtp[col + 1])
3857 {
3858 /* assume no corrupt characters on the screen */
3859 col++;
3860 continue;
3861 }
3862 }
3863 #endif
3864 }
3865 /* redraw one or more characters */
3866
3867 fontdiff = 0;
3868 len = 0;
3869 buffer[len++] = dtp[col] = stp[col];
3870 drp[col] = rend;
3871 xpixel = Col2Pixel(col);
3872
3873 /*
3874 * Find out the longest string we can write out at once
3875 */
3876 #ifndef NO_BOLDFONT
3877 if (MONO_BOLD(rend) && r->TermWin.bfont != NULL)
3878 fprop = (r->TermWin.propfont & PROPFONT_BOLD);
3879 else
3880 #endif
3881 fprop = (r->TermWin.propfont & PROPFONT_NORMAL);
3882
3883 #ifdef MULTICHAR_SET
3884 if (
3885 IS_MULTI1(rend) && col < r->TermWin.ncol - 1
3886 && IS_MULTI2(srp[col + 1])
3887 )
3888 {
3889 if (!wbyte && r->TermWin.mfont)
3890 {
3891 wbyte = 1;
3892 XSetFont(r->Xdisplay, r->TermWin.gc,
3893 r->TermWin.mfont->fid);
3894 fontdiff = (r->TermWin.propfont & PROPFONT_MULTI);
3895 #ifdef XFT_SUPPORT
3896 if ( ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt )
3897 {
3898 drawfunc = XFT_DRAW_STRING_16;
3899 image_drawfunc = XFT_DRAW_IMAGE_STRING_16;
3900 }
3901 else
3902 #endif
3903 {
3904 drawfunc = X11_DRAW_STRING_16;
3905 image_drawfunc = X11_DRAW_IMAGE_STRING_16;
3906 }
3907 }
3908
3909 if (r->TermWin.mfont == NULL)
3910 {
3911 buffer[0] = buffer[1] = ' ';
3912 len = 2;
3913 col++;
3914 }
3915 else
3916 {
3917 /* double stepping - we're in multibyte font mode */
3918 for (; ++col < r->TermWin.ncol;)
3919 {
3920 /* XXX: could check sanity on 2nd byte */
3921 dtp[col] = stp[col];
3922 drp[col] = srp[col];
3923 buffer[len++] = stp[col];
3924 col++;
3925 /* proportional multibyte font mode */
3926 if (fprop)
3927 break;
3928 if ((col == r->TermWin.ncol) ||
3929 (srp[col] != rend))
3930 break;
3931 if ((stp[col] == dtp[col]) &&
3932 (srp[col] == drp[col]) &&
3933 (stp[col + 1] == dtp[col + 1]))
3934 break;
3935 if (len == h->currmaxcol)
3936 break;
3937 dtp[col] = stp[col];
3938 drp[col] = srp[col];
3939 buffer[len++] = stp[col];
3940 }
3941 col--;
3942 }
3943
3944 if (buffer[0] & 0x80)
3945 (h->multichar_decode)( (unsigned char*) buffer, len);
3946 wlen = len / 2;
3947 }
3948 else
3949 {
3950 if (rend & RS_multi1)
3951 {
3952 /* corrupt character - you're outta there */
3953 rend &= ~RS_multiMask;
3954 drp[col] = rend; /* TODO check: may also want */
3955 dtp[col] = ' '; /* to poke into stp/srp */
3956 buffer[0] = ' ';
3957 }
3958 if (wbyte)
3959 {
3960 wbyte = 0;
3961 #ifdef XFT_SUPPORT
3962 if (!(ISSET_OPTION(r, Opt_xft) && r->TermWin.xftfont))
3963 #endif
3964 XSetFont(r->Xdisplay, r->TermWin.gc,
3965 r->TermWin.font->fid);
3966 #ifdef XFT_SUPPORT
3967 if ( ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt )
3968 {
3969 drawfunc = XFT_DRAW_STRING_8;
3970 image_drawfunc = XFT_DRAW_IMAGE_STRING_8;
3971 }
3972 else
3973 #endif
3974 {
3975 drawfunc = X11_DRAW_STRING_8;
3976 image_drawfunc = X11_DRAW_IMAGE_STRING_8;
3977 }
3978 } /* if (wbyte) */
3979 #else
3980 { /* add } for correct % bouncing */
3981 #endif
3982 if (!fprop)
3983 {
3984 int echars;
3985
3986 /* single stepping - `normal' mode */
3987 for (i = 0, echars=0; ++col < r->TermWin.ncol - 1;)
3988 {
3989 /*
3990 * Instead of simply getting the longest string that
3991 * needs to be refreshed, we do some caching.
3992 *
3993 * i is the number of trailing chars that we read (in an
3994 * attempt to cache) that DO NOT need to be refreshed.
3995 * These had better be dumped.
3996 *
3997 * echars are the number of extra chars we drew that did
3998 * not need to be drawn. When echars get's too high,
3999 * then we should break out.
4000 */
4001 if (rend != srp[col])
4002 /* Different attributes. */
4003 break;
4004 buffer[len++] = stp[col];
4005
4006 if ( (stp[col] != dtp[col]) || (srp[col] != drp[col]) )
4007 {
4008 /* This position needed to be refreshed anyway */
4009 /* if (must_clear && (i++ > (len / 2))) break; */
4010
4011 dtp[col] = stp[col];
4012 drp[col] = srp[col];
4013 i = 0; /* Set trailing chars to 0 */
4014 }
4015 else /* if (must_clear ||
4016 (stp[col] != ' ' && ++i > 32)) */
4017 {
4018 /*
4019 * This position did not require a refresh. Let's do
4020 * some caching.
4021 */
4022 i++;
4023 /*
4024 * 25% (arbitarily choosen) of our drawn string can
4025 * be extra chars.
4026 */
4027 if( ++echars > (len >> 2) ) break;
4028 }
4029
4030 } /* for */
4031 col--; /* went one too far. move back */
4032 len -= i; /* dump any matching trailing chars */
4033
4034 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "Drawing %d(%d) chars: %.*s\n", len, echars-i, (len > 55) ? 55 : len, buffer));
4035 } /* if (!fprop) */
4036 wlen = len;
4037 }
4038 buffer[len] = '\0';
4039
4040 /*
4041 * Determine the attributes for the string
4042 */
4043 fore = GET_FGCOLOR(rend);
4044 back = GET_BGCOLOR(rend);
4045 rend = GET_ATTR(rend);
4046
4047 switch (rend & RS_fontMask)
4048 {
4049 case RS_acsFont:
4050 for (i = 0; i < len; i++)
4051 /*
4052 * Xterm leaves 0x5f (_) unchanged in graphics mode.
4053 */
4054 if (buffer[i] > 0x5f && buffer[i] < 0x7f)
4055 buffer[i] -= 0x5f;
4056 break;
4057 case RS_ukFont:
4058 for (i = 0; i < len; i++)
4059 if (buffer[i] == '#')
4060 buffer[i] = 0x1e; /* pound sign */
4061 break;
4062 }
4063
4064 #ifndef NO_BOLD_UNDERLINE_REVERSE
4065 /*
4066 * Bold / underline fonts. We use Color_BD / Color_UL only if we're
4067 * displaying the font with normal colors.
4068 */
4069 if( fore == Color_fg && back == Color_bg )
4070 {
4071 /*
4072 * TODO: Should probably add a Color_BDUL here.
4073 */
4074 if ( rend & RS_Bold )
4075 {
4076 if (
4077 XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_BD)
4078 && r->pixColors[fore] != r->pixColors[Color_BD]
4079 && r->pixColors[back] != r->pixColors[Color_BD]
4080 )
4081 {
4082
4083 fore = Color_BD;
4084 /*
4085 * 2006-03-27 gi1242: Ignore veryBold when Color_BD is
4086 * set. veryBold will only be used when displaying
4087 * colored / blinking text.
4088 */
4089 #if 0
4090 if (NOTSET_OPTION(r, Opt2_veryBold))
4091 #endif
4092 rend &= ~RS_Bold; /* we've taken care of it */
4093 }
4094 }
4095 else if ( rend & RS_Uline )
4096 {
4097 if (
4098 XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_UL)
4099 && r->pixColors[fore] != r->pixColors[Color_UL]
4100 && r->pixColors[back] != r->pixColors[Color_UL]
4101 )
4102 {
4103 fore = Color_UL;
4104 rend &= ~RS_Uline; /* we've taken care of it */
4105 }
4106 }
4107 }
4108 #endif
4109 rvid = (rend & RS_RVid) ? 1 : 0;
4110 #ifdef OPTION_HC
4111 /*
4112 * Use Color_HC for anything blinking. TODO: Add a seperate
4113 * attribute for the XSelection, so that the user can distinguish
4114 * blinking text from the selection. (XTerm does this)
4115 */
4116 if ( (rend & RS_Blink))
4117 {
4118 if (
4119 XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_HC)
4120 && r->pixColors[fore] != r->pixColors[Color_HC]
4121 && r->pixColors[back] != r->pixColors[Color_HC]
4122 # ifndef NO_CURSORCOLOR
4123 /* Don't do this for the cursor */
4124 && (
4125 !ISSET_PIXCOLOR(h, Color_cursor)
4126 || !r->TermWin.focus || !showcursor
4127 || CURROW != row || CURCOL != col
4128 )
4129 # endif
4130 )
4131 {
4132 if( rvid) rvid = 0;
4133 back = Color_HC;
4134 }
4135 else
4136 rvid = 1; /* fall back */
4137 }
4138 #endif
4139
4140 /*
4141 * Reverse Video. If defined, Color_RV for background and leave
4142 * foreground untouched. Done last so that RV-BD text will have
4143 * Color_BD background if set (like in XTerm).
4144 */
4145 if( rvid )
4146 {
4147 #ifndef NO_BOLD_UNDERLINE_REVERSE
4148 if (
4149 XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_RV)
4150 && r->pixColors[fore] != r->pixColors[Color_RV]
4151 && r->pixColors[back] != r->pixColors[Color_RV]
4152 # ifndef NO_CURSORCOLOR
4153 /* Don't do this for the cursor */
4154 && (
4155 !ISSET_PIXCOLOR(h, Color_cursor)
4156 || !r->TermWin.focus || !showcursor
4157 || CURROW != row || CURCOL != col
4158 )
4159 # endif
4160 )
4161 back = Color_RV;
4162 else
4163 #endif
4164 {
4165 #ifdef TTY_256COLOR
4166 SWAP_IT(fore, back, uint16_t);
4167 #else
4168 SWAP_IT(fore, back, unsigned char);
4169 #endif
4170 }
4171 }
4172
4173 #ifndef NO_BRIGHTCOLOR
4174 /* Use bright colors for bold primary colors */
4175 if( (rend & RS_Bold) && NOTSET_OPTION( r, Opt2_boldColors ) )
4176 {
4177 if( fore >= minCOLOR && fore < minBrightCOLOR )
4178 {
4179 fore += minBrightCOLOR - minCOLOR;
4180 if( NOTSET_OPTION( r, Opt_veryBright ) )
4181 rend &= ~RS_Bold;
4182 }
4183 #if defined(TTY_256COLOR) && defined(BOLD_BRIGHTENS_256_COLORS)
4184 /* If fore is in the 6x6x6 color cube, try and brighten it */
4185 else if(
4186 fore >= min256COLOR &&
4187 fore <= min256COLOR + 4*36 + 4*6 + 4 &&
4188 (fore - min256COLOR) % 6 < 5 &&
4189 ((fore - min256COLOR)/6) % 6 < 5
4190 )
4191 {
4192 fore += 36 + 6 + 1;
4193
4194 if( NOTSET_OPTION( r, Opt_veryBright ) )
4195 rend &= ~RS_Bold;
4196 }
4197
4198 /* Brighten up colors in the grey-scale ramp. */
4199 else if(
4200 fore >= min256COLOR + 6*6*6 &&
4201 fore <= max256COLOR - 3
4202 )
4203 {
4204 if( fore == max256COLOR -3 )
4205 fore = min256COLOR + 6*6*6 - 1;
4206 else
4207 fore += 4;
4208
4209 if( NOTSET_OPTION( r, Opt_veryBright ) )
4210 rend &= ~RS_Bold;
4211 }
4212 #endif /*TTY_256COLOR && BOLD_BRIGHTENS_256_COLORS*/
4213 }
4214 #endif /*NO_BRIGHTCOLOR*/
4215
4216
4217 /*
4218 * fore and back should now have the correct colors.
4219 */
4220 gcmask = 0;
4221 if (back != Color_bg)
4222 {
4223 gcvalue.background = r->pixColors[back];
4224 gcmask = GCBackground;
4225 }
4226 if (fore != Color_fg)
4227 {
4228 gcvalue.foreground = r->pixColors[fore];
4229 gcmask |= GCForeground;
4230 }
4231 #ifndef NO_BOLD_UNDERLINE_REVERSE
4232 else if (rend & RS_Bold && ISSET_PIXCOLOR( h, Color_BD) )
4233 {
4234 # ifdef XFT_SUPPORT
4235 /*
4236 * XFT won't use the colors from the GC, so we need to set
4237 * fore.
4238 */
4239 if( ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt )
4240 fore = Color_BD;
4241 else
4242 # endif
4243 {
4244 gcvalue.foreground = r->pixColors[Color_BD];
4245 gcmask |= GCForeground;
4246 }
4247
4248 /*
4249 * If veryBold is not set, then don't render colored text in
4250 * bold.
4251 */
4252 if (NOTSET_OPTION(r, Opt2_veryBold))
4253 rend &= ~RS_Bold;
4254 }
4255 else if (rend & RS_Uline && ISSET_PIXCOLOR( h, Color_UL) )
4256 {
4257 # ifdef XFT_SUPPORT
4258 if( ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt )
4259 fore = Color_UL;
4260 else
4261 # endif
4262 {
4263 gcvalue.foreground = r->pixColors[Color_UL];
4264 gcmask |= GCForeground;
4265 }
4266 rend &= ~RS_Uline; /* we've taken care of it */
4267 }
4268 #endif
4269
4270
4271 if (gcmask)
4272 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
4273 #ifndef NO_BOLDFONT
4274 /*
4275 * Switch to the bold font if we are rendering bold text.
4276 *
4277 * NOTE: We only deal with bold fonts for non-multichar text.
4278 * Multichar bold text will have to be done by over striking (or
4279 * some other shmuck must code it) -- gi1242 2006-08-19.
4280 */
4281 if ( MONO_BOLD_FG(rend, fore) && !wbyte )
4282 {
4283 if( usingBoldFt )
4284 rend &= ~RS_Bold; /* We've taken care of it */
4285
4286 else if( loadedBoldFt )
4287 {
4288 usingBoldFt = 1;
4289
4290 # ifdef XFT_SUPPORT
4291 if( ISSET_OPTION(r, Opt_xft) )
4292 {
4293 SWAP_IT( r->TermWin.xftfont, r->TermWin.xftbfont,
4294 XftFont*);
4295 }
4296 else
4297 # endif
4298 {
4299 XSetFont(r->Xdisplay, r->TermWin.gc,
4300 r->TermWin.bfont->fid);
4301 }
4302
4303 fontdiff = (r->TermWin.propfont & PROPFONT_BOLD);
4304 rend &= ~RS_Bold; /* we've taken care of it */
4305 }
4306 }
4307
4308 /*
4309 * If we are using the bold font, but don't want to render bold
4310 * text, then we should restore the original font.
4311 */
4312 else if( usingBoldFt && !MONO_BOLD_FG( rend, fore ) )
4313 {
4314 usingBoldFt = 0;
4315
4316 /*
4317 * If we're not showing a multi byte char, then we reset
4318 * fontdiff to 0. If we're showing a multi byte char, then font
4319 * diff will have been set elsewhere, and we should not reset
4320 * it.
4321 */
4322 if( !wbyte )
4323 fontdiff = 0;
4324
4325 # ifdef XFT_SUPPORT
4326 if( ISSET_OPTION(r, Opt_xft) )
4327 {
4328 SWAP_IT( r->TermWin.xftfont, r->TermWin.xftbfont, XftFont*);
4329 }
4330 else
4331 # endif
4332 {
4333 XSetFont(r->Xdisplay, r->TermWin.gc, r->TermWin.font->fid);
4334 }
4335 }
4336 #endif
4337
4338 /*
4339 * Actually do the drawing of the string here
4340 */
4341 if (back == Color_bg && must_clear)
4342 {
4343 CLEAR_CHARS( r, page, already_cleared,
4344 xpixel, ypixelc, len);
4345 for (i = 0; i < len; i++)
4346 /* don't draw empty strings */
4347 if (buffer[i] != ' ')
4348 {
4349 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "CL Drawing '%.60s' (%d)\n", buffer, len));
4350
4351 rxvt_scr_draw_string (r, page, xpixel, ypixelc,
4352 buffer, wlen, drawfunc,
4353 fore, back, rend,
4354 ((refresh_type & CLIPPED_REFRESH) ?
4355 r->h->refreshRegion : None ));
4356 break;
4357 }
4358 }
4359 else if (fprop || fontdiff)
4360 {
4361 /* single glyph writing */
4362 unsigned long pixel;
4363
4364 pixel = gcvalue.foreground;
4365 gcvalue.foreground = gcvalue.background;
4366 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
4367 rxvt_fill_rectangle (r, page, xpixel, ypixelc,
4368 (unsigned int) Width2Pixel(len),
4369 (unsigned int) (Height2Pixel(1)
4370 /* - r->TermWin.lineSpace */));
4371 gcvalue.foreground = pixel;
4372 XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
4373
4374 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "PF Drawing '%.60s' (%d)\n", buffer, len));
4375 rxvt_scr_draw_string (r, page,
4376 xpixel, ypixelc, buffer, wlen, drawfunc,
4377 fore, back, rend,
4378 ((refresh_type & CLIPPED_REFRESH) ?
4379 r->h->refreshRegion : None ));
4380 }
4381 else
4382 {
4383 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "NC Drawing '%.60s' (%d)\n", buffer, len));
4384 rxvt_scr_draw_string (r, page,
4385 xpixel, ypixelc, buffer, wlen, image_drawfunc,
4386 fore, back, rend,
4387 ((refresh_type & CLIPPED_REFRESH) ?
4388 r->h->refreshRegion : None ));
4389 }
4390
4391 #ifndef NO_BOLDOVERSTRIKE
4392 # ifdef NO_BOLDOVERSTRIKE_MULTI
4393 if (!wbyte)
4394 # endif
4395 if (MONO_BOLD_FG(rend, fore))
4396 {
4397 /*
4398 * If we still need to draw a bold chars, then all else has
4399 * failed. Fall back to overstriking.
4400 */
4401 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "Overstriking %s\n", buffer ));
4402 rxvt_scr_draw_string (r, page,
4403 xpixel + 1, ypixelc, buffer, wlen, drawfunc,
4404 fore, back, rend,
4405 ((refresh_type & CLIPPED_REFRESH) ?
4406 r->h->refreshRegion : None ));
4407 }
4408 #endif
4409 if (rend & RS_Uline)
4410 {
4411 #ifdef XFT_SUPPORT
4412 if (ISSET_OPTION(r, Opt_xft) && PVTS(r, page)->xftvt)
4413 {
4414 if (r->TermWin.xftfont->descent > 1)
4415 XDrawLine(r->Xdisplay, drawBuffer,
4416 r->TermWin.gc,
4417 xpixel,
4418 ypixelc + r->TermWin.xftfont->ascent + 1,
4419 xpixel + Width2Pixel(len) - 1,
4420 ypixelc + r->TermWin.xftfont->ascent + 1);
4421 }
4422 else
4423 #endif
4424 if (r->TermWin.font->descent > 1)
4425 XDrawLine(r->Xdisplay, drawBuffer, r->TermWin.gc,
4426 xpixel,
4427 ypixelc + r->TermWin.font->ascent + 1,
4428 xpixel + Width2Pixel(len) - 1,
4429 ypixelc + r->TermWin.font->ascent + 1);
4430 }
4431
4432 if (gcmask) /* restore normal colours */
4433 {
4434 gcvalue.foreground = r->pixColors[Color_fg];
4435 gcvalue.background = r->pixColors[Color_bg];
4436 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
4437 }
4438 } /* for (col....) */
4439
4440 /* End of E2 */
4441 } /* for (row....) */
4442
4443 /*
4444 * If we've completed our refresh, and are using the bold font, we need to
4445 * reset it. Only needed when using XFT.
4446 */
4447 if( usingBoldFt )
4448 {
4449 usingBoldFt = 0;
4450
4451 #ifdef XFT_SUPPORT
4452 if( ISSET_OPTION(r, Opt_xft) )
4453 {
4454 SWAP_IT( r->TermWin.xftfont, r->TermWin.xftbfont, XftFont*);
4455 }
4456 else
4457 # endif
4458 {
4459 XSetFont(r->Xdisplay, r->TermWin.gc, r->TermWin.font->fid);
4460 }
4461 }
4462 /* End of E */
4463
4464
4465 /*
4466 ** G: cleanup cursor and display outline cursor in necessary
4467 */
4468 if (showcursor)
4469 {
4470 if (r->TermWin.focus)
4471 {
4472 int currow = CURROW + SVLINES;
4473 srp = &(PSCR(r, page).rend[currow][CURCOL]);
4474 *srp ^= RS_RVid;
4475
4476 #ifndef NO_CURSORCOLOR
4477 *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc1;
4478 #endif
4479 #ifdef MULTICHAR_SET
4480 if (morecur)
4481 {
4482 assert (0 == morecur || -1 == morecur || 1 == morecur);
4483 srp += morecur;
4484 *srp ^= RS_RVid;
4485 # ifndef NO_CURSORCOLOR
4486 *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc2;
4487 # endif
4488 }
4489 #endif
4490 }
4491 else if (h->oldcursor.row >= 0)
4492 {
4493 #ifndef NO_CURSORCOLOR
4494 unsigned long gcmask; /* Graphics Context mask */
4495
4496 gcmask = 0;
4497 if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor))
4498 {
4499 gcvalue.foreground = r->pixColors[Color_cursor];
4500 gcmask = GCForeground;
4501 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
4502 gcvalue.foreground = r->pixColors[Color_fg];
4503 }
4504 #endif
4505
4506 XDrawRectangle(r->Xdisplay, drawBuffer, r->TermWin.gc,
4507 Col2Pixel(h->oldcursor.col + morecur),
4508 Row2Pixel(h->oldcursor.row),
4509 (unsigned int)(Width2Pixel(1 + (morecur?1:0)) - 1),
4510 (unsigned int)(Height2Pixel(1)
4511 /* - r->TermWin.lineSpace*/ - 1));
4512
4513 #ifndef NO_CURSORCOLOR
4514 if (gcmask) /* restore normal colours */
4515 XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
4516 #endif
4517 }
4518 }
4519 /* End of G */
4520
4521
4522 /*
4523 ** H: cleanup selection
4524 */
4525 rxvt_scr_reverse_selection(r, page);
4526
4527
4528 /*
4529 ** I: other general cleanup
4530 */
4531 /*
4532 ** clear the whole screen height, note that width == 0 is treated
4533 ** specially by XClearArea
4534 */
4535 if (clearfirst && r->TermWin.int_bwidth)
4536 rxvt_clear_area (r, page, 0, 0,
4537 (unsigned int)r->TermWin.int_bwidth, VT_HEIGHT(r));
4538 /*
4539 ** clear the whole screen height, note that width == 0 is treated
4540 ** specially by XClearArea
4541 */
4542 if (clearlast && r->TermWin.int_bwidth)
4543 rxvt_clear_area (r, page,
4544 TWIN_WIDTH(r) + r->TermWin.int_bwidth, 0,
4545 (unsigned int)r->TermWin.int_bwidth, VT_HEIGHT(r));
4546
4547 if (refresh_type & SMOOTH_REFRESH)
4548 XSync(r->Xdisplay, False);
4549
4550 if( (refresh_type & CLIPPED_REFRESH) && IS_REGION(h->refreshRegion))
4551 {
4552 /*
4553 * A clipped refresh is complete. Don't restrict future refreshes.
4554 */
4555 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "Completed clipped refresh\n"));
4556
4557 /*
4558 * XSetRegion( r->Xdisplay, r->TermWin.gc, None) causes a segfault.
4559 * Probably because GC's dont' accept the None region as gracefully.
4560 */
4561 XSetClipMask( r->Xdisplay, r->TermWin.gc, None);
4562 #ifdef XFT_SUPPORT
4563 if( ISSET_OPTION(r, Opt_xft) && PVTS( r, page)->xftvt)
4564 XftDrawSetClip( PVTS( r, page)->xftvt, None);
4565 #endif
4566 }
4567 else
4568 /* If we performed an unclipped refresh, then the screen is current */
4569 PVTS(r, page)->want_refresh = 0;
4570
4571 h->refresh_type &= ~CLIPPED_REFRESH;
4572 h->want_clip_refresh = 0; /* clipping is current (regardless of wether we
4573 performed a clipped refresh or not. */
4574
4575 /* Clipping regions will now carry stale information. */
4576 if (IS_REGION(h->refreshRegion))
4577 {
4578 XDestroyRegion( h->refreshRegion );
4579 UNSET_REGION(h->refreshRegion);
4580 }
4581
4582 PVTS(r, page)->num_scr = 0;
4583 h->num_scr_allow = 1;
4584 }
4585
4586
4587 #undef X11_DRAW_STRING_8
4588 #undef X11_DRAW_STRING_16
4589 #undef X11_DRAW_IMAGE_STRING_8
4590 #undef X11_DRAW_IMAGE_STRING_16
4591 #undef XFT_DRAW_STRING_8
4592 #undef XFT_DRAW_STRING_16
4593 #undef XFT_DRAW_STRING_32
4594 #undef XFT_DRAW_STRING_UTF8
4595
4596 /* ------------------------------------------------------------------------- */
4597
4598
4599 /* EXTPROTO */
4600 void
4601 rxvt_scr_clear(rxvt_t* r, int page)
4602 {
4603 if (!PVTS(r, page)->mapped)
4604 return;
4605
4606 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_scr_clear()\n"));
4607
4608 r->h->num_scr_allow = 0;
4609 PVTS(r, page)->want_refresh = 1;
4610 #ifdef TRANSPARENT
4611 if( ISSET_OPTION(r, Opt_transparent) )
4612 {
4613 if (IS_WIN(r->TermWin.parent))
4614 XClearWindow(r->Xdisplay, r->TermWin.parent);
4615 }
4616 #endif
4617 XClearWindow(r->Xdisplay, PVTS(r, page)->vt);
4618 }
4619
4620 /* ------------------------------------------------------------------------- */
4621 /* INTPROTO */
4622 void
4623 rxvt_scr_reverse_selection(rxvt_t* r, int page)
4624 {
4625 int i, col, row, end_row;
4626 rend_t *srp;
4627
4628 if (
4629 SEL(r).op && SEL(r).vt == page &&
4630 PVTS(r, page)->current_screen == SEL(r).screen
4631 )
4632 {
4633 end_row = SVLINES - VSTART;
4634
4635 i = SEL(r).beg.row + SVLINES;
4636 row = SEL(r).end.row + SVLINES;
4637
4638 if (i >= end_row)
4639 col = SEL(r).beg.col;
4640 else
4641 {
4642 col = 0;
4643 i = end_row;
4644 }
4645
4646 end_row += r->TermWin.nrow;
4647 for (; i < row && i < end_row; i++, col = 0)
4648 for (srp = PSCR(r, page).rend[i]; col < r->TermWin.ncol; col++)
4649 #ifndef OPTION_HC
4650 srp[col] ^= RS_RVid;
4651 #else
4652 srp[col] ^= RS_Blink;
4653 #endif
4654 if (i == row && i < end_row)
4655 for (srp = PSCR(r, page).rend[i]; col < SEL(r).end.col; col++)
4656 #ifndef OPTION_HC
4657 srp[col] ^= RS_RVid;
4658 #else
4659 srp[col] ^= RS_Blink;
4660 #endif
4661 }
4662 }
4663
4664 /* ------------------------------------------------------------------------- */
4665 /*
4666 * Dump the whole scrollback and screen to the passed filedescriptor. The
4667 * invoking routine must close the fd.
4668 */
4669 #if 0
4670 /* EXTPROTO */
4671 void
4672 rxvt_scr_dump(rxvt_t* r, int fd)
4673 {
4674 int row, wrote;
4675 unsigned int width, towrite;
4676 char r1[] = "\n";
4677
4678 for (
4679 row = SVLINES - PVTS(r, page)->nscrolled;
4680 row < SVLINES + r->TermWin.nrow - 1;
4681 row++
4682 )
4683 {
4684 width = PSCR(r, page).tlen[row] >= 0 ? PSCR(r, page).tlen[row]
4685 : r->TermWin.ncol;
4686 for (towrite = width; towrite; towrite -= wrote)
4687 {
4688 wrote = write(fd, &(PSCR(r, page).text[row][width - towrite]),
4689 towrite);
4690 if (wrote < 0)
4691 return; /* XXX: death, no report */
4692 }
4693 if (PSCR(r, page).tlen[row] >= 0)
4694 if (write(fd, r1, 1) <= 0)
4695 return; /* XXX: death, no report */
4696 }
4697 }
4698 #endif
4699
4700 /* ------------------------------------------------------------------------- *
4701 * CHARACTER SELECTION *
4702 * ------------------------------------------------------------------------- */
4703
4704 /*
4705 * -PVTS(r, page)->nscrolled <= (selection row) <= r->TermWin.nrow - 1
4706 */
4707 /* EXTPROTO */
4708 void
4709 rxvt_selection_check(rxvt_t* r, int page, int check_more)
4710 {
4711 row_col_t pos;
4712
4713 if (!SEL(r).op ||
4714 SEL(r).vt != page ||
4715 SEL(r).screen != PVTS(r, page)->current_screen)
4716 return;
4717
4718 pos.row = pos.col = 0;
4719 if (
4720 (SEL(r).beg.row < -(int32_t)PVTS(r, page)->nscrolled) ||
4721 (SEL(r).beg.row >= r->TermWin.nrow) ||
4722 (SEL(r).mark.row < -(int32_t)PVTS(r, page)->nscrolled) ||
4723 (SEL(r).mark.row >= r->TermWin.nrow) ||
4724 (SEL(r).end.row < -(int32_t)PVTS(r, page)->nscrolled) ||
4725 (SEL(r).end.row >= r->TermWin.nrow) ||
4726 ( check_more == 1 &&
4727 PVTS(r, page)->current_screen == SEL(r).screen &&
4728 !RC_BEFORE(PSCR(r, page).cur, SEL(r).beg) &&
4729 RC_BEFORE(PSCR(r, page).cur, SEL(r).end)) ||
4730 ( check_more == 2 &&
4731 RC_BEFORE(SEL(r).beg, pos) &&
4732 RC_AFTER(SEL(r).end, pos)) ||
4733 ( check_more == 3 &&
4734 RC_AFTER(SEL(r).end, pos)) ||
4735 ( check_more == 4 /* screen width change */ &&
4736 ( SEL(r).beg.row != SEL(r).end.row ||
4737 SEL(r).end.col > r->TermWin.ncol))
4738 )
4739 {
4740 CLEAR_SELECTION(r);
4741 }
4742 }
4743
4744 /* ------------------------------------------------------------------------- */
4745 /*
4746 * Paste a selection direct to the command fd
4747 */
4748 /* INTPROTO */
4749 void
4750 rxvt_paste_str(rxvt_t* r, int page,
4751 const unsigned char *data, unsigned int nitems)
4752 {
4753 unsigned int i, j, n;
4754 unsigned char *ds = rxvt_malloc(PROP_SIZE);
4755
4756 /*
4757 * Convert normal newline chars into common keyboard Return key sequence
4758 */
4759 for (i = 0; i < nitems; i += PROP_SIZE)
4760 {
4761 n = min(nitems - i, PROP_SIZE);
4762 MEMCPY(ds, data + i, n);
4763 for (j = 0; j < n; j++)
4764 if (ds[j] == '\n')
4765 ds[j] = '\r';
4766 rxvt_tt_write(r, page, ds, (int)n);
4767 }
4768 rxvt_free(ds);
4769 }
4770
4771
4772 /* ------------------------------------------------------------------------- */
4773 /*
4774 * Respond to a notification that a primary selection has been sent
4775 * EXT: SelectionNotify
4776 */
4777 /* EXTPROTO */
4778 int
4779 rxvt_selection_paste(rxvt_t* r, Window win, Atom prop, Bool delete_prop)
4780 {
4781 long nread = 0;
4782 unsigned long bytes_after;
4783 XTextProperty ct;
4784 #ifdef MULTICHAR_SET
4785 int dummy_count;
4786 char** cl;
4787 #endif
4788
4789 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_paste (%08lx, %lu, %d), wait=%2x\n", win, (unsigned long)prop, (int)delete_prop, r->h->selection_wait));
4790
4791 if (NOT_ATOM(prop)) /* check for failed XConvertSelection */
4792 {
4793 #ifdef MULTICHAR_SET
4794 if ((r->h->selection_type & Sel_CompoundText))
4795 {
4796 int selnum = r->h->selection_type & Sel_whereMask;
4797
4798 r->h->selection_type = 0;
4799 if (selnum != Sel_direct)
4800 rxvt_selection_request_other(r, ATAB(r), XA_STRING, selnum);
4801 }
4802 #endif
4803 return 0;
4804 }
4805
4806 for (;;)
4807 {
4808 if(
4809 XGetWindowProperty( r->Xdisplay, win, prop, (long) (nread/4),
4810 (long) (PROP_SIZE / 4), delete_prop, AnyPropertyType,
4811 &ct.encoding, &ct.format, &ct.nitems, &bytes_after,
4812 &ct.value)
4813 != Success
4814 )
4815 break;
4816 if( ct.encoding == None )
4817 {
4818 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_paste: property didn't exist!\n"));
4819 break;
4820 }
4821
4822 if (ct.value == NULL)
4823 {
4824 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_paste: property shooting blanks!\n"));
4825 continue;
4826 }
4827
4828 if (ct.nitems == 0)
4829 {
4830 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_paste: property empty - also INCR end\n"));
4831
4832 if( r->h->selection_wait == Sel_normal && nread == 0 )
4833 {
4834 /*
4835 * pass through again trying CUT_BUFFER0 if we've come from
4836 * XConvertSelection() but nothing was presented
4837 */
4838 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_request: pasting CUT_BUFFER0\n"));
4839 rxvt_selection_paste(r, XROOT, XA_CUT_BUFFER0, False);
4840 }
4841 nread = -1; /* discount any previous stuff */
4842 break;
4843 }
4844
4845 nread += ct.nitems;
4846 #ifdef MULTICHAR_SET
4847 if (
4848 XmbTextPropertyToTextList(r->Xdisplay, &ct, &cl, &dummy_count)
4849 == Success
4850 && cl
4851 )
4852 {
4853 rxvt_paste_str(r, ATAB(r), (const unsigned char*) cl[0],
4854 STRLEN(cl[0]));
4855 XFreeStringList(cl);
4856 }
4857 else
4858 #endif
4859 rxvt_paste_str(r, ATAB(r), ct.value, (unsigned int) ct.nitems);
4860
4861 if( bytes_after == 0 )
4862 break;
4863
4864 XFree(ct.value);
4865 ct.value = 0;
4866 }
4867
4868 if (ct.value)
4869 XFree(ct.value);
4870
4871 if (r->h->selection_wait == Sel_normal)
4872 r->h->selection_wait = Sel_none;
4873
4874 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_paste: bytes written: %ld\n", nread));
4875 return (int)nread;
4876 }
4877
4878
4879 /*
4880 * INCR support originally provided by Paul Sheer <psheer@obsidian.co.za>
4881 */
4882 /* EXTPROTO */
4883 void
4884 rxvt_selection_property(rxvt_t* r, Window win, Atom prop)
4885 {
4886 int reget_time = 0;
4887
4888 if (NOT_ATOM(prop))
4889 return;
4890
4891 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_property(%08lx, %lu)\n", win, (unsigned long)prop));
4892 if (r->h->selection_wait == Sel_normal)
4893 {
4894 int a, afmt;
4895 Atom atype;
4896 unsigned long bytes_after, nitems;
4897 unsigned char *s = NULL;
4898
4899 a = XGetWindowProperty(r->Xdisplay, win, prop, 0L, 1L, False,
4900 r->h->xa[XA_INCR], &atype, &afmt, &nitems,
4901 &bytes_after, &s);
4902 if (s)
4903 XFree(s);
4904 if (a != Success)
4905 return;
4906 #ifndef OS_CYGWIN
4907 if (atype == r->h->xa[XA_INCR]) /* start an INCR transfer */
4908 {
4909 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_property: INCR: starting transfer\n"));
4910 XDeleteProperty(r->Xdisplay, win, prop);
4911 XFlush(r->Xdisplay);
4912 reget_time = 1;
4913 r->h->selection_wait = Sel_incr;
4914 }
4915 #endif
4916 }
4917 else if (r->h->selection_wait == Sel_incr)
4918 {
4919 reget_time = 1;
4920 if (rxvt_selection_paste(r, win, prop, True) == -1)
4921 {
4922 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_property: INCR: clean end\n"));
4923 r->h->selection_wait = Sel_none;
4924 r->h->timeout[TIMEOUT_INCR].tv_sec = 0; /* turn off timer */
4925 }
4926 }
4927 if (reget_time) /* received more data so reget time */
4928 {
4929 gettimeofday( &(r->h->timeout[TIMEOUT_INCR]), NULL);
4930 /* ten seconds wait */
4931 r->h->timeout[TIMEOUT_INCR].tv_sec += 10;
4932 }
4933 }
4934
4935
4936 /* ------------------------------------------------------------------------- */
4937 /*
4938 * Request the content of a selection buffer:
4939 *
4940 * EXT: button 2 release
4941 */
4942 /* EXTPROTO */
4943 void
4944 rxvt_selection_request_by_sel(rxvt_t* r, int page, Time tm, int x, int y,int sel)
4945 {
4946 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_request %d (%lu, %d, %d)\n", page, tm, x, y ));
4947
4948 if (x < 0 || x >= VT_WIDTH(r) || y < 0 || y >= VT_HEIGHT(r))
4949 return; /* outside window */
4950
4951 r->h->selection_request_time = tm;
4952 r->h->selection_wait = Sel_normal;
4953
4954 #ifdef MULTICHAR_SET
4955 r->h->selection_type = Sel_CompoundText;
4956 #else
4957 r->h->selection_type = 0;
4958 #endif
4959 rxvt_selection_request_other(r, page,
4960 #ifdef MULTICHAR_SET
4961 r->h->xa[XA_COMPOUND_TEXT],
4962 #else
4963 XA_STRING,
4964 #endif
4965 sel);
4966 }
4967
4968
4969 /* ------------------------------------------------------------------------- */
4970 /*
4971 * Request the current selection:
4972 * Order: > internal selection if available
4973 * > PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+)
4974 * > CUT_BUFFER0
4975 * (+) if ownership is claimed but property is empty, rxvt_selection_paste()
4976 * will auto fallback to CUT_BUFFER0
4977 * EXT: button 2 release
4978 */
4979 /* EXTPROTO */
4980 void
4981 rxvt_selection_request(rxvt_t* r, int page, Time tm, int x, int y)
4982 {
4983 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_request %d (%lu, %d, %d)\n", page, tm, x, y ));
4984
4985 if (x < 0 || x >= VT_WIDTH(r) || y < 0 || y >= VT_HEIGHT(r))
4986 return; /* outside window */
4987
4988 if( SEL(r).text != NULL ) /* internal selection */
4989 {
4990 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_request %d: pasting internal\n", page ));
4991 rxvt_paste_str( r, page, SEL(r).text, SEL(r).len );
4992 return;
4993 }
4994 else
4995 {
4996 int i;
4997
4998 r->h->selection_request_time = tm;
4999 r->h->selection_wait = Sel_normal;
5000
5001 for (i = Sel_Primary; i <= Sel_Clipboard; i++)
5002 {
5003 #ifdef MULTICHAR_SET
5004 r->h->selection_type = Sel_CompoundText;
5005 #else
5006 r->h->selection_type = 0;
5007 #endif
5008 if (rxvt_selection_request_other(r, page,
5009 #ifdef MULTICHAR_SET
5010 r->h->xa[XA_COMPOUND_TEXT],
5011 #else
5012 XA_STRING,
5013 #endif
5014 i))
5015 return;
5016 }
5017 }
5018
5019 /* don't loop in rxvt_selection_paste() */
5020 r->h->selection_wait = Sel_none;
5021 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_request %d: pasting CUT_BUFFER0\n", page ));
5022 rxvt_selection_paste(r, XROOT, XA_CUT_BUFFER0, False);
5023 }
5024
5025
5026 /* INTPROTO */
5027 int
5028 rxvt_selection_request_other(rxvt_t* r, int page, Atom target, int selnum)
5029 {
5030 Atom sel;
5031 #ifdef DEBUG
5032 char *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
5033 #endif
5034
5035 r->h->selection_type |= selnum;
5036 if (selnum == Sel_Primary)
5037 sel = XA_PRIMARY;
5038 else if (selnum == Sel_Secondary)
5039 sel = XA_SECONDARY;
5040 else
5041 sel = r->h->xa[XA_CLIPBOARD];
5042 if (XGetSelectionOwner(r->Xdisplay, sel) != None)
5043 {
5044 rxvt_dbgmsg(( DBG_DEBUG, DBG_SCREEN, "rxvt_selection_request_other %d: "
5045 "pasting %s\n", page, debug_xa_names[selnum] ));
5046
5047 XConvertSelection(r->Xdisplay, sel, target,
5048 r->h->xa[XA_VT_SELECTION], PVTS(r, page)->vt,
5049 r->h->selection_request_time);
5050 return 1;
5051 }
5052 return 0;
5053 }
5054
5055
5056 /* ------------------------------------------------------------------------- */
5057 /*
5058 * Paste the content of the file specified by filename to the
5059 * currently active tab
5060 * EXT: button 2 release
5061 */
5062 /* EXTPROTO */
5063 void
5064 rxvt_paste_file(rxvt_t* r, int page, Time tm, int x, int y, char* filename)
5065 {
5066 rxvt_dbgmsg(( DBG_DEBUG, DBG_SCREEN,
5067 "rxvt_paste_file %d (%lu, %d, %d) %s\n", page, tm, x, y,
5068 filename ));
5069
5070 if (x < 0 || x >= VT_WIDTH(r) || y < 0 || y >= VT_HEIGHT(r))
5071 return; /* outside window */
5072
5073 char buffer[BUFSIZ];
5074 char TAINTED * str;
5075 FILE * fdpaste;
5076
5077 #ifdef HAVE_WORDEXP_H
5078 wordexp_t p;
5079 int wordexp_result;
5080
5081 /* perform a shell-like expansion of the provided filename */
5082 wordexp_result = wordexp(filename, &p, 0);
5083 if( wordexp_result == 0 && p.we_wordc == 1 )
5084 filename = *p.we_wordv;
5085 else
5086 {
5087 rxvt_msg( DBG_ERROR, DBG_SCREEN,
5088 "Error expanding %s, or possibly ambiguous expansion\n",
5089 filename );
5090 rxvt_msg( DBG_INFO, DBG_SCREEN, "wordexp_result=%i\n", wordexp_result );
5091 }
5092 #endif
5093
5094 if (NOT_NULL(fdpaste = fopen( filename , "r")))
5095 {
5096 while (NOT_NULL(str = fgets(buffer, sizeof(buffer), fdpaste)))
5097 rxvt_paste_str( r, page, (const unsigned char*) str , STRLEN(str));
5098
5099 fclose(fdpaste);
5100 }
5101 else
5102 {
5103 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN,
5104 "rxvt_paste_file : unable to open file '%s'\n", filename));
5105 }
5106
5107 #ifdef HAVE_WORDEXP_H
5108 wordfree(&p);
5109 #endif
5110 return;
5111 }
5112
5113
5114
5115 /* ------------------------------------------------------------------------- */
5116 /*
5117 * Clear all selected text
5118 * EXT: SelectionClear
5119 */
5120 /* EXTPROTO */
5121 void
5122 rxvt_process_selectionclear(rxvt_t* r, int page)
5123 {
5124 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_process_selectionclear %d ()\n", page));
5125
5126 PVTS(r, page)->want_refresh = 1;
5127 if (SEL(r).text)
5128 rxvt_free(SEL(r).text);
5129 SEL(r).text = NULL;
5130 SEL(r).len = 0;
5131 CLEAR_SELECTION(r);
5132 SEL(r).vt = -1;
5133
5134 SEL(r).op = SELECTION_CLEAR;
5135 SEL(r).screen = PRIMARY;
5136 SEL(r).clicks = 0;
5137 }
5138
5139
5140 /* ------------------------------------------------------------------------- */
5141 /*
5142 * Copy a selection into the cut buffer
5143 * EXT: button 1 or 3 release
5144 */
5145 /* EXTPROTO */
5146 void
5147 rxvt_selection_make(rxvt_t* r, int page, Time tm)
5148 {
5149 int i, col, end_col, row, end_row;
5150 unsigned char* new_selection_text;
5151 unsigned char* str;
5152 text_t* t;
5153 #ifdef MULTICHAR_SET
5154 rend_t* tr;
5155 #endif
5156 #ifdef ACS_ASCII
5157 rend_t* re;
5158 #endif
5159
5160 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_make %d (): sel.op=%d, sel.clicks=%d\n", page, SEL(r).op, SEL(r).clicks));
5161 switch (SEL(r).op)
5162 {
5163 case SELECTION_CONT:
5164 break;
5165 case SELECTION_INIT:
5166 CLEAR_SELECTION(r);
5167 /* FALLTHROUGH */
5168 case SELECTION_BEGIN:
5169 SEL(r).op = SELECTION_DONE;
5170 /* FALLTHROUGH */
5171 default:
5172 return;
5173 }
5174 SEL(r).op = SELECTION_DONE;
5175 SEL(r).vt = page; /* update selection vt */
5176
5177 if (SEL(r).clicks == 4)
5178 return; /* nothing selected, go away */
5179
5180 assert ((SEL(r).end.row - SEL(r).beg.row + 1) > 0);
5181 assert ((r->TermWin.ncol + 1) > 0);
5182 i = (SEL(r).end.row - SEL(r).beg.row + 1)
5183 * (r->TermWin.ncol + 1) + 1;
5184 /* possible integer overflow? */
5185 assert (i > 0);
5186 str = rxvt_malloc(i * sizeof(char));
5187
5188 new_selection_text = (unsigned char *)str;
5189
5190 col = SEL(r).beg.col;
5191 MAX_IT(col, 0);
5192 row = SEL(r).beg.row + SVLINES;
5193 end_row = SEL(r).end.row + SVLINES;
5194
5195 /*
5196 ** A: rows before end row
5197 */
5198 for (; row < end_row; row++, col = 0)
5199 {
5200 t = &(PSCR(r, page).text[row][col]);
5201 #ifdef MULTICHAR_SET
5202 tr = &(PSCR(r, page).rend[row][col]);
5203 #endif /* MULTICHAR_SET */
5204 #ifdef ACS_ASCII
5205 re = &(PSCR(r, page).rend[row][col]);
5206 #endif
5207 if ((end_col = PSCR(r, page).tlen[row]) == -1)
5208 end_col = r->TermWin.ncol;
5209
5210
5211 /*
5212 ** Looks like a completely mess. Think about the logic here
5213 ** carefully. ;-)
5214 ** Patch source:
5215 ** http://gentoo.nedlinux.nl/distfiles/rxvt-2.7.10-rk.patch
5216 */
5217 for (; col < end_col; col++, str++, t++)
5218 {
5219 #ifdef MULTICHAR_SET
5220 if (
5221 (ENC_EUCJ == r->encoding_method) && (*t & 0x80)
5222 && !(*tr & RS_multiMask)
5223 )
5224 {
5225 *str++ = 0x8E;
5226 }
5227 tr ++;
5228 #endif /* MULTICHAR_SET */
5229 #ifdef ACS_ASCII
5230 if ((*re++ & RS_acsFont) && *t >= 0x60 && *t < 0x80)
5231 *str = r->h->rs[Rs_acs_chars][(*t) - 0x60];
5232 else
5233 #endif /* ACS_ASCII */
5234 *str = *t;
5235 }
5236
5237
5238 if (PSCR(r, page).tlen[row] != -1)
5239 {
5240 #ifdef DONT_SELECT_TRAILING_SPACES
5241 STRIP_TRAILING_SPACE(str, new_selection_text);
5242 #endif
5243 *str++ = '\n';
5244 }
5245 }
5246
5247 /*
5248 ** B: end row
5249 */
5250 t = &(PSCR(r, page).text[row][col]);
5251 #ifdef MULTICHAR_SET
5252 tr = &(PSCR(r, page).rend[row][col]);
5253 #endif /* MULTICHAR_SET */
5254 #ifdef ACS_ASCII
5255 re = &(PSCR(r, page).rend[row][col]);
5256 #endif
5257 end_col = PSCR(r, page).tlen[row];
5258 if (end_col == -1 || SEL(r).end.col <= end_col)
5259 end_col = SEL(r).end.col;
5260 MIN_IT(end_col, r->TermWin.ncol); /* CHANGE */
5261
5262
5263 /*
5264 ** Looks like a completely mess. Think about the logic here
5265 ** carefully. ;-)
5266 ** Patch source:
5267 ** http://gentoo.nedlinux.nl/distfiles/rxvt-2.7.10-rk.patch
5268 */
5269 for (; col < end_col; col++, str++, t++)
5270 {
5271 #ifdef MULTICHAR_SET
5272 if (
5273 (ENC_EUCJ == r->encoding_method) && (*t & 0x80)
5274 && !(*tr & RS_multiMask)
5275 )
5276 {
5277 *str++ = 0x8E;
5278 }
5279 tr ++;
5280 #endif /* MULTICHAR_SET */
5281 #ifdef ACS_ASCII
5282 if ((*re++ & RS_acsFont) && *t >= 0x60 && *t < 0x80)
5283 *str = r->h->rs[Rs_acs_chars][(*t) - 0x60];
5284 else
5285 #endif /* ACS_ASCII */
5286 *str = *t;
5287 }
5288
5289 #ifdef DONT_SELECT_TRAILING_SPACES
5290 STRIP_TRAILING_SPACE(str, new_selection_text);
5291 #endif
5292
5293
5294 #ifndef NO_OLD_SELECTION
5295 if (r->selection_style == OLD_SELECT)
5296 if (end_col == r->TermWin.ncol)
5297 {
5298 *str++ = '\n';
5299 }
5300 #endif
5301 #ifndef NO_NEW_SELECTION
5302 if (r->selection_style != OLD_SELECT)
5303 if (end_col != SEL(r).end.col)
5304 {
5305 *str++ = '\n';
5306 }
5307 #endif
5308 *str = '\0';
5309 if ((i = STRLEN((char *)new_selection_text)) == 0)
5310 {
5311 rxvt_free(new_selection_text);
5312 return;
5313 }
5314 SEL(r).len = i;
5315 if (SEL(r).text)
5316 rxvt_free(SEL(r).text);
5317 SEL(r).text = new_selection_text;
5318
5319 XSetSelectionOwner(r->Xdisplay, XA_PRIMARY, PVTS(r, page)->vt, tm);
5320 if (XGetSelectionOwner(r->Xdisplay, XA_PRIMARY) != PVTS(r, page)->vt)
5321 rxvt_msg (DBG_ERROR, DBG_SCREEN, "can't get primary selection");
5322 XChangeProperty(r->Xdisplay, XROOT, XA_CUT_BUFFER0, XA_STRING, 8,
5323 PropModeReplace, SEL(r).text, (int)SEL(r).len);
5324 r->h->selection_time = tm;
5325 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_make %d (): sel.len=%d\n", page, SEL(r).len));
5326 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "sel.text=%s\n", SEL(r).text));
5327 }
5328
5329
5330 /* ------------------------------------------------------------------------- */
5331 /*
5332 * Mark or select text based upon number of clicks: 1, 2, or 3
5333 * EXT: button 1 press
5334 */
5335 /* EXTPROTO */
5336 void
5337 rxvt_selection_click(rxvt_t* r, int page, int clicks, int x, int y)
5338 {
5339 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "rxvt_selection_click %d (%d, %d, %d)\n", page, clicks, x, y));
5340
5341 SEL(r).vt = page;
5342 clicks = ((clicks - 1) % 3) + 1;
5343 SEL(r).clicks = clicks; /* save clicks so extend will work */
5344
5345 rxvt_selection_start_colrow(r, page, Pixel2Col(x), Pixel2Row(y));
5346
5347 if (clicks == 2 || clicks == 3)
5348 rxvt_selection_extend_colrow(r, page, SEL(r).mark.col,
5349 SEL(r).mark.row + VSTART,
5350 0, /* button 3 */
5351 1, /* button press */
5352 0); /* click change */
5353 }
5354
5355
5356 /* ------------------------------------------------------------------------- */
5357 /*
5358 * Mark a selection at the specified col/row
5359 */
5360 /* INTPROTO */
5361 void
5362 rxvt_selection_start_colrow(rxvt_t* r, int page, int col, int row)
5363 {
5364 PVTS(r, page)->want_refresh = 1;
5365 SEL(r).mark.col = col;
5366 SEL(r).mark.row = row - VSTART;
5367 MAX_IT(SEL(r).mark.row, -(int32_t)PVTS(r, page)->nscrolled);
5368 MIN_IT(SEL(r).mark.row, (int32_t)r->TermWin.nrow - 1);
5369 MAX_IT(SEL(r).mark.col, 0);
5370 MIN_IT(SEL(r).mark.col, (int32_t)r->TermWin.ncol - 1);
5371
5372 if (SEL(r).op)
5373 {
5374 /* clear the old selection */
5375 SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
5376 SEL(r).beg.col = SEL(r).end.col = SEL(r).mark.col;
5377 }
5378 SEL(r).op = SELECTION_INIT;
5379 SEL(r).screen = PVTS(r, page)->current_screen;
5380 r->selection.vt = page;
5381 }
5382
5383
5384 /* ------------------------------------------------------------------------- */
5385 /*
5386 * Word select: select text for 2 clicks
5387 * We now only find out the boundary in one direction
5388 */
5389
5390 /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
5391 #define DELIMIT_TEXT(x) \
5392 (((x) == ' ' || (x) == '\t') ? 2 : (STRCHR(r->h->rs[Rs_cutchars], (x)) != NULL))
5393 #ifdef MULTICHAR_SET
5394 # define DELIMIT_REND(x) (((x) & RS_multiMask) ? 1 : 0)
5395 #else
5396 # define DELIMIT_REND(x) 1
5397 #endif
5398
5399 /* INTPROTO */
5400 void
5401 rxvt_selection_delimit_word(rxvt_t* r, int page, enum page_dirn dirn, const row_col_t *mark, row_col_t *ret)
5402 {
5403 int col, row, dirnadd, tcol, trow, w1, w2;
5404 row_col_t bound;
5405 text_t *stp;
5406 rend_t *srp;
5407
5408
5409 r->selection.vt = page; /* update selection vt */
5410
5411 if (dirn == UP)
5412 {
5413 bound.row = SVLINES - PVTS(r, page)->nscrolled - 1;
5414 bound.col = 0;
5415 dirnadd = -1;
5416 }
5417 else
5418 {
5419 bound.row = SVLINES + r->TermWin.nrow;
5420 bound.col = r->TermWin.ncol - 1;
5421 dirnadd = 1;
5422 }
5423 row = mark->row + SVLINES;
5424 col = mark->col;
5425 MAX_IT(col, 0);
5426 /* find the edge of a word */
5427 stp = &(PSCR(r, page).text[row][col]);
5428 w1 = DELIMIT_TEXT(*stp);
5429
5430 if (r->selection_style != NEW_SELECT)
5431 {
5432 if (w1 == 1)
5433 {
5434 stp += dirnadd;
5435 if (DELIMIT_TEXT(*stp) == 1)
5436 goto Old_Word_Selection_You_Die;
5437 col += dirnadd;
5438 }
5439 w1 = 0;
5440 }
5441 srp = (&PSCR(r, page).rend[row][col]);
5442 w2 = DELIMIT_REND(*srp);
5443
5444 for (;;)
5445 {
5446 for (; col != bound.col; col += dirnadd)
5447 {
5448 stp += dirnadd;
5449 if (DELIMIT_TEXT(*stp) != w1)
5450 break;
5451 srp += dirnadd;
5452 if (DELIMIT_REND(*srp) != w2)
5453 break;
5454 }
5455 if ((col == bound.col) && (row != bound.row))
5456 {
5457 if (PSCR(r, page).tlen[(row - (dirn == UP ? 1 : 0))] == -1)
5458 {
5459 trow = row + dirnadd;
5460 tcol = dirn == UP ? r->TermWin.ncol - 1 : 0;
5461 if (PSCR(r, page).text[trow] == NULL)
5462 break;
5463 stp = &(PSCR(r, page).text[trow][tcol]);
5464 srp = &(PSCR(r, page).rend[trow][tcol]);
5465 if (DELIMIT_TEXT(*stp) != w1 ||
5466 DELIMIT_REND(*srp) != w2)
5467 break;
5468 row = trow;
5469 col = tcol;
5470 continue;
5471 }
5472 }
5473 break;
5474 }
5475
5476 Old_Word_Selection_You_Die:
5477 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
5478
5479 if (dirn == DN)
5480 col++; /* put us on one past the end */
5481
5482 /* Poke the values back in */
5483 ret->row = row - SVLINES;
5484 ret->col = col;
5485 }
5486
5487
5488 /* ------------------------------------------------------------------------- */
5489 /*
5490 * Extend the selection to the specified x/y pixel location
5491 * EXT: button 3 press; button 1 or 3 drag
5492 * flag == 0 ==> button 1
5493 * flag == 1 ==> button 3 press
5494 * flag == 2 ==> button 3 motion
5495 */
5496 /* EXTPROTO */
5497 void
5498 rxvt_selection_extend(rxvt_t* r, int page, int x, int y, int flag)
5499 {
5500 int col, row;
5501
5502 col = Pixel2Col(x);
5503 row = Pixel2Row(y);
5504 MAX_IT(row, 0);
5505 MIN_IT(row, (int)r->TermWin.nrow - 1);
5506 MAX_IT(col, 0);
5507 MIN_IT(col, (int)r->TermWin.ncol);
5508
5509 #ifndef NO_NEW_SELECTION
5510 /*
5511 * If we're selecting characters (single click) then we must check first
5512 * if we are at the same place as the original mark. If we are then
5513 * select nothing. Otherwise, if we're to the right of the mark, you have to
5514 * be _past_ a character for it to be selected.
5515 */
5516 if (r->selection_style != OLD_SELECT)
5517 {
5518 if (
5519 ((SEL(r).clicks % 3) == 1) && !flag
5520 && (
5521 col == SEL(r).mark.col
5522 && (row == SEL(r).mark.row + VSTART)
5523 )
5524 )
5525 {
5526 /* select nothing */
5527 SEL(r).beg.row = SEL(r).end.row = 0;
5528 SEL(r).beg.col = SEL(r).end.col = 0;
5529 SEL(r).clicks = 4;
5530 PVTS(r, page)->want_refresh = 1;
5531 rxvt_dbgmsg ((DBG_DEBUG, DBG_SCREEN, "rxvt_selection_extend %d () sel.clicks = 4\n", page));
5532 return;
5533 }
5534 }
5535 #endif
5536 if (SEL(r).clicks == 4)
5537 SEL(r).clicks = 1;
5538 rxvt_selection_extend_colrow(r, page, col, row, !!flag,
5539 /* ? button 3 */
5540 flag == 1 ? 1 : 0, /* ? button press */
5541 0); /* no click change */
5542 }
5543
5544
5545 #ifdef MULTICHAR_SET
5546 /* INTPROTO */
5547 void
5548 rxvt_selection_adjust_kanji(rxvt_t* r, int page)
5549 {
5550 int c1, r1;
5551
5552 if (SEL(r).beg.col > 0)
5553 {
5554 r1 = SEL(r).beg.row + SVLINES;
5555 c1 = SEL(r).beg.col;
5556 if (IS_MULTI2(PSCR(r, page).rend[r1][c1]) &&
5557 IS_MULTI1(PSCR(r, page).rend[r1][c1 - 1]))
5558 SEL(r).beg.col--;
5559 }
5560 if (SEL(r).end.col < r->TermWin.ncol)
5561 {
5562 r1 = SEL(r).end.row + SVLINES;
5563 c1 = SEL(r).end.col;
5564 if (IS_MULTI1(PSCR(r, page).rend[r1][c1 - 1]) &&
5565 IS_MULTI2(PSCR(r, page).rend[r1][c1]))
5566 SEL(r).end.col++;
5567 }
5568 }
5569 #endif /* MULTICHAR_SET */
5570
5571
5572 /* ------------------------------------------------------------------------- */
5573 /*
5574 * Extend the selection to the specified col/row
5575 */
5576 /* INTPROTO */
5577 void
5578 rxvt_selection_extend_colrow(rxvt_t* r, int page, int32_t col, int32_t row, int button3, int buttonpress, int clickchange)
5579 {
5580 unsigned int ncol = r->TermWin.ncol;
5581 row_col_t pos;
5582 #ifndef NO_NEW_SELECTION
5583 int end_col;
5584 enum {
5585 LEFT, RIGHT
5586 } closeto = RIGHT;
5587 #endif
5588
5589
5590 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
5591 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
5592
5593 PVTS(r, page)->want_refresh = 1;
5594 switch (SEL(r).op)
5595 {
5596 case SELECTION_INIT:
5597 CLEAR_SELECTION(r);
5598 SEL(r).op = SELECTION_BEGIN;
5599 /* FALLTHROUGH */
5600 case SELECTION_BEGIN:
5601 if (row != SEL(r).mark.row ||
5602 col != SEL(r).mark.col ||
5603 (!button3 && buttonpress))
5604 SEL(r).op = SELECTION_CONT;
5605 break;
5606 case SELECTION_DONE:
5607 SEL(r).op = SELECTION_CONT;
5608 /* FALLTHROUGH */
5609 case SELECTION_CONT:
5610 break;
5611 case SELECTION_CLEAR:
5612 rxvt_selection_start_colrow(r, page, col, row);
5613 /* FALLTHROUGH */
5614 default:
5615 return;
5616 }
5617
5618 if (
5619 SEL(r).beg.col == SEL(r).end.col
5620 && SEL(r).beg.col != SEL(r).mark.col
5621 && SEL(r).beg.row == SEL(r).end.row
5622 && SEL(r).beg.row != SEL(r).mark.row
5623 )
5624 {
5625 SEL(r).beg.col = SEL(r).end.col = SEL(r).mark.col;
5626 SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
5627 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN,
5628 "rxvt_selection_extend_colrow %d () "
5629 "ENT2 b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n",
5630 page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row,
5631 SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
5632 }
5633
5634 pos.col = col;
5635 pos.row = row;
5636
5637 pos.row -= VSTART; /* adjust for scroll */
5638
5639
5640 #ifndef NO_OLD_SELECTION
5641 /*
5642 ** This mimics some of the selection behaviour of version 2.20
5643 ** and before.
5644 ** There are no ``selection modes'', button3 is always character
5645 ** extension.
5646 ** Note: button3 drag is always available, c.f. v2.20
5647 ** Selection always terminates (left or right as appropriate) at
5648 ** the mark.
5649 */
5650 if (r->selection_style == OLD_SELECT)
5651 {
5652 if (SEL(r).clicks == 1 || button3)
5653 {
5654 if (r->h->hate_those_clicks)
5655 {
5656 r->h->hate_those_clicks = 0;
5657 if (SEL(r).clicks == 1)
5658 {
5659 SEL(r).beg.row = SEL(r).mark.row;
5660 SEL(r).beg.col = SEL(r).mark.col;
5661 }
5662 else
5663 {
5664 SEL(r).mark.row = SEL(r).beg.row;
5665 SEL(r).mark.col = SEL(r).beg.col;
5666 }
5667 }
5668
5669 if (RC_BEFORE(pos, SEL(r).mark))
5670 {
5671 SEL(r).end.row = SEL(r).mark.row;
5672 SEL(r).end.col = SEL(r).mark.col + 1;
5673 SEL(r).beg.row = pos.row;
5674 SEL(r).beg.col = pos.col;
5675 }
5676 else
5677 {
5678 SEL(r).beg.row = SEL(r).mark.row;
5679 SEL(r).beg.col = SEL(r).mark.col;
5680 SEL(r).end.row = pos.row;
5681 SEL(r).end.col = pos.col + 1;
5682 }
5683 # ifdef MULTICHAR_SET
5684 rxvt_selection_adjust_kanji(r, page);
5685 # endif /* MULTICHAR_SET */
5686 }
5687 else if (SEL(r).clicks == 2)
5688 {
5689 rxvt_selection_delimit_word(r, page, UP, &(SEL(r).mark),
5690 &(SEL(r).beg));
5691 rxvt_selection_delimit_word(r, page, DN, &(SEL(r).mark),
5692 &(SEL(r).end));
5693 r->h->hate_those_clicks = 1;
5694 }
5695 else if (SEL(r).clicks == 3)
5696 {
5697 SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
5698 SEL(r).beg.col = 0;
5699 SEL(r).end.col = ncol;
5700 r->h->hate_those_clicks = 1;
5701 }
5702
5703 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
5704 return;
5705 }
5706 #endif /* ! NO_OLD_SELECTION */
5707
5708
5709 #ifndef NO_NEW_SELECTION
5710 /* selection_style must not be OLD_SELECT to get here */
5711 /*
5712 ** This is mainly xterm style selection with a couple of
5713 ** differences, mainly in the way button3 drag extension
5714 ** works.
5715 ** We're either doing: button1 drag; button3 press; or
5716 ** button3 drag
5717 ** a) button1 drag : select around a midpoint/word/line -
5718 ** that point/word/line is always at the left/right edge
5719 ** of the SEL(r).
5720 ** b) button3 press: extend/contract character/word/line
5721 ** at whichever edge of the selection we are closest to.
5722 ** c) button3 drag : extend/contract character/word/line
5723 ** - we select around a point/word/line which is either
5724 ** the start or end of the selection and it was decided
5725 ** by whichever point/word/line was `fixed' at the time
5726 ** of the most recent button3 press
5727 */
5728 if (button3 && buttonpress) /* button3 press */
5729 {
5730 /* first determine which edge of the selection we are
5731 ** closest to
5732 */
5733 if (RC_BEFORE(pos, SEL(r).beg) ||
5734 (!RC_AFTER(pos, SEL(r).end) &&
5735 (((pos.col - SEL(r).beg.col) +
5736 ((pos.row - SEL(r).beg.row) * ncol)) <
5737 ((SEL(r).end.col - pos.col) +
5738 ((SEL(r).end.row - pos.row) * ncol)))))
5739 closeto = LEFT;
5740
5741 if (closeto == LEFT)
5742 {
5743 SEL(r).beg.row = pos.row;
5744 SEL(r).beg.col = pos.col;
5745 SEL(r).mark.row = SEL(r).end.row;
5746 SEL(r).mark.col = SEL(r).end.col
5747 - (SEL(r).clicks == 2);
5748 }
5749 else
5750 {
5751 SEL(r).end.row = pos.row;
5752 SEL(r).end.col = pos.col;
5753 SEL(r).mark.row = SEL(r).beg.row;
5754 SEL(r).mark.col = SEL(r).beg.col;
5755 }
5756 }
5757 else /* button1 drag or button3 drag */
5758 {
5759 if (RC_AFTER(SEL(r).mark, pos))
5760 {
5761 if ((SEL(r).mark.row == SEL(r).end.row) &&
5762 (SEL(r).mark.col == SEL(r).end.col) &&
5763 clickchange && SEL(r).clicks == 2)
5764 SEL(r).mark.col--;
5765 SEL(r).beg.row = pos.row;
5766 SEL(r).beg.col = pos.col;
5767 SEL(r).end.row = SEL(r).mark.row;
5768 SEL(r).end.col = SEL(r).mark.col
5769 + (SEL(r).clicks == 2);
5770 }
5771 else
5772 {
5773 SEL(r).beg.row = SEL(r).mark.row;
5774 SEL(r).beg.col = SEL(r).mark.col;
5775 SEL(r).end.row = pos.row;
5776 SEL(r).end.col = pos.col;
5777 }
5778 }
5779
5780
5781 if (SEL(r).clicks == 1)
5782 {
5783 end_col = PSCR(r, page).tlen[SEL(r).beg.row + SVLINES];
5784 if (end_col != -1 && SEL(r).beg.col > end_col)
5785 {
5786 #if 1
5787 SEL(r).beg.col = ncol;
5788 #else
5789 if (SEL(r).beg.row != SEL(r).end.row)
5790 SEL(r).beg.col = ncol;
5791 else
5792 SEL(r).beg.col = SEL(r).mark.col;
5793 #endif
5794 }
5795 end_col = PSCR(r, page).tlen[SEL(r).end.row +
5796 SVLINES];
5797 if (end_col != -1 && SEL(r).end.col > end_col)
5798 SEL(r).end.col = ncol;
5799
5800 # ifdef MULTICHAR_SET
5801 rxvt_selection_adjust_kanji(r, page);
5802 # endif /* MULTICHAR_SET */
5803 }
5804 else if (SEL(r).clicks == 2)
5805 {
5806 if (RC_AFTER(SEL(r).end, SEL(r).beg))
5807 SEL(r).end.col--;
5808 rxvt_selection_delimit_word(r, page, UP, &(SEL(r).beg),
5809 &(SEL(r).beg));
5810 rxvt_selection_delimit_word(r, page, DN, &(SEL(r).end),
5811 &(SEL(r).end));
5812 }
5813 else if (SEL(r).clicks == 3)
5814 {
5815 #ifndef NO_FRILLS
5816 if (ISSET_OPTION(r, Opt_tripleclickwords))
5817 {
5818 int end_row;
5819
5820 rxvt_selection_delimit_word(r, page, UP, &(SEL(r).beg),
5821 &(SEL(r).beg));
5822 end_row = PSCR(r, page).tlen[SEL(r).mark.row +
5823 SVLINES];
5824 for (
5825 end_row = SEL(r).mark.row;
5826 end_row < r->TermWin.nrow;
5827 end_row++
5828 )
5829 {
5830 end_col = PSCR(r, page).tlen[end_row + SVLINES];
5831 if (end_col != -1)
5832 {
5833 SEL(r).end.row = end_row;
5834 SEL(r).end.col = end_col;
5835 rxvt_selection_trim(r, page);
5836 break;
5837 }
5838 } /* for */
5839 }
5840 else
5841 #endif
5842 {
5843 if (RC_AFTER(SEL(r).mark, SEL(r).beg))
5844 SEL(r).mark.col++;
5845 SEL(r).beg.col = 0;
5846 SEL(r).end.col = ncol;
5847 }
5848 } /* if (ISSET_OPTION(r, Opt_tripleclickwords)) */
5849
5850 if (button3 && buttonpress)
5851 {
5852 /* mark may need to be changed */
5853 if (closeto == LEFT)
5854 {
5855 SEL(r).mark.row = SEL(r).end.row;
5856 SEL(r).mark.col = SEL(r).end.col - (SEL(r).clicks == 2);
5857 }
5858 else
5859 {
5860 SEL(r).mark.row = SEL(r).beg.row;
5861 SEL(r).mark.col = SEL(r).beg.col;
5862 }
5863 }
5864
5865 rxvt_dbgmsg ((DBG_VERBOSE, DBG_SCREEN, "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));
5866
5867 #endif /* ! NO_NEW_SELECTION */
5868 }
5869
5870
5871 #ifndef NO_FRILLS
5872 /* INTPROTO */
5873 void
5874 rxvt_selection_trim(rxvt_t* r, int page)
5875 {
5876 int32_t end_col, end_row;
5877 text_t *stp;
5878
5879 end_col = SEL(r).end.col;
5880 end_row = SEL(r).end.row;
5881 for ( ; end_row >= SEL(r).beg.row; )
5882 {
5883 stp = PSCR(r, page).text[end_row + SVLINES];
5884 while (--end_col >= 0)
5885 {
5886 if (stp[end_col] != ' ' && stp[end_col] != '\t')
5887 break;
5888 }
5889 if (end_col >= 0 || PSCR(r, page).tlen[end_row - 1 + SVLINES] != -1)
5890 {
5891 SEL(r).end.col = end_col + 1;
5892 SEL(r).end.row = end_row;
5893 break;
5894 }
5895 end_row--;
5896 end_col = r->TermWin.ncol;
5897 }
5898
5899 if (SEL(r).mark.row > SEL(r).end.row)
5900 {
5901 SEL(r).mark.row = SEL(r).end.row;
5902 SEL(r).mark.col = SEL(r).end.col;
5903 }
5904 else if (SEL(r).mark.row == SEL(r).end.row &&
5905 SEL(r).mark.col > SEL(r).end.col)
5906 SEL(r).mark.col = SEL(r).end.col;
5907 }
5908 #endif
5909
5910
5911 /* ------------------------------------------------------------------------- */
5912 /*
5913 * Double click on button 3 when already selected
5914 * EXT: button 3 double click
5915 */
5916 /* EXTPROTO */
5917 void
5918 rxvt_selection_rotate(rxvt_t* r, int page, int x, int y)
5919 {
5920 SEL(r).clicks = SEL(r).clicks % 3 + 1;
5921
5922 rxvt_selection_extend_colrow (r, page, Pixel2Col(x),
5923 Pixel2Row(y), 1, 0, 1);
5924 }
5925
5926
5927
5928 /* ------------------------------------------------------------------------- */
5929 /*
5930 * Respond to a request for our current selection
5931 * EXT: SelectionRequest
5932 */
5933 /* EXTPROTO */
5934 void
5935 rxvt_process_selectionrequest (rxvt_t* r, int page, const XSelectionRequestEvent *rq)
5936 {
5937 XSelectionEvent ev;
5938 #ifdef USE_XIM
5939 Atom target_list[4];
5940 #else
5941 Atom target_list[3];
5942 #endif
5943 Atom target;
5944 XTextProperty ct;
5945 XICCEncodingStyle style;
5946 char *cl[2], dummy[1];
5947
5948 ev.type = SelectionNotify;
5949 ev.property = None;
5950 ev.display = rq->display;
5951 ev.requestor = rq->requestor;
5952 ev.selection = rq->selection;
5953 ev.target = rq->target;
5954 ev.time = rq->time;
5955
5956 if (rq->target == r->h->xa[XA_TARGETS])
5957 {
5958 target_list[0] = r->h->xa[XA_TARGETS];
5959 target_list[1] = XA_STRING;
5960 target_list[2] = r->h->xa[XA_TEXT];
5961 #ifdef USE_XIM
5962 target_list[3] = r->h->xa[XA_COMPOUND_TEXT];
5963 #endif
5964 XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
5965 XA_ATOM, 32, PropModeReplace,
5966 (unsigned char *)target_list,
5967 (sizeof(target_list) / sizeof(target_list[0])));
5968 ev.property = rq->property;
5969 }
5970 else if (rq->target == r->h->xa[XA_MULTIPLE])
5971 {
5972 /* TODO: Handle MULTIPLE */
5973 }
5974 else if (rq->target == r->h->xa[XA_TIMESTAMP] && SEL(r).text)
5975 {
5976 XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
5977 XA_INTEGER,
5978 sizeof(Time) > 4 ? 32 : (8 * sizeof(Time)),
5979 PropModeReplace, (unsigned char*)&r->h->selection_time,
5980 sizeof(Time) > 4 ? sizeof(Time)/4 : 1);
5981 ev.property = rq->property;
5982 }
5983 else if (
5984 rq->target == XA_STRING
5985 || rq->target == r->h->xa[XA_COMPOUND_TEXT]
5986 || rq->target == r->h->xa[XA_TEXT]
5987 )
5988 {
5989 #ifdef USE_XIM
5990 short freect = 0;
5991 #endif
5992 int selectlen;
5993
5994 #ifdef USE_XIM
5995 if (rq->target != XA_STRING)
5996 {
5997 target = r->h->xa[XA_COMPOUND_TEXT];
5998 style = (rq->target == r->h->xa[XA_COMPOUND_TEXT])
5999 ? XCompoundTextStyle : XStdICCTextStyle;
6000 } else
6001 #endif
6002 {
6003 target = XA_STRING;
6004 style = XStringStyle;
6005 }
6006 if (SEL(r).text)
6007 {
6008 cl[0] = (char *)SEL(r).text;
6009 selectlen = SEL(r).len;
6010 }
6011 else
6012 {
6013 cl[0] = dummy;
6014 *dummy = '\0';
6015 selectlen = 0;
6016 }
6017 #ifdef USE_XIM
6018 if (XmbTextListToTextProperty(r->Xdisplay, cl, 1, style, &ct) == Success) /* if we failed to convert then send it raw */
6019 freect = 1;
6020 else
6021 #endif
6022 {
6023 ct.value = (unsigned char *)cl[0];
6024 ct.nitems = selectlen;
6025 }
6026 XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
6027 target, 8, PropModeReplace,
6028 ct.value, (int)ct.nitems);
6029 ev.property = rq->property;
6030 #ifdef USE_XIM
6031 if (freect)
6032 XFree(ct.value);
6033 #endif
6034 }
6035 XSendEvent(r->Xdisplay, rq->requestor, False, 0L, (XEvent *)&ev);
6036 }
6037
6038 /* ------------------------------------------------------------------------- *
6039 * MOUSE ROUTINES *
6040 * ------------------------------------------------------------------------- */
6041
6042 /*
6043 * return col/row values corresponding to x/y pixel values
6044 */
6045 /* EXTPROTO */
6046 void
6047 rxvt_pixel_position(rxvt_t* r, int *x, int *y)
6048 {
6049 *x = Pixel2Col(*x);
6050 /* MAX_IT(*x, 0); MIN_IT(*x, (int)r->TermWin.ncol - 1); */
6051 *y = Pixel2Row(*y);
6052 /* MAX_IT(*y, 0); MIN_IT(*y, (int)r->TermWin.nrow - 1); */
6053 }
6054
6055 /*----------------------- end-of-file (C source) -----------------------*/
6056