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