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