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