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