ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.97
Committed: Mon Jul 26 18:01:19 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_2
Changes since 1.95: +98 -34 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*--------------------------------*-C-*---------------------------------*
2 pcg 1.93 * File: command.C
3 pcg 1.1 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 1992 John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
7     * - original version
8     * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
9     * - extensive modifications
10     * Copyright (c) 1995 Garrett D'Amore <garrett@netcom.com>
11     * - vt100 printing
12     * Copyright (c) 1995 Steven Hirsch <hirsch@emba.uvm.edu>
13     * - X11 mouse report mode and support for
14     * DEC "private mode" save/restore functions.
15     * Copyright (c) 1995 Jakub Jelinek <jj@gnu.ai.mit.edu>
16     * - key-related changes to handle Shift+function
17     * keys properly.
18     * Copyright (c) 1997 MJ Olesen <olesen@me.queensu.ca>
19     * - extensive modifications
20     * Copyright (c) 1997 Raul Garcia Garcia <rgg@tid.es>
21     * - modification and cleanups for Solaris 2.x
22     * and Linux 1.2.x
23     * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
24     * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
25     * - extensive modifications
26     * Copyright (c) 1998 Alfredo K. Kojima <kojima@windowmaker.org>
27     * Copyright (c) 2001 Marius Gedminas
28     * - Ctrl/Mod4+Tab works like Meta+Tab (options)
29     * Copyright (c) 2003 Rob McMullen <robm@flipturn.org>
30 pcg 1.49 * Copyright (c) 2003-2004 Marc Lehmann <pcg@goof.com>
31 pcg 1.1 *
32     * This program is free software; you can redistribute it and/or modify
33     * it under the terms of the GNU General Public License as published by
34     * the Free Software Foundation; either version 2 of the License, or
35     * (at your option) any later version.
36     *
37     * This program is distributed in the hope that it will be useful,
38     * but WITHOUT ANY WARRANTY; without even the implied warranty of
39     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40     * GNU General Public License for more details.
41     *
42     * You should have received a copy of the GNU General Public License
43     * along with this program; if not, write to the Free Software
44     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
45     *----------------------------------------------------------------------*/
46    
47     /*{{{ includes: */
48     #include "../config.h" /* NECESSARY */
49     #include "rxvt.h" /* NECESSARY */
50     #include "version.h"
51     #include "command.h"
52    
53 pcg 1.20 #include <wchar.h>
54    
55 pcg 1.1 /*----------------------------------------------------------------------*/
56    
57 pcg 1.81 #define IS_CONTROL(ch) !((ch) & 0xffffff60UL)
58    
59     // exception thrown when the command parser runs out of input data
60     class out_of_input { } out_of_input;
61    
62 pcg 1.1 /*{{{ Convert the keypress event into a string */
63     void
64 pcg 1.38 rxvt_term::lookup_key (XKeyEvent &ev)
65 pcg 1.1 {
66 pcg 1.49 int ctrl, meta, shft, len;
67     unsigned int newlen;
68     KeySym keysym;
69 pcg 1.1 #ifdef DEBUG_CMD
70 pcg 1.49 static int debug_key = 1; /* accessible by a debugger only */
71 pcg 1.1 #endif
72 pcg 1.49 int valid_keysym;
73 pcg 1.36 unsigned char kbuf[KBUFSZ];
74 pcg 1.1
75 pcg 1.36 /*
76     * use Num_Lock to toggle Keypad on/off. If Num_Lock is off, allow an
77     * escape sequence to toggle the Keypad.
78     *
79     * Always permit `shift' to override the current setting
80     */
81 pcg 1.38 shft = (ev.state & ShiftMask);
82     ctrl = (ev.state & ControlMask);
83     meta = (ev.state & ModMetaMask);
84 pcg 1.14
85 pcg 1.38 if (numlock_state || (ev.state & ModNumLockMask))
86 pcg 1.36 {
87 pcg 1.38 numlock_state = (ev.state & ModNumLockMask);
88 pcg 1.43 PrivMode ((!numlock_state), PrivMode_aplKP);
89 pcg 1.36 }
90 pcg 1.14
91 pcg 1.36 kbuf[0] = 0;
92 pcg 1.14
93 pcg 1.1 #ifdef USE_XIM
94 pcg 1.36 if (Input_Context)
95     {
96     Status status_return;
97 pcg 1.1
98 pcg 1.81 #if 0
99 pcg 1.1 #ifdef X_HAVE_UTF8_STRING
100 pcg 1.48 if (enc_utf8 && 0) // currently disabled, doesn't seem to work, nor is useful
101 pcg 1.38 len = Xutf8LookupString (Input_Context, &ev, (char *)kbuf,
102 pcg 1.36 KBUFSZ, &keysym, &status_return);
103     else
104 pcg 1.20 #endif
105 pcg 1.81 #endif
106 pcg 1.36 {
107     wchar_t wkbuf[KBUFSZ + 1];
108    
109     // the XOpenIM manpage lies about hardcoding the locale
110     // at the point of XOpenIM, so temporarily switch locales
111     if (rs[Rs_imLocale])
112     SET_LOCALE (rs[Rs_imLocale]);
113     // assume wchar_t == unicode or better
114 pcg 1.38 len = XwcLookupString (Input_Context, &ev, wkbuf,
115 pcg 1.36 KBUFSZ, &keysym, &status_return);
116     if (rs[Rs_imLocale])
117     SET_LOCALE (locale);
118 pcg 1.17
119 pcg 1.36 if (status_return == XLookupChars
120 pcg 1.49 || status_return == XLookupBoth)
121 pcg 1.36 {
122 pcg 1.55 /* make sure the user can type ctrl-@, i.e. NUL */
123     if (len == 1 && *wkbuf == 0)
124     {
125     kbuf[0] = 0;
126     len = 1;
127     }
128     else
129     {
130     wkbuf[len] = 0;
131     len = wcstombs ((char *)kbuf, wkbuf, KBUFSZ);
132     if (len < 0)
133     len = 0;
134     }
135 pcg 1.36 }
136     else
137     len = 0;
138     }
139 pcg 1.20
140 pcg 1.36 valid_keysym = status_return == XLookupKeySym
141 pcg 1.49 || status_return == XLookupBoth;
142 pcg 1.36 }
143     else
144 pcg 1.14 #endif
145 pcg 1.36 {
146 pcg 1.38 len = XLookupString (&ev, (char *)kbuf, KBUFSZ, &keysym, &compose);
147 pcg 1.49 valid_keysym = keysym != NoSymbol;
148 pcg 1.36 }
149    
150     if (valid_keysym)
151     {
152     if (TermWin.saveLines)
153     {
154 pcg 1.1 #ifdef UNSHIFTED_SCROLLKEYS
155 pcg 1.36 if (!ctrl && !meta)
156     {
157 pcg 1.1 #else
158 pcg 1.36 if (IS_SCROLL_MOD)
159     {
160 pcg 1.1 #endif
161 pcg 1.49 int lnsppg;
162 pcg 1.1
163     #ifdef PAGING_CONTEXT_LINES
164 pcg 1.36 lnsppg = TermWin.nrow - PAGING_CONTEXT_LINES;
165 pcg 1.1 #else
166 pcg 1.36 lnsppg = TermWin.nrow * 4 / 5;
167 pcg 1.1 #endif
168 pcg 1.36 if (keysym == XK_Prior)
169     {
170     scr_page (UP, lnsppg);
171     return;
172     }
173     else if (keysym == XK_Next)
174     {
175     scr_page (DN, lnsppg);
176     return;
177     }
178     }
179 pcg 1.1 #ifdef SCROLL_ON_UPDOWN_KEYS
180 pcg 1.36 if (IS_SCROLL_MOD)
181     {
182     if (keysym == XK_Up)
183     {
184     scr_page (UP, 1);
185     return;
186     }
187     else if (keysym == XK_Down)
188     {
189     scr_page (DN, 1);
190     return;
191     }
192     }
193 pcg 1.1 #endif
194     #ifdef SCROLL_ON_HOMEEND_KEYS
195 pcg 1.36 if (IS_SCROLL_MOD)
196     {
197     if (keysym == XK_Home)
198     {
199     scr_move_to (0, 1);
200     return;
201     }
202     else if (keysym == XK_End)
203     {
204     scr_move_to (1, 0);
205     return;
206     }
207     }
208     #endif
209     }
210    
211     if (shft)
212     {
213     /* Shift + F1 - F10 generates F11 - F20 */
214     if (keysym >= XK_F1 && keysym <= XK_F10)
215     {
216     keysym += (XK_F11 - XK_F1);
217     shft = 0; /* turn off Shift */
218     }
219     else if (!ctrl && !meta && (PrivateModes & PrivMode_ShiftKeys))
220     {
221     switch (keysym)
222     {
223     /* normal XTerm key bindings */
224     case XK_Insert: /* Shift+Insert = paste mouse selection */
225 pcg 1.38 selection_request (ev.time, 0, 0);
226 pcg 1.36 return;
227     /* rxvt extras */
228     case XK_KP_Add: /* Shift+KP_Add = bigger font */
229 pcg 1.51 change_font (FONT_UP);
230 pcg 1.36 return;
231     case XK_KP_Subtract: /* Shift+KP_Subtract = smaller font */
232 pcg 1.51 change_font (FONT_DN);
233 pcg 1.36 return;
234     }
235     }
236     }
237 pcg 1.1 #ifdef PRINTPIPE
238 pcg 1.36 if (keysym == XK_Print)
239     {
240     scr_printscreen (ctrl | shft);
241     return;
242     }
243 pcg 1.1 #endif
244    
245 pcg 1.36 if (keysym >= 0xFF00 && keysym <= 0xFFFF)
246     {
247 pcg 1.1 #ifdef KEYSYM_RESOURCE
248 pcg 1.43 if (! (shft | ctrl) && Keysym_map[keysym & 0xFF] != NULL)
249 pcg 1.36 {
250     unsigned int l;
251     const unsigned char *kbuf0;
252 pcg 1.1
253 pcg 1.36 kbuf0 = (Keysym_map[keysym & 0xFF]);
254     l = (unsigned int)*kbuf0++;
255 pcg 1.1
256 pcg 1.36 /* escape prefix */
257 pcg 1.68 if (meta
258 pcg 1.1 # ifdef META8_OPTION
259 pcg 1.68 && meta_char == C0_ESC
260 pcg 1.1 # endif
261 pcg 1.68 )
262     {
263     const unsigned char ch = C0_ESC;
264 pcg 1.36 tt_write (&ch, 1);
265 pcg 1.68 }
266    
267 pcg 1.36 tt_write (kbuf0, l);
268     return;
269     }
270     else
271     #endif
272     {
273     newlen = 1;
274     switch (keysym)
275     {
276 pcg 1.1 #ifndef NO_BACKSPACE_KEY
277 pcg 1.36 case XK_BackSpace:
278     if (PrivateModes & PrivMode_HaveBackSpace)
279     {
280 pcg 1.43 kbuf[0] = (!! (PrivateModes & PrivMode_BackSpace)
281 pcg 1.36 ^ !!ctrl) ? '\b' : '\177';
282     kbuf[1] = '\0';
283     }
284     else
285 pcg 1.43 STRCPY (kbuf, key_backspace);
286 pcg 1.36 break;
287 pcg 1.1 #endif
288     #ifndef NO_DELETE_KEY
289 pcg 1.36 case XK_Delete:
290 pcg 1.43 STRCPY (kbuf, key_delete);
291 pcg 1.36 break;
292 pcg 1.1 #endif
293 pcg 1.36 case XK_Tab:
294     if (shft)
295 pcg 1.43 STRCPY (kbuf, "\033[Z");
296 pcg 1.36 else
297     {
298 pcg 1.1 #ifdef CTRL_TAB_MAKES_META
299 pcg 1.36 if (ctrl)
300     meta = 1;
301 pcg 1.1 #endif
302     #ifdef MOD4_TAB_MAKES_META
303 pcg 1.38 if (ev.state & Mod4Mask)
304 pcg 1.36 meta = 1;
305 pcg 1.1 #endif
306 pcg 1.36 newlen = 0;
307     }
308     break;
309 pcg 1.1
310     #ifdef XK_KP_Left
311 pcg 1.36 case XK_KP_Up: /* \033Ox or standard */
312     case XK_KP_Down: /* \033Or or standard */
313     case XK_KP_Right: /* \033Ov or standard */
314     case XK_KP_Left: /* \033Ot or standard */
315     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
316     {
317 pcg 1.43 STRCPY (kbuf, "\033OZ");
318 pcg 1.46 kbuf[2] = "txvr"[keysym - XK_KP_Left];
319 pcg 1.36 break;
320     }
321     else
322     /* translate to std. cursor key */
323     keysym = XK_Left + (keysym - XK_KP_Left);
324     /* FALLTHROUGH */
325     #endif
326     case XK_Up: /* "\033[A" */
327     case XK_Down: /* "\033[B" */
328     case XK_Right: /* "\033[C" */
329     case XK_Left: /* "\033[D" */
330 pcg 1.43 STRCPY (kbuf, "\033[Z");
331 pcg 1.47 kbuf[2] = "DACB"[keysym - XK_Left];
332 pcg 1.36 /* do Shift first */
333     if (shft)
334 pcg 1.47 kbuf[2] = "dacb"[keysym - XK_Left];
335 pcg 1.36 else if (ctrl)
336     {
337     kbuf[1] = 'O';
338 pcg 1.47 kbuf[2] = "dacb"[keysym - XK_Left];
339 pcg 1.36 }
340     else if (PrivateModes & PrivMode_aplCUR)
341     kbuf[1] = 'O';
342     break;
343 pcg 1.1
344     #ifndef UNSHIFTED_SCROLLKEYS
345     # ifdef XK_KP_Prior
346 pcg 1.36 case XK_KP_Prior:
347     /* allow shift to override */
348     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
349     {
350 pcg 1.43 STRCPY (kbuf, "\033Oy");
351 pcg 1.36 break;
352     }
353     /* FALLTHROUGH */
354 pcg 1.1 # endif
355 pcg 1.36 case XK_Prior:
356 pcg 1.43 STRCPY (kbuf, "\033[5~");
357 pcg 1.36 break;
358 pcg 1.1 # ifdef XK_KP_Next
359 pcg 1.36 case XK_KP_Next:
360     /* allow shift to override */
361     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
362     {
363 pcg 1.43 STRCPY (kbuf, "\033Os");
364 pcg 1.36 break;
365     }
366     /* FALLTHROUGH */
367 pcg 1.1 # endif
368 pcg 1.36 case XK_Next:
369 pcg 1.43 STRCPY (kbuf, "\033[6~");
370 pcg 1.36 break;
371     #endif
372     case XK_KP_Enter:
373     /* allow shift to override */
374     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
375     {
376 pcg 1.43 STRCPY (kbuf, "\033OM");
377 pcg 1.36 }
378     else
379     {
380     kbuf[0] = '\r';
381     kbuf[1] = '\0';
382     }
383     break;
384 pcg 1.1
385     #ifdef XK_KP_Begin
386 pcg 1.36 case XK_KP_Begin:
387 pcg 1.43 STRCPY (kbuf, "\033Ou");
388 pcg 1.36 break;
389    
390     case XK_KP_Insert:
391 pcg 1.43 STRCPY (kbuf, "\033Op");
392 pcg 1.36 break;
393    
394     case XK_KP_Delete:
395 pcg 1.43 STRCPY (kbuf, "\033On");
396 pcg 1.36 break;
397     #endif
398     case XK_KP_F1: /* "\033OP" */
399     case XK_KP_F2: /* "\033OQ" */
400     case XK_KP_F3: /* "\033OR" */
401     case XK_KP_F4: /* "\033OS" */
402 pcg 1.43 STRCPY (kbuf, "\033OP");
403 pcg 1.36 kbuf[2] += (keysym - XK_KP_F1);
404     break;
405    
406     case XK_KP_Multiply: /* "\033Oj" : "*" */
407 pcg 1.49 case XK_KP_Add: /* "\033Ok" : "+" */
408 pcg 1.36 case XK_KP_Separator: /* "\033Ol" : "," */
409     case XK_KP_Subtract: /* "\033Om" : "-" */
410     case XK_KP_Decimal: /* "\033On" : "." */
411     case XK_KP_Divide: /* "\033Oo" : "/" */
412     case XK_KP_0: /* "\033Op" : "0" */
413     case XK_KP_1: /* "\033Oq" : "1" */
414     case XK_KP_2: /* "\033Or" : "2" */
415     case XK_KP_3: /* "\033Os" : "3" */
416     case XK_KP_4: /* "\033Ot" : "4" */
417     case XK_KP_5: /* "\033Ou" : "5" */
418     case XK_KP_6: /* "\033Ov" : "6" */
419     case XK_KP_7: /* "\033Ow" : "7" */
420     case XK_KP_8: /* "\033Ox" : "8" */
421     case XK_KP_9: /* "\033Oy" : "9" */
422     /* allow shift to override */
423     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
424     {
425 pcg 1.43 STRCPY (kbuf, "\033Oj");
426 pcg 1.36 kbuf[2] += (keysym - XK_KP_Multiply);
427     }
428     else
429     {
430     kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
431     kbuf[1] = '\0';
432     }
433     break;
434    
435     case XK_Find:
436 pcg 1.43 STRCPY (kbuf, "\033[1~");
437 pcg 1.36 break;
438     case XK_Insert:
439 pcg 1.43 STRCPY (kbuf, "\033[2~");
440 pcg 1.36 break;
441 pcg 1.1 #ifdef DXK_Remove /* support for DEC remove like key */
442 pcg 1.36 case DXK_Remove:
443     /* FALLTHROUGH */
444 pcg 1.1 #endif
445 pcg 1.36 case XK_Execute:
446 pcg 1.43 STRCPY (kbuf, "\033[3~");
447 pcg 1.36 break;
448     case XK_Select:
449 pcg 1.43 STRCPY (kbuf, "\033[4~");
450 pcg 1.36 break;
451 pcg 1.1 #ifdef XK_KP_End
452 pcg 1.36 case XK_KP_End:
453     /* allow shift to override */
454     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
455     {
456 pcg 1.43 STRCPY (kbuf, "\033Oq");
457 pcg 1.36 break;
458     }
459     /* FALLTHROUGH */
460     #endif
461     case XK_End:
462 pcg 1.43 STRCPY (kbuf, KS_END);
463 pcg 1.36 break;
464 pcg 1.1 #ifdef XK_KP_Home
465 pcg 1.36 case XK_KP_Home:
466     /* allow shift to override */
467     if ((PrivateModes & PrivMode_aplKP) ? !shft : shft)
468     {
469 pcg 1.43 STRCPY (kbuf, "\033Ow");
470 pcg 1.36 break;
471     }
472     /* FALLTHROUGH */
473     #endif
474     case XK_Home:
475 pcg 1.43 STRCPY (kbuf, KS_HOME);
476 pcg 1.36 break;
477 pcg 1.1
478     #define FKEY(n, fkey) \
479 pcg 1.43 sprintf ((char *)kbuf,"\033[%2d~", (int) ((n) + (keysym - fkey)))
480 pcg 1.1
481 pcg 1.36 case XK_F1: /* "\033[11~" */
482     case XK_F2: /* "\033[12~" */
483     case XK_F3: /* "\033[13~" */
484     case XK_F4: /* "\033[14~" */
485     case XK_F5: /* "\033[15~" */
486 pcg 1.43 FKEY (11, XK_F1);
487 pcg 1.36 break;
488     case XK_F6: /* "\033[17~" */
489     case XK_F7: /* "\033[18~" */
490     case XK_F8: /* "\033[19~" */
491     case XK_F9: /* "\033[20~" */
492     case XK_F10: /* "\033[21~" */
493 pcg 1.43 FKEY (17, XK_F6);
494 pcg 1.36 break;
495     case XK_F11: /* "\033[23~" */
496     case XK_F12: /* "\033[24~" */
497     case XK_F13: /* "\033[25~" */
498     case XK_F14: /* "\033[26~" */
499 pcg 1.43 FKEY (23, XK_F11);
500 pcg 1.36 break;
501     case XK_F15: /* "\033[28~" */
502     case XK_F16: /* "\033[29~" */
503 pcg 1.43 FKEY (28, XK_F15);
504 pcg 1.36 break;
505     case XK_Help: /* "\033[28~" */
506 pcg 1.43 FKEY (28, XK_Help);
507 pcg 1.36 break;
508     case XK_Menu: /* "\033[29~" */
509 pcg 1.43 FKEY (29, XK_Menu);
510 pcg 1.36 break;
511     case XK_F17: /* "\033[31~" */
512     case XK_F18: /* "\033[32~" */
513     case XK_F19: /* "\033[33~" */
514     case XK_F20: /* "\033[34~" */
515     case XK_F21: /* "\033[35~" */
516     case XK_F22: /* "\033[36~" */
517     case XK_F23: /* "\033[37~" */
518     case XK_F24: /* "\033[38~" */
519     case XK_F25: /* "\033[39~" */
520     case XK_F26: /* "\033[40~" */
521     case XK_F27: /* "\033[41~" */
522     case XK_F28: /* "\033[42~" */
523     case XK_F29: /* "\033[43~" */
524     case XK_F30: /* "\033[44~" */
525     case XK_F31: /* "\033[45~" */
526     case XK_F32: /* "\033[46~" */
527     case XK_F33: /* "\033[47~" */
528     case XK_F34: /* "\033[48~" */
529     case XK_F35: /* "\033[49~" */
530 pcg 1.43 FKEY (31, XK_F17);
531 pcg 1.36 break;
532 pcg 1.1 #undef FKEY
533 pcg 1.36 default:
534     newlen = 0;
535     break;
536     }
537     if (newlen)
538 pcg 1.43 len = STRLEN (kbuf);
539 pcg 1.36 }
540 pcg 1.68
541 pcg 1.36 /*
542     * Pass meta for all function keys, if 'meta' option set
543     */
544 pcg 1.1 #ifdef META8_OPTION
545 pcg 1.36 if (meta && (meta_char == 0x80) && len > 0)
546     kbuf[len - 1] |= 0x80;
547 pcg 1.1 #endif
548 pcg 1.36
549     }
550     else if (ctrl && keysym == XK_minus)
551     {
552     len = 1;
553     kbuf[0] = '\037'; /* Ctrl-Minus generates ^_ (31) */
554     }
555     else
556     {
557 pcg 1.1 #ifdef META8_OPTION
558 pcg 1.36 /* set 8-bit on */
559     if (meta && (meta_char == 0x80))
560     {
561     unsigned char *ch;
562    
563     for (ch = kbuf; ch < kbuf + len; ch++)
564     *ch |= 0x80;
565 pcg 1.68
566 pcg 1.36 meta = 0;
567     }
568 pcg 1.1 #endif
569 pcg 1.36 /* nil */ ;
570     }
571     }
572 pcg 1.1
573 pcg 1.36 if (len <= 0)
574     return; /* not mapped */
575 pcg 1.1
576 pcg 1.36 if (Options & Opt_scrollTtyKeypress)
577     if (TermWin.view_start)
578     {
579     TermWin.view_start = 0;
580     want_refresh = 1;
581     }
582 pcg 1.1
583 pcg 1.36 /*
584     * these modifications only affect the static keybuffer
585     * pass Shift/Control indicators for function keys ending with `~'
586     *
587     * eg,
588     * Prior = "ESC[5~"
589     * Shift+Prior = "ESC[5$"
590     * Ctrl+Prior = "ESC[5^"
591     * Ctrl+Shift+Prior = "ESC[5@"
592     * Meta adds an Escape prefix (with META8_OPTION, if meta == <escape>).
593     */
594     if (kbuf[0] == C0_ESC && kbuf[1] == '[' && kbuf[len - 1] == '~')
595     kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
596 pcg 1.1
597 pcg 1.36 /* escape prefix */
598     if (meta
599 pcg 1.1 #ifdef META8_OPTION
600 pcg 1.55 && meta_char == C0_ESC
601 pcg 1.1 #endif
602 pcg 1.36 )
603     {
604     const unsigned char ch = C0_ESC;
605 pcg 1.43 tt_write (&ch, 1);
606 pcg 1.1 }
607 pcg 1.55
608     #if defined(DEBUG_CMD)
609     /* Display keyboard buffer contents */
610     unsigned char *p;
611     int i;
612    
613     fprintf (stderr, "key 0x%04X [%d]: `", (unsigned int)keysym, len);
614     for (i = 0, p = kbuf; i < len; i++, p++)
615     fprintf (stderr, (*p >= ' ' && *p < '\177' ? "%c" : "\\%03o"), *p);
616     fprintf (stderr, "'\n");
617 pcg 1.1 #endif /* DEBUG_CMD */
618 pcg 1.36 tt_write (kbuf, (unsigned int)len);
619 pcg 1.1 }
620     /*}}} */
621    
622     #if (MENUBAR_MAX)
623 pcg 1.43 /*{{{ rxvt_cmd_write (), rxvt_cmd_getc () */
624 pcg 1.1 /* attempt to `write' count to the input buffer */
625     unsigned int
626 pcg 1.34 rxvt_term::cmd_write (const unsigned char *str, unsigned int count)
627 pcg 1.1 {
628 pcg 1.81 unsigned int n, s;
629 pcg 1.1
630 pcg 1.36 n = cmdbuf_ptr - cmdbuf_base;
631 pcg 1.81 s = cmdbuf_base + CBUFSIZ - 1 - cmdbuf_endp;
632 pcg 1.57
633 pcg 1.36 if (n > 0 && s < count)
634     {
635 pcg 1.43 MEMMOVE (cmdbuf_base, cmdbuf_ptr,
636     (unsigned int) (cmdbuf_endp - cmdbuf_ptr));
637 pcg 1.36 cmdbuf_ptr = cmdbuf_base;
638     cmdbuf_endp -= n;
639     s += n;
640     }
641 pcg 1.57
642 pcg 1.36 if (count > s)
643     {
644 pcg 1.81 rxvt_warn ("data loss: cmd_write too large, continuing.\n");
645 pcg 1.36 count = s;
646     }
647 pcg 1.57
648 pcg 1.36 for (; count--;)
649     *cmdbuf_endp++ = *str++;
650 pcg 1.57
651     cmd_parse ();
652    
653 pcg 1.36 return 0;
654 pcg 1.1 }
655     #endif /* MENUBAR_MAX */
656    
657 pcg 1.3 void
658 pcg 1.11 rxvt_term::flush ()
659     {
660     #ifdef TRANSPARENT
661     if (want_full_refresh)
662     {
663     want_full_refresh = 0;
664 pcg 1.22 scr_clear ();
665     scr_touch (false);
666 pcg 1.11 want_refresh = 1;
667     }
668     #endif
669    
670     if (want_refresh)
671     {
672 pcg 1.22 scr_refresh (refresh_type);
673 pcg 1.34 scrollbar_show (1);
674 pcg 1.11 #ifdef USE_XIM
675 pcg 1.34 IMSendSpot ();
676 pcg 1.11 #endif
677     }
678    
679 pcg 1.42 display->flush ();
680 pcg 1.11 }
681    
682     void
683     rxvt_term::check_cb (check_watcher &w)
684     {
685     SET_R (this);
686 pcg 1.19 SET_LOCALE (locale);
687 pcg 1.11
688     flush ();
689     }
690    
691 pcg 1.27 #ifdef CURSOR_BLINK
692 pcg 1.3 void
693 pcg 1.31 rxvt_term::cursor_blink_cb (time_watcher &w)
694 pcg 1.5 {
695     hidden_cursor = !hidden_cursor;
696     want_refresh = 1;
697 pcg 1.28
698     w.start (w.at + BLINK_INTERVAL);
699 pcg 1.5 }
700 pcg 1.27 #endif
701 pcg 1.5
702 pcg 1.31 #ifdef TEXT_BLINK
703     void
704     rxvt_term::text_blink_cb (time_watcher &w)
705     {
706     if (scr_refresh_rend (RS_Blink, RS_Blink))
707     {
708     hidden_text = !hidden_text;
709     want_refresh = 1;
710     w.start (w.at + TEXT_BLINK_INTERVAL);
711     }
712     }
713     #endif
714    
715 root 1.97 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
716     void
717     rxvt_term::cont_scroll_cb (time_watcher &w)
718     {
719     if ((scrollbar_isUp() || scrollbar_isDn()) &&
720     scr_page (scrollbar_isUp() ? UP : DN, 1))
721     {
722     refresh_type |= SMOOTH_REFRESH;
723     want_refresh = 1;
724     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
725     }
726     }
727     #endif
728    
729     #ifdef SELECTION_SCROLLING
730     void
731     rxvt_term::sel_scroll_cb (time_watcher &w)
732     {
733     if (scr_page (scroll_selection_dir, scroll_selection_lines))
734     {
735     selection_extend (selection_save_x, selection_save_y, selection_save_state);
736     refresh_type |= SMOOTH_REFRESH;
737     want_refresh = 1;
738     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
739     }
740     }
741     #endif
742    
743     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
744     void
745     rxvt_term::slip_wheel_cb (time_watcher &w)
746     {
747     if (mouse_slip_wheel_speed == 0
748     || mouse_slip_wheel_speed < 0 ? scr_page (DN, -mouse_slip_wheel_speed)
749     : scr_page (UP, mouse_slip_wheel_speed))
750     {
751     refresh_type |= SMOOTH_REFRESH;
752     want_refresh = 1;
753     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
754     }
755     }
756     #endif
757    
758 pcg 1.4 bool
759 pcg 1.8 rxvt_term::pty_fill ()
760 pcg 1.4 {
761     ssize_t n = cmdbuf_endp - cmdbuf_ptr;
762    
763 pcg 1.93 if (CBUFSIZ == n)
764     {
765     rxvt_warn ("pty_fill on full buffer, draining input, continuing.\n");
766     n = 0;
767     }
768    
769 pcg 1.4 memmove (cmdbuf_base, cmdbuf_ptr, n);
770     cmdbuf_ptr = cmdbuf_base;
771     cmdbuf_endp = cmdbuf_ptr + n;
772 pcg 1.36
773 pcg 1.81 n = read (cmd_fd, cmdbuf_endp, CBUFSIZ - n);
774 pcg 1.4
775     if (n > 0)
776     {
777     cmdbuf_endp += n;
778     return true;
779     }
780 pcg 1.13 else if (n < 0 && errno != EAGAIN)
781     destroy ();
782 pcg 1.57
783 pcg 1.13 return false;
784 pcg 1.4 }
785    
786 pcg 1.3 void
787     rxvt_term::pty_cb (io_watcher &w, short revents)
788     {
789 pcg 1.9 SET_R (this);
790 pcg 1.19 SET_LOCALE (locale);
791 pcg 1.9
792 pcg 1.10 if (revents & EVENT_WRITE)
793     tt_write (0, 0);
794     else if (revents & EVENT_READ)
795 pcg 1.93 // loop, but don't allow a single term to monopolize us
796     while (pty_fill ())
797     if (cmd_parse ())
798     break;
799 pcg 1.57 }
800    
801 pcg 1.29 #ifdef POINTER_BLANK
802 pcg 1.6 void
803     rxvt_term::pointer_unblank ()
804     {
805 pcg 1.38 XDefineCursor (display->display, TermWin.vt, TermWin_cursor);
806 pcg 1.19 recolour_cursor ();
807 pcg 1.7
808 pcg 1.6 hidden_pointer = 0;
809 pcg 1.1
810 pcg 1.7 if (Options & Opt_pointerBlank)
811     pointer_ev.start (NOW + pointerBlankDelay);
812 pcg 1.1 }
813    
814     void
815 pcg 1.6 rxvt_term::pointer_blank ()
816 pcg 1.1 {
817 pcg 1.43 if (! (Options & Opt_pointerBlank))
818 pcg 1.6 return;
819    
820 pcg 1.38 XDefineCursor (display->display, TermWin.vt, blank_cursor);
821     XFlush (display->display);
822 pcg 1.1
823 pcg 1.6 hidden_pointer = 1;
824 pcg 1.1 }
825    
826     void
827 pcg 1.6 rxvt_term::pointer_cb (time_watcher &w)
828 pcg 1.1 {
829 pcg 1.9 SET_R (this);
830 pcg 1.19 SET_LOCALE (locale);
831 pcg 1.9
832 pcg 1.6 pointer_blank ();
833 pcg 1.1 }
834     #endif
835    
836     void
837 pcg 1.56 rxvt_term::mouse_report (XButtonEvent &ev)
838 pcg 1.1 {
839 pcg 1.56 int button_number, key_state = 0;
840     int x, y;
841 pcg 1.36
842 pcg 1.38 x = ev.x;
843     y = ev.y;
844 pcg 1.36 pixel_position (&x, &y);
845    
846     if (MEvent.button == AnyButton)
847     {
848     button_number = 3;
849     }
850     else
851     {
852     button_number = MEvent.button - Button1;
853     /* add 0x3D for wheel events, like xterm does */
854     if (button_number >= 3)
855     button_number += (64 - 3);
856     }
857 pcg 1.1
858 pcg 1.36 if (PrivateModes & PrivMode_MouseX10)
859     {
860     /*
861     * do not report ButtonRelease
862     * no state info allowed
863     */
864     key_state = 0;
865     if (button_number == 3)
866     return;
867     }
868     else
869     {
870     /* XTerm mouse reporting needs these values:
871     * 4 = Shift
872     * 8 = Meta
873     * 16 = Control
874     * plus will add in our own Double-Click reporting
875     * 32 = Double Click
876     */
877     key_state = ((MEvent.state & ShiftMask) ? 4 : 0)
878     + ((MEvent.state & ModMetaMask) ? 8 : 0)
879     + ((MEvent.state & ControlMask) ? 16 : 0);
880 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
881 pcg 1.36 key_state += ((MEvent.clicks > 1) ? 32 : 0);
882 pcg 1.1 #endif
883 pcg 1.36
884 pcg 1.1 }
885    
886     #ifdef DEBUG_MOUSEREPORT
887 pcg 1.43 fprintf (stderr, "Mouse [");
888 pcg 1.36 if (key_state & 16)
889 pcg 1.43 fputc ('C', stderr);
890 pcg 1.36 if (key_state & 4)
891 pcg 1.43 fputc ('S', stderr);
892 pcg 1.36 if (key_state & 8)
893 pcg 1.43 fputc ('A', stderr);
894 pcg 1.36 if (key_state & 32)
895 pcg 1.43 fputc ('2', stderr);
896     fprintf (stderr, "]: <%d>, %d/%d\n",
897 pcg 1.36 button_number,
898     x + 1,
899     y + 1);
900 pcg 1.1 #else
901 pcg 1.43 tt_printf ("\033[M%c%c%c",
902 pcg 1.36 (32 + button_number + key_state),
903     (32 + x + 1),
904     (32 + y + 1));
905 pcg 1.1 #endif
906     }
907    
908     #ifdef USING_W11LIB
909     void
910 pcg 1.43 rxvt_W11_process_x_event (XEvent *ev)
911 pcg 1.1 {
912 pcg 1.43 rxvt_t *r = rxvt_get_r ();
913 pcg 1.1
914 pcg 1.38 x_cb (*ev);
915 pcg 1.1 }
916     #endif
917    
918     /*{{{ process an X event */
919     void
920 pcg 1.38 rxvt_term::x_cb (XEvent &ev)
921 pcg 1.1 {
922 pcg 1.38 SET_R (this);
923     SET_LOCALE (locale);
924    
925     #if defined(CURSOR_BLINK)
926     if ((Options & Opt_cursorBlink) && ev.type == KeyPress)
927     {
928     if (hidden_cursor)
929     {
930     hidden_cursor = 0;
931     want_refresh = 1;
932     }
933    
934     cursor_blink_ev.start (NOW + BLINK_INTERVAL);
935     }
936     #endif
937    
938     #if defined(POINTER_BLANK)
939     if ((Options & Opt_pointerBlank) && pointerBlankDelay > 0)
940     {
941     if (ev.type == MotionNotify
942     || ev.type == ButtonPress
943     || ev.type == ButtonRelease)
944     if (hidden_pointer)
945     pointer_unblank ();
946    
947     if (ev.type == KeyPress && hidden_pointer == 0)
948     pointer_blank ();
949     }
950     #endif
951    
952     #ifdef USE_XIM
953     if (XFilterEvent (&ev, None))
954     return;
955     #endif
956    
957 pcg 1.36 Window unused_root, unused_child;
958     int unused_root_x, unused_root_y;
959     unsigned int unused_mask;
960 pcg 1.3
961 pcg 1.1 #ifdef DEBUG_X
962 pcg 1.36 const char *const eventnames[] =
963 pcg 1.1 { /* mason - this matches my system */
964 pcg 1.36 "",
965     "",
966     "KeyPress",
967     "KeyRelease",
968     "ButtonPress",
969     "ButtonRelease",
970     "MotionNotify",
971     "EnterNotify",
972     "LeaveNotify",
973     "FocusIn",
974     "FocusOut",
975     "KeymapNotify",
976     "Expose",
977     "GraphicsExpose",
978     "NoExpose",
979     "VisibilityNotify",
980     "CreateNotify",
981     "DestroyNotify",
982     "UnmapNotify",
983     "MapNotify",
984     "MapRequest",
985     "ReparentNotify",
986     "ConfigureNotify",
987     "ConfigureRequest",
988     "GravityNotify",
989     "ResizeRequest",
990     "CirculateNotify",
991     "CirculateRequest",
992     "PropertyNotify",
993     "SelectionClear",
994     "SelectionRequest",
995     "SelectionNotify",
996     "ColormapNotify",
997     "ClientMessage",
998     "MappingNotify"
999 pcg 1.1 };
1000     #endif
1001    
1002     #ifdef DEBUG_X
1003 pcg 1.36 struct timeval tp;
1004     struct tm *ltt;
1005 pcg 1.43 (void)gettimeofday (&tp, NULL);
1006     ltt = localtime (& (tp.tv_sec));
1007     D_X ((stderr, "Event: %-16s %-7s %08lx (%4d-%02d-%02d %02d:%02d:%02d.%.6ld) %s %lu", eventnames[ev.type], (ev.xany.window == TermWin.parent[0] ? "parent" : (ev.xany.window == TermWin.vt ? "vt" : (ev.xany.window == scrollBar.win ? "scroll" : (ev.xany.window == menuBar.win ? "menubar" : "UNKNOWN")))), (ev.xany.window == TermWin.parent[0] ? TermWin.parent[0] : (ev.xany.window == TermWin.vt ? TermWin.vt : (ev.xany.window == scrollBar.win ? scrollBar.win : (ev.xany.window == menuBar.win ? menuBar.win : 0)))), ltt->tm_year + 1900, ltt->tm_mon + 1, ltt->tm_mday, ltt->tm_hour, ltt->tm_min, ltt->tm_sec, tp.tv_usec, ev.xany.send_event ? "S" : " ", ev.xany.serial));
1008 pcg 1.1 #endif
1009    
1010 pcg 1.38 switch (ev.type)
1011 pcg 1.36 {
1012     case KeyPress:
1013 pcg 1.38 lookup_key (ev.xkey);
1014 pcg 1.36 break;
1015 pcg 1.1
1016     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
1017 pcg 1.36 case KeyRelease:
1018     {
1019 root 1.97 if (!(ev.xkey.state & ControlMask))
1020     slip_wheel_ev.stop ();
1021 pcg 1.36 else
1022     {
1023 root 1.97 KeySym ks;
1024 pcg 1.36
1025 pcg 1.43 ks = XKeycodeToKeysym (display->display, ev.xkey.keycode, 0);
1026 pcg 1.36 if (ks == XK_Control_L || ks == XK_Control_R)
1027     mouse_slip_wheel_speed = 0;
1028     }
1029     break;
1030     }
1031     #endif
1032    
1033     case ButtonPress:
1034 pcg 1.38 button_press (ev.xbutton);
1035 pcg 1.36 break;
1036    
1037     case ButtonRelease:
1038 pcg 1.38 button_release (ev.xbutton);
1039 pcg 1.36 break;
1040    
1041     case ClientMessage:
1042 pcg 1.38 if (ev.xclient.format == 32
1043     && (Atom)ev.xclient.data.l[0] == xa[XA_WMDELETEWINDOW])
1044 pcg 1.34 destroy ();
1045 pcg 1.1 #ifdef OFFIX_DND
1046 pcg 1.36 /* OffiX Dnd (drag 'n' drop) protocol */
1047 pcg 1.38 else if (ev.xclient.message_type == xa[XA_DNDPROTOCOL]
1048     && (ev.xclient.data.l[0] == DndFile
1049     || ev.xclient.data.l[0] == DndDir
1050     || ev.xclient.data.l[0] == DndLink))
1051 pcg 1.36 {
1052     /* Get Dnd data */
1053 pcg 1.93 Atom ActualType;
1054     int ActualFormat;
1055     unsigned char *data;
1056     unsigned long Size, RemainingBytes;
1057 pcg 1.36
1058 pcg 1.43 XGetWindowProperty (display->display, display->root,
1059 pcg 1.36 xa[XA_DNDSELECTION],
1060     0L, 1000000L,
1061     False, AnyPropertyType,
1062     &ActualType, &ActualFormat,
1063     &Size, &RemainingBytes,
1064     &data);
1065 pcg 1.43 XChangeProperty (display->display, display->root,
1066 pcg 1.36 XA_CUT_BUFFER0, XA_STRING,
1067     8, PropModeReplace,
1068 pcg 1.43 data, STRLEN (data));
1069 pcg 1.93 XFree (data);
1070 pcg 1.38 selection_paste (display->root, XA_CUT_BUFFER0, True);
1071 pcg 1.43 XSetInputFocus (display->display, display->root, RevertToNone, CurrentTime);
1072 pcg 1.36 }
1073 pcg 1.1 #endif /* OFFIX_DND */
1074 pcg 1.36 break;
1075 pcg 1.1
1076 pcg 1.36 case MappingNotify:
1077 pcg 1.43 XRefreshKeyboardMapping (& (ev.xmapping));
1078 pcg 1.36 break;
1079    
1080     /*
1081     * XXX: this is not the _current_ arrangement
1082     * Here's my conclusion:
1083     * If the window is completely unobscured, use bitblt's
1084     * to scroll. Even then, they're only used when doing partial
1085     * screen scrolling. When partially obscured, we have to fill
1086     * in the GraphicsExpose parts, which means that after each refresh,
1087     * we need to wait for the graphics expose or Noexpose events,
1088     * which ought to make things real slow!
1089     */
1090     case VisibilityNotify:
1091 pcg 1.38 switch (ev.xvisibility.state)
1092 pcg 1.8 {
1093     case VisibilityUnobscured:
1094 pcg 1.34 refresh_type = FAST_REFRESH;
1095 pcg 1.8 break;
1096     case VisibilityPartiallyObscured:
1097 pcg 1.34 refresh_type = SLOW_REFRESH;
1098 pcg 1.8 break;
1099     default:
1100 pcg 1.34 refresh_type = NO_REFRESH;
1101 pcg 1.8 break;
1102     }
1103 pcg 1.36 break;
1104 pcg 1.1
1105 pcg 1.36 case FocusIn:
1106     if (!TermWin.focus)
1107     {
1108     TermWin.focus = 1;
1109     want_refresh = 1;
1110 pcg 1.1 #ifdef USE_XIM
1111 pcg 1.36 if (Input_Context != NULL)
1112 pcg 1.43 XSetICFocus (Input_Context);
1113 pcg 1.1 #endif
1114 pcg 1.5 #ifdef CURSOR_BLINK
1115 pcg 1.34 if (Options & Opt_cursorBlink)
1116     cursor_blink_ev.start (NOW + BLINK_INTERVAL);
1117 pcg 1.5 #endif
1118 pcg 1.1
1119 pcg 1.36 }
1120     break;
1121    
1122     case FocusOut:
1123     if (TermWin.focus)
1124     {
1125     TermWin.focus = 0;
1126     want_refresh = 1;
1127 pcg 1.1 #ifdef USE_XIM
1128 pcg 1.36 if (Input_Context != NULL)
1129 pcg 1.43 XUnsetICFocus (Input_Context);
1130 pcg 1.5 #endif
1131     #ifdef CURSOR_BLINK
1132 pcg 1.34 if (Options & Opt_cursorBlink)
1133     cursor_blink_ev.stop ();
1134     hidden_cursor = 0;
1135 pcg 1.1 #endif
1136    
1137 pcg 1.36 }
1138     break;
1139    
1140     case ConfigureNotify:
1141 pcg 1.38 if (ev.xconfigure.window == TermWin.parent[0])
1142 pcg 1.36 {
1143 pcg 1.38 int height, width;
1144 pcg 1.36
1145     do
1146     { /* Wrap lots of configures into one */
1147 pcg 1.38 width = ev.xconfigure.width;
1148     height = ev.xconfigure.height;
1149 pcg 1.43 D_SIZE ((stderr, "Size: ConfigureNotify: %4d x %4d", width, height));
1150 pcg 1.36 }
1151 pcg 1.43 while (XCheckTypedWindowEvent (display->display, ev.xconfigure.window, ConfigureNotify, &ev));
1152 pcg 1.38
1153 pcg 1.36 if (szHint.width != width || szHint.height != height)
1154     {
1155 pcg 1.43 D_SIZE ((stderr, "Size: Resizing from: %4d x %4d", szHint.width, szHint.height));
1156 pcg 1.36 resize_all_windows (width, height, 1);
1157     }
1158 pcg 1.1 #ifdef DEBUG_SIZE
1159 pcg 1.36 else
1160     {
1161 pcg 1.43 D_SIZE ((stderr, "Size: Not resizing"));
1162 pcg 1.36 }
1163 pcg 1.1 #endif
1164     #ifdef TRANSPARENT /* XXX: maybe not needed - leave in for now */
1165 pcg 1.36 if (Options & Opt_transparent)
1166     {
1167     check_our_parents ();
1168     if (am_transparent)
1169     want_full_refresh = 1;
1170     }
1171     #endif
1172     }
1173     break;
1174    
1175     case SelectionClear:
1176 pcg 1.81 selection_clear ();
1177 pcg 1.36 break;
1178    
1179     case SelectionNotify:
1180     if (selection_wait == Sel_normal)
1181 pcg 1.38 selection_paste (ev.xselection.requestor,
1182     ev.xselection.property, True);
1183 pcg 1.36 break;
1184    
1185     case SelectionRequest:
1186 pcg 1.38 selection_send (ev.xselectionrequest);
1187 pcg 1.36 break;
1188 pcg 1.1
1189 pcg 1.36 case UnmapNotify:
1190     TermWin.mapped = 0;
1191 pcg 1.31 #ifdef TEXT_BLINK
1192 pcg 1.34 text_blink_ev.stop ();
1193 pcg 1.31 #endif
1194 pcg 1.36 break;
1195 pcg 1.1
1196 pcg 1.36 case MapNotify:
1197     TermWin.mapped = 1;
1198 pcg 1.31 #ifdef TEXT_BLINK
1199 pcg 1.34 text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
1200 pcg 1.31 #endif
1201 pcg 1.36 break;
1202 pcg 1.1
1203     #ifdef TRANSPARENT
1204 pcg 1.36 case ReparentNotify:
1205 pcg 1.38 rootwin_cb (ev);
1206     break;
1207 pcg 1.1 #endif /* TRANSPARENT */
1208    
1209 pcg 1.36 case GraphicsExpose:
1210     case Expose:
1211 pcg 1.38 if (ev.xany.window == TermWin.vt)
1212 pcg 1.36 {
1213 pcg 1.1 #ifdef NO_SLOW_LINK_SUPPORT
1214 pcg 1.38 scr_expose (ev.xexpose.x, ev.xexpose.y,
1215     ev.xexpose.width, ev.xexpose.height, False);
1216 pcg 1.1 #else
1217 pcg 1.95 // I don't understand this, so I changed it :)
1218 pcg 1.38 scr_expose (ev.xexpose.x, ev.xexpose.y,
1219     ev.xexpose.width, ev.xexpose.height, False);
1220     //scr_expose (ev.xexpose.x, 0,
1221     // ev.xexpose.width, TermWin.height, False);
1222 pcg 1.36 #endif
1223     want_refresh = 1;
1224     }
1225     else
1226     {
1227 pcg 1.38 XEvent unused_event;
1228 pcg 1.36
1229 pcg 1.95 while (XCheckTypedWindowEvent (display->display, ev.xany.window, Expose, &unused_event))
1230     ;
1231     while (XCheckTypedWindowEvent (display->display, ev.xany.window, GraphicsExpose, &unused_event))
1232     ;
1233    
1234 pcg 1.43 if (isScrollbarWindow (ev.xany.window))
1235 pcg 1.36 {
1236 pcg 1.43 scrollBar.setIdle ();
1237 pcg 1.36 scrollbar_show (0);
1238     }
1239 pcg 1.1 #ifdef MENUBAR
1240 pcg 1.43 if (menubar_visible () && isMenuBarWindow (ev.xany.window))
1241 pcg 1.36 menubar_expose ();
1242 pcg 1.1 #endif
1243 pcg 1.36 }
1244     break;
1245    
1246     case MotionNotify:
1247 pcg 1.1 #ifdef POINTER_BLANK
1248 pcg 1.36 if (hidden_pointer)
1249     pointer_unblank ();
1250 pcg 1.1 #endif
1251     #if MENUBAR
1252 pcg 1.43 if (isMenuBarWindow (ev.xany.window))
1253 pcg 1.36 {
1254 pcg 1.56 menubar_control (ev.xbutton);
1255 pcg 1.36 break;
1256     }
1257     #endif
1258 pcg 1.43 if ((PrivateModes & PrivMode_mouse_report) && ! (bypass_keystate))
1259 pcg 1.36 break;
1260    
1261 pcg 1.38 if (ev.xany.window == TermWin.vt)
1262 pcg 1.36 {
1263 pcg 1.38 if ((ev.xbutton.state & (Button1Mask | Button3Mask)))
1264 pcg 1.36 {
1265 pcg 1.38 while (XCheckTypedWindowEvent (display->display, TermWin.vt, MotionNotify, &ev))
1266     ;
1267    
1268 pcg 1.43 XQueryPointer (display->display, TermWin.vt,
1269 pcg 1.36 &unused_root, &unused_child,
1270     &unused_root_x, &unused_root_y,
1271 pcg 1.43 & (ev.xbutton.x), & (ev.xbutton.y),
1272 pcg 1.36 &unused_mask);
1273 pcg 1.1 #ifdef MOUSE_THRESHOLD
1274 pcg 1.36 /* deal with a `jumpy' mouse */
1275 pcg 1.38 if ((ev.xmotion.time - MEvent.time) > MOUSE_THRESHOLD)
1276 pcg 1.36 {
1277 pcg 1.1 #endif
1278 pcg 1.38 selection_extend ((ev.xbutton.x), (ev.xbutton.y),
1279     (ev.xbutton.state & Button3Mask) ? 2 : 0);
1280 pcg 1.1 #ifdef SELECTION_SCROLLING
1281 pcg 1.38 if (ev.xbutton.y < TermWin.int_bwidth
1282 pcg 1.43 || Pixel2Row (ev.xbutton.y) > (TermWin.nrow-1))
1283 pcg 1.36 {
1284     int dist;
1285    
1286     /* don't clobber the current delay if we are
1287     * already in the middle of scrolling.
1288     */
1289 root 1.97 if (!sel_scroll_ev.active)
1290     sel_scroll_ev.start (NOW + SCROLLBAR_INITIAL_DELAY);
1291 pcg 1.36
1292     /* save the event params so we can highlight
1293     * the selection in the pending-scroll loop
1294     */
1295 pcg 1.38 selection_save_x=ev.xbutton.x;
1296     selection_save_y=ev.xbutton.y;
1297 pcg 1.36 selection_save_state=
1298 pcg 1.38 (ev.xbutton.state & Button3Mask) ? 2 : 0;
1299 pcg 1.36
1300     /* calc number of lines to scroll */
1301 pcg 1.38 if (ev.xbutton.y<TermWin.int_bwidth)
1302 pcg 1.36 {
1303     scroll_selection_dir = UP;
1304 pcg 1.38 dist = TermWin.int_bwidth - ev.xbutton.y;
1305 pcg 1.36 }
1306     else
1307     {
1308     scroll_selection_dir = DN;
1309 pcg 1.38 dist = ev.xbutton.y -
1310 pcg 1.36 (TermWin.int_bwidth + TermWin.height);
1311     }
1312 pcg 1.43 scroll_selection_lines= (Pixel2Height (dist)/
1313 pcg 1.36 SELECTION_SCROLL_LINE_SPEEDUP)+1;
1314 pcg 1.43 MIN_IT (scroll_selection_lines,
1315 pcg 1.36 SELECTION_SCROLL_MAX_LINES);
1316     }
1317     else
1318     {
1319     /* we are within the text window, so we
1320     * shouldn't be scrolling
1321     */
1322 root 1.97 if (sel_scroll_ev.active)
1323     sel_scroll_ev.stop();
1324 pcg 1.36 }
1325 pcg 1.1 #endif
1326     #ifdef MOUSE_THRESHOLD
1327 pcg 1.36
1328     }
1329 pcg 1.1 #endif
1330 pcg 1.36
1331     }
1332     }
1333 pcg 1.43 else if (isScrollbarWindow (ev.xany.window) && scrollbar_isMotion ())
1334 pcg 1.36 {
1335 pcg 1.43 while (XCheckTypedWindowEvent (display->display, scrollBar.win,
1336 pcg 1.38 MotionNotify, &ev)) ;
1337 pcg 1.43 XQueryPointer (display->display, scrollBar.win,
1338 pcg 1.36 &unused_root, &unused_child,
1339     &unused_root_x, &unused_root_y,
1340 pcg 1.43 & (ev.xbutton.x), & (ev.xbutton.y),
1341 pcg 1.36 &unused_mask);
1342 pcg 1.43 scr_move_to (scrollbar_position (ev.xbutton.y) - csrO,
1343     scrollbar_size ());
1344 pcg 1.36 scr_refresh (refresh_type);
1345     refresh_limit = 0;
1346     scrollbar_show (1);
1347     }
1348     break;
1349     }
1350     }
1351 pcg 1.1
1352     void
1353 pcg 1.38 rxvt_term::rootwin_cb (XEvent &ev)
1354     {
1355     SET_R (this);
1356     SET_LOCALE (locale);
1357    
1358 pcg 1.40 switch (ev.type)
1359 pcg 1.38 {
1360 pcg 1.40 case PropertyNotify:
1361     if (ev.xproperty.atom == xa[XA_VT_SELECTION])
1362     {
1363     if (ev.xproperty.state == PropertyNewValue)
1364     selection_property (ev.xproperty.window, ev.xproperty.atom);
1365     break;
1366     }
1367     #ifdef TRANSPARENT
1368     else
1369     {
1370     /*
1371     * if user used some Esetroot compatible prog to set the root bg,
1372     * use the property to determine the pixmap. We use it later on.
1373     */
1374     if (xa[XA_XROOTPMAPID] == 0)
1375 pcg 1.43 xa[XA_XROOTPMAPID] = XInternAtom (display->display, "_XROOTPMAP_ID", False);
1376 pcg 1.38
1377 pcg 1.40 if (ev.xproperty.atom != xa[XA_XROOTPMAPID])
1378     return;
1379     }
1380 pcg 1.38
1381 pcg 1.40 /* FALLTHROUGH */
1382     case ReparentNotify:
1383 pcg 1.90 if ((Options & Opt_transparent) && check_our_parents () && am_transparent)
1384     want_full_refresh = 1;
1385 pcg 1.40 break;
1386     #endif
1387 pcg 1.38 }
1388     }
1389    
1390     void
1391 pcg 1.56 rxvt_term::button_press (XButtonEvent &ev)
1392 pcg 1.1 {
1393 pcg 1.36 int reportmode = 0, clickintime;
1394 pcg 1.1
1395 pcg 1.38 bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
1396 pcg 1.36 if (!bypass_keystate)
1397 pcg 1.43 reportmode = !! (PrivateModes & PrivMode_mouse_report);
1398 pcg 1.36 /*
1399     * VT window processing of button press
1400     */
1401 pcg 1.38 if (ev.window == TermWin.vt)
1402 pcg 1.36 {
1403 pcg 1.50 clickintime = ev.time - MEvent.time < MULTICLICK_TIME;
1404     if (reportmode)
1405 pcg 1.36 {
1406 pcg 1.50 /* mouse report from vt window */
1407     /* save the xbutton state (for ButtonRelease) */
1408     MEvent.state = ev.state;
1409     #ifdef MOUSE_REPORT_DOUBLECLICK
1410     if (ev.button == MEvent.button && clickintime)
1411 pcg 1.36 {
1412 pcg 1.50 /* same button, within alloted time */
1413     MEvent.clicks++;
1414     if (MEvent.clicks > 1)
1415 pcg 1.36 {
1416 pcg 1.50 /* only report double clicks */
1417     MEvent.clicks = 2;
1418 pcg 1.36 mouse_report (ev);
1419 pcg 1.50
1420     /* don't report the release */
1421     MEvent.clicks = 0;
1422     MEvent.button = AnyButton;
1423 pcg 1.36 }
1424 pcg 1.50 }
1425     else
1426     {
1427     /* different button, or time expired */
1428     MEvent.clicks = 1;
1429 pcg 1.38 MEvent.button = ev.button;
1430 pcg 1.36 mouse_report (ev);
1431 pcg 1.50 }
1432     #else
1433     MEvent.button = ev.button;
1434     mouse_report (ev);
1435 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1436 pcg 1.36
1437 pcg 1.50 }
1438     else
1439     {
1440     if (ev.button != MEvent.button)
1441     MEvent.clicks = 0;
1442     switch (ev.button)
1443 pcg 1.36 {
1444 pcg 1.50 case Button1:
1445     /* allow shift+left click to extend selection */
1446     if (ev.state & ShiftMask && ! (PrivateModes & PrivMode_mouse_report))
1447     {
1448     if (MEvent.button == Button1 && clickintime)
1449     selection_rotate (ev.x, ev.y);
1450     else
1451     selection_extend (ev.x, ev.y, 1);
1452     }
1453     else
1454     {
1455     if (MEvent.button == Button1 && clickintime)
1456     MEvent.clicks++;
1457 pcg 1.36 else
1458 pcg 1.50 MEvent.clicks = 1;
1459 pcg 1.21
1460 pcg 1.50 selection_click (MEvent.clicks, ev.x, ev.y);
1461     }
1462 pcg 1.21
1463 pcg 1.50 MEvent.button = Button1;
1464     break;
1465 pcg 1.1
1466 pcg 1.50 case Button3:
1467     if (MEvent.button == Button3 && clickintime)
1468     selection_rotate (ev.x, ev.y);
1469     else
1470     selection_extend (ev.x, ev.y, 1);
1471     MEvent.button = Button3;
1472     break;
1473 pcg 1.36 }
1474     }
1475 pcg 1.50 MEvent.time = ev.time;
1476     return;
1477 pcg 1.36 }
1478 pcg 1.1
1479 pcg 1.36 /*
1480     * Scrollbar window processing of button press
1481     */
1482 pcg 1.43 if (isScrollbarWindow (ev.window))
1483 pcg 1.36 {
1484     scrollBar.setIdle ();
1485     /*
1486     * Rxvt-style scrollbar:
1487     * move up if mouse is above slider
1488     * move dn if mouse is below slider
1489     *
1490     * XTerm-style scrollbar:
1491     * Move display proportional to pointer location
1492     * pointer near top -> scroll one line
1493     * pointer near bot -> scroll full page
1494     */
1495 pcg 1.1 #ifndef NO_SCROLLBAR_REPORT
1496 pcg 1.36 if (reportmode)
1497     {
1498     /*
1499     * Mouse report disabled scrollbar:
1500     * arrow buttons - send up/down
1501     * click on scrollbar - send pageup/down
1502     */
1503     if ((scrollBar.style == R_SB_NEXT
1504 pcg 1.43 && scrollbarnext_upButton (ev.y))
1505 pcg 1.36 || (scrollBar.style == R_SB_RXVT
1506 pcg 1.43 && scrollbarrxvt_upButton (ev.y)))
1507     tt_printf ("\033[A");
1508 pcg 1.36 else if ((scrollBar.style == R_SB_NEXT
1509 pcg 1.43 && scrollbarnext_dnButton (ev.y))
1510 pcg 1.36 || (scrollBar.style == R_SB_RXVT
1511 pcg 1.43 && scrollbarrxvt_dnButton (ev.y)))
1512     tt_printf ("\033[B");
1513 pcg 1.36 else
1514 pcg 1.38 switch (ev.button)
1515 pcg 1.36 {
1516     case Button2:
1517 pcg 1.43 tt_printf ("\014");
1518 pcg 1.36 break;
1519     case Button1:
1520 pcg 1.43 tt_printf ("\033[6~");
1521 pcg 1.36 break;
1522     case Button3:
1523 pcg 1.43 tt_printf ("\033[5~");
1524 pcg 1.36 break;
1525     }
1526     }
1527     else
1528 pcg 1.1 #endif /* NO_SCROLLBAR_REPORT */
1529    
1530 pcg 1.36 {
1531     char upordown = 0;
1532    
1533     if (scrollBar.style == R_SB_NEXT)
1534     {
1535 pcg 1.43 if (scrollbarnext_upButton (ev.y))
1536 pcg 1.36 upordown = -1; /* up */
1537 pcg 1.43 else if (scrollbarnext_dnButton (ev.y))
1538 pcg 1.36 upordown = 1; /* down */
1539     }
1540     else if (scrollBar.style == R_SB_RXVT)
1541     {
1542 pcg 1.43 if (scrollbarrxvt_upButton (ev.y))
1543 pcg 1.36 upordown = -1; /* up */
1544 pcg 1.43 else if (scrollbarrxvt_dnButton (ev.y))
1545 pcg 1.36 upordown = 1; /* down */
1546     }
1547     if (upordown)
1548     {
1549 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1550 root 1.97 cont_scroll_ev.start (NOW + SCROLLBAR_INITIAL_DELAY);
1551 pcg 1.1 #endif
1552 pcg 1.36 if (scr_page (upordown < 0 ? UP : DN, 1))
1553     {
1554     if (upordown < 0)
1555     scrollBar.setUp ();
1556     else
1557     scrollBar.setDn ();
1558     }
1559     }
1560     else
1561 pcg 1.38 switch (ev.button)
1562 pcg 1.36 {
1563     case Button2:
1564     switch (scrollbar_align)
1565     {
1566     case R_SB_ALIGN_TOP:
1567     csrO = 0;
1568     break;
1569     case R_SB_ALIGN_CENTRE:
1570     csrO = (scrollBar.bot - scrollBar.top) / 2;
1571     break;
1572     case R_SB_ALIGN_BOTTOM:
1573     csrO = scrollBar.bot - scrollBar.top;
1574     break;
1575     }
1576     if (scrollBar.style == R_SB_XTERM
1577 pcg 1.43 || scrollbar_above_slider (ev.y)
1578     || scrollbar_below_slider (ev.y))
1579     scr_move_to ( scrollbar_position (ev.y) - csrO,
1580     scrollbar_size ());
1581 pcg 1.36 scrollBar.setMotion ();
1582     break;
1583    
1584     case Button1:
1585     if (scrollbar_align == R_SB_ALIGN_CENTRE)
1586 pcg 1.38 csrO = ev.y - scrollBar.top;
1587 pcg 1.36 /* FALLTHROUGH */
1588    
1589     case Button3:
1590     if (scrollBar.style != R_SB_XTERM)
1591     {
1592 pcg 1.43 if (scrollbar_above_slider (ev.y))
1593 pcg 1.1 # ifdef RXVT_SCROLL_FULL
1594 pcg 1.36 scr_page (UP, TermWin.nrow - 1);
1595 pcg 1.1 # else
1596 pcg 1.36 scr_page (UP, TermWin.nrow / 4);
1597 pcg 1.1 # endif
1598 pcg 1.43 else if (scrollbar_below_slider (ev.y))
1599 pcg 1.1 # ifdef RXVT_SCROLL_FULL
1600 pcg 1.36 scr_page (DN, TermWin.nrow - 1);
1601 pcg 1.1 # else
1602 pcg 1.36 scr_page (DN, TermWin.nrow / 4);
1603 pcg 1.1 # endif
1604 pcg 1.36 else
1605     scrollBar.setMotion ();
1606     }
1607     else
1608     {
1609 pcg 1.38 scr_page ((ev.button == Button1 ? DN : UP),
1610 pcg 1.36 (TermWin.nrow
1611 pcg 1.43 * scrollbar_position (ev.y)
1612     / scrollbar_size ()));
1613 pcg 1.36 }
1614     break;
1615     }
1616     }
1617     return;
1618 pcg 1.1 }
1619     #if MENUBAR
1620 pcg 1.36 /*
1621     * Menubar window processing of button press
1622     */
1623 pcg 1.43 if (isMenuBarWindow (ev.window))
1624 pcg 1.36 menubar_control (ev);
1625 pcg 1.1 #endif
1626     }
1627    
1628     void
1629 pcg 1.56 rxvt_term::button_release (XButtonEvent &ev)
1630 pcg 1.1 {
1631 pcg 1.38 int reportmode = 0;
1632 pcg 1.1
1633 pcg 1.36 csrO = 0; /* reset csr Offset */
1634     if (!bypass_keystate)
1635 pcg 1.43 reportmode = !! (PrivateModes & PrivMode_mouse_report);
1636 pcg 1.36
1637 pcg 1.43 if (scrollbar_isUpDn ())
1638 pcg 1.36 {
1639     scrollBar.setIdle ();
1640     scrollbar_show (0);
1641 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1642 pcg 1.36 refresh_type &= ~SMOOTH_REFRESH;
1643 pcg 1.1 #endif
1644 pcg 1.36
1645 pcg 1.1 }
1646     #ifdef SELECTION_SCROLLING
1647 root 1.97 if (sel_scroll_ev.active)
1648     sel_scroll_ev.stop();
1649 pcg 1.1 #endif
1650 pcg 1.38 if (ev.window == TermWin.vt)
1651 pcg 1.36 {
1652 pcg 1.50 if (reportmode)
1653 pcg 1.36 {
1654 pcg 1.50 /* mouse report from vt window */
1655     /* don't report release of wheel "buttons" */
1656     if (ev.button >= 4)
1657     return;
1658     #ifdef MOUSE_REPORT_DOUBLECLICK
1659     /* only report the release of 'slow' single clicks */
1660     if (MEvent.button != AnyButton
1661     && (ev.button != MEvent.button
1662     || (ev.time - MEvent.time
1663     > MULTICLICK_TIME / 2)))
1664 pcg 1.36 {
1665 pcg 1.50 MEvent.clicks = 0;
1666 pcg 1.36 MEvent.button = AnyButton;
1667     mouse_report (ev);
1668 pcg 1.50 }
1669     #else /* MOUSE_REPORT_DOUBLECLICK */
1670     MEvent.button = AnyButton;
1671     mouse_report (ev);
1672 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1673 pcg 1.50 return;
1674     }
1675     /*
1676     * dumb hack to compensate for the failure of click-and-drag
1677     * when overriding mouse reporting
1678     */
1679     if (PrivateModes & PrivMode_mouse_report
1680     && bypass_keystate
1681     && ev.button == Button1 && MEvent.clicks <= 1)
1682     selection_extend (ev.x, ev.y, 0);
1683    
1684     switch (ev.button)
1685     {
1686     case Button1:
1687     case Button3:
1688     selection_make (ev.time);
1689     break;
1690     case Button2:
1691     selection_request (ev.time, ev.x, ev.y);
1692     break;
1693     #ifdef MOUSE_WHEEL
1694     case Button4:
1695     case Button5:
1696 pcg 1.36 {
1697 pcg 1.50 int i;
1698     page_dirn v;
1699 pcg 1.36
1700 root 1.97 v = ev.button == Button4 ? UP : DN;
1701    
1702 pcg 1.50 if (ev.state & ShiftMask)
1703     i = 1;
1704 root 1.97 else if (Options & Opt_mouseWheelScrollPage)
1705 pcg 1.50 i = TermWin.nrow - 1;
1706     else
1707     i = 5;
1708 root 1.97
1709 pcg 1.1 # ifdef MOUSE_SLIP_WHEELING
1710 pcg 1.50 if (ev.state & ControlMask)
1711     {
1712 root 1.97 mouse_slip_wheel_speed += v ? -1 : 1;
1713     slip_wheel_ev.start (NOW + SCROLLBAR_CONTINUOUS_DELAY);
1714 pcg 1.50 }
1715 pcg 1.1 # endif
1716     # ifdef JUMP_MOUSE_WHEEL
1717 pcg 1.50 scr_page (v, i);
1718     scr_refresh (SMOOTH_REFRESH);
1719     scrollbar_show (1);
1720     # else
1721     while (i--)
1722     {
1723     scr_page (v, 1);
1724 pcg 1.36 scr_refresh (SMOOTH_REFRESH);
1725     scrollbar_show (1);
1726 pcg 1.50 }
1727 pcg 1.1 # endif
1728 pcg 1.36
1729 pcg 1.50 }
1730     break;
1731 pcg 1.1 #endif
1732 pcg 1.36
1733     }
1734     }
1735 pcg 1.1 #ifdef MENUBAR
1736 pcg 1.43 else if (isMenuBarWindow (ev.window))
1737 pcg 1.36 menubar_control (ev);
1738 pcg 1.1 #endif
1739     }
1740    
1741 pcg 1.90 #ifdef TRANSPARENT
1742     #if TINTING
1743     /* shading taken from eterm-0.9.2 */
1744     /* RGB 15 */
1745    
1746     static void
1747     shade_ximage_15(void *data, int bpl, int w, int h, int rm, int gm, int bm)
1748     {
1749     unsigned char *ptr;
1750     int x, y;
1751    
1752     ptr = (unsigned char *)data + (w * sizeof(uint16_t));
1753     if ((rm <= 256) && (gm <= 256) && (bm <= 256)) {
1754     /* No saturation */
1755     for (y = h; --y >= 0;) {
1756     for (x = -w; x < 0; x++) {
1757     int r, g, b;
1758    
1759     b = ((uint16_t *) ptr)[x];
1760     r = (b & 0x7c00) * rm;
1761     g = (b & 0x3e0) * gm;
1762     b = (b & 0x1f) * bm;
1763     ((uint16_t *) ptr)[x] = ((r >> 8) & 0x7c00)
1764     | ((g >> 8) & 0x3e0)
1765     | ((b >> 8) & 0x1f);
1766     }
1767     ptr += bpl;
1768     }
1769     } else {
1770     for (y = h; --y >= 0;) {
1771     for (x = -w; x < 0; x++) {
1772     int r, g, b;
1773    
1774     b = ((uint16_t *) ptr)[x];
1775     r = (b & 0x7c00) * rm;
1776     g = (b & 0x3e0) * gm;
1777     b = (b & 0x1f) * bm;
1778     r |= (!(r >> 15) - 1);
1779     g |= (!(g >> 10) - 1);
1780     b |= (!(b >> 5) - 1);
1781     ((uint16_t *) ptr)[x] = ((r >> 8) & 0x7c00)
1782     | ((g >> 8) & 0x3e0)
1783     | ((b >> 8) & 0x1f);
1784     }
1785     ptr += bpl;
1786     }
1787     }
1788     }
1789    
1790     /* RGB 16 */
1791     static void
1792     shade_ximage_16(void *data, int bpl, int w, int h, int rm, int gm, int bm)
1793     {
1794     unsigned char *ptr;
1795     int x, y;
1796    
1797     ptr = (unsigned char *)data + (w * sizeof(uint16_t));
1798     if ((rm <= 256) && (gm <= 256) && (bm <= 256)) {
1799     /* No saturation */
1800     for (y = h; --y >= 0;) {
1801     for (x = -w; x < 0; x++) {
1802     int r, g, b;
1803    
1804     b = ((uint16_t *) ptr)[x];
1805     r = (b & 0xf800) * rm;
1806     g = (b & 0x7e0) * gm;
1807     b = (b & 0x1f) * bm;
1808     ((uint16_t *) ptr)[x] = ((r >> 8) & 0xf800)
1809     | ((g >> 8) & 0x7e0)
1810     | ((b >> 8) & 0x1f);
1811     }
1812     ptr += bpl;
1813     }
1814     } else {
1815     for (y = h; --y >= 0;) {
1816     for (x = -w; x < 0; x++) {
1817     int r, g, b;
1818    
1819     b = ((uint16_t *) ptr)[x];
1820     r = (b & 0xf800) * rm;
1821     g = (b & 0x7e0) * gm;
1822     b = (b & 0x1f) * bm;
1823     r |= (!(r >> 16) - 1);
1824     g |= (!(g >> 11) - 1);
1825     b |= (!(b >> 5) - 1);
1826     ((uint16_t *) ptr)[x] = ((r >> 8) & 0xf800)
1827     | ((g >> 8) & 0x7e0)
1828     | ((b >> 8) & 0x1f);
1829     }
1830     ptr += bpl;
1831     }
1832     }
1833     }
1834    
1835     /* RGB 24 */
1836     static void
1837     shade_ximage_24(void *data, int bpl, int w, int h, int rm, int gm, int bm)
1838     {
1839     unsigned char *ptr;
1840     int x, y;
1841    
1842     ptr = (unsigned char *)data + (w * 3);
1843     if ((rm <= 256) && (gm <= 256) && (bm <= 256)) {
1844     /* No saturation */
1845     for (y = h; --y >= 0;) {
1846     for (x = -(w * 3); x < 0; x += 3) {
1847     int r, g, b;
1848    
1849     if (byteorder.big_endian()) {
1850     r = (ptr[x + 0] * rm) >> 8;
1851     g = (ptr[x + 1] * gm) >> 8;
1852     b = (ptr[x + 2] * bm) >> 8;
1853     ptr[x + 0] = r;
1854     ptr[x + 1] = g;
1855     ptr[x + 2] = b;
1856     } else {
1857     r = (ptr[x + 2] * rm) >> 8;
1858     g = (ptr[x + 1] * gm) >> 8;
1859     b = (ptr[x + 0] * bm) >> 8;
1860     ptr[x + 2] = r;
1861     ptr[x + 1] = g;
1862     ptr[x + 0] = b;
1863     }
1864     }
1865     ptr += bpl;
1866     }
1867     } else {
1868     for (y = h; --y >= 0;) {
1869     for (x = -(w * 3); x < 0; x += 3) {
1870     int r, g, b;
1871    
1872     if (byteorder.big_endian()) {
1873     r = (ptr[x + 0] * rm) >> 8;
1874     g = (ptr[x + 1] * gm) >> 8;
1875     b = (ptr[x + 2] * bm) >> 8;
1876    
1877     r |= (!(r >> 8) - 1);
1878     g |= (!(g >> 8) - 1);
1879     b |= (!(b >> 8) - 1);
1880    
1881     ptr[x + 0] = r;
1882     ptr[x + 1] = g;
1883     ptr[x + 2] = b;
1884     } else {
1885     r = (ptr[x + 2] * rm) >> 8;
1886     g = (ptr[x + 1] * gm) >> 8;
1887     b = (ptr[x + 0] * bm) >> 8;
1888    
1889     r |= (!(r >> 8) - 1);
1890     g |= (!(g >> 8) - 1);
1891     b |= (!(b >> 8) - 1);
1892    
1893     ptr[x + 2] = r;
1894     ptr[x + 1] = g;
1895     ptr[x + 0] = b;
1896     }
1897     }
1898     ptr += bpl;
1899     }
1900     }
1901     }
1902    
1903     /* RGB 32 */
1904     static void
1905     shade_ximage_32(void *data, int bpl, int w, int h, int rm, int gm, int bm)
1906     {
1907     unsigned char *ptr;
1908     int x, y;
1909    
1910     ptr = (unsigned char *)data + (w * 4);
1911     if ((rm <= 256) && (gm <= 256) && (bm <= 256)) {
1912     /* No saturation */
1913     for (y = h; --y >= 0;) {
1914     if (byteorder.big_endian()) {
1915     for (x = -(w * 4); x < 0; x += 4) {
1916     int r, g, b;
1917    
1918     r = (ptr[x + 1] * rm) >> 8;
1919     g = (ptr[x + 2] * gm) >> 8;
1920     b = (ptr[x + 3] * bm) >> 8;
1921     ptr[x + 1] = r;
1922     ptr[x + 2] = g;
1923     ptr[x + 3] = b;
1924     }
1925     } else {
1926     for (x = -(w * 4); x < 0; x += 4) {
1927     int r, g, b;
1928    
1929     r = (ptr[x + 2] * rm) >> 8;
1930     g = (ptr[x + 1] * gm) >> 8;
1931     b = (ptr[x + 0] * bm) >> 8;
1932     ptr[x + 2] = r;
1933     ptr[x + 1] = g;
1934     ptr[x + 0] = b;
1935     }
1936     }
1937     ptr += bpl;
1938     }
1939     } else {
1940     for (y = h; --y >= 0;) {
1941     for (x = -(w * 4); x < 0; x += 4) {
1942     int r, g, b;
1943    
1944     if (byteorder.big_endian()) {
1945     r = (ptr[x + 1] * rm) >> 8;
1946     g = (ptr[x + 2] * gm) >> 8;
1947     b = (ptr[x + 3] * bm) >> 8;
1948    
1949     r |= (!(r >> 8) - 1);
1950     g |= (!(g >> 8) - 1);
1951     b |= (!(b >> 8) - 1);
1952    
1953     ptr[x + 1] = r;
1954     ptr[x + 2] = g;
1955     ptr[x + 3] = b;
1956     } else {
1957     r = (ptr[x + 2] * rm) >> 8;
1958     g = (ptr[x + 1] * gm) >> 8;
1959     b = (ptr[x + 0] * bm) >> 8;
1960    
1961     r |= (!(r >> 8) - 1);
1962     g |= (!(g >> 8) - 1);
1963     b |= (!(b >> 8) - 1);
1964    
1965     ptr[x + 2] = r;
1966     ptr[x + 1] = g;
1967     ptr[x + 0] = b;
1968     }
1969     }
1970     ptr += bpl;
1971     }
1972     }
1973     }
1974    
1975     #endif
1976 pcg 1.1
1977     /*
1978     * Check our parents are still who we think they are.
1979     * Do transparency updates if required
1980     */
1981     int
1982 pcg 1.34 rxvt_term::check_our_parents ()
1983 pcg 1.1 {
1984 pcg 1.90 int i, pchanged, aformat, have_pixmap, rootdepth;
1985     unsigned long nitems, bytes_after;
1986     Atom atype;
1987     unsigned char *prop = NULL;
1988     Window root, oldp, *list;
1989     Pixmap rootpixmap = None;
1990 pcg 1.36 XWindowAttributes wattr, wrootattr;
1991    
1992     pchanged = 0;
1993    
1994 pcg 1.90 if (!(Options & Opt_transparent))
1995 pcg 1.36 return pchanged; /* Don't try any more */
1996    
1997 pcg 1.43 XGetWindowAttributes (display->display, display->root, &wrootattr);
1998 pcg 1.36 rootdepth = wrootattr.depth;
1999    
2000 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
2001 pcg 1.90
2002 pcg 1.36 if (rootdepth != wattr.depth)
2003     {
2004     if (am_transparent)
2005     {
2006     pchanged = 1;
2007 pcg 1.90 XSetWindowBackground (display->display, TermWin.vt, PixColors[Color_bg]);
2008 pcg 1.36 am_transparent = am_pixmap_trans = 0;
2009     }
2010 pcg 1.90
2011 pcg 1.36 return pchanged; /* Don't try any more */
2012 pcg 1.1 }
2013    
2014 pcg 1.36 /* Get all X ops out of the queue so that our information is up-to-date. */
2015 pcg 1.43 XSync (display->display, False);
2016 pcg 1.1
2017 pcg 1.36 /*
2018     * Make the frame window set by the window manager have
2019     * the root background. Some window managers put multiple nested frame
2020     * windows for each client, so we have to take care about that.
2021     */
2022 pcg 1.90 i = (xa[XA_XROOTPMAPID]
2023     && XGetWindowProperty (display->display, display->root, xa[XA_XROOTPMAPID],
2024 pcg 1.36 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
2025 pcg 1.90 &nitems, &bytes_after, &prop) == Success);
2026    
2027     if (!i || prop == NULL)
2028     i = (xa[XA_XSETROOTID]
2029     && XGetWindowProperty (display->display, display->root, xa[XA_XSETROOTID],
2030     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
2031     &nitems, &bytes_after, &prop) == Success);
2032    
2033 pcg 1.36 if (!i || prop == NULL)
2034     have_pixmap = 0;
2035     else
2036     {
2037     have_pixmap = 1;
2038 pcg 1.93 rootpixmap = *(Pixmap *)prop;
2039 pcg 1.43 XFree (prop);
2040 pcg 1.1 }
2041 pcg 1.90
2042 pcg 1.36 if (have_pixmap)
2043     {
2044     /*
2045 pcg 1.38 * Copy display->root pixmap transparency
2046 pcg 1.36 */
2047 pcg 1.67 int sx, sy, nx, ny;
2048     unsigned int nw, nh;
2049     Window cr;
2050     XImage *image;
2051     GC gc;
2052     XGCValues gcvalue;
2053 pcg 1.36
2054 pcg 1.43 XTranslateCoordinates (display->display, TermWin.parent[0], display->root,
2055 pcg 1.90 0, 0, &sx, &sy, &cr);
2056 pcg 1.36 nw = (unsigned int)szHint.width;
2057     nh = (unsigned int)szHint.height;
2058     nx = ny = 0;
2059 pcg 1.67
2060 pcg 1.36 if (sx < 0)
2061     {
2062     nw += sx;
2063     nx = -sx;
2064     sx = 0;
2065     }
2066 pcg 1.67
2067 pcg 1.36 if (sy < 0)
2068     {
2069     nh += sy;
2070     ny = -sy;
2071     sy = 0;
2072     }
2073 pcg 1.67
2074 pcg 1.43 MIN_IT (nw, (unsigned int) (wrootattr.width - sx));
2075     MIN_IT (nh, (unsigned int) (wrootattr.height - sy));
2076 pcg 1.36 allowedxerror = -1;
2077 pcg 1.90 image = XGetImage (display->display, rootpixmap, sx, sy, nw, nh, AllPlanes, ZPixmap);
2078    
2079 pcg 1.36 /* XXX: handle BadMatch - usually because we're outside the pixmap */
2080     /* XXX: may need a delay here? */
2081     allowedxerror = 0;
2082 pcg 1.90
2083 pcg 1.36 if (image == NULL)
2084     {
2085     if (am_transparent && am_pixmap_trans)
2086     {
2087     pchanged = 1;
2088     if (TermWin.pixmap != None)
2089     {
2090 pcg 1.43 XFreePixmap (display->display, TermWin.pixmap);
2091 pcg 1.36 TermWin.pixmap = None;
2092     }
2093     }
2094 pcg 1.90
2095 pcg 1.36 am_pixmap_trans = 0;
2096     }
2097     else
2098     {
2099     if (TermWin.pixmap != None)
2100 pcg 1.43 XFreePixmap (display->display, TermWin.pixmap);
2101 pcg 1.90
2102     #if TINTING
2103     if (ISSET_PIXCOLOR (Color_tint))
2104     {
2105     unsigned short shade, rm, gm, bm;
2106    
2107     PixColors[Color_tint].get (display, rm, gm, bm);
2108    
2109     rm >>= 8; gm >>= 8; bm >>= 8; // not 100% correct, but...
2110    
2111     /* Determine bitshift and bitmask values */
2112     switch (image->bits_per_pixel)
2113     {
2114     case 15: shade_ximage_15 (image->data, image->bytes_per_line, image->width, image->height, rm, gm, bm); break;
2115     case 16: shade_ximage_16 (image->data, image->bytes_per_line, image->width, image->height, rm, gm, bm); break;
2116     case 24: shade_ximage_24 (image->data, image->bytes_per_line, image->width, image->height, rm, gm, bm); break;
2117     case 32: shade_ximage_32 (image->data, image->bytes_per_line, image->width, image->height, rm, gm, bm); break;
2118     }
2119     }
2120     #endif
2121    
2122 pcg 1.43 TermWin.pixmap = XCreatePixmap (display->display, TermWin.vt,
2123 pcg 1.90 szHint.width, szHint.height, image->depth);
2124 pcg 1.43 gc = XCreateGC (display->display, TermWin.vt, 0UL, &gcvalue);
2125     XPutImage (display->display, TermWin.pixmap, gc, image, 0, 0,
2126 pcg 1.90 nx, ny, image->width, image->height);
2127 pcg 1.43 XFreeGC (display->display, gc);
2128     XDestroyImage (image);
2129     XSetWindowBackgroundPixmap (display->display, TermWin.vt,
2130 pcg 1.36 TermWin.pixmap);
2131 pcg 1.90
2132 pcg 1.36 if (!am_transparent || !am_pixmap_trans)
2133     pchanged = 1;
2134 pcg 1.90
2135 pcg 1.36 am_transparent = am_pixmap_trans = 1;
2136     }
2137 pcg 1.1 }
2138 pcg 1.67
2139 pcg 1.36 if (!am_pixmap_trans)
2140     {
2141 pcg 1.90 unsigned int n;
2142 pcg 1.36 /*
2143     * InheritPixmap transparency
2144     */
2145 pcg 1.43 D_X ((stderr, "InheritPixmap Seeking to %08lx", display->root));
2146 pcg 1.90 for (i = 1; i < (int) (sizeof (TermWin.parent) / sizeof (Window)); i++)
2147 pcg 1.36 {
2148     oldp = TermWin.parent[i];
2149 pcg 1.43 XQueryTree (display->display, TermWin.parent[i - 1], &root,
2150 pcg 1.90 &TermWin.parent[i], &list, &n);
2151 pcg 1.43 XFree (list);
2152     D_X ((stderr, "InheritPixmap Parent[%d] = %08lx", i, TermWin.parent[i]));
2153 pcg 1.90
2154 pcg 1.38 if (TermWin.parent[i] == display->root)
2155 pcg 1.36 {
2156     if (oldp != None)
2157     pchanged = 1;
2158 pcg 1.90
2159 pcg 1.36 break;
2160     }
2161 pcg 1.90
2162 pcg 1.36 if (oldp != TermWin.parent[i])
2163     pchanged = 1;
2164     }
2165 pcg 1.67
2166 pcg 1.36 n = 0;
2167 pcg 1.67
2168 pcg 1.36 if (pchanged)
2169     {
2170     for (; n < (unsigned int)i; n++)
2171     {
2172 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[n], &wattr);
2173     D_X ((stderr, "InheritPixmap Checking Parent[%d]: %s", n, (wattr.depth == rootdepth && wattr.class != InputOnly) ? "OK" : "FAIL"));
2174 pcg 1.36 if (wattr.depth != rootdepth || wattr.c_class == InputOnly)
2175     {
2176 pcg 1.43 n = (int) (sizeof (TermWin.parent) / sizeof (Window)) + 1;
2177 pcg 1.36 break;
2178     }
2179     }
2180     }
2181 pcg 1.67
2182 pcg 1.90 if (n > (int) (sizeof (TermWin.parent) / sizeof (TermWin.parent[0])))
2183 pcg 1.36 {
2184 pcg 1.43 D_X ((stderr, "InheritPixmap Turning off"));
2185 pcg 1.90 XSetWindowBackground (display->display, TermWin.parent[0], PixColors[Color_fg]);
2186     XSetWindowBackground (display->display, TermWin.vt, PixColors[Color_bg]);
2187 pcg 1.36 am_transparent = 0;
2188     /* XXX: also turn off Opt_transparent? */
2189     }
2190     else
2191     {
2192 pcg 1.90 #if WAIT_FOR_WM
2193 pcg 1.36 /* wait (an arbitrary period) for the WM to do its thing
2194     * needed for fvwm2.2.2 (and before?) */
2195 pcg 1.43 sleep (1);
2196 pcg 1.90 #endif
2197 pcg 1.43 D_X ((stderr, "InheritPixmap Turning on (%d parents)", i - 1));
2198 pcg 1.36 for (n = 0; n < (unsigned int)i; n++)
2199 pcg 1.90 XSetWindowBackgroundPixmap (display->display, TermWin.parent[n], ParentRelative);
2200    
2201     XSetWindowBackgroundPixmap (display->display, TermWin.vt, ParentRelative);
2202 pcg 1.36 am_transparent = 1;
2203     }
2204 pcg 1.67
2205 pcg 1.43 for (; i < (int) (sizeof (TermWin.parent) / sizeof (Window)); i++)
2206 pcg 1.36 TermWin.parent[i] = None;
2207 pcg 1.1 }
2208 pcg 1.90
2209 pcg 1.36 return pchanged;
2210 pcg 1.1 }
2211     #endif
2212    
2213     /*}}} */
2214    
2215 pcg 1.81 bool
2216     rxvt_term::cmd_parse ()
2217     {
2218     bool flag = false;
2219     unicode_t ch = NOCHAR;
2220     unsigned char *seq_begin; // remember start of esc-sequence here
2221    
2222     for (;;)
2223     {
2224     if (ch == NOCHAR)
2225     {
2226     seq_begin = cmdbuf_ptr;
2227     ch = next_char ();
2228     }
2229    
2230     if (ch == NOCHAR) // TODO: improve
2231     break;
2232    
2233 pcg 1.93 if (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT)
2234 pcg 1.81 {
2235     /* Read a text string from the input buffer */
2236     unicode_t buf[UBUFSIZ];
2237     bool refreshnow = false;
2238     int nlines = 0;
2239     unicode_t *str = buf;
2240    
2241     *str++ = ch;
2242    
2243     for (;;)
2244     {
2245     seq_begin = cmdbuf_ptr;
2246     ch = next_char ();
2247    
2248 pcg 1.93 if (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT))
2249 pcg 1.81 break;
2250    
2251     *str++ = ch;
2252    
2253 pcg 1.93 if (ch == C0_LF)
2254 pcg 1.81 {
2255     nlines++;
2256     refresh_count++;
2257    
2258     if (! (Options & Opt_jumpScroll)
2259     || (refresh_count >= (refresh_limit * (TermWin.nrow - 1))))
2260     {
2261     refreshnow = true;
2262     flag = true;
2263     ch = NOCHAR;
2264     break;
2265     }
2266    
2267     // scr_add_lines only works for nlines < TermWin.nrow - 1.
2268     if (nlines >= TermWin.nrow - 1)
2269     {
2270     scr_add_lines (buf, nlines, str - buf);
2271     nlines = 0;
2272     str = buf;
2273     }
2274     }
2275    
2276     if (str >= buf + UBUFSIZ)
2277     {
2278     ch = NOCHAR;
2279     break;
2280     }
2281     }
2282    
2283     scr_add_lines (buf, nlines, str - buf);
2284    
2285     /*
2286     * If there have been a lot of new lines, then update the screen
2287     * What the heck I'll cheat and only refresh less than every page-full.
2288     * the number of pages between refreshes is refresh_limit, which
2289     * is incremented here because we must be doing flat-out scrolling.
2290     *
2291     * refreshing should be correct for small scrolls, because of the
2292     * time-out
2293     */
2294     if (refreshnow)
2295     {
2296     if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
2297     refresh_limit++;
2298 pcg 1.93 else
2299     scr_refresh (refresh_type);
2300 pcg 1.81 }
2301    
2302     }
2303     else
2304     {
2305     try
2306     {
2307     process_nonprinting (ch);
2308     }
2309     catch (const class out_of_input &o)
2310     {
2311     // we ran out of input, retry later
2312     cmdbuf_ptr = seq_begin;
2313     break;
2314     }
2315    
2316     ch = NOCHAR;
2317     }
2318     }
2319    
2320     return flag;
2321     }
2322    
2323 root 1.97 // read the next octet
2324     unicode_t
2325     rxvt_term::next_octet ()
2326     {
2327     return cmdbuf_ptr < cmdbuf_endp
2328     ? *cmdbuf_ptr++
2329     : NOCHAR;
2330     }
2331    
2332 pcg 1.81 // read the next character
2333     unicode_t
2334     rxvt_term::next_char ()
2335     {
2336     while (cmdbuf_ptr < cmdbuf_endp)
2337     {
2338     // assume 7-bit to be ascii ALWAYS
2339     if (*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b)
2340     return *cmdbuf_ptr++;
2341    
2342     wchar_t wc;
2343     size_t len = mbrtowc (&wc, (char *)cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
2344    
2345     if (len == (size_t)-2)
2346     {
2347     // the mbstate stores incomplete sequences. didn't know this :/
2348     cmdbuf_ptr = cmdbuf_endp;
2349     break;
2350     }
2351    
2352     if (len == (size_t)-1)
2353     return *cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
2354    
2355     // assume wchar == unicode
2356     cmdbuf_ptr += len;
2357     return wc;
2358     }
2359    
2360     return NOCHAR;
2361     }
2362    
2363     /* rxvt_cmd_getc () - Return next input character */
2364     /*
2365     * Return the next input character after first passing any keyboard input
2366     * to the command.
2367     */
2368     unicode_t
2369     rxvt_term::cmd_getc ()
2370     {
2371     unicode_t c = next_char ();
2372    
2373     if (c == NOCHAR)
2374     throw out_of_input;
2375    
2376     return c;
2377     }
2378    
2379 root 1.97 unicode_t
2380     rxvt_term::cmd_get8 ()
2381     {
2382     unicode_t c = next_octet ();
2383    
2384     if (c == NOCHAR)
2385     throw out_of_input;
2386    
2387     return c;
2388     }
2389    
2390 pcg 1.1 /*{{{ print pipe */
2391     /*----------------------------------------------------------------------*/
2392     #ifdef PRINTPIPE
2393 pcg 1.34 FILE *
2394     rxvt_term::popen_printer ()
2395 pcg 1.1 {
2396 pcg 1.67 FILE *stream = popen (rs[Rs_print_pipe], "w");
2397 pcg 1.1
2398 pcg 1.36 if (stream == NULL)
2399 pcg 1.81 rxvt_warn ("can't open printer pipe, not printing.\n");
2400    
2401 pcg 1.36 return stream;
2402 pcg 1.1 }
2403    
2404     int
2405 pcg 1.34 rxvt_term::pclose_printer (FILE *stream)
2406 pcg 1.1 {
2407 pcg 1.11 fflush (stream);
2408     return pclose (stream);
2409 pcg 1.1 }
2410    
2411     /*
2412     * simulate attached vt100 printer
2413     */
2414     void
2415 pcg 1.34 rxvt_term::process_print_pipe ()
2416 pcg 1.1 {
2417 pcg 1.81 int done;
2418     FILE *fd;
2419 pcg 1.36
2420     if ((fd = popen_printer ()) == NULL)
2421     return;
2422    
2423     /*
2424     * Send all input to the printer until either ESC[4i or ESC[?4i
2425     * is received.
2426     */
2427     for (done = 0; !done;)
2428     {
2429 pcg 1.81 unsigned char buf[8];
2430     unicode_t ch;
2431     unsigned int i, len;
2432 pcg 1.1
2433 pcg 1.36 if ((ch = cmd_getc ()) != C0_ESC)
2434     {
2435 pcg 1.43 if (putc (ch, fd) == EOF)
2436 pcg 1.36 break; /* done = 1 */
2437     }
2438     else
2439     {
2440     len = 0;
2441     buf[len++] = ch;
2442 pcg 1.1
2443 pcg 1.36 if ((buf[len++] = cmd_getc ()) == '[')
2444     {
2445     if ((ch = cmd_getc ()) == '?')
2446     {
2447     buf[len++] = '?';
2448     ch = cmd_getc ();
2449     }
2450     if ((buf[len++] = ch) == '4')
2451     {
2452     if ((buf[len++] = cmd_getc ()) == 'i')
2453     break; /* done = 1 */
2454     }
2455     }
2456 pcg 1.81
2457 pcg 1.36 for (i = 0; i < len; i++)
2458 pcg 1.43 if (putc (buf[i], fd) == EOF)
2459 pcg 1.36 {
2460     done = 1;
2461     break;
2462     }
2463     }
2464 pcg 1.1 }
2465 pcg 1.81
2466 pcg 1.36 pclose_printer (fd);
2467 pcg 1.1 }
2468     #endif /* PRINTPIPE */
2469     /*}}} */
2470    
2471     /* *INDENT-OFF* */
2472     enum {
2473 pcg 1.36 C1_40 = 0x40,
2474 pcg 1.90 C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
2475 pcg 1.36 C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
2476     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
2477 pcg 1.90 C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC,
2478 pcg 1.1 };
2479     /* *INDENT-ON* */
2480    
2481     /*{{{ process non-printing single characters */
2482     void
2483 pcg 1.81 rxvt_term::process_nonprinting (unicode_t ch)
2484 pcg 1.1 {
2485 pcg 1.36 switch (ch)
2486     {
2487 pcg 1.81 case C0_ESC:
2488     process_escape_seq ();
2489     break;
2490 pcg 1.36 case C0_ENQ: /* terminal Status */
2491     if (rs[Rs_answerbackstring])
2492 pcg 1.90 tt_write ((const unsigned char *)rs[Rs_answerbackstring],
2493     (unsigned int)STRLEN (rs[Rs_answerbackstring]));
2494 pcg 1.36 else
2495 pcg 1.43 tt_write ((unsigned char *)VT100_ANS,
2496 pcg 1.90 (unsigned int)STRLEN (VT100_ANS));
2497 pcg 1.36 break;
2498     case C0_BEL: /* bell */
2499     scr_bell ();
2500     break;
2501     case C0_BS: /* backspace */
2502     scr_backspace ();
2503     break;
2504     case C0_HT: /* tab */
2505     scr_tab (1);
2506     break;
2507     case C0_CR: /* carriage return */
2508     scr_gotorc (0, 0, R_RELATIVE);
2509     break;
2510     case C0_VT: /* vertical tab, form feed */
2511     case C0_FF:
2512     case C0_LF: /* line feed */
2513     scr_index (UP);
2514     break;
2515     case C0_SO: /* shift out - acs */
2516     scr_charset_choose (1);
2517     break;
2518     case C0_SI: /* shift in - acs */
2519     scr_charset_choose (0);
2520     break;
2521 pcg 1.81
2522 root 1.97 #ifdef EIGHT_BIT_CONTROLS
2523 pcg 1.81 // 8-bit controls
2524     case 0x90: /* DCS */
2525     process_dcs_seq ();
2526     break;
2527     case 0x9b: /* CSI */
2528     process_csi_seq ();
2529     break;
2530     case 0x9d: /* CSI */
2531     process_osc_seq ();
2532     break;
2533 root 1.97 #endif
2534 pcg 1.1 }
2535     }
2536     /*}}} */
2537    
2538    
2539     /*{{{ process VT52 escape sequences */
2540     void
2541 pcg 1.81 rxvt_term::process_escape_vt52 (unicode_t ch)
2542 pcg 1.1 {
2543 pcg 1.36 int row, col;
2544    
2545     switch (ch)
2546     {
2547     case 'A': /* cursor up */
2548     scr_gotorc (-1, 0, R_RELATIVE | C_RELATIVE);
2549     break;
2550     case 'B': /* cursor down */
2551     scr_gotorc (1, 0, R_RELATIVE | C_RELATIVE);
2552     break;
2553     case 'C': /* cursor right */
2554     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
2555     break;
2556     case 'D': /* cursor left */
2557     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
2558     break;
2559     case 'H': /* cursor home */
2560     scr_gotorc (0, 0, 0);
2561     break;
2562     case 'I': /* cursor up and scroll down if needed */
2563     scr_index (DN);
2564     break;
2565     case 'J': /* erase to end of screen */
2566     scr_erase_screen (0);
2567     break;
2568     case 'K': /* erase to end of line */
2569     scr_erase_line (0);
2570     break;
2571     case 'Y': /* move to specified row and col */
2572     /* full command is 'ESC Y row col' where row and col
2573     * are encoded by adding 32 and sending the ascii
2574     * character. eg. SPACE = 0, '+' = 13, '0' = 18,
2575     * etc. */
2576     row = cmd_getc () - ' ';
2577     col = cmd_getc () - ' ';
2578     scr_gotorc (row, col, 0);
2579     break;
2580     case 'Z': /* identify the terminal type */
2581 pcg 1.43 tt_printf ("\033/Z"); /* I am a VT100 emulating a VT52 */
2582 pcg 1.1 break;
2583 pcg 1.36 case '<': /* turn off VT52 mode */
2584 pcg 1.43 PrivMode (0, PrivMode_vt52);
2585 pcg 1.36 break;
2586     case 'F': /* use special graphics character set */
2587     case 'G': /* use regular character set */
2588     /* unimplemented */
2589     break;
2590     case '=': /* use alternate keypad mode */
2591     case '>': /* use regular keypad mode */
2592     /* unimplemented */
2593     break;
2594 pcg 1.1 }
2595     }
2596     /*}}} */
2597    
2598    
2599     /*{{{ process escape sequences */
2600     void
2601 pcg 1.34 rxvt_term::process_escape_seq ()
2602 pcg 1.1 {
2603 pcg 1.81 unicode_t ch = cmd_getc ();
2604 pcg 1.36
2605     if (PrivateModes & PrivMode_vt52)
2606     {
2607     process_escape_vt52 (ch);
2608     return;
2609     }
2610 pcg 1.1
2611 pcg 1.36 switch (ch)
2612     {
2613     /* case 1: do_tek_mode (); break; */
2614     case '#':
2615     if (cmd_getc () == '8')
2616     scr_E ();
2617     break;
2618 pcg 1.44 case '(':
2619 pcg 1.36 scr_charset_set (0, (unsigned int)cmd_getc ());
2620     break;
2621     case ')':
2622     scr_charset_set (1, (unsigned int)cmd_getc ());
2623     break;
2624     case '*':
2625     scr_charset_set (2, (unsigned int)cmd_getc ());
2626     break;
2627     case '+':
2628     scr_charset_set (3, (unsigned int)cmd_getc ());
2629     break;
2630 pcg 1.1 #ifndef NO_FRILLS
2631 pcg 1.36 case '6':
2632     scr_backindex ();
2633     break;
2634     #endif
2635     case '7':
2636     scr_cursor (SAVE);
2637     break;
2638     case '8':
2639     scr_cursor (RESTORE);
2640     break;
2641 pcg 1.1 #ifndef NO_FRILLS
2642 pcg 1.36 case '9':
2643     scr_forwardindex ();
2644     break;
2645     #endif
2646     case '=':
2647     case '>':
2648 pcg 1.43 PrivMode ((ch == '='), PrivMode_aplKP);
2649 pcg 1.36 break;
2650    
2651     case C1_40:
2652     cmd_getc ();
2653     break;
2654     case C1_44:
2655     scr_index (UP);
2656     break;
2657 pcg 1.1
2658 pcg 1.36 /* 8.3.87: NEXT LINE */
2659     case C1_NEL: /* ESC E */
2660 pcg 1.1 {
2661 pcg 1.93 unicode_t nlcr[] = { C0_LF, C0_CR };
2662 pcg 1.34 scr_add_lines (nlcr, 1, 2);
2663 pcg 1.1 }
2664 pcg 1.36 break;
2665    
2666     /* kidnapped escape sequence: Should be 8.3.48 */
2667     case C1_ESA: /* ESC G */
2668     process_graphics ();
2669     break;
2670    
2671     /* 8.3.63: CHARACTER TABULATION SET */
2672     case C1_HTS: /* ESC H */
2673     scr_set_tab (1);
2674     break;
2675    
2676     /* 8.3.105: REVERSE LINE FEED */
2677     case C1_RI: /* ESC M */
2678     scr_index (DN);
2679     break;
2680    
2681     /* 8.3.142: SINGLE-SHIFT TWO */
2682 pcg 1.90 /*case C1_SS2: scr_single_shift (2); break; */
2683 pcg 1.36
2684     /* 8.3.143: SINGLE-SHIFT THREE */
2685 pcg 1.90 /*case C1_SS3: scr_single_shift (3); break; */
2686 pcg 1.36
2687     /* 8.3.27: DEVICE CONTROL STRING */
2688     case C1_DCS: /* ESC P */
2689     process_dcs_seq ();
2690     break;
2691    
2692     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
2693     case C1_SCI: /* ESC Z */
2694 pcg 1.43 tt_write ((const unsigned char *)ESCZ_ANSWER,
2695     (unsigned int) (sizeof (ESCZ_ANSWER) - 1));
2696 pcg 1.36 break; /* steal obsolete ESC [ c */
2697    
2698     /* 8.3.16: CONTROL SEQUENCE INTRODUCER */
2699     case C1_CSI: /* ESC [ */
2700     process_csi_seq ();
2701     break;
2702 pcg 1.1
2703 pcg 1.36 /* 8.3.90: OPERATING SYSTEM COMMAND */
2704     case C1_OSC: /* ESC ] */
2705     process_osc_seq ();
2706     break;
2707    
2708     /* 8.3.106: RESET TO INITIAL STATE */
2709     case 'c':
2710 pcg 1.90 mbstate.reset ();
2711 pcg 1.36 scr_poweron ();
2712     scrollbar_show (1);
2713     break;
2714    
2715     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
2716     case 'n':
2717     scr_charset_choose (2);
2718     break;
2719    
2720     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
2721     case 'o':
2722     scr_charset_choose (3);
2723     break;
2724 pcg 1.1 }
2725     }
2726     /*}}} */
2727    
2728     /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
2729     /* *INDENT-OFF* */
2730     enum {
2731 pcg 1.36 CSI_ICH = 0x40,
2732 pcg 1.95 CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
2733 pcg 1.36 CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
2734     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
2735     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
2736     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
2737     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
2738     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
2739     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F
2740 pcg 1.1 };
2741    
2742     #define make_byte(b7,b6,b5,b4,b3,b2,b1,b0) \
2743     (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4) \
2744     | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
2745     #define get_byte_array_bit(array, bit) \
2746 pcg 1.43 (!! ((array)[ (bit) / 8] & (128 >> ((bit) & 7))))
2747 pcg 1.1
2748 pcg 1.36 const unsigned char csi_defaults[] =
2749     {
2750 pcg 1.43 make_byte (1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
2751     make_byte (1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
2752     make_byte (1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
2753     make_byte (1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
2754     make_byte (1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
2755     make_byte (0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
2756     make_byte (0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
2757 pcg 1.90 make_byte (0,0,0,0,0,0,0,0), /* x, y, z, {, |, }, ~, */
2758 pcg 1.36 };
2759 pcg 1.1 /* *INDENT-ON* */
2760    
2761     void
2762 pcg 1.34 rxvt_term::process_csi_seq ()
2763 pcg 1.1 {
2764 pcg 1.81 unicode_t ch, priv, i;
2765     unsigned int nargs, p;
2766     int n, ndef;
2767     int arg[ESC_ARGS];
2768 pcg 1.36
2769     for (nargs = ESC_ARGS; nargs > 0;)
2770     arg[--nargs] = 0;
2771    
2772     priv = 0;
2773     ch = cmd_getc ();
2774     if (ch >= '<' && ch <= '?')
2775     { /* '<' '=' '>' '?' */
2776     priv = ch;
2777     ch = cmd_getc ();
2778     }
2779 pcg 1.81
2780 pcg 1.36 /* read any numerical arguments */
2781     for (n = -1; ch < CSI_ICH; )
2782     {
2783 pcg 1.43 if (isdigit (ch))
2784 pcg 1.36 {
2785     if (n < 0)
2786     n = ch - '0';
2787     else
2788     n = n * 10 + ch - '0';
2789     }
2790     else if (ch == ';')
2791     {
2792     if (nargs < ESC_ARGS)
2793     arg[nargs++] = n;
2794     n = -1;
2795     }
2796 pcg 1.81 else if (IS_CONTROL (ch))
2797     process_nonprinting (ch);
2798    
2799 pcg 1.36 ch = cmd_getc ();
2800     }
2801 pcg 1.1
2802 pcg 1.36 if (ch > CSI_7F)
2803     return;
2804 pcg 1.1
2805 pcg 1.36 if (nargs < ESC_ARGS)
2806     arg[nargs++] = n;
2807    
2808     i = ch - CSI_ICH;
2809 pcg 1.43 ndef = get_byte_array_bit (csi_defaults, i);
2810 pcg 1.36 for (p = 0; p < nargs; p++)
2811     if (arg[p] == -1)
2812     arg[p] = ndef;
2813 pcg 1.1
2814     #ifdef DEBUG_CMD
2815 pcg 1.43 fprintf (stderr, "CSI ");
2816 pcg 1.36 for (p = 0; p < nargs; p++)
2817 pcg 1.43 fprintf (stderr, "%d%s", arg[p], p < nargs - 1 ? ";" : "");
2818     fprintf (stderr, "%c\n", ch);
2819 pcg 1.1 #endif
2820    
2821 pcg 1.36 /*
2822     * private mode handling
2823     */
2824     if (priv)
2825     {
2826     switch (priv)
2827     {
2828     case '>':
2829     if (ch == CSI_DA) /* secondary device attributes */
2830 pcg 1.43 tt_printf ("\033[>%d;%-.8s;0c", 'R', VSTRING);
2831 pcg 1.36 break;
2832     case '?':
2833     if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
2834     process_terminal_mode (ch, priv, nargs, arg);
2835     break;
2836     }
2837     return;
2838 pcg 1.1 }
2839    
2840 pcg 1.36 switch (ch)
2841     {
2842     /*
2843 pcg 1.43 * ISO/IEC 6429:1992 (E) CSI sequences (defaults in parentheses)
2844 pcg 1.36 */
2845 pcg 1.1 #ifdef PRINTPIPE
2846 pcg 1.36 case CSI_MC: /* 8.3.83: (0) MEDIA COPY */
2847     switch (arg[0])
2848     {
2849     case 0: /* initiate transfer to primary aux device */
2850     scr_printscreen (0);
2851     break;
2852     case 5: /* start relay to primary aux device */
2853     process_print_pipe ();
2854     break;
2855     }
2856     break;
2857     #endif
2858 pcg 1.1
2859 pcg 1.36 case CSI_CUU: /* 8.3.22: (1) CURSOR UP */
2860     case CSI_VPR: /* 8.3.161: (1) LINE POSITION FORWARD */
2861     arg[0] = -arg[0];
2862     /* FALLTHROUGH */
2863     case CSI_CUD: /* 8.3.19: (1) CURSOR DOWN */
2864     case CSI_VPB: /* 8.3.160: (1) LINE POSITION BACKWARD */
2865     scr_gotorc (arg[0], 0, RELATIVE);
2866     break;
2867    
2868     case CSI_CUB: /* 8.3.18: (1) CURSOR LEFT */
2869     case CSI_HPB: /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
2870 pcg 1.1 #ifdef ISO6429
2871 pcg 1.36 arg[0] = -arg[0];
2872 pcg 1.1 #else /* emulate common DEC VTs */
2873 pcg 1.36 arg[0] = arg[0] ? -arg[0] : -1;
2874 pcg 1.1 #endif
2875 pcg 1.36 /* FALLTHROUGH */
2876     case CSI_CUF: /* 8.3.20: (1) CURSOR RIGHT */
2877     case CSI_HPR: /* 8.3.60: (1) CHARACTER POSITION FORWARD */
2878 pcg 1.1 #ifdef ISO6429
2879 pcg 1.36 scr_gotorc (0, arg[0], RELATIVE);
2880 pcg 1.1 #else /* emulate common DEC VTs */
2881 pcg 1.36 scr_gotorc (0, arg[0] ? arg[0] : 1, RELATIVE);
2882 pcg 1.1 #endif
2883 pcg 1.36 break;
2884    
2885     case CSI_CPL: /* 8.3.13: (1) CURSOR PRECEDING LINE */
2886     arg[0] = -arg[0];
2887     /* FALLTHROUGH */
2888     case CSI_CNL: /* 8.3.12: (1) CURSOR NEXT LINE */
2889     scr_gotorc (arg[0], 0, R_RELATIVE);
2890     break;
2891    
2892     case CSI_CHA: /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
2893     case CSI_HPA: /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
2894     scr_gotorc (0, arg[0] - 1, R_RELATIVE);
2895     break;
2896    
2897     case CSI_VPA: /* 8.3.159: (1) LINE POSITION ABSOLUTE */
2898     scr_gotorc (arg[0] - 1, 0, C_RELATIVE);
2899     break;
2900    
2901     case CSI_CUP: /* 8.3.21: (1,1) CURSOR POSITION */
2902     case CSI_HVP: /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
2903     scr_gotorc (arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
2904     break;
2905 pcg 1.1
2906 pcg 1.36 case CSI_CBT: /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
2907     arg[0] = -arg[0];
2908     /* FALLTHROUGH */
2909     case CSI_CHT: /* 8.3.10: (1) CURSOR FORWARD TABULATION */
2910     scr_tab (arg[0]);
2911     break;
2912    
2913     case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */
2914     scr_erase_screen (arg[0]);
2915     break;
2916    
2917     case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */
2918     scr_erase_line (arg[0]);
2919     break;
2920    
2921     case CSI_ICH: /* 8.3.65: (1) INSERT CHARACTER */
2922     scr_insdel_chars (arg[0], INSERT);
2923     break;
2924    
2925     case CSI_IL: /* 8.3.68: (1) INSERT LINE */
2926     scr_insdel_lines (arg[0], INSERT);
2927     break;
2928    
2929     case CSI_DL: /* 8.3.33: (1) DELETE LINE */
2930     scr_insdel_lines (arg[0], DELETE);
2931     break;
2932    
2933     case CSI_ECH: /* 8.3.39: (1) ERASE CHARACTER */
2934     scr_insdel_chars (arg[0], ERASE);
2935     break;
2936    
2937     case CSI_DCH: /* 8.3.26: (1) DELETE CHARACTER */
2938     scr_insdel_chars (arg[0], DELETE);
2939     break;
2940    
2941     case CSI_SD: /* 8.3.114: (1) SCROLL DOWN */
2942     arg[0] = -arg[0];
2943     /* FALLTHROUGH */
2944     case CSI_SU: /* 8.3.148: (1) SCROLL UP */
2945     scr_scroll_text (screen.tscroll, screen.bscroll, arg[0], 0);
2946     break;
2947    
2948     case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */
2949 pcg 1.43 tt_write ((const unsigned char *)VT100_ANS,
2950     (unsigned int) (sizeof (VT100_ANS) - 1));
2951 pcg 1.36 break;
2952    
2953     case CSI_SGR: /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
2954     process_sgr_mode (nargs, arg);
2955     break;
2956    
2957     case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */
2958     switch (arg[0])
2959     {
2960     case 5: /* DSR requested */
2961 pcg 1.43 tt_printf ("\033[0n");
2962 pcg 1.36 break;
2963     case 6: /* CPR requested */
2964     scr_report_position ();
2965     break;
2966     case 7: /* unofficial extension */
2967 pcg 1.90 if (Options & Opt_insecure)
2968     tt_printf ("%-.250s\n", rs[Rs_display_name]);
2969 pcg 1.36 break;
2970     case 8: /* unofficial extension */
2971 pcg 1.90 process_xterm_seq (XTerm_title, RESNAME "-" VERSION, CHAR_ST);
2972 pcg 1.36 break;
2973     }
2974     break;
2975 pcg 1.1
2976 pcg 1.36 case CSI_TBC: /* 8.3.155: (0) TABULATION CLEAR */
2977     switch (arg[0])
2978     {
2979     case 0: /* char tab stop cleared at active position */
2980     scr_set_tab (0);
2981     break;
2982     /* case 1: */ /* line tab stop cleared in active line */
2983     /* case 2: */ /* char tab stops cleared in active line */
2984     case 3: /* all char tab stops are cleared */
2985     /* case 4: */ /* all line tab stops are cleared */
2986     case 5: /* all tab stops are cleared */
2987     scr_set_tab (-1);
2988     break;
2989     }
2990     break;
2991    
2992     case CSI_CTC: /* 8.3.17: (0) CURSOR TABULATION CONTROL */
2993     switch (arg[0])
2994     {
2995     case 0: /* char tab stop set at active position */
2996     scr_set_tab (1);
2997     break; /* = ESC H */
2998     /* case 1: */ /* line tab stop set at active line */
2999     case 2: /* char tab stop cleared at active position */
3000     scr_set_tab (0);
3001     break; /* = ESC [ 0 g */
3002     /* case 3: */ /* line tab stop cleared at active line */
3003     /* case 4: */ /* char tab stops cleared at active line */
3004     case 5: /* all char tab stops are cleared */
3005     scr_set_tab (-1);
3006     break; /* = ESC [ 3 g */
3007     /* case 6: */ /* all line tab stops are cleared */
3008     }
3009     break;
3010    
3011     case CSI_RM: /* 8.3.107: RESET MODE */
3012     if (arg[0] == 4)
3013     scr_insert_mode (0);
3014     break;
3015    
3016     case CSI_SM: /* 8.3.126: SET MODE */
3017     if (arg[0] == 4)
3018     scr_insert_mode (1);
3019     break;
3020    
3021     /*
3022     * PRIVATE USE beyond this point. All CSI_7? sequences here
3023     */
3024     case CSI_72: /* DECSTBM: set top and bottom margins */
3025     if (nargs == 1)
3026     scr_scroll_region (arg[0] - 1, MAX_ROWS - 1);
3027     else if (nargs == 0 || arg[0] >= arg[1])
3028     scr_scroll_region (0, MAX_ROWS - 1);
3029     else
3030     scr_scroll_region (arg[0] - 1, arg[1] - 1);
3031     break;
3032    
3033     case CSI_73:
3034     scr_cursor (SAVE);
3035     break;
3036     case CSI_75:
3037     scr_cursor (RESTORE);
3038     break;
3039 pcg 1.1
3040     #ifndef NO_FRILLS
3041 pcg 1.36 case CSI_74:
3042     process_window_ops (arg, nargs);
3043     break;
3044 pcg 1.1 #endif
3045    
3046 pcg 1.36 case CSI_78: /* DECREQTPARM */
3047     if (arg[0] == 0 || arg[0] == 1)
3048 pcg 1.43 tt_printf ("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
3049 pcg 1.81 break;
3050 pcg 1.1
3051 pcg 1.36 default:
3052     break;
3053 pcg 1.1 }
3054     }
3055     /*}}} */
3056    
3057     #ifndef NO_FRILLS
3058     /* ARGSUSED */
3059     void
3060 pcg 1.34 rxvt_term::process_window_ops (const int *args, unsigned int nargs)
3061 pcg 1.1 {
3062 pcg 1.81 int x, y;
3063 pcg 1.36 XWindowAttributes wattr;
3064 pcg 1.81 Window wdummy;
3065 pcg 1.1
3066 pcg 1.36 if (nargs == 0)
3067     return;
3068 pcg 1.81
3069 pcg 1.36 switch (args[0])
3070     {
3071 pcg 1.81 /*
3072     * commands
3073     */
3074 pcg 1.36 case 1: /* deiconify window */
3075 pcg 1.43 XMapWindow (display->display, TermWin.parent[0]);
3076 pcg 1.36 break;
3077     case 2: /* iconify window */
3078 pcg 1.43 XIconifyWindow (display->display, TermWin.parent[0],
3079     DefaultScreen (display->display));
3080 pcg 1.36 break;
3081     case 3: /* set position (pixels) */
3082 pcg 1.43 XMoveWindow (display->display, TermWin.parent[0], args[1], args[2]);
3083 pcg 1.36 break;
3084     case 4: /* set size (pixels) */
3085     set_widthheight ((unsigned int)args[2], (unsigned int)args[1]);
3086     break;
3087     case 5: /* raise window */
3088 pcg 1.43 XRaiseWindow (display->display, TermWin.parent[0]);
3089 pcg 1.36 break;
3090     case 6: /* lower window */
3091 pcg 1.43 XLowerWindow (display->display, TermWin.parent[0]);
3092 pcg 1.36 break;
3093     case 7: /* refresh window */
3094     scr_touch (true);
3095     break;
3096     case 8: /* set size (chars) */
3097 pcg 1.43 set_widthheight ((unsigned int) (args[2] * TermWin.fwidth),
3098     (unsigned int) (args[1] * TermWin.fheight));
3099 pcg 1.36 break;
3100 pcg 1.81
3101     //case 9: NYI, TODO, restore maximized window or maximize window
3102 pcg 1.36 default:
3103     if (args[0] >= 24) /* set height (chars) */
3104     set_widthheight ((unsigned int)TermWin.width,
3105 pcg 1.43 (unsigned int) (args[1] * TermWin.fheight));
3106 pcg 1.36 break;
3107 pcg 1.81
3108    
3109     /*
3110     * reports - some output format copied from XTerm
3111     */
3112 pcg 1.36 case 11: /* report window state */
3113 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
3114     tt_printf ("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
3115 pcg 1.36 break;
3116     case 13: /* report window position */
3117 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
3118     XTranslateCoordinates (display->display, TermWin.parent[0], wattr.root,
3119 pcg 1.90 -wattr.border_width, -wattr.border_width,
3120     &x, &y, &wdummy);
3121 pcg 1.43 tt_printf ("\033[3;%d;%dt", x, y);
3122 pcg 1.36 break;
3123     case 14: /* report window size (pixels) */
3124 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
3125     tt_printf ("\033[4;%d;%dt", wattr.height, wattr.width);
3126 pcg 1.36 break;
3127 pcg 1.81 case 18: /* report text area size (chars) */
3128 pcg 1.43 tt_printf ("\033[8;%d;%dt", TermWin.nrow, TermWin.ncol);
3129 pcg 1.36 break;
3130 pcg 1.81 case 19: /* report window size (chars) */
3131     tt_printf ("\033[9;%d;%dt", TermWin.nrow, TermWin.ncol);
3132     break;
3133 pcg 1.36 case 20: /* report icon label */
3134 pcg 1.90 if (Options & Opt_insecure)
3135     {
3136     char *s;
3137     XGetIconName (display->display, TermWin.parent[0], &s);
3138     tt_printf ("\033]L%-.200s\234", s ? s : ""); /* 8bit ST */
3139     }
3140 pcg 1.36 break;
3141     case 21: /* report window title */
3142 pcg 1.90 if (Options & Opt_insecure)
3143     {
3144     char *s;
3145     XFetchName (display->display, TermWin.parent[0], &s);
3146     tt_printf ("\033]l%-.200s\234", s ? s : ""); /* 8bit ST */
3147     }
3148 pcg 1.36 break;
3149 pcg 1.1 }
3150     }
3151     #endif
3152    
3153     /*----------------------------------------------------------------------*/
3154     /*
3155     * get input up until STRING TERMINATOR (or BEL)
3156 pcg 1.93 * ends_how is terminator used. returned input must be free()'d
3157 pcg 1.1 */
3158 pcg 1.81 unsigned char *
3159     rxvt_term::get_to_st (unicode_t &ends_how)
3160 pcg 1.1 {
3161 root 1.97 unicode_t prev = 0, ch;
3162 pcg 1.81 unsigned int n = 0;
3163     unsigned char *s;
3164     unsigned char string[STRING_MAX];
3165 pcg 1.36
3166 root 1.97 while ((ch = cmd_getc ()) != NOCHAR)
3167 pcg 1.36 {
3168 root 1.97 if (prev == C0_ESC)
3169 pcg 1.36 {
3170 root 1.97 if (ch == 0x5c) /* 7bit ST */
3171     break;
3172     else
3173     return NULL;
3174 pcg 1.36 }
3175 root 1.97 else if (ch == C0_BEL || ch == CHAR_ST)
3176     break;
3177     else if (ch < 0x20)
3178 pcg 1.36 return NULL; /* other control character - exit */
3179 pcg 1.81
3180 pcg 1.90 if (n >= sizeof (string) - 1)
3181     // stop at some sane length
3182     return NULL;
3183 pcg 1.81
3184 root 1.97 if (ch == C0_SYN)
3185     {
3186     string[n++] = cmd_get8 ();
3187     prev = 0;
3188     }
3189     else
3190     string[n++] = prev = ch;
3191 pcg 1.36 }
3192 pcg 1.81
3193 pcg 1.36 string[n++] = '\0';
3194 pcg 1.81
3195 pcg 1.43 if ((s = (unsigned char *)rxvt_malloc (n)) == NULL)
3196 pcg 1.36 return NULL;
3197 pcg 1.81
3198     ends_how = (ch == 0x5c ? C0_ESC : ch);
3199 pcg 1.43 STRNCPY (s, string, n);
3200 pcg 1.36 return s;
3201 pcg 1.1 }
3202    
3203     /*----------------------------------------------------------------------*/
3204     /*
3205     * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
3206     */
3207     void
3208 pcg 1.34 rxvt_term::process_dcs_seq ()
3209 pcg 1.1 {
3210 pcg 1.81 unsigned char *s;
3211     unicode_t eh;
3212    
3213 pcg 1.36 /*
3214     * Not handled yet
3215     */
3216 pcg 1.81 s = get_to_st (eh);
3217 pcg 1.36 if (s)
3218 pcg 1.43 free (s);
3219 pcg 1.81
3220 pcg 1.36 return;
3221 pcg 1.1 }
3222    
3223     /*----------------------------------------------------------------------*/
3224     /*
3225     * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
3226     */
3227     void
3228 pcg 1.34 rxvt_term::process_osc_seq ()
3229 pcg 1.1 {
3230 pcg 1.81 unicode_t ch, eh;
3231     int arg;
3232 pcg 1.1
3233 pcg 1.36 ch = cmd_getc ();
3234 pcg 1.43 for (arg = 0; isdigit (ch); ch = cmd_getc ())
3235 pcg 1.36 arg = arg * 10 + (ch - '0');
3236 pcg 1.1
3237 pcg 1.36 if (ch == ';')
3238     {
3239 pcg 1.81 unsigned char *s = get_to_st (eh);
3240    
3241 pcg 1.36 if (s)
3242     {
3243 pcg 1.90 process_xterm_seq (arg, (char *)s, eh);
3244     free (s);
3245     }
3246     }
3247     }
3248 pcg 1.81
3249 pcg 1.90 void
3250     rxvt_term::process_color_seq (int report, int color, const char *str, unsigned char resp)
3251     {
3252     if (str[0] == '?' && !str[1])
3253     {
3254     if (Options & Opt_insecure)
3255     {
3256     unsigned short r, g, b;
3257     PixColors[color].get (display, r, g, b);
3258     tt_printf ("\033]%d;rgb:%04x/%04x/%04x%c", report, r, g, b, resp);
3259 pcg 1.36 }
3260 pcg 1.1 }
3261 pcg 1.90 else
3262     set_window_color (color, str);
3263 pcg 1.1 }
3264 pcg 1.90
3265 pcg 1.1 /*
3266     * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
3267     * 0 = change iconName/title
3268     * 1 = change iconName
3269     * 2 = change title
3270     * 4 = change color
3271 pcg 1.90 * 10 = change fg color
3272     * 11 = change bg color
3273 pcg 1.1 * 12 = change text color
3274     * 13 = change mouse foreground color
3275     * 17 = change highlight character colour
3276     * 18 = change bold character color
3277     * 19 = change underlined character color
3278     * 46 = change logfile (not implemented)
3279     * 50 = change font
3280     *
3281     * rxvt extensions:
3282     * 20 = bg pixmap
3283     * 39 = change default fg color
3284     * 49 = change default bg color
3285     * 55 = dump scrollback buffer and all of screen
3286 pcg 1.67 * 701 = change locale
3287     * 702 = find font
3288 pcg 1.90 * 703 = menu
3289 pcg 1.1 */
3290     void
3291 pcg 1.90 rxvt_term::process_xterm_seq (int op, const char *str, unsigned char resp)
3292 pcg 1.1 {
3293 pcg 1.81 int changed = 0;
3294     int color;
3295     char *buf, *name;
3296 pcg 1.90 bool query = str[0] == '?' && !str[1];
3297 pcg 1.36
3298 pcg 1.43 assert (str != NULL);
3299 pcg 1.36 switch (op)
3300     {
3301     case XTerm_name:
3302     set_title (str);
3303     /* FALLTHROUGH */
3304     case XTerm_iconName:
3305 pcg 1.81 set_icon_name (str);
3306 pcg 1.36 break;
3307     case XTerm_title:
3308     set_title (str);
3309     break;
3310 pcg 1.90 case XTerm_property:
3311     if (str[0] == '?')
3312     {
3313     Atom prop = XInternAtom (display->display, str + 1, True);
3314     Atom actual_type;
3315     int actual_format;
3316     unsigned long nitems;
3317     unsigned long bytes_after;
3318     unsigned char *value = 0;
3319     const char *str = "";
3320    
3321     if (prop
3322     && XGetWindowProperty (display->display, TermWin.parent[0],
3323     prop, 0, 1<<16, 0, AnyPropertyType,
3324     &actual_type, &actual_format,
3325     &nitems, &bytes_after, &value) == Success
3326     && actual_type != None
3327     && actual_format == 8)
3328     str = (const char *)(value);
3329    
3330     tt_printf ("\033]%d;%s%c", XTerm_property, str, resp);
3331    
3332     XFree (value);
3333     }
3334     else
3335     {
3336     char *eq = strchr (str, '='); // constness lost, but verified to be ok
3337    
3338     if (eq)
3339     {
3340     *eq = 0;
3341     XChangeProperty (display->display, TermWin.parent[0],
3342     display->atom (str), XA_STRING, 8,
3343     PropModeReplace, (unsigned char *)eq + 1,
3344     strlen (eq + 1));
3345     }
3346     else
3347     XDeleteProperty (display->display, TermWin.parent[0],
3348     display->atom (str));
3349     }
3350     break;
3351    
3352 pcg 1.36 case XTerm_Color:
3353     for (buf = (char *)str; buf && *buf;)
3354     {
3355 pcg 1.43 if ((name = STRCHR (buf, ';')) == NULL)
3356 pcg 1.36 break;
3357 pcg 1.81
3358 pcg 1.36 *name++ = '\0';
3359 pcg 1.43 color = atoi (buf);
3360 pcg 1.81
3361 pcg 1.36 if (color < 0 || color >= TOTAL_COLORS)
3362     break;
3363 pcg 1.81
3364 pcg 1.43 if ((buf = STRCHR (name, ';')) != NULL)
3365 pcg 1.36 *buf++ = '\0';
3366 pcg 1.81
3367 pcg 1.90 if (name[0] == '?' && !name[1])
3368     {
3369     if (Options & Opt_insecure)
3370     {
3371     unsigned short r, g, b;
3372     PixColors[color + minCOLOR].get (display, r, g, b);
3373     tt_printf ("\033]%d;%d;rgb:%04x/%04x/%04x%c", XTerm_Color, color, r, g, b, resp);
3374     }
3375     }
3376     else
3377     set_window_color (color + minCOLOR, name);
3378 pcg 1.36 }
3379     break;
3380 pcg 1.90 case XTerm_Color00:
3381     process_color_seq (XTerm_Color00, Color_fg, str, resp);
3382     break;
3383     case XTerm_Color01:
3384     process_color_seq (XTerm_Color00, Color_bg, str, resp);
3385     break;
3386 pcg 1.1 #ifndef NO_CURSORCOLOR
3387 pcg 1.36 case XTerm_Color_cursor:
3388 pcg 1.90 process_color_seq (XTerm_Color_cursor, Color_cursor, str, resp);
3389 pcg 1.36 break;
3390     #endif
3391 pcg 1.90 case XTerm_Color_pointer_fg:
3392     process_color_seq (XTerm_Color_pointer_fg, Color_pointer_fg, str, resp);
3393     break;
3394     case XTerm_Color_pointer_bg:
3395     process_color_seq (XTerm_Color_pointer_bg, Color_pointer_bg, str, resp);
3396 pcg 1.36 break;
3397 pcg 1.1 #ifndef NO_BOLD_UNDERLINE_REVERSE
3398 pcg 1.36 case XTerm_Color_BD:
3399 pcg 1.90 process_color_seq (XTerm_Color_BD, Color_BD, str, resp);
3400 pcg 1.36 break;
3401     case XTerm_Color_UL:
3402 pcg 1.90 process_color_seq (XTerm_Color_UL, Color_UL, str, resp);
3403 pcg 1.36 break;
3404     case XTerm_Color_RV:
3405 pcg 1.90 process_color_seq (XTerm_Color_RV, Color_RV, str, resp);
3406 pcg 1.36 break;
3407 pcg 1.1 #endif
3408    
3409 pcg 1.36 case XTerm_Pixmap:
3410     if (*str != ';')
3411     {
3412 pcg 1.1 #if XPM_BACKGROUND
3413 pcg 1.36 scale_pixmap (""); /* reset to default scaling */
3414     set_bgPixmap (str); /* change pixmap */
3415 pcg 1.1 #endif
3416 pcg 1.36 scr_touch (true);
3417     }
3418 pcg 1.43 while ((str = STRCHR (str, ';')) != NULL)
3419 pcg 1.36 {
3420     str++;
3421 pcg 1.1 #if XPM_BACKGROUND
3422 pcg 1.36 changed += scale_pixmap (str);
3423 pcg 1.1 #endif
3424 pcg 1.36
3425     }
3426     if (changed)
3427     {
3428 pcg 1.1 #ifdef XPM_BACKGROUND
3429 pcg 1.36 resize_pixmap ();
3430 pcg 1.1 #endif
3431 pcg 1.36 scr_touch (true);
3432     }
3433     break;
3434    
3435     case XTerm_restoreFG:
3436     set_window_color (Color_fg, str);
3437     break;
3438     case XTerm_restoreBG:
3439     set_window_color (Color_bg, str);
3440     break;
3441 pcg 1.90
3442 pcg 1.36 case XTerm_logfile:
3443 pcg 1.81 // TODO, when secure mode?
3444 pcg 1.36 break;
3445 pcg 1.90
3446 pcg 1.36 case XTerm_font:
3447 pcg 1.90 if (query)
3448     {
3449     if (Options & Opt_insecure)
3450     tt_printf ("\33]%d;%-.250s%c", XTerm_font,
3451     TermWin.fontset->fontdesc
3452     ? TermWin.fontset->fontdesc
3453     : "",
3454     resp);
3455     }
3456     else
3457     change_font (str);
3458 pcg 1.51 break;
3459 pcg 1.90
3460 pcg 1.60 #ifndef NO_FRILLS
3461 pcg 1.51 case XTerm_locale:
3462 pcg 1.90 if (query)
3463     {
3464     if (Options & Opt_insecure)
3465     tt_printf ("\33]%d;%-.250s%c", XTerm_locale, locale, resp);
3466     }
3467 pcg 1.54 else
3468     {
3469     set_locale (str);
3470 pcg 1.60 # ifdef USE_XIM
3471 pcg 1.54 im_cb ();
3472 pcg 1.60 # endif
3473 pcg 1.54 }
3474 pcg 1.36 break;
3475 pcg 1.90
3476 pcg 1.67 case XTerm_findfont:
3477 pcg 1.90 if (Options & Opt_insecure)
3478     {
3479     int fid = TermWin.fontset->find_font (atoi (str));
3480     tt_printf ("\33]%d;%d;%-.250s%c", XTerm_findfont,
3481     fid, (*TermWin.fontset)[fid]->name, resp);
3482     }
3483 pcg 1.67 break;
3484 pcg 1.60 #endif
3485 pcg 1.90
3486     #ifdef MENUBAR
3487     case XTerm_Menu:
3488     if (Options & Opt_insecure)
3489     menubar_dispatch (const_cast<char *>(str)); // casting away constness is checked
3490     break;
3491     #endif
3492 pcg 1.1 #if 0
3493 pcg 1.36 case XTerm_dumpscreen: /* no error notices */
3494     {
3495 pcg 1.90 int fd;
3496 pcg 1.43 if ((fd = open (str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
3497 pcg 1.36 {
3498     scr_dump (fd);
3499 pcg 1.43 close (fd);
3500 pcg 1.36 }
3501     }
3502     break;
3503 pcg 1.1 #endif
3504     }
3505     }
3506     /*----------------------------------------------------------------------*/
3507    
3508     /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3509     /*
3510     * mode can only have the following values:
3511     * 'l' = low
3512     * 'h' = high
3513     * 's' = save
3514     * 'r' = restore
3515     * 't' = toggle
3516     * so no need for fancy checking
3517     */
3518     int
3519 pcg 1.34 rxvt_term::privcases (int mode, unsigned long bit)
3520 pcg 1.1 {
3521 pcg 1.81 int state;
3522 pcg 1.1
3523 pcg 1.36 if (mode == 's')
3524     {
3525     SavedModes |= (PrivateModes & bit);
3526     return -1;
3527 pcg 1.1 }
3528 pcg 1.36 else
3529     {
3530     if (mode == 'r')
3531     state = (SavedModes & bit) ? 1 : 0; /* no overlapping */
3532     else
3533 pcg 1.43 state = (mode == 't') ? ! (PrivateModes & bit) : mode;
3534     PrivMode (state, bit);
3535 pcg 1.36 }
3536 pcg 1.81
3537 pcg 1.36 return state;
3538 pcg 1.1 }
3539    
3540     /* we're not using priv _yet_ */
3541     void
3542 pcg 1.43 rxvt_term::process_terminal_mode (int mode, int priv __attribute__ ((unused)), unsigned int nargs, const int *arg)
3543 pcg 1.1 {
3544 pcg 1.81 unsigned int i, j;
3545     int state;
3546    
3547 pcg 1.36 static const struct
3548     {
3549     const int argval;
3550     const unsigned long bit;
3551     }
3552 pcg 1.81
3553 pcg 1.36 argtopriv[] = {
3554     { 1, PrivMode_aplCUR },
3555     { 2, PrivMode_vt52 },
3556     { 3, PrivMode_132 },
3557     { 4, PrivMode_smoothScroll },
3558     { 5, PrivMode_rVideo },
3559     { 6, PrivMode_relOrigin },
3560     { 7, PrivMode_Autowrap },
3561     { 9, PrivMode_MouseX10 },
3562 pcg 1.1 #ifdef menuBar_esc
3563 pcg 1.36 { menuBar_esc, PrivMode_menuBar },
3564 pcg 1.1 #endif
3565     #ifdef scrollBar_esc
3566 pcg 1.36 { scrollBar_esc, PrivMode_scrollBar },
3567 pcg 1.1 #endif
3568 pcg 1.73 // 18, 19 printing-related
3569 pcg 1.36 { 25, PrivMode_VisibleCursor },
3570 pcg 1.73 // 30 show scrollbar rxvt. extension
3571     { 35, PrivMode_ShiftKeys }, // rxvt extension
3572 pcg 1.36 { 40, PrivMode_132OK },
3573 pcg 1.73 // 41 xterm more fixes NYI
3574     // 45 margin bell NYI
3575     // 46 start logging
3576 pcg 1.36 { 47, PrivMode_Screen },
3577     { 66, PrivMode_aplKP },
3578 pcg 1.1 #ifndef NO_BACKSPACE_KEY
3579 pcg 1.36 { 67, PrivMode_BackSpace },
3580 pcg 1.1 #endif
3581 pcg 1.36 { 1000, PrivMode_MouseX11 },
3582 pcg 1.73 // 1001 Use Hilite Mouse Tracking. NYI, TODO
3583     // 1002 Use Cell Motion Mouse Tracking. NYI, TODO
3584     // 1003 Use All Motion Mouse Tracking. NYI, TODO
3585     { 1010, PrivMode_TtyOutputInh }, // rxvt extension
3586     { 1011, PrivMode_Keypress }, // rxvt extension
3587     // 1035 enable modifiers for alt, numlock NYI
3588     // 1036 send ESC for meta keys NYI
3589     // 1037 send DEL for keypad delete NYI
3590 pcg 1.36 { 1047, PrivMode_Screen },
3591 pcg 1.73 // 1048 save and restore cursor
3592 pcg 1.90 { 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
3593 pcg 1.73 // 1051, 1052, 1060, 1061 keyboard emulation NYI
3594 pcg 1.36 };
3595    
3596     if (nargs == 0)
3597     return;
3598    
3599     /* make lo/hi boolean */
3600     if (mode == 'l')
3601     mode = 0; /* reset */
3602     else if (mode == 'h')
3603     mode = 1; /* set */
3604    
3605     for (i = 0; i < nargs; i++)
3606     {
3607     state = -1;
3608    
3609     /* basic handling */
3610 pcg 1.43 for (j = 0; j < (sizeof (argtopriv)/sizeof (argtopriv[0])); j++)
3611 pcg 1.36 if (argtopriv[j].argval == arg[i])
3612     {
3613     state = privcases (mode, argtopriv[j].bit);
3614     break;
3615     }
3616 pcg 1.1
3617 pcg 1.36 /* extra handling for values with state unkept */
3618 pcg 1.73 switch (arg[i])
3619     {
3620     case 1048: /* alternative cursor save */
3621 pcg 1.90 if (Options & Opt_secondaryScreen)
3622     if (mode == 0)
3623     scr_cursor (RESTORE);
3624     else if (mode == 1)
3625     scr_cursor (SAVE);
3626     break;
3627 pcg 1.73 }
3628    
3629     if (state >= 0)
3630     /* extra handling for values with valid 0 or 1 state */
3631 pcg 1.36 switch (arg[i])
3632     {
3633 pcg 1.73 /* case 1: - application cursor keys */
3634     case 2: /* VT52 mode */
3635     /* oddball mode. should be set regardless of set/reset
3636     * parameter. Return from VT52 mode with an ESC < from
3637     * within VT52 mode
3638     */
3639     PrivMode (1, PrivMode_vt52);
3640     break;
3641     case 3: /* 80/132 */
3642     if (PrivateModes & PrivMode_132OK)
3643     set_widthheight (((state ? 132 : 80) * TermWin.fwidth), TermWin.height);
3644     break;
3645     case 4: /* smooth scrolling */
3646     if (state)
3647     Options &= ~Opt_jumpScroll;
3648     else
3649     Options |= Opt_jumpScroll;
3650     break;
3651     case 5: /* reverse video */
3652     scr_rvideo_mode (state);
3653     break;
3654     case 6: /* relative/absolute origins */
3655     scr_relative_origin (state);
3656     break;
3657     case 7: /* autowrap */
3658     scr_autowrap (state);
3659     break;
3660 pcg 1.90 /* case 8: - auto repeat, can't do on a per window basis */
3661 pcg 1.73 case 9: /* X10 mouse reporting */
3662     if (state) /* orthogonal */
3663 pcg 1.81 PrivateModes &= ~PrivMode_MouseX11;
3664 pcg 1.73 break;
3665 pcg 1.1 #ifdef menuBar_esc
3666 pcg 1.73 case menuBar_esc:
3667 pcg 1.1 #ifdef MENUBAR
3668 pcg 1.73 map_menuBar (state);
3669 pcg 1.1 #endif
3670 pcg 1.73 break;
3671 pcg 1.1 #endif
3672     #ifdef scrollBar_esc
3673 pcg 1.73 case scrollBar_esc:
3674     if (scrollbar_mapping (state))
3675     {
3676     resize_all_windows (0, 0, 0);
3677     scr_touch (true);
3678     }
3679     break;
3680 pcg 1.1 #endif
3681 pcg 1.73 case 25: /* visible/invisible cursor */
3682     scr_cursor_visible (state);
3683     break;
3684 pcg 1.90 /* case 35: - shift keys */
3685     /* case 40: - 80 <--> 132 mode */
3686 pcg 1.73 case 47: /* secondary screen */
3687     scr_change_screen (state);
3688     break;
3689 pcg 1.90 /* case 66: - application key pad */
3690     /* case 67: - backspace key */
3691 pcg 1.73 case 1000: /* X11 mouse reporting */
3692     if (state) /* orthogonal */
3693 pcg 1.81 PrivateModes &= ~PrivMode_MouseX10;
3694 pcg 1.73 break;
3695 pcg 1.1 #if 0
3696 pcg 1.73 case 1001:
3697     break; /* X11 mouse highlighting */
3698 pcg 1.1 #endif
3699 pcg 1.73 case 1010: /* scroll to bottom on TTY output inhibit */
3700     if (state)
3701     Options &= ~Opt_scrollTtyOutput;
3702     else
3703     Options |= Opt_scrollTtyOutput;
3704     break;
3705     case 1011: /* scroll to bottom on key press */
3706     if (state)
3707     Options |= Opt_scrollTtyKeypress;
3708     else
3709     Options &= ~Opt_scrollTtyKeypress;
3710     break;
3711 pcg 1.90 case 1047: /* secondary screen w/ clearing last */
3712     if (Options & Opt_secondaryScreen)
3713     if (current_screen != PRIMARY)
3714     scr_erase_screen (2);
3715     scr_change_screen (state);
3716     break;
3717     case 1049: /* secondary screen w/ clearing first */
3718 pcg 1.73 scr_change_screen (state);
3719 pcg 1.90 if (Options & Opt_secondaryScreen)
3720     if (current_screen != PRIMARY)
3721     scr_erase_screen (2);
3722     break;
3723 pcg 1.73 default:
3724     break;
3725     }
3726 pcg 1.1 }
3727     }
3728     /*}}} */
3729    
3730     /*{{{ process sgr sequences */
3731     void
3732 pcg 1.34 rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
3733 pcg 1.1 {
3734 pcg 1.81 unsigned int i;
3735     short rendset;
3736     int rendstyle;
3737 pcg 1.36
3738     if (nargs == 0)
3739     {
3740     scr_rendition (0, ~RS_None);
3741     return;
3742     }
3743 pcg 1.81
3744 pcg 1.36 for (i = 0; i < nargs; i++)
3745     {
3746     rendset = -1;
3747     switch (arg[i])
3748     {
3749     case 0:
3750     rendset = 0, rendstyle = ~RS_None;
3751     break;
3752     case 1:
3753     rendset = 1, rendstyle = RS_Bold;
3754     break;
3755     case 4:
3756     rendset = 1, rendstyle = RS_Uline;
3757     break;
3758     case 5:
3759     rendset = 1, rendstyle = RS_Blink;
3760     break;
3761 pcg 1.93 //case 6: // scoansi light background
3762 pcg 1.36 case 7:
3763     rendset = 1, rendstyle = RS_RVid;
3764     break;
3765 pcg 1.73 case 8:
3766     // invisible. NYI
3767     break;
3768 pcg 1.93 //case 10: // scoansi acs off
3769     //case 11: // scoansi acs on
3770     //case 12: // scoansi acs on, |0x80
3771     case 21: // disable bold, blink and invis (some terminals use this)
3772     rendset = 0, rendstyle = RS_Bold | RS_Blink;
3773     break;
3774 pcg 1.36 case 22:
3775     rendset = 0, rendstyle = RS_Bold;
3776     break;
3777     case 24:
3778     rendset = 0, rendstyle = RS_Uline;
3779     break;
3780     case 25:
3781     rendset = 0, rendstyle = RS_Blink;
3782     break;
3783     case 27:
3784     rendset = 0, rendstyle = RS_RVid;
3785     break;
3786 pcg 1.73 case 28:
3787     // visible. NYI
3788     break;
3789 pcg 1.36 }
3790 pcg 1.73
3791 pcg 1.36 if (rendset != -1)
3792     {
3793     scr_rendition (rendset, rendstyle);
3794 pcg 1.43 continue; /* for (;i;) */
3795 pcg 1.36 }
3796    
3797     switch (arg[i])
3798     {
3799     case 30:
3800     case 31: /* set fg color */
3801     case 32:
3802     case 33:
3803     case 34:
3804     case 35:
3805     case 36:
3806     case 37:
3807 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 30)), Color_fg);
3808 pcg 1.36 break;
3809 pcg 1.1 #ifdef TTY_256COLOR
3810 pcg 1.36 case 38:
3811     if (nargs > i + 2 && arg[i + 1] == 5)
3812     {
3813 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_fg);
3814 pcg 1.36 i += 2;
3815     }
3816     break;
3817     #endif
3818     case 39: /* default fg */
3819     scr_color (Color_fg, Color_fg);
3820     break;
3821    
3822     case 40:
3823     case 41: /* set bg color */
3824     case 42:
3825     case 43:
3826     case 44:
3827     case 45:
3828     case 46:
3829     case 47:
3830 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 40)), Color_bg);
3831 pcg 1.36 break;
3832 pcg 1.1 #ifdef TTY_256COLOR
3833 pcg 1.36 case 48:
3834     if (nargs > i + 2 && arg[i + 1] == 5)
3835     {
3836 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_bg);
3837 pcg 1.36 i += 2;
3838     }
3839     break;
3840     #endif
3841     case 49: /* default bg */
3842     scr_color (Color_bg, Color_bg);
3843     break;
3844 pcg 1.1
3845     #ifndef NO_BRIGHTCOLOR
3846 pcg 1.36 case 90:
3847     case 91: /* set bright fg color */
3848     case 92:
3849     case 93:
3850     case 94:
3851     case 95:
3852     case 96:
3853     case 97:
3854 pcg 1.43 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 90)),
3855 pcg 1.36 Color_fg);
3856     break;
3857     case 100:
3858     case 101: /* set bright bg color */
3859     case 102:
3860     case 103:
3861     case 104:
3862     case 105:
3863     case 106:
3864     case 107:
3865 pcg 1.43 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 100)),
3866 pcg 1.36 Color_bg);
3867     break;
3868 pcg 1.1 #endif
3869 pcg 1.36
3870     }
3871 pcg 1.1 }
3872     }
3873     /*}}} */
3874    
3875 pcg 1.93 /*{{{ (do not) process Rob Nation's own graphics mode sequences */
3876 pcg 1.1 void
3877 pcg 1.34 rxvt_term::process_graphics ()
3878 pcg 1.1 {
3879 pcg 1.81 unicode_t ch, cmd = cmd_getc ();
3880 pcg 1.1
3881 pcg 1.36 if (cmd == 'Q')
3882     { /* query graphics */
3883 pcg 1.43 tt_printf ("\033G0\n"); /* no graphics */
3884 pcg 1.36 return;
3885     }
3886     /* swallow other graphics sequences until terminating ':' */
3887     do
3888     ch = cmd_getc ();
3889     while (ch != ':');
3890 pcg 1.1 }
3891     /*}}} */
3892    
3893     /* ------------------------------------------------------------------------- */
3894    
3895     /*
3896 pcg 1.43 * Send printf () formatted output to the command.
3897 pcg 1.1 * Only use for small amounts of data.
3898     */
3899     void
3900 pcg 1.10 rxvt_term::tt_printf (const char *fmt,...)
3901 pcg 1.1 {
3902 pcg 1.10 va_list arg_ptr;
3903     unsigned char buf[256];
3904 pcg 1.1
3905 pcg 1.10 va_start (arg_ptr, fmt);
3906     vsnprintf ((char *)buf, 256, fmt, arg_ptr);
3907     va_end (arg_ptr);
3908     tt_write (buf, STRLEN (buf));
3909 pcg 1.1 }
3910    
3911     /* ---------------------------------------------------------------------- */
3912 pcg 1.10 /* Write data to the pty as typed by the user, pasted with the mouse,
3913 pcg 1.1 * or generated by us in response to a query ESC sequence.
3914     */
3915     void
3916 pcg 1.10 rxvt_term::tt_write (const unsigned char *data, unsigned int len)
3917 pcg 1.1 {
3918 pcg 1.10 enum { MAX_PTY_WRITE = 255 }; // minimum MAX_INPUT
3919    
3920     if (len)
3921     {
3922     if (v_buflen == 0)
3923     {
3924 pcg 1.34 ssize_t written = write (cmd_fd, data, min (MAX_PTY_WRITE, len));
3925    
3926     if ((unsigned int)written == len)
3927 pcg 1.10 return;
3928    
3929     data += written;
3930     len -= written;
3931     }
3932    
3933    
3934     v_buffer = (unsigned char *)realloc (v_buffer, v_buflen + len);
3935    
3936     memcpy (v_buffer + v_buflen, data, len);
3937     v_buflen += len;
3938 pcg 1.1 }
3939    
3940 pcg 1.10 for (;;)
3941     {
3942     int written = write (cmd_fd, v_buffer, min (MAX_PTY_WRITE, v_buflen));
3943    
3944     if (written > 0)
3945     {
3946     v_buflen -= written;
3947    
3948     if (v_buflen == 0)
3949     {
3950     free (v_buffer);
3951     v_buffer = 0;
3952     v_buflen = 0;
3953    
3954     pty_ev.set (EVENT_READ);
3955     return;
3956     }
3957 pcg 1.1
3958 pcg 1.10 memmove (v_buffer, v_buffer + written, v_buflen);
3959     }
3960     else if (written != -1 || (errno != EAGAIN && errno != EINTR))
3961     // original code just ignores this...
3962     destroy ();
3963     else
3964     {
3965     pty_ev.set (EVENT_READ | EVENT_WRITE);
3966     return;
3967     }
3968 pcg 1.1 }
3969     }
3970 pcg 1.10
3971 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
3972