1 #include "rxvtlib.h"
2
3 /*--------------------------------*-C-*--------------------------------------*
4 * File: screen.c
5 *---------------------------------------------------------------------------*
6 * $Id: screen.c,v 1.76.2.9 1999/07/07 13:22:22 mason Exp $
7 *
8 * Copyright (C) 1997,1998 Geoff Wing <gcw@pobox.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *--------------------------------------------------------------------------*/
24 /*
25 * We handle _all_ screen updates and selections
26 */
27
28 /* ------------------------------------------------------------------------- */
29
30 #ifdef MULTICHAR_SET
31 /* set ==> currently using 2 bytes per glyph */
32 /* set ==> we only got half a glyph */
33
34 #else
35 #endif
36
37 /* KANJI methods *//* BIG5 methods: CNS not implemented *//* GB method */
38
39 /* ------------------------------------------------------------------------- */
40
41 /* ------------------------------------------------------------------------- *
42 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
43 * ------------------------------------------------------------------------- */
44
45 /* these must be row_col_t */
46
47 /*
48 * CLEAR_ROWS : clear <num> rows starting from row <row>
49 * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
50 * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour
51 */
52
53 /* ------------------------------------------------------------------------- *
54 * SCREEN `COMMON' ROUTINES *
55 * ------------------------------------------------------------------------- */
56 /* Fill part/all of a line with blanks. */
57 /* INTPROTO */
blank_line(text_t * et,rend_t * er,int width,rend_t efs)58 void blank_line (text_t * et, rend_t * er, int width, rend_t efs)
59 {
60 MEMSET (et, ' ', width);
61 for (; width--;)
62 *er++ = efs;
63 }
64
65 /* ------------------------------------------------------------------------- */
66 /* Fill a full line with blanks - make sure it is allocated first */
67 /* INTPROTO */
rxvtlib_blank_screen_mem(rxvtlib * o,text_t ** tp,rend_t ** rp,int row,rend_t efs)68 void rxvtlib_blank_screen_mem (rxvtlib *o, text_t ** tp, rend_t ** rp, int row,
69 rend_t efs)
70 {
71 int width = o->TermWin.ncol;
72 rend_t *er;
73
74 if (tp[row] == NULL) {
75 tp[row] = MALLOC (sizeof (text_t) * o->TermWin.ncol);
76 rp[row] = MALLOC (sizeof (rend_t) * o->TermWin.ncol);
77 }
78 MEMSET (tp[row], ' ', width);
79 for (er = rp[row]; width--;)
80 *er++ = efs;
81 }
82
83 /* ------------------------------------------------------------------------- *
84 * SCREEN INITIALISATION *
85 * ------------------------------------------------------------------------- */
86
87 /* EXTPROTO */
rxvtlib_scr_reset(rxvtlib * o)88 void rxvtlib_scr_reset (rxvtlib *o)
89 {
90 int i, j, k, total_rows, prev_total_rows;
91 rend_t setrstyle;
92
93 D_SCREEN ((stderr, "scr_reset()"));
94
95 o->TermWin.view_start = 0;
96 RESET_CHSTAT;
97
98 if (o->TermWin.ncol == o->prev_ncol && o->TermWin.nrow == o->prev_nrow)
99 return;
100
101 o->want_refresh = 1;
102
103 if (o->TermWin.ncol <= 0)
104 o->TermWin.ncol = 80;
105 if (o->TermWin.nrow <= 0)
106 o->TermWin.nrow = 24;
107 #ifdef DEBUG_STRICT
108 assert (o->TermWin.saveLines >= 0);
109 #else /* drive with your eyes closed */
110 MAX_IT (o->TermWin.saveLines, 0);
111 #endif
112
113 total_rows = o->TermWin.nrow + o->TermWin.saveLines;
114 prev_total_rows = o->prev_nrow + o->TermWin.saveLines;
115
116 o->screen.tscroll = 0;
117 o->screen.bscroll = (o->TermWin.nrow - 1);
118
119 if (o->prev_nrow == -1) {
120 /*
121 * A: first time called so just malloc everything : don't rely on realloc
122 * Note: this is still needed so that all the scrollback lines are NULL
123 */
124 o->screen.text = CALLOC (text_t *, total_rows);
125 o->buf_text = CALLOC (text_t *, total_rows);
126 o->drawn_text = CALLOC (text_t *, o->TermWin.nrow);
127 o->swap.text = CALLOC (text_t *, o->TermWin.nrow);
128
129 o->screen.tlen = CALLOC (short, total_rows);
130 o->buf_tlen = CALLOC (short, total_rows);
131 o->swap.tlen = CALLOC (short, o->TermWin.nrow);
132
133 o->screen.rend = CALLOC (rend_t *, total_rows);
134 o->buf_rend = CALLOC (rend_t *, total_rows);
135 o->drawn_rend = CALLOC (rend_t *, o->TermWin.nrow);
136 o->swap.rend = CALLOC (rend_t *, o->TermWin.nrow);
137
138 for (i = 0; i < o->TermWin.nrow; i++) {
139 j = i + o->TermWin.saveLines;
140 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, j, DEFAULT_RSTYLE);
141 rxvtlib_blank_screen_mem (o, o->swap.text, o->swap.rend, i, DEFAULT_RSTYLE);
142 o->screen.tlen[j] = o->swap.tlen[i] = 0;
143 rxvtlib_blank_screen_mem (o, o->drawn_text, o->drawn_rend, i, DEFAULT_RSTYLE);
144 }
145 o->TermWin.nscrolled = 0; /* no saved lines */
146 o->screen.flags = o->swap.flags = Screen_DefaultFlags;
147 o->save.cur.row = o->save.cur.col = 0;
148 o->save.charset = 0;
149 o->save.charset_char = 'B';
150 o->rstyle = o->save.rstyle = DEFAULT_RSTYLE;
151 o->selection.text = NULL;
152 o->selection.len = 0;
153 o->selection.op = SELECTION_CLEAR;
154 o->selection.screen = PRIMARY;
155 o->selection.clicks = 0;
156 CLEAR_ALL_SELECTION;
157 MEMSET (o->charsets, 'B', sizeof (o->charsets));
158 o->current_screen = PRIMARY;
159 o->rvideo = 0;
160 #ifdef MULTICHAR_SET
161 o->multi_byte = 0;
162 o->lost_multi = 0;
163 o->chstat = SBYTE;
164 # ifdef ZH
165 o->encoding_method = BIG5;
166 # else
167 # ifdef ZHCN
168 o->encoding_method = GB;
169 # endif
170 # endif
171 #endif
172
173 } else {
174 /*
175 * B1: add or delete rows as appropriate
176 */
177 setrstyle = DEFAULT_RSTYLE | (o->rvideo ? RS_RVid : 0);
178
179 if (o->TermWin.nrow < o->prev_nrow) {
180 /* delete rows */
181 k = min (o->TermWin.nscrolled, o->prev_nrow - o->TermWin.nrow);
182 rxvtlib_scroll_text (o, 0, o->prev_nrow - 1, k, 1);
183 for (i = o->TermWin.nrow; i < o->prev_nrow; i++) {
184 j = i + o->TermWin.saveLines;
185 if (o->screen.text[j])
186 FREE (o->screen.text[j]);
187 if (o->screen.rend[j])
188 FREE (o->screen.rend[j]);
189 if (o->swap.text[i])
190 FREE (o->swap.text[i]);
191 if (o->swap.rend[i])
192 FREE (o->swap.rend[i]);
193 FREE (o->drawn_text[i]);
194 FREE (o->drawn_rend[i]);
195 }
196 /* we have fewer rows so fix up cursor position */
197 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
198 MIN_IT (o->swap.cur.row, o->TermWin.nrow - 1);
199
200 rxvtlib_scr_reset_realloc (o); /* REALLOC _last_ */
201
202 } else if (o->TermWin.nrow > o->prev_nrow) {
203 /* add rows */
204 rxvtlib_scr_reset_realloc (o); /* REALLOC _first_ */
205
206 k = min (o->TermWin.nscrolled, o->TermWin.nrow - o->prev_nrow);
207 for (i = prev_total_rows; i < total_rows - k; i++) {
208 o->screen.tlen[i] = 0;
209 o->screen.text[i] = NULL;
210 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, i, setrstyle);
211 }
212 for (i = total_rows - k; i < total_rows; i++) {
213 o->screen.tlen[i] = 0;
214 o->screen.text[i] = NULL;
215 o->screen.rend[i] = NULL;
216 }
217 for (i = o->prev_nrow; i < o->TermWin.nrow; i++) {
218 o->swap.tlen[i] = 0;
219 o->swap.text[i] = NULL;
220 o->drawn_text[i] = NULL;
221 rxvtlib_blank_screen_mem (o, o->swap.text, o->swap.rend, i, setrstyle);
222 rxvtlib_blank_screen_mem (o, o->drawn_text, o->drawn_rend, i, setrstyle);
223 }
224 if (k > 0) {
225 rxvtlib_scroll_text (o, 0, o->TermWin.nrow - 1, -k, 1);
226 o->screen.cur.row += k;
227 o->TermWin.nscrolled -= k;
228 for (i = o->TermWin.saveLines - o->TermWin.nscrolled; k--; i--)
229 if (o->screen.text[i] == NULL) {
230 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, i,
231 setrstyle);
232 o->screen.tlen[i] = 0;
233 }
234 }
235 #ifdef DEBUG_STRICT
236 assert (o->screen.cur.row < o->TermWin.nrow);
237 assert (o->swap.cur.row < o->TermWin.nrow);
238 #else /* drive with your eyes closed */
239 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
240 MIN_IT (o->swap.cur.row, o->TermWin.nrow - 1);
241 #endif
242 }
243 /* B2: resize columns */
244 if (o->TermWin.ncol != o->prev_ncol) {
245 for (i = 0; i < total_rows; i++) {
246 if (o->screen.text[i]) {
247 o->screen.text[i] = REALLOC (o->screen.text[i],
248 o->TermWin.ncol * sizeof (text_t));
249 o->screen.rend[i] = REALLOC (o->screen.rend[i],
250 o->TermWin.ncol * sizeof (rend_t));
251 MIN_IT (o->screen.tlen[i], o->TermWin.ncol);
252 if (o->TermWin.ncol > o->prev_ncol)
253 blank_line (&(o->screen.text[i][o->prev_ncol]),
254 &(o->screen.rend[i][o->prev_ncol]),
255 o->TermWin.ncol - o->prev_ncol, setrstyle);
256 }
257 }
258 for (i = 0; i < o->TermWin.nrow; i++) {
259 o->drawn_text[i] = REALLOC (o->drawn_text[i],
260 o->TermWin.ncol * sizeof (text_t));
261 o->drawn_rend[i] = REALLOC (o->drawn_rend[i],
262 o->TermWin.ncol * sizeof (rend_t));
263 if (o->swap.text[i]) {
264 o->swap.text[i] = REALLOC (o->swap.text[i],
265 o->TermWin.ncol * sizeof (text_t));
266 o->swap.rend[i] = REALLOC (o->swap.rend[i],
267 o->TermWin.ncol * sizeof (rend_t));
268 MIN_IT (o->swap.tlen[i], o->TermWin.ncol);
269 if (o->TermWin.ncol > o->prev_ncol)
270 blank_line (&(o->swap.text[i][o->prev_ncol]),
271 &(o->swap.rend[i][o->prev_ncol]),
272 o->TermWin.ncol - o->prev_ncol, setrstyle);
273 }
274 if (o->TermWin.ncol > o->prev_ncol)
275 blank_line (&(o->drawn_text[i][o->prev_ncol]),
276 &(o->drawn_rend[i][o->prev_ncol]),
277 o->TermWin.ncol - o->prev_ncol, setrstyle);
278 }
279 MIN_IT (o->screen.cur.col, o->TermWin.ncol - 1);
280 MIN_IT (o->swap.cur.col, o->TermWin.ncol - 1);
281 }
282 if (o->tabs)
283 FREE (o->tabs);
284 }
285
286 o->tabs = MALLOC (o->TermWin.ncol * sizeof (char));
287
288 for (i = 0; i < o->TermWin.ncol; i++)
289 o->tabs[i] = (i % TABSIZE == 0) ? 1 : 0;
290
291 o->prev_nrow = o->TermWin.nrow;
292 o->prev_ncol = o->TermWin.ncol;
293
294 rxvtlib_tt_resize (o);
295 }
296
297 /* INTPROTO */
rxvtlib_scr_reset_realloc(rxvtlib * o)298 void rxvtlib_scr_reset_realloc (rxvtlib *o)
299 {
300 int total_rows;
301
302 total_rows = o->TermWin.nrow + o->TermWin.saveLines;
303 /* *INDENT-OFF* */
304 o->screen.text = REALLOC(o->screen.text, total_rows * sizeof(text_t *));
305 o->buf_text = REALLOC(o->buf_text , total_rows * sizeof(text_t *));
306 o->drawn_text = REALLOC(o->drawn_text , o->TermWin.nrow * sizeof(text_t *));
307 o->swap.text = REALLOC(o->swap.text , o->TermWin.nrow * sizeof(text_t *));
308
309 o->screen.tlen = REALLOC(o->screen.tlen, total_rows * sizeof(short));
310 o->buf_tlen = REALLOC(o->buf_tlen , total_rows * sizeof(short));
311 o->swap.tlen = REALLOC(o->swap.tlen , total_rows * sizeof(short));
312
313 o->screen.rend = REALLOC(o->screen.rend, total_rows * sizeof(rend_t *));
314 o->buf_rend = REALLOC(o->buf_rend , total_rows * sizeof(rend_t *));
315 o->drawn_rend = REALLOC(o->drawn_rend , o->TermWin.nrow * sizeof(rend_t *));
316 o->swap.rend = REALLOC(o->swap.rend , o->TermWin.nrow * sizeof(rend_t *));
317 /* *INDENT-ON* */
318 }
319
320 /* ------------------------------------------------------------------------- */
321 /*
322 * Free everything. That way malloc debugging can find leakage.
323 */
324 /* EXTPROTO */
rxvtlib_scr_release(rxvtlib * o)325 void rxvtlib_scr_release (rxvtlib *o)
326 {
327 int i, total_rows;
328
329 total_rows = o->TermWin.nrow + o->TermWin.saveLines;
330 for (i = 0; i < total_rows; i++) {
331 if (o->screen.text[i]) { /* then so is screen.rend[i] */
332 FREE (o->screen.text[i]);
333 FREE (o->screen.rend[i]);
334 }
335 }
336 for (i = 0; i < o->TermWin.nrow; i++) {
337 FREE (o->drawn_text[i]);
338 FREE (o->drawn_rend[i]);
339 FREE (o->swap.text[i]);
340 FREE (o->swap.rend[i]);
341 }
342 FREE (o->screen.text);
343 FREE (o->screen.tlen);
344 FREE (o->screen.rend);
345 FREE (o->drawn_text);
346 FREE (o->drawn_rend);
347 FREE (o->swap.text);
348 FREE (o->swap.tlen);
349 FREE (o->swap.rend);
350 FREE (o->buf_text);
351 FREE (o->buf_tlen);
352 FREE (o->buf_rend);
353 FREE (o->tabs);
354
355 /* NULL these so if anything tries to use them, we'll know about it */
356 o->screen.text = o->drawn_text = o->swap.text = NULL;
357 o->screen.rend = o->drawn_rend = o->swap.rend = NULL;
358 o->screen.tlen = o->swap.tlen = o->buf_tlen = NULL;
359 o->buf_text = NULL;
360 o->buf_rend = NULL;
361 o->tabs = NULL;
362 }
363
364 /* ------------------------------------------------------------------------- */
365 /* EXTPROTO */
rxvtlib_scr_poweron(rxvtlib * o)366 void rxvtlib_scr_poweron (rxvtlib *o)
367 {
368 D_SCREEN ((stderr, "scr_poweron()"));
369
370 MEMSET (o->charsets, 'B', sizeof (o->charsets));
371 o->rvideo = 0;
372 o->swap.tscroll = 0;
373 o->swap.bscroll = o->TermWin.nrow - 1;
374 o->screen.cur.row = o->screen.cur.col = o->swap.cur.row = o->swap.cur.col = 0;
375 o->screen.charset = o->swap.charset = 0;
376 o->screen.flags = o->swap.flags = Screen_DefaultFlags;
377
378 rxvtlib_scr_cursor (o, SAVE);
379
380 rxvtlib_scr_release (o);
381 o->prev_nrow = -1;
382 o->prev_ncol = -1;
383 rxvtlib_scr_reset (o);
384
385 rxvtlib_scr_clear (o);
386 rxvtlib_scr_refresh (o, SLOW_REFRESH);
387 rxvtlib_Gr_reset (o);
388 }
389
390 /* ------------------------------------------------------------------------- *
391 * PROCESS SCREEN COMMANDS *
392 * ------------------------------------------------------------------------- */
393 /*
394 * Save and Restore cursor
395 * XTERM_SEQ: Save cursor : ESC 7
396 * XTERM_SEQ: Restore cursor: ESC 8
397 */
398 /* EXTPROTO */
rxvtlib_scr_cursor(rxvtlib * o,int mode)399 void rxvtlib_scr_cursor (rxvtlib *o, int mode)
400 {
401 D_SCREEN ((stderr, "scr_cursor(%c)", mode));
402
403 switch (mode) {
404 case SAVE:
405 o->save.cur.row = o->screen.cur.row;
406 o->save.cur.col = o->screen.cur.col;
407 o->save.rstyle = o->rstyle;
408 o->save.charset = o->screen.charset;
409 o->save.charset_char = o->charsets[o->screen.charset];
410 break;
411 case RESTORE:
412 o->want_refresh = 1;
413 o->screen.cur.row = o->save.cur.row;
414 o->screen.cur.col = o->save.cur.col;
415 o->rstyle = o->save.rstyle;
416 o->screen.charset = o->save.charset;
417 o->charsets[o->screen.charset] = o->save.charset_char;
418 rxvtlib_set_font_style (o);
419 break;
420 }
421 /* boundary check in case screen size changed between SAVE and RESTORE */
422 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
423 MIN_IT (o->screen.cur.col, o->TermWin.ncol - 1);
424 #ifdef DEBUG_STRICT
425 assert (o->screen.cur.row >= 0);
426 assert (o->screen.cur.col >= 0);
427 #else /* drive with your eyes closed */
428 MAX_IT (o->screen.cur.row, 0);
429 MAX_IT (o->screen.cur.col, 0);
430 #endif
431 }
432
433 /* ------------------------------------------------------------------------- */
434 /*
435 * Swap between primary and secondary screens
436 * XTERM_SEQ: Primary screen : ESC [ ? 4 7 h
437 * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
438 */
439 /* EXTPROTO */
rxvtlib_scr_change_screen(rxvtlib * o,int scrn)440 int rxvtlib_scr_change_screen (rxvtlib *o, int scrn)
441 {
442 int i, tmp;
443
444 #if NSCREENS
445 int offset;
446 text_t *t0;
447 rend_t *r0;
448 short l0;
449 #endif
450
451 o->want_refresh = 1;
452
453 D_SCREEN ((stderr, "scr_change_screen(%d)", scrn));
454
455 o->TermWin.view_start = 0;
456 RESET_CHSTAT;
457
458 if (o->current_screen == scrn)
459 return o->current_screen;
460
461 CHECK_SELECTION (2); /* check for boundary cross */
462
463 SWAP_IT (o->current_screen, scrn, tmp);
464 #if NSCREENS
465 offset = o->TermWin.saveLines;
466 for (i = o->TermWin.nrow; i--;) {
467 SWAP_IT (o->screen.text[i + offset], o->swap.text[i], t0);
468 SWAP_IT (o->screen.tlen[i + offset], o->swap.tlen[i], l0);
469 SWAP_IT (o->screen.rend[i + offset], o->swap.rend[i], r0);
470 }
471 SWAP_IT (o->screen.cur.row, o->swap.cur.row, l0);
472 SWAP_IT (o->screen.cur.col, o->swap.cur.col, l0);
473 # ifdef DEBUG_STRICT
474 assert (o->screen.cur.row >= 0);
475 assert (o->screen.cur.col >= 0);
476 assert (o->screen.cur.row < o->TermWin.nrow);
477 assert (o->screen.cur.col < o->TermWin.ncol);
478 # else /* drive with your eyes closed */
479 MAX_IT (o->screen.cur.row, 0);
480 MAX_IT (o->screen.cur.col, 0);
481 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
482 MIN_IT (o->screen.cur.col, o->TermWin.ncol - 1);
483 # endif
484 SWAP_IT (o->screen.charset, o->swap.charset, l0);
485 SWAP_IT (o->screen.flags, o->swap.flags, tmp);
486 o->screen.flags |= Screen_VisibleCursor;
487 o->swap.flags |= Screen_VisibleCursor;
488
489 if (rxvtlib_Gr_Displayed (o)) {
490 rxvtlib_Gr_scroll (o, 0);
491 rxvtlib_Gr_ChangeScreen (o);
492 }
493 #else
494 # ifdef SCROLL_ON_NO_SECONDARY
495 if (rxvtlib_Gr_Displayed (o))
496 rxvtlib_Gr_ClearScreen (o);
497 if (o->current_screen == PRIMARY) {
498 if (!rxvtlib_Gr_Displayed (o))
499 rxvtlib_scroll_text (o, 0, (o->TermWin.nrow - 1), o->TermWin.nrow, 0);
500 for (i = o->TermWin.saveLines; i < o->TermWin.nrow + o->TermWin.saveLines; i++)
501 if (o->screen.text[i] == NULL) {
502 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, i, DEFAULT_RSTYLE);
503 o->screen.tlen[i] = 0;
504 }
505 }
506 # endif
507 #endif
508 return scrn;
509 }
510
511 /* ------------------------------------------------------------------------- */
512 /*
513 * Change the colour for following text
514 */
515 /* EXTPROTO */
rxvtlib_scr_color(rxvtlib * o,unsigned int color,unsigned int Intensity)516 void rxvtlib_scr_color (rxvtlib *o, unsigned int color, unsigned int Intensity)
517 {
518 if (color == restoreFG)
519 color = Color_fg;
520 else if (color == restoreBG)
521 color = Color_bg;
522 else {
523 if (o->Xdepth <= 2) { /* Monochrome - ignore colour changes */
524 switch (Intensity) {
525 case RS_Bold:
526 color = Color_fg;
527 break;
528 case RS_Blink:
529 color = Color_bg;
530 break;
531 }
532 } else {
533 #ifndef NO_BRIGHTCOLOR
534 if ((o->rstyle & Intensity) && color >= minCOLOR && color <= maxCOLOR)
535 color += (minBrightCOLOR - minCOLOR);
536 else if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
537 if (o->rstyle & Intensity)
538 return;
539 color -= (minBrightCOLOR - minCOLOR);
540 }
541 #endif
542 }
543 }
544 switch (Intensity) {
545 case RS_Bold:
546 o->rstyle = SET_FGCOLOR (o->rstyle, color);
547 break;
548 case RS_Blink:
549 o->rstyle = SET_BGCOLOR (o->rstyle, color);
550 break;
551 }
552 }
553
554 /* ------------------------------------------------------------------------- */
555 /*
556 * Change the rendition style for following text
557 */
558 /* EXTPROTO */
rxvtlib_scr_rendition(rxvtlib * o,int set,int style)559 void rxvtlib_scr_rendition (rxvtlib *o, int set, int style)
560 {
561 unsigned int color;
562 rend_t font_attr;
563
564 if (set) {
565 /* A: Set style */
566 o->rstyle |= style;
567 switch (style) {
568 case RS_RVid:
569 if (o->rvideo)
570 o->rstyle &= ~RS_RVid;
571 break;
572 #ifndef NO_BRIGHTCOLOR
573 case RS_Bold:
574 color = GET_FGCOLOR (o->rstyle);
575 rxvtlib_scr_color (o, (color == Color_fg ? GET_FGCOLOR (o->colorfgbg) : color),
576 RS_Bold);
577 break;
578 case RS_Blink:
579 color = GET_BGCOLOR (o->rstyle);
580 rxvtlib_scr_color (o, (color == Color_bg ? GET_BGCOLOR (o->colorfgbg) : color),
581 RS_Blink);
582 break;
583 #endif
584 }
585 } else {
586 /* B: Unset style */
587 font_attr = o->rstyle & RS_fontMask;
588 o->rstyle &= ~style;
589
590 switch (style) {
591 case ~RS_None: /* default fg/bg colours */
592 o->rstyle = DEFAULT_RSTYLE | font_attr;
593 /* FALLTHROUGH */
594 case RS_RVid:
595 if (o->rvideo)
596 o->rstyle |= RS_RVid;
597 break;
598 #ifndef NO_BRIGHTCOLOR
599 case RS_Bold:
600 color = GET_FGCOLOR (o->rstyle);
601 if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
602 rxvtlib_scr_color (o, color, RS_Bold);
603 if ((o->rstyle & RS_fgMask) == (o->colorfgbg & RS_fgMask))
604 rxvtlib_scr_color (o, restoreFG, RS_Bold);
605 }
606 break;
607 case RS_Blink:
608 color = GET_BGCOLOR (o->rstyle);
609 if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
610 rxvtlib_scr_color (o, color, RS_Blink);
611 if ((o->rstyle & RS_bgMask) == (o->colorfgbg & RS_bgMask))
612 rxvtlib_scr_color (o, restoreBG, RS_Blink);
613 }
614 break;
615 #endif
616 }
617 }
618 }
619
620 /* ------------------------------------------------------------------------- */
621 /*
622 * Scroll text between <row1> and <row2> inclusive, by <count> lines
623 * count positive ==> scroll up
624 * count negative ==> scroll down
625 * spec == 0 for normal routines
626 */
627 /* INTPROTO */
rxvtlib_scroll_text(rxvtlib * o,int row1,int row2,int count,int spec)628 int rxvtlib_scroll_text (rxvtlib *o, int row1, int row2, int count, int spec)
629 {
630 int i, j;
631
632 o->want_refresh = 1;
633 D_SCREEN (
634 (stderr, "scroll_text(%d,%d,%d,%d): %s", row1, row2, count, spec,
635 (o->current_screen == PRIMARY) ? "Primary" : "Secondary"));
636
637 if (count == 0 || (row1 > row2))
638 return 0;
639
640 if ((count > 0) && (row1 == 0) && (o->current_screen == PRIMARY)) {
641 o->TermWin.nscrolled += count;
642 MIN_IT (o->TermWin.nscrolled, o->TermWin.saveLines);
643 } else if (!spec)
644 row1 += o->TermWin.saveLines;
645 row2 += o->TermWin.saveLines;
646
647 if (o->selection.op && o->current_screen == o->selection.screen) {
648 i = o->selection.beg.row + o->TermWin.saveLines;
649 j = o->selection.end.row + o->TermWin.saveLines;
650 if ((i < row1 && j > row1)
651 || (i < row2 && j > row2)
652 || (i - count < row1 && i >= row1)
653 || (i - count > row2 && i <= row2)
654 || (j - count < row1 && j >= row1)
655 || (j - count > row2 && j <= row2)) {
656 CLEAR_ALL_SELECTION;
657 o->selection.op = SELECTION_CLEAR; /* XXX: too aggressive? */
658 } else if (j >= row1 && j <= row2) {
659 /* move selected region too */
660 o->selection.beg.row -= count;
661 o->selection.end.row -= count;
662 o->selection.mark.row -= count;
663 }
664 }
665 CHECK_SELECTION (0); /* _after_ TermWin.nscrolled update */
666
667 if (count > 0) {
668 /* A: scroll up */
669
670 MIN_IT (count, row2 - row1 + 1);
671 /* A1: Copy lines that will get clobbered by the rotation */
672 for (i = 0, j = row1; i < count; i++, j++) {
673 o->buf_text[i] = o->screen.text[j];
674 o->buf_tlen[i] = o->screen.tlen[j];
675 o->buf_rend[i] = o->screen.rend[j];
676 }
677 /* A2: Rotate lines */
678 for (j = row1; (j + count) <= row2; j++) {
679 o->screen.text[j] = o->screen.text[j + count];
680 o->screen.tlen[j] = o->screen.tlen[j + count];
681 o->screen.rend[j] = o->screen.rend[j + count];
682 }
683 /* A3: Resurrect lines */
684 for (i = 0; i < count; i++, j++) {
685 o->screen.text[j] = o->buf_text[i];
686 o->screen.tlen[j] = o->buf_tlen[i];
687 o->screen.rend[j] = o->buf_rend[i];
688 }
689 } else if (count < 0) {
690 /* B: scroll down */
691
692 count = min (-count, row2 - row1 + 1);
693 /* B1: Copy lines that will get clobbered by the rotation */
694 for (i = 0, j = row2; i < count; i++, j--) {
695 o->buf_text[i] = o->screen.text[j];
696 o->buf_tlen[i] = o->screen.tlen[j];
697 o->buf_rend[i] = o->screen.rend[j];
698 }
699 /* B2: Rotate lines */
700 for (j = row2; (j - count) >= row1; j--) {
701 o->screen.text[j] = o->screen.text[j - count];
702 o->screen.tlen[j] = o->screen.tlen[j - count];
703 o->screen.rend[j] = o->screen.rend[j - count];
704 }
705 /* B3: Resurrect lines */
706 for (i = 0, j = row1; i < count; i++, j++) {
707 o->screen.text[j] = o->buf_text[i];
708 o->screen.tlen[j] = o->buf_tlen[i];
709 o->screen.rend[j] = o->buf_rend[i];
710 }
711 count = -count;
712 }
713 if (rxvtlib_Gr_Displayed (o))
714 rxvtlib_Gr_scroll (o, count);
715 return count;
716 }
717
718 /* ------------------------------------------------------------------------- */
719 /*
720 * A safe scroll text routine
721 */
722 /* EXTPROTO */
rxvtlib_scr_scroll_text(rxvtlib * o,int count)723 void rxvtlib_scr_scroll_text (rxvtlib *o, int count)
724 {
725 int row, erow;
726
727 if (count == 0)
728 return;
729 count = rxvtlib_scroll_text (o, o->screen.tscroll, o->screen.bscroll, count, 0);
730 /* XXX: Ummm, no? care needed with [bt]scroll, yes? */
731 if (count > 0) {
732 row = o->TermWin.nrow - count + o->TermWin.saveLines;
733 erow = o->TermWin.nrow + o->TermWin.saveLines;
734 } else {
735 row = o->TermWin.saveLines;
736 erow = o->TermWin.saveLines - count;
737 }
738 for (; row < erow; row++)
739 if (o->screen.text[row] == NULL)
740 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, row, o->rstyle);
741 }
742
743 /* ------------------------------------------------------------------------- */
744 /*
745 * Add text given in <str> of length <len> to screen struct
746 */
747 /* EXTPROTO */
rxvtlib_scr_add_lines(rxvtlib * o,const unsigned char * str,int nlines,int len)748 void rxvtlib_scr_add_lines (rxvtlib *o, const unsigned char *str, int nlines, int len)
749 {
750 char c;
751 int i, j, row, last_col, checksel, clearsel;
752 text_t *stp;
753 rend_t *srp;
754
755 if (len <= 0) /* sanity */
756 return;
757
758 o->want_refresh = 1;
759 last_col = o->TermWin.ncol;
760
761 D_SCREEN ((stderr, "scr_add_lines(*,%d,%d)", nlines, len));
762 ZERO_SCROLLBACK;
763 if (nlines > 0) {
764 nlines += (o->screen.cur.row - o->screen.bscroll);
765 if ((nlines > 0)
766 && (o->screen.tscroll == 0)
767 && (o->screen.bscroll == (o->TermWin.nrow - 1))) {
768 /* _at least_ this many lines need to be scrolled */
769 rxvtlib_scroll_text (o, o->screen.tscroll, o->screen.bscroll, nlines, 0);
770 for (i = nlines, j = o->screen.bscroll + o->TermWin.saveLines; i--; j--) {
771 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, j, o->rstyle);
772 o->screen.tlen[j] = 0;
773 }
774 o->screen.cur.row -= nlines;
775 }
776 }
777 #ifdef DEBUG_STRICT
778 assert (o->screen.cur.col < last_col);
779 assert (o->screen.cur.row < o->TermWin.nrow);
780 assert (o->screen.cur.row >= -o->TermWin.nscrolled);
781 #else /* drive with your eyes closed */
782 MIN_IT (o->screen.cur.col, last_col - 1);
783 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
784 MAX_IT (o->screen.cur.row, -o->TermWin.nscrolled);
785 #endif
786 row = o->screen.cur.row + o->TermWin.saveLines;
787
788 checksel = (o->selection.op && o->current_screen == o->selection.screen) ? 1 : 0;
789 clearsel = 0;
790
791 stp = o->screen.text[row];
792 srp = o->screen.rend[row];
793
794 #ifdef MULTICHAR_SET
795 if (o->lost_multi && o->screen.cur.col > 0
796 && ((srp[o->screen.cur.col - 1] & RS_multiMask) == RS_multi1)
797 && *str != '\n' && *str != '\r' && *str != '\t')
798 o->chstat = WBYTE;
799 #endif
800
801 for (i = 0; i < len;) {
802 c = str[i++];
803 switch (c) {
804 case '\t':
805 rxvtlib_scr_tab (o, 1);
806 continue;
807 case '\n':
808 if (o->screen.tlen[row] != -1) /* XXX: think about this */
809 MAX_IT (o->screen.tlen[row], o->screen.cur.col);
810 o->screen.flags &= ~Screen_WrapNext;
811 if (o->screen.cur.row == o->screen.bscroll) {
812 rxvtlib_scroll_text (o, o->screen.tscroll, o->screen.bscroll, 1, 0);
813 j = o->screen.bscroll + o->TermWin.saveLines;
814 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, j, o->rstyle);
815 o->screen.tlen[j] = 0;
816 } else if (o->screen.cur.row < (o->TermWin.nrow - 1))
817 row = (++o->screen.cur.row) + o->TermWin.saveLines;
818 stp = o->screen.text[row]; /* _must_ refresh */
819 srp = o->screen.rend[row]; /* _must_ refresh */
820 RESET_CHSTAT;
821 continue;
822 case '\r':
823 if (o->screen.tlen[row] != -1) /* XXX: think about this */
824 MAX_IT (o->screen.tlen[row], o->screen.cur.col);
825 o->screen.flags &= ~Screen_WrapNext;
826 o->screen.cur.col = 0;
827 RESET_CHSTAT;
828 continue;
829 default:
830 #ifdef MULTICHAR_SET
831 o->rstyle &= ~RS_multiMask;
832 if (o->chstat == WBYTE) {
833 o->rstyle |= RS_multi2; /* multibyte 2nd byte */
834 o->chstat = SBYTE;
835 if ((o->encoding_method == EUCJ) || (o->encoding_method == GB))
836 c |= 0x80; /* maybe overkill, but makes it selectable */
837 } else if (o->chstat == SBYTE) {
838 if (o->multi_byte || (c & 0x80)) { /* multibyte 1st byte */
839 o->rstyle |= RS_multi1;
840 o->chstat = WBYTE;
841 if ((o->encoding_method == EUCJ) || (o->encoding_method == GB))
842 c |= 0x80; /* maybe overkill, but makes selectable */
843 }
844 } else
845 #endif
846 if (c == 127)
847 continue; /* yummmm..... */
848 break;
849 }
850
851 if (checksel && !ROWCOL_IS_BEFORE (o->screen.cur, o->selection.beg)
852 && ROWCOL_IS_BEFORE (o->screen.cur, o->selection.end)) {
853 checksel = 0;
854 clearsel = 1;
855 }
856 if (o->screen.flags & Screen_WrapNext) {
857 o->screen.tlen[row] = -1;
858 if (o->screen.cur.row == o->screen.bscroll) {
859 rxvtlib_scroll_text (o, o->screen.tscroll, o->screen.bscroll, 1, 0);
860 j = o->screen.bscroll + o->TermWin.saveLines;
861 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, j, o->rstyle);
862 o->screen.tlen[j] = 0;
863 } else if (o->screen.cur.row < (o->TermWin.nrow - 1))
864 row = (++o->screen.cur.row) + o->TermWin.saveLines;
865 stp = o->screen.text[row]; /* _must_ refresh */
866 srp = o->screen.rend[row]; /* _must_ refresh */
867 o->screen.cur.col = 0;
868 o->screen.flags &= ~Screen_WrapNext;
869 }
870 if (o->screen.flags & Screen_Insert)
871 rxvtlib_scr_insdel_chars (o, 1, INSERT);
872 #ifdef MULTICHAR_SET
873 if ((o->rstyle & RS_multiMask) == RS_multi1
874 && o->screen.cur.col > 0
875 && (srp[o->screen.cur.col - 1] & RS_multiMask) == RS_multi1) {
876 stp[o->screen.cur.col - 1] = ' ';
877 srp[o->screen.cur.col - 1] &= ~RS_multiMask;
878 } else if ((o->rstyle & RS_multiMask) == RS_multi2
879 && o->screen.cur.col < (last_col - 1)
880 && (srp[o->screen.cur.col + 1] & RS_multiMask) == RS_multi2) {
881 stp[o->screen.cur.col + 1] = ' ';
882 srp[o->screen.cur.col + 1] &= ~RS_multiMask;
883 }
884 #endif
885 stp[o->screen.cur.col] = c;
886 srp[o->screen.cur.col] = o->rstyle;
887 if (o->screen.cur.col < (last_col - 1))
888 o->screen.cur.col++;
889 else {
890 o->screen.tlen[row] = last_col;
891 if (o->screen.flags & Screen_Autowrap)
892 o->screen.flags |= Screen_WrapNext;
893 else
894 o->screen.flags &= ~Screen_WrapNext;
895 }
896 }
897 if (o->screen.tlen[row] != -1) /* XXX: think about this */
898 MAX_IT (o->screen.tlen[row], o->screen.cur.col);
899
900 /*
901 * If we wrote anywhere in the selected area, kill the selection
902 * XXX: should we kill the mark too? Possibly, but maybe that
903 * should be a similar check.
904 */
905 if (clearsel)
906 CLEAR_SELECTION;
907
908 #ifdef DEBUG_STRICT
909 assert (o->screen.cur.row >= 0);
910 #else /* drive with your eyes closed */
911 MAX_IT (o->screen.cur.row, 0);
912 #endif
913 }
914
915 /* ------------------------------------------------------------------------- */
916 /*
917 * Process Backspace. Move back the cursor back a position, wrap if have to
918 * XTERM_SEQ: CTRL-H
919 */
920 /* EXTPROTO */
rxvtlib_scr_backspace(rxvtlib * o)921 void rxvtlib_scr_backspace (rxvtlib *o)
922 {
923 RESET_CHSTAT;
924 o->want_refresh = 1;
925 if (o->screen.cur.col == 0) {
926 if (o->screen.cur.row > 0) {
927 #ifdef SUPPORT_BROKEN_APPS_WHICH_RELY_ON_UNDEFINED_BW_BEHAVIOUR_AS_XTERM
928 o->screen.flags &= ~Screen_WrapNext;
929 #else
930 o->screen.cur.col = o->TermWin.ncol - 1;
931 o->screen.cur.row--;
932 #endif
933 } else
934 o->screen.flags &= ~Screen_WrapNext;
935 } else if (o->screen.flags & Screen_WrapNext) {
936 o->screen.flags &= ~Screen_WrapNext;
937 } else
938 rxvtlib_scr_gotorc (o, 0, -1, RELATIVE);
939 }
940
941 /* ------------------------------------------------------------------------- */
942 /*
943 * Process Horizontal Tab
944 * count: +ve = forward; -ve = backwards
945 * XTERM_SEQ: CTRL-I
946 */
947 /* EXTPROTO */
rxvtlib_scr_tab(rxvtlib * o,int count)948 void rxvtlib_scr_tab (rxvtlib *o, int count)
949 {
950 int i, x;
951
952 o->want_refresh = 1;
953 RESET_CHSTAT;
954 x = o->screen.cur.col;
955 if (count == 0)
956 return;
957 else if (count > 0) {
958 for (i = x + 1; i < o->TermWin.ncol; i++) {
959 if (o->tabs[i]) {
960 x = i;
961 if (!--count)
962 break;
963 }
964 }
965 if (count)
966 x = o->TermWin.ncol - 1;
967 } else if (count < 0) {
968 for (i = x - 1; i >= 0; i--) {
969 if (o->tabs[i]) {
970 x = i;
971 if (!++count)
972 break;
973 }
974 }
975 if (count)
976 x = 0;
977 }
978 if (x != o->screen.cur.col)
979 rxvtlib_scr_gotorc (o, 0, x, R_RELATIVE);
980 }
981 /* ------------------------------------------------------------------------- */
982 /*
983 * Process DEC Back Index
984 * XTERM_SEQ: ESC 6
985 * Move cursor left in row. If we're at the left boundary, shift everything
986 * in that row right. Clear left column.
987 */
988 #ifndef NO_FRILLS
989 /* EXTPROTO */
rxvtlib_scr_backindex(rxvtlib * o)990 void rxvtlib_scr_backindex (rxvtlib *o)
991 {
992 int i, row;
993 text_t *t0;
994 rend_t *r0;
995
996 o->want_refresh = 1;
997 if (o->screen.cur.col > 0)
998 rxvtlib_scr_gotorc (o, 0, o->screen.cur.col - 1, R_RELATIVE);
999 else {
1000 row = o->screen.cur.row + o->TermWin.saveLines;
1001 if (o->screen.tlen[row] == 0)
1002 return; /* um, yeah? */
1003 else if (o->screen.tlen[row] < o->TermWin.ncol - 1)
1004 o->screen.tlen[row]++;
1005 t0 = o->screen.text[row];
1006 r0 = o->screen.rend[row];
1007 for (i = o->TermWin.ncol; i-- > 1;) {
1008 t0[i] = t0[i - 1];
1009 r0[i] = r0[i - 1];
1010 }
1011 t0[0] = ' ';
1012 r0[0] = DEFAULT_RSTYLE;
1013 /* TODO: Multi check on last character */
1014 }
1015 }
1016 #endif
1017 /* ------------------------------------------------------------------------- */
1018 /*
1019 * Process DEC Forward Index
1020 * XTERM_SEQ: ESC 9
1021 * Move cursor right in row. If we're at the right boundary, shift everything
1022 * in that row left. Clear right column.
1023 */
1024 #ifndef NO_FRILLS
1025 /* EXTPROTO */
rxvtlib_scr_forwardindex(rxvtlib * o)1026 void rxvtlib_scr_forwardindex (rxvtlib *o)
1027 {
1028 int i, row;
1029 text_t *t0;
1030 rend_t *r0;
1031
1032 o->want_refresh = 1;
1033 if (o->screen.cur.col < o->TermWin.ncol - 1)
1034 rxvtlib_scr_gotorc (o, 0, o->screen.cur.col + 1, R_RELATIVE);
1035 else {
1036 row = o->screen.cur.row + o->TermWin.saveLines;
1037 if (o->screen.tlen[row] == 0)
1038 return; /* um, yeah? */
1039 else if (o->screen.tlen[row] > 0)
1040 o->screen.tlen[row]--;
1041 else
1042 o->screen.tlen[row] = o->TermWin.ncol - 1;
1043 t0 = o->screen.text[row];
1044 r0 = o->screen.rend[row];
1045 for (i = 0; i < o->TermWin.ncol - 2; i++) {
1046 t0[i] = t0[i + 1];
1047 r0[i] = r0[i + 1];
1048 }
1049 t0[i] = ' ';
1050 r0[i] = DEFAULT_RSTYLE;
1051 /* TODO: Multi check on first character */
1052 }
1053 }
1054 #endif
1055
1056 /* ------------------------------------------------------------------------- */
1057 /*
1058 * Goto Row/Column
1059 */
1060 /* EXTPROTO */
rxvtlib_scr_gotorc(rxvtlib * o,int row,int col,int relative)1061 void rxvtlib_scr_gotorc (rxvtlib *o, int row, int col, int relative)
1062 {
1063 o->want_refresh = 1;
1064 ZERO_SCROLLBACK;
1065 RESET_CHSTAT;
1066 if (rxvtlib_Gr_Displayed (o))
1067 rxvtlib_Gr_scroll (o, 0);
1068
1069 D_SCREEN (
1070 (stderr, "scr_gotorc(r:%d,c:%d,%d): from (r:%d,c:%d)", row, col,
1071 relative, o->screen.cur.row, o->screen.cur.col));
1072
1073 o->screen.cur.col = ((relative & C_RELATIVE) ? (o->screen.cur.col + col) : col);
1074 MAX_IT (o->screen.cur.col, 0);
1075 MIN_IT (o->screen.cur.col, o->TermWin.ncol - 1);
1076
1077 if (o->screen.flags & Screen_WrapNext)
1078 o->screen.flags &= ~Screen_WrapNext;
1079 if (relative & R_RELATIVE) {
1080 if (row > 0) {
1081 if (o->screen.cur.row <= o->screen.bscroll
1082 && (o->screen.cur.row + row) > o->screen.bscroll)
1083 o->screen.cur.row = o->screen.bscroll;
1084 else
1085 o->screen.cur.row += row;
1086 } else if (row < 0) {
1087 if (o->screen.cur.row >= o->screen.tscroll
1088 && (o->screen.cur.row + row) < o->screen.tscroll)
1089 o->screen.cur.row = o->screen.tscroll;
1090 else
1091 o->screen.cur.row += row;
1092 }
1093 } else {
1094 if (o->screen.flags & Screen_Relative) { /* relative origin mode */
1095 o->screen.cur.row = row + o->screen.tscroll;
1096 MIN_IT (o->screen.cur.row, o->screen.bscroll);
1097 } else
1098 o->screen.cur.row = row;
1099 }
1100 MAX_IT (o->screen.cur.row, 0);
1101 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
1102 }
1103
1104 /* ------------------------------------------------------------------------- */
1105 /*
1106 * direction should be UP or DN
1107 */
1108 /* EXTPROTO */
rxvtlib_scr_index(rxvtlib * o,int direction)1109 void rxvtlib_scr_index (rxvtlib *o, int direction)
1110 {
1111 int dirn;
1112
1113 o->want_refresh = 1;
1114 dirn = ((direction == UP) ? 1 : -1);
1115 D_SCREEN ((stderr, "scr_index(%d)", dirn));
1116
1117 ZERO_SCROLLBACK;
1118 RESET_CHSTAT;
1119 if (rxvtlib_Gr_Displayed (o))
1120 rxvtlib_Gr_scroll (o, 0);
1121
1122 if (o->screen.flags & Screen_WrapNext) {
1123 o->screen.flags &= ~Screen_WrapNext;
1124 }
1125 if ((o->screen.cur.row == o->screen.bscroll && direction == UP)
1126 || (o->screen.cur.row == o->screen.tscroll && direction == DN)) {
1127 rxvtlib_scroll_text (o, o->screen.tscroll, o->screen.bscroll, dirn, 0);
1128 if (direction == UP)
1129 dirn = o->screen.bscroll + o->TermWin.saveLines;
1130 else
1131 dirn = o->screen.tscroll + o->TermWin.saveLines;
1132 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, dirn, o->rstyle);
1133 o->screen.tlen[dirn] = 0;
1134 } else
1135 o->screen.cur.row += dirn;
1136 MAX_IT (o->screen.cur.row, 0);
1137 MIN_IT (o->screen.cur.row, o->TermWin.nrow - 1);
1138 CHECK_SELECTION (0);
1139 }
1140
1141 /* ------------------------------------------------------------------------- */
1142 /*
1143 * Erase part or whole of a line
1144 * XTERM_SEQ: Clear line to right: ESC [ 0 K
1145 * XTERM_SEQ: Clear line to left : ESC [ 1 K
1146 * XTERM_SEQ: Clear whole line : ESC [ 2 K
1147 */
1148 /* EXTPROTO */
rxvtlib_scr_erase_line(rxvtlib * o,int mode)1149 void rxvtlib_scr_erase_line (rxvtlib *o, int mode)
1150 {
1151 int row, col, num;
1152
1153 o->want_refresh = 1;
1154 D_SCREEN (
1155 (stderr, "scr_erase_line(%d) at screen row: %d", mode,
1156 o->screen.cur.row));
1157 ZERO_SCROLLBACK;
1158 RESET_CHSTAT;
1159 if (rxvtlib_Gr_Displayed (o))
1160 rxvtlib_Gr_scroll (o, 0);
1161 CHECK_SELECTION (1);
1162
1163 if (o->screen.flags & Screen_WrapNext)
1164 o->screen.flags &= ~Screen_WrapNext;
1165
1166 row = o->TermWin.saveLines + o->screen.cur.row;
1167 switch (mode) {
1168 case 0: /* erase to end of line */
1169 col = o->screen.cur.col;
1170 num = o->TermWin.ncol - col;
1171 MIN_IT (o->screen.tlen[row], col);
1172 if (ROWCOL_IN_ROW_AT_OR_AFTER (o->selection.beg, o->screen.cur)
1173 || ROWCOL_IN_ROW_AT_OR_AFTER (o->selection.end, o->screen.cur))
1174 CLEAR_SELECTION;
1175 break;
1176 case 1: /* erase to beginning of line */
1177 col = 0;
1178 num = o->screen.cur.col + 1;
1179 if (ROWCOL_IN_ROW_AT_OR_BEFORE (o->selection.beg, o->screen.cur)
1180 || ROWCOL_IN_ROW_AT_OR_BEFORE (o->selection.end, o->screen.cur))
1181 CLEAR_SELECTION;
1182 break;
1183 case 2: /* erase whole line */
1184 col = 0;
1185 num = o->TermWin.ncol;
1186 o->screen.tlen[row] = 0;
1187 if (o->selection.beg.row <= o->screen.cur.row
1188 && o->selection.end.row >= o->screen.cur.row) CLEAR_SELECTION;
1189 break;
1190 default:
1191 return;
1192 }
1193 if (o->screen.text[row])
1194 blank_line (&(o->screen.text[row][col]), &(o->screen.rend[row][col]), num,
1195 o->rstyle & ~RS_Uline);
1196 else
1197 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, row, o->rstyle & ~RS_Uline);
1198 }
1199
1200 /* ------------------------------------------------------------------------- */
1201 /*
1202 * Erase part of whole of the screen
1203 * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1204 * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1205 * XTERM_SEQ: Clear whole screen : ESC [ 2 J
1206 */
1207 /* EXTPROTO */
rxvtlib_scr_erase_screen(rxvtlib * o,int mode)1208 void rxvtlib_scr_erase_screen (rxvtlib *o, int mode)
1209 {
1210 int row, num, row_offset;
1211 rend_t ren;
1212 long gcmask;
1213 XGCValues gcvalue;
1214
1215 o->want_refresh = 1;
1216 D_SCREEN (
1217 (stderr, "scr_erase_screen(%d) at screen row: %d", mode,
1218 o->screen.cur.row));
1219 ZERO_SCROLLBACK;
1220 RESET_CHSTAT;
1221 row_offset = o->TermWin.saveLines;
1222
1223 switch (mode) {
1224 case 0: /* erase to end of screen */
1225 CHECK_SELECTION (1);
1226 rxvtlib_scr_erase_line (o, 0);
1227 row = o->screen.cur.row + 1; /* possible OOB */
1228 num = o->TermWin.nrow - row;
1229 break;
1230 case 1: /* erase to beginning of screen */
1231 CHECK_SELECTION (3);
1232 rxvtlib_scr_erase_line (o, 1);
1233 row = 0; /* possible OOB */
1234 num = o->screen.cur.row;
1235 break;
1236 case 2: /* erase whole screen */
1237 CHECK_SELECTION (3);
1238 rxvtlib_Gr_ClearScreen (o);
1239 row = 0;
1240 num = o->TermWin.nrow;
1241 break;
1242 default:
1243 return;
1244 }
1245 if (o->selection.op && o->current_screen == o->selection.screen
1246 && ((o->selection.beg.row >= row && o->selection.beg.row <= row + num)
1247 || (o->selection.end.row >= row && o->selection.end.row <= row + num)))
1248 CLEAR_SELECTION;
1249 if (row >= 0 && row < o->TermWin.nrow) { /* check OOB */
1250 MIN_IT (num, (o->TermWin.nrow - row));
1251 if (o->rstyle & (RS_RVid | RS_Uline))
1252 ren = (rend_t) ~ RS_None;
1253 else if (GET_BGCOLOR (o->rstyle) == Color_bg) {
1254 ren = DEFAULT_RSTYLE;
1255 CLEAR_ROWS (row, num);
1256 } else {
1257 ren = (o->rstyle & (RS_fgMask | RS_bgMask));
1258 gcvalue.foreground = o->PixColors[GET_BGCOLOR (ren)];
1259 gcmask = GCForeground;
1260 XChangeGC (o->Xdisplay, o->TermWin.gc, gcmask, &gcvalue);
1261 ERASE_ROWS (row, num);
1262 gcvalue.foreground = o->PixColors[Color_fg];
1263 XChangeGC (o->Xdisplay, o->TermWin.gc, gcmask, &gcvalue);
1264 }
1265 for (; num--; row++) {
1266 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, row + row_offset,
1267 o->rstyle & ~RS_Uline);
1268 o->screen.tlen[row + row_offset] = 0;
1269 blank_line (o->drawn_text[row], o->drawn_rend[row], o->TermWin.ncol, ren);
1270 }
1271 }
1272 }
1273
1274 /* ------------------------------------------------------------------------- */
1275 /*
1276 * Fill the screen with `E's
1277 * XTERM_SEQ: Screen Alignment Test: ESC # 8
1278 */
1279 /* EXTPROTO */
rxvtlib_scr_E(rxvtlib * o)1280 void rxvtlib_scr_E (rxvtlib *o)
1281 {
1282 int i, j;
1283 text_t *t;
1284 rend_t *r, fs;
1285
1286 o->want_refresh = 1;
1287 ZERO_SCROLLBACK;
1288 RESET_CHSTAT;
1289 CHECK_SELECTION (3);
1290
1291 fs = o->rstyle;
1292 for (i = o->TermWin.saveLines; i < o->TermWin.nrow + o->TermWin.saveLines; i++) {
1293 t = o->screen.text[i];
1294 r = o->screen.rend[i];
1295 for (j = 0; j < o->TermWin.ncol; j++) {
1296 *t++ = 'E';
1297 *r++ = fs;
1298 }
1299 o->screen.tlen[i] = o->TermWin.ncol; /* make the `E's selectable */
1300 }
1301 }
1302
1303 /* ------------------------------------------------------------------------- */
1304 /*
1305 * Insert/Delete <count> lines
1306 */
1307 /* EXTPROTO */
rxvtlib_scr_insdel_lines(rxvtlib * o,int count,int insdel)1308 void rxvtlib_scr_insdel_lines (rxvtlib *o, int count, int insdel)
1309 {
1310 int end;
1311
1312 ZERO_SCROLLBACK;
1313 RESET_CHSTAT;
1314 if (rxvtlib_Gr_Displayed (o))
1315 rxvtlib_Gr_scroll (o, 0);
1316 CHECK_SELECTION (1);
1317
1318 if (o->screen.cur.row > o->screen.bscroll)
1319 return;
1320
1321 end = o->screen.bscroll - o->screen.cur.row + 1;
1322 if (count > end) {
1323 if (insdel == DELETE)
1324 return;
1325 else if (insdel == INSERT)
1326 count = end;
1327 }
1328 if (o->screen.flags & Screen_WrapNext)
1329 o->screen.flags &= ~Screen_WrapNext;
1330
1331 rxvtlib_scroll_text (o, o->screen.cur.row, o->screen.bscroll, insdel * count, 0);
1332
1333 /* fill the inserted or new lines with rstyle. TODO: correct for delete? */
1334 if (insdel == DELETE)
1335 end = o->screen.bscroll + o->TermWin.saveLines;
1336 else if (insdel == INSERT)
1337 end = o->screen.cur.row + count - 1 + o->TermWin.saveLines;
1338 for (; count--;) {
1339 rxvtlib_blank_screen_mem (o, o->screen.text, o->screen.rend, end, o->rstyle);
1340 o->screen.tlen[end--] = 0;
1341 }
1342 }
1343
1344 /* ------------------------------------------------------------------------- */
1345 /*
1346 * Insert/Delete <count> characters from the current position
1347 */
1348 /* EXTPROTO */
rxvtlib_scr_insdel_chars(rxvtlib * o,int count,int insdel)1349 void rxvtlib_scr_insdel_chars (rxvtlib *o, int count, int insdel)
1350 {
1351 int col, row;
1352 rend_t tr;
1353
1354 o->want_refresh = 1;
1355 ZERO_SCROLLBACK;
1356 #if 0
1357 RESET_CHSTAT;
1358 #endif
1359 if (rxvtlib_Gr_Displayed (o))
1360 rxvtlib_Gr_scroll (o, 0);
1361
1362 if (count <= 0)
1363 return;
1364
1365 CHECK_SELECTION (1);
1366 MIN_IT (count, (o->TermWin.ncol - o->screen.cur.col));
1367
1368 row = o->screen.cur.row + o->TermWin.saveLines;
1369 o->screen.flags &= ~Screen_WrapNext;
1370
1371 switch (insdel) {
1372 case INSERT:
1373 for (col = o->TermWin.ncol - 1; (col - count) >= o->screen.cur.col; col--) {
1374 o->screen.text[row][col] = o->screen.text[row][col - count];
1375 o->screen.rend[row][col] = o->screen.rend[row][col - count];
1376 }
1377 if (o->screen.tlen[row] != -1) {
1378 o->screen.tlen[row] += count;
1379 MIN_IT (o->screen.tlen[row], o->TermWin.ncol);
1380 }
1381 if (o->selection.op && o->current_screen == o->selection.screen
1382 && ROWCOL_IN_ROW_AT_OR_AFTER (o->selection.beg, o->screen.cur)) {
1383 if (o->selection.end.row != o->screen.cur.row
1384 || (o->selection.end.col + count >= o->TermWin.ncol))
1385 CLEAR_SELECTION;
1386 else { /* shift selection */
1387 o->selection.beg.col += count;
1388 o->selection.mark.col += count; /* XXX: yes? */
1389 o->selection.end.col += count;
1390 }
1391 }
1392 blank_line (&(o->screen.text[row][o->screen.cur.col]),
1393 &(o->screen.rend[row][o->screen.cur.col]), count, o->rstyle);
1394 break;
1395 case ERASE:
1396 o->screen.cur.col += count; /* don't worry if > TermWin.ncol */
1397 CHECK_SELECTION (1);
1398 o->screen.cur.col -= count;
1399 blank_line (&(o->screen.text[row][o->screen.cur.col]),
1400 &(o->screen.rend[row][o->screen.cur.col]), count, o->rstyle);
1401 break;
1402 case DELETE:
1403 tr = o->screen.rend[row][o->TermWin.ncol - 1]
1404 & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1405 for (col = o->screen.cur.col; (col + count) < o->TermWin.ncol; col++) {
1406 o->screen.text[row][col] = o->screen.text[row][col + count];
1407 o->screen.rend[row][col] = o->screen.rend[row][col + count];
1408 }
1409 blank_line (&(o->screen.text[row][o->TermWin.ncol - count]),
1410 &(o->screen.rend[row][o->TermWin.ncol - count]), count, tr);
1411 if (o->screen.tlen[row] == -1) /* break line continuation */
1412 o->screen.tlen[row] = o->TermWin.ncol;
1413 o->screen.tlen[row] -= count;
1414 MAX_IT (o->screen.tlen[row], 0);
1415 if (o->selection.op && o->current_screen == o->selection.screen
1416 && ROWCOL_IN_ROW_AT_OR_AFTER (o->selection.beg, o->screen.cur)) {
1417 if (o->selection.end.row != o->screen.cur.row
1418 || (o->screen.cur.col >= o->selection.beg.col - count)
1419 || o->selection.end.col >= o->TermWin.ncol)
1420 CLEAR_SELECTION;
1421 else {
1422 /* shift selection */
1423 o->selection.beg.col -= count;
1424 o->selection.mark.col -= count; /* XXX: yes? */
1425 o->selection.end.col -= count;
1426 }
1427 }
1428 break;
1429 }
1430 #if 0
1431 if ((o->screen.rend[row][0] & RS_multiMask) == RS_multi2) {
1432 o->screen.rend[row][0] &= ~RS_multiMask;
1433 o->screen.text[row][0] = ' ';
1434 }
1435 if ((o->screen.rend[row][o->TermWin.ncol - 1] & RS_multiMask) == RS_multi1) {
1436 o->screen.rend[row][o->TermWin.ncol - 1] &= ~RS_multiMask;
1437 o->screen.text[row][o->TermWin.ncol - 1] = ' ';
1438 }
1439 #endif
1440 }
1441
1442 /* ------------------------------------------------------------------------- */
1443 /*
1444 * Set the scrolling region
1445 * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1446 */
1447 /* EXTPROTO */
rxvtlib_scr_scroll_region(rxvtlib * o,int top,int bot)1448 void rxvtlib_scr_scroll_region (rxvtlib *o, int top, int bot)
1449 {
1450 MAX_IT (top, 0);
1451 MIN_IT (bot, o->TermWin.nrow - 1);
1452 if (top > bot)
1453 return;
1454 o->screen.tscroll = top;
1455 o->screen.bscroll = bot;
1456 rxvtlib_scr_gotorc (o, 0, 0, 0);
1457 }
1458
1459 /* ------------------------------------------------------------------------- */
1460 /*
1461 * Make the cursor visible/invisible
1462 * XTERM_SEQ: Make cursor visible : ESC [ ? 25 h
1463 * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1464 */
1465 /* EXTPROTO */
rxvtlib_scr_cursor_visible(rxvtlib * o,int mode)1466 void rxvtlib_scr_cursor_visible (rxvtlib *o, int mode)
1467 {
1468 o->want_refresh = 1;
1469 if (mode)
1470 o->screen.flags |= Screen_VisibleCursor;
1471 else
1472 o->screen.flags &= ~Screen_VisibleCursor;
1473 }
1474
1475 /* ------------------------------------------------------------------------- */
1476 /*
1477 * Set/unset automatic wrapping
1478 * XTERM_SEQ: Set Wraparound : ESC [ ? 7 h
1479 * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1480 */
1481 /* EXTPROTO */
rxvtlib_scr_autowrap(rxvtlib * o,int mode)1482 void rxvtlib_scr_autowrap (rxvtlib *o, int mode)
1483 {
1484 if (mode)
1485 o->screen.flags |= Screen_Autowrap;
1486 else
1487 o->screen.flags &= ~Screen_Autowrap;
1488 }
1489
1490 /* ------------------------------------------------------------------------- */
1491 /*
1492 * Set/unset margin origin mode
1493 * Absolute mode: line numbers are counted relative to top margin of screen
1494 * and the cursor can be moved outside the scrolling region.
1495 * Relative mode: line numbers are relative to top margin of scrolling region
1496 * and the cursor cannot be moved outside.
1497 * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1498 * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1499 */
1500 /* EXTPROTO */
rxvtlib_scr_relative_origin(rxvtlib * o,int mode)1501 void rxvtlib_scr_relative_origin (rxvtlib *o, int mode)
1502 {
1503 if (mode)
1504 o->screen.flags |= Screen_Relative;
1505 else
1506 o->screen.flags &= ~Screen_Relative;
1507 rxvtlib_scr_gotorc (o, 0, 0, 0);
1508 }
1509
1510 /* ------------------------------------------------------------------------- */
1511 /*
1512 * Set insert/replace mode
1513 * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1514 * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1515 */
1516 /* EXTPROTO */
rxvtlib_scr_insert_mode(rxvtlib * o,int mode)1517 void rxvtlib_scr_insert_mode (rxvtlib *o, int mode)
1518 {
1519 if (mode)
1520 o->screen.flags |= Screen_Insert;
1521 else
1522 o->screen.flags &= ~Screen_Insert;
1523 }
1524
1525 /* ------------------------------------------------------------------------- */
1526 /*
1527 * Set/Unset tabs
1528 * XTERM_SEQ: Set tab at current column : ESC H
1529 * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1530 * XTERM_SEQ: Clear all tabs : ESC [ 3 g
1531 */
1532 /* EXTPROTO */
rxvtlib_scr_set_tab(rxvtlib * o,int mode)1533 void rxvtlib_scr_set_tab (rxvtlib *o, int mode)
1534 {
1535 if (mode < 0)
1536 MEMSET (o->tabs, 0, o->TermWin.ncol * sizeof (char));
1537
1538 else if (o->screen.cur.col < o->TermWin.ncol)
1539 o->tabs[o->screen.cur.col] = (mode ? 1 : 0);
1540 }
1541
1542 /* ------------------------------------------------------------------------- */
1543 /*
1544 * Set reverse/normal video
1545 * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1546 * XTERM_SEQ: Normal video : ESC [ ? 5 l
1547 */
1548 /* EXTPROTO */
rxvtlib_scr_rvideo_mode(rxvtlib * o,int mode)1549 void rxvtlib_scr_rvideo_mode (rxvtlib *o, int mode)
1550 {
1551 int i, j;
1552 rend_t *r;
1553
1554 if (o->rvideo != mode) {
1555 o->rvideo = mode;
1556 o->rstyle ^= RS_RVid;
1557
1558 for (i = 0; i < o->TermWin.nrow; i++) {
1559 r = o->screen.rend[o->TermWin.saveLines + i];
1560 for (j = 0; j < o->TermWin.ncol; j++)
1561 *r++ ^= RS_RVid;
1562 }
1563 rxvtlib_scr_refresh (o, SLOW_REFRESH);
1564 }
1565 }
1566
1567 /* ------------------------------------------------------------------------- */
1568 /*
1569 * Report current cursor position
1570 * XTERM_SEQ: Report position: ESC [ 6 n
1571 */
1572 /* EXTPROTO */
rxvtlib_scr_report_position(rxvtlib * o)1573 void rxvtlib_scr_report_position (rxvtlib *o)
1574 {
1575 rxvtlib_tt_printf (o, "\033[%d;%dR", o->screen.cur.row + 1, o->screen.cur.col + 1);
1576 }
1577
1578 /* ------------------------------------------------------------------------- *
1579 * FONTS *
1580 * ------------------------------------------------------------------------- */
1581
1582 /*
1583 * Set font style
1584 */
1585 /* INTPROTO */
rxvtlib_set_font_style(rxvtlib * o)1586 void rxvtlib_set_font_style (rxvtlib *o)
1587 {
1588 o->rstyle &= ~RS_fontMask;
1589 switch (o->charsets[o->screen.charset]) {
1590 case '0': /* DEC Special Character & Line Drawing Set */
1591 o->rstyle |= RS_acsFont;
1592 break;
1593 case 'A': /* United Kingdom (UK) */
1594 o->rstyle |= RS_ukFont;
1595 break;
1596 case 'B': /* United States (USASCII) */
1597 break;
1598 case '<': /* Multinational character set */
1599 break;
1600 case '5': /* Finnish character set */
1601 break;
1602 case 'C': /* Finnish character set */
1603 break;
1604 case 'K': /* German character set */
1605 break;
1606 }
1607 }
1608
1609 /* ------------------------------------------------------------------------- */
1610 /*
1611 * Choose a font
1612 * XTERM_SEQ: Invoke G0 character set: CTRL-O
1613 * XTERM_SEQ: Invoke G1 character set: CTRL-N
1614 * XTERM_SEQ: Invoke G2 character set: ESC N
1615 * XTERM_SEQ: Invoke G3 character set: ESC O
1616 */
1617 /* EXTPROTO */
rxvtlib_scr_charset_choose(rxvtlib * o,int set)1618 void rxvtlib_scr_charset_choose (rxvtlib *o, int set)
1619 {
1620 o->screen.charset = set;
1621 rxvtlib_set_font_style (o);
1622 }
1623
1624 /* ------------------------------------------------------------------------- */
1625 /*
1626 * Set a font
1627 * XTERM_SEQ: Set G0 character set: ESC ( <C>
1628 * XTERM_SEQ: Set G1 character set: ESC ) <C>
1629 * XTERM_SEQ: Set G2 character set: ESC * <C>
1630 * XTERM_SEQ: Set G3 character set: ESC + <C>
1631 * See set_font_style for possible values for <C>
1632 */
1633 /* EXTPROTO */
rxvtlib_scr_charset_set(rxvtlib * o,int set,unsigned int ch)1634 void rxvtlib_scr_charset_set (rxvtlib *o, int set, unsigned int ch)
1635 {
1636 #ifdef MULTICHAR_SET
1637 o->multi_byte = (set < 0);
1638 set = abs (set);
1639 #endif
1640 o->charsets[set] = (unsigned char)ch;
1641 rxvtlib_set_font_style (o);
1642 }
1643
1644 /* ------------------------------------------------------------------------- *
1645 * MULTIPLE-CHARACTER FONT SET MANIPULATION FUNCTIONS *
1646 * ------------------------------------------------------------------------- */
1647 #ifdef MULTICHAR_SET
1648
1649 /* INTPROTO */
eucj2jis(unsigned char * str,int len)1650 void eucj2jis (unsigned char *str, int len)
1651 {
1652 register int i;
1653
1654 for (i = 0; i < len; i++)
1655 str[i] &= 0x7F;
1656 }
1657
1658 /* ------------------------------------------------------------------------- */
1659 /* INTPROTO */
sjis2jis(unsigned char * str,int len)1660 void sjis2jis (unsigned char *str, int len)
1661 {
1662 register int i;
1663 unsigned char *high, *low;
1664
1665 for (i = 0; i < len; i += 2, str += 2) {
1666 high = str;
1667 low = str + 1;
1668 (*high) -= (*high > 0x9F ? 0xB1 : 0x71);
1669 *high = (*high) * 2 + 1;
1670 if (*low > 0x9E) {
1671 *low -= 0x7E;
1672 (*high)++;
1673 } else {
1674 if (*low > 0x7E)
1675 (*low)--;
1676 *low -= 0x1F;
1677 }
1678 }
1679 }
1680
1681 /* INTPROTO */
big5dummy(unsigned char * str,int len)1682 void big5dummy (unsigned char *str, int len)
1683 {
1684 }
1685
1686 /* INTPROTO */
gb2jis(unsigned char * str,int len)1687 void gb2jis (unsigned char *str, int len)
1688 {
1689 register int i;
1690
1691 for (i = 0; i < len; i++)
1692 str[i] &= 0x7F;
1693 }
1694
1695 /* EXTPROTO */
rxvtlib_set_multichar_encoding(rxvtlib * o,const char * str)1696 void rxvtlib_set_multichar_encoding (rxvtlib *o, const char *str)
1697 {
1698 if (str && *str) {
1699 if (!strcasecmp (str, "sjis")) {
1700 o->encoding_method = SJIS; /* Kanji SJIS */
1701 o->multichar_decode = sjis2jis;
1702 } else if (!strcasecmp (str, "eucj")) {
1703 o->encoding_method = EUCJ; /* Kanji EUCJ */
1704 o->multichar_decode = eucj2jis;
1705 }
1706 }
1707 }
1708 #endif /* MULTICHAR_SET */
1709
1710 /* ------------------------------------------------------------------------- *
1711 * GRAPHICS COLOURS *
1712 * ------------------------------------------------------------------------- */
1713
1714 #ifdef RXVT_GRAPHICS
1715 /* EXTPROTO */
rxvtlib_scr_get_fgcolor(rxvtlib * o)1716 int rxvtlib_scr_get_fgcolor (rxvtlib *o)
1717 {
1718 return GET_FGCOLOR (o->rstyle);
1719 }
1720
1721 /* ------------------------------------------------------------------------- */
1722 /* EXTPROTO */
rxvtlib_scr_get_bgcolor(rxvtlib * o)1723 int rxvtlib_scr_get_bgcolor (rxvtlib *o)
1724 {
1725 return GET_BGCOLOR (o->rstyle);
1726 }
1727 #endif
1728
1729 /* ------------------------------------------------------------------------- *
1730 * MAJOR SCREEN MANIPULATION *
1731 * ------------------------------------------------------------------------- */
1732
1733 /*
1734 * Refresh an area
1735 */
1736 enum {
1737 PART_BEG = 0,
1738 PART_END,
1739 #if defined(XPM_BACKGROUND) && defined(XPM_BUFFERING)
1740 FULL_BEG,
1741 FULL_END,
1742 #endif
1743 RC_COUNT
1744 };
1745 /* EXTPROTO */
rxvtlib_scr_expose(rxvtlib * o,int x,int y,int width,int height)1746 void rxvtlib_scr_expose (rxvtlib *o, int x, int y, int width, int height)
1747 {
1748 int i;
1749
1750 row_col_t rc[RC_COUNT];
1751
1752 if (o->drawn_text == NULL) /* sanity check */
1753 return;
1754
1755 /* round down */
1756 rc[PART_BEG].col = Pixel2Col(x);
1757 rc[PART_BEG].row = Pixel2Row(y);
1758
1759 /* round up */
1760 rc[PART_END].col = Pixel2Width(x + width + o->TermWin.fwidth - 1);
1761 rc[PART_END].row = Pixel2Row(y + height + o->TermWin.fheight - 1);
1762
1763 #if defined(XPM_BACKGROUND) && defined(XPM_BUFFERING)
1764 /* round down */
1765 rc[FULL_END].col = Pixel2Width(x + width);
1766 rc[FULL_END].row = Pixel2Row(y + height);
1767 /* round up */
1768 rc[FULL_BEG].col = Pixel2Col(x + o->TermWin.fwidth - 1);
1769 rc[FULL_BEG].row = Pixel2Row(y + o->TermWin.fheight - 1);
1770 #endif
1771
1772 /* sanity checks */
1773 for (i = PART_BEG; i < RC_COUNT; i++) {
1774 MAX_IT(rc[i].col, 0);
1775 MAX_IT(rc[i].row, 0);
1776 MIN_IT(rc[i].col, o->TermWin.ncol - 1);
1777 MIN_IT(rc[i].row, o->TermWin.nrow - 1);
1778 }
1779
1780 D_SCREEN((stderr, "scr_expose(x:%d, y:%d, w:%d, h:%d) area (c:%d,r:%d)-(c:%d,r:%d)", x, y, width, height, rc[PART_BEG}.col, rc[PART_BEG].row, rc[PART_END].col, rc[PART_END].row));
1781
1782 #if defined(XPM_BACKGROUND) && defined(XPM_BUFFERING)
1783 /* supposedly we're exposed - so `clear' the fully exposed clear areas */
1784 x = Col2Pixel(rc[FULL_BEG].col);
1785 y = Row2Pixel(rc[FULL_BEG].row);
1786 width = Width2Pixel(rc[FULL_END].col - rc[FULL_BEG].col + 1);
1787 height = Height2Pixel(rc[FULL_END].row - rc[FULL_BEG].row + 1);
1788 XCopyArea (o->Xdisplay, o->TermWin.pixmap, drawBuffer, o->TermWin.gc,
1789 x, y, width, height, x, y);
1790 #endif
1791
1792 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1793 MEMSET(&(o->drawn_text[i][rc[PART_BEG].col]), 0,
1794 rc[PART_END].col - rc[PART_BEG].col + 1);
1795
1796 rxvtlib_scr_refresh (o, SLOW_REFRESH);
1797 }
1798
1799 /* ------------------------------------------------------------------------- */
1800 /*
1801 * Refresh the entire screen
1802 */
1803 /* EXTPROTO */
1804 void rxvtlib_scr_touch (rxvtlib *o)
1805 {
1806 rxvtlib_scr_expose (o, 0, 0, o->TermWin.width, o->TermWin.height);
1807 }
1808
1809 /* ------------------------------------------------------------------------- */
1810 /*
1811 * Move the display so that the line represented by scrollbar value Y is at
1812 * the top of the screen
1813 */
1814 /* EXTPROTO */
1815 int rxvtlib_scr_move_to (rxvtlib *o, int y, int len)
1816 {
1817 int start;
1818
1819 o->want_refresh = 1;
1820 start = o->TermWin.view_start;
1821 if (y >= len)
1822 o->TermWin.view_start = 0;
1823 else {
1824 o->TermWin.view_start = ((len - y)
1825 * (o->TermWin.nrow - 1 + o->TermWin.nscrolled) / len);
1826 if (o->TermWin.view_start < o->TermWin.nrow)
1827 o->TermWin.view_start = 0;
1828 else
1829 o->TermWin.view_start -= (o->TermWin.nrow - 1);
1830 }
1831 D_SCREEN (
1832 (stderr, "scr_move_to(%d, %d) view_start:%d", y, len,
1833 o->TermWin.view_start));
1834
1835 MIN_IT (o->TermWin.view_start, o->TermWin.nscrolled);
1836
1837 if (rxvtlib_Gr_Displayed (o))
1838 rxvtlib_Gr_scroll (o, 0);
1839 return (o->TermWin.view_start - start);
1840 }
1841 /* ------------------------------------------------------------------------- */
1842 /*
1843 * Page the screen up/down nlines
1844 * direction should be UP or DN
1845 */
1846 /* EXTPROTO */
1847 int rxvtlib_scr_page (rxvtlib *o, int direction, int nlines)
1848 {
1849 int start;
1850
1851 D_SCREEN (
1852 (stderr, "scr_page(%s, %d) view_start:%d",
1853 ((direction == UP) ? "UP" : "DN"), nlines, o->TermWin.view_start));
1854
1855 start = o->TermWin.view_start;
1856 MAX_IT (nlines, 1);
1857 MIN_IT (nlines, o->TermWin.nrow);
1858 if (direction == UP)
1859 o->TermWin.view_start = o->TermWin.view_start < o->TermWin.nscrolled - nlines
1860 ? o->TermWin.view_start + nlines : o->TermWin.nscrolled;
1861 else
1862 o->TermWin.view_start = o->TermWin.view_start > nlines
1863 ? o->TermWin.view_start - nlines : 0;
1864
1865 if (rxvtlib_Gr_Displayed (o))
1866 rxvtlib_Gr_scroll (o, 0);
1867 if (o->TermWin.view_start != start)
1868 o->want_refresh = 1;
1869 return (int)(o->TermWin.view_start - start);
1870 }
1871
1872 /* ------------------------------------------------------------------------- */
1873 /* EXTPROTO */
1874 void rxvtlib_scr_bell (rxvtlib *o)
1875 {
1876 #ifndef NO_MAPALERT
1877 # ifdef MAPALERT_OPTION
1878 if (o->Options & Opt_mapAlert)
1879 # endif
1880 XMapWindow (o->Xdisplay, o->TermWin.parent[0]);
1881 #endif
1882 if (o->Options & Opt_visualBell) {
1883 rxvtlib_scr_rvideo_mode (o, !o->rvideo); /* scr_refresh() also done */
1884 rxvtlib_scr_rvideo_mode (o, !o->rvideo); /* scr_refresh() also done */
1885 } else
1886 XBell (o->Xdisplay, 0);
1887 }
1888
1889 /* ------------------------------------------------------------------------- */
1890 /* ARGSUSED */
1891 /* EXTPROTO */
1892 void rxvtlib_scr_printscreen (rxvtlib *o, int fullhist)
1893 {
1894 #ifdef PRINTPIPE
1895 int i, r, nrows, row_offset;
1896 text_t *t;
1897 FILE *fd;
1898
1899 if ((fd = rxvtlib_popen_printer (o)) == NULL)
1900 return;
1901 nrows = o->TermWin.nrow;
1902 row_offset = o->TermWin.saveLines;
1903 if (!fullhist)
1904 row_offset -= o->TermWin.view_start;
1905 else {
1906 nrows += o->TermWin.nscrolled;
1907 row_offset -= o->TermWin.nscrolled;
1908 }
1909
1910 for (r = 0; r < nrows; r++) {
1911 t = o->screen.text[r + row_offset];
1912 for (i = o->TermWin.ncol - 1; i >= 0; i--)
1913 if (!isspace (t[i]))
1914 break;
1915 fprintf (fd, "%.*s\n", (i + 1), t);
1916 }
1917 pclose_printer (fd);
1918 #endif
1919 }
1920
1921 /* ------------------------------------------------------------------------- */
1922 /*
1923 * Refresh the screen
1924 * drawn_text/drawn_rend contain the screen information before the update.
1925 * screen.text/screen.rend contain what the screen will change to.
1926 */
1927
1928 /* EXTPROTO */
1929 void rxvtlib_scr_refresh (rxvtlib *o, int type)
1930 {
1931 int i, j, /* tmp */
1932 col, row, /* column/row we're processing */
1933 scrrow, /* screen row offset */
1934 row_offset, /* basic offset in screen structure */
1935 currow, /* cursor row at appropriate offset */
1936 boldlast, /* last character in some row was bold */
1937 len, wlen, /* text length screen/buffer */
1938 fprop, /* proportional font used */
1939 rvid, /* reverse video this position */
1940 rend, /* rendition */
1941 fore, back, /* desired foreground/background */
1942 wbyte, /* we're in multibyte */
1943 fontdiff, /* current font size different to base font */
1944 morecur = 0, xpixel, /* x offset for start of drawing (font) */
1945 ypixel, /* y offset for start of drawing (font) */
1946 ypixelc; /* y offset for top of drawing */
1947 long gcmask, /* Graphics Context mask */
1948 gcmaskf;
1949 static int focus = -1; /* screen in focus? */
1950 unsigned long ltmp;
1951 rend_t rt1, rt2; /* tmp rend values */
1952
1953 #ifndef NO_CURSORCOLOR
1954 rend_t ccol1, /* Cursor colour */
1955 ccol2, /* Cursor colour2 */
1956 cc1 = 0; /* store colours at cursor position(s) */
1957
1958 # ifdef MULTICHAR_SET
1959 rend_t cc2; /* store colours at cursor position(s) */
1960
1961 # endif
1962 #endif
1963 rend_t *drp, *srp; /* drawn-rend-pointer, screen-rend-pointer */
1964 text_t *dtp, *stp; /* drawn-text-pointer, screen-text-pointer */
1965 XGCValues gcvalue; /* Graphics Context values */
1966 XFontStruct *wf; /* which font are we in */
1967
1968 /* is there an old outline cursor on screen? */
1969 #ifndef NO_BOLDFONT
1970 int bfont = 0; /* we've changed font to bold font */
1971 #endif
1972 int (*draw_string) (), (*draw_image_string) ();
1973
1974 if (type == NO_REFRESH)
1975 return;
1976 if (!o->TermWin.mapped)
1977 return;
1978
1979 /*
1980 * A: set up vars
1981 */
1982 if (o->currmaxcol < o->TermWin.ncol) {
1983 o->currmaxcol = o->TermWin.ncol;
1984 if (o->buffer)
1985 o->buffer = REALLOC (o->buffer, (sizeof (char) * (o->currmaxcol + 1)));
1986
1987 else
1988 o->buffer = MALLOC ((sizeof (char) * (o->currmaxcol + 1)));
1989 }
1990 row_offset = o->TermWin.saveLines - o->TermWin.view_start;
1991 fprop = o->TermWin.fprop;
1992 gcvalue.foreground = o->PixColors[Color_fg];
1993 gcvalue.background = o->PixColors[Color_bg];
1994 /*
1995 * always go back to the base font - it's much safer
1996 */
1997 wbyte = 0;
1998 XSetFont (o->Xdisplay, o->TermWin.gc, o->TermWin.font->fid);
1999 draw_string = XDrawString;
2000 draw_image_string = XDrawImageString;
2001 boldlast = 0;
2002
2003 /*
2004 * B: reverse any characters which are selected
2005 */
2006 rxvtlib_scr_reverse_selection (o);
2007
2008 #ifndef NO_BOLDOVERSTRIKE
2009 /*
2010 * C: Bold Overstrike pixel dropping avoidance. Do this before the main
2011 * refresh. Do a pass across each line at the start, require a refresh of
2012 * anything that will need to be refreshed due to pixels being dropped
2013 * into our area by a previous character which has now been changed.
2014 */
2015 for (row = 0; row < o->TermWin.nrow; row++) {
2016 scrrow = row + row_offset;
2017 stp = o->screen.text[scrrow];
2018 srp = o->screen.rend[scrrow];
2019 dtp = o->drawn_text[row];
2020 drp = o->drawn_rend[row];
2021 # ifndef NO_BOLDFONT
2022 if (o->TermWin.boldFont == NULL) {
2023 # endif
2024 wf = o->TermWin.font;
2025 j = wbyte;
2026 for (col = o->TermWin.ncol - 2; col >= 0; col--) {
2027 # if ! defined (NO_BRIGHTCOLOR) && ! defined (VERYBOLD)
2028 fore = GET_FGCOLOR (drp[col]);
2029 # endif
2030 if (!MONO_BOLD (drp[col]))
2031 continue;
2032 if (dtp[col] == stp[col]
2033 && drp[col] == srp[col])
2034 continue;
2035 if (wbyte) {
2036 ; /* TODO: handle multibyte */
2037 continue; /* don't go past here */
2038 }
2039 if (dtp[col] == ' ') { /* TODO: check character set? */
2040 continue;
2041 }
2042 if (wf->per_char == NULL
2043 || dtp[col] < wf->min_char_or_byte2
2044 || dtp[col] > wf->max_char_or_byte2
2045 || FONT_WIDTH (wf, dtp[col]) == FONT_RBEAR (wf, dtp[col])) {
2046 dtp[col + 1] = 0;
2047 # if defined(MULTICHAR_SET) && ! defined(NO_BOLDOVERSTRIKE_MULTI)
2048 if ((srp[col] & RS_multiMask) == RS_multi2) {
2049 col--;
2050 wbyte = 1;
2051 continue;
2052 }
2053 # endif
2054 }
2055 }
2056 # if ! defined (NO_BRIGHTCOLOR) && ! defined (VERYBOLD)
2057 fore = GET_FGCOLOR (srp[o->TermWin.ncol - 1]);
2058 # endif
2059 if (MONO_BOLD (srp[o->TermWin.ncol - 1]))
2060 boldlast = 1;
2061 wbyte = j;
2062 # ifndef NO_BOLDFONT
2063 }
2064 # endif
2065 }
2066 #endif /* ! NO_BOLDOVERSTRIKE */
2067
2068 /*
2069 * D: set the cursor character(s)
2070 */
2071 currow = o->screen.cur.row + o->TermWin.saveLines;
2072 if (focus != o->TermWin.focus)
2073 focus = o->TermWin.focus;
2074 if (o->screen.flags & Screen_VisibleCursor && focus) {
2075 srp = &(o->screen.rend[currow][o->screen.cur.col]);
2076 *srp ^= RS_RVid;
2077 #ifndef NO_CURSORCOLOR
2078 cc1 = *srp & (RS_fgMask | RS_bgMask);
2079 if (o->Xdepth <= 2 || !o->rs[Rs_color + Color_cursor])
2080 ccol1 = Color_fg;
2081 else
2082 ccol1 = Color_cursor;
2083 if (o->Xdepth <= 2 || !o->rs[Rs_color + Color_cursor2])
2084 ccol2 = Color_bg;
2085 else
2086 ccol2 = Color_cursor2;
2087 *srp = SET_FGCOLOR (*srp, ccol1);
2088 *srp = SET_BGCOLOR (*srp, ccol2);
2089 #endif
2090 #ifdef MULTICHAR_SET
2091 rt1 = *srp & RS_multiMask;
2092 if (rt1 == RS_multi1) {
2093 if (o->screen.cur.col < o->TermWin.ncol - 2
2094 && ((srp[1] & RS_multiMask) == RS_multi2))
2095 morecur = 1;
2096 } else if (rt1 == RS_multi2) {
2097 if (o->screen.cur.col > 0 && ((srp[-1] & RS_multiMask) == RS_multi1))
2098 morecur = -1;
2099 }
2100 if (morecur) {
2101 srp += morecur;
2102 *srp ^= RS_RVid;
2103 }
2104 # ifndef NO_CURSORCOLOR
2105 if (morecur) {
2106 cc2 = *srp & (RS_fgMask | RS_bgMask);
2107 *srp = SET_FGCOLOR (*srp, ccol1);
2108 *srp = SET_BGCOLOR (*srp, ccol2);
2109 }
2110 # endif
2111 #endif
2112 }
2113 i = 0;
2114 if (o->oldcursor.row != -1) {
2115 /* make sure no outline cursor is left around */
2116 if (o->screen.cur.row + o->TermWin.view_start != o->oldcursor.row
2117 || o->screen.cur.col != o->oldcursor.col) {
2118 if (o->oldcursor.row < o->TermWin.nrow && o->oldcursor.col < o->TermWin.ncol) {
2119 o->drawn_text[o->oldcursor.row][o->oldcursor.col] = 0;
2120 #ifdef MULTICHAR_SET
2121 if (o->oldcursormulti) {
2122 col = o->oldcursor.col + o->oldcursormulti;
2123 if (col < o->TermWin.ncol)
2124 o->drawn_text[o->oldcursor.row][col] = 0;
2125 }
2126 #endif
2127 }
2128 if (focus || !(o->screen.flags & Screen_VisibleCursor))
2129 o->oldcursor.row = -1;
2130 else
2131 i = 1;
2132 }
2133 } else if (!focus)
2134 i = 1;
2135 if (i) {
2136 if (o->screen.cur.row + o->TermWin.view_start >= o->TermWin.nrow)
2137 o->oldcursor.row = -1;
2138 else {
2139 o->oldcursor.row = o->screen.cur.row + o->TermWin.view_start;
2140 o->oldcursor.col = o->screen.cur.col;
2141 #ifdef MULTICHAR_SET
2142 o->oldcursormulti = morecur;
2143 #endif
2144 }
2145 }
2146 /*
2147 * E: OK, now the real pass
2148 */
2149 for (row = 0; row < o->TermWin.nrow; row++) {
2150 scrrow = row + row_offset;
2151 stp = o->screen.text[scrrow];
2152 srp = o->screen.rend[scrrow];
2153 dtp = o->drawn_text[row];
2154 drp = o->drawn_rend[row];
2155 for (col = 0; col < o->TermWin.ncol; col++) {
2156 /* compare new text with old - if exactly the same then continue */
2157 rt1 = srp[col]; /* screen rendition */
2158 rt2 = drp[col]; /* drawn rendition */
2159 if ((stp[col] == dtp[col]) /* must match characters to skip */
2160 &&((rt1 == rt2) /* either rendition the same or */
2161 ||((stp[col] == ' ') /* space w/ no bg change */
2162 &&(GET_BGATTR (rt1) == GET_BGATTR (rt2))))) {
2163 #ifdef MULTICHAR_SET
2164 /* if first byte is Kanji then compare second bytes */
2165 if ((rt1 & RS_multiMask) != RS_multi1)
2166 continue;
2167 else if (stp[col + 1] == dtp[col + 1]) {
2168 /* assume no corrupt characters on the screen */
2169 col++;
2170 continue;
2171 }
2172 #else
2173 continue;
2174 #endif
2175 }
2176 /* redraw one or more characters */
2177 dtp[col] = stp[col];
2178 rend = drp[col] = srp[col];
2179
2180 len = 0;
2181 o->buffer[len++] = stp[col];
2182 ypixelc = Row2Pixel(row);
2183 ypixel = ypixelc + o->TermWin.font->ascent;
2184 xpixel = Col2Pixel (col);
2185 fontdiff = 0;
2186 wlen = 1;
2187
2188 /*
2189 * Find out the longest string we can write out at once
2190 */
2191 if (fprop == 0) { /* Fixed width font */
2192 #ifdef MULTICHAR_SET
2193 if (((rend & RS_multiMask) == RS_multi1)
2194 && col < o->TermWin.ncol - 1
2195 && ((srp[col + 1]) & RS_multiMask) == RS_multi2) {
2196 if (!wbyte) {
2197 wbyte = 1;
2198 XSetFont (o->Xdisplay, o->TermWin.gc, o->TermWin.mfont->fid);
2199 fontdiff = o->TermWin.mprop;
2200 draw_string = XDrawString16;
2201 draw_image_string = XDrawImageString16;
2202 }
2203 /* double stepping - we're in Kanji mode */
2204 for (; ++col < o->TermWin.ncol;) {
2205 /* XXX: could check sanity on 2nd byte */
2206 dtp[col] = stp[col];
2207 drp[col] = srp[col];
2208 o->buffer[len++] = stp[col];
2209 col++;
2210 if ((col == o->TermWin.ncol) || (srp[col] != rend))
2211 break;
2212 if ((stp[col] == dtp[col])
2213 && (srp[col] == drp[col])
2214 && (stp[col + 1] == dtp[col + 1]))
2215 break;
2216 if (len == o->currmaxcol)
2217 break;
2218 dtp[col] = stp[col];
2219 drp[col] = srp[col];
2220 o->buffer[len++] = stp[col];
2221 }
2222 col--;
2223 if (o->buffer[0] & 0x80)
2224 o->multichar_decode (o->buffer, len);
2225 wlen = len / 2;
2226 } else {
2227 if ((rend & RS_multiMask) == RS_multi1) {
2228 /* XXX : maybe do the same thing for RS_multi2 */
2229 /* corrupt character - you're outta there */
2230 rend &= ~RS_multiMask;
2231 drp[col] = rend; /* TODO check: may also want */
2232 dtp[col] = ' '; /* to poke into stp/srp */
2233 o->buffer[0] = ' ';
2234 }
2235 if (wbyte) {
2236 wbyte = 0;
2237 XSetFont (o->Xdisplay, o->TermWin.gc, o->TermWin.font->fid);
2238 fontdiff = o->TermWin.mprop;
2239 draw_string = XDrawString;
2240 draw_image_string = XDrawImageString;
2241 }
2242 #endif
2243 /* single stepping - `normal' mode */
2244 for (j = 0; ++col < o->TermWin.ncol - 1;) {
2245 if (rend != srp[col])
2246 break;
2247 if (len == o->currmaxcol)
2248 break;
2249 if ((stp[col] == dtp[col]) && (srp[col] == drp[col])) {
2250 #ifdef INEXPENSIVE_LOCAL_X_CALLS
2251 if (o->display_is_local)
2252 break;
2253 #endif
2254 j++;
2255 } else {
2256 j = 0;
2257 dtp[col] = stp[col];
2258 drp[col] = srp[col];
2259 }
2260 o->buffer[len++] = stp[col];
2261 }
2262 col--; /* went one too far. move back */
2263 len -= j; /* dump any matching trailing chars */
2264 wlen = len;
2265 #ifdef MULTICHAR_SET
2266 }
2267 #endif
2268 }
2269 o->buffer[len] = '\0';
2270
2271 /*
2272 * Determine the attributes for the string
2273 */
2274 fore = GET_FGCOLOR (rend);
2275 back = GET_BGCOLOR (rend);
2276 rend = GET_ATTR (rend);
2277 gcmask = 0;
2278 rvid = (rend & RS_RVid) ? 1 : 0;
2279
2280 switch (rend & RS_fontMask) {
2281 case RS_acsFont:
2282 for (i = 0; i < len; i++)
2283 if (o->buffer[i] == 0x5f)
2284 o->buffer[i] = 0x7f;
2285 else if (o->buffer[i] > 0x5f && o->buffer[i] < 0x7f)
2286 o->buffer[i] -= 0x5f;
2287 break;
2288 case RS_ukFont:
2289 for (i = 0; i < len; i++)
2290 if (o->buffer[i] == '#')
2291 o->buffer[i] = 0x1e;
2292 break;
2293 }
2294 if (rvid)
2295 SWAP_IT (fore, back, i);
2296 if (back != Color_bg) {
2297 gcvalue.background = o->PixColors[back];
2298 gcmask |= GCBackground;
2299 }
2300 if (fore != Color_fg) {
2301 gcvalue.foreground = o->PixColors[fore];
2302 gcmask |= GCForeground;
2303 }
2304 #ifndef NO_BOLDUNDERLINE
2305 else if (rend & RS_Bold) {
2306 if (o->Xdepth > 2 && o->rs[Rs_color + Color_BD]
2307 && o->PixColors[fore] != o->PixColors[Color_BD]
2308 && o->PixColors[back] != o->PixColors[Color_BD]) {
2309 gcvalue.foreground = o->PixColors[Color_BD];
2310 gcmask |= GCForeground;
2311 # ifndef VERYBOLD
2312 rend &= ~RS_Bold; /* we've taken care of it */
2313 # endif
2314 }
2315 } else if (rend & RS_Uline) {
2316 if (o->Xdepth > 2 && o->rs[Rs_color + Color_UL]
2317 && o->PixColors[fore] != o->PixColors[Color_UL]
2318 && o->PixColors[back] != o->PixColors[Color_UL]) {
2319 gcvalue.foreground = o->PixColors[Color_UL];
2320 gcmask |= GCForeground;
2321 rend &= ~RS_Uline; /* we've taken care of it */
2322 }
2323 }
2324 #endif
2325 if (gcmask)
2326 XChangeGC (o->Xdisplay, o->TermWin.gc, gcmask, &gcvalue);
2327 #ifndef NO_BOLDFONT
2328 if (!wbyte && MONO_BOLD (rend) && o->TermWin.boldFont != NULL) {
2329 bfont = 1;
2330 XSetFont (o->Xdisplay, o->TermWin.gc, o->TermWin.boldFont->fid);
2331 rend &= ~RS_Bold; /* we've taken care of it */
2332 } else if (bfont) {
2333 bfont = 0;
2334 XSetFont (o->Xdisplay, o->TermWin.gc, o->TermWin.font->fid);
2335 }
2336 #endif
2337 /*
2338 * Actually do the drawing of the string here
2339 */
2340 if (back == Color_bg) {
2341 CLEAR_CHARS(xpixel, ypixelc, len);
2342 DRAW_STRING(draw_string, xpixel, ypixel, o->buffer, wlen);
2343 } else {
2344 if (fprop || fontdiff) {
2345 gcmaskf = GCForeground;
2346 ltmp = gcvalue.foreground;
2347 gcvalue.foreground = gcvalue.background;
2348 XChangeGC(o->Xdisplay, o->TermWin.gc, gcmaskf, &gcvalue);
2349 XFillRectangle (o->Xdisplay, drawBuffer, o->TermWin.gc,
2350 xpixel, ypixelc,
2351 Width2Pixel(len), Height2Pixel(1));
2352 gcvalue.foreground = ltmp;
2353 XChangeGC(o->Xdisplay, o->TermWin.gc, gcmaskf, &gcvalue);
2354 DRAW_STRING(draw_string, xpixel, ypixel, o->buffer, wlen);
2355 } else
2356 DRAW_STRING(draw_image_string, xpixel, ypixel, o->buffer, wlen);
2357 }
2358
2359 #ifndef NO_BOLDOVERSTRIKE
2360 # ifdef NO_BOLDOVERSTRIKE_MULTI
2361 if (!wbyte)
2362 # endif
2363 if (MONO_BOLD (rend))
2364 DRAW_STRING (draw_string, xpixel + 1, ypixel, o->buffer,
2365 wlen);
2366 #endif
2367 if ((rend & RS_Uline) && (o->TermWin.font->descent > 1))
2368 XDrawLine (o->Xdisplay, drawBuffer, o->TermWin.gc,
2369 xpixel, ypixel + 1,
2370 xpixel + Width2Pixel (len) - 1, ypixel + 1);
2371 if (gcmask) { /* restore normal colours */
2372 gcvalue.foreground = o->PixColors[Color_fg];
2373 gcvalue.background = o->PixColors[Color_bg];
2374 XChangeGC (o->Xdisplay, o->TermWin.gc, gcmask, &gcvalue);
2375 }
2376 }
2377 }
2378
2379 /*
2380 * F: cleanup cursor and display outline cursor in necessary
2381 */
2382 if (o->screen.flags & Screen_VisibleCursor) {
2383 if (focus) {
2384 srp = &(o->screen.rend[currow][o->screen.cur.col]);
2385 *srp ^= RS_RVid;
2386 #ifndef NO_CURSORCOLOR
2387 *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc1;
2388 #endif
2389 if (morecur) {
2390 srp += morecur;
2391 *srp ^= RS_RVid;
2392 #if defined(MULTICHAR_SET) && ! defined(NO_CURSORCOLOR)
2393 *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc2;
2394 #endif
2395 }
2396 } else if (o->oldcursor.row >= 0) {
2397 col = o->oldcursor.col + morecur;
2398 wbyte = morecur ? 1 : 0;
2399 #ifndef NO_CURSORCOLOR
2400 gcmask = 0;
2401 if (o->Xdepth > 2 && o->rs[Rs_color + Color_cursor]) {
2402 gcvalue.foreground = o->PixColors[Color_cursor];
2403 gcmask = GCForeground;
2404 XChangeGC (o->Xdisplay, o->TermWin.gc, gcmask, &gcvalue);
2405 gcvalue.foreground = o->PixColors[Color_fg];
2406 }
2407 #endif
2408 XDrawRectangle (o->Xdisplay, drawBuffer, o->TermWin.gc,
2409 Col2Pixel (col), Row2Pixel (o->oldcursor.row),
2410 Width2Pixel (1 + wbyte) - 1, Height2Pixel (1) - 1);
2411 #ifndef NO_CURSORCOLOR
2412 if (gcmask) /* restore normal colours */
2413 XChangeGC (o->Xdisplay, o->TermWin.gc, gcmask, &gcvalue);
2414 #endif
2415 }
2416 }
2417 /*
2418 * G: cleanup selection
2419 */
2420 rxvtlib_scr_reverse_selection (o);
2421
2422 /*
2423 * H: other general cleanup
2424 */
2425 #if defined(XPM_BACKGROUND) && defined(XPM_BUFFERING)
2426 XClearWindow (o->Xdisplay, o->TermWin.vt);
2427 #else
2428 if (boldlast) /* clear the whole screen height */
2429 XClearArea (o->Xdisplay, o->TermWin.vt, TermWin_TotalWidth () - 2, 0,
2430 1, TermWin_TotalHeight () - 1, 0);
2431 #endif
2432 if (type & SMOOTH_REFRESH)
2433 XSync (o->Xdisplay, False);
2434
2435 o->want_refresh = 0; /* screen is current */
2436 }
2437
2438 /* EXTPROTO */
2439 void rxvtlib_scr_clear (rxvtlib *o)
2440 {
2441 if (!o->TermWin.mapped)
2442 return;
2443 #ifdef TRANSPARENT
2444 if (o->Options & Opt_transparent) {
2445 int i;
2446
2447 for (i = KNOW_PARENTS; i--;)
2448 if (o->TermWin.parent[i] != None)
2449 XClearWindow (o->Xdisplay, o->TermWin.parent[i]);
2450 }
2451 #endif
2452 XClearWindow (o->Xdisplay, o->TermWin.vt);
2453 }
2454
2455 /* ------------------------------------------------------------------------- */
2456 /* INTPROTO */
2457 void rxvtlib_scr_reverse_selection (rxvtlib *o)
2458 {
2459 int i, col, row, end_row;
2460 rend_t *srp;
2461
2462 end_row = o->TermWin.saveLines - o->TermWin.view_start;
2463 if (o->selection.op && o->current_screen == o->selection.screen) {
2464 i = o->selection.beg.row + o->TermWin.saveLines;
2465 row = o->selection.end.row + o->TermWin.saveLines;
2466 if (i >= end_row)
2467 col = o->selection.beg.col;
2468 else {
2469 col = 0;
2470 i = end_row;
2471 }
2472 end_row += o->TermWin.nrow;
2473 for (; i < row && i < end_row; i++, col = 0)
2474 for (srp = o->screen.rend[i]; col < o->TermWin.ncol; col++)
2475 srp[col] ^= RS_RVid;
2476 if (i == row && i < end_row)
2477 for (srp = o->screen.rend[i]; col < o->selection.end.col; col++)
2478 srp[col] ^= RS_RVid;
2479 }
2480 }
2481
2482 /* ------------------------------------------------------------------------- *
2483 * CHARACTER SELECTION *
2484 * ------------------------------------------------------------------------- */
2485
2486 /*
2487 * -TermWin.nscrolled <= (selection row) <= TermWin.nrow - 1
2488 */
2489 /* INTPROTO */
2490 void rxvtlib_selection_check (rxvtlib *o, int check_more)
2491 {
2492 row_col_t pos;
2493
2494 if ((o->selection.beg.row < -o->TermWin.nscrolled)
2495 || (o->selection.beg.row >= o->TermWin.nrow)
2496 || (o->selection.mark.row < -o->TermWin.nscrolled)
2497 || (o->selection.mark.row >= o->TermWin.nrow)
2498 || (o->selection.end.row < -o->TermWin.nscrolled)
2499 || (o->selection.end.row >= o->TermWin.nrow))
2500 CLEAR_ALL_SELECTION;
2501
2502 if (check_more == 1 && o->current_screen == o->selection.screen) {
2503 /* check for cursor position */
2504 pos.row = o->screen.cur.row;
2505 pos.col = o->screen.cur.col;
2506 if (!ROWCOL_IS_BEFORE (pos, o->selection.beg)
2507 && ROWCOL_IS_BEFORE (pos, o->selection.end))
2508 CLEAR_SELECTION;
2509 } else if (check_more == 2) {
2510 pos.row = 0;
2511 pos.col = 0;
2512 if (ROWCOL_IS_BEFORE (o->selection.beg, pos)
2513 && ROWCOL_IS_AFTER (o->selection.end, pos))
2514 CLEAR_SELECTION;
2515 } else if (check_more == 3) {
2516 pos.row = 0;
2517 pos.col = 0;
2518 if (ROWCOL_IS_AFTER (o->selection.end, pos))
2519 CLEAR_SELECTION;
2520 }
2521 }
2522
2523 /* ------------------------------------------------------------------------- */
2524 /*
2525 * Paste a selection direct to the command
2526 */
2527 /* INTPROTO */
2528 void rxvtlib_PasteIt (rxvtlib *o, const unsigned char *data, unsigned int nitems)
2529 {
2530 int num;
2531 const unsigned char *p;
2532 const unsigned char cr = '\r';
2533
2534 for (p = data, num = 0; nitems--; p++)
2535 if (*p != '\n')
2536 num++;
2537 else {
2538 rxvtlib_tt_write (o, data, num);
2539 rxvtlib_tt_write (o, &cr, 1);
2540 data += (num + 1);
2541 num = 0;
2542 }
2543 if (num)
2544 rxvtlib_tt_write (o, data, num);
2545 }
2546
2547 /* ------------------------------------------------------------------------- */
2548 /*
2549 * Respond to a notification that a primary selection has been sent
2550 * EXT: SelectionNotify
2551 */
2552 /* EXTPROTO */
2553 int _rxvtlib_selection_paste (rxvtlib * o, Window win, unsigned int prop, int Delete)
2554 {
2555 long nread;
2556 unsigned long bytes_after;
2557 XTextProperty ct;
2558
2559 #ifdef MULTICHAR_SET
2560 int dummy_count;
2561 char **cl;
2562 #endif
2563
2564 D_SELECT ((stderr, "selection_paste(%08x, %u, %d)", win, prop, Delete));
2565 if (prop == None)
2566 return 1;
2567 for (nread = 0, bytes_after = 1; bytes_after > 0; nread += ct.nitems) {
2568 if ((XGetWindowProperty (o->Xdisplay, win, prop, (nread / 4), PROP_SIZE,
2569 Delete, AnyPropertyType, &ct.encoding,
2570 &ct.format, &ct.nitems, &bytes_after, &ct.value) != Success)) {
2571 XFree (ct.value);
2572 return 1;
2573 }
2574 if (ct.value == NULL)
2575 continue;
2576 #ifdef MULTICHAR_SET
2577 if (XmbTextPropertyToTextList (o->Xdisplay, &ct, &cl, &dummy_count) == Success && cl) {
2578 rxvtlib_PasteIt (o, cl[0], STRLEN (cl[0]));
2579 XFreeStringList (cl);
2580 } else
2581 #endif
2582 rxvtlib_PasteIt (o, ct.value, ct.nitems);
2583 XFree (ct.value);
2584 }
2585 if (!nread)
2586 return 1;
2587 return 0;
2588 }
2589
2590 /*
2591 * Respond to a notification that a primary selection has been sent
2592 * repeated in editwidget.c
2593 */
2594 void rxvtlib_selection_paste (rxvtlib * o, Window win, unsigned int prop, int delete_prop)
2595 {
2596 struct timeval tv, tv_start;
2597 long nread;
2598 unsigned long bytes_after;
2599 Atom actual_type;
2600 int actual_fmt;
2601 unsigned long nitems;
2602 unsigned char *s = 0;
2603 if (prop == None)
2604 return;
2605 nread = 0;
2606 if (XGetWindowProperty
2607 (o->Xdisplay, win, prop, 0, 8, False, AnyPropertyType, &actual_type, &actual_fmt, &nitems,
2608 &bytes_after, &s) != Success) {
2609 XFree (s);
2610 return;
2611 }
2612 XFree (s);
2613 if (actual_type != XInternAtom (o->Xdisplay, "INCR", False)) {
2614 _rxvtlib_selection_paste (o, win, prop, delete_prop);
2615 return;
2616 }
2617 XDeleteProperty (o->Xdisplay, win, prop);
2618 gettimeofday (&tv_start, 0);
2619 for (;;) {
2620 long t;
2621 fd_set r;
2622 XEvent xe;
2623 if (XCheckMaskEvent (o->Xdisplay, PropertyChangeMask, &xe)) {
2624 if (xe.type == PropertyNotify && xe.xproperty.state == PropertyNewValue) {
2625 /* time between arrivals of data */
2626 gettimeofday (&tv_start, 0);
2627 if (_rxvtlib_selection_paste (o, win, prop, True))
2628 break;
2629 }
2630 } else {
2631 tv.tv_sec = 0;
2632 tv.tv_usec = 10000;
2633 FD_ZERO (&r);
2634 FD_SET (ConnectionNumber (o->Xdisplay), &r);
2635 select (ConnectionNumber (o->Xdisplay) + 1, &r, 0, 0, &tv);
2636 if (FD_ISSET (ConnectionNumber (o->Xdisplay), &r))
2637 continue;
2638 }
2639 gettimeofday (&tv, 0);
2640 t = (tv.tv_sec - tv_start.tv_sec) * 1000000L + (tv.tv_usec - tv_start.tv_usec);
2641 /* no data for five seconds, so quit */
2642 if (t > 5000000L)
2643 break;
2644 }
2645 }
2646
2647 #ifndef STANDALONE
2648 extern struct edit_selection selection;
2649 #endif
2650
2651 /* ------------------------------------------------------------------------- */
2652 /*
2653 * Request the current primary selection
2654 * EXT: button 2 release
2655 */
2656 /* EXTPROTO */
2657 void rxvtlib_selection_request (rxvtlib *o, Time tm, int x, int y)
2658 {
2659 Atom prop;
2660
2661 #ifdef MULTICHAR_SET
2662 Atom ct;
2663 #endif
2664
2665 D_SELECT ((stderr, "selection_request(%ld, %d, %d)", tm, x, y));
2666 if (x < 0 || x >= o->TermWin.width || y < 0 || y >= o->TermWin.height)
2667 return; /* outside window */
2668
2669 if (o->selection.text != NULL)
2670 rxvtlib_PasteIt (o, o->selection.text, o->selection.len); /* internal selection */
2671 #if 0
2672 #ifndef STANDALONE
2673 else if (selection.text != NULL)
2674 rxvtlib_PasteIt (o, selection.text, selection.len); /* cooledit selection */
2675 #endif
2676 #endif
2677 else if (XGetSelectionOwner (o->Xdisplay, XA_PRIMARY) == None)
2678 rxvtlib_selection_paste (o, Xroot, XA_CUT_BUFFER0, False);
2679 else {
2680 prop = XInternAtom (o->Xdisplay, "VT_SELECTION", False);
2681 #ifdef MULTICHAR_SET
2682 ct = XInternAtom (o->Xdisplay, "COMPOUND_TEXT", False);
2683 XConvertSelection (o->Xdisplay, XA_PRIMARY, ct, prop, o->TermWin.vt, tm);
2684 #else
2685 XConvertSelection (o->Xdisplay, XA_PRIMARY, XA_STRING, prop, o->TermWin.vt,
2686 tm);
2687 #endif
2688 }
2689 }
2690
2691 /* ------------------------------------------------------------------------- */
2692 /*
2693 * Clear all selected text
2694 * EXT: SelectionClear
2695 */
2696 /* EXTPROTO */
2697 void rxvtlib_selection_clear (rxvtlib *o)
2698 {
2699 #ifdef STANDALONE
2700 D_SELECT ((stderr, "selection_clear()"));
2701
2702 o->want_refresh = 1;
2703 if (o->selection.text)
2704 FREE (o->selection.text);
2705 o->selection.text = NULL;
2706 o->selection.len = 0;
2707 CLEAR_SELECTION;
2708 #else
2709 o->want_refresh = 1;
2710 selection_clear ();
2711 CLEAR_SELECTION;
2712 #endif
2713 }
2714
2715 extern Atom ATOM_ICCCM_P2P_CLIPBOARD;
2716
2717 /* ------------------------------------------------------------------------- */
2718 /*
2719 * Copy a selection into the cut buffer
2720 * EXT: button 1 or 3 release
2721 */
2722 /* EXTPROTO */
2723 void rxvtlib_selection_make (rxvtlib *o, Time tm)
2724 {
2725 int i, col, end_col, row, end_row;
2726 unsigned char *new_selection_text;
2727 char *str;
2728 text_t *t;
2729
2730 D_SELECT (
2731 (stderr,
2732 "selection_make(): selection.op=%d, selection.clicks=%d",
2733 o->selection.op, o->selection.clicks));
2734 switch (o->selection.op) {
2735 case SELECTION_CONT:
2736 break;
2737 case SELECTION_INIT:
2738 CLEAR_SELECTION;
2739 /* FALLTHROUGH */
2740 case SELECTION_BEGIN:
2741 o->selection.op = SELECTION_DONE;
2742 /* FALLTHROUGH */
2743 default:
2744 return;
2745 }
2746 o->selection.op = SELECTION_DONE;
2747
2748 if (o->selection.clicks == 4)
2749 return; /* nothing selected, go away */
2750
2751 i = (o->selection.end.row - o->selection.beg.row + 1) * (o->TermWin.ncol + 1) + 1;
2752 str = MALLOC (i * sizeof (char));
2753
2754 new_selection_text = (unsigned char *)str;
2755
2756 col = max (o->selection.beg.col, 0);
2757 row = o->selection.beg.row + o->TermWin.saveLines;
2758 end_row = o->selection.end.row + o->TermWin.saveLines;
2759 /*
2760 * A: rows before end row
2761 */
2762 for (; row < end_row; row++) {
2763 t = &(o->screen.text[row][col]);
2764 if ((end_col = o->screen.tlen[row]) == -1)
2765 end_col = o->TermWin.ncol;
2766 for (; col < end_col; col++)
2767 *str++ = *t++;
2768 col = 0;
2769 if (o->screen.tlen[row] != -1)
2770 *str++ = '\n';
2771 }
2772 /*
2773 * B: end row
2774 */
2775 t = &(o->screen.text[row][col]);
2776 end_col = o->screen.tlen[row];
2777 if (end_col == -1 || o->selection.end.col <= end_col)
2778 end_col = o->selection.end.col;
2779 MIN_IT (end_col, o->TermWin.ncol); /* CHANGE */
2780 for (; col < end_col; col++)
2781 *str++ = *t++;
2782 #ifndef NO_OLD_SELECTION
2783 if (o->selection_style == OLD_SELECT)
2784 if (end_col == o->TermWin.ncol)
2785 *str++ = '\n';
2786 #endif
2787 #ifndef NO_NEW_SELECTION
2788 if (o->selection_style != OLD_SELECT)
2789 if (end_col != o->selection.end.col)
2790 *str++ = '\n';
2791 #endif
2792 *str = '\0';
2793 if ((i = strlen ((char *)new_selection_text)) == 0) {
2794 FREE (new_selection_text);
2795 return;
2796 }
2797 #ifndef STANDALONE
2798 selection_clear ();
2799 #endif
2800 o->selection.len = i;
2801 if (o->selection.text)
2802 FREE (o->selection.text);
2803 o->selection.text = new_selection_text;
2804
2805 XSetSelectionOwner (o->Xdisplay, XA_PRIMARY, o->TermWin.vt, tm);
2806 if (XGetSelectionOwner (o->Xdisplay, XA_PRIMARY) != o->TermWin.vt)
2807 print_error ("can't get primary selection");
2808 XSetSelectionOwner (o->Xdisplay, ATOM_ICCCM_P2P_CLIPBOARD, o->TermWin.vt, tm);
2809 XChangeProperty (o->Xdisplay, Xroot, XA_CUT_BUFFER0, XA_STRING, 8,
2810 PropModeReplace, o->selection.text, o->selection.len);
2811 D_SELECT ((stderr, "selection_make(): selection.len=%d", o->selection.len));
2812 }
2813
2814 /* ------------------------------------------------------------------------- */
2815 /*
2816 * Mark or select text based upon number of clicks: 1, 2, or 3
2817 * EXT: button 1 press
2818 */
2819 /* EXTPROTO */
2820 void rxvtlib_selection_click (rxvtlib *o, int clicks, int x, int y)
2821 {
2822 /* int r, c;
2823 * row_col_t ext_beg, ext_end;
2824 */
2825
2826 D_SELECT ((stderr, "selection_click(%d, %d, %d)", clicks, x, y));
2827
2828 clicks = ((clicks - 1) % 3) + 1;
2829 o->selection.clicks = clicks; /* save clicks so extend will work */
2830
2831 rxvtlib_selection_start_colrow (o, Pixel2Col (x), Pixel2Row (y));
2832 if (clicks == 2 || clicks == 3)
2833 rxvtlib_selection_extend_colrow (o, o->selection.mark.col,
2834 o->selection.mark.row + o->TermWin.view_start, 0, /* button 3 */
2835 1, /* button press */
2836 0); /* click change */
2837 }
2838
2839 /* ------------------------------------------------------------------------- */
2840 /*
2841 * Mark a selection at the specified col/row
2842 */
2843 /* INTPROTO */
2844 void rxvtlib_selection_start_colrow (rxvtlib *o, int col, int row)
2845 {
2846 o->want_refresh = 1;
2847 o->selection.mark.col = col;
2848 o->selection.mark.row = row - o->TermWin.view_start;
2849 MAX_IT (o->selection.mark.row, -o->TermWin.nscrolled);
2850 MIN_IT (o->selection.mark.row, o->TermWin.nrow - 1);
2851 MAX_IT (o->selection.mark.col, 0);
2852 MIN_IT (o->selection.mark.col, o->TermWin.ncol - 1);
2853
2854 if (o->selection.op) { /* clear the old selection */
2855 o->selection.beg.row = o->selection.end.row = o->selection.mark.row;
2856 o->selection.beg.col = o->selection.end.col = o->selection.mark.col;
2857 }
2858 o->selection.op = SELECTION_INIT;
2859 o->selection.screen = o->current_screen;
2860 }
2861
2862 /* ------------------------------------------------------------------------- */
2863 /*
2864 * Word select: select text for 2 clicks
2865 * We now only find out the boundary in one direction
2866 */
2867
2868 /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
2869
2870 /* INTPROTO */
2871 void rxvtlib_selection_delimit_word (rxvtlib *o, int dirn, const row_col_t * mark,
2872 row_col_t * ret)
2873 {
2874 int col, row, dirnadd, tcol, trow, w1, w2;
2875 row_col_t bound;
2876 text_t *stp;
2877 rend_t *srp;
2878
2879 if (o->selection.clicks != 2)
2880 return; /* Go away: we only handle double clicks */
2881
2882 if (dirn == UP) {
2883 bound.row = o->TermWin.saveLines - o->TermWin.nscrolled - 1;
2884 bound.col = 0;
2885 dirnadd = -1;
2886 } else {
2887 bound.row = o->TermWin.saveLines + o->TermWin.nrow;
2888 bound.col = o->TermWin.ncol - 1;
2889 dirnadd = 1;
2890 }
2891 row = mark->row + o->TermWin.saveLines;
2892 col = mark->col;
2893 MAX_IT (col, 0);
2894 /* find the edge of a word */
2895 stp = &(o->screen.text[row][col]);
2896 w1 = DELIMIT_TEXT (*stp);
2897
2898 if (o->selection_style != NEW_SELECT) {
2899 if (w1 == 1) {
2900 stp += dirnadd;
2901 if (DELIMIT_TEXT (*stp) == 1)
2902 goto Old_Word_Selection_You_Die;
2903 col += dirnadd;
2904 }
2905 w1 = 0;
2906 }
2907 srp = (&o->screen.rend[row][col]);
2908 w2 = DELIMIT_REND (*srp);
2909
2910 for (;;) {
2911 for (; col != bound.col; col += dirnadd) {
2912 stp += dirnadd;
2913 if (DELIMIT_TEXT (*stp) != w1)
2914 break;
2915 srp += dirnadd;
2916 if (DELIMIT_REND (*srp) != w2)
2917 break;
2918 }
2919 if ((col == bound.col) && (row != bound.row)) {
2920 if (o->screen.tlen[(row - (dirn == UP))] == -1) {
2921 trow = row + dirnadd;
2922 tcol = (dirn == UP) ? (o->TermWin.ncol - 1) : 0;
2923 if (o->screen.text[trow] == NULL)
2924 break;
2925 stp = &(o->screen.text[trow][tcol]);
2926 srp = &(o->screen.rend[trow][tcol]);
2927 if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2)
2928 break;
2929 row = trow;
2930 col = tcol;
2931 continue;
2932 }
2933 }
2934 break;
2935 }
2936 Old_Word_Selection_You_Die:
2937 D_SELECT (
2938 (stderr,
2939 "selection_delimit_word(%s,...) @ (r:%3d, c:%3d) has boundary (r:%3d, c:%3d)",
2940 (dirn == UP ? "up " : "down"), mark->row, mark->col,
2941 row - o->TermWin.saveLines, col));
2942
2943 if (dirn == DN)
2944 col++; /* put us on one past the end */
2945
2946 /* Poke the values back in */
2947 ret->row = row - o->TermWin.saveLines;
2948 ret->col = col;
2949 }
2950
2951 /* ------------------------------------------------------------------------- */
2952 /*
2953 * Extend the selection to the specified x/y pixel location
2954 * EXT: button 3 press; button 1 or 3 drag
2955 * flag == 0 ==> button 1
2956 * flag == 1 ==> button 3 press
2957 * flag == 2 ==> button 3 motion
2958 */
2959 /* EXTPROTO */
2960 void rxvtlib_selection_extend (rxvtlib *o, int x, int y, int flag)
2961 {
2962 int col, row;
2963
2964 col = Pixel2Col (x);
2965 row = Pixel2Row (y);
2966 MAX_IT (row, 0);
2967 MIN_IT (row, o->TermWin.nrow - 1);
2968 MAX_IT (col, 0);
2969 MIN_IT (col, o->TermWin.ncol);
2970 #ifndef NO_NEW_SELECTION
2971 /*
2972 * If we're selecting characters (single click) then we must check first
2973 * if we are at the same place as the original mark. If we are then
2974 * select nothing. Otherwise, if we're to the right of the mark, you have to
2975 * be _past_ a character for it to be selected.
2976 */
2977 if (o->selection_style != OLD_SELECT) {
2978 if (((o->selection.clicks % 3) == 1) && !flag
2979 && (col == o->selection.mark.col
2980 && (row == o->selection.mark.row + o->TermWin.view_start))) {
2981 /* select nothing */
2982 o->selection.beg.row = o->selection.end.row = 0;
2983 o->selection.beg.col = o->selection.end.col = 0;
2984 o->selection.clicks = 4;
2985 D_SELECT ((stderr, "selection_extend() selection.clicks = 4"));
2986 return;
2987 }
2988 }
2989 #endif
2990 if (o->selection.clicks == 4)
2991 o->selection.clicks = 1;
2992 rxvtlib_selection_extend_colrow (o, col, row, !!flag, /* ? button 3 */
2993 flag == 1 ? 1 : 0, /* ? button press */
2994 0); /* no click change */
2995 }
2996
2997 #ifdef MULTICHAR_SET
2998 /* INTPROTO */
2999 void rxvtlib_selection_adjust_kanji (rxvtlib *o)
3000 {
3001 int c, r;
3002
3003 if (o->selection.beg.col > 0) {
3004 r = o->selection.beg.row + o->TermWin.saveLines;
3005 c = o->selection.beg.col;
3006 if (((o->screen.rend[r][c] & RS_multiMask) == RS_multi2)
3007 && ((o->screen.rend[r][c - 1] & RS_multiMask) == RS_multi1))
3008 o->selection.beg.col--;
3009 }
3010 if (o->selection.end.col < o->TermWin.ncol) {
3011 r = o->selection.end.row + o->TermWin.saveLines;
3012 c = o->selection.end.col;
3013 if (((o->screen.rend[r][c - 1] & RS_multiMask) == RS_multi1)
3014 && ((o->screen.rend[r][c] & RS_multiMask) == RS_multi2))
3015 o->selection.end.col++;
3016 }
3017 }
3018 #endif /* MULTICHAR_SET */
3019
3020 /* ------------------------------------------------------------------------- */
3021 /*
3022 * Extend the selection to the specified col/row
3023 */
3024 /* INTPROTO */
3025 void rxvtlib_selection_extend_colrow (rxvtlib *o, int col, int row, int button3,
3026 int buttonpress, int clickchange)
3027 {
3028 int end_col;
3029 row_col_t pos;
3030 enum {
3031 LEFT, RIGHT
3032 } closeto = RIGHT;
3033
3034 D_SELECT (
3035 (stderr, "selection_extend_colrow(c:%d, r:%d, %d, %d) clicks:%d",
3036 col, row, button3, buttonpress, o->selection.clicks));
3037 D_SELECT (
3038 (stderr,
3039 "selection_extend_colrow() ENT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)",
3040 o->selection.beg.row, o->selection.beg.col, o->selection.mark.row,
3041 o->selection.mark.col, o->selection.end.row, o->selection.end.col));
3042
3043 o->want_refresh = 1;
3044 switch (o->selection.op) {
3045 case SELECTION_INIT:
3046 CLEAR_SELECTION;
3047 o->selection.op = SELECTION_BEGIN;
3048 /* FALLTHROUGH */
3049 case SELECTION_BEGIN:
3050 if (row != o->selection.mark.row || col != o->selection.mark.col
3051 || (!button3 && buttonpress))
3052 o->selection.op = SELECTION_CONT;
3053 break;
3054 case SELECTION_DONE:
3055 o->selection.op = SELECTION_CONT;
3056 /* FALLTHROUGH */
3057 case SELECTION_CONT:
3058 break;
3059 case SELECTION_CLEAR:
3060 rxvtlib_selection_start_colrow (o, col, row);
3061 /* FALLTHROUGH */
3062 default:
3063 return;
3064 }
3065
3066 pos.col = col;
3067 pos.row = row;
3068
3069 pos.row -= o->TermWin.view_start; /* adjust for scroll */
3070
3071 #ifndef NO_OLD_SELECTION
3072 /*
3073 * This mimics some of the selection behaviour of version 2.20 and before.
3074 * There are no ``selection modes'', button3 is always character extension.
3075 * Note: button3 drag is always available, c.f. v2.20
3076 * Selection always terminates (left or right as appropriate) at the mark.
3077 */
3078 if (o->selection_style == OLD_SELECT) {
3079 static int hate_those_clicks = 0; /* a.k.a. keep mark position */
3080
3081 if (o->selection.clicks == 1 || button3) {
3082 if (hate_those_clicks) {
3083 hate_those_clicks = 0;
3084 if (o->selection.clicks == 1) {
3085 o->selection.beg.row = o->selection.mark.row;
3086 o->selection.beg.col = o->selection.mark.col;
3087 } else {
3088 o->selection.mark.row = o->selection.beg.row;
3089 o->selection.mark.col = o->selection.beg.col;
3090 }
3091 }
3092 if (ROWCOL_IS_BEFORE (pos, o->selection.mark)) {
3093 o->selection.end.row = o->selection.mark.row;
3094 o->selection.end.col = o->selection.mark.col + 1;
3095 o->selection.beg.row = pos.row;
3096 o->selection.beg.col = pos.col;
3097 } else {
3098 o->selection.beg.row = o->selection.mark.row;
3099 o->selection.beg.col = o->selection.mark.col;
3100 o->selection.end.row = pos.row;
3101 o->selection.end.col = pos.col + 1;
3102 }
3103 # ifdef MULTICHAR_SET
3104 rxvtlib_selection_adjust_kanji (o);
3105 # endif /* MULTICHAR_SET */
3106 } else if (o->selection.clicks == 2) {
3107 rxvtlib_selection_delimit_word (o, UP, &(o->selection.mark), &(o->selection.beg));
3108 rxvtlib_selection_delimit_word (o, DN, &(o->selection.mark), &(o->selection.end));
3109 hate_those_clicks = 1;
3110 } else if (o->selection.clicks == 3) {
3111 o->selection.beg.row = o->selection.end.row = o->selection.mark.row;
3112 o->selection.beg.col = 0;
3113 o->selection.end.col = o->TermWin.ncol;
3114 hate_those_clicks = 1;
3115 }
3116 D_SELECT (
3117 (stderr,
3118 "selection_extend_colrow() EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)",
3119 o->selection.beg.row, o->selection.beg.col, o->selection.mark.row,
3120 o->selection.mark.col, o->selection.end.row, o->selection.end.col));
3121 return;
3122 }
3123 #endif /* ! NO_OLD_SELECTION */
3124 #ifndef NO_NEW_SELECTION
3125 /* selection_style must not be OLD_SELECT to get here */
3126 /*
3127 * This is mainly xterm style selection with a couple of differences, mainly
3128 * in the way button3 drag extension works.
3129 * We're either doing: button1 drag; button3 press; or button3 drag
3130 * a) button1 drag : select around a midpoint/word/line - that point/word/line
3131 * is always at the left/right edge of the selection.
3132 * b) button3 press: extend/contract character/word/line at whichever edge of
3133 * the selection we are closest to.
3134 * c) button3 drag : extend/contract character/word/line - we select around
3135 * a point/word/line which is either the start or end of the selection
3136 * and it was decided by whichever point/word/line was `fixed' at the
3137 * time of the most recent button3 press
3138 */
3139 if (button3 && buttonpress) { /* button3 press */
3140 /*
3141 * first determine which edge of the selection we are closest to
3142 */
3143 if (ROWCOL_IS_BEFORE (pos, o->selection.beg)
3144 || (!ROWCOL_IS_AFTER (pos, o->selection.end)
3145 && (((pos.col - o->selection.beg.col)
3146 + ((pos.row - o->selection.beg.row) * o->TermWin.ncol))
3147 < ((o->selection.end.col - pos.col)
3148 + ((o->selection.end.row - pos.row) * o->TermWin.ncol)))))
3149 closeto = LEFT;
3150 if (closeto == LEFT) {
3151 o->selection.beg.row = pos.row;
3152 o->selection.beg.col = pos.col;
3153 o->selection.mark.row = o->selection.end.row;
3154 o->selection.mark.col = o->selection.end.col - (o->selection.clicks == 2);
3155 } else {
3156 o->selection.end.row = pos.row;
3157 o->selection.end.col = pos.col;
3158 o->selection.mark.row = o->selection.beg.row;
3159 o->selection.mark.col = o->selection.beg.col;
3160 }
3161 } else { /* button1 drag or button3 drag */
3162 if (ROWCOL_IS_AFTER (o->selection.mark, pos)) {
3163 if ((o->selection.mark.row == o->selection.end.row)
3164 && (o->selection.mark.col == o->selection.end.col)
3165 && clickchange && o->selection.clicks == 2)
3166 o->selection.mark.col--;
3167 o->selection.beg.row = pos.row;
3168 o->selection.beg.col = pos.col;
3169 o->selection.end.row = o->selection.mark.row;
3170 o->selection.end.col = o->selection.mark.col + (o->selection.clicks == 2);
3171 } else {
3172 o->selection.beg.row = o->selection.mark.row;
3173 o->selection.beg.col = o->selection.mark.col;
3174 o->selection.end.row = pos.row;
3175 o->selection.end.col = pos.col;
3176 }
3177 }
3178
3179 if (o->selection.clicks == 1) {
3180 end_col = o->screen.tlen[o->selection.beg.row + o->TermWin.saveLines];
3181 if (end_col != -1 && o->selection.beg.col > end_col) {
3182 #if 1
3183 o->selection.beg.col = o->TermWin.ncol;
3184 #else
3185 if (o->selection.beg.row != o->selection.end.row)
3186 o->selection.beg.col = o->TermWin.ncol;
3187 else
3188 o->selection.beg.col = o->selection.mark.col;
3189 #endif
3190 }
3191 end_col = o->screen.tlen[o->selection.end.row + o->TermWin.saveLines];
3192 if (end_col != -1 && o->selection.end.col > end_col)
3193 o->selection.end.col = o->TermWin.ncol;
3194
3195 # ifdef MULTICHAR_SET
3196 rxvtlib_selection_adjust_kanji (o);
3197 # endif /* MULTICHAR_SET */
3198 } else if (o->selection.clicks == 2) {
3199 if (ROWCOL_IS_AFTER (o->selection.end, o->selection.beg))
3200 o->selection.end.col--;
3201 rxvtlib_selection_delimit_word (o, UP, &(o->selection.beg), &(o->selection.beg));
3202 rxvtlib_selection_delimit_word (o, DN, &(o->selection.end), &(o->selection.end));
3203 } else if (o->selection.clicks == 3) {
3204 if (ROWCOL_IS_AFTER (o->selection.mark, o->selection.beg))
3205 o->selection.mark.col++;
3206 o->selection.beg.col = 0;
3207 o->selection.end.col = o->TermWin.ncol;
3208 }
3209 if (button3 && buttonpress) { /* mark may need to be changed */
3210 if (closeto == LEFT) {
3211 o->selection.mark.row = o->selection.end.row;
3212 o->selection.mark.col = o->selection.end.col - (o->selection.clicks == 2);
3213 } else {
3214 o->selection.mark.row = o->selection.beg.row;
3215 o->selection.mark.col = o->selection.beg.col;
3216 }
3217 }
3218 D_SELECT (
3219 (stderr,
3220 "selection_extend_colrow() EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)",
3221 o->selection.beg.row, o->selection.beg.col, o->selection.mark.row,
3222 o->selection.mark.col, o->selection.end.row, o->selection.end.col));
3223 #endif /* ! NO_NEW_SELECTION */
3224 }
3225
3226 /* ------------------------------------------------------------------------- */
3227 /*
3228 * Double click on button 3 when already selected
3229 * EXT: button 3 double click
3230 */
3231 /* EXTPROTO */
3232 void rxvtlib_selection_rotate (rxvtlib *o, int x, int y)
3233 {
3234 o->selection.clicks = o->selection.clicks % 3 + 1;
3235 rxvtlib_selection_extend_colrow (o, Pixel2Col (x), Pixel2Row (y), 1, 0, 1);
3236 }
3237
3238 /* ------------------------------------------------------------------------- */
3239 /*
3240 * On some systems, the Atom typedef is 64 bits wide. We need to have a type
3241 * that is exactly 32 bits wide, because a format of 64 is not allowed by
3242 * the X11 protocol.
3243 */
3244
3245 /* ------------------------------------------------------------------------- */
3246 /*
3247 * Respond to a request for our current selection
3248 * EXT: SelectionRequest
3249 */
3250 /* EXTPROTO */
3251 void rxvtlib_selection_send (rxvtlib *o, const XSelectionRequestEvent * rq)
3252 {
3253 XEvent ev;
3254 Atom target_list[4];
3255 Atom target;
3256 static Atom xa_targets = None;
3257 static Atom xa_compound_text = None;
3258 static Atom xa_text = None;
3259 XTextProperty ct;
3260 XICCEncodingStyle style;
3261 char *cl[4];
3262
3263 memset(&ev, 0, sizeof(ev));
3264 memset(&ct, 0, sizeof(ct));
3265 memset(&style, 0, sizeof(style));
3266
3267 if (xa_text == None)
3268 xa_text = XInternAtom (o->Xdisplay, "TEXT", False);
3269 if (xa_compound_text == None)
3270 xa_compound_text = XInternAtom (o->Xdisplay, "COMPOUND_TEXT", False);
3271 if (xa_targets == None)
3272 xa_targets = XInternAtom (o->Xdisplay, "TARGETS", False);
3273
3274 ev.xselection.type = SelectionNotify;
3275 ev.xselection.property = None;
3276 ev.xselection.display = rq->display;
3277 ev.xselection.requestor = rq->requestor;
3278 ev.xselection.selection = rq->selection;
3279 ev.xselection.target = rq->target;
3280 ev.xselection.time = rq->time;
3281
3282 if (rq->target == xa_targets) {
3283 target_list[0] = (Atom32) xa_targets;
3284 target_list[1] = (Atom32) XA_STRING;
3285 target_list[2] = (Atom32) xa_text;
3286 target_list[3] = (Atom32) xa_compound_text;
3287
3288 XChangeProperty (o->Xdisplay, rq->requestor, rq->property, rq->target,
3289 32, PropModeReplace,
3290 (unsigned char *)target_list,
3291 (sizeof (target_list) / sizeof (target_list[0])));
3292 ev.xselection.property = rq->property;
3293 } else if (rq->target == XA_STRING
3294 || rq->target == xa_compound_text || rq->target == xa_text) {
3295 if (rq->target == XA_STRING) {
3296 style = XStringStyle;
3297 target = XA_STRING;
3298 } else {
3299 target = xa_compound_text;
3300 style = (rq->target == xa_compound_text) ? XCompoundTextStyle
3301 : XStdICCTextStyle;
3302 }
3303 cl[0] = (char *) o->selection.text;
3304 XmbTextListToTextProperty (o->Xdisplay, cl, 1, style, &ct);
3305 XChangeProperty (o->Xdisplay, rq->requestor, rq->property,
3306 target, 8, PropModeReplace, ct.value, ct.nitems);
3307 ev.xselection.property = rq->property;
3308 }
3309 XSendEvent (o->Xdisplay, rq->requestor, False, 0, &ev);
3310 }
3311
3312 /* ------------------------------------------------------------------------- *
3313 * MOUSE ROUTINES *
3314 * ------------------------------------------------------------------------- */
3315
3316 /*
3317 * return col/row values corresponding to x/y pixel values
3318 */
3319 /* EXTPROTO */
3320 void pixel_position (rxvtlib *o, int *x, int *y)
3321 {
3322 *x = Pixel2Col (*x);
3323 /* MAX_IT(*x, 0); MIN_IT(*x, TermWin.ncol - 1); */
3324 *y = Pixel2Row (*y);
3325 /* MAX_IT(*y, 0); MIN_IT(*y, TermWin.nrow - 1); */
3326 }
3327
3328 /* ------------------------------------------------------------------------- */
3329 /* ARGSUSED */
3330 /* INTPROTO */
3331 void mouse_tracking (int report, int x, int y, int firstrow,
3332 int lastrow)
3333 {
3334 /* TODO */
3335 }
3336
3337 /* ------------------------------------------------------------------------- *
3338 * DEBUG ROUTINES *
3339 * ------------------------------------------------------------------------- */
3340 /* ARGSUSED */
3341 /* INTPROTO */
3342 void debug_PasteIt (unsigned char *data, int nitems)
3343 {
3344 /* TODO */
3345 }
3346
3347 /* ------------------------------------------------------------------------- */
3348 #if 0
3349 /* INTPROTO */
3350 void debug_colors (void)
3351 {
3352 int color;
3353 const char *name[] = { "fg", "bg",
3354 "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"
3355 };
3356
3357 fprintf (stderr, "Color ( ");
3358 if (rstyle & RS_RVid)
3359 fprintf (stderr, "rvid ");
3360 if (rstyle & RS_Bold)
3361 fprintf (stderr, "bold ");
3362 if (rstyle & RS_Blink)
3363 fprintf (stderr, "blink ");
3364 if (rstyle & RS_Uline)
3365 fprintf (stderr, "uline ");
3366 fprintf (stderr, "): ");
3367
3368 color = GET_FGCOLOR (rstyle);
3369 #ifndef NO_BRIGHTCOLOR
3370 if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
3371 color -= (minBrightCOLOR - minCOLOR);
3372 fprintf (stderr, "bright ");
3373 }
3374 #endif
3375 fprintf (stderr, "%s on ", name[color]);
3376
3377 color = GET_BGCOLOR (rstyle);
3378 #ifndef NO_BRIGHTCOLOR
3379 if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
3380 color -= (minBrightCOLOR - minCOLOR);
3381 fprintf (stderr, "bright ");
3382 }
3383 #endif
3384 fprintf (stderr, "%s\n", name[color]);
3385 }
3386 #endif
3387
3388 #ifdef USE_XIM
3389 /* EXTPROTO */
3390 void rxvtlib_setPosition (rxvtlib *o, XPoint * pos)
3391 {
3392 XWindowAttributes xwa;
3393
3394 XGetWindowAttributes (o->Xdisplay, o->TermWin.vt, &xwa);
3395 pos->x = Col2Pixel (o->screen.cur.col) + xwa.x;
3396 pos->y = Height2Pixel ((o->screen.cur.row + 1)) + xwa.y;
3397 }
3398
3399 #endif
3400