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